xref: /minix/minix/lib/libc/sys/recvmsg.c (revision 045e0ed3)
1 #include <sys/cdefs.h>
2 #include "namespace.h"
3 #include <lib.h>
4 
5 #include <errno.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/ioctl.h>
10 #include <sys/ioc_net.h>
11 #include <sys/socket.h>
12 #include <sys/types.h>
13 #include <sys/un.h>
14 
15 #define DEBUG 0
16 
17 static ssize_t _uds_recvmsg_conn(int sock, struct msghdr *msg, int flags);
18 static ssize_t _uds_recvmsg_dgram(int sock, struct msghdr *msg, int flags);
19 
20 /*
21  * Receive a message from a socket using a message structure.
22  */
23 static ssize_t
24 __recvmsg(int fd, struct msghdr * msg, int flags)
25 {
26 	struct iovec iov;
27 	struct msghdr msg2, *msgp;
28 	char *ptr;
29 	message m;
30 	ssize_t r;
31 
32 	/*
33 	 * Currently, MINIX3 does not support vector I/O operations.  Like in
34 	 * the readv and writev implementations, we coalesce the data vector
35 	 * into a single buffer used for I/O.  For future ABI compatibility, we
36 	 * then supply this buffer as a single vector element.  This involves
37 	 * supplying a modified copy of the message header, as well as extra
38 	 * pre-checks.  Once true vector I/O support has been added, the checks
39 	 * and vector I/O coalescing can be removed from here, leaving just the
40 	 * system call.  Nothing will change at the system call ABI level.
41 	 */
42 	if (msg == NULL || (msg->msg_iovlen > 1 && msg->msg_iov == NULL)) {
43 		errno = EFAULT;
44 		return -1;
45 	}
46 
47 	if (msg->msg_iovlen < 0 || msg->msg_iovlen > IOV_MAX) {
48 		errno = EMSGSIZE;	/* different from readv/writev */
49 		return -1;
50 	}
51 
52 	if (msg->msg_iovlen > 1) {
53 		if ((r = _vectorio_setup(msg->msg_iov, msg->msg_iovlen, &ptr,
54 		    _VECTORIO_READ)) < 0)
55 			return -1;
56 
57 		iov.iov_base = ptr;
58 		iov.iov_len = r;
59 
60 		memcpy(&msg2, msg, sizeof(msg2));
61 		msg2.msg_iov = &iov;
62 		msg2.msg_iovlen = 1;
63 		msgp = &msg2;
64 	} else
65 		msgp = msg;
66 
67 	/* Issue the actual system call. */
68 	memset(&m, 0, sizeof(m));
69 	m.m_lc_vfs_sockmsg.fd = fd;
70 	m.m_lc_vfs_sockmsg.msgbuf = (vir_bytes)msgp;
71 	m.m_lc_vfs_sockmsg.flags = flags;
72 
73 	r = _syscall(VFS_PROC_NR, VFS_RECVMSG, &m);
74 
75 	/* If we coalesced the vector, clean up and copy back the results. */
76 	if (msgp != msg) {
77 		_vectorio_cleanup(msg->msg_iov, msg->msg_iovlen, ptr, r,
78 		    _VECTORIO_READ);
79 
80 		if (r >= 0)
81 			memcpy(msg, &msg2, sizeof(msg2));
82 	}
83 
84 	return r;
85 }
86 
87 ssize_t recvmsg(int sock, struct msghdr *msg, int flags)
88 {
89 	int r;
90 	int uds_sotype;
91 
92 	r = __recvmsg(sock, msg, flags);
93 	if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS))
94 		return r;
95 
96 	if (msg == NULL) {
97 		errno= EFAULT;
98 		return -1;
99 	}
100 
101 	r= ioctl(sock, NWIOGUDSSOTYPE, &uds_sotype);
102 	if (r != -1 || errno != ENOTTY) {
103 		if (r == -1) {
104 			return r;
105 		}
106 
107 		if (uds_sotype == SOCK_DGRAM) {
108 			return _uds_recvmsg_dgram(sock, msg, flags);
109 		} else {
110 			return _uds_recvmsg_conn(sock, msg, flags);
111 		}
112 	}
113 
114 	errno = ENOTSOCK;
115 	return -1;
116 }
117 
118 static ssize_t _uds_recvmsg_conn(int sock, struct msghdr *msg, int flags)
119 {
120 	int r, rc;
121 
122 	if (flags != 0) {
123 #if DEBUG
124 		fprintf(stderr, "recvmsg(uds): flags not implemented\n");
125 #endif
126 		errno= ENOSYS;
127 		return -1;
128 	}
129 
130 	r= readv(sock, msg->msg_iov, msg->msg_iovlen);
131 
132 	if (r >= 0 && msg->msg_name && msg->msg_namelen > 0) {
133 		getpeername(sock, msg->msg_name, &msg->msg_namelen);
134 	}
135 
136 	/* get control data */
137 	if (r >= 0 && msg->msg_control && msg->msg_controllen > 0) {
138 		struct msg_control msg_ctrl;
139 
140 		memset(&msg_ctrl, '\0', sizeof(struct msg_control));
141 		msg_ctrl.msg_controllen = msg->msg_controllen;
142 		rc = ioctl(sock, NWIOGUDSCTRL, &msg_ctrl);
143 		if (rc == -1) {
144 			return rc;
145 		}
146 
147 		if (msg_ctrl.msg_controllen <= msg->msg_controllen) {
148 			memcpy(msg->msg_control, msg_ctrl.msg_control,
149 						msg_ctrl.msg_controllen);
150 			msg->msg_controllen = msg_ctrl.msg_controllen;
151 		}
152 	}
153 
154 	msg->msg_flags = 0;
155 
156 	return r;
157 }
158 
159 static ssize_t _uds_recvmsg_dgram(int sock, struct msghdr *msg, int flags)
160 {
161 	int r, rc;
162 
163 	if (flags != 0) {
164 #if DEBUG
165 		fprintf(stderr, "recvmsg(uds): flags not implemented\n");
166 #endif
167 		errno= ENOSYS;
168 		return -1;
169 	}
170 
171 	r= readv(sock, msg->msg_iov, msg->msg_iovlen);
172 
173 	if (r >= 0 && msg->msg_name &&
174 				msg->msg_namelen >= sizeof(struct sockaddr_un))
175 	{
176 		rc= ioctl(sock, NWIOGUDSFADDR, msg->msg_name);
177 		if (rc == -1) {
178 			return rc;
179 		}
180 		msg->msg_namelen= sizeof(struct sockaddr_un);
181 	}
182 
183 	/* get control data */
184 	if (r >= 0 && msg->msg_control && msg->msg_controllen > 0) {
185 		struct msg_control msg_ctrl;
186 
187 		memset(&msg_ctrl, '\0', sizeof(struct msg_control));
188 		msg_ctrl.msg_controllen = msg->msg_controllen;
189 		rc = ioctl(sock, NWIOGUDSCTRL, &msg_ctrl);
190 		if (rc == -1) {
191 			return rc;
192 		}
193 
194 		if (msg_ctrl.msg_controllen <= msg->msg_controllen) {
195 			memcpy(msg->msg_control, msg_ctrl.msg_control,
196 						msg_ctrl.msg_controllen);
197 			msg->msg_controllen = msg_ctrl.msg_controllen;
198 		}
199 	}
200 
201 	msg->msg_flags = 0;
202 
203 	return r;
204 }
205