sockets.c revision 269847
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_network_io.h" 19251875Speter#include "apr_strings.h" 20251875Speter#include "apr_support.h" 21251875Speter#include "apr_portable.h" 22251875Speter#include "apr_arch_inherit.h" 23251875Speter 24251875Speter#ifdef BEOS_R5 25251875Speter#undef close 26251875Speter#define close closesocket 27251875Speter#endif /* BEOS_R5 */ 28251875Speter 29251875Speterstatic char generic_inaddr_any[16] = {0}; /* big enough for IPv4 or IPv6 */ 30251875Speter 31251875Speterstatic apr_status_t socket_cleanup(void *sock) 32251875Speter{ 33251875Speter apr_socket_t *thesocket = sock; 34251875Speter int sd = thesocket->socketdes; 35251875Speter 36251875Speter /* Set socket descriptor to -1 before close(), so that there is no 37251875Speter * chance of returning an already closed FD from apr_os_sock_get(). 38251875Speter */ 39251875Speter thesocket->socketdes = -1; 40251875Speter 41251875Speter if (close(sd) == 0) { 42251875Speter return APR_SUCCESS; 43251875Speter } 44251875Speter else { 45251875Speter /* Restore, close() was not successful. */ 46251875Speter thesocket->socketdes = sd; 47251875Speter 48251875Speter return errno; 49251875Speter } 50251875Speter} 51251875Speter 52251875Speterstatic void set_socket_vars(apr_socket_t *sock, int family, int type, int protocol) 53251875Speter{ 54251875Speter sock->type = type; 55251875Speter sock->protocol = protocol; 56251875Speter apr_sockaddr_vars_set(sock->local_addr, family, 0); 57251875Speter apr_sockaddr_vars_set(sock->remote_addr, family, 0); 58251875Speter sock->options = 0; 59251875Speter#if defined(BEOS) && !defined(BEOS_BONE) 60251875Speter /* BeOS pre-BONE has TCP_NODELAY on by default and it can't be 61251875Speter * switched off! 62251875Speter */ 63251875Speter sock->options |= APR_TCP_NODELAY; 64251875Speter#endif 65251875Speter} 66251875Speter 67251875Speterstatic void alloc_socket(apr_socket_t **new, apr_pool_t *p) 68251875Speter{ 69251875Speter *new = (apr_socket_t *)apr_pcalloc(p, sizeof(apr_socket_t)); 70251875Speter (*new)->pool = p; 71251875Speter (*new)->local_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool, 72251875Speter sizeof(apr_sockaddr_t)); 73251875Speter (*new)->local_addr->pool = p; 74251875Speter (*new)->remote_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool, 75251875Speter sizeof(apr_sockaddr_t)); 76251875Speter (*new)->remote_addr->pool = p; 77251875Speter (*new)->remote_addr_unknown = 1; 78251875Speter#ifndef WAITIO_USES_POLL 79251875Speter /* Create a pollset with room for one descriptor. */ 80251875Speter /* ### check return codes */ 81251875Speter (void) apr_pollset_create(&(*new)->pollset, 1, p, 0); 82251875Speter#endif 83251875Speter} 84251875Speter 85251875Speterapr_status_t apr_socket_protocol_get(apr_socket_t *sock, int *protocol) 86251875Speter{ 87251875Speter *protocol = sock->protocol; 88251875Speter return APR_SUCCESS; 89251875Speter} 90251875Speter 91251875Speterapr_status_t apr_socket_create(apr_socket_t **new, int ofamily, int type, 92251875Speter int protocol, apr_pool_t *cont) 93251875Speter{ 94251875Speter int family = ofamily, flags = 0; 95251875Speter 96251875Speter#ifdef HAVE_SOCK_CLOEXEC 97251875Speter flags |= SOCK_CLOEXEC; 98251875Speter#endif 99251875Speter 100251875Speter if (family == APR_UNSPEC) { 101251875Speter#if APR_HAVE_IPV6 102251875Speter family = APR_INET6; 103251875Speter#else 104251875Speter family = APR_INET; 105251875Speter#endif 106251875Speter } 107251875Speter 108251875Speter alloc_socket(new, cont); 109251875Speter 110251875Speter#ifndef BEOS_R5 111251875Speter (*new)->socketdes = socket(family, type|flags, protocol); 112251875Speter#else 113251875Speter /* For some reason BeOS R5 has an unconventional protocol numbering, 114251875Speter * so we need to translate here. */ 115251875Speter switch (protocol) { 116251875Speter case 0: 117251875Speter (*new)->socketdes = socket(family, type|flags, 0); 118251875Speter break; 119251875Speter case APR_PROTO_TCP: 120251875Speter (*new)->socketdes = socket(family, type|flags, IPPROTO_TCP); 121251875Speter break; 122251875Speter case APR_PROTO_UDP: 123251875Speter (*new)->socketdes = socket(family, type|flags, IPPROTO_UDP); 124251875Speter break; 125251875Speter case APR_PROTO_SCTP: 126251875Speter default: 127251875Speter errno = EPROTONOSUPPORT; 128251875Speter (*new)->socketdes = -1; 129251875Speter break; 130251875Speter } 131251875Speter#endif /* BEOS_R5 */ 132251875Speter 133251875Speter#if APR_HAVE_IPV6 134251875Speter if ((*new)->socketdes < 0 && ofamily == APR_UNSPEC) { 135251875Speter family = APR_INET; 136251875Speter (*new)->socketdes = socket(family, type|flags, protocol); 137251875Speter } 138251875Speter#endif 139251875Speter 140251875Speter if ((*new)->socketdes < 0) { 141251875Speter return errno; 142251875Speter } 143251875Speter set_socket_vars(*new, family, type, protocol); 144251875Speter 145251875Speter#ifndef HAVE_SOCK_CLOEXEC 146251875Speter { 147251875Speter int flags; 148251875Speter 149251875Speter if ((flags = fcntl((*new)->socketdes, F_GETFD)) == -1) 150251875Speter return errno; 151251875Speter 152251875Speter flags |= FD_CLOEXEC; 153251875Speter if (fcntl((*new)->socketdes, F_SETFD, flags) == -1) 154251875Speter return errno; 155251875Speter } 156251875Speter#endif 157251875Speter 158251875Speter (*new)->timeout = -1; 159251875Speter (*new)->inherit = 0; 160251875Speter apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup, 161251875Speter socket_cleanup); 162251875Speter 163251875Speter return APR_SUCCESS; 164251875Speter} 165251875Speter 166251875Speterapr_status_t apr_socket_shutdown(apr_socket_t *thesocket, 167251875Speter apr_shutdown_how_e how) 168251875Speter{ 169251875Speter return (shutdown(thesocket->socketdes, how) == -1) ? errno : APR_SUCCESS; 170251875Speter} 171251875Speter 172251875Speterapr_status_t apr_socket_close(apr_socket_t *thesocket) 173251875Speter{ 174251875Speter return apr_pool_cleanup_run(thesocket->pool, thesocket, socket_cleanup); 175251875Speter} 176251875Speter 177251875Speterapr_status_t apr_socket_bind(apr_socket_t *sock, apr_sockaddr_t *sa) 178251875Speter{ 179251875Speter if (bind(sock->socketdes, 180251875Speter (struct sockaddr *)&sa->sa, sa->salen) == -1) { 181251875Speter return errno; 182251875Speter } 183251875Speter else { 184251875Speter sock->local_addr = sa; 185251875Speter /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ 186251875Speter if (sock->local_addr->sa.sin.sin_port == 0) { /* no need for ntohs() when comparing w/ 0 */ 187251875Speter sock->local_port_unknown = 1; /* kernel got us an ephemeral port */ 188251875Speter } 189251875Speter return APR_SUCCESS; 190251875Speter } 191251875Speter} 192251875Speter 193251875Speterapr_status_t apr_socket_listen(apr_socket_t *sock, apr_int32_t backlog) 194251875Speter{ 195251875Speter if (listen(sock->socketdes, backlog) == -1) 196251875Speter return errno; 197251875Speter else 198251875Speter return APR_SUCCESS; 199251875Speter} 200251875Speter 201251875Speterapr_status_t apr_socket_accept(apr_socket_t **new, apr_socket_t *sock, 202251875Speter apr_pool_t *connection_context) 203251875Speter{ 204251875Speter int s; 205251875Speter apr_sockaddr_t sa; 206251875Speter 207251875Speter sa.salen = sizeof(sa.sa); 208251875Speter 209251875Speter#ifdef HAVE_ACCEPT4 210269847Speter { 211269847Speter int flags = SOCK_CLOEXEC; 212269847Speter 213269847Speter#if defined(SOCK_NONBLOCK) && APR_O_NONBLOCK_INHERITED 214269847Speter /* With FreeBSD accept4() (avail in 10+), O_NONBLOCK is not inherited 215269847Speter * (unlike Linux). Mimic the accept() behavior here in a way that 216269847Speter * may help other platforms. 217269847Speter */ 218269847Speter if (apr_is_option_set(sock, APR_SO_NONBLOCK) == 1) { 219269847Speter flags |= SOCK_NONBLOCK; 220269847Speter } 221269847Speter#endif 222269847Speter s = accept4(sock->socketdes, (struct sockaddr *)&sa.sa, &sa.salen, flags); 223269847Speter } 224251875Speter#else 225251875Speter s = accept(sock->socketdes, (struct sockaddr *)&sa.sa, &sa.salen); 226251875Speter#endif 227251875Speter 228251875Speter if (s < 0) { 229251875Speter return errno; 230251875Speter } 231251875Speter#ifdef TPF 232251875Speter if (s == 0) { 233251875Speter /* 0 is an invalid socket for TPF */ 234251875Speter return APR_EINTR; 235251875Speter } 236251875Speter#endif 237251875Speter alloc_socket(new, connection_context); 238251875Speter 239251875Speter /* Set up socket variables -- note that it may be possible for 240251875Speter * *new to be an AF_INET socket when sock is AF_INET6 in some 241251875Speter * dual-stack configurations, so ensure that the remote_/local_addr 242251875Speter * structures are adjusted for the family of the accepted 243251875Speter * socket: */ 244251875Speter set_socket_vars(*new, sa.sa.sin.sin_family, SOCK_STREAM, sock->protocol); 245251875Speter 246251875Speter#ifndef HAVE_POLL 247251875Speter (*new)->connected = 1; 248251875Speter#endif 249251875Speter (*new)->timeout = -1; 250251875Speter 251251875Speter (*new)->remote_addr_unknown = 0; 252251875Speter 253251875Speter (*new)->socketdes = s; 254251875Speter 255251875Speter /* Copy in peer's address. */ 256251875Speter (*new)->remote_addr->sa = sa.sa; 257251875Speter (*new)->remote_addr->salen = sa.salen; 258251875Speter 259251875Speter *(*new)->local_addr = *sock->local_addr; 260251875Speter 261251875Speter /* The above assignment just overwrote the pool entry. Setting the local_addr 262251875Speter pool for the accepted socket back to what it should be. Otherwise all 263251875Speter allocations for this socket will come from a server pool that is not 264251875Speter freed until the process goes down.*/ 265251875Speter (*new)->local_addr->pool = connection_context; 266251875Speter 267251875Speter /* fix up any pointers which are no longer valid */ 268251875Speter if (sock->local_addr->sa.sin.sin_family == AF_INET) { 269251875Speter (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin.sin_addr; 270251875Speter } 271251875Speter#if APR_HAVE_IPV6 272251875Speter else if (sock->local_addr->sa.sin.sin_family == AF_INET6) { 273251875Speter (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin6.sin6_addr; 274251875Speter } 275251875Speter#endif 276251875Speter (*new)->remote_addr->port = ntohs((*new)->remote_addr->sa.sin.sin_port); 277251875Speter if (sock->local_port_unknown) { 278251875Speter /* not likely for a listening socket, but theoretically possible :) */ 279251875Speter (*new)->local_port_unknown = 1; 280251875Speter } 281251875Speter 282251875Speter#if APR_TCP_NODELAY_INHERITED 283251875Speter if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1) { 284251875Speter apr_set_option(*new, APR_TCP_NODELAY, 1); 285251875Speter } 286251875Speter#endif /* TCP_NODELAY_INHERITED */ 287251875Speter#if APR_O_NONBLOCK_INHERITED 288251875Speter if (apr_is_option_set(sock, APR_SO_NONBLOCK) == 1) { 289251875Speter apr_set_option(*new, APR_SO_NONBLOCK, 1); 290251875Speter } 291251875Speter#endif /* APR_O_NONBLOCK_INHERITED */ 292251875Speter 293251875Speter if (sock->local_interface_unknown || 294251875Speter !memcmp(sock->local_addr->ipaddr_ptr, 295251875Speter generic_inaddr_any, 296251875Speter sock->local_addr->ipaddr_len)) { 297251875Speter /* If the interface address inside the listening socket's local_addr wasn't 298251875Speter * up-to-date, we don't know local interface of the connected socket either. 299251875Speter * 300251875Speter * If the listening socket was not bound to a specific interface, we 301251875Speter * don't know the local_addr of the connected socket. 302251875Speter */ 303251875Speter (*new)->local_interface_unknown = 1; 304251875Speter } 305251875Speter 306251875Speter#ifndef HAVE_ACCEPT4 307251875Speter { 308251875Speter int flags; 309251875Speter 310251875Speter if ((flags = fcntl((*new)->socketdes, F_GETFD)) == -1) 311251875Speter return errno; 312251875Speter 313251875Speter flags |= FD_CLOEXEC; 314251875Speter if (fcntl((*new)->socketdes, F_SETFD, flags) == -1) 315251875Speter return errno; 316251875Speter } 317251875Speter#endif 318251875Speter 319251875Speter (*new)->inherit = 0; 320251875Speter apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup, 321251875Speter socket_cleanup); 322251875Speter return APR_SUCCESS; 323251875Speter} 324251875Speter 325251875Speterapr_status_t apr_socket_connect(apr_socket_t *sock, apr_sockaddr_t *sa) 326251875Speter{ 327251875Speter int rc; 328251875Speter 329251875Speter do { 330251875Speter rc = connect(sock->socketdes, 331251875Speter (const struct sockaddr *)&sa->sa.sin, 332251875Speter sa->salen); 333251875Speter } while (rc == -1 && errno == EINTR); 334251875Speter 335251875Speter /* we can see EINPROGRESS the first time connect is called on a non-blocking 336251875Speter * socket; if called again, we can see EALREADY 337251875Speter */ 338251875Speter if ((rc == -1) && (errno == EINPROGRESS || errno == EALREADY) 339251875Speter && (sock->timeout > 0)) { 340251875Speter rc = apr_wait_for_io_or_timeout(NULL, sock, 0); 341251875Speter if (rc != APR_SUCCESS) { 342251875Speter return rc; 343251875Speter } 344251875Speter 345251875Speter#ifdef SO_ERROR 346251875Speter { 347251875Speter int error; 348251875Speter apr_socklen_t len = sizeof(error); 349251875Speter if ((rc = getsockopt(sock->socketdes, SOL_SOCKET, SO_ERROR, 350251875Speter (char *)&error, &len)) < 0) { 351251875Speter return errno; 352251875Speter } 353251875Speter if (error) { 354251875Speter return error; 355251875Speter } 356251875Speter } 357251875Speter#endif /* SO_ERROR */ 358251875Speter } 359251875Speter 360251875Speter 361251875Speter if (memcmp(sa->ipaddr_ptr, generic_inaddr_any, sa->ipaddr_len)) { 362251875Speter /* A real remote address was passed in. If the unspecified 363251875Speter * address was used, the actual remote addr will have to be 364251875Speter * determined using getpeername() if required. */ 365251875Speter sock->remote_addr_unknown = 0; 366251875Speter 367251875Speter /* Copy the address structure details in. */ 368251875Speter sock->remote_addr->sa = sa->sa; 369251875Speter sock->remote_addr->salen = sa->salen; 370251875Speter /* Adjust ipaddr_ptr et al. */ 371251875Speter apr_sockaddr_vars_set(sock->remote_addr, sa->family, sa->port); 372251875Speter } 373251875Speter 374251875Speter if (sock->local_addr->port == 0) { 375251875Speter /* connect() got us an ephemeral port */ 376251875Speter sock->local_port_unknown = 1; 377251875Speter } 378251875Speter if (!memcmp(sock->local_addr->ipaddr_ptr, 379251875Speter generic_inaddr_any, 380251875Speter sock->local_addr->ipaddr_len)) { 381251875Speter /* not bound to specific local interface; connect() had to assign 382251875Speter * one for the socket 383251875Speter */ 384251875Speter sock->local_interface_unknown = 1; 385251875Speter } 386251875Speter 387251875Speter if (rc == -1 && errno != EISCONN) { 388251875Speter return errno; 389251875Speter } 390251875Speter 391251875Speter#ifndef HAVE_POLL 392251875Speter sock->connected=1; 393251875Speter#endif 394251875Speter return APR_SUCCESS; 395251875Speter} 396251875Speter 397251875Speterapr_status_t apr_socket_type_get(apr_socket_t *sock, int *type) 398251875Speter{ 399251875Speter *type = sock->type; 400251875Speter return APR_SUCCESS; 401251875Speter} 402251875Speter 403251875Speterapr_status_t apr_socket_data_get(void **data, const char *key, apr_socket_t *sock) 404251875Speter{ 405251875Speter sock_userdata_t *cur = sock->userdata; 406251875Speter 407251875Speter *data = NULL; 408251875Speter 409251875Speter while (cur) { 410251875Speter if (!strcmp(cur->key, key)) { 411251875Speter *data = cur->data; 412251875Speter break; 413251875Speter } 414251875Speter cur = cur->next; 415251875Speter } 416251875Speter 417251875Speter return APR_SUCCESS; 418251875Speter} 419251875Speter 420251875Speterapr_status_t apr_socket_data_set(apr_socket_t *sock, void *data, const char *key, 421251875Speter apr_status_t (*cleanup) (void *)) 422251875Speter{ 423251875Speter sock_userdata_t *new = apr_palloc(sock->pool, sizeof(sock_userdata_t)); 424251875Speter 425251875Speter new->key = apr_pstrdup(sock->pool, key); 426251875Speter new->data = data; 427251875Speter new->next = sock->userdata; 428251875Speter sock->userdata = new; 429251875Speter 430251875Speter if (cleanup) { 431251875Speter apr_pool_cleanup_register(sock->pool, data, cleanup, cleanup); 432251875Speter } 433251875Speter 434251875Speter return APR_SUCCESS; 435251875Speter} 436251875Speter 437251875Speterapr_status_t apr_os_sock_get(apr_os_sock_t *thesock, apr_socket_t *sock) 438251875Speter{ 439251875Speter *thesock = sock->socketdes; 440251875Speter return APR_SUCCESS; 441251875Speter} 442251875Speter 443251875Speterapr_status_t apr_os_sock_make(apr_socket_t **apr_sock, 444251875Speter apr_os_sock_info_t *os_sock_info, 445251875Speter apr_pool_t *cont) 446251875Speter{ 447251875Speter alloc_socket(apr_sock, cont); 448251875Speter set_socket_vars(*apr_sock, os_sock_info->family, os_sock_info->type, os_sock_info->protocol); 449251875Speter (*apr_sock)->timeout = -1; 450251875Speter (*apr_sock)->socketdes = *os_sock_info->os_sock; 451251875Speter if (os_sock_info->local) { 452251875Speter memcpy(&(*apr_sock)->local_addr->sa.sin, 453251875Speter os_sock_info->local, 454251875Speter (*apr_sock)->local_addr->salen); 455251875Speter /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ 456251875Speter (*apr_sock)->local_addr->port = ntohs((*apr_sock)->local_addr->sa.sin.sin_port); 457251875Speter } 458251875Speter else { 459251875Speter (*apr_sock)->local_port_unknown = (*apr_sock)->local_interface_unknown = 1; 460251875Speter } 461251875Speter if (os_sock_info->remote) { 462251875Speter#ifndef HAVE_POLL 463251875Speter (*apr_sock)->connected = 1; 464251875Speter#endif 465251875Speter memcpy(&(*apr_sock)->remote_addr->sa.sin, 466251875Speter os_sock_info->remote, 467251875Speter (*apr_sock)->remote_addr->salen); 468251875Speter /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ 469251875Speter (*apr_sock)->remote_addr->port = ntohs((*apr_sock)->remote_addr->sa.sin.sin_port); 470251875Speter } 471251875Speter else { 472251875Speter (*apr_sock)->remote_addr_unknown = 1; 473251875Speter } 474251875Speter 475251875Speter (*apr_sock)->inherit = 0; 476251875Speter apr_pool_cleanup_register((*apr_sock)->pool, (void *)(*apr_sock), 477251875Speter socket_cleanup, socket_cleanup); 478251875Speter return APR_SUCCESS; 479251875Speter} 480251875Speter 481251875Speterapr_status_t apr_os_sock_put(apr_socket_t **sock, apr_os_sock_t *thesock, 482251875Speter apr_pool_t *cont) 483251875Speter{ 484251875Speter /* XXX Bogus assumption that *sock points at anything legit */ 485251875Speter if ((*sock) == NULL) { 486251875Speter alloc_socket(sock, cont); 487251875Speter /* XXX IPv6 figure out the family here! */ 488251875Speter /* XXX figure out the actual socket type here */ 489251875Speter /* *or* just decide that apr_os_sock_put() has to be told the family and type */ 490251875Speter set_socket_vars(*sock, APR_INET, SOCK_STREAM, 0); 491251875Speter (*sock)->timeout = -1; 492251875Speter } 493251875Speter (*sock)->local_port_unknown = (*sock)->local_interface_unknown = 1; 494251875Speter (*sock)->remote_addr_unknown = 1; 495251875Speter (*sock)->socketdes = *thesock; 496251875Speter return APR_SUCCESS; 497251875Speter} 498251875Speter 499251875SpeterAPR_POOL_IMPLEMENT_ACCESSOR(socket) 500251875Speter 501251875SpeterAPR_IMPLEMENT_INHERIT_SET(socket, inherit, pool, socket_cleanup) 502251875Speter 503251875SpeterAPR_IMPLEMENT_INHERIT_UNSET(socket, inherit, pool, socket_cleanup) 504