tests: add a test for -yy option

* 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.
This commit is contained in:
Дмитрий Левин 2014-09-23 00:14:04 +00:00
parent 9a0dd74ae0
commit fdfa72276a
7 changed files with 353 additions and 2 deletions

6
tests/.gitignore vendored
View File

@ -1,4 +1,6 @@
inet-accept-connect-send-recv
net-accept-connect
netlink_inet_diag
scm_rights
set_ptracer_any
sigaction
@ -8,5 +10,7 @@ uio
*.log
*.log.*
*.o
*.trs
*.tmp
*.tmp-*
*.tmp.*
*.trs

View File

@ -3,7 +3,9 @@
AM_CFLAGS = $(WARN_CFLAGS)
check_PROGRAMS = \
inet-accept-connect-send-recv \
net-accept-connect \
netlink_inet_diag \
scm_rights \
set_ptracer_any \
sigaction \
@ -27,6 +29,7 @@ TESTS = \
statfs.test \
net.test \
net-fd.test \
net-yy.test \
uio.test \
count.test \
detach-sleeping.test \
@ -38,6 +41,11 @@ net-fd.log: net.log
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)

View File

@ -0,0 +1,53 @@
#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;
}

76
tests/net-yy-accept.awk Normal file
View File

@ -0,0 +1,76 @@
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
}
}

55
tests/net-yy-connect.awk Normal file
View File

@ -0,0 +1,55 @@
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
}
}

59
tests/net-yy.test Executable file
View File

@ -0,0 +1,59 @@
#!/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

96
tests/netlink_inet_diag.c Normal file
View File

@ -0,0 +1,96 @@
#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;
}