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