1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more 2251875Speter * contributor license agreements. See the NOTICE file distributed with 3251875Speter * this work for additional information regarding copyright ownership. 4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0 5251875Speter * (the "License"); you may not use this file except in compliance with 6251875Speter * the License. You may obtain a copy of the License at 7251875Speter * 8251875Speter * http://www.apache.org/licenses/LICENSE-2.0 9251875Speter * 10251875Speter * Unless required by applicable law or agreed to in writing, software 11251875Speter * distributed under the License is distributed on an "AS IS" BASIS, 12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13251875Speter * See the License for the specific language governing permissions and 14251875Speter * limitations under the License. 15251875Speter */ 16251875Speter 17251875Speter#include "apr_arch_networkio.h" 18251875Speter#include "apr_strings.h" 19251875Speter 20251875Speter 21251875Speterstatic apr_status_t soblock(int sd) 22251875Speter{ 23251875Speter/* BeOS uses setsockopt at present for non blocking... */ 24251875Speter#ifndef BEOS 25251875Speter int fd_flags; 26251875Speter 27251875Speter fd_flags = fcntl(sd, F_GETFL, 0); 28251875Speter#if defined(O_NONBLOCK) 29251875Speter fd_flags &= ~O_NONBLOCK; 30251875Speter#elif defined(O_NDELAY) 31251875Speter fd_flags &= ~O_NDELAY; 32251875Speter#elif defined(FNDELAY) 33251875Speter fd_flags &= ~FNDELAY; 34251875Speter#else 35251875Speter#error Please teach APR how to make sockets blocking on your platform. 36251875Speter#endif 37251875Speter if (fcntl(sd, F_SETFL, fd_flags) == -1) { 38251875Speter return errno; 39251875Speter } 40251875Speter#else 41251875Speter int on = 0; 42251875Speter if (setsockopt(sd, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)) < 0) 43251875Speter return errno; 44251875Speter#endif /* BEOS */ 45251875Speter return APR_SUCCESS; 46251875Speter} 47251875Speter 48251875Speterstatic apr_status_t sononblock(int sd) 49251875Speter{ 50251875Speter#ifndef BEOS 51251875Speter int fd_flags; 52251875Speter 53251875Speter fd_flags = fcntl(sd, F_GETFL, 0); 54251875Speter#if defined(O_NONBLOCK) 55251875Speter fd_flags |= O_NONBLOCK; 56251875Speter#elif defined(O_NDELAY) 57251875Speter fd_flags |= O_NDELAY; 58251875Speter#elif defined(FNDELAY) 59251875Speter fd_flags |= FNDELAY; 60251875Speter#else 61251875Speter#error Please teach APR how to make sockets non-blocking on your platform. 62251875Speter#endif 63251875Speter if (fcntl(sd, F_SETFL, fd_flags) == -1) { 64251875Speter return errno; 65251875Speter } 66251875Speter#else 67251875Speter int on = 1; 68251875Speter if (setsockopt(sd, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)) < 0) 69251875Speter return errno; 70251875Speter#endif /* BEOS */ 71251875Speter return APR_SUCCESS; 72251875Speter} 73251875Speter 74251875Speter 75251875Speterapr_status_t apr_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t) 76251875Speter{ 77251875Speter apr_status_t stat; 78251875Speter 79251875Speter /* If our new timeout is non-negative and our old timeout was 80251875Speter * negative, then we need to ensure that we are non-blocking. 81251875Speter * Conversely, if our new timeout is negative and we had 82251875Speter * non-negative timeout, we must make sure our socket is blocking. 83251875Speter * We want to avoid calling fcntl more than necessary on the 84251875Speter * socket. 85251875Speter */ 86251875Speter if (t >= 0 && sock->timeout < 0) { 87251875Speter if (apr_is_option_set(sock, APR_SO_NONBLOCK) != 1) { 88251875Speter if ((stat = sononblock(sock->socketdes)) != APR_SUCCESS) { 89251875Speter return stat; 90251875Speter } 91251875Speter apr_set_option(sock, APR_SO_NONBLOCK, 1); 92251875Speter } 93251875Speter } 94251875Speter else if (t < 0 && sock->timeout >= 0) { 95251875Speter if (apr_is_option_set(sock, APR_SO_NONBLOCK) != 0) { 96251875Speter if ((stat = soblock(sock->socketdes)) != APR_SUCCESS) { 97251875Speter return stat; 98251875Speter } 99251875Speter apr_set_option(sock, APR_SO_NONBLOCK, 0); 100251875Speter } 101251875Speter } 102251875Speter /* must disable the incomplete read support if we disable 103251875Speter * a timeout 104251875Speter */ 105251875Speter if (t <= 0) { 106251875Speter sock->options &= ~APR_INCOMPLETE_READ; 107251875Speter } 108251875Speter sock->timeout = t; 109251875Speter return APR_SUCCESS; 110251875Speter} 111251875Speter 112251875Speter 113251875Speterapr_status_t apr_socket_opt_set(apr_socket_t *sock, 114251875Speter apr_int32_t opt, apr_int32_t on) 115251875Speter{ 116251875Speter int one; 117251875Speter apr_status_t rv; 118251875Speter 119251875Speter if (on) 120251875Speter one = 1; 121251875Speter else 122251875Speter one = 0; 123251875Speter switch(opt) { 124251875Speter case APR_SO_KEEPALIVE: 125251875Speter#ifdef SO_KEEPALIVE 126251875Speter if (on != apr_is_option_set(sock, APR_SO_KEEPALIVE)) { 127251875Speter if (setsockopt(sock->socketdes, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, sizeof(int)) == -1) { 128251875Speter return errno; 129251875Speter } 130251875Speter apr_set_option(sock, APR_SO_KEEPALIVE, on); 131251875Speter } 132251875Speter#else 133251875Speter return APR_ENOTIMPL; 134251875Speter#endif 135251875Speter break; 136251875Speter case APR_SO_DEBUG: 137251875Speter if (on != apr_is_option_set(sock, APR_SO_DEBUG)) { 138251875Speter if (setsockopt(sock->socketdes, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(int)) == -1) { 139251875Speter return errno; 140251875Speter } 141251875Speter apr_set_option(sock, APR_SO_DEBUG, on); 142251875Speter } 143251875Speter break; 144269847Speter case APR_SO_BROADCAST: 145269847Speter#ifdef SO_BROADCAST 146269847Speter if (on != apr_is_option_set(sock, APR_SO_BROADCAST)) { 147269847Speter if (setsockopt(sock->socketdes, SOL_SOCKET, SO_BROADCAST, (void *)&one, sizeof(int)) == -1) { 148269847Speter return errno; 149269847Speter } 150269847Speter apr_set_option(sock, APR_SO_BROADCAST, on); 151269847Speter } 152269847Speter#else 153269847Speter return APR_ENOTIMPL; 154269847Speter#endif 155269847Speter break; 156251875Speter case APR_SO_REUSEADDR: 157251875Speter if (on != apr_is_option_set(sock, APR_SO_REUSEADDR)) { 158251875Speter if (setsockopt(sock->socketdes, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(int)) == -1) { 159251875Speter return errno; 160251875Speter } 161251875Speter apr_set_option(sock, APR_SO_REUSEADDR, on); 162251875Speter } 163251875Speter break; 164251875Speter case APR_SO_SNDBUF: 165251875Speter#ifdef SO_SNDBUF 166251875Speter if (setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDBUF, (void *)&on, sizeof(int)) == -1) { 167251875Speter return errno; 168251875Speter } 169251875Speter#else 170251875Speter return APR_ENOTIMPL; 171251875Speter#endif 172251875Speter break; 173251875Speter case APR_SO_RCVBUF: 174251875Speter#ifdef SO_RCVBUF 175251875Speter if (setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVBUF, (void *)&on, sizeof(int)) == -1) { 176251875Speter return errno; 177251875Speter } 178251875Speter#else 179251875Speter return APR_ENOTIMPL; 180251875Speter#endif 181251875Speter break; 182251875Speter case APR_SO_NONBLOCK: 183251875Speter if (apr_is_option_set(sock, APR_SO_NONBLOCK) != on) { 184251875Speter if (on) { 185251875Speter if ((rv = sononblock(sock->socketdes)) != APR_SUCCESS) 186251875Speter return rv; 187251875Speter } 188251875Speter else { 189251875Speter if ((rv = soblock(sock->socketdes)) != APR_SUCCESS) 190251875Speter return rv; 191251875Speter } 192251875Speter apr_set_option(sock, APR_SO_NONBLOCK, on); 193251875Speter } 194251875Speter break; 195251875Speter case APR_SO_LINGER: 196251875Speter#ifdef SO_LINGER 197251875Speter if (apr_is_option_set(sock, APR_SO_LINGER) != on) { 198251875Speter struct linger li; 199251875Speter li.l_onoff = on; 200251875Speter li.l_linger = APR_MAX_SECS_TO_LINGER; 201251875Speter if (setsockopt(sock->socketdes, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(struct linger)) == -1) { 202251875Speter return errno; 203251875Speter } 204251875Speter apr_set_option(sock, APR_SO_LINGER, on); 205251875Speter } 206251875Speter#else 207251875Speter return APR_ENOTIMPL; 208251875Speter#endif 209251875Speter break; 210251875Speter case APR_TCP_DEFER_ACCEPT: 211251875Speter#if defined(TCP_DEFER_ACCEPT) 212251875Speter if (apr_is_option_set(sock, APR_TCP_DEFER_ACCEPT) != on) { 213251875Speter int optlevel = IPPROTO_TCP; 214251875Speter int optname = TCP_DEFER_ACCEPT; 215251875Speter 216251875Speter if (setsockopt(sock->socketdes, optlevel, optname, 217251875Speter (void *)&on, sizeof(int)) == -1) { 218251875Speter return errno; 219251875Speter } 220251875Speter apr_set_option(sock, APR_TCP_DEFER_ACCEPT, on); 221251875Speter } 222251875Speter#else 223251875Speter return APR_ENOTIMPL; 224251875Speter#endif 225251875Speter break; 226251875Speter case APR_TCP_NODELAY: 227251875Speter#if defined(TCP_NODELAY) 228251875Speter if (apr_is_option_set(sock, APR_TCP_NODELAY) != on) { 229251875Speter int optlevel = IPPROTO_TCP; 230251875Speter int optname = TCP_NODELAY; 231251875Speter 232251875Speter#if APR_HAVE_SCTP 233251875Speter if (sock->protocol == IPPROTO_SCTP) { 234251875Speter optlevel = IPPROTO_SCTP; 235251875Speter optname = SCTP_NODELAY; 236251875Speter } 237251875Speter#endif 238251875Speter if (setsockopt(sock->socketdes, optlevel, optname, (void *)&on, sizeof(int)) == -1) { 239251875Speter return errno; 240251875Speter } 241251875Speter apr_set_option(sock, APR_TCP_NODELAY, on); 242251875Speter } 243251875Speter#else 244251875Speter /* BeOS pre-BONE has TCP_NODELAY set by default. 245251875Speter * As it can't be turned off we might as well check if they're asking 246251875Speter * for it to be turned on! 247251875Speter */ 248251875Speter#ifdef BEOS 249251875Speter if (on == 1) 250251875Speter return APR_SUCCESS; 251251875Speter else 252251875Speter#endif 253251875Speter return APR_ENOTIMPL; 254251875Speter#endif 255251875Speter break; 256251875Speter case APR_TCP_NOPUSH: 257251875Speter#if APR_TCP_NOPUSH_FLAG 258251875Speter /* TCP_NODELAY and TCP_CORK are mutually exclusive on Linux 259251875Speter * kernels < 2.6; on newer kernels they can be used together 260251875Speter * and TCP_CORK takes preference, which is the desired 261251875Speter * behaviour. On older kernels, TCP_NODELAY must be toggled 262251875Speter * to "off" whilst TCP_CORK is in effect. */ 263251875Speter if (apr_is_option_set(sock, APR_TCP_NOPUSH) != on) { 264251875Speter#ifndef HAVE_TCP_NODELAY_WITH_CORK 265251875Speter int optlevel = IPPROTO_TCP; 266251875Speter int optname = TCP_NODELAY; 267251875Speter 268251875Speter#if APR_HAVE_SCTP 269251875Speter if (sock->protocol == IPPROTO_SCTP) { 270251875Speter optlevel = IPPROTO_SCTP; 271251875Speter optname = SCTP_NODELAY; 272251875Speter } 273251875Speter#endif 274251875Speter /* OK we're going to change some settings here... */ 275251875Speter if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1 && on) { 276251875Speter /* Now toggle TCP_NODELAY to off, if TCP_CORK is being 277251875Speter * turned on: */ 278251875Speter int tmpflag = 0; 279251875Speter if (setsockopt(sock->socketdes, optlevel, optname, 280251875Speter (void*)&tmpflag, sizeof(int)) == -1) { 281251875Speter return errno; 282251875Speter } 283251875Speter apr_set_option(sock, APR_RESET_NODELAY, 1); 284251875Speter apr_set_option(sock, APR_TCP_NODELAY, 0); 285251875Speter } else if (on) { 286251875Speter apr_set_option(sock, APR_RESET_NODELAY, 0); 287251875Speter } 288251875Speter#endif /* HAVE_TCP_NODELAY_WITH_CORK */ 289251875Speter 290251875Speter /* OK, now we can just set the TCP_NOPUSH flag accordingly...*/ 291251875Speter if (setsockopt(sock->socketdes, IPPROTO_TCP, APR_TCP_NOPUSH_FLAG, 292251875Speter (void*)&on, sizeof(int)) == -1) { 293251875Speter return errno; 294251875Speter } 295251875Speter apr_set_option(sock, APR_TCP_NOPUSH, on); 296251875Speter#ifndef HAVE_TCP_NODELAY_WITH_CORK 297251875Speter if (!on && apr_is_option_set(sock, APR_RESET_NODELAY)) { 298251875Speter /* Now, if TCP_CORK was just turned off, turn 299251875Speter * TCP_NODELAY back on again if it was earlier toggled 300251875Speter * to off: */ 301251875Speter int tmpflag = 1; 302251875Speter if (setsockopt(sock->socketdes, optlevel, optname, 303251875Speter (void*)&tmpflag, sizeof(int)) == -1) { 304251875Speter return errno; 305251875Speter } 306251875Speter apr_set_option(sock, APR_RESET_NODELAY,0); 307251875Speter apr_set_option(sock, APR_TCP_NODELAY, 1); 308251875Speter } 309251875Speter#endif /* HAVE_TCP_NODELAY_WITH_CORK */ 310251875Speter } 311251875Speter#else 312251875Speter return APR_ENOTIMPL; 313251875Speter#endif 314251875Speter break; 315251875Speter case APR_INCOMPLETE_READ: 316251875Speter apr_set_option(sock, APR_INCOMPLETE_READ, on); 317251875Speter break; 318251875Speter case APR_IPV6_V6ONLY: 319251875Speter#if APR_HAVE_IPV6 && defined(IPV6_V6ONLY) 320251875Speter /* we don't know the initial setting of this option, 321251875Speter * so don't check sock->options since that optimization 322251875Speter * won't work 323251875Speter */ 324251875Speter if (setsockopt(sock->socketdes, IPPROTO_IPV6, IPV6_V6ONLY, 325251875Speter (void *)&on, sizeof(int)) == -1) { 326251875Speter return errno; 327251875Speter } 328251875Speter apr_set_option(sock, APR_IPV6_V6ONLY, on); 329251875Speter#else 330251875Speter return APR_ENOTIMPL; 331251875Speter#endif 332251875Speter break; 333251875Speter default: 334251875Speter return APR_EINVAL; 335251875Speter } 336251875Speter 337251875Speter return APR_SUCCESS; 338251875Speter} 339251875Speter 340251875Speter 341251875Speterapr_status_t apr_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t) 342251875Speter{ 343251875Speter *t = sock->timeout; 344251875Speter return APR_SUCCESS; 345251875Speter} 346251875Speter 347251875Speter 348251875Speterapr_status_t apr_socket_opt_get(apr_socket_t *sock, 349251875Speter apr_int32_t opt, apr_int32_t *on) 350251875Speter{ 351251875Speter switch(opt) { 352251875Speter default: 353251875Speter *on = apr_is_option_set(sock, opt); 354251875Speter } 355251875Speter return APR_SUCCESS; 356251875Speter} 357251875Speter 358251875Speter 359251875Speterapr_status_t apr_socket_atmark(apr_socket_t *sock, int *atmark) 360251875Speter{ 361251875Speter#ifndef BEOS_R5 362251875Speter int oobmark; 363251875Speter 364251875Speter if (ioctl(sock->socketdes, SIOCATMARK, (void*) &oobmark) < 0) 365251875Speter return apr_get_netos_error(); 366251875Speter 367251875Speter *atmark = (oobmark != 0); 368251875Speter 369251875Speter return APR_SUCCESS; 370251875Speter#else /* BEOS_R5 */ 371251875Speter return APR_ENOTIMPL; 372251875Speter#endif 373251875Speter} 374251875Speter 375251875Speterapr_status_t apr_gethostname(char *buf, apr_int32_t len, apr_pool_t *cont) 376251875Speter{ 377251875Speter#ifdef BEOS_R5 378251875Speter if (gethostname(buf, len) == 0) { 379251875Speter#else 380251875Speter if (gethostname(buf, len) != 0) { 381251875Speter#endif 382251875Speter buf[0] = '\0'; 383251875Speter return errno; 384251875Speter } 385251875Speter else if (!memchr(buf, '\0', len)) { /* buffer too small */ 386251875Speter /* note... most platforms just truncate in this condition 387251875Speter * linux+glibc return an error 388251875Speter */ 389251875Speter buf[0] = '\0'; 390251875Speter return APR_ENAMETOOLONG; 391251875Speter } 392251875Speter return APR_SUCCESS; 393251875Speter} 394251875Speter 395251875Speter#if APR_HAS_SO_ACCEPTFILTER 396253734Speterapr_status_t apr_socket_accept_filter(apr_socket_t *sock, char *nonconst_name, 397253734Speter char *nonconst_args) 398251875Speter{ 399253734Speter /* these should have been const; act like they are */ 400253734Speter const char *name = nonconst_name; 401253734Speter const char *args = nonconst_args; 402253734Speter 403251875Speter struct accept_filter_arg af; 404253734Speter socklen_t optlen = sizeof(af); 405251875Speter 406253734Speter /* FreeBSD returns an error if the filter is already set; ignore 407253734Speter * this call if we previously set it to the same value. 408253734Speter */ 409253734Speter if ((getsockopt(sock->socketdes, SOL_SOCKET, SO_ACCEPTFILTER, 410253734Speter &af, &optlen)) == 0) { 411253734Speter if (!strcmp(name, af.af_name) && !strcmp(args, af.af_arg)) { 412253734Speter return APR_SUCCESS; 413253734Speter } 414253734Speter } 415253734Speter 416253734Speter /* Uhh, at least in FreeBSD 9 the fields are declared as arrays of 417253734Speter * these lengths; did sizeof not work in some ancient release? 418253734Speter * 419253734Speter * FreeBSD kernel sets the last byte to a '\0'. 420253734Speter */ 421253734Speter apr_cpystrn(af.af_name, name, 16); 422253734Speter apr_cpystrn(af.af_arg, args, 256 - 16); 423253734Speter 424251875Speter if ((setsockopt(sock->socketdes, SOL_SOCKET, SO_ACCEPTFILTER, 425251875Speter &af, sizeof(af))) < 0) { 426251875Speter return errno; 427251875Speter } 428251875Speter return APR_SUCCESS; 429251875Speter} 430251875Speter#endif 431