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; 144251875Speter case APR_SO_REUSEADDR: 145251875Speter if (on != apr_is_option_set(sock, APR_SO_REUSEADDR)) { 146251875Speter if (setsockopt(sock->socketdes, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(int)) == -1) { 147251875Speter return errno; 148251875Speter } 149251875Speter apr_set_option(sock, APR_SO_REUSEADDR, on); 150251875Speter } 151251875Speter break; 152251875Speter case APR_SO_SNDBUF: 153251875Speter#ifdef SO_SNDBUF 154251875Speter if (setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDBUF, (void *)&on, sizeof(int)) == -1) { 155251875Speter return errno; 156251875Speter } 157251875Speter#else 158251875Speter return APR_ENOTIMPL; 159251875Speter#endif 160251875Speter break; 161251875Speter case APR_SO_RCVBUF: 162251875Speter#ifdef SO_RCVBUF 163251875Speter if (setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVBUF, (void *)&on, sizeof(int)) == -1) { 164251875Speter return errno; 165251875Speter } 166251875Speter#else 167251875Speter return APR_ENOTIMPL; 168251875Speter#endif 169251875Speter break; 170251875Speter case APR_SO_NONBLOCK: 171251875Speter if (apr_is_option_set(sock, APR_SO_NONBLOCK) != on) { 172251875Speter if (on) { 173251875Speter if ((rv = sononblock(sock->socketdes)) != APR_SUCCESS) 174251875Speter return rv; 175251875Speter } 176251875Speter else { 177251875Speter if ((rv = soblock(sock->socketdes)) != APR_SUCCESS) 178251875Speter return rv; 179251875Speter } 180251875Speter apr_set_option(sock, APR_SO_NONBLOCK, on); 181251875Speter } 182251875Speter break; 183251875Speter case APR_SO_LINGER: 184251875Speter#ifdef SO_LINGER 185251875Speter if (apr_is_option_set(sock, APR_SO_LINGER) != on) { 186251875Speter struct linger li; 187251875Speter li.l_onoff = on; 188251875Speter li.l_linger = APR_MAX_SECS_TO_LINGER; 189251875Speter if (setsockopt(sock->socketdes, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(struct linger)) == -1) { 190251875Speter return errno; 191251875Speter } 192251875Speter apr_set_option(sock, APR_SO_LINGER, on); 193251875Speter } 194251875Speter#else 195251875Speter return APR_ENOTIMPL; 196251875Speter#endif 197251875Speter break; 198251875Speter case APR_TCP_DEFER_ACCEPT: 199251875Speter#if defined(TCP_DEFER_ACCEPT) 200251875Speter if (apr_is_option_set(sock, APR_TCP_DEFER_ACCEPT) != on) { 201251875Speter int optlevel = IPPROTO_TCP; 202251875Speter int optname = TCP_DEFER_ACCEPT; 203251875Speter 204251875Speter if (setsockopt(sock->socketdes, optlevel, optname, 205251875Speter (void *)&on, sizeof(int)) == -1) { 206251875Speter return errno; 207251875Speter } 208251875Speter apr_set_option(sock, APR_TCP_DEFER_ACCEPT, on); 209251875Speter } 210251875Speter#else 211251875Speter return APR_ENOTIMPL; 212251875Speter#endif 213251875Speter break; 214251875Speter case APR_TCP_NODELAY: 215251875Speter#if defined(TCP_NODELAY) 216251875Speter if (apr_is_option_set(sock, APR_TCP_NODELAY) != on) { 217251875Speter int optlevel = IPPROTO_TCP; 218251875Speter int optname = TCP_NODELAY; 219251875Speter 220251875Speter#if APR_HAVE_SCTP 221251875Speter if (sock->protocol == IPPROTO_SCTP) { 222251875Speter optlevel = IPPROTO_SCTP; 223251875Speter optname = SCTP_NODELAY; 224251875Speter } 225251875Speter#endif 226251875Speter if (setsockopt(sock->socketdes, optlevel, optname, (void *)&on, sizeof(int)) == -1) { 227251875Speter return errno; 228251875Speter } 229251875Speter apr_set_option(sock, APR_TCP_NODELAY, on); 230251875Speter } 231251875Speter#else 232251875Speter /* BeOS pre-BONE has TCP_NODELAY set by default. 233251875Speter * As it can't be turned off we might as well check if they're asking 234251875Speter * for it to be turned on! 235251875Speter */ 236251875Speter#ifdef BEOS 237251875Speter if (on == 1) 238251875Speter return APR_SUCCESS; 239251875Speter else 240251875Speter#endif 241251875Speter return APR_ENOTIMPL; 242251875Speter#endif 243251875Speter break; 244251875Speter case APR_TCP_NOPUSH: 245251875Speter#if APR_TCP_NOPUSH_FLAG 246251875Speter /* TCP_NODELAY and TCP_CORK are mutually exclusive on Linux 247251875Speter * kernels < 2.6; on newer kernels they can be used together 248251875Speter * and TCP_CORK takes preference, which is the desired 249251875Speter * behaviour. On older kernels, TCP_NODELAY must be toggled 250251875Speter * to "off" whilst TCP_CORK is in effect. */ 251251875Speter if (apr_is_option_set(sock, APR_TCP_NOPUSH) != on) { 252251875Speter#ifndef HAVE_TCP_NODELAY_WITH_CORK 253251875Speter int optlevel = IPPROTO_TCP; 254251875Speter int optname = TCP_NODELAY; 255251875Speter 256251875Speter#if APR_HAVE_SCTP 257251875Speter if (sock->protocol == IPPROTO_SCTP) { 258251875Speter optlevel = IPPROTO_SCTP; 259251875Speter optname = SCTP_NODELAY; 260251875Speter } 261251875Speter#endif 262251875Speter /* OK we're going to change some settings here... */ 263251875Speter if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1 && on) { 264251875Speter /* Now toggle TCP_NODELAY to off, if TCP_CORK is being 265251875Speter * turned on: */ 266251875Speter int tmpflag = 0; 267251875Speter if (setsockopt(sock->socketdes, optlevel, optname, 268251875Speter (void*)&tmpflag, sizeof(int)) == -1) { 269251875Speter return errno; 270251875Speter } 271251875Speter apr_set_option(sock, APR_RESET_NODELAY, 1); 272251875Speter apr_set_option(sock, APR_TCP_NODELAY, 0); 273251875Speter } else if (on) { 274251875Speter apr_set_option(sock, APR_RESET_NODELAY, 0); 275251875Speter } 276251875Speter#endif /* HAVE_TCP_NODELAY_WITH_CORK */ 277251875Speter 278251875Speter /* OK, now we can just set the TCP_NOPUSH flag accordingly...*/ 279251875Speter if (setsockopt(sock->socketdes, IPPROTO_TCP, APR_TCP_NOPUSH_FLAG, 280251875Speter (void*)&on, sizeof(int)) == -1) { 281251875Speter return errno; 282251875Speter } 283251875Speter apr_set_option(sock, APR_TCP_NOPUSH, on); 284251875Speter#ifndef HAVE_TCP_NODELAY_WITH_CORK 285251875Speter if (!on && apr_is_option_set(sock, APR_RESET_NODELAY)) { 286251875Speter /* Now, if TCP_CORK was just turned off, turn 287251875Speter * TCP_NODELAY back on again if it was earlier toggled 288251875Speter * to off: */ 289251875Speter int tmpflag = 1; 290251875Speter if (setsockopt(sock->socketdes, optlevel, optname, 291251875Speter (void*)&tmpflag, sizeof(int)) == -1) { 292251875Speter return errno; 293251875Speter } 294251875Speter apr_set_option(sock, APR_RESET_NODELAY,0); 295251875Speter apr_set_option(sock, APR_TCP_NODELAY, 1); 296251875Speter } 297251875Speter#endif /* HAVE_TCP_NODELAY_WITH_CORK */ 298251875Speter } 299251875Speter#else 300251875Speter return APR_ENOTIMPL; 301251875Speter#endif 302251875Speter break; 303251875Speter case APR_INCOMPLETE_READ: 304251875Speter apr_set_option(sock, APR_INCOMPLETE_READ, on); 305251875Speter break; 306251875Speter case APR_IPV6_V6ONLY: 307251875Speter#if APR_HAVE_IPV6 && defined(IPV6_V6ONLY) 308251875Speter /* we don't know the initial setting of this option, 309251875Speter * so don't check sock->options since that optimization 310251875Speter * won't work 311251875Speter */ 312251875Speter if (setsockopt(sock->socketdes, IPPROTO_IPV6, IPV6_V6ONLY, 313251875Speter (void *)&on, sizeof(int)) == -1) { 314251875Speter return errno; 315251875Speter } 316251875Speter apr_set_option(sock, APR_IPV6_V6ONLY, on); 317251875Speter#else 318251875Speter return APR_ENOTIMPL; 319251875Speter#endif 320251875Speter break; 321251875Speter default: 322251875Speter return APR_EINVAL; 323251875Speter } 324251875Speter 325251875Speter return APR_SUCCESS; 326251875Speter} 327251875Speter 328251875Speter 329251875Speterapr_status_t apr_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t) 330251875Speter{ 331251875Speter *t = sock->timeout; 332251875Speter return APR_SUCCESS; 333251875Speter} 334251875Speter 335251875Speter 336251875Speterapr_status_t apr_socket_opt_get(apr_socket_t *sock, 337251875Speter apr_int32_t opt, apr_int32_t *on) 338251875Speter{ 339251875Speter switch(opt) { 340251875Speter default: 341251875Speter *on = apr_is_option_set(sock, opt); 342251875Speter } 343251875Speter return APR_SUCCESS; 344251875Speter} 345251875Speter 346251875Speter 347251875Speterapr_status_t apr_socket_atmark(apr_socket_t *sock, int *atmark) 348251875Speter{ 349251875Speter#ifndef BEOS_R5 350251875Speter int oobmark; 351251875Speter 352251875Speter if (ioctl(sock->socketdes, SIOCATMARK, (void*) &oobmark) < 0) 353251875Speter return apr_get_netos_error(); 354251875Speter 355251875Speter *atmark = (oobmark != 0); 356251875Speter 357251875Speter return APR_SUCCESS; 358251875Speter#else /* BEOS_R5 */ 359251875Speter return APR_ENOTIMPL; 360251875Speter#endif 361251875Speter} 362251875Speter 363251875Speterapr_status_t apr_gethostname(char *buf, apr_int32_t len, apr_pool_t *cont) 364251875Speter{ 365251875Speter#ifdef BEOS_R5 366251875Speter if (gethostname(buf, len) == 0) { 367251875Speter#else 368251875Speter if (gethostname(buf, len) != 0) { 369251875Speter#endif 370251875Speter buf[0] = '\0'; 371251875Speter return errno; 372251875Speter } 373251875Speter else if (!memchr(buf, '\0', len)) { /* buffer too small */ 374251875Speter /* note... most platforms just truncate in this condition 375251875Speter * linux+glibc return an error 376251875Speter */ 377251875Speter buf[0] = '\0'; 378251875Speter return APR_ENAMETOOLONG; 379251875Speter } 380251875Speter return APR_SUCCESS; 381251875Speter} 382251875Speter 383251875Speter#if APR_HAS_SO_ACCEPTFILTER 384253734Speterapr_status_t apr_socket_accept_filter(apr_socket_t *sock, char *nonconst_name, 385253734Speter char *nonconst_args) 386251875Speter{ 387253734Speter /* these should have been const; act like they are */ 388253734Speter const char *name = nonconst_name; 389253734Speter const char *args = nonconst_args; 390253734Speter 391251875Speter struct accept_filter_arg af; 392253734Speter socklen_t optlen = sizeof(af); 393251875Speter 394253734Speter /* FreeBSD returns an error if the filter is already set; ignore 395253734Speter * this call if we previously set it to the same value. 396253734Speter */ 397253734Speter if ((getsockopt(sock->socketdes, SOL_SOCKET, SO_ACCEPTFILTER, 398253734Speter &af, &optlen)) == 0) { 399253734Speter if (!strcmp(name, af.af_name) && !strcmp(args, af.af_arg)) { 400253734Speter return APR_SUCCESS; 401253734Speter } 402253734Speter } 403253734Speter 404253734Speter /* Uhh, at least in FreeBSD 9 the fields are declared as arrays of 405253734Speter * these lengths; did sizeof not work in some ancient release? 406253734Speter * 407253734Speter * FreeBSD kernel sets the last byte to a '\0'. 408253734Speter */ 409253734Speter apr_cpystrn(af.af_name, name, 16); 410253734Speter apr_cpystrn(af.af_arg, args, 256 - 16); 411253734Speter 412251875Speter if ((setsockopt(sock->socketdes, SOL_SOCKET, SO_ACCEPTFILTER, 413251875Speter &af, sizeof(af))) < 0) { 414251875Speter return errno; 415251875Speter } 416251875Speter return APR_SUCCESS; 417251875Speter} 418251875Speter#endif 419