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