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