summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry V. Levin <ldv@altlinux.org>2019-05-15 16:52:37 +0000
committerDmitry V. Levin <ldv@altlinux.org>2019-05-15 16:52:37 +0000
commitc2619c5a76651a80ff3b53f1d891d67b9760d961 (patch)
tree5529d497d6321897fd0a3e9cc984b1d2c662e70d
parent62bff525f8cd0564222b08fd83b82c497e2425e5 (diff)
downloadstrace-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/.gitignore1
-rw-r--r--tests/gen_tests.in1
-rwxr-xr-xtests/pure_executables.list1
-rw-r--r--tests/sockopt-timestamp.c158
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;
+}