xref: /minix3/minix/lib/libc/sys/accept.c (revision 84ed480ef770e26a28565a26c8ef94ba01312a41)
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