xref: /minix3/minix/lib/libc/sys/getsockopt.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc #include <sys/cdefs.h>
2*433d6423SLionel Sambuc #include "namespace.h"
3*433d6423SLionel Sambuc 
4*433d6423SLionel Sambuc #include <assert.h>
5*433d6423SLionel Sambuc #include <errno.h>
6*433d6423SLionel Sambuc #include <stdio.h>
7*433d6423SLionel Sambuc #include <string.h>
8*433d6423SLionel Sambuc #include <sys/ioctl.h>
9*433d6423SLionel Sambuc #include <sys/socket.h>
10*433d6423SLionel Sambuc #include <sys/types.h>
11*433d6423SLionel Sambuc #include <sys/ucred.h>
12*433d6423SLionel Sambuc #include <netinet/tcp.h>
13*433d6423SLionel Sambuc 
14*433d6423SLionel Sambuc #include <net/gen/in.h>
15*433d6423SLionel Sambuc #include <net/gen/tcp.h>
16*433d6423SLionel Sambuc #include <net/gen/tcp_io.h>
17*433d6423SLionel Sambuc #include <net/gen/udp.h>
18*433d6423SLionel Sambuc #include <net/gen/udp_io.h>
19*433d6423SLionel Sambuc 
20*433d6423SLionel Sambuc #include <minix/type.h>
21*433d6423SLionel Sambuc 
22*433d6423SLionel Sambuc #define DEBUG 0
23*433d6423SLionel Sambuc 
24*433d6423SLionel Sambuc static int _tcp_getsockopt(int sock, int level, int option_name,
25*433d6423SLionel Sambuc 	void *__restrict option_value, socklen_t *__restrict option_len);
26*433d6423SLionel Sambuc static int _udp_getsockopt(int sock, int level, int option_name,
27*433d6423SLionel Sambuc 	void *__restrict option_value, socklen_t *__restrict option_len);
28*433d6423SLionel Sambuc static int _uds_getsockopt(int sock, int level, int option_name,
29*433d6423SLionel Sambuc 	void *__restrict option_value, socklen_t *__restrict option_len);
30*433d6423SLionel Sambuc static void getsockopt_copy(void *return_value, size_t return_len,
31*433d6423SLionel Sambuc 	void *__restrict option_value, socklen_t *__restrict option_len);
32*433d6423SLionel Sambuc 
33*433d6423SLionel Sambuc int getsockopt(int sock, int level, int option_name,
34*433d6423SLionel Sambuc         void *__restrict option_value, socklen_t *__restrict option_len)
35*433d6423SLionel Sambuc {
36*433d6423SLionel Sambuc 	int r;
37*433d6423SLionel Sambuc 	nwio_tcpopt_t tcpopt;
38*433d6423SLionel Sambuc 	nwio_udpopt_t udpopt;
39*433d6423SLionel Sambuc 	struct sockaddr_un uds_addr;
40*433d6423SLionel Sambuc 
41*433d6423SLionel Sambuc 	r= ioctl(sock, NWIOGTCPOPT, &tcpopt);
42*433d6423SLionel Sambuc 	if (r != -1 || errno != ENOTTY)
43*433d6423SLionel Sambuc 	{
44*433d6423SLionel Sambuc 		if (r == -1)
45*433d6423SLionel Sambuc 		{
46*433d6423SLionel Sambuc 			/* Bad file descriptor */
47*433d6423SLionel Sambuc 			return -1;
48*433d6423SLionel Sambuc 		}
49*433d6423SLionel Sambuc 		return _tcp_getsockopt(sock, level, option_name,
50*433d6423SLionel Sambuc 			option_value, option_len);
51*433d6423SLionel Sambuc 	}
52*433d6423SLionel Sambuc 
53*433d6423SLionel Sambuc 	r= ioctl(sock, NWIOGUDPOPT, &udpopt);
54*433d6423SLionel Sambuc 	if (r != -1 || errno != ENOTTY)
55*433d6423SLionel Sambuc 	{
56*433d6423SLionel Sambuc 		if (r == -1)
57*433d6423SLionel Sambuc 		{
58*433d6423SLionel Sambuc 			/* Bad file descriptor */
59*433d6423SLionel Sambuc 			return -1;
60*433d6423SLionel Sambuc 		}
61*433d6423SLionel Sambuc 		return _udp_getsockopt(sock, level, option_name,
62*433d6423SLionel Sambuc 			option_value, option_len);
63*433d6423SLionel Sambuc 	}
64*433d6423SLionel Sambuc 
65*433d6423SLionel Sambuc 	r= ioctl(sock, NWIOGUDSADDR, &uds_addr);
66*433d6423SLionel Sambuc 	if (r != -1 || errno != ENOTTY)
67*433d6423SLionel Sambuc 	{
68*433d6423SLionel Sambuc 		if (r == -1)
69*433d6423SLionel Sambuc 		{
70*433d6423SLionel Sambuc 			/* Bad file descriptor */
71*433d6423SLionel Sambuc 			return -1;
72*433d6423SLionel Sambuc 		}
73*433d6423SLionel Sambuc 		return _uds_getsockopt(sock, level, option_name,
74*433d6423SLionel Sambuc 			option_value, option_len);
75*433d6423SLionel Sambuc 	}
76*433d6423SLionel Sambuc 
77*433d6423SLionel Sambuc 
78*433d6423SLionel Sambuc #if DEBUG
79*433d6423SLionel Sambuc 	fprintf(stderr, "getsockopt: not implemented for fd %d\n", sock);
80*433d6423SLionel Sambuc #endif
81*433d6423SLionel Sambuc 	errno= ENOTSOCK;
82*433d6423SLionel Sambuc 	return -1;
83*433d6423SLionel Sambuc }
84*433d6423SLionel Sambuc 
85*433d6423SLionel Sambuc static void getsockopt_copy(void *return_value, size_t return_len,
86*433d6423SLionel Sambuc 	void *__restrict option_value, socklen_t *__restrict option_len)
87*433d6423SLionel Sambuc {
88*433d6423SLionel Sambuc 	/* copy as much data as possible */
89*433d6423SLionel Sambuc 	if (*option_len < return_len)
90*433d6423SLionel Sambuc 		memcpy(option_value, return_value, *option_len);
91*433d6423SLionel Sambuc 	else
92*433d6423SLionel Sambuc 		memcpy(option_value, return_value, return_len);
93*433d6423SLionel Sambuc 
94*433d6423SLionel Sambuc 	/* return length */
95*433d6423SLionel Sambuc 	*option_len = return_len;
96*433d6423SLionel Sambuc }
97*433d6423SLionel Sambuc 
98*433d6423SLionel Sambuc static int _tcp_getsockopt(int sock, int level, int option_name,
99*433d6423SLionel Sambuc 	void *__restrict option_value, socklen_t *__restrict option_len)
100*433d6423SLionel Sambuc {
101*433d6423SLionel Sambuc 	int i, r, err;
102*433d6423SLionel Sambuc 
103*433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
104*433d6423SLionel Sambuc 	{
105*433d6423SLionel Sambuc 		i = 1;	/* Binds to TIME_WAIT sockets never cause errors */
106*433d6423SLionel Sambuc 		getsockopt_copy(&i, sizeof(i), option_value, option_len);
107*433d6423SLionel Sambuc 		return 0;
108*433d6423SLionel Sambuc 	}
109*433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_KEEPALIVE)
110*433d6423SLionel Sambuc 	{
111*433d6423SLionel Sambuc 		i = 1;	/* Keepalive is always on */
112*433d6423SLionel Sambuc 		getsockopt_copy(&i, sizeof(i), option_value, option_len);
113*433d6423SLionel Sambuc 		return 0;
114*433d6423SLionel Sambuc 	}
115*433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_ERROR)
116*433d6423SLionel Sambuc 	{
117*433d6423SLionel Sambuc 		r = ioctl(sock, NWIOTCPGERROR, &err);
118*433d6423SLionel Sambuc 		if (r != 0)
119*433d6423SLionel Sambuc 			return r;
120*433d6423SLionel Sambuc 
121*433d6423SLionel Sambuc 		getsockopt_copy(&err, sizeof(err), option_value, option_len);
122*433d6423SLionel Sambuc 		return 0;
123*433d6423SLionel Sambuc 	}
124*433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_RCVBUF)
125*433d6423SLionel Sambuc 	{
126*433d6423SLionel Sambuc 		i = 32 * 1024;	/* Receive buffer in the current
127*433d6423SLionel Sambuc 		              	 * implementation
128*433d6423SLionel Sambuc 				 */
129*433d6423SLionel Sambuc 		getsockopt_copy(&i, sizeof(i), option_value, option_len);
130*433d6423SLionel Sambuc 		return 0;
131*433d6423SLionel Sambuc 	}
132*433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_SNDBUF)
133*433d6423SLionel Sambuc 	{
134*433d6423SLionel Sambuc 		i = 32 * 1024;	/* Send buffer in the current implementation */
135*433d6423SLionel Sambuc 		getsockopt_copy(&i, sizeof(i), option_value, option_len);
136*433d6423SLionel Sambuc 		return 0;
137*433d6423SLionel Sambuc 	}
138*433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_TYPE)
139*433d6423SLionel Sambuc 	{
140*433d6423SLionel Sambuc 		i = SOCK_STREAM;	/* this is a TCP socket */
141*433d6423SLionel Sambuc 		getsockopt_copy(&i, sizeof(i), option_value, option_len);
142*433d6423SLionel Sambuc 		return 0;
143*433d6423SLionel Sambuc 	}
144*433d6423SLionel Sambuc 	if (level == IPPROTO_TCP && option_name == TCP_NODELAY)
145*433d6423SLionel Sambuc 	{
146*433d6423SLionel Sambuc 		i = 0;	/* nodelay is always off */
147*433d6423SLionel Sambuc 		getsockopt_copy(&i, sizeof(i), option_value, option_len);
148*433d6423SLionel Sambuc 		return 0;
149*433d6423SLionel Sambuc 	}
150*433d6423SLionel Sambuc #if DEBUG
151*433d6423SLionel Sambuc 	fprintf(stderr, "_tcp_getsocketopt: level %d, name %d\n",
152*433d6423SLionel Sambuc 		level, option_name);
153*433d6423SLionel Sambuc #endif
154*433d6423SLionel Sambuc 
155*433d6423SLionel Sambuc 	errno= ENOPROTOOPT;
156*433d6423SLionel Sambuc 	return -1;
157*433d6423SLionel Sambuc }
158*433d6423SLionel Sambuc 
159*433d6423SLionel Sambuc static int _udp_getsockopt(int sock, int level, int option_name,
160*433d6423SLionel Sambuc 	void *__restrict option_value, socklen_t *__restrict option_len)
161*433d6423SLionel Sambuc {
162*433d6423SLionel Sambuc 	int i;
163*433d6423SLionel Sambuc 
164*433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_TYPE)
165*433d6423SLionel Sambuc 	{
166*433d6423SLionel Sambuc 		i = SOCK_DGRAM;	/* this is a UDP socket */
167*433d6423SLionel Sambuc 		getsockopt_copy(&i, sizeof(i), option_value, option_len);
168*433d6423SLionel Sambuc 		return 0;
169*433d6423SLionel Sambuc 	}
170*433d6423SLionel Sambuc #if DEBUG
171*433d6423SLionel Sambuc 	fprintf(stderr, "_udp_getsocketopt: level %d, name %d\n",
172*433d6423SLionel Sambuc 		level, option_name);
173*433d6423SLionel Sambuc #endif
174*433d6423SLionel Sambuc 
175*433d6423SLionel Sambuc 	errno= ENOSYS;
176*433d6423SLionel Sambuc 	return -1;
177*433d6423SLionel Sambuc }
178*433d6423SLionel Sambuc 
179*433d6423SLionel Sambuc static int _uds_getsockopt(int sock, int level, int option_name,
180*433d6423SLionel Sambuc 	void *__restrict option_value, socklen_t *__restrict option_len)
181*433d6423SLionel Sambuc {
182*433d6423SLionel Sambuc 	int i, r;
183*433d6423SLionel Sambuc 	size_t size;
184*433d6423SLionel Sambuc 
185*433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_RCVBUF)
186*433d6423SLionel Sambuc 	{
187*433d6423SLionel Sambuc  		r= ioctl(sock, NWIOGUDSRCVBUF, &size);
188*433d6423SLionel Sambuc 		if (r == -1) {
189*433d6423SLionel Sambuc 			return r;
190*433d6423SLionel Sambuc 		}
191*433d6423SLionel Sambuc 
192*433d6423SLionel Sambuc 		getsockopt_copy(&size, sizeof(size), option_value, option_len);
193*433d6423SLionel Sambuc 		return 0;
194*433d6423SLionel Sambuc 	}
195*433d6423SLionel Sambuc 
196*433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_SNDBUF)
197*433d6423SLionel Sambuc 	{
198*433d6423SLionel Sambuc  		r= ioctl(sock, NWIOGUDSSNDBUF, &size);
199*433d6423SLionel Sambuc 		if (r == -1) {
200*433d6423SLionel Sambuc 			return r;
201*433d6423SLionel Sambuc 		}
202*433d6423SLionel Sambuc 
203*433d6423SLionel Sambuc 		getsockopt_copy(&size, sizeof(size), option_value, option_len);
204*433d6423SLionel Sambuc 		return 0;
205*433d6423SLionel Sambuc 	}
206*433d6423SLionel Sambuc 
207*433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_TYPE)
208*433d6423SLionel Sambuc 	{
209*433d6423SLionel Sambuc  		r= ioctl(sock, NWIOGUDSSOTYPE, &i);
210*433d6423SLionel Sambuc 		if (r == -1) {
211*433d6423SLionel Sambuc 			return r;
212*433d6423SLionel Sambuc 		}
213*433d6423SLionel Sambuc 
214*433d6423SLionel Sambuc 		getsockopt_copy(&i, sizeof(i), option_value, option_len);
215*433d6423SLionel Sambuc 		return 0;
216*433d6423SLionel Sambuc 	}
217*433d6423SLionel Sambuc 
218*433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_PEERCRED)
219*433d6423SLionel Sambuc 	{
220*433d6423SLionel Sambuc 		struct uucred cred;
221*433d6423SLionel Sambuc 
222*433d6423SLionel Sambuc 		r= ioctl(sock, NWIOGUDSPEERCRED, &cred);
223*433d6423SLionel Sambuc 		if (r == -1) {
224*433d6423SLionel Sambuc 			return -1;
225*433d6423SLionel Sambuc 		}
226*433d6423SLionel Sambuc 
227*433d6423SLionel Sambuc 		getsockopt_copy(&cred, sizeof(struct uucred), option_value,
228*433d6423SLionel Sambuc 							option_len);
229*433d6423SLionel Sambuc 		return 0;
230*433d6423SLionel Sambuc 	}
231*433d6423SLionel Sambuc 
232*433d6423SLionel Sambuc 
233*433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
234*433d6423SLionel Sambuc 	{
235*433d6423SLionel Sambuc 		i = 1;	/* as long as nobody is listen()ing on the address,
236*433d6423SLionel Sambuc 			 * it can be reused without waiting for a
237*433d6423SLionel Sambuc 			 * timeout to expire.
238*433d6423SLionel Sambuc 			 */
239*433d6423SLionel Sambuc 		getsockopt_copy(&i, sizeof(i), option_value, option_len);
240*433d6423SLionel Sambuc 		return 0;
241*433d6423SLionel Sambuc 	}
242*433d6423SLionel Sambuc 
243*433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_PASSCRED)
244*433d6423SLionel Sambuc 	{
245*433d6423SLionel Sambuc 		i = 1;	/* option is always 'on' */
246*433d6423SLionel Sambuc 		getsockopt_copy(&i, sizeof(i), option_value, option_len);
247*433d6423SLionel Sambuc 		return 0;
248*433d6423SLionel Sambuc 	}
249*433d6423SLionel Sambuc 
250*433d6423SLionel Sambuc #if DEBUG
251*433d6423SLionel Sambuc 	fprintf(stderr, "_uds_getsocketopt: level %d, name %d\n",
252*433d6423SLionel Sambuc 		level, option_name);
253*433d6423SLionel Sambuc #endif
254*433d6423SLionel Sambuc 
255*433d6423SLionel Sambuc 	errno= ENOSYS;
256*433d6423SLionel Sambuc 	return -1;
257*433d6423SLionel Sambuc }
258