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