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