about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/internal/syscall.h7
-rw-r--r--src/mman/mmap.c1
-rw-r--r--src/network/getsockopt.c9
-rw-r--r--src/network/recvmsg.c45
-rw-r--r--src/network/setsockopt.c9
5 files changed, 71 insertions, 0 deletions
diff --git a/src/internal/syscall.h b/src/internal/syscall.h
index 9f2784db..d768fb64 100644
--- a/src/internal/syscall.h
+++ b/src/internal/syscall.h
@@ -306,6 +306,13 @@ hidden long __syscall_ret(unsigned long),
 #define SO_SNDTIMEO_OLD  21
 #endif
 
+#define SO_TIMESTAMP_OLD    29
+#define SO_TIMESTAMPNS_OLD  35
+#define SO_TIMESTAMPING_OLD 37
+#define SCM_TIMESTAMP_OLD    SO_TIMESTAMP_OLD
+#define SCM_TIMESTAMPNS_OLD  SO_TIMESTAMPNS_OLD
+#define SCM_TIMESTAMPING_OLD SO_TIMESTAMPING_OLD
+
 #ifndef SIOCGSTAMP_OLD
 #define SIOCGSTAMP_OLD 0x8906
 #endif
diff --git a/src/mman/mmap.c b/src/mman/mmap.c
index eff88d82..2da11b87 100644
--- a/src/mman/mmap.c
+++ b/src/mman/mmap.c
@@ -1,3 +1,4 @@
+#define SYSCALL_NO_TLS 1
 #include <unistd.h>
 #include <sys/mman.h>
 #include <errno.h>
diff --git a/src/network/getsockopt.c b/src/network/getsockopt.c
index e871d624..d3640d9c 100644
--- a/src/network/getsockopt.c
+++ b/src/network/getsockopt.c
@@ -26,6 +26,15 @@ int getsockopt(int fd, int level, int optname, void *restrict optval, socklen_t
 			tv->tv_sec = tv32[0];
 			tv->tv_usec = tv32[1];
 			*optlen = sizeof *tv;
+			break;
+		case SO_TIMESTAMP:
+		case SO_TIMESTAMPNS:
+			if (SO_TIMESTAMP == SO_TIMESTAMP_OLD) break;
+			if (optname==SO_TIMESTAMP) optname=SO_TIMESTAMP_OLD;
+			if (optname==SO_TIMESTAMPNS) optname=SO_TIMESTAMPNS_OLD;
+			r = __socketcall(getsockopt, fd, level,
+				optname, optval, optlen, 0);
+			break;
 		}
 	}
 	return __syscall_ret(r);
diff --git a/src/network/recvmsg.c b/src/network/recvmsg.c
index 4ca7da8b..5ce37e73 100644
--- a/src/network/recvmsg.c
+++ b/src/network/recvmsg.c
@@ -1,10 +1,54 @@
 #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;
+
+	struct cmsghdr *cmsg, *last=0;
+	long tmp;
+	long long tvts[2];
+	int type = 0;
+
+	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:
+			if (type) break;
+			type = SCM_TIMESTAMP;
+			goto common;
+		case SCM_TIMESTAMPNS_OLD:
+			type = SCM_TIMESTAMPNS;
+		common:
+			memcpy(&tmp, CMSG_DATA(cmsg), sizeof tmp);
+			tvts[0] = tmp;
+			memcpy(&tmp, CMSG_DATA(cmsg) + sizeof tmp, sizeof tmp);
+			tvts[1] = tmp;
+			break;
+		}
+		last = cmsg;
+	}
+	if (!last || !type) return;
+	if (CMSG_SPACE(sizeof tvts) > csize-msg->msg_controllen) {
+		msg->msg_flags |= MSG_CTRUNC;
+		return;
+	}
+	msg->msg_controllen += CMSG_SPACE(sizeof tvts);
+	cmsg = CMSG_NXTHDR(msg, last);
+	cmsg->cmsg_level = SOL_SOCKET;
+	cmsg->cmsg_type = type;
+	cmsg->cmsg_len = CMSG_LEN(sizeof tvts);
+	memcpy(CMSG_DATA(cmsg), &tvts, sizeof tvts);
+}
+
 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) {
@@ -14,6 +58,7 @@ ssize_t recvmsg(int fd, struct msghdr *msg, int flags)
 	}
 #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
diff --git a/src/network/setsockopt.c b/src/network/setsockopt.c
index 2c188a96..612a1947 100644
--- a/src/network/setsockopt.c
+++ b/src/network/setsockopt.c
@@ -31,6 +31,15 @@ int setsockopt(int fd, int level, int optname, const void *optval, socklen_t opt
 
 			r = __socketcall(setsockopt, fd, level, optname,
 				((long[]){s, CLAMP(us)}), 2*sizeof(long), 0);
+			break;
+		case SO_TIMESTAMP:
+		case SO_TIMESTAMPNS:
+			if (SO_TIMESTAMP == SO_TIMESTAMP_OLD) break;
+			if (optname==SO_TIMESTAMP) optname=SO_TIMESTAMP_OLD;
+			if (optname==SO_TIMESTAMPNS) optname=SO_TIMESTAMPNS_OLD;
+			r = __socketcall(setsockopt, fd, level,
+				optname, optval, optlen, 0);
+			break;
 		}
 	}
 	return __syscall_ret(r);