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