root/main/network.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_gai_strerror
  2. php_network_freeaddresses
  3. php_network_getaddresses
  4. php_network_connect_socket
  5. sub_times
  6. php_network_bind_socket_to_local_addr
  7. php_network_parse_network_address_with_port
  8. php_network_populate_name_from_sockaddr
  9. php_network_get_peer_name
  10. php_network_get_sock_name
  11. php_network_accept_incoming
  12. php_network_connect_socket_to_host
  13. php_any_addr
  14. php_sockaddr_size
  15. php_socket_strerror
  16. _php_stream_sock_open_from_socket
  17. _php_stream_sock_open_host
  18. php_set_sock_blocking
  19. _php_emit_fd_setsize_warning
  20. php_poll2

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 5                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Author: Stig Venaas <venaas@uninett.no>                              |
  16    | Streams work by Wez Furlong <wez@thebrainroom.com>                   |
  17    +----------------------------------------------------------------------+
  18  */
  19 
  20 /* $Id$ */
  21 
  22 /*#define DEBUG_MAIN_NETWORK 1*/
  23 
  24 #include "php.h"
  25 
  26 #include <stddef.h>
  27 #include <errno.h>
  28 
  29 
  30 #ifdef PHP_WIN32
  31 # include <Ws2tcpip.h>
  32 # include "win32/inet.h"
  33 # define O_RDONLY _O_RDONLY
  34 # include "win32/param.h"
  35 #elif defined(NETWARE)
  36 #include <sys/timeval.h>
  37 #include <sys/param.h>
  38 #else
  39 #include <sys/param.h>
  40 #endif
  41 
  42 #include <sys/types.h>
  43 #if HAVE_SYS_SOCKET_H
  44 #include <sys/socket.h>
  45 #endif
  46 
  47 #ifndef _FCNTL_H
  48 #include <fcntl.h>
  49 #endif
  50 
  51 #ifdef HAVE_SYS_SELECT_H
  52 #include <sys/select.h>
  53 #endif
  54 #if HAVE_SYS_POLL_H
  55 #include <sys/poll.h>
  56 #endif
  57 
  58 #if defined(NETWARE)
  59 #ifdef USE_WINSOCK
  60 #include <novsock2.h>
  61 #else
  62 #include <arpa/inet.h>
  63 #include <netinet/in.h>
  64 #include <netdb.h>
  65 #include <sys/select.h>
  66 #include <sys/socket.h>
  67 #endif
  68 #elif !defined(PHP_WIN32)
  69 #include <netinet/in.h>
  70 #include <netdb.h>
  71 #if HAVE_ARPA_INET_H
  72 #include <arpa/inet.h>
  73 #endif
  74 #endif
  75 
  76 #ifndef HAVE_INET_ATON
  77 int inet_aton(const char *, struct in_addr *);
  78 #endif
  79 
  80 #include "php_network.h"
  81 
  82 #if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE)
  83 #undef AF_UNIX
  84 #endif
  85 
  86 #if defined(AF_UNIX)
  87 #include <sys/un.h>
  88 #endif
  89 
  90 #include "ext/standard/file.h"
  91 
  92 #ifdef PHP_WIN32
  93 # include "win32/time.h"
  94 # define SOCK_ERR INVALID_SOCKET
  95 # define SOCK_CONN_ERR SOCKET_ERROR
  96 # define PHP_TIMEOUT_ERROR_VALUE                WSAETIMEDOUT
  97 
  98 #if HAVE_IPV6
  99 const struct in6_addr in6addr_any = {0}; /* IN6ADDR_ANY_INIT; */
 100 #endif
 101 
 102 #else
 103 # define SOCK_ERR -1
 104 # define SOCK_CONN_ERR -1
 105 # define PHP_TIMEOUT_ERROR_VALUE                ETIMEDOUT
 106 #endif
 107 
 108 #if HAVE_GETADDRINFO
 109 #ifdef HAVE_GAI_STRERROR
 110 #  define PHP_GAI_STRERROR(x) (gai_strerror(x))
 111 #else
 112 #  define PHP_GAI_STRERROR(x) (php_gai_strerror(x))
 113 /* {{{ php_gai_strerror
 114  */
 115 static const char *php_gai_strerror(int code)
 116 {
 117         static struct {
 118                 int code;
 119                 const char *msg;
 120         } values[] = {
 121 #  ifdef EAI_ADDRFAMILY
 122                 {EAI_ADDRFAMILY, "Address family for hostname not supported"},
 123 #  endif
 124                 {EAI_AGAIN, "Temporary failure in name resolution"},
 125                 {EAI_BADFLAGS, "Bad value for ai_flags"},
 126                 {EAI_FAIL, "Non-recoverable failure in name resolution"},
 127                 {EAI_FAMILY, "ai_family not supported"},
 128                 {EAI_MEMORY, "Memory allocation failure"},
 129 #  ifdef EAI_NODATA
 130                 {EAI_NODATA, "No address associated with hostname"},
 131 #  endif
 132                 {EAI_NONAME, "Name or service not known"},
 133                 {EAI_SERVICE, "Servname not supported for ai_socktype"},
 134                 {EAI_SOCKTYPE, "ai_socktype not supported"},
 135                 {EAI_SYSTEM, "System error"},
 136                 {0, NULL}
 137         };
 138         int i;
 139 
 140         for (i = 0; values[i].msg != NULL; i++) {
 141                 if (values[i].code == code) {
 142                         return (char *)values[i].msg;
 143                 }
 144         }
 145 
 146         return "Unknown error";
 147 }
 148 /* }}} */
 149 #endif
 150 #endif
 151 
 152 /* {{{ php_network_freeaddresses
 153  */
 154 PHPAPI void php_network_freeaddresses(struct sockaddr **sal)
 155 {
 156         struct sockaddr **sap;
 157 
 158         if (sal == NULL)
 159                 return;
 160         for (sap = sal; *sap != NULL; sap++)
 161                 efree(*sap);
 162         efree(sal);
 163 }
 164 /* }}} */
 165 
 166 /* {{{ php_network_getaddresses
 167  * Returns number of addresses, 0 for none/error
 168  */
 169 PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, char **error_string TSRMLS_DC)
 170 {
 171         struct sockaddr **sap;
 172         int n;
 173 #if HAVE_GETADDRINFO
 174 # if HAVE_IPV6
 175         static int ipv6_borked = -1; /* the way this is used *is* thread safe */
 176 # endif
 177         struct addrinfo hints, *res, *sai;
 178 #else
 179         struct hostent *host_info;
 180         struct in_addr in;
 181 #endif
 182 
 183         if (host == NULL) {
 184                 return 0;
 185         }
 186 #if HAVE_GETADDRINFO
 187         memset(&hints, '\0', sizeof(hints));
 188 
 189         hints.ai_family = AF_INET; /* default to regular inet (see below) */
 190         hints.ai_socktype = socktype;
 191 
 192 # if HAVE_IPV6
 193         /* probe for a working IPv6 stack; even if detected as having v6 at compile
 194          * time, at runtime some stacks are slow to resolve or have other issues
 195          * if they are not correctly configured.
 196          * static variable use is safe here since simple store or fetch operations
 197          * are atomic and because the actual probe process is not in danger of
 198          * collisions or race conditions. */
 199         if (ipv6_borked == -1) {
 200                 int s;
 201 
 202                 s = socket(PF_INET6, SOCK_DGRAM, 0);
 203                 if (s == SOCK_ERR) {
 204                         ipv6_borked = 1;
 205                 } else {
 206                         ipv6_borked = 0;
 207                         closesocket(s);
 208                 }
 209         }
 210         hints.ai_family = ipv6_borked ? AF_INET : AF_UNSPEC;
 211 # endif
 212 
 213         if ((n = getaddrinfo(host, NULL, &hints, &res))) {
 214                 if (error_string) {
 215                         spprintf(error_string, 0, "php_network_getaddresses: getaddrinfo failed: %s", PHP_GAI_STRERROR(n));
 216                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", *error_string);
 217                 } else {
 218                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "php_network_getaddresses: getaddrinfo failed: %s", PHP_GAI_STRERROR(n));
 219                 }
 220                 return 0;
 221         } else if (res == NULL) {
 222                 if (error_string) {
 223                         spprintf(error_string, 0, "php_network_getaddresses: getaddrinfo failed (null result pointer) errno=%d", errno);
 224                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", *error_string);
 225                 } else {
 226                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "php_network_getaddresses: getaddrinfo failed (null result pointer)");
 227                 }
 228                 return 0;
 229         }
 230 
 231         sai = res;
 232         for (n = 1; (sai = sai->ai_next) != NULL; n++)
 233                 ;
 234 
 235         *sal = safe_emalloc((n + 1), sizeof(*sal), 0);
 236         sai = res;
 237         sap = *sal;
 238 
 239         do {
 240                 *sap = emalloc(sai->ai_addrlen);
 241                 memcpy(*sap, sai->ai_addr, sai->ai_addrlen);
 242                 sap++;
 243         } while ((sai = sai->ai_next) != NULL);
 244 
 245         freeaddrinfo(res);
 246 #else
 247         if (!inet_aton(host, &in)) {
 248                 /* XXX NOT THREAD SAFE (is safe under win32) */
 249                 if(strlen(host) > MAXFQDNLEN) {
 250                         host_info = NULL;
 251                         errno = E2BIG;
 252                 } else {
 253                         host_info = gethostbyname(host);
 254                 }
 255                 if (host_info == NULL) {
 256                         if (error_string) {
 257                                 spprintf(error_string, 0, "php_network_getaddresses: gethostbyname failed. errno=%d", errno);
 258                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", *error_string);
 259                         } else {
 260                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "php_network_getaddresses: gethostbyname failed");
 261                         }
 262                         return 0;
 263                 }
 264                 in = *((struct in_addr *) host_info->h_addr);
 265         }
 266 
 267         *sal = safe_emalloc(2, sizeof(*sal), 0);
 268         sap = *sal;
 269         *sap = emalloc(sizeof(struct sockaddr_in));
 270         (*sap)->sa_family = AF_INET;
 271         ((struct sockaddr_in *)*sap)->sin_addr = in;
 272         sap++;
 273         n = 1;
 274 #endif
 275 
 276         *sap = NULL;
 277         return n;
 278 }
 279 /* }}} */
 280 
 281 #ifndef O_NONBLOCK
 282 #define O_NONBLOCK O_NDELAY
 283 #endif
 284 
 285 #if !defined(__BEOS__)
 286 # define HAVE_NON_BLOCKING_CONNECT 1
 287 # ifdef PHP_WIN32
 288 typedef u_long php_non_blocking_flags_t;
 289 #  define SET_SOCKET_BLOCKING_MODE(sock, save) \
 290      save = TRUE; ioctlsocket(sock, FIONBIO, &save)
 291 #  define RESTORE_SOCKET_BLOCKING_MODE(sock, save) \
 292          ioctlsocket(sock, FIONBIO, &save)
 293 # else
 294 typedef int php_non_blocking_flags_t;
 295 #  define SET_SOCKET_BLOCKING_MODE(sock, save) \
 296          save = fcntl(sock, F_GETFL, 0); \
 297          fcntl(sock, F_SETFL, save | O_NONBLOCK)
 298 #  define RESTORE_SOCKET_BLOCKING_MODE(sock, save) \
 299          fcntl(sock, F_SETFL, save)
 300 # endif
 301 #endif
 302 
 303 /* Connect to a socket using an interruptible connect with optional timeout.
 304  * Optionally, the connect can be made asynchronously, which will implicitly
 305  * enable non-blocking mode on the socket.
 306  * */
 307 /* {{{ php_network_connect_socket */
 308 PHPAPI int php_network_connect_socket(php_socket_t sockfd,
 309                 const struct sockaddr *addr,
 310                 socklen_t addrlen,
 311                 int asynchronous,
 312                 struct timeval *timeout,
 313                 char **error_string,
 314                 int *error_code)
 315 {
 316 #if HAVE_NON_BLOCKING_CONNECT
 317         php_non_blocking_flags_t orig_flags;
 318         int n;
 319         int error = 0;
 320         socklen_t len;
 321         int ret = 0;
 322 
 323         SET_SOCKET_BLOCKING_MODE(sockfd, orig_flags);
 324 
 325         if ((n = connect(sockfd, addr, addrlen)) != 0) {
 326                 error = php_socket_errno();
 327 
 328                 if (error_code) {
 329                         *error_code = error;
 330                 }
 331 
 332                 if (error != EINPROGRESS) {
 333                         if (error_string) {
 334                                 *error_string = php_socket_strerror(error, NULL, 0);
 335                         }
 336 
 337                         return -1;
 338                 }
 339                 if (asynchronous && error == EINPROGRESS) {
 340                         /* this is fine by us */
 341                         return 0;
 342                 }
 343         }
 344 
 345         if (n == 0) {
 346                 goto ok;
 347         }
 348 # ifdef PHP_WIN32
 349         /* The documentation for connect() says in case of non-blocking connections
 350          * the select function reports success in the writefds set and failure in
 351          * the exceptfds set. Indeed, using PHP_POLLREADABLE results in select
 352          * failing only due to the timeout and not immediately as would be
 353          * expected when a connection is actively refused. This way,
 354          * php_pollfd_for will return a mask with POLLOUT if the connection
 355          * is successful and with POLLPRI otherwise. */
 356         if ((n = php_pollfd_for(sockfd, POLLOUT|POLLPRI, timeout)) == 0) {
 357 #else
 358         if ((n = php_pollfd_for(sockfd, PHP_POLLREADABLE|POLLOUT, timeout)) == 0) {
 359 #endif
 360                 error = PHP_TIMEOUT_ERROR_VALUE;
 361         }
 362 
 363         if (n > 0) {
 364                 len = sizeof(error);
 365                 /*
 366                    BSD-derived systems set errno correctly
 367                    Solaris returns -1 from getsockopt in case of error
 368                    */
 369                 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char*)&error, &len) != 0) {
 370                         ret = -1;
 371                 }
 372         } else {
 373                 /* whoops: sockfd has disappeared */
 374                 ret = -1;
 375         }
 376 
 377 ok:
 378         if (!asynchronous) {
 379                 /* back to blocking mode */
 380                 RESTORE_SOCKET_BLOCKING_MODE(sockfd, orig_flags);
 381         }
 382 
 383         if (error_code) {
 384                 *error_code = error;
 385         }
 386 
 387         if (error) {
 388                 ret = -1;
 389                 if (error_string) {
 390                         *error_string = php_socket_strerror(error, NULL, 0);
 391                 }
 392         }
 393         return ret;
 394 #else
 395         if (asynchronous) {
 396                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Asynchronous connect() not supported on this platform");
 397         }
 398         return (connect(sockfd, addr, addrlen) == 0) ? 0 : -1;
 399 #endif
 400 }
 401 /* }}} */
 402 
 403 /* {{{ sub_times */
 404 static inline void sub_times(struct timeval a, struct timeval b, struct timeval *result)
 405 {
 406         result->tv_usec = a.tv_usec - b.tv_usec;
 407         if (result->tv_usec < 0L) {
 408                 a.tv_sec--;
 409                 result->tv_usec += 1000000L;
 410         }
 411         result->tv_sec = a.tv_sec - b.tv_sec;
 412         if (result->tv_sec < 0L) {
 413                 result->tv_sec++;
 414                 result->tv_usec -= 1000000L;
 415         }
 416 }
 417 /* }}} */
 418 
 419 /* Bind to a local IP address.
 420  * Returns the bound socket, or -1 on failure.
 421  * */
 422 /* {{{ php_network_bind_socket_to_local_addr */
 423 php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned port,
 424                 int socktype, char **error_string, int *error_code
 425                 TSRMLS_DC)
 426 {
 427         int num_addrs, n, err = 0;
 428         php_socket_t sock;
 429         struct sockaddr **sal, **psal, *sa;
 430         socklen_t socklen;
 431 
 432         num_addrs = php_network_getaddresses(host, socktype, &psal, error_string TSRMLS_CC);
 433 
 434         if (num_addrs == 0) {
 435                 /* could not resolve address(es) */
 436                 return -1;
 437         }
 438 
 439         for (sal = psal; *sal != NULL; sal++) {
 440                 sa = *sal;
 441 
 442                 /* create a socket for this address */
 443                 sock = socket(sa->sa_family, socktype, 0);
 444 
 445                 if (sock == SOCK_ERR) {
 446                         continue;
 447                 }
 448 
 449                 switch (sa->sa_family) {
 450 #if HAVE_GETADDRINFO && HAVE_IPV6
 451                         case AF_INET6:
 452                                 ((struct sockaddr_in6 *)sa)->sin6_family = sa->sa_family;
 453                                 ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
 454                                 socklen = sizeof(struct sockaddr_in6);
 455                                 break;
 456 #endif
 457                         case AF_INET:
 458                                 ((struct sockaddr_in *)sa)->sin_family = sa->sa_family;
 459                                 ((struct sockaddr_in *)sa)->sin_port = htons(port);
 460                                 socklen = sizeof(struct sockaddr_in);
 461                                 break;
 462                         default:
 463                                 /* Unknown family */
 464                                 socklen = 0;
 465                                 sa = NULL;
 466                 }
 467 
 468                 if (sa) {
 469                         /* attempt to bind */
 470 
 471 #ifdef SO_REUSEADDR
 472                         {
 473                                 int val = 1;
 474                                 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&val, sizeof(val));
 475                         }
 476 #endif
 477 
 478                         n = bind(sock, sa, socklen);
 479 
 480                         if (n != SOCK_CONN_ERR) {
 481                                 goto bound;
 482                         }
 483 
 484                         err = php_socket_errno();
 485                 }
 486 
 487                 closesocket(sock);
 488         }
 489         sock = -1;
 490 
 491         if (error_code) {
 492                 *error_code = err;
 493         }
 494         if (error_string) {
 495                 *error_string = php_socket_strerror(err, NULL, 0);
 496         }
 497 
 498 bound:
 499 
 500         php_network_freeaddresses(psal);
 501 
 502         return sock;
 503 
 504 }
 505 /* }}} */
 506 
 507 PHPAPI int php_network_parse_network_address_with_port(const char *addr, long addrlen, struct sockaddr *sa, socklen_t *sl TSRMLS_DC)
 508 {
 509         char *colon;
 510         char *tmp;
 511         int ret = FAILURE;
 512         short port;
 513         struct sockaddr_in *in4 = (struct sockaddr_in*)sa;
 514         struct sockaddr **psal;
 515         int n;
 516         char *errstr = NULL;
 517 #if HAVE_IPV6
 518         struct sockaddr_in6 *in6 = (struct sockaddr_in6*)sa;
 519 #endif
 520 
 521         if (*addr == '[') {
 522                 colon = memchr(addr + 1, ']', addrlen-1);
 523                 if (!colon || colon[1] != ':') {
 524                         return FAILURE;
 525                 }
 526                 port = atoi(colon + 2);
 527                 addr++;
 528         } else {
 529                 colon = memchr(addr, ':', addrlen);
 530                 if (!colon) {
 531                         return FAILURE;
 532                 }
 533                 port = atoi(colon + 1);
 534         }
 535 
 536         tmp = estrndup(addr, colon - addr);
 537 
 538         /* first, try interpreting the address as a numeric address */
 539 
 540 #if HAVE_IPV6 && HAVE_INET_PTON
 541         if (inet_pton(AF_INET6, tmp, &in6->sin6_addr) > 0) {
 542                 in6->sin6_port = htons(port);
 543                 in6->sin6_family = AF_INET6;
 544                 *sl = sizeof(struct sockaddr_in6);
 545                 ret = SUCCESS;
 546                 goto out;
 547         }
 548 #endif
 549         if (inet_aton(tmp, &in4->sin_addr) > 0) {
 550                 in4->sin_port = htons(port);
 551                 in4->sin_family = AF_INET;
 552                 *sl = sizeof(struct sockaddr_in);
 553                 ret = SUCCESS;
 554                 goto out;
 555         }
 556 
 557         /* looks like we'll need to resolve it */
 558         n = php_network_getaddresses(tmp, SOCK_DGRAM, &psal, &errstr TSRMLS_CC);
 559 
 560         if (n == 0) {
 561                 if (errstr) {
 562                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to resolve `%s': %s", tmp, errstr);
 563                         STR_FREE(errstr);
 564                 }
 565                 goto out;
 566         }
 567 
 568         /* copy the details from the first item */
 569         switch ((*psal)->sa_family) {
 570 #if HAVE_GETADDRINFO && HAVE_IPV6
 571                 case AF_INET6:
 572                         *in6 = **(struct sockaddr_in6**)psal;
 573                         in6->sin6_port = htons(port);
 574                         *sl = sizeof(struct sockaddr_in6);
 575                         ret = SUCCESS;
 576                         break;
 577 #endif
 578                 case AF_INET:
 579                         *in4 = **(struct sockaddr_in**)psal;
 580                         in4->sin_port = htons(port);
 581                         *sl = sizeof(struct sockaddr_in);
 582                         ret = SUCCESS;
 583                         break;
 584         }
 585 
 586         php_network_freeaddresses(psal);
 587 
 588 out:
 589         STR_FREE(tmp);
 590         return ret;
 591 }
 592 
 593 
 594 PHPAPI void php_network_populate_name_from_sockaddr(
 595                 /* input address */
 596                 struct sockaddr *sa, socklen_t sl,
 597                 /* output readable address */
 598                 char **textaddr, long *textaddrlen,
 599                 /* output address */
 600                 struct sockaddr **addr,
 601                 socklen_t *addrlen
 602                 TSRMLS_DC)
 603 {
 604         if (addr) {
 605                 *addr = emalloc(sl);
 606                 memcpy(*addr, sa, sl);
 607                 *addrlen = sl;
 608         }
 609 
 610         if (textaddr) {
 611 #if HAVE_IPV6 && HAVE_INET_NTOP
 612                 char abuf[256];
 613 #endif
 614                 char *buf = NULL;
 615 
 616                 switch (sa->sa_family) {
 617                         case AF_INET:
 618                                 /* generally not thread safe, but it *is* thread safe under win32 */
 619                                 buf = inet_ntoa(((struct sockaddr_in*)sa)->sin_addr);
 620                                 if (buf) {
 621                                         *textaddrlen = spprintf(textaddr, 0, "%s:%d",
 622                                                 buf, ntohs(((struct sockaddr_in*)sa)->sin_port));
 623                                 }
 624 
 625                                 break;
 626 
 627 #if HAVE_IPV6 && HAVE_INET_NTOP
 628                         case AF_INET6:
 629                                 buf = (char*)inet_ntop(sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, (char *)&abuf, sizeof(abuf));
 630                                 if (buf) {
 631                                         *textaddrlen = spprintf(textaddr, 0, "%s:%d",
 632                                                 buf, ntohs(((struct sockaddr_in6*)sa)->sin6_port));
 633                                 }
 634 
 635                                 break;
 636 #endif
 637 #ifdef AF_UNIX
 638                         case AF_UNIX:
 639                                 {
 640                                         struct sockaddr_un *ua = (struct sockaddr_un*)sa;
 641 
 642                                         if (ua->sun_path[0] == '\0') {
 643                                                 /* abstract name */
 644                                                 int len = strlen(ua->sun_path + 1) + 1;
 645                                                 *textaddrlen = len;
 646                                                 *textaddr = emalloc(len + 1);
 647                                                 memcpy(*textaddr, ua->sun_path, len);
 648                                                 (*textaddr)[len] = '\0';
 649                                         } else {
 650                                                 *textaddrlen = strlen(ua->sun_path);
 651                                                 *textaddr = estrndup(ua->sun_path, *textaddrlen);
 652                                         }
 653                                 }
 654                                 break;
 655 #endif
 656 
 657                 }
 658 
 659         }
 660 }
 661 
 662 PHPAPI int php_network_get_peer_name(php_socket_t sock,
 663                 char **textaddr, long *textaddrlen,
 664                 struct sockaddr **addr,
 665                 socklen_t *addrlen
 666                 TSRMLS_DC)
 667 {
 668         php_sockaddr_storage sa;
 669         socklen_t sl = sizeof(sa);
 670         memset(&sa, 0, sizeof(sa));
 671 
 672         if (getpeername(sock, (struct sockaddr*)&sa, &sl) == 0) {
 673                 php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
 674                                 textaddr, textaddrlen,
 675                                 addr, addrlen
 676                                 TSRMLS_CC);
 677                 return 0;
 678         }
 679         return -1;
 680 }
 681 
 682 PHPAPI int php_network_get_sock_name(php_socket_t sock,
 683                 char **textaddr, long *textaddrlen,
 684                 struct sockaddr **addr,
 685                 socklen_t *addrlen
 686                 TSRMLS_DC)
 687 {
 688         php_sockaddr_storage sa;
 689         socklen_t sl = sizeof(sa);
 690         memset(&sa, 0, sizeof(sa));
 691 
 692         if (getsockname(sock, (struct sockaddr*)&sa, &sl) == 0) {
 693                 php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
 694                                 textaddr, textaddrlen,
 695                                 addr, addrlen
 696                                 TSRMLS_CC);
 697                 return 0;
 698         }
 699         return -1;
 700 
 701 }
 702 
 703 
 704 /* Accept a client connection from a server socket,
 705  * using an optional timeout.
 706  * Returns the peer address in addr/addrlen (it will emalloc
 707  * these, so be sure to efree the result).
 708  * If you specify textaddr/textaddrlen, a text-printable
 709  * version of the address will be emalloc'd and returned.
 710  * */
 711 
 712 /* {{{ php_network_accept_incoming */
 713 PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
 714                 char **textaddr, long *textaddrlen,
 715                 struct sockaddr **addr,
 716                 socklen_t *addrlen,
 717                 struct timeval *timeout,
 718                 char **error_string,
 719                 int *error_code
 720                 TSRMLS_DC)
 721 {
 722         php_socket_t clisock = -1;
 723         int error = 0, n;
 724         php_sockaddr_storage sa;
 725         socklen_t sl;
 726 
 727         n = php_pollfd_for(srvsock, PHP_POLLREADABLE, timeout);
 728 
 729         if (n == 0) {
 730                 error = PHP_TIMEOUT_ERROR_VALUE;
 731         } else if (n == -1) {
 732                 error = php_socket_errno();
 733         } else {
 734                 sl = sizeof(sa);
 735 
 736                 clisock = accept(srvsock, (struct sockaddr*)&sa, &sl);
 737 
 738                 if (clisock != SOCK_ERR) {
 739                         php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
 740                                         textaddr, textaddrlen,
 741                                         addr, addrlen
 742                                         TSRMLS_CC);
 743                 } else {
 744                         error = php_socket_errno();
 745                 }
 746         }
 747 
 748         if (error_code) {
 749                 *error_code = error;
 750         }
 751         if (error_string) {
 752                 *error_string = php_socket_strerror(error, NULL, 0);
 753         }
 754 
 755         return clisock;
 756 }
 757 /* }}} */
 758 
 759 
 760 
 761 /* Connect to a remote host using an interruptible connect with optional timeout.
 762  * Optionally, the connect can be made asynchronously, which will implicitly
 763  * enable non-blocking mode on the socket.
 764  * Returns the connected (or connecting) socket, or -1 on failure.
 765  * */
 766 
 767 /* {{{ php_network_connect_socket_to_host */
 768 php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port,
 769                 int socktype, int asynchronous, struct timeval *timeout, char **error_string,
 770                 int *error_code, char *bindto, unsigned short bindport
 771                 TSRMLS_DC)
 772 {
 773         int num_addrs, n, fatal = 0;
 774         php_socket_t sock;
 775         struct sockaddr **sal, **psal, *sa;
 776         struct timeval working_timeout;
 777         socklen_t socklen;
 778 #if HAVE_GETTIMEOFDAY
 779         struct timeval limit_time, time_now;
 780 #endif
 781 
 782         num_addrs = php_network_getaddresses(host, socktype, &psal, error_string TSRMLS_CC);
 783 
 784         if (num_addrs == 0) {
 785                 /* could not resolve address(es) */
 786                 return -1;
 787         }
 788 
 789         if (timeout) {
 790                 memcpy(&working_timeout, timeout, sizeof(working_timeout));
 791 #if HAVE_GETTIMEOFDAY
 792                 gettimeofday(&limit_time, NULL);
 793                 limit_time.tv_sec += working_timeout.tv_sec;
 794                 limit_time.tv_usec += working_timeout.tv_usec;
 795                 if (limit_time.tv_usec >= 1000000) {
 796                         limit_time.tv_usec -= 1000000;
 797                         limit_time.tv_sec++;
 798                 }
 799 #endif
 800         }
 801 
 802         for (sal = psal; !fatal && *sal != NULL; sal++) {
 803                 sa = *sal;
 804 
 805                 /* create a socket for this address */
 806                 sock = socket(sa->sa_family, socktype, 0);
 807 
 808                 if (sock == SOCK_ERR) {
 809                         continue;
 810                 }
 811 
 812                 switch (sa->sa_family) {
 813 #if HAVE_GETADDRINFO && HAVE_IPV6
 814                         case AF_INET6:
 815                                 if (!bindto || strchr(bindto, ':')) {
 816                                         ((struct sockaddr_in6 *)sa)->sin6_family = sa->sa_family;
 817                                         ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
 818                                         socklen = sizeof(struct sockaddr_in6);
 819                                 } else {
 820                                         socklen = 0;
 821                                         sa = NULL;
 822                                 }
 823                                 break;
 824 #endif
 825                         case AF_INET:
 826                                 ((struct sockaddr_in *)sa)->sin_family = sa->sa_family;
 827                                 ((struct sockaddr_in *)sa)->sin_port = htons(port);
 828                                 socklen = sizeof(struct sockaddr_in);
 829                                 break;
 830                         default:
 831                                 /* Unknown family */
 832                                 socklen = 0;
 833                                 sa = NULL;
 834                 }
 835 
 836                 if (sa) {
 837                         /* make a connection attempt */
 838 
 839                         if (bindto) {
 840                                 struct sockaddr *local_address = NULL;
 841                                 int local_address_len = 0;
 842 
 843                                 if (sa->sa_family == AF_INET) {
 844                                         struct sockaddr_in *in4 = emalloc(sizeof(struct sockaddr_in));
 845 
 846                                         local_address = (struct sockaddr*)in4;
 847                                         local_address_len = sizeof(struct sockaddr_in);
 848 
 849                                         in4->sin_family = sa->sa_family;
 850                                         in4->sin_port = htons(bindport);
 851                                         if (!inet_aton(bindto, &in4->sin_addr)) {
 852                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid IP Address: %s", bindto);
 853                                                 goto skip_bind;
 854                                         }
 855                                         memset(&(in4->sin_zero), 0, sizeof(in4->sin_zero));
 856                                 }
 857 #if HAVE_IPV6 && HAVE_INET_PTON
 858                                  else { /* IPV6 */
 859                                         struct sockaddr_in6 *in6 = emalloc(sizeof(struct sockaddr_in6));
 860 
 861                                         local_address = (struct sockaddr*)in6;
 862                                         local_address_len = sizeof(struct sockaddr_in6);
 863 
 864                                         in6->sin6_family = sa->sa_family;
 865                                         in6->sin6_port = htons(bindport);
 866                                         if (inet_pton(AF_INET6, bindto, &in6->sin6_addr) < 1) {
 867                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid IP Address: %s", bindto);
 868                                                 goto skip_bind;
 869                                         }
 870                                 }
 871 #endif
 872                                 if (!local_address || bind(sock, local_address, local_address_len)) {
 873                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to bind to '%s:%d', system said: %s", bindto, bindport, strerror(errno));
 874                                 }
 875 skip_bind:
 876                                 if (local_address) {
 877                                         efree(local_address);
 878                                 }
 879                         }
 880                         /* free error string received during previous iteration (if any) */
 881                         if (error_string && *error_string) {
 882                                 efree(*error_string);
 883                                 *error_string = NULL;
 884                         }
 885 
 886                         n = php_network_connect_socket(sock, sa, socklen, asynchronous,
 887                                         timeout ? &working_timeout : NULL,
 888                                         error_string, error_code);
 889 
 890                         if (n != -1) {
 891                                 goto connected;
 892                         }
 893 
 894                         /* adjust timeout for next attempt */
 895 #if HAVE_GETTIMEOFDAY
 896                         if (timeout) {
 897                                 gettimeofday(&time_now, NULL);
 898 
 899                                 if (timercmp(&time_now, &limit_time, >=)) {
 900                                         /* time limit expired; don't attempt any further connections */
 901                                         fatal = 1;
 902                                 } else {
 903                                         /* work out remaining time */
 904                                         sub_times(limit_time, time_now, &working_timeout);
 905                                 }
 906                         }
 907 #else
 908                         if (error_code && *error_code == PHP_TIMEOUT_ERROR_VALUE) {
 909                                 /* Don't even bother trying to connect to the next alternative;
 910                                  * we have no way to determine how long we have already taken
 911                                  * and it is quite likely that the next attempt will fail too. */
 912                                 fatal = 1;
 913                         } else {
 914                                 /* re-use the same initial timeout.
 915                                  * Not the best thing, but in practice it should be good-enough */
 916                                 if (timeout) {
 917                                         memcpy(&working_timeout, timeout, sizeof(working_timeout));
 918                                 }
 919                         }
 920 #endif
 921                 }
 922 
 923                 closesocket(sock);
 924         }
 925         sock = -1;
 926 
 927 connected:
 928 
 929         php_network_freeaddresses(psal);
 930 
 931         return sock;
 932 }
 933 /* }}} */
 934 
 935 /* {{{ php_any_addr
 936  * Fills the any (wildcard) address into php_sockaddr_storage
 937  */
 938 PHPAPI void php_any_addr(int family, php_sockaddr_storage *addr, unsigned short port)
 939 {
 940         memset(addr, 0, sizeof(php_sockaddr_storage));
 941         switch (family) {
 942 #if HAVE_IPV6
 943         case AF_INET6: {
 944                 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr;
 945                 sin6->sin6_family = AF_INET6;
 946                 sin6->sin6_port = htons(port);
 947                 sin6->sin6_addr = in6addr_any;
 948                 break;
 949         }
 950 #endif
 951         case AF_INET: {
 952                 struct sockaddr_in *sin = (struct sockaddr_in *) addr;
 953                 sin->sin_family = AF_INET;
 954                 sin->sin_port = htons(port);
 955                 sin->sin_addr.s_addr = htonl(INADDR_ANY);
 956                 break;
 957         }
 958         }
 959 }
 960 /* }}} */
 961 
 962 /* {{{ php_sockaddr_size
 963  * Returns the size of struct sockaddr_xx for the family
 964  */
 965 PHPAPI int php_sockaddr_size(php_sockaddr_storage *addr)
 966 {
 967         switch (((struct sockaddr *)addr)->sa_family) {
 968         case AF_INET:
 969                 return sizeof(struct sockaddr_in);
 970 #if HAVE_IPV6
 971         case AF_INET6:
 972                 return sizeof(struct sockaddr_in6);
 973 #endif
 974 #ifdef AF_UNIX
 975         case AF_UNIX:
 976                 return sizeof(struct sockaddr_un);
 977 #endif
 978         default:
 979                 return 0;
 980         }
 981 }
 982 /* }}} */
 983 
 984 /* Given a socket error code, if buf == NULL:
 985  *   emallocs storage for the error message and returns
 986  * else
 987  *   sprintf message into provided buffer and returns buf
 988  */
 989 /* {{{ php_socket_strerror */
 990 PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize)
 991 {
 992 #ifndef PHP_WIN32
 993         char *errstr;
 994 
 995         errstr = strerror(err);
 996         if (buf == NULL) {
 997                 buf = estrdup(errstr);
 998         } else {
 999                 strncpy(buf, errstr, bufsize);
1000                 buf[bufsize?(bufsize-1):0] = 0;
1001         }
1002         return buf;
1003 #else
1004         char *sysbuf;
1005         int free_it = 1;
1006 
1007         if (!FormatMessage(
1008                                 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1009                                 FORMAT_MESSAGE_FROM_SYSTEM |
1010                                 FORMAT_MESSAGE_IGNORE_INSERTS,
1011                                 NULL,
1012                                 err,
1013                                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1014                                 (LPTSTR)&sysbuf,
1015                                 0,
1016                                 NULL)) {
1017                 free_it = 0;
1018                 sysbuf = "Unknown Error";
1019         }
1020 
1021         if (buf == NULL) {
1022                 buf = estrdup(sysbuf);
1023         } else {
1024                 strncpy(buf, sysbuf, bufsize);
1025                 buf[bufsize?(bufsize-1):0] = 0;
1026         }
1027 
1028         if (free_it) {
1029                 LocalFree(sysbuf);
1030         }
1031 
1032         return buf;
1033 #endif
1034 }
1035 /* }}} */
1036 
1037 /* deprecated */
1038 PHPAPI php_stream *_php_stream_sock_open_from_socket(php_socket_t socket, const char *persistent_id STREAMS_DC TSRMLS_DC)
1039 {
1040         php_stream *stream;
1041         php_netstream_data_t *sock;
1042 
1043         sock = pemalloc(sizeof(php_netstream_data_t), persistent_id ? 1 : 0);
1044         memset(sock, 0, sizeof(php_netstream_data_t));
1045 
1046         sock->is_blocked = 1;
1047         sock->timeout.tv_sec = FG(default_socket_timeout);
1048         sock->timeout.tv_usec = 0;
1049         sock->socket = socket;
1050 
1051         stream = php_stream_alloc_rel(&php_stream_generic_socket_ops, sock, persistent_id, "r+");
1052 
1053         if (stream == NULL) {
1054                 pefree(sock, persistent_id ? 1 : 0);
1055         } else {
1056                 stream->flags |= PHP_STREAM_FLAG_AVOID_BLOCKING;
1057         }
1058 
1059         return stream;
1060 }
1061 
1062 PHPAPI php_stream *_php_stream_sock_open_host(const char *host, unsigned short port,
1063                 int socktype, struct timeval *timeout, const char *persistent_id STREAMS_DC TSRMLS_DC)
1064 {
1065         char *res;
1066         long reslen;
1067         php_stream *stream;
1068 
1069         reslen = spprintf(&res, 0, "tcp://%s:%d", host, port);
1070 
1071         stream = php_stream_xport_create(res, reslen, REPORT_ERRORS,
1072                         STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, persistent_id, timeout, NULL, NULL, NULL);
1073 
1074         efree(res);
1075 
1076         return stream;
1077 }
1078 
1079 PHPAPI int php_set_sock_blocking(int socketd, int block TSRMLS_DC)
1080 {
1081         int ret = SUCCESS;
1082         int flags;
1083         int myflag = 0;
1084 
1085 #ifdef PHP_WIN32
1086         /* with ioctlsocket, a non-zero sets nonblocking, a zero sets blocking */
1087         flags = !block;
1088         if (ioctlsocket(socketd, FIONBIO, &flags) == SOCKET_ERROR) {
1089                 ret = FAILURE;
1090         }
1091 #else
1092         flags = fcntl(socketd, F_GETFL);
1093 #ifdef O_NONBLOCK
1094         myflag = O_NONBLOCK; /* POSIX version */
1095 #elif defined(O_NDELAY)
1096         myflag = O_NDELAY;   /* old non-POSIX version */
1097 #endif
1098         if (!block) {
1099                 flags |= myflag;
1100         } else {
1101                 flags &= ~myflag;
1102         }
1103         if (fcntl(socketd, F_SETFL, flags) == -1) {
1104                 ret = FAILURE;
1105         }
1106 #endif
1107         return ret;
1108 }
1109 
1110 PHPAPI void _php_emit_fd_setsize_warning(int max_fd)
1111 {
1112         TSRMLS_FETCH();
1113 
1114 #ifdef PHP_WIN32
1115         php_error_docref(NULL TSRMLS_CC, E_WARNING,
1116                 "PHP needs to be recompiled with a larger value of FD_SETSIZE.\n"
1117                 "If this binary is from an official www.php.net package, file a bug report\n"
1118                 "at http://bugs.php.net, including the following information:\n"
1119                 "FD_SETSIZE=%d, but you are using %d.\n"
1120                 " --enable-fd-setsize=%d is recommended, but you may want to set it\n"
1121                 "to match to maximum number of sockets each script will work with at\n"
1122                 "one time, in order to avoid seeing this error again at a later date.",
1123                 FD_SETSIZE, max_fd, (max_fd + 128) & ~127);
1124 #else
1125         php_error_docref(NULL TSRMLS_CC, E_WARNING,
1126                 "You MUST recompile PHP with a larger value of FD_SETSIZE.\n"
1127                 "It is set to %d, but you have descriptors numbered at least as high as %d.\n"
1128                 " --enable-fd-setsize=%d is recommended, but you may want to set it\n"
1129                 "to equal the maximum number of open files supported by your system,\n"
1130                 "in order to avoid seeing this error again at a later date.",
1131                 FD_SETSIZE, max_fd, (max_fd + 1024) & ~1023);
1132 #endif
1133 }
1134 
1135 #if defined(PHP_USE_POLL_2_EMULATION)
1136 
1137 /* emulate poll(2) using select(2), safely. */
1138 
1139 PHPAPI int php_poll2(php_pollfd *ufds, unsigned int nfds, int timeout)
1140 {
1141         fd_set rset, wset, eset;
1142         php_socket_t max_fd = SOCK_ERR;
1143         unsigned int i;
1144         int n;
1145         struct timeval tv;
1146 
1147         /* check the highest numbered descriptor */
1148         for (i = 0; i < nfds; i++) {
1149                 if (ufds[i].fd > max_fd)
1150                         max_fd = ufds[i].fd;
1151         }
1152 
1153         PHP_SAFE_MAX_FD(max_fd, nfds + 1);
1154 
1155         FD_ZERO(&rset);
1156         FD_ZERO(&wset);
1157         FD_ZERO(&eset);
1158 
1159         for (i = 0; i < nfds; i++) {
1160                 if (ufds[i].events & PHP_POLLREADABLE) {
1161                         PHP_SAFE_FD_SET(ufds[i].fd, &rset);
1162                 }
1163                 if (ufds[i].events & POLLOUT) {
1164                         PHP_SAFE_FD_SET(ufds[i].fd, &wset);
1165                 }
1166                 if (ufds[i].events & POLLPRI) {
1167                         PHP_SAFE_FD_SET(ufds[i].fd, &eset);
1168                 }
1169         }
1170 
1171         if (timeout >= 0) {
1172                 tv.tv_sec = timeout / 1000;
1173                 tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000;
1174         }
1175 /* Reseting/initializing */
1176 #ifdef PHP_WIN32
1177         WSASetLastError(0);
1178 #else
1179         errno = 0;
1180 #endif
1181         n = select(max_fd + 1, &rset, &wset, &eset, timeout >= 0 ? &tv : NULL);
1182 
1183         if (n >= 0) {
1184                 for (i = 0; i < nfds; i++) {
1185                         ufds[i].revents = 0;
1186 
1187                         if (PHP_SAFE_FD_ISSET(ufds[i].fd, &rset)) {
1188                                 /* could be POLLERR or POLLHUP but can't tell without probing */
1189                                 ufds[i].revents |= POLLIN;
1190                         }
1191                         if (PHP_SAFE_FD_ISSET(ufds[i].fd, &wset)) {
1192                                 ufds[i].revents |= POLLOUT;
1193                         }
1194                         if (PHP_SAFE_FD_ISSET(ufds[i].fd, &eset)) {
1195                                 ufds[i].revents |= POLLPRI;
1196                         }
1197                 }
1198         }
1199         return n;
1200 }
1201 
1202 #endif
1203 
1204 
1205 /*
1206  * Local variables:
1207  * tab-width: 8
1208  * c-basic-offset: 8
1209  * End:
1210  * vim600: sw=4 ts=4 fdm=marker
1211  * vim<600: sw=4 ts=4
1212  */

/* [<][>][^][v][top][bottom][index][help] */