Ping again. This specific patch is here: https://patchew.org/QEMU/cover.1597129029.git....@google.com/611db81c87911cb38a35e5f761e11b76e1f0d538.1597129029.git....@google.com/
If you want to include the first four patches for now and prefer a separate patch set for the pending changes I can split them off into a new thread. Shu-Chun On Thu, Sep 17, 2020 at 12:29 AM Shu-Chun Weng <s...@google.com> wrote: > 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