xref: /minix/minix/lib/libc/sys/sendmsg.c (revision 045e0ed3)
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 	/* For old socket driver implementations, this flag is the default. */
100 	flags &= ~MSG_NOSIGNAL;
101 
102 	r= ioctl(sock, NWIOGUDSSOTYPE, &uds_sotype);
103 	if (r != -1 || errno != ENOTTY) {
104 		if (r == -1) {
105 			return r;
106 		}
107 
108 		if (uds_sotype == SOCK_DGRAM) {
109 			return _uds_sendmsg_dgram(sock, msg, flags);
110 		} else {
111 			return _uds_sendmsg_conn(sock, msg, flags);
112 		}
113 
114 	}
115 
116 	errno = ENOTSOCK;
117 	return -1;
118 }
119 
120 static ssize_t _uds_sendmsg_conn(int sock, const struct msghdr *msg,
121 	int flags)
122 {
123 	struct msg_control msg_ctrl;
124 	int r;
125 
126 	if (flags != 0) {
127 #if DEBUG
128 		fprintf(stderr, "sendmsg(uds): flags not implemented\n");
129 #endif
130 		errno= ENOSYS;
131 		return -1;
132 
133 	}
134 
135 	/* grab the control data */
136 	memset(&msg_ctrl, '\0', sizeof(struct msg_control));
137 	if (msg->msg_controllen > MSG_CONTROL_MAX) {
138 		errno = ENOMEM;
139 		return -1;
140 	} else if (msg->msg_controllen > 0) {
141 		memcpy(&msg_ctrl.msg_control, msg->msg_control,
142 							msg->msg_controllen);
143 	}
144 	msg_ctrl.msg_controllen = msg->msg_controllen;
145 
146 	/* send the control data to PFS */
147 	r= ioctl(sock, NWIOSUDSCTRL, (void *) &msg_ctrl);
148 	if (r == -1) {
149 		return r;
150 	}
151 
152 	/* Silently ignore destination, if given. */
153 
154 	return writev(sock, msg->msg_iov, msg->msg_iovlen);
155 }
156 
157 static ssize_t _uds_sendmsg_dgram(int sock, const struct msghdr *msg,
158 	int flags)
159 {
160 	struct msg_control msg_ctrl;
161 	struct sockaddr_un *dest_addr;
162 	int r;
163 
164 	if (flags != 0) {
165 #if DEBUG
166 		fprintf(stderr, "sendmsg(uds): flags not implemented\n");
167 #endif
168 		errno= ENOSYS;
169 		return -1;
170 
171 	}
172 
173 	dest_addr = msg->msg_name;
174 	if (dest_addr == NULL) {
175 		errno= EFAULT;
176 		return -1;
177 	}
178 
179 	/* set the target address */
180 	r= ioctl(sock, NWIOSUDSTADDR, (void *) dest_addr);
181 	if (r == -1) {
182 		return r;
183 	}
184 
185 	/* grab the control data */
186 	memset(&msg_ctrl, '\0', sizeof(struct msg_control));
187 	if (msg->msg_controllen > MSG_CONTROL_MAX) {
188 		errno = ENOMEM;
189 		return -1;
190 	} else if (msg->msg_controllen > 0) {
191 		memcpy(&msg_ctrl.msg_control, msg->msg_control,
192 							msg->msg_controllen);
193 	}
194 	msg_ctrl.msg_controllen = msg->msg_controllen;
195 
196 	/* send the control data to PFS */
197 	r= ioctl(sock, NWIOSUDSCTRL, (void *) &msg_ctrl);
198 	if (r == -1) {
199 		return r;
200 	}
201 
202 	/* do the send */
203 	return writev(sock, msg->msg_iov, msg->msg_iovlen);
204 }
205