1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
| | #include <sys/socket.h>
#include <limits.h>
#include <time.h>
#include <sys/time.h>
#include <string.h>
#include "syscall.h"
static void convert_scm_timestamps(struct msghdr *msg, socklen_t csize)
{
if (SCM_TIMESTAMP == SCM_TIMESTAMP_OLD) return;
if (!msg->msg_control || !msg->msg_controllen) return;
int have_tv=0, have_ts=0;
struct timeval tv;
struct timespec ts;
struct cmsghdr *cmsg, *last=0;
socklen_t clen = msg->msg_controllen;
for (cmsg=CMSG_FIRSTHDR(msg); cmsg; cmsg=CMSG_NXTHDR(msg, cmsg)) {
if (cmsg->cmsg_level==SOL_SOCKET) switch (cmsg->cmsg_type) {
case SCM_TIMESTAMP_OLD:
have_tv = 1;
tv.tv_sec = *(long *)(CMSG_DATA(cmsg) + 0);
tv.tv_usec = *(long *)(CMSG_DATA(cmsg) + 4);
break;
case SCM_TIMESTAMPNS_OLD:
have_ts = 1;
ts.tv_sec = *(long *)(CMSG_DATA(cmsg) + 0);
ts.tv_nsec = *(long *)(CMSG_DATA(cmsg) + 4);
break;
}
last = cmsg;
}
if (!last) return;
msg->msg_controllen = csize;
cmsg = CMSG_NXTHDR(msg, last);
if (cmsg && have_ts && CMSG_SPACE(sizeof ts)<=csize-clen) {
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_TIMESTAMPNS;
cmsg->cmsg_len = CMSG_LEN(sizeof ts);
memcpy(CMSG_DATA(cmsg), &ts, sizeof ts);
cmsg = CMSG_NXTHDR(msg, cmsg);
clen += CMSG_SPACE(sizeof ts);
}
if (cmsg && have_tv && CMSG_SPACE(sizeof tv)<=csize-clen) {
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_TIMESTAMP;
cmsg->cmsg_len = CMSG_LEN(sizeof tv);
memcpy(CMSG_DATA(cmsg), &tv, sizeof tv);
cmsg = CMSG_NXTHDR(msg, cmsg);
clen += CMSG_SPACE(sizeof tv);
}
msg->msg_controllen = clen;
}
ssize_t recvmsg(int fd, struct msghdr *msg, int flags)
{
ssize_t r;
socklen_t orig_controllen = msg->msg_controllen;
#if LONG_MAX > INT_MAX
struct msghdr h, *orig = msg;
if (msg) {
h = *msg;
h.__pad1 = h.__pad2 = 0;
msg = &h;
}
#endif
r = socketcall_cp(recvmsg, fd, msg, flags, 0, 0, 0);
if (r >= 0) convert_scm_timestamps(msg, orig_controllen);
#if LONG_MAX > INT_MAX
if (orig) *orig = h;
#endif
return r;
}
|