PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - main - network.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 250 395 63.3 %
Date: 2016-08-24 Functions: 19 21 90.5 %
Legend: Lines: hit not hit

          Line data    Source code
       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        2501 : PHPAPI void php_network_freeaddresses(struct sockaddr **sal)
     155             : {
     156             :         struct sockaddr **sap;
     157             : 
     158        2501 :         if (sal == NULL)
     159           0 :                 return;
     160        6304 :         for (sap = sal; *sap != NULL; sap++)
     161        3803 :                 efree(*sap);
     162        2501 :         efree(sal);
     163             : }
     164             : /* }}} */
     165             : 
     166             : /* {{{ php_network_getaddresses
     167             :  * Returns number of addresses, 0 for none/error
     168             :  */
     169        2510 : 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        2510 :         if (host == NULL) {
     184           0 :                 return 0;
     185             :         }
     186             : #if HAVE_GETADDRINFO
     187        2510 :         memset(&hints, '\0', sizeof(hints));
     188             : 
     189        2510 :         hints.ai_family = AF_INET; /* default to regular inet (see below) */
     190        2510 :         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        2510 :         if (ipv6_borked == -1) {
     200             :                 int s;
     201             : 
     202         276 :                 s = socket(PF_INET6, SOCK_DGRAM, 0);
     203         276 :                 if (s == SOCK_ERR) {
     204           0 :                         ipv6_borked = 1;
     205             :                 } else {
     206         276 :                         ipv6_borked = 0;
     207         276 :                         closesocket(s);
     208             :                 }
     209             :         }
     210        2510 :         hints.ai_family = ipv6_borked ? AF_INET : AF_UNSPEC;
     211             : # endif
     212             : 
     213        2510 :         if ((n = getaddrinfo(host, NULL, &hints, &res))) {
     214           9 :                 if (error_string) {
     215           7 :                         *error_string = strpprintf(0, "php_network_getaddresses: getaddrinfo failed: %s", PHP_GAI_STRERROR(n));
     216           7 :                         php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(*error_string));
     217             :                 } else {
     218           2 :                         php_error_docref(NULL, E_WARNING, "php_network_getaddresses: getaddrinfo failed: %s", PHP_GAI_STRERROR(n));
     219             :                 }
     220           9 :                 return 0;
     221        2501 :         } else if (res == NULL) {
     222           0 :                 if (error_string) {
     223           0 :                         *error_string = strpprintf(0, "php_network_getaddresses: getaddrinfo failed (null result pointer) errno=%d", errno);
     224           0 :                         php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(*error_string));
     225             :                 } else {
     226           0 :                         php_error_docref(NULL, E_WARNING, "php_network_getaddresses: getaddrinfo failed (null result pointer)");
     227             :                 }
     228           0 :                 return 0;
     229             :         }
     230             : 
     231        2501 :         sai = res;
     232        2501 :         for (n = 1; (sai = sai->ai_next) != NULL; n++)
     233             :                 ;
     234             : 
     235        2501 :         *sal = safe_emalloc((n + 1), sizeof(*sal), 0);
     236        2501 :         sai = res;
     237        2501 :         sap = *sal;
     238             : 
     239             :         do {
     240        3803 :                 *sap = emalloc(sai->ai_addrlen);
     241        3803 :                 memcpy(*sap, sai->ai_addr, sai->ai_addrlen);
     242        3803 :                 sap++;
     243        3803 :         } while ((sai = sai->ai_next) != NULL);
     244             : 
     245        2501 :         freeaddrinfo(res);
     246             : #else
     247             :         if (!inet_aton(host, &in)) {
     248             :                 if(strlen(host) > MAXFQDNLEN) {
     249             :                         host_info = NULL;
     250             :                         errno = E2BIG;
     251             :                 } else {
     252             :                         host_info = php_network_gethostbyname(host);
     253             :                 }
     254             :                 if (host_info == NULL) {
     255             :                         if (error_string) {
     256             :                                 *error_string = strpprintf(0, "php_network_getaddresses: gethostbyname failed. errno=%d", errno);
     257             :                                 php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(*error_string));
     258             :                         } else {
     259             :                                 php_error_docref(NULL, E_WARNING, "php_network_getaddresses: gethostbyname failed");
     260             :                         }
     261             :                         return 0;
     262             :                 }
     263             :                 in = *((struct in_addr *) host_info->h_addr);
     264             :         }
     265             : 
     266             :         *sal = safe_emalloc(2, sizeof(*sal), 0);
     267             :         sap = *sal;
     268             :         *sap = emalloc(sizeof(struct sockaddr_in));
     269             :         (*sap)->sa_family = AF_INET;
     270             :         ((struct sockaddr_in *)*sap)->sin_addr = in;
     271             :         sap++;
     272             :         n = 1;
     273             : #endif
     274             : 
     275        2501 :         *sap = NULL;
     276        2501 :         return n;
     277             : }
     278             : /* }}} */
     279             : 
     280             : #ifndef O_NONBLOCK
     281             : #define O_NONBLOCK O_NDELAY
     282             : #endif
     283             : 
     284             : #if !defined(__BEOS__)
     285             : # define HAVE_NON_BLOCKING_CONNECT 1
     286             : # ifdef PHP_WIN32
     287             : typedef u_long php_non_blocking_flags_t;
     288             : #  define SET_SOCKET_BLOCKING_MODE(sock, save) \
     289             :      save = TRUE; ioctlsocket(sock, FIONBIO, &save)
     290             : #  define RESTORE_SOCKET_BLOCKING_MODE(sock, save) \
     291             :          ioctlsocket(sock, FIONBIO, &save)
     292             : # else
     293             : typedef int php_non_blocking_flags_t;
     294             : #  define SET_SOCKET_BLOCKING_MODE(sock, save) \
     295             :          save = fcntl(sock, F_GETFL, 0); \
     296             :          fcntl(sock, F_SETFL, save | O_NONBLOCK)
     297             : #  define RESTORE_SOCKET_BLOCKING_MODE(sock, save) \
     298             :          fcntl(sock, F_SETFL, save)
     299             : # endif
     300             : #endif
     301             : 
     302             : /* Connect to a socket using an interruptible connect with optional timeout.
     303             :  * Optionally, the connect can be made asynchronously, which will implicitly
     304             :  * enable non-blocking mode on the socket.
     305             :  * */
     306             : /* {{{ php_network_connect_socket */
     307        5095 : PHPAPI int php_network_connect_socket(php_socket_t sockfd,
     308             :                 const struct sockaddr *addr,
     309             :                 socklen_t addrlen,
     310             :                 int asynchronous,
     311             :                 struct timeval *timeout,
     312             :                 zend_string **error_string,
     313             :                 int *error_code)
     314             : {
     315             : #if HAVE_NON_BLOCKING_CONNECT
     316             :         php_non_blocking_flags_t orig_flags;
     317             :         int n;
     318        5095 :         int error = 0;
     319             :         socklen_t len;
     320        5095 :         int ret = 0;
     321             : 
     322        5095 :         SET_SOCKET_BLOCKING_MODE(sockfd, orig_flags);
     323             : 
     324        5095 :         if ((n = connect(sockfd, addr, addrlen)) != 0) {
     325        2772 :                 error = php_socket_errno();
     326             : 
     327        2772 :                 if (error_code) {
     328        2741 :                         *error_code = error;
     329             :                 }
     330             : 
     331        2772 :                 if (error != EINPROGRESS) {
     332           5 :                         if (error_string) {
     333           5 :                                 *error_string = php_socket_error_str(error);
     334             :                         }
     335             : 
     336           5 :                         return -1;
     337             :                 }
     338        2767 :                 if (asynchronous && error == EINPROGRESS) {
     339             :                         /* this is fine by us */
     340           1 :                         return 0;
     341             :                 }
     342             :         }
     343             : 
     344        5089 :         if (n == 0) {
     345        2323 :                 goto ok;
     346             :         }
     347             : # ifdef PHP_WIN32
     348             :         /* The documentation for connect() says in case of non-blocking connections
     349             :          * the select function reports success in the writefds set and failure in
     350             :          * the exceptfds set. Indeed, using PHP_POLLREADABLE results in select
     351             :          * failing only due to the timeout and not immediately as would be
     352             :          * expected when a connection is actively refused. This way,
     353             :          * php_pollfd_for will return a mask with POLLOUT if the connection
     354             :          * is successful and with POLLPRI otherwise. */
     355             :         if ((n = php_pollfd_for(sockfd, POLLOUT|POLLPRI, timeout)) == 0) {
     356             : #else
     357        2766 :         if ((n = php_pollfd_for(sockfd, PHP_POLLREADABLE|POLLOUT, timeout)) == 0) {
     358             : #endif
     359           0 :                 error = PHP_TIMEOUT_ERROR_VALUE;
     360             :         }
     361             : 
     362        2766 :         if (n > 0) {
     363        2766 :                 len = sizeof(error);
     364             :                 /*
     365             :                    BSD-derived systems set errno correctly
     366             :                    Solaris returns -1 from getsockopt in case of error
     367             :                    */
     368        2766 :                 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char*)&error, &len) != 0) {
     369           0 :                         ret = -1;
     370             :                 }
     371             :         } else {
     372             :                 /* whoops: sockfd has disappeared */
     373           0 :                 ret = -1;
     374             :         }
     375             : 
     376             : ok:
     377        5089 :         if (!asynchronous) {
     378             :                 /* back to blocking mode */
     379        5089 :                 RESTORE_SOCKET_BLOCKING_MODE(sockfd, orig_flags);
     380             :         }
     381             : 
     382        5089 :         if (error_code) {
     383        5058 :                 *error_code = error;
     384             :         }
     385             : 
     386        5089 :         if (error) {
     387        2564 :                 ret = -1;
     388        2564 :                 if (error_string) {
     389        2564 :                         *error_string = php_socket_error_str(error);
     390             :                 }
     391             :         }
     392        5089 :         return ret;
     393             : #else
     394             :         if (asynchronous) {
     395             :                 php_error_docref(NULL, E_WARNING, "Asynchronous connect() not supported on this platform");
     396             :         }
     397             :         return (connect(sockfd, addr, addrlen) == 0) ? 0 : -1;
     398             : #endif
     399             : }
     400             : /* }}} */
     401             : 
     402             : /* {{{ sub_times */
     403        2564 : static inline void sub_times(struct timeval a, struct timeval b, struct timeval *result)
     404             : {
     405        2564 :         result->tv_usec = a.tv_usec - b.tv_usec;
     406        2564 :         if (result->tv_usec < 0L) {
     407        2538 :                 a.tv_sec--;
     408        2538 :                 result->tv_usec += 1000000L;
     409             :         }
     410        2564 :         result->tv_sec = a.tv_sec - b.tv_sec;
     411        2564 :         if (result->tv_sec < 0L) {
     412           0 :                 result->tv_sec++;
     413           0 :                 result->tv_usec -= 1000000L;
     414             :         }
     415        2564 : }
     416             : /* }}} */
     417             : 
     418             : /* Bind to a local IP address.
     419             :  * Returns the bound socket, or -1 on failure.
     420             :  * */
     421             : /* {{{ php_network_bind_socket_to_local_addr */
     422         149 : php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned port,
     423             :                 int socktype, long sockopts, zend_string **error_string, int *error_code
     424             :                 )
     425             : {
     426         149 :         int num_addrs, n, err = 0;
     427             :         php_socket_t sock;
     428             :         struct sockaddr **sal, **psal, *sa;
     429             :         socklen_t socklen;
     430         149 :         int sockoptval = 1;
     431             : 
     432         149 :         num_addrs = php_network_getaddresses(host, socktype, &psal, error_string);
     433             : 
     434         149 :         if (num_addrs == 0) {
     435             :                 /* could not resolve address(es) */
     436           0 :                 return -1;
     437             :         }
     438             : 
     439         149 :         for (sal = psal; *sal != NULL; sal++) {
     440         149 :                 sa = *sal;
     441             : 
     442             :                 /* create a socket for this address */
     443         149 :                 sock = socket(sa->sa_family, socktype, 0);
     444             : 
     445         149 :                 if (sock == SOCK_ERR) {
     446           0 :                         continue;
     447             :                 }
     448             : 
     449         149 :                 switch (sa->sa_family) {
     450             : #if HAVE_GETADDRINFO && HAVE_IPV6
     451             :                         case AF_INET6:
     452           2 :                                 ((struct sockaddr_in6 *)sa)->sin6_family = sa->sa_family;
     453           2 :                                 ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
     454           2 :                                 socklen = sizeof(struct sockaddr_in6);
     455           2 :                                 break;
     456             : #endif
     457             :                         case AF_INET:
     458         147 :                                 ((struct sockaddr_in *)sa)->sin_family = sa->sa_family;
     459         147 :                                 ((struct sockaddr_in *)sa)->sin_port = htons(port);
     460         147 :                                 socklen = sizeof(struct sockaddr_in);
     461         147 :                                 break;
     462             :                         default:
     463             :                                 /* Unknown family */
     464           0 :                                 socklen = 0;
     465           0 :                                 sa = NULL;
     466             :                 }
     467             : 
     468         149 :                 if (sa) {
     469             :                         /* attempt to bind */
     470             : 
     471             : #ifdef SO_REUSEADDR
     472         149 :                         setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&sockoptval, sizeof(sockoptval));
     473             : #endif
     474             : #ifdef IPV6_V6ONLY
     475         149 :                         if (sockopts & STREAM_SOCKOP_IPV6_V6ONLY) {
     476           0 :                                 int ipv6_val = !!(sockopts & STREAM_SOCKOP_IPV6_V6ONLY_ENABLED);
     477           0 :                                 setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6_val, sizeof(sockoptval));
     478             :                         }
     479             : #endif
     480             : #ifdef SO_REUSEPORT
     481         149 :                         if (sockopts & STREAM_SOCKOP_SO_REUSEPORT) {
     482           0 :                                 setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char*)&sockoptval, sizeof(sockoptval));
     483             :                         }
     484             : #endif
     485             : #ifdef SO_BROADCAST
     486         149 :                         if (sockopts & STREAM_SOCKOP_SO_BROADCAST) {
     487           0 :                                 setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&sockoptval, sizeof(sockoptval));
     488             :                         }
     489             : #endif
     490             : #ifdef TCP_NODELAY
     491         149 :                         if (sockopts & STREAM_SOCKOP_TCP_NODELAY) {
     492           0 :                                 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&sockoptval, sizeof(sockoptval));
     493             :                         }
     494             : #endif
     495             : 
     496         149 :                         n = bind(sock, sa, socklen);
     497             : 
     498         149 :                         if (n != SOCK_CONN_ERR) {
     499         149 :                                 goto bound;
     500             :                         }
     501             : 
     502           0 :                         err = php_socket_errno();
     503             :                 }
     504             : 
     505           0 :                 closesocket(sock);
     506             :         }
     507           0 :         sock = -1;
     508             : 
     509           0 :         if (error_code) {
     510           0 :                 *error_code = err;
     511             :         }
     512           0 :         if (error_string) {
     513           0 :                 *error_string = php_socket_error_str(err);
     514             :         }
     515             : 
     516             : bound:
     517             : 
     518         149 :         php_network_freeaddresses(psal);
     519             : 
     520         149 :         return sock;
     521             : 
     522             : }
     523             : /* }}} */
     524             : 
     525           0 : PHPAPI int php_network_parse_network_address_with_port(const char *addr, zend_long addrlen, struct sockaddr *sa, socklen_t *sl)
     526             : {
     527             :         char *colon;
     528             :         char *tmp;
     529           0 :         int ret = FAILURE;
     530             :         short port;
     531           0 :         struct sockaddr_in *in4 = (struct sockaddr_in*)sa;
     532             :         struct sockaddr **psal;
     533             :         int n;
     534           0 :         zend_string *errstr = NULL;
     535             : #if HAVE_IPV6
     536           0 :         struct sockaddr_in6 *in6 = (struct sockaddr_in6*)sa;
     537             : #endif
     538             : 
     539           0 :         if (*addr == '[') {
     540           0 :                 colon = memchr(addr + 1, ']', addrlen-1);
     541           0 :                 if (!colon || colon[1] != ':') {
     542           0 :                         return FAILURE;
     543             :                 }
     544           0 :                 port = atoi(colon + 2);
     545           0 :                 addr++;
     546             :         } else {
     547           0 :                 colon = memchr(addr, ':', addrlen);
     548           0 :                 if (!colon) {
     549           0 :                         return FAILURE;
     550             :                 }
     551           0 :                 port = atoi(colon + 1);
     552             :         }
     553             : 
     554           0 :         tmp = estrndup(addr, colon - addr);
     555             : 
     556             :         /* first, try interpreting the address as a numeric address */
     557             : 
     558             : #if HAVE_IPV6 && HAVE_INET_PTON
     559           0 :         if (inet_pton(AF_INET6, tmp, &in6->sin6_addr) > 0) {
     560           0 :                 in6->sin6_port = htons(port);
     561           0 :                 in6->sin6_family = AF_INET6;
     562           0 :                 *sl = sizeof(struct sockaddr_in6);
     563           0 :                 ret = SUCCESS;
     564           0 :                 goto out;
     565             :         }
     566             : #endif
     567           0 :         if (inet_aton(tmp, &in4->sin_addr) > 0) {
     568           0 :                 in4->sin_port = htons(port);
     569           0 :                 in4->sin_family = AF_INET;
     570           0 :                 *sl = sizeof(struct sockaddr_in);
     571           0 :                 ret = SUCCESS;
     572           0 :                 goto out;
     573             :         }
     574             : 
     575             :         /* looks like we'll need to resolve it */
     576           0 :         n = php_network_getaddresses(tmp, SOCK_DGRAM, &psal, &errstr);
     577             : 
     578           0 :         if (n == 0) {
     579           0 :                 if (errstr) {
     580           0 :                         php_error_docref(NULL, E_WARNING, "Failed to resolve `%s': %s", tmp, ZSTR_VAL(errstr));
     581           0 :                         zend_string_release(errstr);
     582             :                 }
     583           0 :                 goto out;
     584             :         }
     585             : 
     586             :         /* copy the details from the first item */
     587           0 :         switch ((*psal)->sa_family) {
     588             : #if HAVE_GETADDRINFO && HAVE_IPV6
     589             :                 case AF_INET6:
     590           0 :                         *in6 = **(struct sockaddr_in6**)psal;
     591           0 :                         in6->sin6_port = htons(port);
     592           0 :                         *sl = sizeof(struct sockaddr_in6);
     593           0 :                         ret = SUCCESS;
     594           0 :                         break;
     595             : #endif
     596             :                 case AF_INET:
     597           0 :                         *in4 = **(struct sockaddr_in**)psal;
     598           0 :                         in4->sin_port = htons(port);
     599           0 :                         *sl = sizeof(struct sockaddr_in);
     600           0 :                         ret = SUCCESS;
     601             :                         break;
     602             :         }
     603             : 
     604           0 :         php_network_freeaddresses(psal);
     605             : 
     606             : out:
     607           0 :         efree(tmp);
     608           0 :         return ret;
     609             : }
     610             : 
     611             : 
     612         111 : PHPAPI void php_network_populate_name_from_sockaddr(
     613             :                 /* input address */
     614             :                 struct sockaddr *sa, socklen_t sl,
     615             :                 /* output readable address */
     616             :                 zend_string **textaddr,
     617             :                 /* output address */
     618             :                 struct sockaddr **addr,
     619             :                 socklen_t *addrlen
     620             :                 )
     621             : {
     622         111 :         if (addr) {
     623           0 :                 *addr = emalloc(sl);
     624           0 :                 memcpy(*addr, sa, sl);
     625           0 :                 *addrlen = sl;
     626             :         }
     627             : 
     628         111 :         if (textaddr) {
     629             : #if HAVE_IPV6 && HAVE_INET_NTOP
     630             :                 char abuf[256];
     631             : #endif
     632           1 :                 char *buf = NULL;
     633             : 
     634           1 :                 switch (sa->sa_family) {
     635             :                         case AF_INET:
     636             :                                 /* generally not thread safe, but it *is* thread safe under win32 */
     637           1 :                                 buf = inet_ntoa(((struct sockaddr_in*)sa)->sin_addr);
     638           1 :                                 if (buf) {
     639           1 :                                         *textaddr = strpprintf(0, "%s:%d",
     640           1 :                                                 buf, ntohs(((struct sockaddr_in*)sa)->sin_port));
     641             :                                 }
     642             : 
     643           1 :                                 break;
     644             : 
     645             : #if HAVE_IPV6 && HAVE_INET_NTOP
     646             :                         case AF_INET6:
     647           0 :                                 buf = (char*)inet_ntop(sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, (char *)&abuf, sizeof(abuf));
     648           0 :                                 if (buf) {
     649           0 :                                         *textaddr = strpprintf(0, "%s:%d",
     650           0 :                                                 buf, ntohs(((struct sockaddr_in6*)sa)->sin6_port));
     651             :                                 }
     652             : 
     653           0 :                                 break;
     654             : #endif
     655             : #ifdef AF_UNIX
     656             :                         case AF_UNIX:
     657             :                                 {
     658           0 :                                         struct sockaddr_un *ua = (struct sockaddr_un*)sa;
     659             : 
     660           0 :                                         if (ua->sun_path[0] == '\0') {
     661             :                                                 /* abstract name */
     662           0 :                                                 int len = strlen(ua->sun_path + 1) + 1;
     663           0 :                                                 *textaddr = zend_string_init((char*)ua->sun_path, len, 0);
     664             :                                         } else {
     665           0 :                                                 int len = strlen(ua->sun_path);
     666           0 :                                                 *textaddr = zend_string_init((char*)ua->sun_path, len, 0);
     667             :                                         }
     668             :                                 }
     669             :                                 break;
     670             : #endif
     671             : 
     672             :                 }
     673             : 
     674             :         }
     675         111 : }
     676             : 
     677           1 : PHPAPI int php_network_get_peer_name(php_socket_t sock,
     678             :                 zend_string **textaddr,
     679             :                 struct sockaddr **addr,
     680             :                 socklen_t *addrlen
     681             :                 )
     682             : {
     683             :         php_sockaddr_storage sa;
     684           1 :         socklen_t sl = sizeof(sa);
     685           1 :         memset(&sa, 0, sizeof(sa));
     686             : 
     687           1 :         if (getpeername(sock, (struct sockaddr*)&sa, &sl) == 0) {
     688           0 :                 php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
     689             :                                 textaddr,
     690             :                                 addr, addrlen
     691             :                                 );
     692           0 :                 return 0;
     693             :         }
     694           1 :         return -1;
     695             : }
     696             : 
     697           1 : PHPAPI int php_network_get_sock_name(php_socket_t sock,
     698             :                 zend_string **textaddr,
     699             :                 struct sockaddr **addr,
     700             :                 socklen_t *addrlen
     701             :                 )
     702             : {
     703             :         php_sockaddr_storage sa;
     704           1 :         socklen_t sl = sizeof(sa);
     705           1 :         memset(&sa, 0, sizeof(sa));
     706             : 
     707           1 :         if (getsockname(sock, (struct sockaddr*)&sa, &sl) == 0) {
     708           1 :                 php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
     709             :                                 textaddr,
     710             :                                 addr, addrlen
     711             :                                 );
     712           1 :                 return 0;
     713             :         }
     714           0 :         return -1;
     715             : 
     716             : }
     717             : 
     718             : 
     719             : /* Accept a client connection from a server socket,
     720             :  * using an optional timeout.
     721             :  * Returns the peer address in addr/addrlen (it will emalloc
     722             :  * these, so be sure to efree the result).
     723             :  * If you specify textaddr, a text-printable
     724             :  * version of the address will be emalloc'd and returned.
     725             :  * */
     726             : 
     727             : /* {{{ php_network_accept_incoming */
     728         115 : PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
     729             :                 zend_string **textaddr,
     730             :                 struct sockaddr **addr,
     731             :                 socklen_t *addrlen,
     732             :                 struct timeval *timeout,
     733             :                 zend_string **error_string,
     734             :                 int *error_code,
     735             :                 int tcp_nodelay
     736             :                 )
     737             : {
     738         115 :         php_socket_t clisock = -1;
     739         115 :         int error = 0, n;
     740             :         php_sockaddr_storage sa;
     741             :         socklen_t sl;
     742             : 
     743         115 :         n = php_pollfd_for(srvsock, PHP_POLLREADABLE, timeout);
     744             : 
     745         115 :         if (n == 0) {
     746           5 :                 error = PHP_TIMEOUT_ERROR_VALUE;
     747         110 :         } else if (n == -1) {
     748           0 :                 error = php_socket_errno();
     749             :         } else {
     750         110 :                 sl = sizeof(sa);
     751             : 
     752         110 :                 clisock = accept(srvsock, (struct sockaddr*)&sa, &sl);
     753             : 
     754         110 :                 if (clisock != SOCK_ERR) {
     755         110 :                         php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
     756             :                                         textaddr,
     757             :                                         addr, addrlen
     758             :                                         );
     759         110 :                         if (tcp_nodelay) {
     760             : #ifdef TCP_NODELAY
     761           1 :                                 setsockopt(clisock, IPPROTO_TCP, TCP_NODELAY, (char*)&tcp_nodelay, sizeof(tcp_nodelay));
     762             : #endif
     763             :                         }
     764             :                 } else {
     765           0 :                         error = php_socket_errno();
     766             :                 }
     767             :         }
     768             : 
     769         115 :         if (error_code) {
     770         115 :                 *error_code = error;
     771             :         }
     772         115 :         if (error_string) {
     773         115 :                 *error_string = php_socket_error_str(error);
     774             :         }
     775             : 
     776         115 :         return clisock;
     777             : }
     778             : /* }}} */
     779             : 
     780             : 
     781             : /* Connect to a remote host using an interruptible connect with optional timeout.
     782             :  * Optionally, the connect can be made asynchronously, which will implicitly
     783             :  * enable non-blocking mode on the socket.
     784             :  * Returns the connected (or connecting) socket, or -1 on failure.
     785             :  * */
     786             : 
     787             : /* {{{ php_network_connect_socket_to_host */
     788        2113 : php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port,
     789             :                 int socktype, int asynchronous, struct timeval *timeout, zend_string **error_string,
     790             :                 int *error_code, char *bindto, unsigned short bindport, long sockopts
     791             :                 )
     792             : {
     793        2113 :         int num_addrs, n, fatal = 0;
     794             :         php_socket_t sock;
     795             :         struct sockaddr **sal, **psal, *sa;
     796             :         struct timeval working_timeout;
     797             :         socklen_t socklen;
     798             : #if HAVE_GETTIMEOFDAY
     799             :         struct timeval limit_time, time_now;
     800             : #endif
     801             : 
     802        2113 :         num_addrs = php_network_getaddresses(host, socktype, &psal, error_string);
     803             : 
     804        2113 :         if (num_addrs == 0) {
     805             :                 /* could not resolve address(es) */
     806           8 :                 return -1;
     807             :         }
     808             : 
     809        2105 :         if (timeout) {
     810        2105 :                 memcpy(&working_timeout, timeout, sizeof(working_timeout));
     811             : #if HAVE_GETTIMEOFDAY
     812        2105 :                 gettimeofday(&limit_time, NULL);
     813        2105 :                 limit_time.tv_sec += working_timeout.tv_sec;
     814        2105 :                 limit_time.tv_usec += working_timeout.tv_usec;
     815        2105 :                 if (limit_time.tv_usec >= 1000000) {
     816          18 :                         limit_time.tv_usec -= 1000000;
     817          18 :                         limit_time.tv_sec++;
     818             :                 }
     819             : #endif
     820             :         }
     821             : 
     822        4669 :         for (sal = psal; !fatal && *sal != NULL; sal++) {
     823        3386 :                 sa = *sal;
     824             : 
     825             :                 /* create a socket for this address */
     826        3386 :                 sock = socket(sa->sa_family, socktype, 0);
     827             : 
     828        3386 :                 if (sock == SOCK_ERR) {
     829           0 :                         continue;
     830             :                 }
     831             : 
     832        3386 :                 switch (sa->sa_family) {
     833             : #if HAVE_GETADDRINFO && HAVE_IPV6
     834             :                         case AF_INET6:
     835        2594 :                                 if (!bindto || strchr(bindto, ':')) {
     836        1297 :                                         ((struct sockaddr_in6 *)sa)->sin6_family = sa->sa_family;
     837        1297 :                                         ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
     838        1297 :                                         socklen = sizeof(struct sockaddr_in6);
     839             :                                 } else {
     840           0 :                                         socklen = 0;
     841           0 :                                         sa = NULL;
     842             :                                 }
     843        1297 :                                 break;
     844             : #endif
     845             :                         case AF_INET:
     846        2089 :                                 ((struct sockaddr_in *)sa)->sin_family = sa->sa_family;
     847        2089 :                                 ((struct sockaddr_in *)sa)->sin_port = htons(port);
     848        2089 :                                 socklen = sizeof(struct sockaddr_in);
     849        2089 :                                 break;
     850             :                         default:
     851             :                                 /* Unknown family */
     852           0 :                                 socklen = 0;
     853           0 :                                 sa = NULL;
     854             :                 }
     855             : 
     856        3386 :                 if (sa) {
     857             :                         /* make a connection attempt */
     858             : 
     859        3386 :                         if (bindto) {
     860           0 :                                 struct sockaddr *local_address = NULL;
     861           0 :                                 int local_address_len = 0;
     862             : 
     863           0 :                                 if (sa->sa_family == AF_INET) {
     864           0 :                                         struct sockaddr_in *in4 = emalloc(sizeof(struct sockaddr_in));
     865             : 
     866           0 :                                         local_address = (struct sockaddr*)in4;
     867           0 :                                         local_address_len = sizeof(struct sockaddr_in);
     868             : 
     869           0 :                                         in4->sin_family = sa->sa_family;
     870           0 :                                         in4->sin_port = htons(bindport);
     871           0 :                                         if (!inet_aton(bindto, &in4->sin_addr)) {
     872           0 :                                                 php_error_docref(NULL, E_WARNING, "Invalid IP Address: %s", bindto);
     873           0 :                                                 goto skip_bind;
     874             :                                         }
     875           0 :                                         memset(&(in4->sin_zero), 0, sizeof(in4->sin_zero));
     876             :                                 }
     877             : #if HAVE_IPV6 && HAVE_INET_PTON
     878             :                                  else { /* IPV6 */
     879           0 :                                         struct sockaddr_in6 *in6 = emalloc(sizeof(struct sockaddr_in6));
     880             : 
     881           0 :                                         local_address = (struct sockaddr*)in6;
     882           0 :                                         local_address_len = sizeof(struct sockaddr_in6);
     883             : 
     884           0 :                                         in6->sin6_family = sa->sa_family;
     885           0 :                                         in6->sin6_port = htons(bindport);
     886           0 :                                         if (inet_pton(AF_INET6, bindto, &in6->sin6_addr) < 1) {
     887           0 :                                                 php_error_docref(NULL, E_WARNING, "Invalid IP Address: %s", bindto);
     888           0 :                                                 goto skip_bind;
     889             :                                         }
     890             :                                 }
     891             : #endif
     892             : 
     893           0 :                                 if (!local_address || bind(sock, local_address, local_address_len)) {
     894           0 :                                         php_error_docref(NULL, E_WARNING, "failed to bind to '%s:%d', system said: %s", bindto, bindport, strerror(errno));
     895             :                                 }
     896             : skip_bind:
     897           0 :                                 if (local_address) {
     898           0 :                                         efree(local_address);
     899             :                                 }
     900             :                         }
     901             :                         /* free error string received during previous iteration (if any) */
     902        3386 :                         if (error_string && *error_string) {
     903        1281 :                                 zend_string_release(*error_string);
     904        1281 :                                 *error_string = NULL;
     905             :                         }
     906             : 
     907             : #ifdef SO_BROADCAST
     908             :                         {
     909        3386 :                                 int val = 1;
     910        3386 :                                 if (sockopts & STREAM_SOCKOP_SO_BROADCAST) {
     911           0 :                                         setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&val, sizeof(val));
     912             :                                 }
     913             :                         }
     914             : #endif
     915             : 
     916             : #ifdef TCP_NODELAY
     917             :                         {
     918        3386 :                                 int val = 1;
     919        3386 :                                 if (sockopts & STREAM_SOCKOP_TCP_NODELAY) {
     920           2 :                                         setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&val, sizeof(val));
     921             :                                 }
     922             :                         }
     923             : #endif
     924        3386 :                         n = php_network_connect_socket(sock, sa, socklen, asynchronous,
     925             :                                         timeout ? &working_timeout : NULL,
     926             :                                         error_string, error_code);
     927             : 
     928        3386 :                         if (n != -1) {
     929         822 :                                 goto connected;
     930             :                         }
     931             : 
     932             :                         /* adjust timeout for next attempt */
     933             : #if HAVE_GETTIMEOFDAY
     934        2564 :                         if (timeout) {
     935        2564 :                                 gettimeofday(&time_now, NULL);
     936             : 
     937        2564 :                                 if (timercmp(&time_now, &limit_time, >=)) {
     938             :                                         /* time limit expired; don't attempt any further connections */
     939           0 :                                         fatal = 1;
     940             :                                 } else {
     941             :                                         /* work out remaining time */
     942        2564 :                                         sub_times(limit_time, time_now, &working_timeout);
     943             :                                 }
     944             :                         }
     945             : #else
     946             :                         if (error_code && *error_code == PHP_TIMEOUT_ERROR_VALUE) {
     947             :                                 /* Don't even bother trying to connect to the next alternative;
     948             :                                  * we have no way to determine how long we have already taken
     949             :                                  * and it is quite likely that the next attempt will fail too. */
     950             :                                 fatal = 1;
     951             :                         } else {
     952             :                                 /* re-use the same initial timeout.
     953             :                                  * Not the best thing, but in practice it should be good-enough */
     954             :                                 if (timeout) {
     955             :                                         memcpy(&working_timeout, timeout, sizeof(working_timeout));
     956             :                                 }
     957             :                         }
     958             : #endif
     959             :                 }
     960             : 
     961        2564 :                 closesocket(sock);
     962             :         }
     963        1283 :         sock = -1;
     964             : 
     965             : connected:
     966             : 
     967        2105 :         php_network_freeaddresses(psal);
     968             : 
     969        2105 :         return sock;
     970             : }
     971             : /* }}} */
     972             : 
     973             : /* {{{ php_any_addr
     974             :  * Fills the any (wildcard) address into php_sockaddr_storage
     975             :  */
     976          23 : PHPAPI void php_any_addr(int family, php_sockaddr_storage *addr, unsigned short port)
     977             : {
     978          23 :         memset(addr, 0, sizeof(php_sockaddr_storage));
     979          23 :         switch (family) {
     980             : #if HAVE_IPV6
     981             :         case AF_INET6: {
     982           0 :                 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr;
     983           0 :                 sin6->sin6_family = AF_INET6;
     984           0 :                 sin6->sin6_port = htons(port);
     985           0 :                 sin6->sin6_addr = in6addr_any;
     986           0 :                 break;
     987             :         }
     988             : #endif
     989             :         case AF_INET: {
     990          23 :                 struct sockaddr_in *sin = (struct sockaddr_in *) addr;
     991          23 :                 sin->sin_family = AF_INET;
     992          23 :                 sin->sin_port = htons(port);
     993          23 :                 sin->sin_addr.s_addr = htonl(INADDR_ANY);
     994             :                 break;
     995             :         }
     996             :         }
     997          23 : }
     998             : /* }}} */
     999             : 
    1000             : /* {{{ php_sockaddr_size
    1001             :  * Returns the size of struct sockaddr_xx for the family
    1002             :  */
    1003          23 : PHPAPI int php_sockaddr_size(php_sockaddr_storage *addr)
    1004             : {
    1005          23 :         switch (((struct sockaddr *)addr)->sa_family) {
    1006             :         case AF_INET:
    1007          23 :                 return sizeof(struct sockaddr_in);
    1008             : #if HAVE_IPV6
    1009             :         case AF_INET6:
    1010           0 :                 return sizeof(struct sockaddr_in6);
    1011             : #endif
    1012             : #ifdef AF_UNIX
    1013             :         case AF_UNIX:
    1014           0 :                 return sizeof(struct sockaddr_un);
    1015             : #endif
    1016             :         default:
    1017           0 :                 return 0;
    1018             :         }
    1019             : }
    1020             : /* }}} */
    1021             : 
    1022             : /* Given a socket error code, if buf == NULL:
    1023             :  *   emallocs storage for the error message and returns
    1024             :  * else
    1025             :  *   sprintf message into provided buffer and returns buf
    1026             :  */
    1027             : /* {{{ php_socket_strerror */
    1028          15 : PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize)
    1029             : {
    1030             : #ifndef PHP_WIN32
    1031             :         char *errstr;
    1032             : 
    1033          15 :         errstr = strerror(err);
    1034          15 :         if (buf == NULL) {
    1035          15 :                 buf = estrdup(errstr);
    1036             :         } else {
    1037           0 :                 strncpy(buf, errstr, bufsize);
    1038           0 :                 buf[bufsize?(bufsize-1):0] = 0;
    1039             :         }
    1040          15 :         return buf;
    1041             : #else
    1042             :         char *sysbuf;
    1043             :         int free_it = 1;
    1044             : 
    1045             :         if (!FormatMessage(
    1046             :                                 FORMAT_MESSAGE_ALLOCATE_BUFFER |
    1047             :                                 FORMAT_MESSAGE_FROM_SYSTEM |
    1048             :                                 FORMAT_MESSAGE_IGNORE_INSERTS,
    1049             :                                 NULL,
    1050             :                                 err,
    1051             :                                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    1052             :                                 (LPTSTR)&sysbuf,
    1053             :                                 0,
    1054             :                                 NULL)) {
    1055             :                 free_it = 0;
    1056             :                 sysbuf = "Unknown Error";
    1057             :         }
    1058             : 
    1059             :         if (buf == NULL) {
    1060             :                 buf = estrdup(sysbuf);
    1061             :         } else {
    1062             :                 strncpy(buf, sysbuf, bufsize);
    1063             :                 buf[bufsize?(bufsize-1):0] = 0;
    1064             :         }
    1065             : 
    1066             :         if (free_it) {
    1067             :                 LocalFree(sysbuf);
    1068             :         }
    1069             : 
    1070             :         return buf;
    1071             : #endif
    1072             : }
    1073             : /* }}} */
    1074             : 
    1075             : /* {{{ php_socket_error_str */
    1076        2684 : PHPAPI zend_string *php_socket_error_str(long err)
    1077             : {
    1078             : #ifndef PHP_WIN32
    1079             :         char *errstr;
    1080             : 
    1081        2684 :         errstr = strerror(err);
    1082        5368 :         return zend_string_init(errstr, strlen(errstr), 0);
    1083             : #else
    1084             :         zend_string *ret;
    1085             :         char *sysbuf;
    1086             :         int free_it = 1;
    1087             : 
    1088             :         if (!FormatMessage(
    1089             :                                 FORMAT_MESSAGE_ALLOCATE_BUFFER |
    1090             :                                 FORMAT_MESSAGE_FROM_SYSTEM |
    1091             :                                 FORMAT_MESSAGE_IGNORE_INSERTS,
    1092             :                                 NULL,
    1093             :                                 err,
    1094             :                                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    1095             :                                 (LPTSTR)&sysbuf,
    1096             :                                 0,
    1097             :                                 NULL)) {
    1098             :                 free_it = 0;
    1099             :                 sysbuf = "Unknown Error";
    1100             :         }
    1101             : 
    1102             :         ret = zend_string_init(sysbuf, strlen(sysbuf), 0);
    1103             : 
    1104             :         if (free_it) {
    1105             :                 LocalFree(sysbuf);
    1106             :         }
    1107             : 
    1108             :         return ret;
    1109             : #endif
    1110             : }
    1111             : /* }}} */
    1112             : 
    1113             : /* deprecated */
    1114          16 : PHPAPI php_stream *_php_stream_sock_open_from_socket(php_socket_t socket, const char *persistent_id STREAMS_DC)
    1115             : {
    1116             :         php_stream *stream;
    1117             :         php_netstream_data_t *sock;
    1118             : 
    1119          16 :         sock = pemalloc(sizeof(php_netstream_data_t), persistent_id ? 1 : 0);
    1120          16 :         memset(sock, 0, sizeof(php_netstream_data_t));
    1121             : 
    1122          16 :         sock->is_blocked = 1;
    1123          16 :         sock->timeout.tv_sec = FG(default_socket_timeout);
    1124          16 :         sock->timeout.tv_usec = 0;
    1125          16 :         sock->socket = socket;
    1126             : 
    1127          16 :         stream = php_stream_alloc_rel(&php_stream_generic_socket_ops, sock, persistent_id, "r+");
    1128             : 
    1129          16 :         if (stream == NULL) {
    1130           0 :                 pefree(sock, persistent_id ? 1 : 0);
    1131             :         } else {
    1132          16 :                 stream->flags |= PHP_STREAM_FLAG_AVOID_BLOCKING;
    1133             :         }
    1134             : 
    1135          16 :         return stream;
    1136             : }
    1137             : 
    1138           4 : PHPAPI php_stream *_php_stream_sock_open_host(const char *host, unsigned short port,
    1139             :                 int socktype, struct timeval *timeout, const char *persistent_id STREAMS_DC)
    1140             : {
    1141             :         char *res;
    1142             :         zend_long reslen;
    1143             :         php_stream *stream;
    1144             : 
    1145           4 :         reslen = spprintf(&res, 0, "tcp://%s:%d", host, port);
    1146             : 
    1147           4 :         stream = php_stream_xport_create(res, reslen, REPORT_ERRORS,
    1148             :                         STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, persistent_id, timeout, NULL, NULL, NULL);
    1149             : 
    1150           4 :         efree(res);
    1151             : 
    1152           4 :         return stream;
    1153             : }
    1154             : 
    1155         629 : PHPAPI int php_set_sock_blocking(php_socket_t socketd, int block)
    1156             : {
    1157         629 :         int ret = SUCCESS;
    1158             : 
    1159             : #ifdef PHP_WIN32
    1160             :         u_long flags;
    1161             : 
    1162             :         /* with ioctlsocket, a non-zero sets nonblocking, a zero sets blocking */
    1163             :         flags = !block;
    1164             :         if (ioctlsocket(socketd, FIONBIO, &flags) == SOCKET_ERROR) {
    1165             :                 ret = FAILURE;
    1166             :         }
    1167             : #else
    1168         629 :         int myflag = 0;
    1169         629 :         int flags = fcntl(socketd, F_GETFL);
    1170             : 
    1171             : #ifdef O_NONBLOCK
    1172         629 :         myflag = O_NONBLOCK; /* POSIX version */
    1173             : #elif defined(O_NDELAY)
    1174             :         myflag = O_NDELAY;   /* old non-POSIX version */
    1175             : #endif
    1176         629 :         if (!block) {
    1177         331 :                 flags |= myflag;
    1178             :         } else {
    1179         298 :                 flags &= ~myflag;
    1180             :         }
    1181         629 :         if (fcntl(socketd, F_SETFL, flags) == -1) {
    1182           2 :                 ret = FAILURE;
    1183             :         }
    1184             : #endif
    1185         629 :         return ret;
    1186             : }
    1187             : 
    1188           0 : PHPAPI void _php_emit_fd_setsize_warning(int max_fd)
    1189             : {
    1190             : 
    1191             : #ifdef PHP_WIN32
    1192             :         php_error_docref(NULL, E_WARNING,
    1193             :                 "PHP needs to be recompiled with a larger value of FD_SETSIZE.\n"
    1194             :                 "If this binary is from an official www.php.net package, file a bug report\n"
    1195             :                 "at http://bugs.php.net, including the following information:\n"
    1196             :                 "FD_SETSIZE=%d, but you are using %d.\n"
    1197             :                 " --enable-fd-setsize=%d is recommended, but you may want to set it\n"
    1198             :                 "to match to maximum number of sockets each script will work with at\n"
    1199             :                 "one time, in order to avoid seeing this error again at a later date.",
    1200             :                 FD_SETSIZE, max_fd, (max_fd + 128) & ~127);
    1201             : #else
    1202           0 :         php_error_docref(NULL, E_WARNING,
    1203             :                 "You MUST recompile PHP with a larger value of FD_SETSIZE.\n"
    1204             :                 "It is set to %d, but you have descriptors numbered at least as high as %d.\n"
    1205             :                 " --enable-fd-setsize=%d is recommended, but you may want to set it\n"
    1206             :                 "to equal the maximum number of open files supported by your system,\n"
    1207             :                 "in order to avoid seeing this error again at a later date.",
    1208           0 :                 FD_SETSIZE, max_fd, (max_fd + 1024) & ~1023);
    1209             : #endif
    1210           0 : }
    1211             : 
    1212             : #if defined(PHP_USE_POLL_2_EMULATION)
    1213             : 
    1214             : /* emulate poll(2) using select(2), safely. */
    1215             : 
    1216             : PHPAPI int php_poll2(php_pollfd *ufds, unsigned int nfds, int timeout)
    1217             : {
    1218             :         fd_set rset, wset, eset;
    1219             :         php_socket_t max_fd = SOCK_ERR;
    1220             :         unsigned int i;
    1221             :         int n;
    1222             :         struct timeval tv;
    1223             : 
    1224             :         /* check the highest numbered descriptor */
    1225             :         for (i = 0; i < nfds; i++) {
    1226             :                 if (ufds[i].fd > max_fd)
    1227             :                         max_fd = ufds[i].fd;
    1228             :         }
    1229             : 
    1230             :         PHP_SAFE_MAX_FD(max_fd, nfds + 1);
    1231             : 
    1232             :         FD_ZERO(&rset);
    1233             :         FD_ZERO(&wset);
    1234             :         FD_ZERO(&eset);
    1235             : 
    1236             :         for (i = 0; i < nfds; i++) {
    1237             :                 if (ufds[i].events & PHP_POLLREADABLE) {
    1238             :                         PHP_SAFE_FD_SET(ufds[i].fd, &rset);
    1239             :                 }
    1240             :                 if (ufds[i].events & POLLOUT) {
    1241             :                         PHP_SAFE_FD_SET(ufds[i].fd, &wset);
    1242             :                 }
    1243             :                 if (ufds[i].events & POLLPRI) {
    1244             :                         PHP_SAFE_FD_SET(ufds[i].fd, &eset);
    1245             :                 }
    1246             :         }
    1247             : 
    1248             :         if (timeout >= 0) {
    1249             :                 tv.tv_sec = timeout / 1000;
    1250             :                 tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000;
    1251             :         }
    1252             : /* Reseting/initializing */
    1253             : #ifdef PHP_WIN32
    1254             :         WSASetLastError(0);
    1255             : #else
    1256             :         errno = 0;
    1257             : #endif
    1258             :         n = select(max_fd + 1, &rset, &wset, &eset, timeout >= 0 ? &tv : NULL);
    1259             : 
    1260             :         if (n >= 0) {
    1261             :                 for (i = 0; i < nfds; i++) {
    1262             :                         ufds[i].revents = 0;
    1263             : 
    1264             :                         if (PHP_SAFE_FD_ISSET(ufds[i].fd, &rset)) {
    1265             :                                 /* could be POLLERR or POLLHUP but can't tell without probing */
    1266             :                                 ufds[i].revents |= POLLIN;
    1267             :                         }
    1268             :                         if (PHP_SAFE_FD_ISSET(ufds[i].fd, &wset)) {
    1269             :                                 ufds[i].revents |= POLLOUT;
    1270             :                         }
    1271             :                         if (PHP_SAFE_FD_ISSET(ufds[i].fd, &eset)) {
    1272             :                                 ufds[i].revents |= POLLPRI;
    1273             :                         }
    1274             :                 }
    1275             :         }
    1276             :         return n;
    1277             : }
    1278             : #endif
    1279             : 
    1280             : #if defined(HAVE_GETHOSTBYNAME_R)
    1281             : #ifdef HAVE_FUNC_GETHOSTBYNAME_R_6
    1282          31 : struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen)
    1283             : {
    1284             :         struct hostent *hp;
    1285             :         int herr,res;
    1286             : 
    1287          31 :         if (*hstbuflen == 0) {
    1288          31 :                 *hstbuflen = 1024; 
    1289          31 :                 *tmphstbuf = (char *)malloc (*hstbuflen);
    1290             :         }
    1291             : 
    1292          62 :         while (( res = 
    1293          31 :                 gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&hp,&herr))
    1294           0 :                 && (errno == ERANGE)) {
    1295             :                 /* Enlarge the buffer. */
    1296           0 :                 *hstbuflen *= 2;
    1297           0 :                 *tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen);
    1298             :         }
    1299             : 
    1300          31 :         if (res != SUCCESS) {
    1301           0 :                 return NULL;
    1302             :         }
    1303             :                 
    1304          31 :         return hp;
    1305             : }
    1306             : #endif
    1307             : #ifdef HAVE_FUNC_GETHOSTBYNAME_R_5
    1308             : struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen)
    1309             : {
    1310             :         struct hostent *hp;
    1311             :         int herr;
    1312             : 
    1313             :         if (*hstbuflen == 0) {
    1314             :                 *hstbuflen = 1024;
    1315             :                 *tmphstbuf = (char *)malloc (*hstbuflen);
    1316             :         }
    1317             : 
    1318             :         while ((NULL == ( hp = 
    1319             :                 gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&herr)))
    1320             :                 && (errno == ERANGE)) {
    1321             :                 /* Enlarge the buffer. */
    1322             :                 *hstbuflen *= 2;
    1323             :                 *tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen);
    1324             :         }
    1325             :         return hp;
    1326             : }
    1327             : #endif
    1328             : #ifdef HAVE_FUNC_GETHOSTBYNAME_R_3
    1329             : struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen)
    1330             : {
    1331             :         if (*hstbuflen == 0) {
    1332             :                 *hstbuflen = sizeof(struct hostent_data);
    1333             :                 *tmphstbuf = (char *)malloc (*hstbuflen);
    1334             :         } else {
    1335             :                 if (*hstbuflen < sizeof(struct hostent_data)) {
    1336             :                         *hstbuflen = sizeof(struct hostent_data);
    1337             :                         *tmphstbuf = (char *)realloc(*tmphstbuf, *hstbuflen);
    1338             :                 }
    1339             :         }
    1340             :         memset((void *)(*tmphstbuf),0,*hstbuflen);
    1341             : 
    1342             :         if (SUCCESS != gethostbyname_r(host,hostbuf,(struct hostent_data *)*tmphstbuf)) {
    1343             :                 return NULL;
    1344             :         }
    1345             : 
    1346             :         return hostbuf;
    1347             : }
    1348             : #endif
    1349             : #endif
    1350             : 
    1351          31 : PHPAPI struct hostent*  php_network_gethostbyname(char *name) {
    1352             : #if !defined(HAVE_GETHOSTBYNAME_R)
    1353             :         return gethostbyname(name);
    1354             : #else
    1355          31 :         if (FG(tmp_host_buf)) {
    1356           6 :                 free(FG(tmp_host_buf));
    1357             :         }
    1358             : 
    1359          31 :         FG(tmp_host_buf) = NULL;
    1360          31 :         FG(tmp_host_buf_len) = 0;
    1361             : 
    1362          31 :         memset(&FG(tmp_host_info), 0, sizeof(struct hostent));
    1363             : 
    1364          31 :         return gethostname_re(name, &FG(tmp_host_info), &FG(tmp_host_buf), &FG(tmp_host_buf_len));
    1365             : #endif
    1366             : }
    1367             : 
    1368             : /*
    1369             :  * Local variables:
    1370             :  * tab-width: 8
    1371             :  * c-basic-offset: 8
    1372             :  * End:
    1373             :  * vim600: sw=4 ts=4 fdm=marker
    1374             :  * vim<600: sw=4 ts=4
    1375             :  */

Generated by: LCOV version 1.10

Generated at Wed, 24 Aug 2016 12:20:36 +0000 (2 days ago)

Copyright © 2005-2016 The PHP Group
All rights reserved.