1433d6423SLionel Sambuc #include <sys/cdefs.h> 2433d6423SLionel Sambuc #include "namespace.h" 3*c38dbb97SDavid van Moolenbroek #include <lib.h> 4433d6423SLionel Sambuc 5433d6423SLionel Sambuc #include <errno.h> 6433d6423SLionel Sambuc #include <fcntl.h> 7433d6423SLionel Sambuc #include <stdio.h> 8433d6423SLionel Sambuc #include <stdlib.h> 9433d6423SLionel Sambuc #include <unistd.h> 10433d6423SLionel Sambuc #include <string.h> 11433d6423SLionel Sambuc #include <sys/ioctl.h> 12433d6423SLionel Sambuc #include <sys/socket.h> 13433d6423SLionel Sambuc #include <sys/un.h> 14433d6423SLionel Sambuc 15433d6423SLionel Sambuc #include <net/netlib.h> 16433d6423SLionel Sambuc #include <net/gen/in.h> 17433d6423SLionel Sambuc #include <net/gen/tcp.h> 18433d6423SLionel Sambuc #include <net/gen/tcp_io.h> 19433d6423SLionel Sambuc #include <net/gen/udp.h> 20433d6423SLionel Sambuc #include <net/gen/udp_io.h> 21433d6423SLionel Sambuc 22433d6423SLionel Sambuc static int _tcp_accept(int sock, struct sockaddr *__restrict address, 23433d6423SLionel Sambuc socklen_t *__restrict address_len); 24433d6423SLionel Sambuc 25433d6423SLionel Sambuc static int _uds_accept(int sock, struct sockaddr *__restrict address, 26433d6423SLionel Sambuc socklen_t *__restrict address_len); 27433d6423SLionel Sambuc 28*c38dbb97SDavid van Moolenbroek /* 29*c38dbb97SDavid van Moolenbroek * Accept a connection on a listening socket, creating a new socket. 30*c38dbb97SDavid van Moolenbroek */ 31*c38dbb97SDavid van Moolenbroek static int 32*c38dbb97SDavid van Moolenbroek __accept(int fd, struct sockaddr * __restrict address, 33*c38dbb97SDavid van Moolenbroek socklen_t * __restrict address_len) 34*c38dbb97SDavid van Moolenbroek { 35*c38dbb97SDavid van Moolenbroek message m; 36*c38dbb97SDavid van Moolenbroek int r; 37*c38dbb97SDavid van Moolenbroek 38*c38dbb97SDavid van Moolenbroek if (address != NULL && address_len == NULL) { 39*c38dbb97SDavid van Moolenbroek errno = EFAULT; 40*c38dbb97SDavid van Moolenbroek return -1; 41*c38dbb97SDavid van Moolenbroek } 42*c38dbb97SDavid van Moolenbroek 43*c38dbb97SDavid van Moolenbroek memset(&m, 0, sizeof(m)); 44*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockaddr.fd = fd; 45*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockaddr.addr = (vir_bytes)address; 46*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockaddr.addr_len = (address != NULL) ? *address_len : 0; 47*c38dbb97SDavid van Moolenbroek 48*c38dbb97SDavid van Moolenbroek if ((r = _syscall(VFS_PROC_NR, VFS_ACCEPT, &m)) < 0) 49*c38dbb97SDavid van Moolenbroek return -1; 50*c38dbb97SDavid van Moolenbroek 51*c38dbb97SDavid van Moolenbroek if (address != NULL) 52*c38dbb97SDavid van Moolenbroek *address_len = m.m_vfs_lc_socklen.len; 53*c38dbb97SDavid van Moolenbroek return r; 54*c38dbb97SDavid van Moolenbroek } 55*c38dbb97SDavid van Moolenbroek 56433d6423SLionel Sambuc int accept(int sock, struct sockaddr *__restrict address, 57433d6423SLionel Sambuc socklen_t *__restrict address_len) 58433d6423SLionel Sambuc { 59433d6423SLionel Sambuc int r; 60433d6423SLionel Sambuc nwio_udpopt_t udpopt; 61433d6423SLionel Sambuc 62*c38dbb97SDavid van Moolenbroek r = __accept(sock, address, address_len); 63*c38dbb97SDavid van Moolenbroek if (r != -1 || errno != ENOTSOCK) 64*c38dbb97SDavid van Moolenbroek return r; 65*c38dbb97SDavid van Moolenbroek 66433d6423SLionel Sambuc r= _tcp_accept(sock, address, address_len); 67433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 68433d6423SLionel Sambuc return r; 69433d6423SLionel Sambuc 70433d6423SLionel Sambuc r= _uds_accept(sock, address, address_len); 71433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 72433d6423SLionel Sambuc return r; 73433d6423SLionel Sambuc 74433d6423SLionel Sambuc /* Unfortunately, we have to return EOPNOTSUPP for a socket that 75433d6423SLionel Sambuc * does not support accept (such as a UDP socket) and ENOTSOCK for 76433d6423SLionel Sambuc * filedescriptors that do not refer to a socket. 77433d6423SLionel Sambuc */ 78433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDPOPT, &udpopt); 79*c38dbb97SDavid van Moolenbroek if (r == 0 || (r == -1 && errno != ENOTTY)) { 80433d6423SLionel Sambuc /* UDP socket */ 81433d6423SLionel Sambuc errno= EOPNOTSUPP; 82433d6423SLionel Sambuc return -1; 83433d6423SLionel Sambuc } 84*c38dbb97SDavid van Moolenbroek 85433d6423SLionel Sambuc errno = ENOTSOCK; 86433d6423SLionel Sambuc return -1; 87433d6423SLionel Sambuc } 88433d6423SLionel Sambuc 89433d6423SLionel Sambuc static int _tcp_accept(int sock, struct sockaddr *__restrict address, 90433d6423SLionel Sambuc socklen_t *__restrict address_len) 91433d6423SLionel Sambuc { 92433d6423SLionel Sambuc int r, s1, t_errno; 93433d6423SLionel Sambuc tcp_cookie_t cookie; 94433d6423SLionel Sambuc 95433d6423SLionel Sambuc s1= open(TCP_DEVICE, O_RDWR); 96433d6423SLionel Sambuc if (s1 == -1) 97433d6423SLionel Sambuc return s1; 98433d6423SLionel Sambuc r= ioctl(s1, NWIOGTCPCOOKIE, &cookie); 99433d6423SLionel Sambuc if (r == -1) 100433d6423SLionel Sambuc { 101433d6423SLionel Sambuc t_errno= errno; 102433d6423SLionel Sambuc close(s1); 103433d6423SLionel Sambuc errno= t_errno; 104433d6423SLionel Sambuc return -1; 105433d6423SLionel Sambuc } 106433d6423SLionel Sambuc r= ioctl(sock, NWIOTCPACCEPTTO, &cookie); 107433d6423SLionel Sambuc if (r == -1) 108433d6423SLionel Sambuc { 109433d6423SLionel Sambuc t_errno= errno; 110433d6423SLionel Sambuc close(s1); 111433d6423SLionel Sambuc errno= t_errno; 112433d6423SLionel Sambuc return -1; 113433d6423SLionel Sambuc } 114433d6423SLionel Sambuc if (address != NULL) 115433d6423SLionel Sambuc getpeername(s1, address, address_len); 116433d6423SLionel Sambuc return s1; 117433d6423SLionel Sambuc } 118433d6423SLionel Sambuc 119433d6423SLionel Sambuc static int _uds_accept(int sock, struct sockaddr *__restrict address, 120433d6423SLionel Sambuc socklen_t *__restrict address_len) 121433d6423SLionel Sambuc { 122433d6423SLionel Sambuc int s1; 123433d6423SLionel Sambuc int r; 124433d6423SLionel Sambuc struct sockaddr_un uds_addr; 125433d6423SLionel Sambuc socklen_t len; 126433d6423SLionel Sambuc 127433d6423SLionel Sambuc memset(&uds_addr, '\0', sizeof(struct sockaddr_un)); 128433d6423SLionel Sambuc 129433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDSADDR, &uds_addr); 130433d6423SLionel Sambuc if (r == -1) { 131433d6423SLionel Sambuc return r; 132433d6423SLionel Sambuc } 133433d6423SLionel Sambuc 134433d6423SLionel Sambuc if (uds_addr.sun_family != AF_UNIX) { 135433d6423SLionel Sambuc errno= EINVAL; 136433d6423SLionel Sambuc return -1; 137433d6423SLionel Sambuc } 138433d6423SLionel Sambuc 139433d6423SLionel Sambuc len= *address_len; 140433d6423SLionel Sambuc if (len > sizeof(struct sockaddr_un)) 141433d6423SLionel Sambuc len = sizeof(struct sockaddr_un); 142433d6423SLionel Sambuc 143433d6423SLionel Sambuc memcpy(address, &uds_addr, len); 144433d6423SLionel Sambuc *address_len= len; 145433d6423SLionel Sambuc 146433d6423SLionel Sambuc s1= open(UDS_DEVICE, O_RDWR); 147433d6423SLionel Sambuc if (s1 == -1) 148433d6423SLionel Sambuc return s1; 149433d6423SLionel Sambuc 150433d6423SLionel Sambuc /* Copy file descriptor flags from the listening socket. */ 151433d6423SLionel Sambuc fcntl(s1, F_SETFL, fcntl(sock, F_GETFL)); 152433d6423SLionel Sambuc 153433d6423SLionel Sambuc r= ioctl(s1, NWIOSUDSACCEPT, address); 154433d6423SLionel Sambuc if (r == -1) { 155433d6423SLionel Sambuc int ioctl_errno = errno; 156433d6423SLionel Sambuc close(s1); 157433d6423SLionel Sambuc errno = ioctl_errno; 158433d6423SLionel Sambuc return r; 159433d6423SLionel Sambuc } 160433d6423SLionel Sambuc 161433d6423SLionel Sambuc return s1; 162433d6423SLionel Sambuc } 163