1 #include <sys/cdefs.h> 2 #include "namespace.h" 3 #include <lib.h> 4 5 #include <errno.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <sys/ioctl.h> 10 #include <sys/ioc_net.h> 11 #include <sys/socket.h> 12 #include <sys/types.h> 13 #include <sys/un.h> 14 15 #define DEBUG 0 16 17 static ssize_t _uds_recvmsg_conn(int sock, struct msghdr *msg, int flags); 18 static ssize_t _uds_recvmsg_dgram(int sock, struct msghdr *msg, int flags); 19 20 /* 21 * Receive a message from a socket using a message structure. 22 */ 23 static ssize_t 24 __recvmsg(int fd, struct msghdr * msg, int flags) 25 { 26 struct iovec iov; 27 struct msghdr msg2, *msgp; 28 char *ptr; 29 message m; 30 ssize_t r; 31 32 /* 33 * Currently, MINIX3 does not support vector I/O operations. Like in 34 * the readv and writev implementations, we coalesce the data vector 35 * into a single buffer used for I/O. For future ABI compatibility, we 36 * then supply this buffer as a single vector element. This involves 37 * supplying a modified copy of the message header, as well as extra 38 * pre-checks. Once true vector I/O support has been added, the checks 39 * and vector I/O coalescing can be removed from here, leaving just the 40 * system call. Nothing will change at the system call ABI level. 41 */ 42 if (msg == NULL || (msg->msg_iovlen > 1 && msg->msg_iov == NULL)) { 43 errno = EFAULT; 44 return -1; 45 } 46 47 if (msg->msg_iovlen < 0 || msg->msg_iovlen > IOV_MAX) { 48 errno = EMSGSIZE; /* different from readv/writev */ 49 return -1; 50 } 51 52 if (msg->msg_iovlen > 1) { 53 if ((r = _vectorio_setup(msg->msg_iov, msg->msg_iovlen, &ptr, 54 _VECTORIO_READ)) < 0) 55 return -1; 56 57 iov.iov_base = ptr; 58 iov.iov_len = r; 59 60 memcpy(&msg2, msg, sizeof(msg2)); 61 msg2.msg_iov = &iov; 62 msg2.msg_iovlen = 1; 63 msgp = &msg2; 64 } else 65 msgp = msg; 66 67 /* Issue the actual system call. */ 68 memset(&m, 0, sizeof(m)); 69 m.m_lc_vfs_sockmsg.fd = fd; 70 m.m_lc_vfs_sockmsg.msgbuf = (vir_bytes)msgp; 71 m.m_lc_vfs_sockmsg.flags = flags; 72 73 r = _syscall(VFS_PROC_NR, VFS_RECVMSG, &m); 74 75 /* If we coalesced the vector, clean up and copy back the results. */ 76 if (msgp != msg) { 77 _vectorio_cleanup(msg->msg_iov, msg->msg_iovlen, ptr, r, 78 _VECTORIO_READ); 79 80 if (r >= 0) 81 memcpy(msg, &msg2, sizeof(msg2)); 82 } 83 84 return r; 85 } 86 87 ssize_t recvmsg(int sock, struct msghdr *msg, int flags) 88 { 89 int r; 90 int uds_sotype; 91 92 r = __recvmsg(sock, msg, flags); 93 if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS)) 94 return r; 95 96 if (msg == NULL) { 97 errno= EFAULT; 98 return -1; 99 } 100 101 r= ioctl(sock, NWIOGUDSSOTYPE, &uds_sotype); 102 if (r != -1 || errno != ENOTTY) { 103 if (r == -1) { 104 return r; 105 } 106 107 if (uds_sotype == SOCK_DGRAM) { 108 return _uds_recvmsg_dgram(sock, msg, flags); 109 } else { 110 return _uds_recvmsg_conn(sock, msg, flags); 111 } 112 } 113 114 errno = ENOTSOCK; 115 return -1; 116 } 117 118 static ssize_t _uds_recvmsg_conn(int sock, struct msghdr *msg, int flags) 119 { 120 int r, rc; 121 122 if (flags != 0) { 123 #if DEBUG 124 fprintf(stderr, "recvmsg(uds): flags not implemented\n"); 125 #endif 126 errno= ENOSYS; 127 return -1; 128 } 129 130 r= readv(sock, msg->msg_iov, msg->msg_iovlen); 131 132 if (r >= 0 && msg->msg_name && msg->msg_namelen > 0) { 133 getpeername(sock, msg->msg_name, &msg->msg_namelen); 134 } 135 136 /* get control data */ 137 if (r >= 0 && msg->msg_control && msg->msg_controllen > 0) { 138 struct msg_control msg_ctrl; 139 140 memset(&msg_ctrl, '\0', sizeof(struct msg_control)); 141 msg_ctrl.msg_controllen = msg->msg_controllen; 142 rc = ioctl(sock, NWIOGUDSCTRL, &msg_ctrl); 143 if (rc == -1) { 144 return rc; 145 } 146 147 if (msg_ctrl.msg_controllen <= msg->msg_controllen) { 148 memcpy(msg->msg_control, msg_ctrl.msg_control, 149 msg_ctrl.msg_controllen); 150 msg->msg_controllen = msg_ctrl.msg_controllen; 151 } 152 } 153 154 msg->msg_flags = 0; 155 156 return r; 157 } 158 159 static ssize_t _uds_recvmsg_dgram(int sock, struct msghdr *msg, int flags) 160 { 161 int r, rc; 162 163 if (flags != 0) { 164 #if DEBUG 165 fprintf(stderr, "recvmsg(uds): flags not implemented\n"); 166 #endif 167 errno= ENOSYS; 168 return -1; 169 } 170 171 r= readv(sock, msg->msg_iov, msg->msg_iovlen); 172 173 if (r >= 0 && msg->msg_name && 174 msg->msg_namelen >= sizeof(struct sockaddr_un)) 175 { 176 rc= ioctl(sock, NWIOGUDSFADDR, msg->msg_name); 177 if (rc == -1) { 178 return rc; 179 } 180 msg->msg_namelen= sizeof(struct sockaddr_un); 181 } 182 183 /* get control data */ 184 if (r >= 0 && msg->msg_control && msg->msg_controllen > 0) { 185 struct msg_control msg_ctrl; 186 187 memset(&msg_ctrl, '\0', sizeof(struct msg_control)); 188 msg_ctrl.msg_controllen = msg->msg_controllen; 189 rc = ioctl(sock, NWIOGUDSCTRL, &msg_ctrl); 190 if (rc == -1) { 191 return rc; 192 } 193 194 if (msg_ctrl.msg_controllen <= msg->msg_controllen) { 195 memcpy(msg->msg_control, msg_ctrl.msg_control, 196 msg_ctrl.msg_controllen); 197 msg->msg_controllen = msg_ctrl.msg_controllen; 198 } 199 } 200 201 msg->msg_flags = 0; 202 203 return r; 204 } 205