1 /*
2 * Copyright (c) 1993 W. Richard Stevens. All rights reserved.
3 * Permission to use or modify this software and its documentation only for
4 * educational purposes and without fee is hereby granted, provided that
5 * the above copyright notice appear in all copies. The author makes no
6 * representations about the suitability of this software for any purpose.
7 * It is provided "as is" without express or implied warranty.
8 */
9
10 #include "sock.h"
11 #include <fcntl.h>
12 #include <sys/ioctl.h>
13
14 void
sockopts(int sockfd,int doall)15 sockopts(int sockfd, int doall)
16 {
17 int option, optlen;
18 struct linger ling;
19 struct timeval timer;
20
21 /* "doall" is 0 for a server's listening socket (i.e., before
22 accept() has returned.) Some socket options such as SO_KEEPALIVE
23 don't make sense at this point, while others like SO_DEBUG do. */
24
25 if (debug) {
26 option = 1;
27 if (setsockopt(sockfd, SOL_SOCKET, SO_DEBUG,
28 &option, sizeof(option)) < 0)
29 err_sys("SO_DEBUG setsockopt error");
30
31 option = 0;
32 optlen = sizeof(option);
33 if (getsockopt(sockfd, SOL_SOCKET, SO_DEBUG,
34 &option, &optlen) < 0)
35 err_sys("SO_DEBUG getsockopt error");
36 if (option == 0)
37 err_quit("SO_DEBUG not set (%d)", option);
38
39 if (verbose)
40 fprintf(stderr, "SO_DEBUG set\n");
41 }
42
43 if (dontroute) {
44 option = 1;
45 if (setsockopt(sockfd, SOL_SOCKET, SO_DONTROUTE,
46 &option, sizeof(option)) < 0)
47 err_sys("SO_DONTROUTE setsockopt error");
48
49 option = 0;
50 optlen = sizeof(option);
51 if (getsockopt(sockfd, SOL_SOCKET, SO_DONTROUTE,
52 &option, &optlen) < 0)
53 err_sys("SO_DONTROUTE getsockopt error");
54 if (option == 0)
55 err_quit("SO_DONTROUTE not set (%d)", option);
56
57 if (verbose)
58 fprintf(stderr, "SO_DONTROUTE set\n");
59 }
60
61 #ifdef IP_TOS
62 if (iptos != -1 && doall == 0) {
63 if (setsockopt(sockfd, IPPROTO_IP, IP_TOS,
64 &iptos, sizeof(iptos)) < 0)
65 err_sys("IP_TOS setsockopt error");
66
67 option = 0;
68 optlen = sizeof(option);
69 if (getsockopt(sockfd, IPPROTO_IP, IP_TOS,
70 &option, &optlen) < 0)
71 err_sys("IP_TOS getsockopt error");
72 if (option != iptos)
73 err_quit("IP_TOS not set (%d)", option);
74
75 if (verbose)
76 fprintf(stderr, "IP_TOS set to %d\n", iptos);
77 }
78 #endif
79
80 #ifdef IP_TTL
81 if (ipttl != -1 && doall == 0) {
82 if (setsockopt(sockfd, IPPROTO_IP, IP_TTL,
83 &ipttl, sizeof(ipttl)) < 0)
84 err_sys("IP_TTL setsockopt error");
85
86 option = 0;
87 optlen = sizeof(option);
88 if (getsockopt(sockfd, IPPROTO_IP, IP_TTL,
89 &option, &optlen) < 0)
90 err_sys("IP_TTL getsockopt error");
91 if (option != ipttl)
92 err_quit("IP_TTL not set (%d)", option);
93
94 if (verbose)
95 fprintf(stderr, "IP_TTL set to %d\n", ipttl);
96 }
97 #endif
98
99 if (maxseg && udp == 0) {
100 /* Need to set MSS for server before connection established */
101 /* Beware: some kernels do not let the process set this socket
102 option; others only let it be decreased. */
103 if (setsockopt(sockfd, IPPROTO_TCP, TCP_MAXSEG,
104 &maxseg, sizeof(maxseg)) < 0)
105 err_sys("TCP_MAXSEG setsockopt error");
106
107 option = 0;
108 optlen = sizeof(option);
109 if (getsockopt(sockfd, IPPROTO_TCP, TCP_MAXSEG,
110 &option, &optlen) < 0)
111 err_sys("TCP_MAXSEG getsockopt error");
112
113 if (verbose)
114 fprintf(stderr, "TCP_MAXSEG = %d\n", option);
115 }
116
117 if (sroute_cnt > 0)
118 sroute_set(sockfd);
119
120 if (broadcast) {
121 option = 1;
122 if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST,
123 &option, sizeof(option)) < 0)
124 err_sys("SO_BROADCAST setsockopt error");
125
126 option = 0;
127 optlen = sizeof(option);
128 if (getsockopt(sockfd, SOL_SOCKET, SO_BROADCAST,
129 &option, &optlen) < 0)
130 err_sys("SO_BROADCAST getsockopt error");
131 if (option == 0)
132 err_quit("SO_BROADCAST not set (%d)", option);
133
134 if (verbose)
135 fprintf(stderr, "SO_BROADCAST set\n");
136
137 #ifdef IP_ONESBCAST
138 if (onesbcast) {
139 option = 1;
140 if (setsockopt(sockfd, IPPROTO_IP, IP_ONESBCAST,
141 &option, sizeof(option)) < 0)
142 err_sys("IP_ONESBCAST setsockopt error");
143
144 option = 0;
145 optlen = sizeof(option);
146 if (getsockopt(sockfd, IPPROTO_IP, IP_ONESBCAST,
147 &option, &optlen) < 0)
148 err_sys("IP_ONESBCAST getsockopt error");
149 if (option == 0)
150 err_quit("IP_ONESBCAST not set (%d)", option);
151
152 if (verbose)
153 fprintf(stderr, "IP_ONESBCAST set\n");
154 }
155 #endif
156 }
157
158 #ifdef IP_ADD_MEMBERSHIP
159 if (joinip[0]) {
160 struct ip_mreq join;
161
162 if (inet_aton(joinip, &join.imr_multiaddr) == 0)
163 err_quit("invalid multicast address: %s", joinip);
164 join.imr_interface.s_addr = htonl(INADDR_ANY);
165 if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
166 &join, sizeof(join)) < 0)
167 err_sys("IP_ADD_MEMBERSHIP setsockopt error");
168
169 if (verbose)
170 fprintf(stderr, "IP_ADD_MEMBERSHIP set\n");
171 }
172 #endif
173
174 #ifdef IP_MULTICAST_TTL
175 if (mcastttl) {
176 u_char ttl = mcastttl;
177
178 if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
179 &ttl, sizeof(ttl)) < 0)
180 err_sys("IP_MULTICAST_TTL setsockopt error");
181
182 optlen = sizeof(ttl);
183 if (getsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
184 &ttl, &optlen) < 0)
185 err_sys("IP_MULTICAST_TTL getsockopt error");
186 if (ttl != mcastttl)
187 err_quit("IP_MULTICAST_TTL not set (%d)", ttl);
188
189 if (verbose)
190 fprintf(stderr, "IP_MULTICAST_TTL set to %d\n", ttl);
191 }
192 #endif
193
194 if (keepalive && doall && udp == 0) {
195 option = 1;
196 if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
197 &option, sizeof(option)) < 0)
198 err_sys("SO_KEEPALIVE setsockopt error");
199
200 option = 0;
201 optlen = sizeof(option);
202 if (getsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
203 &option, &optlen) < 0)
204 err_sys("SO_KEEPALIVE getsockopt error");
205 if (option == 0)
206 err_quit("SO_KEEPALIVE not set (%d)", option);
207
208 if (verbose)
209 fprintf(stderr, "SO_KEEPALIVE set\n");
210 }
211
212 if (nodelay && doall && udp == 0) {
213 option = 1;
214 if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,
215 &option, sizeof(option)) < 0)
216 err_sys("TCP_NODELAY setsockopt error");
217
218 option = 0;
219 optlen = sizeof(option);
220 if (getsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,
221 &option, &optlen) < 0)
222 err_sys("TCP_NODELAY getsockopt error");
223 if (option == 0)
224 err_quit("TCP_NODELAY not set (%d)", option);
225
226 if (verbose)
227 fprintf(stderr, "TCP_NODELAY set\n");
228 }
229
230 if (doall && verbose && udp == 0) { /* just print MSS if verbose */
231 option = 0;
232 optlen = sizeof(option);
233 if (getsockopt(sockfd, IPPROTO_TCP, TCP_MAXSEG,
234 &option, &optlen) < 0)
235 err_sys("TCP_MAXSEG getsockopt error");
236
237 fprintf(stderr, "TCP_MAXSEG = %d\n", option);
238 }
239
240 if (linger >= 0 && doall && udp == 0) {
241 ling.l_onoff = 1;
242 ling.l_linger = linger; /* 0 for abortive disconnect */
243 if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER,
244 &ling, sizeof(ling)) < 0)
245 err_sys("SO_LINGER setsockopt error");
246
247 ling.l_onoff = 0;
248 ling.l_linger = -1;
249 optlen = sizeof(struct linger);
250 if (getsockopt(sockfd, SOL_SOCKET, SO_LINGER,
251 &ling, &optlen) < 0)
252 err_sys("SO_LINGER getsockopt error");
253 if (ling.l_onoff == 0 || ling.l_linger != linger)
254 err_quit("SO_LINGER not set (%d, %d)", ling.l_onoff, ling.l_linger);
255
256 if (verbose)
257 fprintf(stderr, "linger %s, time = %d\n",
258 ling.l_onoff ? "on" : "off", ling.l_linger);
259 }
260
261 if (doall && rcvtimeo) {
262 #ifdef SO_RCVTIMEO
263 /* User specifies millisec, must convert to sec/usec */
264 timer.tv_sec = rcvtimeo / 1000;
265 timer.tv_usec = (rcvtimeo % 1000) * 1000;
266 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO,
267 &timer, sizeof(timer)) < 0)
268 err_sys("SO_RCVTIMEO setsockopt error");
269
270 timer.tv_sec = timer.tv_usec = 0;
271 optlen = sizeof(timer);
272 if (getsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO,
273 &timer, &optlen) < 0)
274 err_sys("SO_RCVTIMEO getsockopt error");
275
276 if (verbose)
277 fprintf(stderr, "SO_RCVTIMEO: %ld.%06ld\n",
278 timer.tv_sec, timer.tv_usec);
279 #else
280 fprintf(stderr, "warning: SO_RCVTIMEO not supported by host\n");
281 #endif
282 }
283
284 if (doall && sndtimeo) {
285 #ifdef SO_SNDTIMEO
286 /* User specifies millisec, must convert to sec/usec */
287 timer.tv_sec = sndtimeo / 1000;
288 timer.tv_usec = (sndtimeo % 1000) * 1000;
289 if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO,
290 &timer, sizeof(timer)) < 0)
291 err_sys("SO_SNDTIMEO setsockopt error");
292
293 timer.tv_sec = timer.tv_usec = 0;
294 optlen = sizeof(timer);
295 if (getsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO,
296 &timer, &optlen) < 0)
297 err_sys("SO_SNDTIMEO getsockopt error");
298
299 if (verbose)
300 fprintf(stderr, "SO_SNDTIMEO: %ld.%06ld\n",
301 timer.tv_sec, timer.tv_usec);
302 #else
303 fprintf(stderr, "warning: SO_SNDTIMEO not supported by host\n");
304 #endif
305 }
306
307 if (recvdstaddr && udp) {
308 #ifdef IP_RECVDSTADDR
309 option = 1;
310 if (setsockopt(sockfd, IPPROTO_IP, IP_RECVDSTADDR,
311 &option, sizeof(option)) < 0)
312 err_sys("IP_RECVDSTADDR setsockopt error");
313
314 option = 0;
315 optlen = sizeof(option);
316 if (getsockopt(sockfd, IPPROTO_IP, IP_RECVDSTADDR,
317 &option, &optlen) < 0)
318 err_sys("IP_RECVDSTADDR getsockopt error");
319 if (option == 0)
320 err_quit("IP_RECVDSTADDR not set (%d)", option);
321
322 if (verbose)
323 fprintf(stderr, "IP_RECVDSTADDR set\n");
324 #else
325 fprintf(stderr, "warning: IP_RECVDSTADDR not supported by host\n");
326 #endif
327 }
328
329 if (sigio) {
330 #ifdef FIOASYNC
331 static void sigio_func(int);
332
333 /*
334 * Should be able to set this with fcntl(O_ASYNC) or fcntl(FASYNC),
335 * but some systems (AIX?) only do it with ioctl().
336 *
337 * Need to set this for listening socket and for connected socket.
338 */
339 signal(SIGIO, sigio_func);
340
341 if (fcntl(sockfd, F_SETOWN, getpid()) < 0)
342 err_sys("fcntl F_SETOWN error");
343
344 option = 1;
345 if (ioctl(sockfd, FIOASYNC, (char *) &option) < 0)
346 err_sys("ioctl FIOASYNC error");
347
348 if (verbose)
349 fprintf(stderr, "FIOASYNC set\n");
350 #else
351 fprintf(stderr, "warning: FIOASYNC not supported by host\n");
352 #endif
353 }
354 }
355
356 static void
sigio_func(int signo)357 sigio_func(int signo)
358 {
359 fprintf(stderr, "SIGIO\n");
360 /* shouldn't printf from a signal handler ... */
361 }
362