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