sockopts.c 10 KB

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