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