xref: /minix3/minix/lib/libc/sys/recvmsg.c (revision 84ed480ef770e26a28565a26c8ef94ba01312a41)
1433d6423SLionel Sambuc #include <sys/cdefs.h>
2433d6423SLionel Sambuc #include "namespace.h"
3c38dbb97SDavid van Moolenbroek #include <lib.h>
4433d6423SLionel Sambuc 
5433d6423SLionel Sambuc #include <errno.h>
6433d6423SLionel Sambuc #include <stdio.h>
7433d6423SLionel Sambuc #include <stdlib.h>
8433d6423SLionel Sambuc #include <string.h>
9433d6423SLionel Sambuc #include <sys/ioctl.h>
10433d6423SLionel Sambuc #include <sys/ioc_net.h>
11433d6423SLionel Sambuc #include <sys/socket.h>
12433d6423SLionel Sambuc #include <sys/types.h>
13433d6423SLionel Sambuc #include <sys/un.h>
14433d6423SLionel Sambuc 
15433d6423SLionel Sambuc #define DEBUG 0
16433d6423SLionel Sambuc 
17433d6423SLionel Sambuc static ssize_t _uds_recvmsg_conn(int sock, struct msghdr *msg, int flags);
18433d6423SLionel Sambuc static ssize_t _uds_recvmsg_dgram(int sock, struct msghdr *msg, int flags);
19433d6423SLionel Sambuc 
20c38dbb97SDavid van Moolenbroek /*
21c38dbb97SDavid van Moolenbroek  * Receive a message from a socket using a message structure.
22c38dbb97SDavid van Moolenbroek  */
23c38dbb97SDavid van Moolenbroek static ssize_t
__recvmsg(int fd,struct msghdr * msg,int flags)24c38dbb97SDavid van Moolenbroek __recvmsg(int fd, struct msghdr * msg, int flags)
25c38dbb97SDavid van Moolenbroek {
26c38dbb97SDavid van Moolenbroek 	struct iovec iov;
27c38dbb97SDavid van Moolenbroek 	struct msghdr msg2, *msgp;
28c38dbb97SDavid van Moolenbroek 	char *ptr;
29c38dbb97SDavid van Moolenbroek 	message m;
30c38dbb97SDavid van Moolenbroek 	ssize_t r;
31c38dbb97SDavid van Moolenbroek 
32c38dbb97SDavid van Moolenbroek 	/*
33c38dbb97SDavid van Moolenbroek 	 * Currently, MINIX3 does not support vector I/O operations.  Like in
34c38dbb97SDavid van Moolenbroek 	 * the readv and writev implementations, we coalesce the data vector
35c38dbb97SDavid van Moolenbroek 	 * into a single buffer used for I/O.  For future ABI compatibility, we
36c38dbb97SDavid van Moolenbroek 	 * then supply this buffer as a single vector element.  This involves
37c38dbb97SDavid van Moolenbroek 	 * supplying a modified copy of the message header, as well as extra
38c38dbb97SDavid van Moolenbroek 	 * pre-checks.  Once true vector I/O support has been added, the checks
39c38dbb97SDavid van Moolenbroek 	 * and vector I/O coalescing can be removed from here, leaving just the
40c38dbb97SDavid van Moolenbroek 	 * system call.  Nothing will change at the system call ABI level.
41c38dbb97SDavid van Moolenbroek 	 */
42c38dbb97SDavid van Moolenbroek 	if (msg == NULL || (msg->msg_iovlen > 1 && msg->msg_iov == NULL)) {
43c38dbb97SDavid van Moolenbroek 		errno = EFAULT;
44c38dbb97SDavid van Moolenbroek 		return -1;
45c38dbb97SDavid van Moolenbroek 	}
46c38dbb97SDavid van Moolenbroek 
47c38dbb97SDavid van Moolenbroek 	if (msg->msg_iovlen < 0 || msg->msg_iovlen > IOV_MAX) {
48c38dbb97SDavid van Moolenbroek 		errno = EMSGSIZE;	/* different from readv/writev */
49c38dbb97SDavid van Moolenbroek 		return -1;
50c38dbb97SDavid van Moolenbroek 	}
51c38dbb97SDavid van Moolenbroek 
52c38dbb97SDavid van Moolenbroek 	if (msg->msg_iovlen > 1) {
53c38dbb97SDavid van Moolenbroek 		if ((r = _vectorio_setup(msg->msg_iov, msg->msg_iovlen, &ptr,
54c38dbb97SDavid van Moolenbroek 		    _VECTORIO_READ)) < 0)
55c38dbb97SDavid van Moolenbroek 			return -1;
56c38dbb97SDavid van Moolenbroek 
57c38dbb97SDavid van Moolenbroek 		iov.iov_base = ptr;
58c38dbb97SDavid van Moolenbroek 		iov.iov_len = r;
59c38dbb97SDavid van Moolenbroek 
60c38dbb97SDavid van Moolenbroek 		memcpy(&msg2, msg, sizeof(msg2));
61c38dbb97SDavid van Moolenbroek 		msg2.msg_iov = &iov;
62c38dbb97SDavid van Moolenbroek 		msg2.msg_iovlen = 1;
63c38dbb97SDavid van Moolenbroek 		msgp = &msg2;
64c38dbb97SDavid van Moolenbroek 	} else
65c38dbb97SDavid van Moolenbroek 		msgp = msg;
66c38dbb97SDavid van Moolenbroek 
67c38dbb97SDavid van Moolenbroek 	/* Issue the actual system call. */
68c38dbb97SDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
69c38dbb97SDavid van Moolenbroek 	m.m_lc_vfs_sockmsg.fd = fd;
70c38dbb97SDavid van Moolenbroek 	m.m_lc_vfs_sockmsg.msgbuf = (vir_bytes)msgp;
71c38dbb97SDavid van Moolenbroek 	m.m_lc_vfs_sockmsg.flags = flags;
72c38dbb97SDavid van Moolenbroek 
73c38dbb97SDavid van Moolenbroek 	r = _syscall(VFS_PROC_NR, VFS_RECVMSG, &m);
74c38dbb97SDavid van Moolenbroek 
75c38dbb97SDavid van Moolenbroek 	/* If we coalesced the vector, clean up and copy back the results. */
76c38dbb97SDavid van Moolenbroek 	if (msgp != msg) {
77c38dbb97SDavid van Moolenbroek 		_vectorio_cleanup(msg->msg_iov, msg->msg_iovlen, ptr, r,
78c38dbb97SDavid van Moolenbroek 		    _VECTORIO_READ);
79c38dbb97SDavid van Moolenbroek 
80c38dbb97SDavid van Moolenbroek 		if (r >= 0)
81c38dbb97SDavid van Moolenbroek 			memcpy(msg, &msg2, sizeof(msg2));
82c38dbb97SDavid van Moolenbroek 	}
83c38dbb97SDavid van Moolenbroek 
84c38dbb97SDavid van Moolenbroek 	return r;
85c38dbb97SDavid van Moolenbroek }
86c38dbb97SDavid van Moolenbroek 
recvmsg(int sock,struct msghdr * msg,int flags)87433d6423SLionel Sambuc ssize_t recvmsg(int sock, struct msghdr *msg, int flags)
88433d6423SLionel Sambuc {
89433d6423SLionel Sambuc 	int r;
90433d6423SLionel Sambuc 	int uds_sotype;
91433d6423SLionel Sambuc 
92c38dbb97SDavid van Moolenbroek 	r = __recvmsg(sock, msg, flags);
93*84ed480eSDavid van Moolenbroek 	if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS))
94c38dbb97SDavid van Moolenbroek 		return r;
95c38dbb97SDavid van Moolenbroek 
96433d6423SLionel Sambuc 	if (msg == NULL) {
97433d6423SLionel Sambuc 		errno= EFAULT;
98433d6423SLionel Sambuc 		return -1;
99433d6423SLionel Sambuc 	}
100433d6423SLionel Sambuc 
101433d6423SLionel Sambuc 	r= ioctl(sock, NWIOGUDSSOTYPE, &uds_sotype);
102433d6423SLionel Sambuc 	if (r != -1 || errno != ENOTTY) {
103433d6423SLionel Sambuc 		if (r == -1) {
104433d6423SLionel Sambuc 			return r;
105433d6423SLionel Sambuc 		}
106433d6423SLionel Sambuc 
107433d6423SLionel Sambuc 		if (uds_sotype == SOCK_DGRAM) {
108433d6423SLionel Sambuc 			return _uds_recvmsg_dgram(sock, msg, flags);
109433d6423SLionel Sambuc 		} else {
110433d6423SLionel Sambuc 			return _uds_recvmsg_conn(sock, msg, flags);
111433d6423SLionel Sambuc 		}
112433d6423SLionel Sambuc 	}
113433d6423SLionel Sambuc 
114c38dbb97SDavid van Moolenbroek 	errno = ENOTSOCK;
115433d6423SLionel Sambuc 	return -1;
116433d6423SLionel Sambuc }
117433d6423SLionel Sambuc 
_uds_recvmsg_conn(int sock,struct msghdr * msg,int flags)118433d6423SLionel Sambuc static ssize_t _uds_recvmsg_conn(int sock, struct msghdr *msg, int flags)
119433d6423SLionel Sambuc {
120433d6423SLionel Sambuc 	int r, rc;
121433d6423SLionel Sambuc 
122433d6423SLionel Sambuc 	if (flags != 0) {
123433d6423SLionel Sambuc #if DEBUG
124433d6423SLionel Sambuc 		fprintf(stderr, "recvmsg(uds): flags not implemented\n");
125433d6423SLionel Sambuc #endif
126433d6423SLionel Sambuc 		errno= ENOSYS;
127433d6423SLionel Sambuc 		return -1;
128433d6423SLionel Sambuc 	}
129433d6423SLionel Sambuc 
130433d6423SLionel Sambuc 	r= readv(sock, msg->msg_iov, msg->msg_iovlen);
131433d6423SLionel Sambuc 
132433d6423SLionel Sambuc 	if (r >= 0 && msg->msg_name && msg->msg_namelen > 0) {
133433d6423SLionel Sambuc 		getpeername(sock, msg->msg_name, &msg->msg_namelen);
134433d6423SLionel Sambuc 	}
135433d6423SLionel Sambuc 
136433d6423SLionel Sambuc 	/* get control data */
137433d6423SLionel Sambuc 	if (r >= 0 && msg->msg_control && msg->msg_controllen > 0) {
138433d6423SLionel Sambuc 		struct msg_control msg_ctrl;
139433d6423SLionel Sambuc 
140433d6423SLionel Sambuc 		memset(&msg_ctrl, '\0', sizeof(struct msg_control));
141433d6423SLionel Sambuc 		msg_ctrl.msg_controllen = msg->msg_controllen;
142433d6423SLionel Sambuc 		rc = ioctl(sock, NWIOGUDSCTRL, &msg_ctrl);
143433d6423SLionel Sambuc 		if (rc == -1) {
144433d6423SLionel Sambuc 			return rc;
145433d6423SLionel Sambuc 		}
146433d6423SLionel Sambuc 
147433d6423SLionel Sambuc 		if (msg_ctrl.msg_controllen <= msg->msg_controllen) {
148433d6423SLionel Sambuc 			memcpy(msg->msg_control, msg_ctrl.msg_control,
149433d6423SLionel Sambuc 						msg_ctrl.msg_controllen);
150433d6423SLionel Sambuc 			msg->msg_controllen = msg_ctrl.msg_controllen;
151433d6423SLionel Sambuc 		}
152433d6423SLionel Sambuc 	}
153433d6423SLionel Sambuc 
154433d6423SLionel Sambuc 	msg->msg_flags = 0;
155433d6423SLionel Sambuc 
156433d6423SLionel Sambuc 	return r;
157433d6423SLionel Sambuc }
158433d6423SLionel Sambuc 
_uds_recvmsg_dgram(int sock,struct msghdr * msg,int flags)159433d6423SLionel Sambuc static ssize_t _uds_recvmsg_dgram(int sock, struct msghdr *msg, int flags)
160433d6423SLionel Sambuc {
161433d6423SLionel Sambuc 	int r, rc;
162433d6423SLionel Sambuc 
163433d6423SLionel Sambuc 	if (flags != 0) {
164433d6423SLionel Sambuc #if DEBUG
165433d6423SLionel Sambuc 		fprintf(stderr, "recvmsg(uds): flags not implemented\n");
166433d6423SLionel Sambuc #endif
167433d6423SLionel Sambuc 		errno= ENOSYS;
168433d6423SLionel Sambuc 		return -1;
169433d6423SLionel Sambuc 	}
170433d6423SLionel Sambuc 
171433d6423SLionel Sambuc 	r= readv(sock, msg->msg_iov, msg->msg_iovlen);
172433d6423SLionel Sambuc 
173433d6423SLionel Sambuc 	if (r >= 0 && msg->msg_name &&
174433d6423SLionel Sambuc 				msg->msg_namelen >= sizeof(struct sockaddr_un))
175433d6423SLionel Sambuc 	{
176433d6423SLionel Sambuc 		rc= ioctl(sock, NWIOGUDSFADDR, msg->msg_name);
177433d6423SLionel Sambuc 		if (rc == -1) {
178433d6423SLionel Sambuc 			return rc;
179433d6423SLionel Sambuc 		}
180433d6423SLionel Sambuc 		msg->msg_namelen= sizeof(struct sockaddr_un);
181433d6423SLionel Sambuc 	}
182433d6423SLionel Sambuc 
183433d6423SLionel Sambuc 	/* get control data */
184433d6423SLionel Sambuc 	if (r >= 0 && msg->msg_control && msg->msg_controllen > 0) {
185433d6423SLionel Sambuc 		struct msg_control msg_ctrl;
186433d6423SLionel Sambuc 
187433d6423SLionel Sambuc 		memset(&msg_ctrl, '\0', sizeof(struct msg_control));
188433d6423SLionel Sambuc 		msg_ctrl.msg_controllen = msg->msg_controllen;
189433d6423SLionel Sambuc 		rc = ioctl(sock, NWIOGUDSCTRL, &msg_ctrl);
190433d6423SLionel Sambuc 		if (rc == -1) {
191433d6423SLionel Sambuc 			return rc;
192433d6423SLionel Sambuc 		}
193433d6423SLionel Sambuc 
194433d6423SLionel Sambuc 		if (msg_ctrl.msg_controllen <= msg->msg_controllen) {
195433d6423SLionel Sambuc 			memcpy(msg->msg_control, msg_ctrl.msg_control,
196433d6423SLionel Sambuc 						msg_ctrl.msg_controllen);
197433d6423SLionel Sambuc 			msg->msg_controllen = msg_ctrl.msg_controllen;
198433d6423SLionel Sambuc 		}
199433d6423SLionel Sambuc 	}
200433d6423SLionel Sambuc 
201433d6423SLionel Sambuc 	msg->msg_flags = 0;
202433d6423SLionel Sambuc 
203433d6423SLionel Sambuc 	return r;
204433d6423SLionel Sambuc }
205