]> granicus.if.org Git - strace/commitdiff
tests: add another test of SO_TIMESTAMP and SO_TIMESTAMPNS decoding
authorDmitry V. Levin <ldv@altlinux.org>
Wed, 15 May 2019 16:52:37 +0000 (16:52 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Wed, 15 May 2019 16:52:37 +0000 (16:52 +0000)
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.

tests/.gitignore
tests/gen_tests.in
tests/pure_executables.list
tests/sockopt-timestamp.c [new file with mode: 0644]

index 5a601641fb8a4459ee3963e78ca5e8665af3b1bc..0d881d9356a8cffc93740a54a33d2c869a85183f 100644 (file)
@@ -546,6 +546,7 @@ sockaddr_xlat-Xraw
 sockaddr_xlat-Xverbose
 socketcall
 sockopt-sol_netlink
+sockopt-timestamp
 splice
 stack-fcall
 stack-fcall-mangled
index 314608eb27bb3f205724ab4d710fab307bb01d3e..8bdf6ba829ca117b5e64d95f4ebef2cc8111f741 100644 (file)
@@ -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
index b695a0ecee21ce65669f4657bf5abffa33a931c9..502ce5b374e625581caa88f9ca247d979cc38163 100755 (executable)
@@ -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 (file)
index 0000000..0f60d64
--- /dev/null
@@ -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;
+}