Ping -- any comments on the four patches start with this? https://patchew.org/QEMU/cover.1597129029.git....@google.com/
On Tue, Aug 11, 2020 at 12:10 AM Shu-Chun Weng <s...@google.com> wrote: > 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 <s...@google.com> > --- > v1 -> v2: > Only keep track of old or new format globally, remove support for > different > sockets mixing different formats. > Fix style problems. > > 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 089fb3968e..a11a5e9e86 100644 > --- a/linux-user/strace.c > +++ b/linux-user/strace.c > @@ -2257,8 +2257,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 cda194a7cc..e6b1a18cc0 100644 > --- a/linux-user/syscall.c > +++ b/linux-user/syscall.c > @@ -1697,6 +1697,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) > { > @@ -1747,8 +1759,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; > @@ -1782,20 +1803,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: > @@ -1937,6 +1977,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: > @@ -2331,9 +2373,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; > @@ -2346,6 +2393,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: > @@ -2396,6 +2446,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: > @@ -2576,7 +2627,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: > @@ -2604,6 +2662,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.28.0.220.ged08abb693-goog > >
smime.p7s
Description: S/MIME Cryptographic Signature