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