sockets.c revision 362181
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 17#include "apr_arch_networkio.h" 18#include "apr_network_io.h" 19#include "apr_strings.h" 20#include "apr_support.h" 21#include "apr_portable.h" 22#include "apr_arch_inherit.h" 23 24#ifdef BEOS_R5 25#undef close 26#define close closesocket 27#endif /* BEOS_R5 */ 28 29#if APR_HAVE_SOCKADDR_UN 30#define GENERIC_INADDR_ANY_LEN sizeof(struct sockaddr_un) 31#else 32#define GENERIC_INADDR_ANY_LEN 16 33#endif 34 35/* big enough for IPv4, IPv6 and optionaly sun_path */ 36static char generic_inaddr_any[GENERIC_INADDR_ANY_LEN] = {0}; 37 38static apr_status_t socket_cleanup(void *sock) 39{ 40 apr_socket_t *thesocket = sock; 41 int sd = thesocket->socketdes; 42 43#if APR_HAVE_SOCKADDR_UN 44 if (thesocket->bound && thesocket->local_addr->family == APR_UNIX) { 45 /* XXX: Check for return values ? */ 46 unlink(thesocket->local_addr->hostname); 47 } 48#endif 49 /* Set socket descriptor to -1 before close(), so that there is no 50 * chance of returning an already closed FD from apr_os_sock_get(). 51 */ 52 thesocket->socketdes = -1; 53 54 if (close(sd) == 0) { 55 return APR_SUCCESS; 56 } 57 else { 58 /* Restore, close() was not successful. */ 59 thesocket->socketdes = sd; 60 61 return errno; 62 } 63} 64 65static apr_status_t socket_child_cleanup(void *sock) 66{ 67 apr_socket_t *thesocket = sock; 68 if (close(thesocket->socketdes) == 0) { 69 thesocket->socketdes = -1; 70 return APR_SUCCESS; 71 } 72 else { 73 return errno; 74 } 75} 76 77static void set_socket_vars(apr_socket_t *sock, int family, int type, int protocol) 78{ 79 sock->type = type; 80 sock->protocol = protocol; 81 apr_sockaddr_vars_set(sock->local_addr, family, 0); 82 apr_sockaddr_vars_set(sock->remote_addr, family, 0); 83 sock->options = 0; 84#if defined(BEOS) && !defined(BEOS_BONE) 85 /* BeOS pre-BONE has TCP_NODELAY on by default and it can't be 86 * switched off! 87 */ 88 sock->options |= APR_TCP_NODELAY; 89#endif 90} 91 92static void alloc_socket(apr_socket_t **new, apr_pool_t *p) 93{ 94 *new = (apr_socket_t *)apr_pcalloc(p, sizeof(apr_socket_t)); 95 (*new)->pool = p; 96 (*new)->local_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool, 97 sizeof(apr_sockaddr_t)); 98 (*new)->local_addr->pool = p; 99 (*new)->remote_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool, 100 sizeof(apr_sockaddr_t)); 101 (*new)->remote_addr->pool = p; 102 (*new)->remote_addr_unknown = 1; 103#ifndef WAITIO_USES_POLL 104 /* Create a pollset with room for one descriptor. */ 105 /* ### check return codes */ 106 (void) apr_pollset_create(&(*new)->pollset, 1, p, 0); 107#endif 108} 109 110apr_status_t apr_socket_protocol_get(apr_socket_t *sock, int *protocol) 111{ 112 *protocol = sock->protocol; 113 return APR_SUCCESS; 114} 115 116apr_status_t apr_socket_create(apr_socket_t **new, int ofamily, int type, 117 int protocol, apr_pool_t *cont) 118{ 119 int family = ofamily, flags = 0; 120 int oprotocol = protocol; 121 122#ifdef HAVE_SOCK_CLOEXEC 123 flags |= SOCK_CLOEXEC; 124#endif 125 126 if (family == APR_UNSPEC) { 127#if APR_HAVE_IPV6 128 family = APR_INET6; 129#else 130 family = APR_INET; 131#endif 132 } 133#if APR_HAVE_SOCKADDR_UN 134 if (family == APR_UNIX) { 135 protocol = 0; 136 } 137#endif 138 alloc_socket(new, cont); 139 140#ifndef BEOS_R5 141 (*new)->socketdes = socket(family, type|flags, protocol); 142#else 143 /* For some reason BeOS R5 has an unconventional protocol numbering, 144 * so we need to translate here. */ 145 switch (protocol) { 146 case 0: 147 (*new)->socketdes = socket(family, type|flags, 0); 148 break; 149 case APR_PROTO_TCP: 150 (*new)->socketdes = socket(family, type|flags, IPPROTO_TCP); 151 break; 152 case APR_PROTO_UDP: 153 (*new)->socketdes = socket(family, type|flags, IPPROTO_UDP); 154 break; 155 case APR_PROTO_SCTP: 156 default: 157 errno = EPROTONOSUPPORT; 158 (*new)->socketdes = -1; 159 break; 160 } 161#endif /* BEOS_R5 */ 162 163#if APR_HAVE_IPV6 164 if ((*new)->socketdes < 0 && ofamily == APR_UNSPEC) { 165 family = APR_INET; 166 (*new)->socketdes = socket(family, type|flags, protocol); 167 } 168#endif 169 170 if ((*new)->socketdes < 0) { 171 return errno; 172 } 173 set_socket_vars(*new, family, type, oprotocol); 174 175#ifndef HAVE_SOCK_CLOEXEC 176 { 177 int flags; 178 apr_status_t rv; 179 180 if ((flags = fcntl((*new)->socketdes, F_GETFD)) == -1) { 181 rv = errno; 182 close((*new)->socketdes); 183 (*new)->socketdes = -1; 184 return rv; 185 } 186 187 flags |= FD_CLOEXEC; 188 if (fcntl((*new)->socketdes, F_SETFD, flags) == -1) { 189 rv = errno; 190 close((*new)->socketdes); 191 (*new)->socketdes = -1; 192 return rv; 193 } 194 } 195#endif 196 197 (*new)->timeout = -1; 198 (*new)->inherit = 0; 199 apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup, 200 socket_child_cleanup); 201 202 return APR_SUCCESS; 203} 204 205apr_status_t apr_socket_shutdown(apr_socket_t *thesocket, 206 apr_shutdown_how_e how) 207{ 208 return (shutdown(thesocket->socketdes, how) == -1) ? errno : APR_SUCCESS; 209} 210 211apr_status_t apr_socket_close(apr_socket_t *thesocket) 212{ 213 return apr_pool_cleanup_run(thesocket->pool, thesocket, socket_cleanup); 214} 215 216apr_status_t apr_socket_bind(apr_socket_t *sock, apr_sockaddr_t *sa) 217{ 218 if (bind(sock->socketdes, 219 (struct sockaddr *)&sa->sa, sa->salen) == -1) { 220 return errno; 221 } 222 else { 223 sock->local_addr = sa; 224 /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ 225#if APR_HAVE_SOCKADDR_UN 226 if (sock->local_addr->family == APR_UNIX) { 227 sock->bound = 1; 228 sock->local_port_unknown = 1; 229 } 230 else 231#endif 232 if (sock->local_addr->sa.sin.sin_port == 0) { /* no need for ntohs() when comparing w/ 0 */ 233 sock->local_port_unknown = 1; /* kernel got us an ephemeral port */ 234 } 235 return APR_SUCCESS; 236 } 237} 238 239apr_status_t apr_socket_listen(apr_socket_t *sock, apr_int32_t backlog) 240{ 241 if (listen(sock->socketdes, backlog) == -1) 242 return errno; 243 else 244 return APR_SUCCESS; 245} 246 247apr_status_t apr_socket_accept(apr_socket_t **new, apr_socket_t *sock, 248 apr_pool_t *connection_context) 249{ 250 int s; 251 apr_sockaddr_t sa; 252 253 sa.salen = sizeof(sa.sa); 254 255#ifdef HAVE_ACCEPT4 256 { 257 int flags = SOCK_CLOEXEC; 258 259#if defined(SOCK_NONBLOCK) && APR_O_NONBLOCK_INHERITED 260 /* With FreeBSD accept4() (avail in 10+), O_NONBLOCK is not inherited 261 * (unlike Linux). Mimic the accept() behavior here in a way that 262 * may help other platforms. 263 */ 264 if (apr_is_option_set(sock, APR_SO_NONBLOCK) == 1) { 265 flags |= SOCK_NONBLOCK; 266 } 267#endif 268 s = accept4(sock->socketdes, (struct sockaddr *)&sa.sa, &sa.salen, flags); 269 } 270#else 271 s = accept(sock->socketdes, (struct sockaddr *)&sa.sa, &sa.salen); 272#endif 273 274 if (s < 0) { 275 return errno; 276 } 277#ifdef TPF 278 if (s == 0) { 279 /* 0 is an invalid socket for TPF */ 280 return APR_EINTR; 281 } 282#endif 283 alloc_socket(new, connection_context); 284 285 /* Set up socket variables -- note that it may be possible for 286 * *new to be an AF_INET socket when sock is AF_INET6 in some 287 * dual-stack configurations, so ensure that the remote_/local_addr 288 * structures are adjusted for the family of the accepted 289 * socket: */ 290 set_socket_vars(*new, sa.sa.sin.sin_family, SOCK_STREAM, sock->protocol); 291 292#ifndef HAVE_POLL 293 (*new)->connected = 1; 294#endif 295 (*new)->timeout = -1; 296 297 (*new)->remote_addr_unknown = 0; 298 299 (*new)->socketdes = s; 300 301 /* Copy in peer's address. */ 302 (*new)->remote_addr->sa = sa.sa; 303 (*new)->remote_addr->salen = sa.salen; 304 305 *(*new)->local_addr = *sock->local_addr; 306 307 /* The above assignment just overwrote the pool entry. Setting the local_addr 308 pool for the accepted socket back to what it should be. Otherwise all 309 allocations for this socket will come from a server pool that is not 310 freed until the process goes down.*/ 311 (*new)->local_addr->pool = connection_context; 312 313 /* fix up any pointers which are no longer valid */ 314 if (sock->local_addr->sa.sin.sin_family == AF_INET) { 315 (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin.sin_addr; 316 } 317#if APR_HAVE_IPV6 318 else if (sock->local_addr->sa.sin.sin_family == AF_INET6) { 319 (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin6.sin6_addr; 320 } 321#endif 322#if APR_HAVE_SOCKADDR_UN 323 else if (sock->local_addr->sa.sin.sin_family == AF_UNIX) { 324 *(*new)->remote_addr = *sock->local_addr; 325 (*new)->local_addr->ipaddr_ptr = &((*new)->local_addr->sa.unx.sun_path); 326 (*new)->remote_addr->ipaddr_ptr = &((*new)->remote_addr->sa.unx.sun_path); 327 } 328 if (sock->local_addr->sa.sin.sin_family != AF_UNIX) 329#endif 330 (*new)->remote_addr->port = ntohs((*new)->remote_addr->sa.sin.sin_port); 331 if (sock->local_port_unknown) { 332 /* not likely for a listening socket, but theoretically possible :) */ 333 (*new)->local_port_unknown = 1; 334 } 335 336#if APR_TCP_NODELAY_INHERITED 337 if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1) { 338 apr_set_option(*new, APR_TCP_NODELAY, 1); 339 } 340#endif /* TCP_NODELAY_INHERITED */ 341#if APR_O_NONBLOCK_INHERITED 342 if (apr_is_option_set(sock, APR_SO_NONBLOCK) == 1) { 343 apr_set_option(*new, APR_SO_NONBLOCK, 1); 344 } 345#endif /* APR_O_NONBLOCK_INHERITED */ 346 347 if (sock->local_interface_unknown || 348 !memcmp(sock->local_addr->ipaddr_ptr, 349 generic_inaddr_any, 350 sock->local_addr->ipaddr_len)) { 351 /* If the interface address inside the listening socket's local_addr wasn't 352 * up-to-date, we don't know local interface of the connected socket either. 353 * 354 * If the listening socket was not bound to a specific interface, we 355 * don't know the local_addr of the connected socket. 356 */ 357 (*new)->local_interface_unknown = 1; 358 } 359 360#ifndef HAVE_ACCEPT4 361 { 362 int flags; 363 apr_status_t rv; 364 365 if ((flags = fcntl((*new)->socketdes, F_GETFD)) == -1) { 366 rv = errno; 367 close((*new)->socketdes); 368 (*new)->socketdes = -1; 369 return rv; 370 } 371 372 flags |= FD_CLOEXEC; 373 if (fcntl((*new)->socketdes, F_SETFD, flags) == -1) { 374 rv = errno; 375 close((*new)->socketdes); 376 (*new)->socketdes = -1; 377 return rv; 378 } 379 } 380#endif 381 382 (*new)->inherit = 0; 383 apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup, 384 socket_cleanup); 385 return APR_SUCCESS; 386} 387 388apr_status_t apr_socket_connect(apr_socket_t *sock, apr_sockaddr_t *sa) 389{ 390 int rc; 391 392 do { 393 rc = connect(sock->socketdes, 394 (const struct sockaddr *)&sa->sa.sin, 395 sa->salen); 396 } while (rc == -1 && errno == EINTR); 397 398 /* we can see EINPROGRESS the first time connect is called on a non-blocking 399 * socket; if called again, we can see EALREADY 400 */ 401 if ((rc == -1) && (errno == EINPROGRESS || errno == EALREADY) 402 && (sock->timeout > 0)) { 403 rc = apr_wait_for_io_or_timeout(NULL, sock, 0); 404 if (rc != APR_SUCCESS) { 405 return rc; 406 } 407 408#ifdef SO_ERROR 409 { 410 int error; 411 apr_socklen_t len = sizeof(error); 412 if ((rc = getsockopt(sock->socketdes, SOL_SOCKET, SO_ERROR, 413 (char *)&error, &len)) < 0) { 414 return errno; 415 } 416 if (error) { 417 return error; 418 } 419 } 420#endif /* SO_ERROR */ 421 } 422 423 if (memcmp(sa->ipaddr_ptr, generic_inaddr_any, sa->ipaddr_len)) { 424 /* A real remote address was passed in. If the unspecified 425 * address was used, the actual remote addr will have to be 426 * determined using getpeername() if required. */ 427 sock->remote_addr_unknown = 0; 428 429 /* Copy the address structure details in. */ 430 sock->remote_addr->sa = sa->sa; 431 sock->remote_addr->salen = sa->salen; 432 /* Adjust ipaddr_ptr et al. */ 433 apr_sockaddr_vars_set(sock->remote_addr, sa->family, sa->port); 434 } 435 436 if (sock->local_addr->port == 0) { 437 /* connect() got us an ephemeral port */ 438 sock->local_port_unknown = 1; 439 } 440#if APR_HAVE_SOCKADDR_UN 441 if (sock->local_addr->sa.sin.sin_family == AF_UNIX) { 442 /* Assign connect address as local. */ 443 sock->local_addr = sa; 444 } 445 else 446#endif 447 if (!memcmp(sock->local_addr->ipaddr_ptr, 448 generic_inaddr_any, 449 sock->local_addr->ipaddr_len)) { 450 /* not bound to specific local interface; connect() had to assign 451 * one for the socket 452 */ 453 sock->local_interface_unknown = 1; 454 } 455 456 if (rc == -1 && errno != EISCONN) { 457 return errno; 458 } 459 460#ifndef HAVE_POLL 461 sock->connected=1; 462#endif 463 return APR_SUCCESS; 464} 465 466apr_status_t apr_socket_type_get(apr_socket_t *sock, int *type) 467{ 468 *type = sock->type; 469 return APR_SUCCESS; 470} 471 472apr_status_t apr_socket_data_get(void **data, const char *key, apr_socket_t *sock) 473{ 474 sock_userdata_t *cur = sock->userdata; 475 476 *data = NULL; 477 478 while (cur) { 479 if (!strcmp(cur->key, key)) { 480 *data = cur->data; 481 break; 482 } 483 cur = cur->next; 484 } 485 486 return APR_SUCCESS; 487} 488 489apr_status_t apr_socket_data_set(apr_socket_t *sock, void *data, const char *key, 490 apr_status_t (*cleanup) (void *)) 491{ 492 sock_userdata_t *new = apr_palloc(sock->pool, sizeof(sock_userdata_t)); 493 494 new->key = apr_pstrdup(sock->pool, key); 495 new->data = data; 496 new->next = sock->userdata; 497 sock->userdata = new; 498 499 if (cleanup) { 500 apr_pool_cleanup_register(sock->pool, data, cleanup, cleanup); 501 } 502 503 return APR_SUCCESS; 504} 505 506apr_status_t apr_os_sock_get(apr_os_sock_t *thesock, apr_socket_t *sock) 507{ 508 *thesock = sock->socketdes; 509 return APR_SUCCESS; 510} 511 512apr_status_t apr_os_sock_make(apr_socket_t **apr_sock, 513 apr_os_sock_info_t *os_sock_info, 514 apr_pool_t *cont) 515{ 516 alloc_socket(apr_sock, cont); 517 set_socket_vars(*apr_sock, os_sock_info->family, os_sock_info->type, os_sock_info->protocol); 518 (*apr_sock)->timeout = -1; 519 (*apr_sock)->socketdes = *os_sock_info->os_sock; 520 if (os_sock_info->local) { 521 memcpy(&(*apr_sock)->local_addr->sa.sin, 522 os_sock_info->local, 523 (*apr_sock)->local_addr->salen); 524 /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ 525 (*apr_sock)->local_addr->port = ntohs((*apr_sock)->local_addr->sa.sin.sin_port); 526 } 527 else { 528 (*apr_sock)->local_port_unknown = (*apr_sock)->local_interface_unknown = 1; 529 } 530 if (os_sock_info->remote) { 531#ifndef HAVE_POLL 532 (*apr_sock)->connected = 1; 533#endif 534 memcpy(&(*apr_sock)->remote_addr->sa.sin, 535 os_sock_info->remote, 536 (*apr_sock)->remote_addr->salen); 537 /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ 538 (*apr_sock)->remote_addr->port = ntohs((*apr_sock)->remote_addr->sa.sin.sin_port); 539 } 540 else { 541 (*apr_sock)->remote_addr_unknown = 1; 542 } 543 544 (*apr_sock)->inherit = 0; 545 apr_pool_cleanup_register((*apr_sock)->pool, (void *)(*apr_sock), 546 socket_cleanup, socket_cleanup); 547 return APR_SUCCESS; 548} 549 550apr_status_t apr_os_sock_put(apr_socket_t **sock, apr_os_sock_t *thesock, 551 apr_pool_t *cont) 552{ 553 /* XXX Bogus assumption that *sock points at anything legit */ 554 if ((*sock) == NULL) { 555 alloc_socket(sock, cont); 556 /* XXX IPv6 figure out the family here! */ 557 /* XXX figure out the actual socket type here */ 558 /* *or* just decide that apr_os_sock_put() has to be told the family and type */ 559 set_socket_vars(*sock, APR_INET, SOCK_STREAM, 0); 560 (*sock)->timeout = -1; 561 } 562 (*sock)->local_port_unknown = (*sock)->local_interface_unknown = 1; 563 (*sock)->remote_addr_unknown = 1; 564 (*sock)->socketdes = *thesock; 565 return APR_SUCCESS; 566} 567 568APR_POOL_IMPLEMENT_ACCESSOR(socket) 569 570APR_IMPLEMENT_INHERIT_SET(socket, inherit, pool, socket_cleanup) 571 572APR_IMPLEMENT_INHERIT_UNSET(socket, inherit, pool, socket_cleanup) 573