#include #include #include #include #include #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; }