xref: /minix3/minix/lib/libc/sys/setsockopt.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1  #include <sys/cdefs.h>
2  #include "namespace.h"
3  
4  #include <assert.h>
5  #include <errno.h>
6  #include <stdio.h>
7  #include <sys/ioctl.h>
8  #include <sys/socket.h>
9  #include <sys/types.h>
10  #include <netinet/tcp.h>
11  
12  #include <net/gen/in.h>
13  #include <net/gen/tcp.h>
14  #include <net/gen/tcp_io.h>
15  #include <net/gen/udp.h>
16  #include <net/gen/udp_io.h>
17  
18  #define DEBUG 0
19  
20  static int _tcp_setsockopt(int sock, int level, int option_name,
21  	const void *option_value, socklen_t option_len);
22  
23  static int _udp_setsockopt(int sock, int level, int option_name,
24  	const void *option_value, socklen_t option_len);
25  
26  static int _uds_setsockopt(int sock, int level, int option_name,
27  	const void *option_value, socklen_t option_len);
28  
29  int setsockopt(int sock, int level, int option_name,
30          const void *option_value, socklen_t option_len)
31  {
32  	int r;
33  	nwio_tcpopt_t tcpopt;
34  	nwio_udpopt_t udpopt;
35  	struct sockaddr_un uds_addr;
36  
37  	r= ioctl(sock, NWIOGTCPOPT, &tcpopt);
38  	if (r != -1 || errno != ENOTTY)
39  	{
40  		if (r == -1)
41  		{
42  			/* Bad file descriptor */
43  			return -1;
44  		}
45  		return _tcp_setsockopt(sock, level, option_name,
46  			option_value, option_len);
47  	}
48  
49  	r= ioctl(sock, NWIOGUDPOPT, &udpopt);
50  	if (r != -1 || errno != ENOTTY)
51  	{
52  		if (r == -1)
53  		{
54  			/* Bad file descriptor */
55  			return -1;
56  		}
57  		return _udp_setsockopt(sock, level, option_name,
58  			option_value, option_len);
59  	}
60  
61  	r= ioctl(sock, NWIOGUDSADDR, &uds_addr);
62  	if (r != -1 || errno != ENOTTY)
63  	{
64  		if (r == -1)
65  		{
66  			/* Bad file descriptor */
67  			return -1;
68  		}
69  		return _uds_setsockopt(sock, level, option_name,
70  			option_value, option_len);
71  	}
72  
73  
74  #if DEBUG
75  	fprintf(stderr, "setsockopt: not implemented for fd %d\n", sock);
76  #endif
77  	errno= ENOTSOCK;
78  	return -1;
79  }
80  
81  static int _tcp_setsockopt(int sock, int level, int option_name,
82  	const void *option_value, socklen_t option_len)
83  {
84  	int i;
85  
86  	if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
87  	{
88  		if (option_len != sizeof(i))
89  		{
90  			errno= EINVAL;
91  			return -1;
92  		}
93  		i= *(const int *)option_value;
94  		if (!i)
95  		{
96  			/* At the moment there is no way to turn off
97  			 * reusing addresses.
98  			 */
99  			errno= ENOSYS;
100  			return -1;
101  		}
102  		return 0;
103  	}
104  	if (level == SOL_SOCKET && option_name == SO_KEEPALIVE)
105  	{
106  		if (option_len != sizeof(i))
107  		{
108  			errno= EINVAL;
109  			return -1;
110  		}
111  		i= *(const int *)option_value;
112  		if (!i)
113  		{
114  			/* At the moment there is no way to turn off
115  			 * keepalives.
116  			 */
117  			errno= ENOSYS;
118  			return -1;
119  		}
120  		return 0;
121  	}
122  	if (level == SOL_SOCKET && option_name == SO_RCVBUF)
123  	{
124  		if (option_len != sizeof(i))
125  		{
126  			errno= EINVAL;
127  			return -1;
128  		}
129  		i= *(const int *)option_value;
130  		if (i > 32*1024)
131  		{
132  			/* The receive buffer is limited to 32K at the moment.
133  			 */
134  			errno= ENOSYS;
135  			return -1;
136  		}
137  		/* There is no way to reduce the receive buffer, do we have to
138  		 * let this call fail for smaller buffers?
139  		 */
140  		return 0;
141  	}
142  	if (level == SOL_SOCKET && option_name == SO_SNDBUF)
143  	{
144  		if (option_len != sizeof(i))
145  		{
146  			errno= EINVAL;
147  			return -1;
148  		}
149  		i= *(const int *)option_value;
150  		if (i > 32*1024)
151  		{
152  			/* The send buffer is limited to 32K at the moment.
153  			 */
154  			errno= ENOSYS;
155  			return -1;
156  		}
157  		/* There is no way to reduce the send buffer, do we have to
158  		 * let this call fail for smaller buffers?
159  		 */
160  		return 0;
161  	}
162  	if (level == IPPROTO_TCP && option_name == TCP_NODELAY)
163  	{
164  		if (option_len != sizeof(i))
165  		{
166  			errno= EINVAL;
167  			return -1;
168  		}
169  		i= *(const int *)option_value;
170  		if (i)
171  		{
172  			/* At the moment there is no way to turn on
173  			 * nodelay.
174  			 */
175  			errno= ENOSYS;
176  			return -1;
177  		}
178  		return 0;
179  	}
180  #if DEBUG
181  	fprintf(stderr, "_tcp_setsocketopt: level %d, name %d\n",
182  		level, option_name);
183  #endif
184  
185  	errno= ENOSYS;
186  	return -1;
187  }
188  
189  static int _udp_setsockopt(int sock, int level, int option_name,
190  	const void *option_value, socklen_t option_len)
191  {
192  #if DEBUG
193  	fprintf(stderr, "_udp_setsocketopt: level %d, name %d\n",
194  		level, option_name);
195  #endif
196  
197  	errno= ENOSYS;
198  	return -1;
199  }
200  
201  
202  static int _uds_setsockopt(int sock, int level, int option_name,
203  	const void *option_value, socklen_t option_len)
204  {
205  	int i;
206  	size_t size;
207  
208  	if (level == SOL_SOCKET && option_name == SO_RCVBUF)
209  	{
210  		if (option_len != sizeof(size))
211  		{
212  			errno= EINVAL;
213  			return -1;
214  		}
215  		size= *(const size_t *)option_value;
216  		return ioctl(sock, NWIOSUDSRCVBUF, &size);
217  	}
218  
219  	if (level == SOL_SOCKET && option_name == SO_SNDBUF)
220  	{
221  		if (option_len != sizeof(size))
222  		{
223  			errno= EINVAL;
224  			return -1;
225  		}
226  		size= *(const size_t *)option_value;
227  		return ioctl(sock, NWIOSUDSSNDBUF, &size);
228  	}
229  
230  	if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
231  	{
232  		if (option_len != sizeof(i))
233  		{
234  			errno= EINVAL;
235  			return -1;
236  		}
237  		i= *(const int *)option_value;
238  		if (!i)
239  		{
240  			/* At the moment there is no way to turn off
241  			 * reusing addresses.
242  			 */
243  			errno= ENOSYS;
244  			return -1;
245  		}
246  		return 0;
247  	}
248  
249  	if (level == SOL_SOCKET && option_name == SO_PASSCRED)
250  	{
251  		if (option_len != sizeof(i))
252  		{
253  			errno= EINVAL;
254  			return -1;
255  		}
256  		i= *(const int *)option_value;
257  		if (!i)
258  		{
259  			/* credentials can always be received. */
260  			errno= ENOSYS;
261  			return -1;
262  		}
263  		return 0;
264  	}
265  
266  #if DEBUG
267  	fprintf(stderr, "_uds_setsocketopt: level %d, name %d\n",
268  		level, option_name);
269  #endif
270  
271  	errno= ENOSYS;
272  	return -1;
273  }
274