* [PATCH v3 0/2] linux-user: SO_TIMESTAMP/NS/ING sockopt
@ 2020-12-18 19:54 Shu-Chun Weng via
2020-12-18 19:54 ` [PATCH v3 1/2] linux-user: Update SO_TIMESTAMP to SO_TIMESTAMP_OLD/NEW Shu-Chun Weng via
2020-12-18 19:54 ` [PATCH v3 2/2] linux-user: setsockopt() SO_TIMESTAMPNS and SO_TIMESTAMPING Shu-Chun Weng via
0 siblings, 2 replies; 3+ messages in thread
From: Shu-Chun Weng via @ 2020-12-18 19:54 UTC (permalink / raw)
To: qemu-devel, laurent; +Cc: Shu-Chun Weng
Hi Laurent,
This is the two timestamp-related patches splitted off per
https://lists.nongnu.org/archive/html/qemu-devel/2020-12/msg05149.html
v1 -> v2:
Address comments on the first 5 (was 3) patches.
Fix style problems.
v2 -> v3:
Split off into own group per
https://lists.nongnu.org/archive/html/qemu-devel/2020-12/msg05149.html
Rebase to master on Dec 18, 2020
Shu-Chun Weng (2):
linux-user: Update SO_TIMESTAMP to SO_TIMESTAMP_OLD/NEW
linux-user: setsockopt() SO_TIMESTAMPNS and SO_TIMESTAMPING
linux-user/alpha/sockbits.h | 21 +-
linux-user/generic/sockbits.h | 17 +-
linux-user/hppa/sockbits.h | 20 +-
linux-user/mips/sockbits.h | 16 +-
linux-user/sparc/sockbits.h | 21 +-
linux-user/strace.c | 19 +-
linux-user/syscall.c | 230 ++++++++++-
tests/tcg/multiarch/socket_timestamp.c | 540 +++++++++++++++++++++++++
8 files changed, 844 insertions(+), 40 deletions(-)
create mode 100644 tests/tcg/multiarch/socket_timestamp.c
--
2.29.2.684.gfbc64c5ab5-goog
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v3 1/2] linux-user: Update SO_TIMESTAMP to SO_TIMESTAMP_OLD/NEW
2020-12-18 19:54 [PATCH v3 0/2] linux-user: SO_TIMESTAMP/NS/ING sockopt Shu-Chun Weng via
@ 2020-12-18 19:54 ` Shu-Chun Weng via
2020-12-18 19:54 ` [PATCH v3 2/2] linux-user: setsockopt() SO_TIMESTAMPNS and SO_TIMESTAMPING Shu-Chun Weng via
1 sibling, 0 replies; 3+ messages in thread
From: Shu-Chun Weng via @ 2020-12-18 19:54 UTC (permalink / raw)
To: qemu-devel, laurent; +Cc: Shu-Chun Weng
Both guest options map to host SO_TIMESTAMP while keeping a global bit to
remember if the guest expects the old or the new format. Don't support
programs mixing two formats.
Added a multiarch test to verify.
Signed-off-by: Shu-Chun Weng <scw@google.com>
---
v1 -> v2:
Only keep track of old or new format globally, remove support for different
sockets mixing different formats.
Fix style problems.
v2 -> v3:
Rebase to master on Dec 18, 2020
linux-user/alpha/sockbits.h | 8 +-
linux-user/generic/sockbits.h | 9 +-
linux-user/hppa/sockbits.h | 8 +-
linux-user/mips/sockbits.h | 8 +-
linux-user/sparc/sockbits.h | 8 +-
linux-user/strace.c | 7 +-
linux-user/syscall.c | 91 ++++++--
tests/tcg/multiarch/socket_timestamp.c | 296 +++++++++++++++++++++++++
8 files changed, 408 insertions(+), 27 deletions(-)
create mode 100644 tests/tcg/multiarch/socket_timestamp.c
diff --git a/linux-user/alpha/sockbits.h b/linux-user/alpha/sockbits.h
index d54dc98c09..40f0644df0 100644
--- a/linux-user/alpha/sockbits.h
+++ b/linux-user/alpha/sockbits.h
@@ -48,8 +48,6 @@
#define TARGET_SO_DETACH_FILTER 27
#define TARGET_SO_PEERNAME 28
-#define TARGET_SO_TIMESTAMP 29
-#define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP
#define TARGET_SO_PEERSEC 30
#define TARGET_SO_PASSSEC 34
@@ -75,6 +73,12 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define TARGET_SO_NOFCS 43
+#define TARGET_SO_TIMESTAMP_OLD 29
+#define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD
+
+#define TARGET_SO_TIMESTAMP_NEW 63
+#define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW
+
/* TARGET_O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here.
*/
diff --git a/linux-user/generic/sockbits.h b/linux-user/generic/sockbits.h
index e44733c601..532cf2d3dc 100644
--- a/linux-user/generic/sockbits.h
+++ b/linux-user/generic/sockbits.h
@@ -49,10 +49,15 @@
#define TARGET_SO_DETACH_FILTER 27
#define TARGET_SO_PEERNAME 28
-#define TARGET_SO_TIMESTAMP 29
-#define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP
#define TARGET_SO_ACCEPTCONN 30
#define TARGET_SO_PEERSEC 31
+
+#define TARGET_SO_TIMESTAMP_OLD 29
+#define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD
+
+#define TARGET_SO_TIMESTAMP_NEW 63
+#define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW
+
#endif
diff --git a/linux-user/hppa/sockbits.h b/linux-user/hppa/sockbits.h
index 23f69a3293..284a47e74e 100644
--- a/linux-user/hppa/sockbits.h
+++ b/linux-user/hppa/sockbits.h
@@ -29,8 +29,6 @@
#define TARGET_SO_BSDCOMPAT 0x400e
#define TARGET_SO_PASSCRED 0x4010
#define TARGET_SO_PEERCRED 0x4011
-#define TARGET_SO_TIMESTAMP 0x4012
-#define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP
#define TARGET_SO_TIMESTAMPNS 0x4013
#define TARGET_SCM_TIMESTAMPNS TARGET_SO_TIMESTAMPNS
@@ -67,6 +65,12 @@
#define TARGET_SO_CNX_ADVICE 0x402E
+#define TARGET_SO_TIMESTAMP_OLD 0x4012
+#define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD
+
+#define TARGET_SO_TIMESTAMP_NEW 0x4038
+#define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW
+
/* TARGET_O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here.
*/
diff --git a/linux-user/mips/sockbits.h b/linux-user/mips/sockbits.h
index 0f022cd598..b4c39d9588 100644
--- a/linux-user/mips/sockbits.h
+++ b/linux-user/mips/sockbits.h
@@ -61,14 +61,18 @@
#define TARGET_SO_DETACH_FILTER 27
#define TARGET_SO_PEERNAME 28
-#define TARGET_SO_TIMESTAMP 29
-#define SCM_TIMESTAMP SO_TIMESTAMP
#define TARGET_SO_PEERSEC 30
#define TARGET_SO_SNDBUFFORCE 31
#define TARGET_SO_RCVBUFFORCE 33
#define TARGET_SO_PASSSEC 34
+#define TARGET_SO_TIMESTAMP_OLD 29
+#define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD
+
+#define TARGET_SO_TIMESTAMP_NEW 63
+#define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW
+
/** sock_type - Socket types
*
* Please notice that for binary compat reasons MIPS has to
diff --git a/linux-user/sparc/sockbits.h b/linux-user/sparc/sockbits.h
index 0a822e3e1f..07440efd14 100644
--- a/linux-user/sparc/sockbits.h
+++ b/linux-user/sparc/sockbits.h
@@ -48,8 +48,6 @@
#define TARGET_SO_GET_FILTER TARGET_SO_ATTACH_FILTER
#define TARGET_SO_PEERNAME 0x001c
-#define TARGET_SO_TIMESTAMP 0x001d
-#define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP
#define TARGET_SO_PEERSEC 0x001e
#define TARGET_SO_PASSSEC 0x001f
@@ -104,6 +102,12 @@
#define TARGET_SO_ZEROCOPY 0x003e
+#define TARGET_SO_TIMESTAMP_OLD 0x001d
+#define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD
+
+#define TARGET_SO_TIMESTAMP_NEW 0x0046
+#define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW
+
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define TARGET_SO_SECURITY_AUTHENTICATION 0x5001
#define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
diff --git a/linux-user/strace.c b/linux-user/strace.c
index e00275fcb5..1a4dd13fe8 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -2679,8 +2679,11 @@ print_optint:
case TARGET_SO_PASSCRED:
qemu_log("SO_PASSCRED,");
goto print_optint;
- case TARGET_SO_TIMESTAMP:
- qemu_log("SO_TIMESTAMP,");
+ case TARGET_SO_TIMESTAMP_OLD:
+ qemu_log("SO_TIMESTAMP_OLD,");
+ goto print_optint;
+ case TARGET_SO_TIMESTAMP_NEW:
+ qemu_log("SO_TIMESTAMP_NEW,");
goto print_optint;
case TARGET_SO_RCVLOWAT:
qemu_log("SO_RCVLOWAT,");
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 7bf99beb18..ddeca7bfd2 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -1934,6 +1934,18 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
return 0;
}
+/*
+ * Linux kernel actually keeps track of whether the old version (potentially
+ * 32-bit time_t) or the new version is used for each socket. Instead of
+ * replicate it will all the complexity, we only keep track of one global state,
+ * which is enough for guest programs that don't intentionally mix the two
+ * versions.
+ */
+static enum TargetTimestampVersion {
+ TARGET_TIMESTAMP_OLD,
+ TARGET_TIMESTAMP_NEW,
+} target_expected_timestamp_version = TARGET_TIMESTAMP_OLD;
+
static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
struct msghdr *msgh)
{
@@ -1984,8 +1996,17 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
switch (cmsg->cmsg_level) {
case SOL_SOCKET:
switch (cmsg->cmsg_type) {
- case SO_TIMESTAMP:
- tgt_len = sizeof(struct target_timeval);
+ case SCM_TIMESTAMP:
+ switch (target_expected_timestamp_version) {
+ case TARGET_TIMESTAMP_OLD:
+ tgt_len = sizeof(struct target_timeval);
+ target_cmsg->cmsg_type = tswap32(TARGET_SCM_TIMESTAMP_OLD);
+ break;
+ case TARGET_TIMESTAMP_NEW:
+ tgt_len = sizeof(struct target__kernel_sock_timeval);
+ target_cmsg->cmsg_type = tswap32(TARGET_SCM_TIMESTAMP_NEW);
+ break;
+ }
break;
default:
break;
@@ -2019,20 +2040,39 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
}
break;
}
- case SO_TIMESTAMP:
+ case SCM_TIMESTAMP:
{
struct timeval *tv = (struct timeval *)data;
- struct target_timeval *target_tv =
- (struct target_timeval *)target_data;
-
- if (len != sizeof(struct timeval) ||
- tgt_len != sizeof(struct target_timeval)) {
+ if (len != sizeof(struct timeval)) {
goto unimplemented;
}
- /* copy struct timeval to target */
- __put_user(tv->tv_sec, &target_tv->tv_sec);
- __put_user(tv->tv_usec, &target_tv->tv_usec);
+ switch (target_expected_timestamp_version) {
+ case TARGET_TIMESTAMP_OLD:
+ {
+ struct target_timeval *target_tv =
+ (struct target_timeval *)target_data;
+ if (tgt_len != sizeof(struct target_timeval)) {
+ goto unimplemented;
+ }
+
+ __put_user(tv->tv_sec, &target_tv->tv_sec);
+ __put_user(tv->tv_usec, &target_tv->tv_usec);
+ break;
+ }
+ case TARGET_TIMESTAMP_NEW:
+ {
+ struct target__kernel_sock_timeval *target_tv =
+ (struct target__kernel_sock_timeval *)target_data;
+ if (tgt_len != sizeof(struct target__kernel_sock_timeval)) {
+ goto unimplemented;
+ }
+
+ __put_user(tv->tv_sec, &target_tv->tv_sec);
+ __put_user(tv->tv_usec, &target_tv->tv_usec);
+ break;
+ }
+ }
break;
}
case SCM_CREDENTIALS:
@@ -2174,6 +2214,8 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
int val;
struct ip_mreqn *ip_mreq;
struct ip_mreq_source *ip_mreq_source;
+ enum TargetTimestampVersion target_timestamp_version =
+ target_expected_timestamp_version;
switch(level) {
case SOL_TCP:
@@ -2566,9 +2608,14 @@ set_timeout:
case TARGET_SO_PASSSEC:
optname = SO_PASSSEC;
break;
- case TARGET_SO_TIMESTAMP:
- optname = SO_TIMESTAMP;
- break;
+ case TARGET_SO_TIMESTAMP_OLD:
+ target_timestamp_version = TARGET_TIMESTAMP_OLD;
+ optname = SO_TIMESTAMP;
+ break;
+ case TARGET_SO_TIMESTAMP_NEW:
+ target_timestamp_version = TARGET_TIMESTAMP_NEW;
+ optname = SO_TIMESTAMP;
+ break;
case TARGET_SO_RCVLOWAT:
optname = SO_RCVLOWAT;
break;
@@ -2581,6 +2628,9 @@ set_timeout:
if (get_user_u32(val, optval_addr))
return -TARGET_EFAULT;
ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
+ if (!is_error(ret) && optname == SO_TIMESTAMP) {
+ target_expected_timestamp_version = target_timestamp_version;
+ }
break;
#ifdef SOL_NETLINK
case SOL_NETLINK:
@@ -2631,6 +2681,7 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
abi_long ret;
int len, val;
socklen_t lv;
+ int timestamp_format_matches = 0;
switch(level) {
case TARGET_SOL_SOCKET:
@@ -2811,7 +2862,14 @@ get_timeout:
case TARGET_SO_PASSCRED:
optname = SO_PASSCRED;
goto int_case;
- case TARGET_SO_TIMESTAMP:
+ case TARGET_SO_TIMESTAMP_OLD:
+ timestamp_format_matches =
+ (target_expected_timestamp_version == TARGET_TIMESTAMP_OLD);
+ optname = SO_TIMESTAMP;
+ goto int_case;
+ case TARGET_SO_TIMESTAMP_NEW:
+ timestamp_format_matches =
+ (target_expected_timestamp_version == TARGET_TIMESTAMP_NEW);
optname = SO_TIMESTAMP;
goto int_case;
case TARGET_SO_RCVLOWAT:
@@ -2838,6 +2896,9 @@ get_timeout:
if (optname == SO_TYPE) {
val = host_to_target_sock_type(val);
}
+ if (optname == SO_TIMESTAMP) {
+ val = val && timestamp_format_matches;
+ }
if (len > lv)
len = lv;
if (len == 4) {
diff --git a/tests/tcg/multiarch/socket_timestamp.c b/tests/tcg/multiarch/socket_timestamp.c
new file mode 100644
index 0000000000..71ab1845de
--- /dev/null
+++ b/tests/tcg/multiarch/socket_timestamp.c
@@ -0,0 +1,296 @@
+#include <assert.h>
+#include <errno.h>
+#include <linux/types.h>
+#include <netinet/in.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#ifdef __kernel_old_timeval
+#define kernel_old_timeval __kernel_old_timeval
+#else
+struct kernel_old_timeval {
+ __kernel_long_t tv_sec;
+ __kernel_long_t tv_usec;
+};
+#endif
+
+struct kernel_sock_timeval {
+ int64_t tv_sec;
+ int64_t tv_usec;
+};
+
+int create_udp_socket(struct sockaddr_in *sockaddr)
+{
+ socklen_t sockaddr_len;
+ int sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ int err = errno;
+ fprintf(stderr, "Failed to create server socket: %s\n", strerror(err));
+ exit(err);
+ }
+
+ memset(sockaddr, 0, sizeof(*sockaddr));
+ sockaddr->sin_family = AF_INET;
+ sockaddr->sin_port = htons(0); /* let kernel select a port for us */
+ sockaddr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ if (bind(sock, (struct sockaddr *)sockaddr, sizeof(*sockaddr)) < 0) {
+ int err = errno;
+ fprintf(stderr, "Failed to bind server socket: %s\n", strerror(err));
+ exit(err);
+ }
+
+ sockaddr_len = sizeof(*sockaddr);
+ if (getsockname(sock, (struct sockaddr *)sockaddr, &sockaddr_len) < 0) {
+ int err = errno;
+ fprintf(stderr, "Failed to get socket name: %s\n", strerror(err));
+ exit(err);
+ }
+ return sock;
+}
+
+/*
+ * Checks that the timestamp in the message is not after the reception timestamp
+ * as well as the reception time is within 10 seconds of the message time.
+ */
+void check_timestamp_difference(const struct timeval *msg_tv,
+ const struct timeval *pkt_tv)
+{
+ if (pkt_tv->tv_sec < msg_tv->tv_sec ||
+ (pkt_tv->tv_sec == msg_tv->tv_sec && pkt_tv->tv_usec < msg_tv->tv_usec))
+ {
+ fprintf(stderr,
+ "Packet received before sent: %lld.%06lld < %lld.%06lld\n",
+ (long long)pkt_tv->tv_sec, (long long)pkt_tv->tv_usec,
+ (long long)msg_tv->tv_sec, (long long)msg_tv->tv_usec);
+ exit(-1);
+ }
+
+ if (pkt_tv->tv_sec > msg_tv->tv_sec + 10 ||
+ (pkt_tv->tv_sec == msg_tv->tv_sec + 10 &&
+ pkt_tv->tv_usec > msg_tv->tv_usec)) {
+ fprintf(stderr,
+ "Packet received more than 10 seconds after sent: "
+ "%lld.%06lld > %lld.%06lld + 10\n",
+ (long long)pkt_tv->tv_sec, (long long)pkt_tv->tv_usec,
+ (long long)msg_tv->tv_sec, (long long)msg_tv->tv_usec);
+ exit(-1);
+ }
+}
+
+void send_current_time(int sock, struct sockaddr_in server_sockaddr)
+{
+ struct timeval tv = {0, 0};
+ gettimeofday(&tv, NULL);
+ sendto(sock, &tv, sizeof(tv), 0, (struct sockaddr *)&server_sockaddr,
+ sizeof(server_sockaddr));
+}
+
+typedef void (*get_timeval_t)(const struct cmsghdr *cmsg, struct timeval *tv);
+
+
+void receive_packet(int sock, get_timeval_t get_timeval)
+{
+ struct msghdr msg = {0};
+
+ char iobuf[1024];
+ struct iovec iov;
+
+ union {
+ /*
+ * 128 bytes are enough for all existing
+ * timeval/timespec/scm_timestamping structures.
+ */
+ char cmsg_buf[CMSG_SPACE(128)];
+ struct cmsghdr align;
+ } u;
+ struct cmsghdr *cmsg;
+ struct timeval msg_tv, pkt_tv;
+
+ int res;
+
+ iov.iov_base = iobuf;
+ iov.iov_len = sizeof(iobuf);
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = (caddr_t)u.cmsg_buf;
+ msg.msg_controllen = sizeof(u.cmsg_buf);
+
+ res = recvmsg(sock, &msg, 0);
+ if (res < 0) {
+ int err = errno;
+ fprintf(stderr, "Failed to receive packet: %s\n", strerror(err));
+ exit(err);
+ }
+
+ assert(res == sizeof(struct timeval));
+ assert(iov.iov_base == iobuf);
+ memcpy(&msg_tv, iov.iov_base, sizeof(msg_tv));
+ printf("Message timestamp: %lld.%06lld\n",
+ (long long)msg_tv.tv_sec, (long long)msg_tv.tv_usec);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ assert(cmsg);
+ (*get_timeval)(cmsg, &pkt_tv);
+ printf("Packet timestamp: %lld.%06lld\n",
+ (long long)pkt_tv.tv_sec, (long long)pkt_tv.tv_usec);
+
+ check_timestamp_difference(&msg_tv, &pkt_tv);
+}
+
+void get_timeval_from_so_timestamp(const struct cmsghdr *cmsg,
+ struct timeval *tv)
+{
+ assert(cmsg->cmsg_level == SOL_SOCKET);
+ assert(cmsg->cmsg_type == SCM_TIMESTAMP);
+ assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)));
+ memcpy(tv, CMSG_DATA(cmsg), sizeof(*tv));
+}
+
+#ifdef SO_TIMESTAMP_OLD
+void get_timeval_from_so_timestamp_old(const struct cmsghdr *cmsg,
+ struct timeval *tv)
+{
+ struct kernel_old_timeval old_tv;
+ assert(cmsg->cmsg_level == SOL_SOCKET);
+ assert(cmsg->cmsg_type == SO_TIMESTAMP_OLD);
+ assert(cmsg->cmsg_len == CMSG_LEN(sizeof(old_tv)));
+
+ memcpy(&old_tv, CMSG_DATA(cmsg), sizeof(old_tv));
+ tv->tv_sec = old_tv.tv_sec;
+ tv->tv_usec = old_tv.tv_usec;
+}
+
+#ifdef SO_TIMESTAMP_NEW
+void get_timeval_from_so_timestamp_new(const struct cmsghdr *cmsg,
+ struct timeval *tv)
+{
+ struct kernel_sock_timeval sock_tv;
+ assert(cmsg->cmsg_level == SOL_SOCKET);
+ assert(cmsg->cmsg_type == SO_TIMESTAMP_NEW);
+ assert(cmsg->cmsg_len == CMSG_LEN(sizeof(sock_tv)));
+
+ memcpy(&sock_tv, CMSG_DATA(cmsg), sizeof(sock_tv));
+ tv->tv_sec = sock_tv.tv_sec;
+ tv->tv_usec = sock_tv.tv_usec;
+}
+#endif /* defined(SO_TIMESTAMP_NEW) */
+#endif /* defined(SO_TIMESTAMP_OLD) */
+
+void set_socket_option(int sock, int sockopt, int on)
+{
+ socklen_t len;
+ int val = on;
+ if (setsockopt(sock, SOL_SOCKET, sockopt, &val, sizeof(val)) < 0) {
+ int err = errno;
+ fprintf(stderr, "Failed to setsockopt %d (%s): %s\n",
+ sockopt, on ? "on" : "off", strerror(err));
+ exit(err);
+ }
+
+ len = sizeof(val);
+ val = -1;
+ if (getsockopt(sock, SOL_SOCKET, sockopt, &val, &len) < 0) {
+ int err = errno;
+ fprintf(stderr, "Failed to getsockopt (%d): %s\n", sock, strerror(err));
+ exit(err);
+ }
+ assert(len == sizeof(val));
+ assert(val == on);
+}
+
+int main(int argc, char **argv)
+{
+ int parent_sock, child_sock;
+ struct sockaddr_in parent_sockaddr, child_sockaddr;
+ int pid;
+ struct timeval tv = {0, 0};
+ gettimeofday(&tv, NULL);
+
+ parent_sock = create_udp_socket(&parent_sockaddr);
+ child_sock = create_udp_socket(&child_sockaddr);
+
+ printf("Parent sock bound to port %d\nChild sock bound to port %d\n",
+ parent_sockaddr.sin_port, child_sockaddr.sin_port);
+
+ pid = fork();
+ if (pid < 0) {
+ fprintf(stderr, "SKIPPED. Failed to fork: %s\n", strerror(errno));
+ } else if (pid == 0) {
+ close(child_sock);
+
+ /* Test 1: SO_TIMESTAMP */
+ send_current_time(parent_sock, child_sockaddr);
+
+ if (tv.tv_sec > 0x7fffff00) {
+ /* Too close to y2038 problem, old system may not work. */
+ close(parent_sock);
+ return 0;
+ }
+
+#ifdef SO_TIMESTAMP_OLD
+ if (SO_TIMESTAMP_OLD != SO_TIMESTAMP) {
+ /* Test 2a: SO_TIMESTAMP_OLD */
+ set_socket_option(parent_sock, SO_TIMESTAMP_OLD, 1);
+ receive_packet(parent_sock, &get_timeval_from_so_timestamp_old);
+ set_socket_option(parent_sock, SO_TIMESTAMP_OLD, 0);
+ }
+#ifdef SO_TIMESTAMP_NEW
+ else {
+ /* Test 2b: SO_TIMESTAMP_NEW */
+ set_socket_option(parent_sock, SO_TIMESTAMP_NEW, 1);
+ receive_packet(parent_sock, &get_timeval_from_so_timestamp_new);
+ set_socket_option(parent_sock, SO_TIMESTAMP_NEW, 0);
+ }
+#endif /* defined(SO_TIMESTAMP_NEW) */
+#endif /* defined(SO_TIMESTAMP_OLD) */
+
+ close(parent_sock);
+ } else {
+ int child_status;
+ close(parent_sock);
+
+ /* Test 1: SO_TIMESTAMP */
+ set_socket_option(child_sock, SO_TIMESTAMP, 1);
+ receive_packet(child_sock, &get_timeval_from_so_timestamp);
+ set_socket_option(child_sock, SO_TIMESTAMP, 0);
+
+ if (tv.tv_sec > 0x7fffff00) {
+ /* Too close to y2038 problem, old system may not work. */
+ close(child_sock);
+ return 0;
+ }
+
+#ifdef SO_TIMESTAMP_OLD
+ if (SO_TIMESTAMP_OLD != SO_TIMESTAMP) {
+ /* Test 2a: SO_TIMESTAMP_OLD */
+ send_current_time(child_sock, parent_sockaddr);
+ }
+#ifdef SO_TIMESTAMP_NEW
+ else {
+ /* Test 2b: SO_TIMESTAMP_NEW */
+ send_current_time(child_sock, parent_sockaddr);
+ }
+#endif /* defined(SO_TIMESTAMP_NEW) */
+#endif /* defined(SO_TIMESTAMP_OLD) */
+
+ close(child_sock);
+
+ if (waitpid(pid, &child_status, 0) < 0) {
+ int err = errno;
+ fprintf(stderr, "Final wait() failed: %s\n", strerror(err));
+ return err;
+ }
+ return child_status;
+ }
+ return 0;
+}
--
2.29.2.684.gfbc64c5ab5-goog
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH v3 2/2] linux-user: setsockopt() SO_TIMESTAMPNS and SO_TIMESTAMPING
2020-12-18 19:54 [PATCH v3 0/2] linux-user: SO_TIMESTAMP/NS/ING sockopt Shu-Chun Weng via
2020-12-18 19:54 ` [PATCH v3 1/2] linux-user: Update SO_TIMESTAMP to SO_TIMESTAMP_OLD/NEW Shu-Chun Weng via
@ 2020-12-18 19:54 ` Shu-Chun Weng via
1 sibling, 0 replies; 3+ messages in thread
From: Shu-Chun Weng via @ 2020-12-18 19:54 UTC (permalink / raw)
To: qemu-devel, laurent; +Cc: Shu-Chun Weng
This change supports SO_TIMESTAMPNS_OLD/NEW and SO_TIMESTAMPING_OLD/NEW
for setsocketopt() with SOL_SOCKET. Based on the SO_TIMESTAMP_OLD/NEW
framework. The three pairs share the same flag `SOCK_TSTAMP_NEW` in
linux kernel for deciding if the old or the new format is used.
Signed-off-by: Shu-Chun Weng <scw@google.com>
---
v1 -> v2:
Only keep track of old/new format in a global state.
Fix style problems.
v2 -> v3:
Rebase to master on Dec 18, 2020
linux-user/alpha/sockbits.h | 13 +-
linux-user/generic/sockbits.h | 8 +
linux-user/hppa/sockbits.h | 12 +-
linux-user/mips/sockbits.h | 8 +
linux-user/sparc/sockbits.h | 13 +-
linux-user/strace.c | 12 +
linux-user/syscall.c | 149 ++++++++-
tests/tcg/multiarch/socket_timestamp.c | 442 +++++++++++++++++++------
8 files changed, 540 insertions(+), 117 deletions(-)
diff --git a/linux-user/alpha/sockbits.h b/linux-user/alpha/sockbits.h
index 40f0644df0..c2c88f432b 100644
--- a/linux-user/alpha/sockbits.h
+++ b/linux-user/alpha/sockbits.h
@@ -51,8 +51,6 @@
#define TARGET_SO_PEERSEC 30
#define TARGET_SO_PASSSEC 34
-#define TARGET_SO_TIMESTAMPNS 35
-#define TARGET_SCM_TIMESTAMPNS TARGET_SO_TIMESTAMPNS
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define TARGET_SO_SECURITY_AUTHENTICATION 19
@@ -61,9 +59,6 @@
#define TARGET_SO_MARK 36
-#define TARGET_SO_TIMESTAMPING 37
-#define TARGET_SCM_TIMESTAMPING TARGET_SO_TIMESTAMPING
-
#define TARGET_SO_RXQ_OVFL 40
#define TARGET_SO_WIFI_STATUS 41
@@ -75,9 +70,17 @@
#define TARGET_SO_TIMESTAMP_OLD 29
#define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD
+#define TARGET_SO_TIMESTAMPNS_OLD 35
+#define TARGET_SCM_TIMESTAMPNS_OLD TARGET_SO_TIMESTAMPNS_OLD
+#define TARGET_SO_TIMESTAMPING_OLD 37
+#define TARGET_SCM_TIMESTAMPING_OLD TARGET_SO_TIMESTAMPING_OLD
#define TARGET_SO_TIMESTAMP_NEW 63
#define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW
+#define TARGET_SO_TIMESTAMPNS_NEW 64
+#define TARGET_SCM_TIMESTAMPNS_NEW TARGET_SO_TIMESTAMPNS_NEW
+#define TARGET_SO_TIMESTAMPING_NEW 65
+#define TARGET_SCM_TIMESTAMPING_NEW TARGET_SO_TIMESTAMPING_NEW
/* TARGET_O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here.
diff --git a/linux-user/generic/sockbits.h b/linux-user/generic/sockbits.h
index 532cf2d3dc..a0496d8751 100644
--- a/linux-user/generic/sockbits.h
+++ b/linux-user/generic/sockbits.h
@@ -56,8 +56,16 @@
#define TARGET_SO_TIMESTAMP_OLD 29
#define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD
+#define TARGET_SO_TIMESTAMPNS_OLD 35
+#define TARGET_SCM_TIMESTAMPNS_OLD TARGET_SO_TIMESTAMPNS_OLD
+#define TARGET_SO_TIMESTAMPING_OLD 37
+#define TARGET_SCM_TIMESTAMPING_OLD TARGET_SO_TIMESTAMPING_OLD
#define TARGET_SO_TIMESTAMP_NEW 63
#define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW
+#define TARGET_SO_TIMESTAMPNS_NEW 64
+#define TARGET_SCM_TIMESTAMPNS_NEW TARGET_SO_TIMESTAMPNS_NEW
+#define TARGET_SO_TIMESTAMPING_NEW 65
+#define TARGET_SCM_TIMESTAMPING_NEW TARGET_SO_TIMESTAMPING_NEW
#endif
diff --git a/linux-user/hppa/sockbits.h b/linux-user/hppa/sockbits.h
index 284a47e74e..d7e9aa340d 100644
--- a/linux-user/hppa/sockbits.h
+++ b/linux-user/hppa/sockbits.h
@@ -29,8 +29,6 @@
#define TARGET_SO_BSDCOMPAT 0x400e
#define TARGET_SO_PASSCRED 0x4010
#define TARGET_SO_PEERCRED 0x4011
-#define TARGET_SO_TIMESTAMPNS 0x4013
-#define TARGET_SCM_TIMESTAMPNS TARGET_SO_TIMESTAMPNS
#define TARGET_SO_SECURITY_AUTHENTICATION 0x4016
#define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 0x4017
@@ -44,8 +42,6 @@
#define TARGET_SO_PEERSEC 0x401d
#define TARGET_SO_PASSSEC 0x401e
#define TARGET_SO_MARK 0x401f
-#define TARGET_SO_TIMESTAMPING 0x4020
-#define TARGET_SCM_TIMESTAMPING TARGET_SO_TIMESTAMPING
#define TARGET_SO_RXQ_OVFL 0x4021
#define TARGET_SO_WIFI_STATUS 0x4022
#define TARGET_SCM_WIFI_STATUS TARGET_SO_WIFI_STATUS
@@ -67,9 +63,17 @@
#define TARGET_SO_TIMESTAMP_OLD 0x4012
#define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD
+#define TARGET_SO_TIMESTAMPNS_OLD 0x4013
+#define TARGET_SCM_TIMESTAMPNS_OLD TARGET_SO_TIMESTAMPNS_OLD
+#define TARGET_SO_TIMESTAMPING_OLD 0x4020
+#define TARGET_SCM_TIMESTAMPING_OLD TARGET_SO_TIMESTAMPING_OLD
#define TARGET_SO_TIMESTAMP_NEW 0x4038
#define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW
+#define TARGET_SO_TIMESTAMPNS_NEW 0x4039
+#define TARGET_SCM_TIMESTAMPNS_NEW TARGET_SO_TIMESTAMPNS_NEW
+#define TARGET_SO_TIMESTAMPING_NEW 0x403A
+#define TARGET_SCM_TIMESTAMPING_NEW TARGET_SO_TIMESTAMPING_NEW
/* TARGET_O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here.
diff --git a/linux-user/mips/sockbits.h b/linux-user/mips/sockbits.h
index b4c39d9588..49524e23ac 100644
--- a/linux-user/mips/sockbits.h
+++ b/linux-user/mips/sockbits.h
@@ -69,9 +69,17 @@
#define TARGET_SO_TIMESTAMP_OLD 29
#define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD
+#define TARGET_SO_TIMESTAMPNS_OLD 35
+#define TARGET_SCM_TIMESTAMPNS_OLD TARGET_SO_TIMESTAMPNS_OLD
+#define TARGET_SO_TIMESTAMPING_OLD 37
+#define TARGET_SCM_TIMESTAMPING_OLD TARGET_SO_TIMESTAMPING_OLD
#define TARGET_SO_TIMESTAMP_NEW 63
#define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW
+#define TARGET_SO_TIMESTAMPNS_NEW 64
+#define TARGET_SCM_TIMESTAMPNS_NEW TARGET_SO_TIMESTAMPNS_NEW
+#define TARGET_SO_TIMESTAMPING_NEW 65
+#define TARGET_SCM_TIMESTAMPING_NEW TARGET_SO_TIMESTAMPING_NEW
/** sock_type - Socket types
*
diff --git a/linux-user/sparc/sockbits.h b/linux-user/sparc/sockbits.h
index 07440efd14..c5fade3ad1 100644
--- a/linux-user/sparc/sockbits.h
+++ b/linux-user/sparc/sockbits.h
@@ -51,14 +51,9 @@
#define TARGET_SO_PEERSEC 0x001e
#define TARGET_SO_PASSSEC 0x001f
-#define TARGET_SO_TIMESTAMPNS 0x0021
-#define TARGET_SCM_TIMESTAMPNS TARGET_SO_TIMESTAMPNS
#define TARGET_SO_MARK 0x0022
-#define TARGET_SO_TIMESTAMPING 0x0023
-#define TARGET_SCM_TIMESTAMPING TARGET_SO_TIMESTAMPING
-
#define TARGET_SO_RXQ_OVFL 0x0024
#define TARGET_SO_WIFI_STATUS 0x0025
@@ -104,9 +99,17 @@
#define TARGET_SO_TIMESTAMP_OLD 0x001d
#define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD
+#define TARGET_SO_TIMESTAMPNS_OLD 0x0021
+#define TARGET_SCM_TIMESTAMPNS_OLD TARGET_SO_TIMESTAMPNS_OLD
+#define TARGET_SO_TIMESTAMPING_OLD 0x0023
+#define TARGET_SCM_TIMESTAMPING_OLD TARGET_SO_TIMESTAMPING_OLD
#define TARGET_SO_TIMESTAMP_NEW 0x0046
#define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW
+#define TARGET_SO_TIMESTAMPNS_NEW 0x0042
+#define TARGET_SCM_TIMESTAMPNS_NEW TARGET_SO_TIMESTAMPNS_NEW
+#define TARGET_SO_TIMESTAMPING_NEW 0x0043
+#define TARGET_SCM_TIMESTAMPING_NEW TARGET_SO_TIMESTAMPING_NEW
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define TARGET_SO_SECURITY_AUTHENTICATION 0x5001
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 1a4dd13fe8..563e87bfaa 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -2682,9 +2682,21 @@ print_optint:
case TARGET_SO_TIMESTAMP_OLD:
qemu_log("SO_TIMESTAMP_OLD,");
goto print_optint;
+ case TARGET_SO_TIMESTAMPNS_OLD:
+ qemu_log("SO_TIMESTAMPNS_OLD,");
+ goto print_optint;
+ case TARGET_SO_TIMESTAMPING_OLD:
+ qemu_log("SO_TIMESTAMPING_OLD,");
+ goto print_optint;
case TARGET_SO_TIMESTAMP_NEW:
qemu_log("SO_TIMESTAMP_NEW,");
goto print_optint;
+ case TARGET_SO_TIMESTAMPNS_NEW:
+ qemu_log("SO_TIMESTAMPNS_NEW,");
+ goto print_optint;
+ case TARGET_SO_TIMESTAMPING_NEW:
+ qemu_log("SO_TIMESTAMPING_NEW,");
+ goto print_optint;
case TARGET_SO_RCVLOWAT:
qemu_log("SO_RCVLOWAT,");
goto print_optint;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index ddeca7bfd2..4f834b16ab 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -2008,6 +2008,34 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
break;
}
break;
+ case SCM_TIMESTAMPNS:
+ switch (target_expected_timestamp_version) {
+ case TARGET_TIMESTAMP_OLD:
+ tgt_len = sizeof(struct target_timespec);
+ target_cmsg->cmsg_type =
+ tswap32(TARGET_SCM_TIMESTAMPNS_OLD);
+ break;
+ case TARGET_TIMESTAMP_NEW:
+ tgt_len = sizeof(struct target__kernel_timespec);
+ target_cmsg->cmsg_type =
+ tswap32(TARGET_SCM_TIMESTAMPNS_NEW);
+ break;
+ }
+ break;
+ case SCM_TIMESTAMPING:
+ switch (target_expected_timestamp_version) {
+ case TARGET_TIMESTAMP_OLD:
+ tgt_len = sizeof(struct target_timespec[3]);
+ target_cmsg->cmsg_type =
+ tswap32(TARGET_SCM_TIMESTAMPING_OLD);
+ break;
+ case TARGET_TIMESTAMP_NEW:
+ tgt_len = sizeof(struct target__kernel_timespec[3]);
+ target_cmsg->cmsg_type =
+ tswap32(TARGET_SCM_TIMESTAMPING_NEW);
+ break;
+ }
+ break;
default:
break;
}
@@ -2075,6 +2103,81 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
}
break;
}
+ case SCM_TIMESTAMPNS:
+ {
+ struct timespec *ts = (struct timespec *)data;
+ if (len != sizeof(struct timespec)) {
+ goto unimplemented;
+ }
+
+ switch (target_expected_timestamp_version) {
+ case TARGET_TIMESTAMP_OLD:
+ {
+ struct target_timespec *target_ts =
+ (struct target_timespec *)target_data;
+ if (tgt_len != sizeof(struct target_timespec)) {
+ goto unimplemented;
+ }
+
+ __put_user(ts->tv_sec, &target_ts->tv_sec);
+ __put_user(ts->tv_nsec, &target_ts->tv_nsec);
+ break;
+ }
+ case TARGET_TIMESTAMP_NEW:
+ {
+ struct target__kernel_timespec *target_ts =
+ (struct target__kernel_timespec *)target_data;
+ if (tgt_len != sizeof(struct target__kernel_timespec)) {
+ goto unimplemented;
+ }
+
+ __put_user(ts->tv_sec, &target_ts->tv_sec);
+ __put_user(ts->tv_nsec, &target_ts->tv_nsec);
+ break;
+ }
+ }
+ break;
+ }
+ case SCM_TIMESTAMPING:
+ {
+ int i;
+ struct timespec *ts = (struct timespec *)data;
+ if (len != sizeof(struct timespec[3])) {
+ goto unimplemented;
+ }
+
+ switch (target_expected_timestamp_version) {
+ case TARGET_TIMESTAMP_OLD:
+ {
+ struct target_timespec *target_ts =
+ (struct target_timespec *)target_data;
+ if (tgt_len != sizeof(struct target_timespec[3])) {
+ goto unimplemented;
+ }
+
+ for (i = 0; i < 3; ++i) {
+ __put_user(ts[i].tv_sec, &target_ts[i].tv_sec);
+ __put_user(ts[i].tv_nsec, &target_ts[i].tv_nsec);
+ }
+ break;
+ }
+ case TARGET_TIMESTAMP_NEW:
+ {
+ struct target__kernel_timespec *target_ts =
+ (struct target__kernel_timespec *)target_data;
+ if (tgt_len != sizeof(struct target__kernel_timespec[3])) {
+ goto unimplemented;
+ }
+
+ for (i = 0; i < 3; ++i) {
+ __put_user(ts[i].tv_sec, &target_ts[i].tv_sec);
+ __put_user(ts[i].tv_nsec, &target_ts[i].tv_nsec);
+ }
+ break;
+ }
+ }
+ break;
+ }
case SCM_CREDENTIALS:
{
struct ucred *cred = (struct ucred *)data;
@@ -2616,6 +2719,22 @@ set_timeout:
target_timestamp_version = TARGET_TIMESTAMP_NEW;
optname = SO_TIMESTAMP;
break;
+ case TARGET_SO_TIMESTAMPNS_OLD:
+ target_timestamp_version = TARGET_TIMESTAMP_OLD;
+ optname = SO_TIMESTAMPNS;
+ break;
+ case TARGET_SO_TIMESTAMPNS_NEW:
+ target_timestamp_version = TARGET_TIMESTAMP_NEW;
+ optname = SO_TIMESTAMPNS;
+ break;
+ case TARGET_SO_TIMESTAMPING_OLD:
+ target_timestamp_version = TARGET_TIMESTAMP_OLD;
+ optname = SO_TIMESTAMPING;
+ break;
+ case TARGET_SO_TIMESTAMPING_NEW:
+ target_timestamp_version = TARGET_TIMESTAMP_NEW;
+ optname = SO_TIMESTAMPING;
+ break;
case TARGET_SO_RCVLOWAT:
optname = SO_RCVLOWAT;
break;
@@ -2628,7 +2747,9 @@ set_timeout:
if (get_user_u32(val, optval_addr))
return -TARGET_EFAULT;
ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
- if (!is_error(ret) && optname == SO_TIMESTAMP) {
+ if (!is_error(ret) &&
+ (optname == SO_TIMESTAMP || optname == SO_TIMESTAMPNS ||
+ optname == SO_TIMESTAMPING)) {
target_expected_timestamp_version = target_timestamp_version;
}
break;
@@ -2872,6 +2993,26 @@ get_timeout:
(target_expected_timestamp_version == TARGET_TIMESTAMP_NEW);
optname = SO_TIMESTAMP;
goto int_case;
+ case TARGET_SO_TIMESTAMPNS_OLD:
+ timestamp_format_matches =
+ (target_expected_timestamp_version == TARGET_TIMESTAMP_OLD);
+ optname = SO_TIMESTAMPNS;
+ goto int_case;
+ case TARGET_SO_TIMESTAMPNS_NEW:
+ timestamp_format_matches =
+ (target_expected_timestamp_version == TARGET_TIMESTAMP_NEW);
+ optname = SO_TIMESTAMPNS;
+ goto int_case;
+ case TARGET_SO_TIMESTAMPING_OLD:
+ timestamp_format_matches =
+ (target_expected_timestamp_version == TARGET_TIMESTAMP_OLD);
+ optname = SO_TIMESTAMPING;
+ goto int_case;
+ case TARGET_SO_TIMESTAMPING_NEW:
+ timestamp_format_matches =
+ (target_expected_timestamp_version == TARGET_TIMESTAMP_NEW);
+ optname = SO_TIMESTAMPING;
+ goto int_case;
case TARGET_SO_RCVLOWAT:
optname = SO_RCVLOWAT;
goto int_case;
@@ -2895,9 +3036,9 @@ get_timeout:
return ret;
if (optname == SO_TYPE) {
val = host_to_target_sock_type(val);
- }
- if (optname == SO_TIMESTAMP) {
- val = val && timestamp_format_matches;
+ } else if ((optname == SO_TIMESTAMP || optname == SO_TIMESTAMPNS ||
+ optname == SO_TIMESTAMPING) && !timestamp_format_matches) {
+ val = 0;
}
if (len > lv)
len = lv;
diff --git a/tests/tcg/multiarch/socket_timestamp.c b/tests/tcg/multiarch/socket_timestamp.c
index 71ab1845de..3ae833ad44 100644
--- a/tests/tcg/multiarch/socket_timestamp.c
+++ b/tests/tcg/multiarch/socket_timestamp.c
@@ -1,5 +1,6 @@
#include <assert.h>
#include <errno.h>
+#include <linux/net_tstamp.h>
#include <linux/types.h>
#include <netinet/in.h>
#include <stdint.h>
@@ -11,6 +12,7 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <time.h>
#include <unistd.h>
#ifdef __kernel_old_timeval
@@ -27,6 +29,33 @@ struct kernel_sock_timeval {
int64_t tv_usec;
};
+struct kernel_old_timespec {
+ __kernel_long_t tv_sec;
+ long tv_nsec;
+};
+
+struct kernel_timespec {
+ int64_t tv_sec;
+ long long tv_nsec;
+};
+
+struct scm_timestamping {
+ struct timespec ts[3];
+};
+
+struct scm_old_timestamping {
+ struct kernel_old_timespec ts[3];
+};
+
+struct scm_timestamping64 {
+ struct kernel_timespec ts[3];
+};
+
+const int so_timestamping_flags =
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE;
+
int create_udp_socket(struct sockaddr_in *sockaddr)
{
socklen_t sockaddr_len;
@@ -61,43 +90,47 @@ int create_udp_socket(struct sockaddr_in *sockaddr)
* Checks that the timestamp in the message is not after the reception timestamp
* as well as the reception time is within 10 seconds of the message time.
*/
-void check_timestamp_difference(const struct timeval *msg_tv,
- const struct timeval *pkt_tv)
+void check_timestamp_difference(const struct timespec *msg_ts,
+ const struct timespec *pkt_ts)
{
- if (pkt_tv->tv_sec < msg_tv->tv_sec ||
- (pkt_tv->tv_sec == msg_tv->tv_sec && pkt_tv->tv_usec < msg_tv->tv_usec))
+ if (pkt_ts->tv_sec < msg_ts->tv_sec ||
+ (pkt_ts->tv_sec == msg_ts->tv_sec && pkt_ts->tv_nsec < msg_ts->tv_nsec))
{
fprintf(stderr,
- "Packet received before sent: %lld.%06lld < %lld.%06lld\n",
- (long long)pkt_tv->tv_sec, (long long)pkt_tv->tv_usec,
- (long long)msg_tv->tv_sec, (long long)msg_tv->tv_usec);
+ "Packet received before sent: %lld.%06lld < %lld.%09lld\n",
+ (long long)pkt_ts->tv_sec, (long long)pkt_ts->tv_nsec,
+ (long long)msg_ts->tv_sec, (long long)msg_ts->tv_nsec);
exit(-1);
}
- if (pkt_tv->tv_sec > msg_tv->tv_sec + 10 ||
- (pkt_tv->tv_sec == msg_tv->tv_sec + 10 &&
- pkt_tv->tv_usec > msg_tv->tv_usec)) {
+ if (pkt_ts->tv_sec > msg_ts->tv_sec + 10 ||
+ (pkt_ts->tv_sec == msg_ts->tv_sec + 10 &&
+ pkt_ts->tv_nsec > msg_ts->tv_nsec)) {
fprintf(stderr,
"Packet received more than 10 seconds after sent: "
- "%lld.%06lld > %lld.%06lld + 10\n",
- (long long)pkt_tv->tv_sec, (long long)pkt_tv->tv_usec,
- (long long)msg_tv->tv_sec, (long long)msg_tv->tv_usec);
+ "%lld.%06lld > %lld.%09lld + 10\n",
+ (long long)pkt_ts->tv_sec, (long long)pkt_ts->tv_nsec,
+ (long long)msg_ts->tv_sec, (long long)msg_ts->tv_nsec);
exit(-1);
}
}
void send_current_time(int sock, struct sockaddr_in server_sockaddr)
{
- struct timeval tv = {0, 0};
- gettimeofday(&tv, NULL);
- sendto(sock, &tv, sizeof(tv), 0, (struct sockaddr *)&server_sockaddr,
+ struct timespec ts = {0, 0};
+ clock_gettime(CLOCK_REALTIME, &ts);
+#ifdef MSG_CONFIRM
+ const int flags = MSG_CONFIRM;
+#else
+ const int flags = 0;
+#endif
+ sendto(sock, &ts, sizeof(ts), flags, (struct sockaddr *)&server_sockaddr,
sizeof(server_sockaddr));
}
-typedef void (*get_timeval_t)(const struct cmsghdr *cmsg, struct timeval *tv);
+typedef void (*get_timespec_t)(const struct cmsghdr *cmsg, struct timespec *tv);
-
-void receive_packet(int sock, get_timeval_t get_timeval)
+void receive_packet(int sock, get_timespec_t get_timespec)
{
struct msghdr msg = {0};
@@ -113,7 +146,7 @@ void receive_packet(int sock, get_timeval_t get_timeval)
struct cmsghdr align;
} u;
struct cmsghdr *cmsg;
- struct timeval msg_tv, pkt_tv;
+ struct timespec msg_ts, pkt_ts;
int res;
@@ -134,31 +167,35 @@ void receive_packet(int sock, get_timeval_t get_timeval)
assert(res == sizeof(struct timeval));
assert(iov.iov_base == iobuf);
- memcpy(&msg_tv, iov.iov_base, sizeof(msg_tv));
- printf("Message timestamp: %lld.%06lld\n",
- (long long)msg_tv.tv_sec, (long long)msg_tv.tv_usec);
+ memcpy(&msg_ts, iov.iov_base, sizeof(msg_ts));
+ printf("Message timestamp: %lld.%09lld\n",
+ (long long)msg_ts.tv_sec, (long long)msg_ts.tv_nsec);
cmsg = CMSG_FIRSTHDR(&msg);
assert(cmsg);
- (*get_timeval)(cmsg, &pkt_tv);
- printf("Packet timestamp: %lld.%06lld\n",
- (long long)pkt_tv.tv_sec, (long long)pkt_tv.tv_usec);
+ (*get_timespec)(cmsg, &pkt_ts);
+ printf("Packet timestamp: %lld.%09lld\n",
+ (long long)pkt_ts.tv_sec, (long long)pkt_ts.tv_nsec);
- check_timestamp_difference(&msg_tv, &pkt_tv);
+ check_timestamp_difference(&msg_ts, &pkt_ts);
}
-void get_timeval_from_so_timestamp(const struct cmsghdr *cmsg,
- struct timeval *tv)
+void get_timespec_from_so_timestamp(const struct cmsghdr *cmsg,
+ struct timespec *ts)
{
+ struct timeval tv;
assert(cmsg->cmsg_level == SOL_SOCKET);
assert(cmsg->cmsg_type == SCM_TIMESTAMP);
- assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)));
- memcpy(tv, CMSG_DATA(cmsg), sizeof(*tv));
+ assert(cmsg->cmsg_len == CMSG_LEN(sizeof(tv)));
+
+ memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
+ ts->tv_sec = tv.tv_sec;
+ ts->tv_nsec = tv.tv_usec * 1000LL;
}
#ifdef SO_TIMESTAMP_OLD
-void get_timeval_from_so_timestamp_old(const struct cmsghdr *cmsg,
- struct timeval *tv)
+void get_timespec_from_so_timestamp_old(const struct cmsghdr *cmsg,
+ struct timespec *ts)
{
struct kernel_old_timeval old_tv;
assert(cmsg->cmsg_level == SOL_SOCKET);
@@ -166,13 +203,13 @@ void get_timeval_from_so_timestamp_old(const struct cmsghdr *cmsg,
assert(cmsg->cmsg_len == CMSG_LEN(sizeof(old_tv)));
memcpy(&old_tv, CMSG_DATA(cmsg), sizeof(old_tv));
- tv->tv_sec = old_tv.tv_sec;
- tv->tv_usec = old_tv.tv_usec;
+ ts->tv_sec = old_tv.tv_sec;
+ ts->tv_nsec = old_tv.tv_usec * 1000LL;
}
#ifdef SO_TIMESTAMP_NEW
-void get_timeval_from_so_timestamp_new(const struct cmsghdr *cmsg,
- struct timeval *tv)
+void get_timespec_from_so_timestamp_new(const struct cmsghdr *cmsg,
+ struct timespec *ts)
{
struct kernel_sock_timeval sock_tv;
assert(cmsg->cmsg_level == SOL_SOCKET);
@@ -180,42 +217,298 @@ void get_timeval_from_so_timestamp_new(const struct cmsghdr *cmsg,
assert(cmsg->cmsg_len == CMSG_LEN(sizeof(sock_tv)));
memcpy(&sock_tv, CMSG_DATA(cmsg), sizeof(sock_tv));
- tv->tv_sec = sock_tv.tv_sec;
- tv->tv_usec = sock_tv.tv_usec;
+ ts->tv_sec = sock_tv.tv_sec;
+ ts->tv_nsec = sock_tv.tv_usec * 1000LL;
}
#endif /* defined(SO_TIMESTAMP_NEW) */
#endif /* defined(SO_TIMESTAMP_OLD) */
-void set_socket_option(int sock, int sockopt, int on)
+void get_timespec_from_so_timestampns(const struct cmsghdr *cmsg,
+ struct timespec *ts)
+{
+ assert(cmsg->cmsg_level == SOL_SOCKET);
+ assert(cmsg->cmsg_type == SCM_TIMESTAMPNS);
+ assert(cmsg->cmsg_len == CMSG_LEN(sizeof(*ts)));
+
+ memcpy(ts, CMSG_DATA(cmsg), sizeof(*ts));
+}
+
+#ifdef SO_TIMESTAMPNS_OLD
+void get_timespec_from_so_timestampns_old(const struct cmsghdr *cmsg,
+ struct timespec *ts)
+{
+ struct kernel_old_timespec old_ts;
+ assert(cmsg->cmsg_level == SOL_SOCKET);
+ assert(cmsg->cmsg_type == SO_TIMESTAMPNS_OLD);
+ assert(cmsg->cmsg_len == CMSG_LEN(sizeof(old_ts)));
+
+ memcpy(&old_ts, CMSG_DATA(cmsg), sizeof(old_ts));
+ ts->tv_sec = old_ts.tv_sec;
+ ts->tv_nsec = old_ts.tv_nsec;
+}
+
+#ifdef SO_TIMESTAMPNS_NEW
+void get_timespec_from_so_timestampns_new(const struct cmsghdr *cmsg,
+ struct timespec *ts)
+{
+ struct kernel_timespec sock_ts;
+ assert(cmsg->cmsg_level == SOL_SOCKET);
+ assert(cmsg->cmsg_type == SO_TIMESTAMPNS_NEW);
+ assert(cmsg->cmsg_len == CMSG_LEN(sizeof(sock_ts)));
+
+ memcpy(&sock_ts, CMSG_DATA(cmsg), sizeof(sock_ts));
+ ts->tv_sec = sock_ts.tv_sec;
+ ts->tv_nsec = sock_ts.tv_nsec;
+}
+#endif /* defined(SO_TIMESTAMPNS_NEW) */
+#endif /* defined(SO_TIMESTAMPNS_OLD) */
+
+void get_timespec_from_so_timestamping(const struct cmsghdr *cmsg,
+ struct timespec *ts)
+{
+ int i;
+ struct scm_timestamping tss;
+ assert(cmsg->cmsg_level == SOL_SOCKET);
+ assert(cmsg->cmsg_type == SCM_TIMESTAMPING);
+ assert(cmsg->cmsg_len == CMSG_LEN(sizeof(tss)));
+
+ memcpy(&tss, CMSG_DATA(cmsg), sizeof(tss));
+
+ for (i = 0; i < 3; ++i) {
+ if (tss.ts[i].tv_sec || tss.ts[i].tv_nsec) {
+ *ts = tss.ts[i];
+ return;
+ }
+ }
+ assert(!"All three entries in scm_timestamping are empty");
+}
+
+#ifdef SO_TIMESTAMPING_OLD
+void get_timespec_from_so_timestamping_old(const struct cmsghdr *cmsg,
+ struct timespec *ts)
+{
+ int i;
+ struct scm_old_timestamping tss;
+ assert(cmsg->cmsg_level == SOL_SOCKET);
+ assert(cmsg->cmsg_type == SO_TIMESTAMPING_OLD);
+ assert(cmsg->cmsg_len == CMSG_LEN(sizeof(tss)));
+
+ memcpy(&tss, CMSG_DATA(cmsg), sizeof(tss));
+
+ for (i = 0; i < 3; ++i) {
+ if (tss.ts[i].tv_sec || tss.ts[i].tv_nsec) {
+ ts->tv_sec = tss.ts[i].tv_sec;
+ ts->tv_nsec = tss.ts[i].tv_nsec;
+ return;
+ }
+ }
+ assert(!"All three entries in scm_old_timestamping are empty");
+}
+
+#ifdef SO_TIMESTAMPING_NEW
+void get_timespec_from_so_timestamping_new(const struct cmsghdr *cmsg,
+ struct timespec *ts)
+{
+ int i;
+ struct scm_timestamping64 tss;
+ assert(cmsg->cmsg_level == SOL_SOCKET);
+ assert(cmsg->cmsg_type == SO_TIMESTAMPING_NEW);
+ assert(cmsg->cmsg_len == CMSG_LEN(sizeof(tss)));
+
+ memcpy(&tss, CMSG_DATA(cmsg), sizeof(tss));
+ for (i = 0; i < 3; ++i) {
+ if (tss.ts[i].tv_sec || tss.ts[i].tv_nsec) {
+ ts->tv_sec = tss.ts[i].tv_sec;
+ ts->tv_nsec = tss.ts[i].tv_nsec;
+ return;
+ }
+ }
+ assert(!"All three entries in scm_timestamp64 are empty");
+}
+#endif /* defined(SO_TIMESTAMPING_NEW) */
+#endif /* defined(SO_TIMESTAMPING_OLD) */
+
+void set_socket_option(int sock, int sockopt, int set_to)
{
socklen_t len;
- int val = on;
+ int val = set_to;
if (setsockopt(sock, SOL_SOCKET, sockopt, &val, sizeof(val)) < 0) {
int err = errno;
- fprintf(stderr, "Failed to setsockopt %d (%s): %s\n",
- sockopt, on ? "on" : "off", strerror(err));
+ fprintf(stderr, "Failed at setsockopt(%d, SOL_SOCKET, %d, %d): %s\n",
+ sock, sockopt, set_to, strerror(err));
exit(err);
}
+#ifdef SO_TIMESTAMPING_NEW
+ if (sockopt == SO_TIMESTAMPING_NEW) {
+ /*
+ * `getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING_NEW)` not implemented
+ * as of linux kernel v5.8-rc4.
+ */
+ return;
+ }
+#endif
+
len = sizeof(val);
val = -1;
if (getsockopt(sock, SOL_SOCKET, sockopt, &val, &len) < 0) {
int err = errno;
- fprintf(stderr, "Failed to getsockopt (%d): %s\n", sock, strerror(err));
+ fprintf(stderr, "Failed at getsockopt(%d, SOL_SOCKET, %d): %s\n",
+ sock, sockopt, strerror(err));
exit(err);
}
assert(len == sizeof(val));
- assert(val == on);
+ assert(val == set_to);
+}
+
+void child_steps(int sock, struct sockaddr_in addr, int run_old)
+{
+ /* Test 1: SO_TIMESTAMP */
+ send_current_time(sock, addr);
+
+ /* Test 2: SO_TIMESTAMPNS */
+ printf("Test 2: SO_TIMESTAMPNS\n");
+ set_socket_option(sock, SO_TIMESTAMPNS, 1);
+ receive_packet(sock, &get_timespec_from_so_timestampns);
+ set_socket_option(sock, SO_TIMESTAMPNS, 0);
+
+ /* Test 3: SO_TIMESTAMPING */
+ send_current_time(sock, addr);
+
+ if (!run_old) {
+ return;
+ }
+
+#ifdef SO_TIMESTAMP_OLD
+ if (SO_TIMESTAMP_OLD != SO_TIMESTAMP) {
+ /* Test 4a: SO_TIMESTAMP_OLD */
+ printf("Test 4a: SO_TIMESTAMP_OLD\n");
+ set_socket_option(sock, SO_TIMESTAMP_OLD, 1);
+ receive_packet(sock, &get_timespec_from_so_timestamp_old);
+ set_socket_option(sock, SO_TIMESTAMP_OLD, 0);
+ }
+#ifdef SO_TIMESTAMP_NEW
+ else {
+ /* Test 4b: SO_TIMESTAMP_NEW */
+ printf("Test 4b: SO_TIMESTAMP_NEW\n");
+ set_socket_option(sock, SO_TIMESTAMP_NEW, 1);
+ receive_packet(sock, &get_timespec_from_so_timestamp_new);
+ set_socket_option(sock, SO_TIMESTAMP_NEW, 0);
+ }
+#endif /* defined(SO_TIMESTAMP_NEW) */
+#endif /* defined(SO_TIMESTAMP_OLD) */
+
+#ifdef SO_TIMESTAMPNS_OLD
+ if (SO_TIMESTAMPNS_OLD != SO_TIMESTAMPNS) {
+ /* Test 5a: SO_TIMESTAMPNS_OLD */
+ send_current_time(sock, addr);
+ }
+#ifdef SO_TIMESTAMPNS_NEW
+ else {
+ /* Test 5b: SO_TIMESTAMPNS_NEW */
+ send_current_time(sock, addr);
+ }
+#endif /* defined(SO_TIMESTAMPNS_NEW) */
+#endif /* defined(SO_TIMESTAMPNS_OLD) */
+
+#ifdef SO_TIMESTAMPING_OLD
+ if (SO_TIMESTAMPING_OLD != SO_TIMESTAMPING) {
+ /* Test 6a: SO_TIMESTAMPING_OLD */
+ printf("Test 6a: SO_TIMESTAMPING_OLD\n");
+ set_socket_option(sock, SO_TIMESTAMPING_OLD, so_timestamping_flags);
+ receive_packet(sock, &get_timespec_from_so_timestamping_old);
+ set_socket_option(sock, SO_TIMESTAMPING_OLD, 0);
+ }
+#ifdef SO_TIMESTAMPING_NEW
+ else {
+ /* Test 6b: SO_TIMESTAMPING_NEW */
+ printf("Test 6b: SO_TIMESTAMPING_NEW\n");
+ set_socket_option(sock, SO_TIMESTAMPING_NEW, so_timestamping_flags);
+ receive_packet(sock, &get_timespec_from_so_timestamping_new);
+ set_socket_option(sock, SO_TIMESTAMPING_NEW, 0);
+ }
+#endif /* defined(SO_TIMESTAMPING_NEW) */
+#endif /* defined(SO_TIMESTAMPING_OLD) */
+}
+
+void parent_steps(int sock, struct sockaddr_in addr, int run_old)
+{
+ /* Test 1: SO_TIMESTAMP */
+ printf("Test 1: SO_TIMESTAMP\n");
+ set_socket_option(sock, SO_TIMESTAMP, 1);
+ receive_packet(sock, &get_timespec_from_so_timestamp);
+ set_socket_option(sock, SO_TIMESTAMP, 0);
+
+ /* Test 2: SO_TIMESTAMPNS */
+ send_current_time(sock, addr);
+
+ /* Test 3: SO_TIMESTAMPING */
+ printf("Test 3: SO_TIMESTAMPING\n");
+ set_socket_option(sock, SO_TIMESTAMPING, so_timestamping_flags);
+ receive_packet(sock, &get_timespec_from_so_timestamping);
+ set_socket_option(sock, SO_TIMESTAMPING, 0);
+
+ if (!run_old) {
+ return;
+ }
+
+#ifdef SO_TIMESTAMP_OLD
+ if (SO_TIMESTAMP_OLD != SO_TIMESTAMP) {
+ /* Test 4a: SO_TIMESTAMP_OLD */
+ send_current_time(sock, addr);
+ }
+#ifdef SO_TIMESTAMP_NEW
+ else {
+ /* Test 4b: SO_TIMESTAMP_NEW */
+ send_current_time(sock, addr);
+ }
+#endif /* defined(SO_TIMESTAMP_NEW) */
+#endif /* defined(SO_TIMESTAMP_OLD) */
+
+#ifdef SO_TIMESTAMPNS_OLD
+ if (SO_TIMESTAMPNS_OLD != SO_TIMESTAMPNS) {
+ /* Test 5a: SO_TIMESTAMPNS_OLD */
+ printf("Test 5a: SO_TIMESTAMPNS_OLD\n");
+ set_socket_option(sock, SO_TIMESTAMPNS_OLD, 1);
+ receive_packet(sock, &get_timespec_from_so_timestampns_old);
+ set_socket_option(sock, SO_TIMESTAMPNS_OLD, 0);
+ }
+#ifdef SO_TIMESTAMPNS_NEW
+ else {
+ /* Test 5b: SO_TIMESTAMPNS_NEW */
+ printf("Test 5b: SO_TIMESTAMPNS_NEW\n");
+ set_socket_option(sock, SO_TIMESTAMPNS_NEW, 1);
+ receive_packet(sock, &get_timespec_from_so_timestampns_new);
+ set_socket_option(sock, SO_TIMESTAMPNS_NEW, 0);
+ }
+#endif /* defined(SO_TIMESTAMPNS_NEW) */
+#endif /* defined(SO_TIMESTAMPNS_OLD) */
+
+#ifdef SO_TIMESTAMPING_OLD
+ if (SO_TIMESTAMPING_OLD != SO_TIMESTAMPING) {
+ /* Test 6a: SO_TIMESTAMPING_OLD */
+ send_current_time(sock, addr);
+ }
+#ifdef SO_TIMESTAMPING_NEW
+ else {
+ /* Test 6b: SO_TIMESTAMPING_NEW */
+ send_current_time(sock, addr);
+ }
+#endif /* defined(SO_TIMESTAMPING_NEW) */
+#endif /* defined(SO_TIMESTAMPING_OLD) */
}
int main(int argc, char **argv)
{
int parent_sock, child_sock;
struct sockaddr_in parent_sockaddr, child_sockaddr;
- int pid;
+ int pid, run_old;
struct timeval tv = {0, 0};
gettimeofday(&tv, NULL);
+ /* Too close to y2038 old systems may not work. */
+ run_old = tv.tv_sec < 0x7fffff00;
+
parent_sock = create_udp_socket(&parent_sockaddr);
child_sock = create_udp_socket(&child_sockaddr);
@@ -226,64 +519,15 @@ int main(int argc, char **argv)
if (pid < 0) {
fprintf(stderr, "SKIPPED. Failed to fork: %s\n", strerror(errno));
} else if (pid == 0) {
- close(child_sock);
-
- /* Test 1: SO_TIMESTAMP */
- send_current_time(parent_sock, child_sockaddr);
-
- if (tv.tv_sec > 0x7fffff00) {
- /* Too close to y2038 problem, old system may not work. */
- close(parent_sock);
- return 0;
- }
-
-#ifdef SO_TIMESTAMP_OLD
- if (SO_TIMESTAMP_OLD != SO_TIMESTAMP) {
- /* Test 2a: SO_TIMESTAMP_OLD */
- set_socket_option(parent_sock, SO_TIMESTAMP_OLD, 1);
- receive_packet(parent_sock, &get_timeval_from_so_timestamp_old);
- set_socket_option(parent_sock, SO_TIMESTAMP_OLD, 0);
- }
-#ifdef SO_TIMESTAMP_NEW
- else {
- /* Test 2b: SO_TIMESTAMP_NEW */
- set_socket_option(parent_sock, SO_TIMESTAMP_NEW, 1);
- receive_packet(parent_sock, &get_timeval_from_so_timestamp_new);
- set_socket_option(parent_sock, SO_TIMESTAMP_NEW, 0);
- }
-#endif /* defined(SO_TIMESTAMP_NEW) */
-#endif /* defined(SO_TIMESTAMP_OLD) */
-
close(parent_sock);
+ child_steps(child_sock, parent_sockaddr, run_old);
+ close(child_sock);
} else {
int child_status;
- close(parent_sock);
-
- /* Test 1: SO_TIMESTAMP */
- set_socket_option(child_sock, SO_TIMESTAMP, 1);
- receive_packet(child_sock, &get_timeval_from_so_timestamp);
- set_socket_option(child_sock, SO_TIMESTAMP, 0);
-
- if (tv.tv_sec > 0x7fffff00) {
- /* Too close to y2038 problem, old system may not work. */
- close(child_sock);
- return 0;
- }
-
-#ifdef SO_TIMESTAMP_OLD
- if (SO_TIMESTAMP_OLD != SO_TIMESTAMP) {
- /* Test 2a: SO_TIMESTAMP_OLD */
- send_current_time(child_sock, parent_sockaddr);
- }
-#ifdef SO_TIMESTAMP_NEW
- else {
- /* Test 2b: SO_TIMESTAMP_NEW */
- send_current_time(child_sock, parent_sockaddr);
- }
-#endif /* defined(SO_TIMESTAMP_NEW) */
-#endif /* defined(SO_TIMESTAMP_OLD) */
close(child_sock);
+ parent_steps(parent_sock, child_sockaddr, run_old);
+ close(parent_sock);
if (waitpid(pid, &child_status, 0) < 0) {
int err = errno;
--
2.29.2.684.gfbc64c5ab5-goog
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2020-12-18 19:56 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-18 19:54 [PATCH v3 0/2] linux-user: SO_TIMESTAMP/NS/ING sockopt Shu-Chun Weng via
2020-12-18 19:54 ` [PATCH v3 1/2] linux-user: Update SO_TIMESTAMP to SO_TIMESTAMP_OLD/NEW Shu-Chun Weng via
2020-12-18 19:54 ` [PATCH v3 2/2] linux-user: setsockopt() SO_TIMESTAMPNS and SO_TIMESTAMPING Shu-Chun Weng via
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).