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_socket_error_str
  17. _php_stream_sock_open_from_socket
  18. _php_stream_sock_open_host
  19. php_set_sock_blocking
  20. _php_emit_fd_setsize_warning
  21. php_poll2

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   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, zend_string **error_string)
 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                         *error_string = strpprintf(0, "php_network_getaddresses: getaddrinfo failed: %s", PHP_GAI_STRERROR(n));
 216                         php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(*error_string));
 217                 } else {
 218                         php_error_docref(NULL, 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                         *error_string = strpprintf(0, "php_network_getaddresses: getaddrinfo failed (null result pointer) errno=%d", errno);
 224                         php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(*error_string));
 225                 } else {
 226                         php_error_docref(NULL, 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                                 error_string = strpprintf(0, "php_network_getaddresses: gethostbyname failed. errno=%d", errno);
 258                                 php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(*error_string));
 259                         } else {
 260                                 php_error_docref(NULL, 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                 zend_string **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_error_str(error);
 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_error_str(error);
 391                 }
 392         }
 393         return ret;
 394 #else
 395         if (asynchronous) {
 396                 php_error_docref(NULL, 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, long sockopts, zend_string **error_string, int *error_code
 425                 )
 426 {
 427         int num_addrs, n, err = 0;
 428         php_socket_t sock;
 429         struct sockaddr **sal, **psal, *sa;
 430         socklen_t socklen;
 431         int sockoptval = 1;
 432 
 433         num_addrs = php_network_getaddresses(host, socktype, &psal, error_string);
 434 
 435         if (num_addrs == 0) {
 436                 /* could not resolve address(es) */
 437                 return -1;
 438         }
 439 
 440         for (sal = psal; *sal != NULL; sal++) {
 441                 sa = *sal;
 442 
 443                 /* create a socket for this address */
 444                 sock = socket(sa->sa_family, socktype, 0);
 445 
 446                 if (sock == SOCK_ERR) {
 447                         continue;
 448                 }
 449 
 450                 switch (sa->sa_family) {
 451 #if HAVE_GETADDRINFO && HAVE_IPV6
 452                         case AF_INET6:
 453                                 ((struct sockaddr_in6 *)sa)->sin6_family = sa->sa_family;
 454                                 ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
 455                                 socklen = sizeof(struct sockaddr_in6);
 456                                 break;
 457 #endif
 458                         case AF_INET:
 459                                 ((struct sockaddr_in *)sa)->sin_family = sa->sa_family;
 460                                 ((struct sockaddr_in *)sa)->sin_port = htons(port);
 461                                 socklen = sizeof(struct sockaddr_in);
 462                                 break;
 463                         default:
 464                                 /* Unknown family */
 465                                 socklen = 0;
 466                                 sa = NULL;
 467                 }
 468 
 469                 if (sa) {
 470                         /* attempt to bind */
 471 
 472 #ifdef SO_REUSEADDR
 473                         setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&sockoptval, sizeof(sockoptval));
 474 #endif
 475 #ifdef IPV6_V6ONLY
 476                         if (sockopts & STREAM_SOCKOP_IPV6_V6ONLY) {
 477                                 int ipv6_val = !!(sockopts & STREAM_SOCKOP_IPV6_V6ONLY_ENABLED);
 478                                 setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6_val, sizeof(sockoptval));
 479                         }
 480 #endif
 481 #ifdef SO_REUSEPORT
 482                         if (sockopts & STREAM_SOCKOP_SO_REUSEPORT) {
 483                                 setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char*)&sockoptval, sizeof(sockoptval));
 484                         }
 485 #endif
 486 #ifdef SO_BROADCAST
 487                         if (sockopts & STREAM_SOCKOP_SO_BROADCAST) {
 488                                 setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&sockoptval, sizeof(sockoptval));
 489                         }
 490 #endif
 491 
 492                         n = bind(sock, sa, socklen);
 493 
 494                         if (n != SOCK_CONN_ERR) {
 495                                 goto bound;
 496                         }
 497 
 498                         err = php_socket_errno();
 499                 }
 500 
 501                 closesocket(sock);
 502         }
 503         sock = -1;
 504 
 505         if (error_code) {
 506                 *error_code = err;
 507         }
 508         if (error_string) {
 509                 *error_string = php_socket_error_str(err);
 510         }
 511 
 512 bound:
 513 
 514         php_network_freeaddresses(psal);
 515 
 516         return sock;
 517 
 518 }
 519 /* }}} */
 520 
 521 PHPAPI int php_network_parse_network_address_with_port(const char *addr, zend_long addrlen, struct sockaddr *sa, socklen_t *sl)
 522 {
 523         char *colon;
 524         char *tmp;
 525         int ret = FAILURE;
 526         short port;
 527         struct sockaddr_in *in4 = (struct sockaddr_in*)sa;
 528         struct sockaddr **psal;
 529         int n;
 530         zend_string *errstr = NULL;
 531 #if HAVE_IPV6
 532         struct sockaddr_in6 *in6 = (struct sockaddr_in6*)sa;
 533 #endif
 534 
 535         if (*addr == '[') {
 536                 colon = memchr(addr + 1, ']', addrlen-1);
 537                 if (!colon || colon[1] != ':') {
 538                         return FAILURE;
 539                 }
 540                 port = atoi(colon + 2);
 541                 addr++;
 542         } else {
 543                 colon = memchr(addr, ':', addrlen);
 544                 if (!colon) {
 545                         return FAILURE;
 546                 }
 547                 port = atoi(colon + 1);
 548         }
 549 
 550         tmp = estrndup(addr, colon - addr);
 551 
 552         /* first, try interpreting the address as a numeric address */
 553 
 554 #if HAVE_IPV6 && HAVE_INET_PTON
 555         if (inet_pton(AF_INET6, tmp, &in6->sin6_addr) > 0) {
 556                 in6->sin6_port = htons(port);
 557                 in6->sin6_family = AF_INET6;
 558                 *sl = sizeof(struct sockaddr_in6);
 559                 ret = SUCCESS;
 560                 goto out;
 561         }
 562 #endif
 563         if (inet_aton(tmp, &in4->sin_addr) > 0) {
 564                 in4->sin_port = htons(port);
 565                 in4->sin_family = AF_INET;
 566                 *sl = sizeof(struct sockaddr_in);
 567                 ret = SUCCESS;
 568                 goto out;
 569         }
 570 
 571         /* looks like we'll need to resolve it */
 572         n = php_network_getaddresses(tmp, SOCK_DGRAM, &psal, &errstr);
 573 
 574         if (n == 0) {
 575                 if (errstr) {
 576                         php_error_docref(NULL, E_WARNING, "Failed to resolve `%s': %s", tmp, ZSTR_VAL(errstr));
 577                         zend_string_release(errstr);
 578                 }
 579                 goto out;
 580         }
 581 
 582         /* copy the details from the first item */
 583         switch ((*psal)->sa_family) {
 584 #if HAVE_GETADDRINFO && HAVE_IPV6
 585                 case AF_INET6:
 586                         *in6 = **(struct sockaddr_in6**)psal;
 587                         in6->sin6_port = htons(port);
 588                         *sl = sizeof(struct sockaddr_in6);
 589                         ret = SUCCESS;
 590                         break;
 591 #endif
 592                 case AF_INET:
 593                         *in4 = **(struct sockaddr_in**)psal;
 594                         in4->sin_port = htons(port);
 595                         *sl = sizeof(struct sockaddr_in);
 596                         ret = SUCCESS;
 597                         break;
 598         }
 599 
 600         php_network_freeaddresses(psal);
 601 
 602 out:
 603         efree(tmp);
 604         return ret;
 605 }
 606 
 607 
 608 PHPAPI void php_network_populate_name_from_sockaddr(
 609                 /* input address */
 610                 struct sockaddr *sa, socklen_t sl,
 611                 /* output readable address */
 612                 zend_string **textaddr,
 613                 /* output address */
 614                 struct sockaddr **addr,
 615                 socklen_t *addrlen
 616                 )
 617 {
 618         if (addr) {
 619                 *addr = emalloc(sl);
 620                 memcpy(*addr, sa, sl);
 621                 *addrlen = sl;
 622         }
 623 
 624         if (textaddr) {
 625 #if HAVE_IPV6 && HAVE_INET_NTOP
 626                 char abuf[256];
 627 #endif
 628                 char *buf = NULL;
 629 
 630                 switch (sa->sa_family) {
 631                         case AF_INET:
 632                                 /* generally not thread safe, but it *is* thread safe under win32 */
 633                                 buf = inet_ntoa(((struct sockaddr_in*)sa)->sin_addr);
 634                                 if (buf) {
 635                                         *textaddr = strpprintf(0, "%s:%d",
 636                                                 buf, ntohs(((struct sockaddr_in*)sa)->sin_port));
 637                                 }
 638 
 639                                 break;
 640 
 641 #if HAVE_IPV6 && HAVE_INET_NTOP
 642                         case AF_INET6:
 643                                 buf = (char*)inet_ntop(sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, (char *)&abuf, sizeof(abuf));
 644                                 if (buf) {
 645                                         *textaddr = strpprintf(0, "%s:%d",
 646                                                 buf, ntohs(((struct sockaddr_in6*)sa)->sin6_port));
 647                                 }
 648 
 649                                 break;
 650 #endif
 651 #ifdef AF_UNIX
 652                         case AF_UNIX:
 653                                 {
 654                                         struct sockaddr_un *ua = (struct sockaddr_un*)sa;
 655 
 656                                         if (ua->sun_path[0] == '\0') {
 657                                                 /* abstract name */
 658                                                 int len = strlen(ua->sun_path + 1) + 1;
 659                                                 *textaddr = zend_string_init((char*)ua->sun_path, len, 0);
 660                                         } else {
 661                                                 int len = strlen(ua->sun_path);
 662                                                 *textaddr = zend_string_init((char*)ua->sun_path, len, 0);
 663                                         }
 664                                 }
 665                                 break;
 666 #endif
 667 
 668                 }
 669 
 670         }
 671 }
 672 
 673 PHPAPI int php_network_get_peer_name(php_socket_t sock,
 674                 zend_string **textaddr,
 675                 struct sockaddr **addr,
 676                 socklen_t *addrlen
 677                 )
 678 {
 679         php_sockaddr_storage sa;
 680         socklen_t sl = sizeof(sa);
 681         memset(&sa, 0, sizeof(sa));
 682 
 683         if (getpeername(sock, (struct sockaddr*)&sa, &sl) == 0) {
 684                 php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
 685                                 textaddr,
 686                                 addr, addrlen
 687                                 );
 688                 return 0;
 689         }
 690         return -1;
 691 }
 692 
 693 PHPAPI int php_network_get_sock_name(php_socket_t sock,
 694                 zend_string **textaddr,
 695                 struct sockaddr **addr,
 696                 socklen_t *addrlen
 697                 )
 698 {
 699         php_sockaddr_storage sa;
 700         socklen_t sl = sizeof(sa);
 701         memset(&sa, 0, sizeof(sa));
 702 
 703         if (getsockname(sock, (struct sockaddr*)&sa, &sl) == 0) {
 704                 php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
 705                                 textaddr,
 706                                 addr, addrlen
 707                                 );
 708                 return 0;
 709         }
 710         return -1;
 711 
 712 }
 713 
 714 
 715 /* Accept a client connection from a server socket,
 716  * using an optional timeout.
 717  * Returns the peer address in addr/addrlen (it will emalloc
 718  * these, so be sure to efree the result).
 719  * If you specify textaddr, a text-printable
 720  * version of the address will be emalloc'd and returned.
 721  * */
 722 
 723 /* {{{ php_network_accept_incoming */
 724 PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
 725                 zend_string **textaddr,
 726                 struct sockaddr **addr,
 727                 socklen_t *addrlen,
 728                 struct timeval *timeout,
 729                 zend_string **error_string,
 730                 int *error_code
 731                 )
 732 {
 733         php_socket_t clisock = -1;
 734         int error = 0, n;
 735         php_sockaddr_storage sa;
 736         socklen_t sl;
 737 
 738         n = php_pollfd_for(srvsock, PHP_POLLREADABLE, timeout);
 739 
 740         if (n == 0) {
 741                 error = PHP_TIMEOUT_ERROR_VALUE;
 742         } else if (n == -1) {
 743                 error = php_socket_errno();
 744         } else {
 745                 sl = sizeof(sa);
 746 
 747                 clisock = accept(srvsock, (struct sockaddr*)&sa, &sl);
 748 
 749                 if (clisock != SOCK_ERR) {
 750                         php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
 751                                         textaddr,
 752                                         addr, addrlen
 753                                         );
 754                 } else {
 755                         error = php_socket_errno();
 756                 }
 757         }
 758 
 759         if (error_code) {
 760                 *error_code = error;
 761         }
 762         if (error_string) {
 763                 *error_string = php_socket_error_str(error);
 764         }
 765 
 766         return clisock;
 767 }
 768 /* }}} */
 769 
 770 
 771 
 772 /* Connect to a remote host using an interruptible connect with optional timeout.
 773  * Optionally, the connect can be made asynchronously, which will implicitly
 774  * enable non-blocking mode on the socket.
 775  * Returns the connected (or connecting) socket, or -1 on failure.
 776  * */
 777 
 778 /* {{{ php_network_connect_socket_to_host */
 779 php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port,
 780                 int socktype, int asynchronous, struct timeval *timeout, zend_string **error_string,
 781                 int *error_code, char *bindto, unsigned short bindport, long sockopts
 782                 )
 783 {
 784         int num_addrs, n, fatal = 0;
 785         php_socket_t sock;
 786         struct sockaddr **sal, **psal, *sa;
 787         struct timeval working_timeout;
 788         socklen_t socklen;
 789 #if HAVE_GETTIMEOFDAY
 790         struct timeval limit_time, time_now;
 791 #endif
 792 
 793         num_addrs = php_network_getaddresses(host, socktype, &psal, error_string);
 794 
 795         if (num_addrs == 0) {
 796                 /* could not resolve address(es) */
 797                 return -1;
 798         }
 799 
 800         if (timeout) {
 801                 memcpy(&working_timeout, timeout, sizeof(working_timeout));
 802 #if HAVE_GETTIMEOFDAY
 803                 gettimeofday(&limit_time, NULL);
 804                 limit_time.tv_sec += working_timeout.tv_sec;
 805                 limit_time.tv_usec += working_timeout.tv_usec;
 806                 if (limit_time.tv_usec >= 1000000) {
 807                         limit_time.tv_usec -= 1000000;
 808                         limit_time.tv_sec++;
 809                 }
 810 #endif
 811         }
 812 
 813         for (sal = psal; !fatal && *sal != NULL; sal++) {
 814                 sa = *sal;
 815 
 816                 /* create a socket for this address */
 817                 sock = socket(sa->sa_family, socktype, 0);
 818 
 819                 if (sock == SOCK_ERR) {
 820                         continue;
 821                 }
 822 
 823                 switch (sa->sa_family) {
 824 #if HAVE_GETADDRINFO && HAVE_IPV6
 825                         case AF_INET6:
 826                                 if (!bindto || strchr(bindto, ':')) {
 827                                         ((struct sockaddr_in6 *)sa)->sin6_family = sa->sa_family;
 828                                         ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
 829                                         socklen = sizeof(struct sockaddr_in6);
 830                                 } else {
 831                                         socklen = 0;
 832                                         sa = NULL;
 833                                 }
 834                                 break;
 835 #endif
 836                         case AF_INET:
 837                                 ((struct sockaddr_in *)sa)->sin_family = sa->sa_family;
 838                                 ((struct sockaddr_in *)sa)->sin_port = htons(port);
 839                                 socklen = sizeof(struct sockaddr_in);
 840                                 break;
 841                         default:
 842                                 /* Unknown family */
 843                                 socklen = 0;
 844                                 sa = NULL;
 845                 }
 846 
 847                 if (sa) {
 848                         /* make a connection attempt */
 849 
 850                         if (bindto) {
 851                                 struct sockaddr *local_address = NULL;
 852                                 int local_address_len = 0;
 853 
 854                                 if (sa->sa_family == AF_INET) {
 855                                         struct sockaddr_in *in4 = emalloc(sizeof(struct sockaddr_in));
 856 
 857                                         local_address = (struct sockaddr*)in4;
 858                                         local_address_len = sizeof(struct sockaddr_in);
 859 
 860                                         in4->sin_family = sa->sa_family;
 861                                         in4->sin_port = htons(bindport);
 862                                         if (!inet_aton(bindto, &in4->sin_addr)) {
 863                                                 php_error_docref(NULL, E_WARNING, "Invalid IP Address: %s", bindto);
 864                                                 goto skip_bind;
 865                                         }
 866                                         memset(&(in4->sin_zero), 0, sizeof(in4->sin_zero));
 867                                 }
 868 #if HAVE_IPV6 && HAVE_INET_PTON
 869                                  else { /* IPV6 */
 870                                         struct sockaddr_in6 *in6 = emalloc(sizeof(struct sockaddr_in6));
 871 
 872                                         local_address = (struct sockaddr*)in6;
 873                                         local_address_len = sizeof(struct sockaddr_in6);
 874 
 875                                         in6->sin6_family = sa->sa_family;
 876                                         in6->sin6_port = htons(bindport);
 877                                         if (inet_pton(AF_INET6, bindto, &in6->sin6_addr) < 1) {
 878                                                 php_error_docref(NULL, E_WARNING, "Invalid IP Address: %s", bindto);
 879                                                 goto skip_bind;
 880                                         }
 881                                 }
 882 #endif
 883 
 884                                 if (!local_address || bind(sock, local_address, local_address_len)) {
 885                                         php_error_docref(NULL, E_WARNING, "failed to bind to '%s:%d', system said: %s", bindto, bindport, strerror(errno));
 886                                 }
 887 skip_bind:
 888                                 if (local_address) {
 889                                         efree(local_address);
 890                                 }
 891                         }
 892                         /* free error string received during previous iteration (if any) */
 893                         if (error_string && *error_string) {
 894                                 zend_string_release(*error_string);
 895                                 *error_string = NULL;
 896                         }
 897 
 898 #ifdef SO_BROADCAST
 899                         {
 900                                 int val = 1;
 901                                 if (sockopts & STREAM_SOCKOP_SO_BROADCAST) {
 902                                         setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&val, sizeof(val));
 903                                 }
 904                         }
 905 #endif
 906                         n = php_network_connect_socket(sock, sa, socklen, asynchronous,
 907                                         timeout ? &working_timeout : NULL,
 908                                         error_string, error_code);
 909 
 910                         if (n != -1) {
 911                                 goto connected;
 912                         }
 913 
 914                         /* adjust timeout for next attempt */
 915 #if HAVE_GETTIMEOFDAY
 916                         if (timeout) {
 917                                 gettimeofday(&time_now, NULL);
 918 
 919                                 if (timercmp(&time_now, &limit_time, >=)) {
 920                                         /* time limit expired; don't attempt any further connections */
 921                                         fatal = 1;
 922                                 } else {
 923                                         /* work out remaining time */
 924                                         sub_times(limit_time, time_now, &working_timeout);
 925                                 }
 926                         }
 927 #else
 928                         if (error_code && *error_code == PHP_TIMEOUT_ERROR_VALUE) {
 929                                 /* Don't even bother trying to connect to the next alternative;
 930                                  * we have no way to determine how long we have already taken
 931                                  * and it is quite likely that the next attempt will fail too. */
 932                                 fatal = 1;
 933                         } else {
 934                                 /* re-use the same initial timeout.
 935                                  * Not the best thing, but in practice it should be good-enough */
 936                                 if (timeout) {
 937                                         memcpy(&working_timeout, timeout, sizeof(working_timeout));
 938                                 }
 939                         }
 940 #endif
 941                 }
 942 
 943                 closesocket(sock);
 944         }
 945         sock = -1;
 946 
 947 connected:
 948 
 949         php_network_freeaddresses(psal);
 950 
 951         return sock;
 952 }
 953 /* }}} */
 954 
 955 /* {{{ php_any_addr
 956  * Fills the any (wildcard) address into php_sockaddr_storage
 957  */
 958 PHPAPI void php_any_addr(int family, php_sockaddr_storage *addr, unsigned short port)
 959 {
 960         memset(addr, 0, sizeof(php_sockaddr_storage));
 961         switch (family) {
 962 #if HAVE_IPV6
 963         case AF_INET6: {
 964                 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr;
 965                 sin6->sin6_family = AF_INET6;
 966                 sin6->sin6_port = htons(port);
 967                 sin6->sin6_addr = in6addr_any;
 968                 break;
 969         }
 970 #endif
 971         case AF_INET: {
 972                 struct sockaddr_in *sin = (struct sockaddr_in *) addr;
 973                 sin->sin_family = AF_INET;
 974                 sin->sin_port = htons(port);
 975                 sin->sin_addr.s_addr = htonl(INADDR_ANY);
 976                 break;
 977         }
 978         }
 979 }
 980 /* }}} */
 981 
 982 /* {{{ php_sockaddr_size
 983  * Returns the size of struct sockaddr_xx for the family
 984  */
 985 PHPAPI int php_sockaddr_size(php_sockaddr_storage *addr)
 986 {
 987         switch (((struct sockaddr *)addr)->sa_family) {
 988         case AF_INET:
 989                 return sizeof(struct sockaddr_in);
 990 #if HAVE_IPV6
 991         case AF_INET6:
 992                 return sizeof(struct sockaddr_in6);
 993 #endif
 994 #ifdef AF_UNIX
 995         case AF_UNIX:
 996                 return sizeof(struct sockaddr_un);
 997 #endif
 998         default:
 999                 return 0;
1000         }
1001 }
1002 /* }}} */
1003 
1004 /* Given a socket error code, if buf == NULL:
1005  *   emallocs storage for the error message and returns
1006  * else
1007  *   sprintf message into provided buffer and returns buf
1008  */
1009 /* {{{ php_socket_strerror */
1010 PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize)
1011 {
1012 #ifndef PHP_WIN32
1013         char *errstr;
1014 
1015         errstr = strerror(err);
1016         if (buf == NULL) {
1017                 buf = estrdup(errstr);
1018         } else {
1019                 strncpy(buf, errstr, bufsize);
1020                 buf[bufsize?(bufsize-1):0] = 0;
1021         }
1022         return buf;
1023 #else
1024         char *sysbuf;
1025         int free_it = 1;
1026 
1027         if (!FormatMessage(
1028                                 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1029                                 FORMAT_MESSAGE_FROM_SYSTEM |
1030                                 FORMAT_MESSAGE_IGNORE_INSERTS,
1031                                 NULL,
1032                                 err,
1033                                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1034                                 (LPTSTR)&sysbuf,
1035                                 0,
1036                                 NULL)) {
1037                 free_it = 0;
1038                 sysbuf = "Unknown Error";
1039         }
1040 
1041         if (buf == NULL) {
1042                 buf = estrdup(sysbuf);
1043         } else {
1044                 strncpy(buf, sysbuf, bufsize);
1045                 buf[bufsize?(bufsize-1):0] = 0;
1046         }
1047 
1048         if (free_it) {
1049                 LocalFree(sysbuf);
1050         }
1051 
1052         return buf;
1053 #endif
1054 }
1055 /* }}} */
1056 
1057 /* {{{ php_socket_error_str */
1058 PHPAPI zend_string *php_socket_error_str(long err)
1059 {
1060 #ifndef PHP_WIN32
1061         char *errstr;
1062 
1063         errstr = strerror(err);
1064         return zend_string_init(errstr, strlen(errstr), 0);
1065 #else
1066         zend_string *ret;
1067         char *sysbuf;
1068         int free_it = 1;
1069 
1070         if (!FormatMessage(
1071                                 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1072                                 FORMAT_MESSAGE_FROM_SYSTEM |
1073                                 FORMAT_MESSAGE_IGNORE_INSERTS,
1074                                 NULL,
1075                                 err,
1076                                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1077                                 (LPTSTR)&sysbuf,
1078                                 0,
1079                                 NULL)) {
1080                 free_it = 0;
1081                 sysbuf = "Unknown Error";
1082         }
1083 
1084         ret = zend_string_init(sysbuf, strlen(sysbuf), 0);
1085 
1086         if (free_it) {
1087                 LocalFree(sysbuf);
1088         }
1089 
1090         return ret;
1091 #endif
1092 }
1093 /* }}} */
1094 
1095 /* deprecated */
1096 PHPAPI php_stream *_php_stream_sock_open_from_socket(php_socket_t socket, const char *persistent_id STREAMS_DC)
1097 {
1098         php_stream *stream;
1099         php_netstream_data_t *sock;
1100 
1101         sock = pemalloc(sizeof(php_netstream_data_t), persistent_id ? 1 : 0);
1102         memset(sock, 0, sizeof(php_netstream_data_t));
1103 
1104         sock->is_blocked = 1;
1105         sock->timeout.tv_sec = FG(default_socket_timeout);
1106         sock->timeout.tv_usec = 0;
1107         sock->socket = socket;
1108 
1109         stream = php_stream_alloc_rel(&php_stream_generic_socket_ops, sock, persistent_id, "r+");
1110 
1111         if (stream == NULL) {
1112                 pefree(sock, persistent_id ? 1 : 0);
1113         } else {
1114                 stream->flags |= PHP_STREAM_FLAG_AVOID_BLOCKING;
1115         }
1116 
1117         return stream;
1118 }
1119 
1120 PHPAPI php_stream *_php_stream_sock_open_host(const char *host, unsigned short port,
1121                 int socktype, struct timeval *timeout, const char *persistent_id STREAMS_DC)
1122 {
1123         char *res;
1124         zend_long reslen;
1125         php_stream *stream;
1126 
1127         reslen = spprintf(&res, 0, "tcp://%s:%d", host, port);
1128 
1129         stream = php_stream_xport_create(res, reslen, REPORT_ERRORS,
1130                         STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, persistent_id, timeout, NULL, NULL, NULL);
1131 
1132         efree(res);
1133 
1134         return stream;
1135 }
1136 
1137 PHPAPI int php_set_sock_blocking(php_socket_t socketd, int block)
1138 {
1139         int ret = SUCCESS;
1140 
1141 #ifdef PHP_WIN32
1142         u_long flags;
1143 
1144         /* with ioctlsocket, a non-zero sets nonblocking, a zero sets blocking */
1145         flags = !block;
1146         if (ioctlsocket(socketd, FIONBIO, &flags) == SOCKET_ERROR) {
1147                 ret = FAILURE;
1148         }
1149 #else
1150         int myflag = 0;
1151         int flags = fcntl(socketd, F_GETFL);
1152 
1153 #ifdef O_NONBLOCK
1154         myflag = O_NONBLOCK; /* POSIX version */
1155 #elif defined(O_NDELAY)
1156         myflag = O_NDELAY;   /* old non-POSIX version */
1157 #endif
1158         if (!block) {
1159                 flags |= myflag;
1160         } else {
1161                 flags &= ~myflag;
1162         }
1163         if (fcntl(socketd, F_SETFL, flags) == -1) {
1164                 ret = FAILURE;
1165         }
1166 #endif
1167         return ret;
1168 }
1169 
1170 PHPAPI void _php_emit_fd_setsize_warning(int max_fd)
1171 {
1172 
1173 #ifdef PHP_WIN32
1174         php_error_docref(NULL, E_WARNING,
1175                 "PHP needs to be recompiled with a larger value of FD_SETSIZE.\n"
1176                 "If this binary is from an official www.php.net package, file a bug report\n"
1177                 "at http://bugs.php.net, including the following information:\n"
1178                 "FD_SETSIZE=%d, but you are using %d.\n"
1179                 " --enable-fd-setsize=%d is recommended, but you may want to set it\n"
1180                 "to match to maximum number of sockets each script will work with at\n"
1181                 "one time, in order to avoid seeing this error again at a later date.",
1182                 FD_SETSIZE, max_fd, (max_fd + 128) & ~127);
1183 #else
1184         php_error_docref(NULL, E_WARNING,
1185                 "You MUST recompile PHP with a larger value of FD_SETSIZE.\n"
1186                 "It is set to %d, but you have descriptors numbered at least as high as %d.\n"
1187                 " --enable-fd-setsize=%d is recommended, but you may want to set it\n"
1188                 "to equal the maximum number of open files supported by your system,\n"
1189                 "in order to avoid seeing this error again at a later date.",
1190                 FD_SETSIZE, max_fd, (max_fd + 1024) & ~1023);
1191 #endif
1192 }
1193 
1194 #if defined(PHP_USE_POLL_2_EMULATION)
1195 
1196 /* emulate poll(2) using select(2), safely. */
1197 
1198 PHPAPI int php_poll2(php_pollfd *ufds, unsigned int nfds, int timeout)
1199 {
1200         fd_set rset, wset, eset;
1201         php_socket_t max_fd = SOCK_ERR;
1202         unsigned int i;
1203         int n;
1204         struct timeval tv;
1205 
1206         /* check the highest numbered descriptor */
1207         for (i = 0; i < nfds; i++) {
1208                 if (ufds[i].fd > max_fd)
1209                         max_fd = ufds[i].fd;
1210         }
1211 
1212         PHP_SAFE_MAX_FD(max_fd, nfds + 1);
1213 
1214         FD_ZERO(&rset);
1215         FD_ZERO(&wset);
1216         FD_ZERO(&eset);
1217 
1218         for (i = 0; i < nfds; i++) {
1219                 if (ufds[i].events & PHP_POLLREADABLE) {
1220                         PHP_SAFE_FD_SET(ufds[i].fd, &rset);
1221                 }
1222                 if (ufds[i].events & POLLOUT) {
1223                         PHP_SAFE_FD_SET(ufds[i].fd, &wset);
1224                 }
1225                 if (ufds[i].events & POLLPRI) {
1226                         PHP_SAFE_FD_SET(ufds[i].fd, &eset);
1227                 }
1228         }
1229 
1230         if (timeout >= 0) {
1231                 tv.tv_sec = timeout / 1000;
1232                 tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000;
1233         }
1234 /* Reseting/initializing */
1235 #ifdef PHP_WIN32
1236         WSASetLastError(0);
1237 #else
1238         errno = 0;
1239 #endif
1240         n = select(max_fd + 1, &rset, &wset, &eset, timeout >= 0 ? &tv : NULL);
1241 
1242         if (n >= 0) {
1243                 for (i = 0; i < nfds; i++) {
1244                         ufds[i].revents = 0;
1245 
1246                         if (PHP_SAFE_FD_ISSET(ufds[i].fd, &rset)) {
1247                                 /* could be POLLERR or POLLHUP but can't tell without probing */
1248                                 ufds[i].revents |= POLLIN;
1249                         }
1250                         if (PHP_SAFE_FD_ISSET(ufds[i].fd, &wset)) {
1251                                 ufds[i].revents |= POLLOUT;
1252                         }
1253                         if (PHP_SAFE_FD_ISSET(ufds[i].fd, &eset)) {
1254                                 ufds[i].revents |= POLLPRI;
1255                         }
1256                 }
1257         }
1258         return n;
1259 }
1260 
1261 #endif
1262 
1263 
1264 /*
1265  * Local variables:
1266  * tab-width: 8
1267  * c-basic-offset: 8
1268  * End:
1269  * vim600: sw=4 ts=4 fdm=marker
1270  * vim<600: sw=4 ts=4
1271  */

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