sockets.c revision 251875
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 210251875Speter s = accept4(sock->socketdes, (struct sockaddr *)&sa.sa, &sa.salen, SOCK_CLOEXEC); 211251875Speter#else 212251875Speter s = accept(sock->socketdes, (struct sockaddr *)&sa.sa, &sa.salen); 213251875Speter#endif 214251875Speter 215251875Speter if (s < 0) { 216251875Speter return errno; 217251875Speter } 218251875Speter#ifdef TPF 219251875Speter if (s == 0) { 220251875Speter /* 0 is an invalid socket for TPF */ 221251875Speter return APR_EINTR; 222251875Speter } 223251875Speter#endif 224251875Speter alloc_socket(new, connection_context); 225251875Speter 226251875Speter /* Set up socket variables -- note that it may be possible for 227251875Speter * *new to be an AF_INET socket when sock is AF_INET6 in some 228251875Speter * dual-stack configurations, so ensure that the remote_/local_addr 229251875Speter * structures are adjusted for the family of the accepted 230251875Speter * socket: */ 231251875Speter set_socket_vars(*new, sa.sa.sin.sin_family, SOCK_STREAM, sock->protocol); 232251875Speter 233251875Speter#ifndef HAVE_POLL 234251875Speter (*new)->connected = 1; 235251875Speter#endif 236251875Speter (*new)->timeout = -1; 237251875Speter 238251875Speter (*new)->remote_addr_unknown = 0; 239251875Speter 240251875Speter (*new)->socketdes = s; 241251875Speter 242251875Speter /* Copy in peer's address. */ 243251875Speter (*new)->remote_addr->sa = sa.sa; 244251875Speter (*new)->remote_addr->salen = sa.salen; 245251875Speter 246251875Speter *(*new)->local_addr = *sock->local_addr; 247251875Speter 248251875Speter /* The above assignment just overwrote the pool entry. Setting the local_addr 249251875Speter pool for the accepted socket back to what it should be. Otherwise all 250251875Speter allocations for this socket will come from a server pool that is not 251251875Speter freed until the process goes down.*/ 252251875Speter (*new)->local_addr->pool = connection_context; 253251875Speter 254251875Speter /* fix up any pointers which are no longer valid */ 255251875Speter if (sock->local_addr->sa.sin.sin_family == AF_INET) { 256251875Speter (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin.sin_addr; 257251875Speter } 258251875Speter#if APR_HAVE_IPV6 259251875Speter else if (sock->local_addr->sa.sin.sin_family == AF_INET6) { 260251875Speter (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin6.sin6_addr; 261251875Speter } 262251875Speter#endif 263251875Speter (*new)->remote_addr->port = ntohs((*new)->remote_addr->sa.sin.sin_port); 264251875Speter if (sock->local_port_unknown) { 265251875Speter /* not likely for a listening socket, but theoretically possible :) */ 266251875Speter (*new)->local_port_unknown = 1; 267251875Speter } 268251875Speter 269251875Speter#if APR_TCP_NODELAY_INHERITED 270251875Speter if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1) { 271251875Speter apr_set_option(*new, APR_TCP_NODELAY, 1); 272251875Speter } 273251875Speter#endif /* TCP_NODELAY_INHERITED */ 274251875Speter#if APR_O_NONBLOCK_INHERITED 275251875Speter if (apr_is_option_set(sock, APR_SO_NONBLOCK) == 1) { 276251875Speter apr_set_option(*new, APR_SO_NONBLOCK, 1); 277251875Speter } 278251875Speter#endif /* APR_O_NONBLOCK_INHERITED */ 279251875Speter 280251875Speter if (sock->local_interface_unknown || 281251875Speter !memcmp(sock->local_addr->ipaddr_ptr, 282251875Speter generic_inaddr_any, 283251875Speter sock->local_addr->ipaddr_len)) { 284251875Speter /* If the interface address inside the listening socket's local_addr wasn't 285251875Speter * up-to-date, we don't know local interface of the connected socket either. 286251875Speter * 287251875Speter * If the listening socket was not bound to a specific interface, we 288251875Speter * don't know the local_addr of the connected socket. 289251875Speter */ 290251875Speter (*new)->local_interface_unknown = 1; 291251875Speter } 292251875Speter 293251875Speter#ifndef HAVE_ACCEPT4 294251875Speter { 295251875Speter int flags; 296251875Speter 297251875Speter if ((flags = fcntl((*new)->socketdes, F_GETFD)) == -1) 298251875Speter return errno; 299251875Speter 300251875Speter flags |= FD_CLOEXEC; 301251875Speter if (fcntl((*new)->socketdes, F_SETFD, flags) == -1) 302251875Speter return errno; 303251875Speter } 304251875Speter#endif 305251875Speter 306251875Speter (*new)->inherit = 0; 307251875Speter apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup, 308251875Speter socket_cleanup); 309251875Speter return APR_SUCCESS; 310251875Speter} 311251875Speter 312251875Speterapr_status_t apr_socket_connect(apr_socket_t *sock, apr_sockaddr_t *sa) 313251875Speter{ 314251875Speter int rc; 315251875Speter 316251875Speter do { 317251875Speter rc = connect(sock->socketdes, 318251875Speter (const struct sockaddr *)&sa->sa.sin, 319251875Speter sa->salen); 320251875Speter } while (rc == -1 && errno == EINTR); 321251875Speter 322251875Speter /* we can see EINPROGRESS the first time connect is called on a non-blocking 323251875Speter * socket; if called again, we can see EALREADY 324251875Speter */ 325251875Speter if ((rc == -1) && (errno == EINPROGRESS || errno == EALREADY) 326251875Speter && (sock->timeout > 0)) { 327251875Speter rc = apr_wait_for_io_or_timeout(NULL, sock, 0); 328251875Speter if (rc != APR_SUCCESS) { 329251875Speter return rc; 330251875Speter } 331251875Speter 332251875Speter#ifdef SO_ERROR 333251875Speter { 334251875Speter int error; 335251875Speter apr_socklen_t len = sizeof(error); 336251875Speter if ((rc = getsockopt(sock->socketdes, SOL_SOCKET, SO_ERROR, 337251875Speter (char *)&error, &len)) < 0) { 338251875Speter return errno; 339251875Speter } 340251875Speter if (error) { 341251875Speter return error; 342251875Speter } 343251875Speter } 344251875Speter#endif /* SO_ERROR */ 345251875Speter } 346251875Speter 347251875Speter 348251875Speter if (memcmp(sa->ipaddr_ptr, generic_inaddr_any, sa->ipaddr_len)) { 349251875Speter /* A real remote address was passed in. If the unspecified 350251875Speter * address was used, the actual remote addr will have to be 351251875Speter * determined using getpeername() if required. */ 352251875Speter sock->remote_addr_unknown = 0; 353251875Speter 354251875Speter /* Copy the address structure details in. */ 355251875Speter sock->remote_addr->sa = sa->sa; 356251875Speter sock->remote_addr->salen = sa->salen; 357251875Speter /* Adjust ipaddr_ptr et al. */ 358251875Speter apr_sockaddr_vars_set(sock->remote_addr, sa->family, sa->port); 359251875Speter } 360251875Speter 361251875Speter if (sock->local_addr->port == 0) { 362251875Speter /* connect() got us an ephemeral port */ 363251875Speter sock->local_port_unknown = 1; 364251875Speter } 365251875Speter if (!memcmp(sock->local_addr->ipaddr_ptr, 366251875Speter generic_inaddr_any, 367251875Speter sock->local_addr->ipaddr_len)) { 368251875Speter /* not bound to specific local interface; connect() had to assign 369251875Speter * one for the socket 370251875Speter */ 371251875Speter sock->local_interface_unknown = 1; 372251875Speter } 373251875Speter 374251875Speter if (rc == -1 && errno != EISCONN) { 375251875Speter return errno; 376251875Speter } 377251875Speter 378251875Speter#ifndef HAVE_POLL 379251875Speter sock->connected=1; 380251875Speter#endif 381251875Speter return APR_SUCCESS; 382251875Speter} 383251875Speter 384251875Speterapr_status_t apr_socket_type_get(apr_socket_t *sock, int *type) 385251875Speter{ 386251875Speter *type = sock->type; 387251875Speter return APR_SUCCESS; 388251875Speter} 389251875Speter 390251875Speterapr_status_t apr_socket_data_get(void **data, const char *key, apr_socket_t *sock) 391251875Speter{ 392251875Speter sock_userdata_t *cur = sock->userdata; 393251875Speter 394251875Speter *data = NULL; 395251875Speter 396251875Speter while (cur) { 397251875Speter if (!strcmp(cur->key, key)) { 398251875Speter *data = cur->data; 399251875Speter break; 400251875Speter } 401251875Speter cur = cur->next; 402251875Speter } 403251875Speter 404251875Speter return APR_SUCCESS; 405251875Speter} 406251875Speter 407251875Speterapr_status_t apr_socket_data_set(apr_socket_t *sock, void *data, const char *key, 408251875Speter apr_status_t (*cleanup) (void *)) 409251875Speter{ 410251875Speter sock_userdata_t *new = apr_palloc(sock->pool, sizeof(sock_userdata_t)); 411251875Speter 412251875Speter new->key = apr_pstrdup(sock->pool, key); 413251875Speter new->data = data; 414251875Speter new->next = sock->userdata; 415251875Speter sock->userdata = new; 416251875Speter 417251875Speter if (cleanup) { 418251875Speter apr_pool_cleanup_register(sock->pool, data, cleanup, cleanup); 419251875Speter } 420251875Speter 421251875Speter return APR_SUCCESS; 422251875Speter} 423251875Speter 424251875Speterapr_status_t apr_os_sock_get(apr_os_sock_t *thesock, apr_socket_t *sock) 425251875Speter{ 426251875Speter *thesock = sock->socketdes; 427251875Speter return APR_SUCCESS; 428251875Speter} 429251875Speter 430251875Speterapr_status_t apr_os_sock_make(apr_socket_t **apr_sock, 431251875Speter apr_os_sock_info_t *os_sock_info, 432251875Speter apr_pool_t *cont) 433251875Speter{ 434251875Speter alloc_socket(apr_sock, cont); 435251875Speter set_socket_vars(*apr_sock, os_sock_info->family, os_sock_info->type, os_sock_info->protocol); 436251875Speter (*apr_sock)->timeout = -1; 437251875Speter (*apr_sock)->socketdes = *os_sock_info->os_sock; 438251875Speter if (os_sock_info->local) { 439251875Speter memcpy(&(*apr_sock)->local_addr->sa.sin, 440251875Speter os_sock_info->local, 441251875Speter (*apr_sock)->local_addr->salen); 442251875Speter /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ 443251875Speter (*apr_sock)->local_addr->port = ntohs((*apr_sock)->local_addr->sa.sin.sin_port); 444251875Speter } 445251875Speter else { 446251875Speter (*apr_sock)->local_port_unknown = (*apr_sock)->local_interface_unknown = 1; 447251875Speter } 448251875Speter if (os_sock_info->remote) { 449251875Speter#ifndef HAVE_POLL 450251875Speter (*apr_sock)->connected = 1; 451251875Speter#endif 452251875Speter memcpy(&(*apr_sock)->remote_addr->sa.sin, 453251875Speter os_sock_info->remote, 454251875Speter (*apr_sock)->remote_addr->salen); 455251875Speter /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ 456251875Speter (*apr_sock)->remote_addr->port = ntohs((*apr_sock)->remote_addr->sa.sin.sin_port); 457251875Speter } 458251875Speter else { 459251875Speter (*apr_sock)->remote_addr_unknown = 1; 460251875Speter } 461251875Speter 462251875Speter (*apr_sock)->inherit = 0; 463251875Speter apr_pool_cleanup_register((*apr_sock)->pool, (void *)(*apr_sock), 464251875Speter socket_cleanup, socket_cleanup); 465251875Speter return APR_SUCCESS; 466251875Speter} 467251875Speter 468251875Speterapr_status_t apr_os_sock_put(apr_socket_t **sock, apr_os_sock_t *thesock, 469251875Speter apr_pool_t *cont) 470251875Speter{ 471251875Speter /* XXX Bogus assumption that *sock points at anything legit */ 472251875Speter if ((*sock) == NULL) { 473251875Speter alloc_socket(sock, cont); 474251875Speter /* XXX IPv6 figure out the family here! */ 475251875Speter /* XXX figure out the actual socket type here */ 476251875Speter /* *or* just decide that apr_os_sock_put() has to be told the family and type */ 477251875Speter set_socket_vars(*sock, APR_INET, SOCK_STREAM, 0); 478251875Speter (*sock)->timeout = -1; 479251875Speter } 480251875Speter (*sock)->local_port_unknown = (*sock)->local_interface_unknown = 1; 481251875Speter (*sock)->remote_addr_unknown = 1; 482251875Speter (*sock)->socketdes = *thesock; 483251875Speter return APR_SUCCESS; 484251875Speter} 485251875Speter 486251875SpeterAPR_POOL_IMPLEMENT_ACCESSOR(socket) 487251875Speter 488251875SpeterAPR_IMPLEMENT_INHERIT_SET(socket, inherit, pool, socket_cleanup) 489251875Speter 490251875SpeterAPR_IMPLEMENT_INHERIT_UNSET(socket, inherit, pool, socket_cleanup) 491