sockets.c revision 251875
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 s = accept4(sock->socketdes, (struct sockaddr *)&sa.sa, &sa.salen, SOCK_CLOEXEC); 211#else 212 s = accept(sock->socketdes, (struct sockaddr *)&sa.sa, &sa.salen); 213#endif 214 215 if (s < 0) { 216 return errno; 217 } 218#ifdef TPF 219 if (s == 0) { 220 /* 0 is an invalid socket for TPF */ 221 return APR_EINTR; 222 } 223#endif 224 alloc_socket(new, connection_context); 225 226 /* Set up socket variables -- note that it may be possible for 227 * *new to be an AF_INET socket when sock is AF_INET6 in some 228 * dual-stack configurations, so ensure that the remote_/local_addr 229 * structures are adjusted for the family of the accepted 230 * socket: */ 231 set_socket_vars(*new, sa.sa.sin.sin_family, SOCK_STREAM, sock->protocol); 232 233#ifndef HAVE_POLL 234 (*new)->connected = 1; 235#endif 236 (*new)->timeout = -1; 237 238 (*new)->remote_addr_unknown = 0; 239 240 (*new)->socketdes = s; 241 242 /* Copy in peer's address. */ 243 (*new)->remote_addr->sa = sa.sa; 244 (*new)->remote_addr->salen = sa.salen; 245 246 *(*new)->local_addr = *sock->local_addr; 247 248 /* The above assignment just overwrote the pool entry. Setting the local_addr 249 pool for the accepted socket back to what it should be. Otherwise all 250 allocations for this socket will come from a server pool that is not 251 freed until the process goes down.*/ 252 (*new)->local_addr->pool = connection_context; 253 254 /* fix up any pointers which are no longer valid */ 255 if (sock->local_addr->sa.sin.sin_family == AF_INET) { 256 (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin.sin_addr; 257 } 258#if APR_HAVE_IPV6 259 else if (sock->local_addr->sa.sin.sin_family == AF_INET6) { 260 (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin6.sin6_addr; 261 } 262#endif 263 (*new)->remote_addr->port = ntohs((*new)->remote_addr->sa.sin.sin_port); 264 if (sock->local_port_unknown) { 265 /* not likely for a listening socket, but theoretically possible :) */ 266 (*new)->local_port_unknown = 1; 267 } 268 269#if APR_TCP_NODELAY_INHERITED 270 if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1) { 271 apr_set_option(*new, APR_TCP_NODELAY, 1); 272 } 273#endif /* TCP_NODELAY_INHERITED */ 274#if APR_O_NONBLOCK_INHERITED 275 if (apr_is_option_set(sock, APR_SO_NONBLOCK) == 1) { 276 apr_set_option(*new, APR_SO_NONBLOCK, 1); 277 } 278#endif /* APR_O_NONBLOCK_INHERITED */ 279 280 if (sock->local_interface_unknown || 281 !memcmp(sock->local_addr->ipaddr_ptr, 282 generic_inaddr_any, 283 sock->local_addr->ipaddr_len)) { 284 /* If the interface address inside the listening socket's local_addr wasn't 285 * up-to-date, we don't know local interface of the connected socket either. 286 * 287 * If the listening socket was not bound to a specific interface, we 288 * don't know the local_addr of the connected socket. 289 */ 290 (*new)->local_interface_unknown = 1; 291 } 292 293#ifndef HAVE_ACCEPT4 294 { 295 int flags; 296 297 if ((flags = fcntl((*new)->socketdes, F_GETFD)) == -1) 298 return errno; 299 300 flags |= FD_CLOEXEC; 301 if (fcntl((*new)->socketdes, F_SETFD, flags) == -1) 302 return errno; 303 } 304#endif 305 306 (*new)->inherit = 0; 307 apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup, 308 socket_cleanup); 309 return APR_SUCCESS; 310} 311 312apr_status_t apr_socket_connect(apr_socket_t *sock, apr_sockaddr_t *sa) 313{ 314 int rc; 315 316 do { 317 rc = connect(sock->socketdes, 318 (const struct sockaddr *)&sa->sa.sin, 319 sa->salen); 320 } while (rc == -1 && errno == EINTR); 321 322 /* we can see EINPROGRESS the first time connect is called on a non-blocking 323 * socket; if called again, we can see EALREADY 324 */ 325 if ((rc == -1) && (errno == EINPROGRESS || errno == EALREADY) 326 && (sock->timeout > 0)) { 327 rc = apr_wait_for_io_or_timeout(NULL, sock, 0); 328 if (rc != APR_SUCCESS) { 329 return rc; 330 } 331 332#ifdef SO_ERROR 333 { 334 int error; 335 apr_socklen_t len = sizeof(error); 336 if ((rc = getsockopt(sock->socketdes, SOL_SOCKET, SO_ERROR, 337 (char *)&error, &len)) < 0) { 338 return errno; 339 } 340 if (error) { 341 return error; 342 } 343 } 344#endif /* SO_ERROR */ 345 } 346 347 348 if (memcmp(sa->ipaddr_ptr, generic_inaddr_any, sa->ipaddr_len)) { 349 /* A real remote address was passed in. If the unspecified 350 * address was used, the actual remote addr will have to be 351 * determined using getpeername() if required. */ 352 sock->remote_addr_unknown = 0; 353 354 /* Copy the address structure details in. */ 355 sock->remote_addr->sa = sa->sa; 356 sock->remote_addr->salen = sa->salen; 357 /* Adjust ipaddr_ptr et al. */ 358 apr_sockaddr_vars_set(sock->remote_addr, sa->family, sa->port); 359 } 360 361 if (sock->local_addr->port == 0) { 362 /* connect() got us an ephemeral port */ 363 sock->local_port_unknown = 1; 364 } 365 if (!memcmp(sock->local_addr->ipaddr_ptr, 366 generic_inaddr_any, 367 sock->local_addr->ipaddr_len)) { 368 /* not bound to specific local interface; connect() had to assign 369 * one for the socket 370 */ 371 sock->local_interface_unknown = 1; 372 } 373 374 if (rc == -1 && errno != EISCONN) { 375 return errno; 376 } 377 378#ifndef HAVE_POLL 379 sock->connected=1; 380#endif 381 return APR_SUCCESS; 382} 383 384apr_status_t apr_socket_type_get(apr_socket_t *sock, int *type) 385{ 386 *type = sock->type; 387 return APR_SUCCESS; 388} 389 390apr_status_t apr_socket_data_get(void **data, const char *key, apr_socket_t *sock) 391{ 392 sock_userdata_t *cur = sock->userdata; 393 394 *data = NULL; 395 396 while (cur) { 397 if (!strcmp(cur->key, key)) { 398 *data = cur->data; 399 break; 400 } 401 cur = cur->next; 402 } 403 404 return APR_SUCCESS; 405} 406 407apr_status_t apr_socket_data_set(apr_socket_t *sock, void *data, const char *key, 408 apr_status_t (*cleanup) (void *)) 409{ 410 sock_userdata_t *new = apr_palloc(sock->pool, sizeof(sock_userdata_t)); 411 412 new->key = apr_pstrdup(sock->pool, key); 413 new->data = data; 414 new->next = sock->userdata; 415 sock->userdata = new; 416 417 if (cleanup) { 418 apr_pool_cleanup_register(sock->pool, data, cleanup, cleanup); 419 } 420 421 return APR_SUCCESS; 422} 423 424apr_status_t apr_os_sock_get(apr_os_sock_t *thesock, apr_socket_t *sock) 425{ 426 *thesock = sock->socketdes; 427 return APR_SUCCESS; 428} 429 430apr_status_t apr_os_sock_make(apr_socket_t **apr_sock, 431 apr_os_sock_info_t *os_sock_info, 432 apr_pool_t *cont) 433{ 434 alloc_socket(apr_sock, cont); 435 set_socket_vars(*apr_sock, os_sock_info->family, os_sock_info->type, os_sock_info->protocol); 436 (*apr_sock)->timeout = -1; 437 (*apr_sock)->socketdes = *os_sock_info->os_sock; 438 if (os_sock_info->local) { 439 memcpy(&(*apr_sock)->local_addr->sa.sin, 440 os_sock_info->local, 441 (*apr_sock)->local_addr->salen); 442 /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ 443 (*apr_sock)->local_addr->port = ntohs((*apr_sock)->local_addr->sa.sin.sin_port); 444 } 445 else { 446 (*apr_sock)->local_port_unknown = (*apr_sock)->local_interface_unknown = 1; 447 } 448 if (os_sock_info->remote) { 449#ifndef HAVE_POLL 450 (*apr_sock)->connected = 1; 451#endif 452 memcpy(&(*apr_sock)->remote_addr->sa.sin, 453 os_sock_info->remote, 454 (*apr_sock)->remote_addr->salen); 455 /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ 456 (*apr_sock)->remote_addr->port = ntohs((*apr_sock)->remote_addr->sa.sin.sin_port); 457 } 458 else { 459 (*apr_sock)->remote_addr_unknown = 1; 460 } 461 462 (*apr_sock)->inherit = 0; 463 apr_pool_cleanup_register((*apr_sock)->pool, (void *)(*apr_sock), 464 socket_cleanup, socket_cleanup); 465 return APR_SUCCESS; 466} 467 468apr_status_t apr_os_sock_put(apr_socket_t **sock, apr_os_sock_t *thesock, 469 apr_pool_t *cont) 470{ 471 /* XXX Bogus assumption that *sock points at anything legit */ 472 if ((*sock) == NULL) { 473 alloc_socket(sock, cont); 474 /* XXX IPv6 figure out the family here! */ 475 /* XXX figure out the actual socket type here */ 476 /* *or* just decide that apr_os_sock_put() has to be told the family and type */ 477 set_socket_vars(*sock, APR_INET, SOCK_STREAM, 0); 478 (*sock)->timeout = -1; 479 } 480 (*sock)->local_port_unknown = (*sock)->local_interface_unknown = 1; 481 (*sock)->remote_addr_unknown = 1; 482 (*sock)->socketdes = *thesock; 483 return APR_SUCCESS; 484} 485 486APR_POOL_IMPLEMENT_ACCESSOR(socket) 487 488APR_IMPLEMENT_INHERIT_SET(socket, inherit, pool, socket_cleanup) 489 490APR_IMPLEMENT_INHERIT_UNSET(socket, inherit, pool, socket_cleanup) 491