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
>>
>>

Attachment: smime.p7s
Description: S/MIME Cryptographic Signature

Reply via email to