sockopt.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /* Licensed to the Apache Software Foundation (ASF) under one or more
  2. * contributor license agreements. See the NOTICE file distributed with
  3. * this work for additional information regarding copyright ownership.
  4. * The ASF licenses this file to You under the Apache License, Version 2.0
  5. * (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "apr_arch_networkio.h"
  17. #include "apr_strings.h"
  18. static apr_status_t soblock(int sd)
  19. {
  20. /* BeOS uses setsockopt at present for non blocking... */
  21. #ifndef BEOS
  22. int fd_flags;
  23. fd_flags = fcntl(sd, F_GETFL, 0);
  24. #if defined(O_NONBLOCK)
  25. fd_flags &= ~O_NONBLOCK;
  26. #elif defined(O_NDELAY)
  27. fd_flags &= ~O_NDELAY;
  28. #elif defined(FNDELAY)
  29. fd_flags &= ~FNDELAY;
  30. #else
  31. #error Please teach APR how to make sockets blocking on your platform.
  32. #endif
  33. if (fcntl(sd, F_SETFL, fd_flags) == -1) {
  34. return errno;
  35. }
  36. #else
  37. int on = 0;
  38. if (setsockopt(sd, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)) < 0)
  39. return errno;
  40. #endif /* BEOS */
  41. return APR_SUCCESS;
  42. }
  43. static apr_status_t sononblock(int sd)
  44. {
  45. #ifndef BEOS
  46. int fd_flags;
  47. fd_flags = fcntl(sd, F_GETFL, 0);
  48. #if defined(O_NONBLOCK)
  49. fd_flags |= O_NONBLOCK;
  50. #elif defined(O_NDELAY)
  51. fd_flags |= O_NDELAY;
  52. #elif defined(FNDELAY)
  53. fd_flags |= FNDELAY;
  54. #else
  55. #error Please teach APR how to make sockets non-blocking on your platform.
  56. #endif
  57. if (fcntl(sd, F_SETFL, fd_flags) == -1) {
  58. return errno;
  59. }
  60. #else
  61. int on = 1;
  62. if (setsockopt(sd, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)) < 0)
  63. return errno;
  64. #endif /* BEOS */
  65. return APR_SUCCESS;
  66. }
  67. apr_status_t apr_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
  68. {
  69. apr_status_t stat;
  70. /* If our new timeout is non-negative and our old timeout was
  71. * negative, then we need to ensure that we are non-blocking.
  72. * Conversely, if our new timeout is negative and we had
  73. * non-negative timeout, we must make sure our socket is blocking.
  74. * We want to avoid calling fcntl more than necessary on the
  75. * socket.
  76. */
  77. if (t >= 0 && sock->timeout < 0) {
  78. if (apr_is_option_set(sock, APR_SO_NONBLOCK) != 1) {
  79. if ((stat = sononblock(sock->socketdes)) != APR_SUCCESS) {
  80. return stat;
  81. }
  82. apr_set_option(sock, APR_SO_NONBLOCK, 1);
  83. }
  84. }
  85. else if (t < 0 && sock->timeout >= 0) {
  86. if (apr_is_option_set(sock, APR_SO_NONBLOCK) != 0) {
  87. if ((stat = soblock(sock->socketdes)) != APR_SUCCESS) {
  88. return stat;
  89. }
  90. apr_set_option(sock, APR_SO_NONBLOCK, 0);
  91. }
  92. }
  93. /* must disable the incomplete read support if we disable
  94. * a timeout
  95. */
  96. if (t <= 0) {
  97. sock->options &= ~APR_INCOMPLETE_READ;
  98. }
  99. sock->timeout = t;
  100. return APR_SUCCESS;
  101. }
  102. apr_status_t apr_socket_opt_set(apr_socket_t *sock,
  103. apr_int32_t opt, apr_int32_t on)
  104. {
  105. int one;
  106. apr_status_t rv;
  107. if (on)
  108. one = 1;
  109. else
  110. one = 0;
  111. switch(opt) {
  112. case APR_SO_KEEPALIVE:
  113. #ifdef SO_KEEPALIVE
  114. if (on != apr_is_option_set(sock, APR_SO_KEEPALIVE)) {
  115. if (setsockopt(sock->socketdes, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, sizeof(int)) == -1) {
  116. return errno;
  117. }
  118. apr_set_option(sock, APR_SO_KEEPALIVE, on);
  119. }
  120. #else
  121. return APR_ENOTIMPL;
  122. #endif
  123. break;
  124. case APR_SO_DEBUG:
  125. if (on != apr_is_option_set(sock, APR_SO_DEBUG)) {
  126. if (setsockopt(sock->socketdes, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(int)) == -1) {
  127. return errno;
  128. }
  129. apr_set_option(sock, APR_SO_DEBUG, on);
  130. }
  131. break;
  132. case APR_SO_REUSEADDR:
  133. if (on != apr_is_option_set(sock, APR_SO_REUSEADDR)) {
  134. if (setsockopt(sock->socketdes, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(int)) == -1) {
  135. return errno;
  136. }
  137. apr_set_option(sock, APR_SO_REUSEADDR, on);
  138. }
  139. break;
  140. case APR_SO_SNDBUF:
  141. #ifdef SO_SNDBUF
  142. if (setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDBUF, (void *)&on, sizeof(int)) == -1) {
  143. return errno;
  144. }
  145. #else
  146. return APR_ENOTIMPL;
  147. #endif
  148. break;
  149. case APR_SO_RCVBUF:
  150. #ifdef SO_RCVBUF
  151. if (setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVBUF, (void *)&on, sizeof(int)) == -1) {
  152. return errno;
  153. }
  154. #else
  155. return APR_ENOTIMPL;
  156. #endif
  157. break;
  158. case APR_SO_NONBLOCK:
  159. if (apr_is_option_set(sock, APR_SO_NONBLOCK) != on) {
  160. if (on) {
  161. if ((rv = sononblock(sock->socketdes)) != APR_SUCCESS)
  162. return rv;
  163. }
  164. else {
  165. if ((rv = soblock(sock->socketdes)) != APR_SUCCESS)
  166. return rv;
  167. }
  168. apr_set_option(sock, APR_SO_NONBLOCK, on);
  169. }
  170. break;
  171. case APR_SO_LINGER:
  172. #ifdef SO_LINGER
  173. if (apr_is_option_set(sock, APR_SO_LINGER) != on) {
  174. struct linger li;
  175. li.l_onoff = on;
  176. li.l_linger = APR_MAX_SECS_TO_LINGER;
  177. if (setsockopt(sock->socketdes, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(struct linger)) == -1) {
  178. return errno;
  179. }
  180. apr_set_option(sock, APR_SO_LINGER, on);
  181. }
  182. #else
  183. return APR_ENOTIMPL;
  184. #endif
  185. break;
  186. case APR_TCP_DEFER_ACCEPT:
  187. #if defined(TCP_DEFER_ACCEPT)
  188. if (apr_is_option_set(sock, APR_TCP_DEFER_ACCEPT) != on) {
  189. int optlevel = IPPROTO_TCP;
  190. int optname = TCP_DEFER_ACCEPT;
  191. if (setsockopt(sock->socketdes, optlevel, optname,
  192. (void *)&on, sizeof(int)) == -1) {
  193. return errno;
  194. }
  195. apr_set_option(sock, APR_TCP_DEFER_ACCEPT, on);
  196. }
  197. #else
  198. return APR_ENOTIMPL;
  199. #endif
  200. break;
  201. case APR_TCP_NODELAY:
  202. #if defined(TCP_NODELAY)
  203. if (apr_is_option_set(sock, APR_TCP_NODELAY) != on) {
  204. int optlevel = IPPROTO_TCP;
  205. int optname = TCP_NODELAY;
  206. #if APR_HAVE_SCTP
  207. if (sock->protocol == IPPROTO_SCTP) {
  208. optlevel = IPPROTO_SCTP;
  209. optname = SCTP_NODELAY;
  210. }
  211. #endif
  212. if (setsockopt(sock->socketdes, optlevel, optname, (void *)&on, sizeof(int)) == -1) {
  213. return errno;
  214. }
  215. apr_set_option(sock, APR_TCP_NODELAY, on);
  216. }
  217. #else
  218. /* BeOS pre-BONE has TCP_NODELAY set by default.
  219. * As it can't be turned off we might as well check if they're asking
  220. * for it to be turned on!
  221. */
  222. #ifdef BEOS
  223. if (on == 1)
  224. return APR_SUCCESS;
  225. else
  226. #endif
  227. return APR_ENOTIMPL;
  228. #endif
  229. break;
  230. case APR_TCP_NOPUSH:
  231. #if APR_TCP_NOPUSH_FLAG
  232. /* TCP_NODELAY and TCP_CORK are mutually exclusive on Linux
  233. * kernels < 2.6; on newer kernels they can be used together
  234. * and TCP_CORK takes preference, which is the desired
  235. * behaviour. On older kernels, TCP_NODELAY must be toggled
  236. * to "off" whilst TCP_CORK is in effect. */
  237. if (apr_is_option_set(sock, APR_TCP_NOPUSH) != on) {
  238. #ifndef HAVE_TCP_NODELAY_WITH_CORK
  239. int optlevel = IPPROTO_TCP;
  240. int optname = TCP_NODELAY;
  241. #if APR_HAVE_SCTP
  242. if (sock->protocol == IPPROTO_SCTP) {
  243. optlevel = IPPROTO_SCTP;
  244. optname = SCTP_NODELAY;
  245. }
  246. #endif
  247. /* OK we're going to change some settings here... */
  248. if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1 && on) {
  249. /* Now toggle TCP_NODELAY to off, if TCP_CORK is being
  250. * turned on: */
  251. int tmpflag = 0;
  252. if (setsockopt(sock->socketdes, optlevel, optname,
  253. (void*)&tmpflag, sizeof(int)) == -1) {
  254. return errno;
  255. }
  256. apr_set_option(sock, APR_RESET_NODELAY, 1);
  257. apr_set_option(sock, APR_TCP_NODELAY, 0);
  258. } else if (on) {
  259. apr_set_option(sock, APR_RESET_NODELAY, 0);
  260. }
  261. #endif /* HAVE_TCP_NODELAY_WITH_CORK */
  262. /* OK, now we can just set the TCP_NOPUSH flag accordingly...*/
  263. if (setsockopt(sock->socketdes, IPPROTO_TCP, APR_TCP_NOPUSH_FLAG,
  264. (void*)&on, sizeof(int)) == -1) {
  265. return errno;
  266. }
  267. apr_set_option(sock, APR_TCP_NOPUSH, on);
  268. #ifndef HAVE_TCP_NODELAY_WITH_CORK
  269. if (!on && apr_is_option_set(sock, APR_RESET_NODELAY)) {
  270. /* Now, if TCP_CORK was just turned off, turn
  271. * TCP_NODELAY back on again if it was earlier toggled
  272. * to off: */
  273. int tmpflag = 1;
  274. if (setsockopt(sock->socketdes, optlevel, optname,
  275. (void*)&tmpflag, sizeof(int)) == -1) {
  276. return errno;
  277. }
  278. apr_set_option(sock, APR_RESET_NODELAY,0);
  279. apr_set_option(sock, APR_TCP_NODELAY, 1);
  280. }
  281. #endif /* HAVE_TCP_NODELAY_WITH_CORK */
  282. }
  283. #else
  284. return APR_ENOTIMPL;
  285. #endif
  286. break;
  287. case APR_INCOMPLETE_READ:
  288. apr_set_option(sock, APR_INCOMPLETE_READ, on);
  289. break;
  290. case APR_IPV6_V6ONLY:
  291. #if APR_HAVE_IPV6 && defined(IPV6_V6ONLY)
  292. /* we don't know the initial setting of this option,
  293. * so don't check sock->options since that optimization
  294. * won't work
  295. */
  296. if (setsockopt(sock->socketdes, IPPROTO_IPV6, IPV6_V6ONLY,
  297. (void *)&on, sizeof(int)) == -1) {
  298. return errno;
  299. }
  300. apr_set_option(sock, APR_IPV6_V6ONLY, on);
  301. #else
  302. return APR_ENOTIMPL;
  303. #endif
  304. break;
  305. default:
  306. return APR_EINVAL;
  307. }
  308. return APR_SUCCESS;
  309. }
  310. apr_status_t apr_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
  311. {
  312. *t = sock->timeout;
  313. return APR_SUCCESS;
  314. }
  315. apr_status_t apr_socket_opt_get(apr_socket_t *sock,
  316. apr_int32_t opt, apr_int32_t *on)
  317. {
  318. switch(opt) {
  319. default:
  320. *on = apr_is_option_set(sock, opt);
  321. }
  322. return APR_SUCCESS;
  323. }
  324. int apr_socket_fd_get(apr_socket_t *sock)
  325. {
  326. if (sock) {
  327. return sock->socketdes;
  328. } else {
  329. return 0;
  330. }
  331. }
  332. apr_status_t apr_socket_atmark(apr_socket_t *sock, int *atmark)
  333. {
  334. #ifndef BEOS_R5
  335. int oobmark;
  336. if (ioctl(sock->socketdes, SIOCATMARK, (void*) &oobmark) < 0)
  337. return apr_get_netos_error();
  338. *atmark = (oobmark != 0);
  339. return APR_SUCCESS;
  340. #else /* BEOS_R5 */
  341. return APR_ENOTIMPL;
  342. #endif
  343. }
  344. apr_status_t apr_gethostname(char *buf, apr_int32_t len, apr_pool_t *cont)
  345. {
  346. #ifdef BEOS_R5
  347. if (gethostname(buf, len) == 0) {
  348. #else
  349. if (gethostname(buf, len) != 0) {
  350. #endif
  351. buf[0] = '\0';
  352. return errno;
  353. }
  354. else if (!memchr(buf, '\0', len)) { /* buffer too small */
  355. /* note... most platforms just truncate in this condition
  356. * linux+glibc return an error
  357. */
  358. buf[0] = '\0';
  359. return APR_ENAMETOOLONG;
  360. }
  361. return APR_SUCCESS;
  362. }
  363. #if APR_HAS_SO_ACCEPTFILTER
  364. apr_status_t apr_socket_accept_filter(apr_socket_t *sock, char *name,
  365. char *args)
  366. {
  367. struct accept_filter_arg af;
  368. strncpy(af.af_name, name, 16);
  369. strncpy(af.af_arg, args, 256 - 16);
  370. if ((setsockopt(sock->socketdes, SOL_SOCKET, SO_ACCEPTFILTER,
  371. &af, sizeof(af))) < 0) {
  372. return errno;
  373. }
  374. return APR_SUCCESS;
  375. }
  376. #endif