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