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