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