]> granicus.if.org Git - php/commitdiff
A Simple fix for Bug #12360 (fsockopen timeout doesn't work).
authorWez Furlong <wez@php.net>
Sun, 22 Dec 2002 13:55:45 +0000 (13:55 +0000)
committerWez Furlong <wez@php.net>
Sun, 22 Dec 2002 13:55:45 +0000 (13:55 +0000)
Analysis:
On systems with HAVE_GETADDRINFO and IPV6 support, php_hostconnect would
attempt to connect to each possible address that matched the requested IP.

If the remote host:port combination are dropping packets this would cause the
first connection to timeout (after waiting for the full timeout duration).

PHP would then attempt the second address and wait the full duration again.

Solution:
If the first connection attempt times out, abort the connection loop.

main/network.c

index 97b6c57f2d031977cff0b99b7fee02e48bd8a074..10b5097ede66af216a6a1725bec5c9db25d681ce 100644 (file)
@@ -100,9 +100,11 @@ int inet_aton(const char *, struct in_addr *);
 #ifdef PHP_WIN32
 # define SOCK_ERR INVALID_SOCKET
 # define SOCK_CONN_ERR SOCKET_ERROR
+# define PHP_TIMEOUT_ERROR_VALUE               WSAETIMEDOUT
 #else
 # define SOCK_ERR -1
 # define SOCK_CONN_ERR -1
+# define PHP_TIMEOUT_ERROR_VALUE               ETIMEDOUT
 #endif
 
 #ifdef HAVE_GETADDRINFO
@@ -266,6 +268,7 @@ PHPAPI int php_connect_nonb(int sockfd,
        int ret = 0;
        fd_set rset;
        fd_set wset;
+       fd_set eset;
 
        if (timeout == NULL)    {
                /* blocking mode */
@@ -286,11 +289,13 @@ PHPAPI int php_connect_nonb(int sockfd,
        }
 
        FD_ZERO(&rset);
+       FD_ZERO(&eset);
        FD_SET(sockfd, &rset);
+       FD_SET(sockfd, &eset);
 
        wset = rset;
 
-       if ((n = select(sockfd + 1, &rset, &wset, NULL, timeout)) == 0) {
+       if ((n = select(sockfd + 1, &rset, &wset, &eset, timeout)) == 0) {
                error = ETIMEDOUT;
        }
 
@@ -400,9 +405,7 @@ int php_hostconnect(const char *host, unsigned short port, int socktype, struct
        struct sockaddr **sal, **psal;
        struct timeval individual_timeout;
        int set_timeout = 0;
-#ifdef PHP_WIN32
        int err;
-#endif
        
        n = php_network_getaddresses(host, &sal TSRMLS_CC);
 
@@ -463,10 +466,19 @@ int php_hostconnect(const char *host, unsigned short port, int socktype, struct
 #ifdef PHP_WIN32
                        /* Preserve the last error */
                        err = WSAGetLastError();
+#else
+                       err = errno;
 #endif
                        close (s);
                }
                sal++;
+
+               if (err == PHP_TIMEOUT_ERROR_VALUE) {
+                       /* if the first attempt timed out, it's highly likely
+                        * that any subsequent attempts will do so also */
+                       break;
+               }
+               
        }
        php_network_freeaddresses(psal);
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "php_hostconnect: connect failed");