1 #include <sys/cdefs.h> 2 #include "namespace.h" 3 #include <lib.h> 4 5 #include <errno.h> 6 #include <fcntl.h> 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <unistd.h> 10 #include <string.h> 11 #include <sys/ioctl.h> 12 #include <sys/socket.h> 13 #include <sys/un.h> 14 15 #include <net/netlib.h> 16 #include <net/gen/in.h> 17 #include <net/gen/tcp.h> 18 #include <net/gen/tcp_io.h> 19 #include <net/gen/udp.h> 20 #include <net/gen/udp_io.h> 21 22 static int _tcp_accept(int sock, struct sockaddr *__restrict address, 23 socklen_t *__restrict address_len); 24 25 static int _uds_accept(int sock, struct sockaddr *__restrict address, 26 socklen_t *__restrict address_len); 27 28 /* 29 * Accept a connection on a listening socket, creating a new socket. 30 */ 31 static int 32 __accept(int fd, struct sockaddr * __restrict address, 33 socklen_t * __restrict address_len) 34 { 35 message m; 36 int r; 37 38 if (address != NULL && address_len == NULL) { 39 errno = EFAULT; 40 return -1; 41 } 42 43 memset(&m, 0, sizeof(m)); 44 m.m_lc_vfs_sockaddr.fd = fd; 45 m.m_lc_vfs_sockaddr.addr = (vir_bytes)address; 46 m.m_lc_vfs_sockaddr.addr_len = (address != NULL) ? *address_len : 0; 47 48 if ((r = _syscall(VFS_PROC_NR, VFS_ACCEPT, &m)) < 0) 49 return -1; 50 51 if (address != NULL) 52 *address_len = m.m_vfs_lc_socklen.len; 53 return r; 54 } 55 56 int accept(int sock, struct sockaddr *__restrict address, 57 socklen_t *__restrict address_len) 58 { 59 int r; 60 nwio_udpopt_t udpopt; 61 62 r = __accept(sock, address, address_len); 63 if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS)) 64 return r; 65 66 r= _tcp_accept(sock, address, address_len); 67 if (r != -1 || errno != ENOTTY) 68 return r; 69 70 r= _uds_accept(sock, address, address_len); 71 if (r != -1 || errno != ENOTTY) 72 return r; 73 74 /* Unfortunately, we have to return EOPNOTSUPP for a socket that 75 * does not support accept (such as a UDP socket) and ENOTSOCK for 76 * filedescriptors that do not refer to a socket. 77 */ 78 r= ioctl(sock, NWIOGUDPOPT, &udpopt); 79 if (r == 0 || (r == -1 && errno != ENOTTY)) { 80 /* UDP socket */ 81 errno= EOPNOTSUPP; 82 return -1; 83 } 84 85 errno = ENOTSOCK; 86 return -1; 87 } 88 89 static int _tcp_accept(int sock, struct sockaddr *__restrict address, 90 socklen_t *__restrict address_len) 91 { 92 int r, s1, t_errno; 93 tcp_cookie_t cookie; 94 95 s1= open(TCP_DEVICE, O_RDWR); 96 if (s1 == -1) 97 return s1; 98 r= ioctl(s1, NWIOGTCPCOOKIE, &cookie); 99 if (r == -1) 100 { 101 t_errno= errno; 102 close(s1); 103 errno= t_errno; 104 return -1; 105 } 106 r= ioctl(sock, NWIOTCPACCEPTTO, &cookie); 107 if (r == -1) 108 { 109 t_errno= errno; 110 close(s1); 111 errno= t_errno; 112 return -1; 113 } 114 if (address != NULL) 115 getpeername(s1, address, address_len); 116 return s1; 117 } 118 119 static int _uds_accept(int sock, struct sockaddr *__restrict address, 120 socklen_t *__restrict address_len) 121 { 122 int s1; 123 int r; 124 struct sockaddr_un uds_addr; 125 socklen_t len; 126 127 memset(&uds_addr, '\0', sizeof(struct sockaddr_un)); 128 129 r= ioctl(sock, NWIOGUDSADDR, &uds_addr); 130 if (r == -1) { 131 return r; 132 } 133 134 if (uds_addr.sun_family != AF_UNIX) { 135 errno= EINVAL; 136 return -1; 137 } 138 139 len= *address_len; 140 if (len > sizeof(struct sockaddr_un)) 141 len = sizeof(struct sockaddr_un); 142 143 memcpy(address, &uds_addr, len); 144 *address_len= len; 145 146 s1= open(UDS_DEVICE, O_RDWR); 147 if (s1 == -1) 148 return s1; 149 150 /* Copy file descriptor flags from the listening socket. */ 151 fcntl(s1, F_SETFL, fcntl(sock, F_GETFL)); 152 153 r= ioctl(s1, NWIOSUDSACCEPT, address); 154 if (r == -1) { 155 int ioctl_errno = errno; 156 close(s1); 157 errno = ioctl_errno; 158 return r; 159 } 160 161 return s1; 162 } 163