Which clock does SO_TIMESTAMP socket option use?

Viewed 1702

I am receiving a stream of messages from a TCP server (a robot sending its status) every 0.1 s. I can not guarantee that I call recvmsg every 0.1 s, so I would like to have a timestamp on those received messages so that when I recvmsg them I know if I've just received them, or if they had been in the buffer for long enough to be outdated and I should call recvmsg again until I read a recent msg.

First of all, which clock does the struct timespec of the SO_TIMESTAMP timestamp use? I've found sources on google that point to CLOCK_REALTIME, but they are around 10 years old, so they might be outdated.

Which of all the time functions should I call to get a time that's comparable to that of the timestamp?

Is it possible to use CLOCK_BOOTTIME to avoid continuity problems?


I made a mistake. I mixed SO_TIMESTAMP (uses struct timeval) with SO_TIMESTAMPNS (uses struct timespec) (SO_TIMESTAMPNS doesn't seem available).

While SO_TIMESTAMPNS doesn't seem available per the documentation, when I #include <sys/socket.h> I have it defined as 35.

2 Answers

UPDATE: The documentation was missing, so I wrote it. It is documented in man 7 socket in version 5.06 of the man-pages.


Experimentally, SO_TIMESTAMPNS works, and it looks like it's using CLOCK_REALTIME.

Therefore, the function to be used with SO_TIMESTAMPNS is clock_gettime(CLOCK_REALTIME, &tm);


I don't know specific documentation for it, but I did some experiment:

I wrote a simple server and client test.

In the client side, I connected a socket specifying SOCK_STREAM and "tcp".

Then I enabled timestamp in ns:

    int     enable = 1;

    if (setsockopt(sd, SOL_SOCKET, SO_TIMESTAMPNS, &enable,
                                                    sizeof(enable)))
            goto err;

Then I prepared the msg header:

    char            buf[BUFSIZ];
    char            cbuf[BUFSIZ];
    struct msghdr   msg;
    struct iovec    iov;

    iov.iov_base    = buf;
    memset(buf, 0, ARRAY_BYTES(buf));
    iov.iov_len     = ARRAY_BYTES(buf) - 1;
    msg.msg_name    = NULL;
    msg.msg_iov     = &iov;
    msg.msg_iovlen  = 1;
    msg.msg_control = cbuf;
    msg.msg_controllen = ARRAY_BYTES(cbuf);

And got some times before and after receiving the msg:

    struct timespec tm_before, tm_recvmsg, tm_after, tm_msg;

    clock_gettime(CLOCK_REALTIME, &tm_before);
    usleep(500000);
    clock_gettime(CLOCK_REALTIME, &tm_recvmsg);
    n   = recvmsg(sd, &msg, MSG_WAITALL);
    if (n < 0)
            goto err;
    usleep(1000000);
    clock_gettime(CLOCK_REALTIME, &tm_after);

After that I read the timestamp of the msg:

    struct cmsghdr  *cmsg;

    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
            if (cmsg->cmsg_level == SOL_SOCKET  &&
                                    cmsg->cmsg_type == SCM_TIMESTAMPNS) {
                    memcpy(&tm_msg, CMSG_DATA(cmsg), sizeof(tm_msg));
                    break;
            }
    }
    if (!cmsg)
            goto err;

And finally printed the results:

    double      tdiff;

    printf("%s\n", buf);
    tdiff   = timespec_diff_ms(&tm_before, &tm_recvmsg);
    printf("tm_r - tm_b = %lf ms\n", tdiff);
    tdiff   = timespec_diff_ms(&tm_before, &tm_after);
    printf("tm_a - tm_b = %lf ms\n", tdiff);
    tdiff   = timespec_diff_ms(&tm_before, &tm_msg);
    printf("tm_m - tm_b = %lf ms\n", tdiff);

Which printed:

asdasdfasdfasdfadfgdfghfthgujty 6, 0;

tm_r - tm_b = 500.000000 ms
tm_a - tm_b = 1500.000000 ms
tm_m - tm_b = 18.000000 ms

System:

Linux debian 5.4.0-4-amd64 #1 SMP Debian 5.4.19-1 (2020-02-13) x86_64 GNU/Linux
gcc (Debian 9.3.0-8) 9.3.0

However, I didn't find any man page that talks about SO_TIMESTAMPNS, so this may not work on other systems.


I didn't test SO_TIMESTAMP because it uses struct timeval which AFAIK is obsolete.

Related