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