(root)/
strace-6.5/
tests/
sockopt-timestamp.c
       1  /*
       2   * Check decoding of timestamp control messages.
       3   *
       4   * Copyright (c) 2019 Dmitry V. Levin <ldv@strace.io>
       5   * Copyright (c) 2019-2023 The strace developers.
       6   * All rights reserved.
       7   *
       8   * SPDX-License-Identifier: GPL-2.0-or-later
       9   */
      10  
      11  #include "tests.h"
      12  #include "scno.h"
      13  
      14  #ifdef __NR_recvmsg
      15  
      16  # include <errno.h>
      17  # include <stdio.h>
      18  # include <string.h>
      19  # include <unistd.h>
      20  # include <sys/socket.h>
      21  
      22  # include "kernel_time_types.h"
      23  # include "kernel_timeval.h"
      24  # include "kernel_old_timespec.h"
      25  
      26  # define XLAT_MACROS_ONLY
      27  #  include "xlat/sock_options.h"
      28  # undef XLAT_MACROS_ONLY
      29  
      30  static const char *errstr;
      31  
      32  static long
      33  k_recvmsg(const unsigned int fd, const void *const ptr, const unsigned int flags)
      34  {
      35  	const kernel_ulong_t fill = (kernel_ulong_t) 0xdefaced00000000ULL;
      36  	const kernel_ulong_t bad = (kernel_ulong_t) 0xbadc0dedbadc0dedULL;
      37  	const kernel_ulong_t arg1 = fill | fd;
      38  	const kernel_ulong_t arg2 = (uintptr_t) ptr;
      39  	const kernel_ulong_t arg3 = fill | flags;
      40  	const long rc = syscall(__NR_recvmsg, arg1, arg2, arg3, bad, bad, bad);
      41  	if (rc && errno == ENOSYS)
      42  		perror_msg_and_skip("recvmsg");
      43  	errstr = sprintrc(rc);
      44  	return rc;
      45  }
      46  
      47  # define SC_setsockopt 14
      48  static long
      49  k_setsockopt(const unsigned int fd, const unsigned int level,
      50  	     const unsigned int optname, const void *const optval,
      51  	     const unsigned int len)
      52  {
      53  	const kernel_ulong_t fill = (kernel_ulong_t) 0xdefaced00000000ULL;
      54  # ifdef __NR_setsockopt
      55  	const kernel_ulong_t bad = (kernel_ulong_t) 0xbadc0dedbadc0dedULL;
      56  # endif
      57  
      58  	return syscall(
      59  # ifdef __NR_setsockopt
      60  		__NR_setsockopt,
      61  # else /* socketcall */
      62  		__NR_socketcall, SC_setsockopt,
      63  # endif
      64  		fill | fd , fill | level, fill | optname, optval, fill | len
      65  # ifdef __NR_setsockopt
      66  		, bad
      67  # endif
      68  		);
      69  }
      70  
      71  static void
      72  print_timestamp_old(const struct cmsghdr *c)
      73  {
      74  	const void *cmsg_header = c;
      75  	const void *cmsg_data = CMSG_DATA(c);
      76  	kernel_old_timeval_t tv;
      77  	const unsigned int expected_len = sizeof(tv);
      78  	const unsigned int data_len = c->cmsg_len - (cmsg_data - cmsg_header);
      79  
      80  	if (expected_len != data_len)
      81  		perror_msg_and_fail("sizeof(struct timeval) = %u"
      82  				    ", data_len = %u\n",
      83  				    expected_len, data_len);
      84  
      85  	memcpy(&tv, cmsg_data, sizeof(tv));
      86  	printf("{tv_sec=%lld, tv_usec=%lld}",
      87  	       (long long) tv.tv_sec, (long long) tv.tv_usec);
      88  }
      89  
      90  static void
      91  print_timestampns_old(const struct cmsghdr *c)
      92  {
      93  	const void *cmsg_header = c;
      94  	const void *cmsg_data = CMSG_DATA(c);
      95  	kernel_old_timespec_t ts;
      96  	const unsigned int expected_len = sizeof(ts);
      97  	const unsigned int data_len = c->cmsg_len - (cmsg_data - cmsg_header);
      98  
      99  	if (expected_len != data_len)
     100  		perror_msg_and_fail("sizeof(struct timespec) = %u"
     101  				    ", data_len = %u\n",
     102  				    expected_len, data_len);
     103  
     104  	memcpy(&ts, cmsg_data, sizeof(ts));
     105  	printf("{tv_sec=%lld, tv_nsec=%lld}",
     106  	       (long long) ts.tv_sec, (long long) ts.tv_nsec);
     107  }
     108  
     109  static void
     110  print_timestamp_new(const struct cmsghdr *c)
     111  {
     112  	const void *cmsg_header = c;
     113  	const void *cmsg_data = CMSG_DATA(c);
     114  	struct __kernel_sock_timeval tv;
     115  	const unsigned int expected_len = sizeof(tv);
     116  	const unsigned int data_len = c->cmsg_len - (cmsg_data - cmsg_header);
     117  
     118  	if (expected_len != data_len)
     119  		perror_msg_and_fail("sizeof(struct __kernel_sock_timeval) = %u"
     120  				    ", data_len = %u\n",
     121  				    expected_len, data_len);
     122  
     123  	memcpy(&tv, cmsg_data, sizeof(tv));
     124  	printf("{tv_sec=%lld, tv_usec=%lld}",
     125  	       (long long) tv.tv_sec, (long long) tv.tv_usec);
     126  }
     127  
     128  static void
     129  print_timestampns_new(const struct cmsghdr *c)
     130  {
     131  	const void *cmsg_header = c;
     132  	const void *cmsg_data = CMSG_DATA(c);
     133  	struct __kernel_timespec ts;
     134  	const unsigned int expected_len = sizeof(ts);
     135  	const unsigned int data_len = c->cmsg_len - (cmsg_data - cmsg_header);
     136  
     137  	if (expected_len != data_len)
     138  		perror_msg_and_fail("sizeof(struct __kernel_timespec) = %u"
     139  				    ", data_len = %u\n",
     140  				    expected_len, data_len);
     141  
     142  	memcpy(&ts, cmsg_data, sizeof(ts));
     143  	printf("{tv_sec=%lld, tv_nsec=%lld}",
     144  	       (long long) ts.tv_sec, (long long) ts.tv_nsec);
     145  }
     146  
     147  static unsigned int
     148  test_sockopt(int so_val, const char *str, void (*fun)(const struct cmsghdr *))
     149  {
     150  	static const char data[] = "socketpair";
     151  	const size_t size = sizeof(data) - 1;
     152  
     153  	int sv[2];
     154  	if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv))
     155  		perror_msg_and_skip(data);
     156  
     157  	const int opt_1 = 1;
     158  	/*
     159  	 * glibc-2.34~294 adds a fallback for SO_TIMESTAMP{,NS}_NEW that calls
     160  	 * SO_TIMESTAMP{,NS}_OLD, so we have to call the setsockopt directly
     161  	 * in order to avoid unexpected recvmsg msg types.
     162  	 */
     163  	if (k_setsockopt(sv[0], SOL_SOCKET, so_val, &opt_1, sizeof(opt_1))) {
     164  		perror(str);
     165  		return 0;
     166  	}
     167  
     168  	if (send(sv[1], data, size, 0) != (int) size)
     169  		perror_msg_and_fail("send");
     170  	if (close(sv[1]))
     171  		perror_msg_and_fail("close send");
     172  
     173  	char buf[size];
     174  	struct iovec iov = {
     175  		.iov_base = buf,
     176  		.iov_len = sizeof(buf)
     177  	};
     178  	struct cmsghdr control[16];
     179  	struct msghdr mh = {
     180  		.msg_iov = &iov,
     181  		.msg_iovlen = 1,
     182  		.msg_control = control,
     183  		.msg_controllen = sizeof(control)
     184  	};
     185  
     186  	if (k_recvmsg(sv[0], &mh, 0) != (int) size)
     187  		perror_msg_and_fail("recvmsg");
     188  	if (close(sv[0]))
     189  		perror_msg_and_fail("close recv");
     190  
     191  	printf("recvmsg(%d, {msg_name=NULL, msg_namelen=0"
     192  	       ", msg_iov=[{iov_base=\"%s\", iov_len=%u}], msg_iovlen=1",
     193  	       sv[0], data, (unsigned int) size);
     194  
     195  	unsigned int tested = 0;
     196  	if (mh.msg_controllen) {
     197  		printf(", msg_control=[");
     198  		for (struct cmsghdr *c = CMSG_FIRSTHDR(&mh); c;
     199  		     c = CMSG_NXTHDR(&mh, c)) {
     200  			printf("%s{cmsg_len=%lu, cmsg_level=",
     201  			       (c == control ? "" : ", "),
     202  			       (unsigned long) c->cmsg_len);
     203  			if (c->cmsg_level == SOL_SOCKET) {
     204  				printf("SOL_SOCKET");
     205  			} else {
     206  				printf("%d /* expected SOL_SOCKET == %d */",
     207  				       c->cmsg_level, (int) SOL_SOCKET);
     208  			}
     209  			printf(", cmsg_type=");
     210  			if (c->cmsg_type == so_val) {
     211  				printf("%s, cmsg_data=", str);
     212  				fun(c);
     213  				tested = 1;
     214  			} else {
     215  				printf("%d /* expected %d */",
     216  				       c->cmsg_type, so_val);
     217  			}
     218  			printf("}");
     219  		}
     220  		printf("]");
     221  	}
     222  	printf(", msg_controllen=%lu, msg_flags=0}, 0) = %u\n",
     223  	       (unsigned long) mh.msg_controllen, (unsigned int) size);
     224  
     225  	return tested;
     226  }
     227  
     228  int
     229  main(void)
     230  {
     231  	static const struct {
     232  		int val;
     233  		const char *str;
     234  		void (*fun)(const struct cmsghdr *);
     235  	} tests[] = {
     236  		{ SO_TIMESTAMP_OLD, "SO_TIMESTAMP_OLD", print_timestamp_old },
     237  		{ SO_TIMESTAMPNS_OLD, "SO_TIMESTAMPNS_OLD", print_timestampns_old },
     238  		{ SO_TIMESTAMP_NEW, "SO_TIMESTAMP_NEW", print_timestamp_new },
     239  		{ SO_TIMESTAMPNS_NEW, "SO_TIMESTAMPNS_NEW", print_timestampns_new },
     240  	};
     241  	unsigned int tested = 0;
     242  	for (unsigned int i = 0; i < ARRAY_SIZE(tests); ++i)
     243  		tested |= test_sockopt(tests[i].val,
     244  				       tests[i].str,
     245  				       tests[i].fun);
     246  	if (!tested)
     247  		return 77;
     248  
     249  	puts("+++ exited with 0 +++");
     250  	return 0;
     251  }
     252  
     253  #else
     254  
     255  SKIP_MAIN_UNDEFINED("__NR_recvmsg")
     256  
     257  #endif