* tests/net-yy.test: New test.
* tests/inet-accept-connect-send-recv.c: New file.
* tests/netlink_inet_diag.c: Likewise.
* tests/net-yy-accept.awk: Likewise.
* tests/net-yy-connect.awk: Likewise.
* tests/.gitignore: Add inet-accept-connect-send-recv,
netlink_inet_diag, *.tmp-*, and *.tmp.*.
* tests/Makefile.am (check_PROGRAMS): Add inet-accept-connect-send-recv
and netlink_inet_diag.
(TESTS): Add net-yy.test.
(EXTRA_DIST): Add net-yy-accept.awk and net-yy-connect.awk.
+inet-accept-connect-send-recv
net-accept-connect
+netlink_inet_diag
scm_rights
set_ptracer_any
sigaction
*.log
*.log.*
*.o
-*.trs
*.tmp
+*.tmp-*
+*.tmp.*
+*.trs
AM_CFLAGS = $(WARN_CFLAGS)
check_PROGRAMS = \
+ inet-accept-connect-send-recv \
net-accept-connect \
+ netlink_inet_diag \
scm_rights \
set_ptracer_any \
sigaction \
statfs.test \
net.test \
net-fd.test \
+ net-yy.test \
uio.test \
count.test \
detach-sleeping.test \
TEST_LOG_COMPILER = $(srcdir)/run.sh
-EXTRA_DIST = init.sh run.sh getdents.awk sigaction.awk $(TESTS)
+EXTRA_DIST = init.sh run.sh \
+ getdents.awk \
+ net-yy-accept.awk \
+ net-yy-connect.awk \
+ sigaction.awk \
+ $(TESTS)
CLEANFILES = $(TESTS:=.tmp)
--- /dev/null
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+int main(void)
+{
+ static const char data[] = "data";
+ const size_t size = sizeof(data) - 1;
+ struct sockaddr_in addr;
+ socklen_t len = sizeof(addr);
+ pid_t pid;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ close(0);
+ close(1);
+
+ assert(socket(PF_INET, SOCK_STREAM, 0) == 0);
+ assert(bind(0, (struct sockaddr *) &addr, len) == 0);
+ assert(listen(0, 5) == 0);
+
+ memset(&addr, 0, sizeof(addr));
+ assert(getsockname(0, (struct sockaddr *) &addr, &len) == 0);
+
+ assert((pid = fork()) >= 0);
+
+ if (pid) {
+ char buf[sizeof(data)];
+ int status;
+
+ assert(accept(0, (struct sockaddr *) &addr, &len) == 1);
+ assert(close(0) == 0);
+ assert(recv(1, buf, sizeof(buf), MSG_WAITALL) == (int) size);
+ assert(waitpid(pid, &status, 0) == pid);
+ assert(status == 0);
+ assert(close(1) == 0);
+ } else {
+ assert(close(0) == 0);
+ assert(socket(PF_INET, SOCK_STREAM, 0) == 0);
+ assert(connect(0, (struct sockaddr *) &addr, len) == 0);
+ assert(send(0, data, size, MSG_DONTROUTE) == (int) size);
+ assert(close(0) == 0);
+ }
+
+ return 0;
+}
--- /dev/null
+BEGIN {
+ lines = 9
+ fail = 0
+
+ inode = "?"
+ port_l = "?"
+ port_r = "?"
+
+ r_i = "[1-9][0-9]*"
+ r_port = "[1-9][0-9][0-9][0-9]+"
+ r_localhost = "127\\.0\\.0\\.1"
+ r_bind = "^bind\\(0<socket:\\[(" r_i ")\\]>, {sa_family=AF_INET, sin_port=htons\\(0\\), sin_addr=inet_addr\\(\"" r_localhost "\"\\)}, " r_i "\\) += 0$"
+ r_listen = "^/$"
+ r_getsockname = "^getsockname\\(0<" r_localhost ":(" r_port ")>, {sa_family=AF_INET, sin_port=htons\\((" r_port ")\\), sin_addr=inet_addr\\(\"" r_localhost "\"\\)}, \\[" r_i "\\]\\) += 0$"
+ r_accept = "^/$"
+ r_close0 = "^/$"
+ r_recv = "^/$"
+ r_recvfrom = "^/$"
+ r_close1 = "^/$"
+}
+
+NR == 1 && /^socket\(PF_INET, SOCK_STREAM, IPPROTO_IP\) += 0$/ {next}
+
+NR == 2 {
+ if (match($0, r_bind, a)) {
+ inode = a[1]
+ r_listen = "^listen\\(0<socket:\\[" inode "\\]>, 5\\) += 0$"
+ next
+ }
+}
+
+NR == 3 {if (match($0, r_listen)) next}
+
+NR == 4 {
+ if (match($0, r_getsockname, a) && a[1] == a[2]) {
+ port_l = a[1]
+ r_accept = "^accept\\(0<" r_localhost ":" port_l ">, {sa_family=AF_INET, sin_port=htons\\((" r_port ")\\), sin_addr=inet_addr\\(\"" r_localhost "\"\\)}, \\[" r_i "\\]\\) += 1<" r_localhost ":" port_l "->" r_localhost ":(" r_port ")>$"
+ r_close0 = "^close\\(0<" r_localhost ":" port_l ">) += 0$"
+ next
+ }
+}
+
+NR == 5 {
+ if (match($0, r_accept, a) && a[1] == a[2]) {
+ port_r = a[1]
+ r_recv = "^recv\\(1<" r_localhost ":" port_l "->" r_localhost ":" port_r ">, \"data\", 5, MSG_WAITALL\\) += 4$"
+ r_recvfrom = "^recvfrom\\(1<" r_localhost ":" port_l "->" r_localhost ":" port_r ">, \"data\", 5, MSG_WAITALL, NULL, NULL\\) += 4$"
+ r_close1 = "^close\\(1<" r_localhost ":" port_l "->" r_localhost ":" port_r ">) += 0$"
+ next
+ }
+}
+
+NR == 6 {if (match($0, r_close0)) next}
+
+NR == 7 {if (match($0, r_recv) || match($0, r_recvfrom)) next}
+
+NR == 8 {if (match($0, r_close1)) next}
+
+NR == lines && /^\+\+\+ exited with 0 \+\+\+$/ {next}
+
+{
+ print "Line " NR " does not match: " $0
+ fail=1
+}
+
+END {
+ if (NR != lines) {
+ print "Expected " lines " lines, found " NR " line(s)."
+ print ""
+ exit 1
+ }
+ if (fail) {
+ print ""
+ exit 1
+ }
+}
--- /dev/null
+BEGIN {
+ lines = 5
+ fail = 0
+
+ port_l = "?"
+ port_r = "?"
+
+ r_i = "[1-9][0-9]*"
+ r_port = "[1-9][0-9][0-9][0-9]+"
+ r_localhost = "127\\.0\\.0\\.1"
+ r_connect = "^connect\\(0<socket:\\[" r_i "\\]>, {sa_family=AF_INET, sin_port=htons\\((" r_port ")\\), sin_addr=inet_addr\\(\"" r_localhost "\"\\)}, " r_i ") += 0$"
+ r_send = "^/$"
+ r_sendto = "^/$"
+ r_close = "^/$"
+}
+
+NR == 1 && /^socket\(PF_INET, SOCK_STREAM, IPPROTO_IP\) += 0$/ {next}
+
+NR == 2 {
+ if (match($0, r_connect, a)) {
+ port_r = a[1]
+ r_send = "^send\\(0<" r_localhost ":(" r_port ")->" r_localhost ":" port_r ">, \"data\", 4, MSG_DONTROUTE\\) += 4$"
+ r_sendto = "^sendto\\(0<" r_localhost ":(" r_port ")->" r_localhost ":" port_r ">, \"data\", 4, MSG_DONTROUTE, NULL, 0\\) += 4$"
+ next
+ }
+}
+
+NR == 3 {
+ if (match($0, r_send, a) || match($0, r_sendto, a)) {
+ port_l = a[1]
+ r_close = "^close\\(0<" r_localhost ":" port_l "->" r_localhost ":" port_r ">\\) += 0$"
+ next
+ }
+}
+
+NR == 4 {if (match($0, r_close)) next}
+
+NR == lines && /^\+\+\+ exited with 0 \+\+\+$/ {next}
+
+{
+ print "Line " NR " does not match: " $0
+ fail=1
+}
+
+END {
+ if (NR != lines) {
+ print "Expected " lines " lines, found " NR " line(s)."
+ print ""
+ exit 1
+ }
+ if (fail) {
+ print ""
+ exit 1
+ }
+}
--- /dev/null
+#!/bin/sh
+
+# Check decoding of ip:port pairs associated with socket descriptors
+
+. "${srcdir=.}/init.sh"
+
+# strace -yy is implemented using /proc/self/fd
+[ -d /proc/self/fd/ ] ||
+ framework_skip_ '/proc/self/fd/ is not available'
+
+check_prog sed
+check_prog awk
+
+rm -f $LOG.* $LOG-*
+
+./inet-accept-connect-send-recv ||
+ fail_ 'inet-accept-connect-send-recv failed'
+
+./netlink_inet_diag || {
+ if [ $? -eq 77 ]; then
+ framework_skip_ 'NETLINK_INET_DIAG is not available'
+ else
+ fail_ 'netlink_inet_diag failed'
+ fi
+}
+
+args="-tt -ff -yy -o $LOG -eclose,network ./inet-accept-connect-send-recv"
+$STRACE $args ||
+ fail_ "strace $args failed"
+
+"$srcdir"/../strace-log-merge $LOG > $LOG || {
+ cat $LOG
+ fail_ 'strace-log-merge failed'
+}
+rm -f $LOG.*
+
+child="$(sed -rn '/SIGCHLD/ s/^.*, si_pid=([1-9][0-9]*), .*/\1/p' $LOG)"
+[ -n "$child" ] || {
+ cat $LOG
+ fail_ 'failed to find pid of child process'
+}
+
+sed -rn "/^$child"' /!d; / socket\(/,$ s/^[0-9]+ +[^ ]+ (.+)/\1/p' $LOG > $LOG-connect &&
+sed -rn "/^$child"' /d; /SIGCHLD/d; / socket\(/,$ s/^[0-9]+ +[^ ]+ (.+)/\1/p' $LOG > $LOG-accept || {
+ cat $LOG
+ fail_ 'failed to separate logs'
+}
+
+awk -f "$srcdir"/net-yy-connect.awk $LOG-connect || {
+ cat $LOG-connect
+ fail_ "strace $args failed to decode socket descriptors properly"
+}
+
+awk -f "$srcdir"/net-yy-accept.awk $LOG-accept || {
+ cat $LOG-accept
+ fail_ "strace $args failed to decode socket descriptors properly"
+}
+
+exit 0
--- /dev/null
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <linux/netlink.h>
+#include <linux/sock_diag.h>
+#include <linux/inet_diag.h>
+
+static int
+send_query(const int fd, const int family, const int proto)
+{
+ struct sockaddr_nl nladdr;
+ struct {
+ struct nlmsghdr nlh;
+ struct inet_diag_req_v2 idr;
+ } req;
+ struct iovec iov = {
+ .iov_base = &req,
+ .iov_len = sizeof(req)
+ };
+ struct msghdr msg = {
+ .msg_name = (void*)&nladdr,
+ .msg_namelen = sizeof(nladdr),
+ .msg_iov = &iov,
+ .msg_iovlen = 1
+ };
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+
+ memset(&req, 0, sizeof(req));
+ req.nlh.nlmsg_len = sizeof(req);
+ req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
+ req.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
+ req.idr.sdiag_family = family;
+ req.idr.sdiag_protocol = proto;
+ req.idr.idiag_states = -1;
+
+ return sendmsg(fd, &msg, 0) > 0;
+}
+
+static int
+check_responses(const int fd)
+{
+ static char buf[8192];
+ struct sockaddr_nl nladdr;
+ struct iovec iov = {
+ .iov_base = buf,
+ .iov_len = sizeof(buf)
+ };
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+
+ struct msghdr msg = {
+ .msg_name = (void*)&nladdr,
+ .msg_namelen = sizeof(nladdr),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = NULL,
+ .msg_controllen = 0,
+ .msg_flags = 0
+ };
+
+ ssize_t ret = recvmsg(fd, &msg, 0);
+ if (ret <= 0)
+ return 0;
+
+ struct nlmsghdr *h = (struct nlmsghdr*)buf;
+ return (NLMSG_OK(h, ret) &&
+ h->nlmsg_type != NLMSG_ERROR &&
+ h->nlmsg_type != NLMSG_DONE) ? 1 : 0;
+}
+
+int main(void)
+{
+ struct sockaddr_in addr;
+ socklen_t len = sizeof(addr);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ close(0);
+ close(1);
+
+ assert(socket(PF_INET, SOCK_STREAM, 0) == 0);
+ assert(bind(0, (struct sockaddr *) &addr, len) == 0);
+ assert(listen(0, 5) == 0);
+
+ if (socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG) != 1)
+ return 77;
+
+ return (send_query(1, AF_INET, IPPROTO_TCP) &&
+ check_responses(1)) ? 0 : 77;
+}