1433d6423SLionel Sambuc #include <sys/cdefs.h>
2433d6423SLionel Sambuc #include "namespace.h"
3c38dbb97SDavid 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
28c38dbb97SDavid van Moolenbroek /*
29c38dbb97SDavid van Moolenbroek * Accept a connection on a listening socket, creating a new socket.
30c38dbb97SDavid van Moolenbroek */
31c38dbb97SDavid van Moolenbroek static int
__accept(int fd,struct sockaddr * __restrict address,socklen_t * __restrict address_len)32c38dbb97SDavid van Moolenbroek __accept(int fd, struct sockaddr * __restrict address,
33c38dbb97SDavid van Moolenbroek socklen_t * __restrict address_len)
34c38dbb97SDavid van Moolenbroek {
35c38dbb97SDavid van Moolenbroek message m;
36c38dbb97SDavid van Moolenbroek int r;
37c38dbb97SDavid van Moolenbroek
38c38dbb97SDavid van Moolenbroek if (address != NULL && address_len == NULL) {
39c38dbb97SDavid van Moolenbroek errno = EFAULT;
40c38dbb97SDavid van Moolenbroek return -1;
41c38dbb97SDavid van Moolenbroek }
42c38dbb97SDavid van Moolenbroek
43c38dbb97SDavid van Moolenbroek memset(&m, 0, sizeof(m));
44c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockaddr.fd = fd;
45c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockaddr.addr = (vir_bytes)address;
46c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockaddr.addr_len = (address != NULL) ? *address_len : 0;
47c38dbb97SDavid van Moolenbroek
48c38dbb97SDavid van Moolenbroek if ((r = _syscall(VFS_PROC_NR, VFS_ACCEPT, &m)) < 0)
49c38dbb97SDavid van Moolenbroek return -1;
50c38dbb97SDavid van Moolenbroek
51c38dbb97SDavid van Moolenbroek if (address != NULL)
52c38dbb97SDavid van Moolenbroek *address_len = m.m_vfs_lc_socklen.len;
53c38dbb97SDavid van Moolenbroek return r;
54c38dbb97SDavid van Moolenbroek }
55c38dbb97SDavid van Moolenbroek
accept(int sock,struct sockaddr * __restrict address,socklen_t * __restrict address_len)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
62c38dbb97SDavid van Moolenbroek r = __accept(sock, address, address_len);
63*84ed480eSDavid van Moolenbroek if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS))
64c38dbb97SDavid van Moolenbroek return r;
65c38dbb97SDavid 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);
79c38dbb97SDavid van Moolenbroek if (r == 0 || (r == -1 && errno != ENOTTY)) {
80433d6423SLionel Sambuc /* UDP socket */
81433d6423SLionel Sambuc errno= EOPNOTSUPP;
82433d6423SLionel Sambuc return -1;
83433d6423SLionel Sambuc }
84c38dbb97SDavid van Moolenbroek
85433d6423SLionel Sambuc errno = ENOTSOCK;
86433d6423SLionel Sambuc return -1;
87433d6423SLionel Sambuc }
88433d6423SLionel Sambuc
_tcp_accept(int sock,struct sockaddr * __restrict address,socklen_t * __restrict address_len)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
_uds_accept(int sock,struct sockaddr * __restrict address,socklen_t * __restrict address_len)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