diff options
author | Dmitry V. Levin <ldv@altlinux.org> | 2019-05-15 16:52:37 +0000 |
---|---|---|
committer | Dmitry V. Levin <ldv@altlinux.org> | 2019-05-15 16:52:37 +0000 |
commit | c2619c5a76651a80ff3b53f1d891d67b9760d961 (patch) | |
tree | 5529d497d6321897fd0a3e9cc984b1d2c662e70d | |
parent | 62bff525f8cd0564222b08fd83b82c497e2425e5 (diff) | |
download | strace-c2619c5a76651a80ff3b53f1d891d67b9760d961.tar.gz |
tests: add another test of SO_TIMESTAMP and SO_TIMESTAMPNS decoding
Unlike msg_control test, this new test makes the kernel generate
SO_TIMESTAMP and SO_TIMESTAMPNS messages.
* tests/sockopt-timestamp.c: New file.
* tests/gen_tests.in (sockopt-timestamp): New entry.
* tests/pure_executables.list: Add sockopt-timestamp.
* tests/.gitignore: Likewise.
-rw-r--r-- | tests/.gitignore | 1 | ||||
-rw-r--r-- | tests/gen_tests.in | 1 | ||||
-rwxr-xr-x | tests/pure_executables.list | 1 | ||||
-rw-r--r-- | tests/sockopt-timestamp.c | 158 |
4 files changed, 161 insertions, 0 deletions
diff --git a/tests/.gitignore b/tests/.gitignore index 5a601641f..0d881d935 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -546,6 +546,7 @@ sockaddr_xlat-Xraw sockaddr_xlat-Xverbose socketcall sockopt-sol_netlink +sockopt-timestamp splice stack-fcall stack-fcall-mangled diff --git a/tests/gen_tests.in b/tests/gen_tests.in index 314608eb2..8bdf6ba82 100644 --- a/tests/gen_tests.in +++ b/tests/gen_tests.in @@ -455,6 +455,7 @@ sockaddr_xlat-Xraw -Xraw -e trace=connect sockaddr_xlat-Xverbose -Xverbose -e trace=connect socketcall -a20 sockopt-sol_netlink -e trace=getsockopt,setsockopt +sockopt-timestamp -e trace=recvmsg splice stat -a32 -v -P stat.sample -P /dev/full stat64 -a32 -v -P stat.sample -P /dev/full diff --git a/tests/pure_executables.list b/tests/pure_executables.list index b695a0ece..502ce5b37 100755 --- a/tests/pure_executables.list +++ b/tests/pure_executables.list @@ -460,6 +460,7 @@ sockaddr_xlat-Xraw sockaddr_xlat-Xverbose socketcall sockopt-sol_netlink +sockopt-timestamp splice stat stat64 diff --git a/tests/sockopt-timestamp.c b/tests/sockopt-timestamp.c new file mode 100644 index 000000000..0f60d64c2 --- /dev/null +++ b/tests/sockopt-timestamp.c @@ -0,0 +1,158 @@ +/* + * Check decoding of timestamp control messages. + * + * Copyright (c) 2019 Dmitry V. Levin <ldv@altlinux.org> + * All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "tests.h" +#include <stdio.h> +#include <unistd.h> +#include <sys/socket.h> + +#ifndef SO_TIMESTAMP_OLD +# define SO_TIMESTAMP_OLD SO_TIMESTAMP +#endif + +#ifndef SO_TIMESTAMPNS_OLD +# ifdef SO_TIMESTAMPNS +# define SO_TIMESTAMPNS_OLD SO_TIMESTAMPNS +# endif +#endif + +static void +print_timestamp_old(const struct cmsghdr *c) +{ + const void *cmsg_header = c; + const void *cmsg_data = CMSG_DATA(c); + const struct timeval *tv = cmsg_data; + const unsigned int expected_len = sizeof(*tv); + const unsigned int data_len = c->cmsg_len - (cmsg_data - cmsg_header); + + if (expected_len != data_len) + perror_msg_and_fail("sizeof(struct timeval) = %u" + ", data_len = %u\n", + expected_len, data_len); + printf("{tv_sec=%lld, tv_usec=%lld}", + (long long) tv->tv_sec, (long long) tv->tv_usec); +} + +#ifdef SO_TIMESTAMPNS_OLD +static void +print_timestampns_old(const struct cmsghdr *c) +{ + const void *cmsg_header = c; + const void *cmsg_data = CMSG_DATA(c); + const struct timespec *ts = cmsg_data; + const unsigned int expected_len = sizeof(*ts); + const unsigned int data_len = c->cmsg_len - (cmsg_data - cmsg_header); + + if (expected_len != data_len) + perror_msg_and_fail("sizeof(struct timespec) = %u" + ", data_len = %u\n", + expected_len, data_len); + printf("{tv_sec=%lld, tv_nsec=%lld}", + (long long) ts->tv_sec, (long long) ts->tv_nsec); +} +#endif /* SO_TIMESTAMPNS_OLD */ + +static unsigned int +test_sockopt(int so_val, const char *str, void (*fun)(const struct cmsghdr *)) +{ + static const char data[] = "socketpair"; + const size_t size = sizeof(data) - 1; + + int sv[2]; + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv)) + perror_msg_and_skip(data); + + const int opt_1 = 1; + if (setsockopt(sv[0], SOL_SOCKET, so_val, &opt_1, sizeof(opt_1))) { + perror(str); + return 0; + } + + if (send(sv[1], data, size, 0) != (int) size) + perror_msg_and_fail("send"); + if (close(sv[1])) + perror_msg_and_fail("close send"); + + char buf[size]; + struct iovec iov = { + .iov_base = buf, + .iov_len = sizeof(buf) + }; + struct cmsghdr control[16]; + struct msghdr mh = { + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = control, + .msg_controllen = sizeof(control) + }; + + if (recvmsg(sv[0], &mh, 0) != (int) size) + perror_msg_and_fail("recvmsg"); + if (close(sv[0])) + perror_msg_and_fail("close recv"); + + printf("recvmsg(%d, {msg_name=NULL, msg_namelen=0" + ", msg_iov=[{iov_base=\"%s\", iov_len=%u}], msg_iovlen=1", + sv[0], data, (unsigned int) size); + + unsigned int tested = 0; + if (mh.msg_controllen) { + printf(", msg_control=["); + for (struct cmsghdr *c = CMSG_FIRSTHDR(&mh); c; + c = CMSG_NXTHDR(&mh, c)) { + printf("%s{cmsg_len=%lu, cmsg_level=", + (c == control ? "" : ", "), + (unsigned long) c->cmsg_len); + if (c->cmsg_level == SOL_SOCKET) { + printf("SOL_SOCKET"); + } else { + printf("%d", c->cmsg_level); + } + printf(", cmsg_type="); + if (c->cmsg_type == so_val) { + printf("SCM_%s, cmsg_data=", str); + fun(c); + tested = 1; + } else { + printf("%d", c->cmsg_type); + } + printf("}"); + } + printf("]"); + } + printf(", msg_controllen=%lu, msg_flags=0}, 0) = %u\n", + (unsigned long) mh.msg_controllen, (unsigned int) size); + + return tested; +} + +int +main(void) +{ + static const struct { + int val; + const char *str; + void (*fun)(const struct cmsghdr *); + } tests[] = { + { SO_TIMESTAMP_OLD, "TIMESTAMP", print_timestamp_old }, +#ifdef SO_TIMESTAMPNS_OLD + { SO_TIMESTAMPNS_OLD, "TIMESTAMPNS", print_timestampns_old }, +#endif + }; + unsigned int tested = 0; + for (unsigned int i = 0; i < ARRAY_SIZE(tests); ++i) + tested |= test_sockopt(tests[i].val, + tests[i].str, + tests[i].fun); + if (!tested) + return 77; + + puts("+++ exited with 0 +++"); + return 0; +} |