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