wez             Fri Sep 17 08:44:56 2004 EDT

  Modified files:              
    /php-src    configure.in 
    /php-src/ext/ftp    ftp.c 
    /php-src/ext/openssl        xp_ssl.c 
    /php-src/ext/soap   php_http.c 
    /php-src/ext/sockets        sockets.c 
    /php-src/ext/standard       streamsfuncs.c 
    /php-src/main       network.c php_network.h 
    /php-src/main/streams       xp_socket.c 
    /php-src/win32/build        config.w32 
  Log:
  Fix for Bug #24189: possibly unsafe select(2) usage.
  We avoid the problem by using poll(2).
  
  On systems without poll(2) (older bsd-ish systems, and win32), we emulate
  poll(2) using select(2) and check for valid descriptors before attempting
  to access them via the descriptor sets.
  
  If an out-of-range descriptor is detected, an E_WARNING is raised suggesting
  that PHP should be recompiled with a larger FD_SETSIZE (and also with a
  suggested value).
  
  Most uses of select(2) in the source are to poll a single descriptor, so
  a couple of handy wrapper functions have been added to make this easier.
  
  A configure option --enable-fd-setsize has been added to both the unix and
  win32 builds; on unix we default to 16384 and on windows we default to 256.
  Windows FD_SETSIZE imposes a limit on the maximum number of descriptors that
  can be select()ed at once, whereas the unix FD_SETSIZE limit is based on the
  highest numbered descriptor; 256 should be plenty for PHP scripts under windows
  (the default OS setting is 64).
  
  The win32 specific parts are untested; will do that now.
  
  
  
http://cvs.php.net/diff.php/php-src/configure.in?r1=1.516&r2=1.517&ty=u
Index: php-src/configure.in
diff -u php-src/configure.in:1.516 php-src/configure.in:1.517
--- php-src/configure.in:1.516  Wed Jul 21 19:02:28 2004
+++ php-src/configure.in        Fri Sep 17 08:44:55 2004
@@ -1,4 +1,4 @@
-dnl ## $Id: configure.in,v 1.516 2004/07/21 23:02:28 edink Exp $ -*- sh -*-
+dnl ## $Id: configure.in,v 1.517 2004/09/17 12:44:55 wez Exp $ -*- sh -*-
 dnl ## Process this file with autoconf to produce a configure script.
 
 divert(1)
@@ -569,6 +569,9 @@
   AC_TRY_RUN([
 #include <netdb.h>
 #include <sys/types.h>
+#ifndef AF_INET
+# include <sys/socket.h>
+#endif
 int main(void) {
   struct addrinfo *ai, *pai, hints;
 
@@ -788,6 +791,19 @@
 if test "$PHP_IPV6" != "no" && test "$ac_cv_ipv6_support" = yes; then
   AC_DEFINE(HAVE_IPV6,1,[Whether to enable IPv6 support])
 fi
+
+AC_MSG_CHECKING([how big to make fd sets])
+AC_ARG_ENABLE(fd-setsize,
+[  --enable-fd-setsize     Set size of descriptor sets],[
+  if test "x$enableval" != "xyes"; then
+    CPPFLAGS="$CPPFLAGS -DFD_SETSIZE=$enableval"
+    AC_MSG_RESULT(using $enableval)
+  else
+    AC_MSG_RESULT(using system default)
+  fi
+],[
+  AC_MSG_RESULT(using system default)
+])
 
 AC_MSG_CHECKING([whether to enable versioning])
 AC_ARG_ENABLE(versioning,
http://cvs.php.net/diff.php/php-src/ext/ftp/ftp.c?r1=1.103&r2=1.104&ty=u
Index: php-src/ext/ftp/ftp.c
diff -u php-src/ext/ftp/ftp.c:1.103 php-src/ext/ftp/ftp.c:1.104
--- php-src/ext/ftp/ftp.c:1.103 Wed Mar 31 15:43:40 2004
+++ php-src/ext/ftp/ftp.c       Fri Sep 17 08:44:55 2004
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: ftp.c,v 1.103 2004/03/31 20:43:40 iliaa Exp $ */
+/* $Id: ftp.c,v 1.104 2004/09/17 12:44:55 wez Exp $ */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -1236,19 +1236,11 @@
 int
 my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
 {
-       fd_set          write_set;
-       struct timeval  tv;
        int             n, size, sent;
 
        size = len;
        while (size) {
-               tv.tv_sec = ftp->timeout_sec;
-               tv.tv_usec = 0;
-
-               FD_ZERO(&write_set);
-               FD_SET(s, &write_set);
-
-               n = select(s + 1, NULL, &write_set, NULL, &tv);
+               n = php_pollfd_for_ms(s, POLLOUT, ftp->timeout_sec * 1000);
 
                if (n < 1) {
 
@@ -1288,17 +1280,9 @@
 int
 my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
 {
-       fd_set          read_set;
-       struct timeval  tv;
        int             n, nr_bytes;
 
-       tv.tv_sec = ftp->timeout_sec;
-       tv.tv_usec = 0;
-
-       FD_ZERO(&read_set);
-       FD_SET(s, &read_set);
-
-       n = select(s + 1, &read_set, NULL, NULL, &tv);
+       n = php_pollfd_for_ms(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
        if (n < 1) {
 #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
                if (n == 0) {
@@ -1328,16 +1312,9 @@
 int
 data_available(ftpbuf_t *ftp, php_socket_t s)
 {
-       fd_set          read_set;
-       struct timeval  tv;
        int             n;
 
-       tv.tv_sec = 0;
-       tv.tv_usec = 1;
-
-       FD_ZERO(&read_set);
-       FD_SET(s, &read_set);
-       n = select(s + 1, &read_set, NULL, NULL, &tv);
+       n = php_pollfd_for_ms(s, PHP_POLLREADABLE, 1000);
        if (n < 1) {
 #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
                if (n == 0) {
@@ -1355,16 +1332,9 @@
 int
 data_writeable(ftpbuf_t *ftp, php_socket_t s)
 {
-       fd_set          write_set;
-       struct timeval  tv;
        int             n;
 
-       tv.tv_sec = 0;
-       tv.tv_usec = 1;
-
-       FD_ZERO(&write_set);
-       FD_SET(s, &write_set);
-       n = select(s + 1, NULL, &write_set, NULL, &tv);
+       n = php_pollfd_for_ms(s, POLLOUT, 1000);
        if (n < 1) {
 #ifndef PHP_WIN32
                if (n == 0) {
@@ -1383,16 +1353,9 @@
 int
 my_accept(ftpbuf_t *ftp, php_socket_t s, struct sockaddr *addr, socklen_t *addrlen)
 {
-       fd_set          accept_set;
-       struct timeval  tv;
        int             n;
 
-       tv.tv_sec = ftp->timeout_sec;
-       tv.tv_usec = 0;
-       FD_ZERO(&accept_set);
-       FD_SET(s, &accept_set);
-
-       n = select(s + 1, &accept_set, NULL, NULL, &tv);
+       n = php_pollfd_for_ms(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
        if (n < 1) {
 #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
                if (n == 0) {
http://cvs.php.net/diff.php/php-src/ext/openssl/xp_ssl.c?r1=1.17&r2=1.18&ty=u
Index: php-src/ext/openssl/xp_ssl.c
diff -u php-src/ext/openssl/xp_ssl.c:1.17 php-src/ext/openssl/xp_ssl.c:1.18
--- php-src/ext/openssl/xp_ssl.c:1.17   Fri Sep 10 07:43:46 2004
+++ php-src/ext/openssl/xp_ssl.c        Fri Sep 17 08:44:55 2004
@@ -16,7 +16,7 @@
   +----------------------------------------------------------------------+
 */
 
-/* $Id: xp_ssl.c,v 1.17 2004/09/10 11:43:46 wez Exp $ */
+/* $Id: xp_ssl.c,v 1.18 2004/09/17 12:44:55 wez Exp $ */
 
 #include "php.h"
 #include "ext/standard/file.h"
@@ -235,9 +235,7 @@
 {
        php_openssl_netstream_data_t *sslsock = 
(php_openssl_netstream_data_t*)stream->abstract;
 #ifdef PHP_WIN32
-       fd_set wrfds, efds;
        int n;
-       struct timeval timeout;
 #endif
        if (close_handle) {
                if (sslsock->ssl_active) {
@@ -248,7 +246,7 @@
                        SSL_free(sslsock->ssl_handle);
                        sslsock->ssl_handle = NULL;
                }
-               if (sslsock->s.socket != -1) {
+               if (sslsock->s.socket != SOCK_ERR) {
 #ifdef PHP_WIN32
                        /* prevent more data from coming in */
                        shutdown(sslsock->s.socket, SHUT_RD);
@@ -260,19 +258,11 @@
                         * but at the same time avoid hanging indefintely.
                         * */
                        do {
-                               FD_ZERO(&wrfds);
-                               FD_SET(sslsock->s.socket, &wrfds);
-                               efds = wrfds;
-
-                               timeout.tv_sec = 0;
-                               timeout.tv_usec = 5000; /* arbitrary */
-
-                               n = select(sslsock->s.socket + 1, NULL, &wrfds, &efds, 
&timeout);
+                               n = php_pollfd_for_ms(sslsock->s.socket, POLLOUT, 500);
                        } while (n == -1 && php_socket_errno() == EINTR);
 #endif
-
                        closesocket(sslsock->s.socket);
-                       sslsock->s.socket = -1;
+                       sslsock->s.socket = SOCK_ERR;
                }
        }
 
@@ -512,47 +502,48 @@
                                char buf;
                                int alive = 1;
 
-                               if (sslsock->s.timeout.tv_sec == -1) {
-                                       tv.tv_sec = FG(default_socket_timeout);
+                               if (value == -1) {
+                                       if (sslsock->s.timeout.tv_sec == -1) {
+                                               tv.tv_sec = FG(default_socket_timeout);
+                                               tv.tv_usec = 0;
+                                       } else {
+                                               tv = sslsock->s.timeout;
+                                       }
                                } else {
-                                       tv = sslsock->s.timeout;
+                                       tv.tv_sec = value;
+                                       tv.tv_usec = 0;
                                }
 
                                if (sslsock->s.socket == -1) {
                                        alive = 0;
-                               } else {
-                                       FD_ZERO(&rfds);
-                                       FD_SET(sslsock->s.socket, &rfds);
-
-                                       if (select(sslsock->s.socket + 1, &rfds, NULL, 
NULL, &tv) > 0 && FD_ISSET(sslsock->s.socket, &rfds)) {
-                                               if (sslsock->ssl_active) {
-                                                       int n;
-
-                                                       do {
-                                                               n = 
SSL_peek(sslsock->ssl_handle, &buf, sizeof(buf));
-                                                               if (n <= 0) {
-                                                                       int err = 
SSL_get_error(sslsock->ssl_handle, n);
-
-                                                                       if (err == 
SSL_ERROR_SYSCALL) {
-                                                                               alive 
= php_socket_errno() == EAGAIN;
-                                                                               break;
-                                                                       }
-
-                                                                       if (err == 
SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
-                                                                               /* 
re-negotiate */
-                                                                               
continue;
-                                                                       }
+                               } else if (php_pollfd_for(sslsock->s.socket, 
PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
+                                       if (sslsock->ssl_active) {
+                                               int n;
+
+                                               do {
+                                                       n = 
SSL_peek(sslsock->ssl_handle, &buf, sizeof(buf));
+                                                       if (n <= 0) {
+                                                               int err = 
SSL_get_error(sslsock->ssl_handle, n);
+
+                                                               if (err == 
SSL_ERROR_SYSCALL) {
+                                                                       alive = 
php_socket_errno() == EAGAIN;
+                                                                       break;
+                                                               }
 
-                                                                       /* any other 
problem is a fatal error */
-                                                                       alive = 0;
+                                                               if (err == 
SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
+                                                                       /* 
re-negotiate */
+                                                                       continue;
                                                                }
-                                                               /* either peek 
succeeded or there was an error; we
-                                                                * have set the alive 
flag appropriately */
-                                                               break;
-                                                       } while (1);
-                                               } else if (0 == 
recv(sslsock->s.socket, &buf, sizeof(buf), MSG_PEEK) && php_socket_errno() != EAGAIN) {
-                                                       alive = 0;
-                                               }
+
+                                                               /* any other problem 
is a fatal error */
+                                                               alive = 0;
+                                                       }
+                                                       /* either peek succeeded or 
there was an error; we
+                                                        * have set the alive flag 
appropriately */
+                                                       break;
+                                               } while (1);
+                                       } else if (0 == recv(sslsock->s.socket, &buf, 
sizeof(buf), MSG_PEEK) && php_socket_errno() != EAGAIN) {
+                                               alive = 0;
                                        }
                                }
                                return alive ? PHP_STREAM_OPTION_RETURN_OK : 
PHP_STREAM_OPTION_RETURN_ERR;
http://cvs.php.net/diff.php/php-src/ext/soap/php_http.c?r1=1.55&r2=1.56&ty=u
Index: php-src/ext/soap/php_http.c
diff -u php-src/ext/soap/php_http.c:1.55 php-src/ext/soap/php_http.c:1.56
--- php-src/ext/soap/php_http.c:1.55    Tue Jun 22 08:42:17 2004
+++ php-src/ext/soap/php_http.c Fri Sep 17 08:44:55 2004
@@ -17,7 +17,7 @@
   |          Dmitry Stogov <[EMAIL PROTECTED]>                             |
   +----------------------------------------------------------------------+
 */
-/* $Id: php_http.c,v 1.55 2004/06/22 12:42:17 dmitry Exp $ */
+/* $Id: php_http.c,v 1.56 2004/09/17 12:44:55 wez Exp $ */
 
 #include "php_soap.h"
 #include "ext/standard/base64.h"
@@ -32,21 +32,19 @@
 static int stream_alive(php_stream *stream  TSRMLS_DC)
 {
        int socket;
-       fd_set rfds;
-       struct timeval tv;
        char buf;
 
+       /* maybe better to use:
+        * php_stream_set_option(stream, PHP_STREAM_OPTION_CHECK_LIVENESS, 0, NULL)
+        * here instead */
+
        if (stream == NULL || stream->eof || php_stream_cast(stream, 
PHP_STREAM_AS_FD_FOR_SELECT, (void**)&socket, 0) != SUCCESS) {
                return FALSE;
        }
        if (socket == -1) {
                return FALSE;
        } else {
-               FD_ZERO(&rfds);
-               FD_SET(socket, &rfds);
-               tv.tv_sec = 0;
-               tv.tv_usec = 0;
-               if (select(socket + 1, &rfds, NULL, NULL, &tv) > 0 && FD_ISSET(socket, 
&rfds)) {
+               if (php_pollfd_for_ms(socket, PHP_POLLREADABLE, 0) > 0) {
                        if (0 == recv(socket, &buf, sizeof(buf), MSG_PEEK) && 
php_socket_errno() != EAGAIN) {
                                return FALSE;
                        }
http://cvs.php.net/diff.php/php-src/ext/sockets/sockets.c?r1=1.165&r2=1.166&ty=u
Index: php-src/ext/sockets/sockets.c
diff -u php-src/ext/sockets/sockets.c:1.165 php-src/ext/sockets/sockets.c:1.166
--- php-src/ext/sockets/sockets.c:1.165 Mon Jun  7 01:00:37 2004
+++ php-src/ext/sockets/sockets.c       Fri Sep 17 08:44:56 2004
@@ -19,7 +19,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: sockets.c,v 1.165 2004/06/07 05:00:37 pollita Exp $ */
+/* $Id: sockets.c,v 1.166 2004/09/17 12:44:56 wez Exp $ */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -533,7 +533,7 @@
                php_sock = (php_socket*) zend_fetch_resource(element TSRMLS_CC, -1, 
le_socket_name, NULL, 1, le_socket);
                if (!php_sock) continue; /* If element is not a resource, skip it */
 
-               FD_SET(php_sock->bsd_socket, fds);
+               PHP_SAFE_FD_SET(php_sock->bsd_socket, fds);
                if (php_sock->bsd_socket > *max_fd) {
                        *max_fd = php_sock->bsd_socket;
                }
@@ -560,7 +560,7 @@
                php_sock = (php_socket*) zend_fetch_resource(element TSRMLS_CC, -1, 
le_socket_name, NULL, 1, le_socket);
                if (!php_sock) continue; /* If element is not a resource, skip it */
 
-               if (FD_ISSET(php_sock->bsd_socket, fds)) {
+               if (PHP_SAFE_FD_ISSET(php_sock->bsd_socket, fds)) {
                        /* Add fd to new array */
                        zend_hash_next_index_insert(new_hash, (void *)element, 
sizeof(zval *), (void **)&dest_element);
                        if (dest_element) zval_add_ref(dest_element);
@@ -604,6 +604,8 @@
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "no resource arrays were 
passed to select");
                RETURN_FALSE;
        }
+
+       PHP_SAFE_MAX_FD(max_fd, 0); /* someone needs to make this look more like 
stream_socket_select */
 
        /* If seconds is not set to null, build the timeval, else we wait indefinitely 
*/
        if (sec != NULL) {
http://cvs.php.net/diff.php/php-src/ext/standard/streamsfuncs.c?r1=1.41&r2=1.42&ty=u
Index: php-src/ext/standard/streamsfuncs.c
diff -u php-src/ext/standard/streamsfuncs.c:1.41 
php-src/ext/standard/streamsfuncs.c:1.42
--- php-src/ext/standard/streamsfuncs.c:1.41    Mon Sep 13 23:48:16 2004
+++ php-src/ext/standard/streamsfuncs.c Fri Sep 17 08:44:56 2004
@@ -17,7 +17,7 @@
   +----------------------------------------------------------------------+
 */
 
-/* $Id: streamsfuncs.c,v 1.41 2004/09/14 03:48:16 pollita Exp $ */
+/* $Id: streamsfuncs.c,v 1.42 2004/09/17 12:44:56 wez Exp $ */
 
 #include "php.h"
 #include "php_globals.h"
@@ -217,7 +217,7 @@
 
        if (peername) {
                zval_dtor(peername);
-               ZVAL_STRING(peername, "", 1);
+               ZVAL_STRING(peername, NULL, 0);
        }
 
        if (0 == php_stream_xport_accept(stream, &clistream,
@@ -237,6 +237,10 @@
        if (errstr) {
                efree(errstr);
        }
+
+       if (peername && Z_STRVAL_P(peername) == NULL) {
+               ZVAL_STRING(peername, "", 1);
+       }
 }
 /* }}} */
 
@@ -543,7 +547,9 @@
                 * is not displayed.
                 * */
                if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | 
PHP_STREAM_CAST_INTERNAL, (void*)&this_fd, 1) && this_fd >= 0) {
-                       FD_SET(this_fd, fds);
+                       
+                       PHP_SAFE_FD_SET(this_fd, fds);
+
                        if (this_fd > *max_fd) {
                                *max_fd = this_fd;
                        }
@@ -579,7 +585,7 @@
                 * is not displayed.
                 */
                if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | 
PHP_STREAM_CAST_INTERNAL, (void*)&this_fd, 1) && this_fd >= 0) {
-                       if (FD_ISSET(this_fd, fds)) {
+                       if (PHP_SAFE_FD_ISSET(this_fd, fds)) {
                                zend_hash_next_index_insert(new_hash, (void *)elem, 
sizeof(zval *), (void **)&dest_elem);
                                if (dest_elem) {
                                        zval_add_ref(dest_elem);
@@ -664,6 +670,7 @@
        int                             max_fd = 0;
        int                             retval, sets = 0;
        long                    usec = 0;
+       int                             set_count, max_set_count = 0;
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!a!a!z!|l", &r_array, 
&w_array, &e_array, &sec, &usec) == FAILURE)
                return;
@@ -672,14 +679,33 @@
        FD_ZERO(&wfds);
        FD_ZERO(&efds);
 
-       if (r_array != NULL) sets += stream_array_to_fd_set(r_array, &rfds, &max_fd 
TSRMLS_CC);
-       if (w_array != NULL) sets += stream_array_to_fd_set(w_array, &wfds, &max_fd 
TSRMLS_CC);
-       if (e_array != NULL) sets += stream_array_to_fd_set(e_array, &efds, &max_fd 
TSRMLS_CC);
+       if (r_array != NULL) {
+               set_count = stream_array_to_fd_set(r_array, &rfds, &max_fd TSRMLS_CC);
+               if (set_count > max_set_count)
+                       max_set_count = set_count;
+               sets += set_count;
+       }
+       
+       if (w_array != NULL) {
+               set_count = stream_array_to_fd_set(w_array, &wfds, &max_fd TSRMLS_CC);
+               if (set_count > max_set_count)
+                       max_set_count = set_count;
+               sets += set_count;
+       }
+
+       if (e_array != NULL) {
+               set_count = stream_array_to_fd_set(e_array, &efds, &max_fd TSRMLS_CC);
+               if (set_count > max_set_count)
+                       max_set_count = set_count;
+               sets += set_count;
+       }
 
        if (!sets) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "No stream arrays were 
passed");
                RETURN_FALSE;
        }
+
+       PHP_SAFE_MAX_FD(max_fd, max_set_count);
 
        /* If seconds is not set to null, build the timeval, else we wait indefinitely 
*/
        if (sec != NULL) {
http://cvs.php.net/diff.php/php-src/main/network.c?r1=1.111&r2=1.112&ty=u
Index: php-src/main/network.c
diff -u php-src/main/network.c:1.111 php-src/main/network.c:1.112
--- php-src/main/network.c:1.111        Wed Jul 28 19:30:23 2004
+++ php-src/main/network.c      Fri Sep 17 08:44:56 2004
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: network.c,v 1.111 2004/07/28 23:30:23 wez Exp $ */
+/* $Id: network.c,v 1.112 2004/09/17 12:44:56 wez Exp $ */
 
 /*#define DEBUG_MAIN_NETWORK 1*/
 
@@ -295,9 +295,6 @@
        int error = 0;
        socklen_t len;
        int ret = 0;
-       fd_set rset;
-       fd_set wset;
-       fd_set eset;
 
        SET_SOCKET_BLOCKING_MODE(sockfd, orig_flags);
        
@@ -325,18 +322,11 @@
                goto ok;
        }
 
-       FD_ZERO(&rset);
-       FD_ZERO(&eset);
-       FD_SET(sockfd, &rset);
-       FD_SET(sockfd, &eset);
-
-       wset = rset;
-
-       if ((n = select(sockfd + 1, &rset, &wset, &eset, timeout)) == 0) {
+       if ((n = php_pollfd_for(sockfd, PHP_POLLREADABLE|POLLOUT, timeout)) == 0) {
                error = PHP_TIMEOUT_ERROR_VALUE;
        }
 
-       if(FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
+       if (n > 0) {
                len = sizeof(error);
                /*
                   BSD-derived systems set errno correctly
@@ -692,21 +682,17 @@
                TSRMLS_DC)
 {
        php_socket_t clisock = -1;
-       fd_set rset;
        int error = 0, n;
        php_sockaddr_storage sa;
        socklen_t sl;
-
-       FD_ZERO(&rset);
-       FD_SET(srvsock, &rset);
                
-       n = select(srvsock + 1, &rset, NULL, NULL, timeout);
+       n = php_pollfd_for(srvsock, PHP_POLLREADABLE, timeout);
 
        if (n == 0) {
                error = PHP_TIMEOUT_ERROR_VALUE;
        } else if (n == -1) {
                error = php_socket_errno();
-       } else if (FD_ISSET(srvsock, &rset)) {
+       } else {
                sl = sizeof(sa);
 
                clisock = accept(srvsock, (struct sockaddr*)&sa, &sl);
@@ -1025,6 +1011,104 @@
 #endif
       return ret;
 }
+
+PHPAPI void _php_emit_fd_setsize_warning(int max_fd)
+{
+       TSRMLS_FETCH();
+
+#ifdef PHP_WIN32
+       php_error_docref(NULL TSRMLS_CC, E_WARNING,
+               "PHP needs to be recompiled with a larger value of FD_SETSIZE.\n"
+               "If this binary is from an official www.php.net package, file a bug 
report\n"
+               "at http://bugs.php.net, including the following information:\n"
+               "FD_SETSIZE=%d, but you are using %d.\n"
+               " --enable-fd-setsize=%d is recommended, but you may want to set it\n"
+               "to match to maximum number of sockets each script will work with at\n"
+               "one time, in order to avoid seeing this error again at a later date.",
+               FD_SETSIZE, max_fd, (max_fd + 128) & ~127);
+#else
+       php_error_docref(NULL TSRMLS_CC, E_WARNING,
+               "You MUST recompile PHP with a larger value of FD_SETSIZE.\n"
+               "It is set to %d, but you have descriptors numbered at least as high 
as %d.\n"
+               " --enable-fd-setsize=%d is recommended, but you may want to set it\n"
+               "to equal the maximum number of open files supported by your system,\n"
+               "in order to avoid seeing this error again at a later date.",
+               FD_SETSIZE, max_fd, (max_fd + 1024) & ~1023);
+#endif
+}
+
+#if defined(PHP_USE_POLL_2_EMULATION)
+
+/* emulate poll(2) using select(2), safely. */
+
+PHPAPI int php_poll2(php_pollfd *ufds, unsigned int nfds, int timeout)
+{
+       fd_set rset, wset, eset;
+       php_socket_t max_fd = SOCK_ERR;
+       unsigned int i, n;
+       struct timeval tv;
+       
+       /* check the highest numbered descriptor */
+       for (i = 0; i < nfds; i++) {
+               if (ufds[i].fd > max_fd)
+                       max_fd = ufds[i].fd;
+       }
+
+       PHP_SAFE_MAX_FD(max_fd, nfds + 1);
+
+       FD_ZERO(&rset);
+       FD_ZERO(&wset);
+       FD_ZERO(&eset);
+
+       for (i = 0; i < nfds; i++) {
+               if (ufds[i].fd >= FD_SETSIZE) {
+                       /* unsafe to set */
+                       ufds[i].revents = POLLNVAL;
+                       continue;
+               }
+               if (ufds[i].events & PHP_POLLREADABLE) {
+                       FD_SET(ufds[i].fd, &rset);
+               }
+               if (ufds[i].events & POLLOUT) {
+                       FD_SET(ufds[i].fd, &wset);
+               }
+               if (ufds[i].events & POLLPRI) {
+                       FD_SET(ufds[i].fd, &eset);
+               }
+       }
+
+       if (timeout >= 0) {
+               tv.tv_sec = timeout / 1000;
+               tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000;
+       }
+
+       n = select(max_fd + 1, &rset, &wset, &eset, timeout >= 0 ? &tv : NULL);
+
+       if (n >= 0) {
+               for (i = 0; i < nfds; i++) {
+                       if (ufds[i].fd >= FD_SETSIZE) {
+                               continue;
+                       }
+
+                       ufds[i].revents = 0;
+
+                       if (FD_ISSET(ufds[i].fd, &rset)) {
+                               /* could be POLLERR or POLLHUP but can't tell without 
probing */
+                               ufds[i].revents |= POLLIN;
+                       }
+                       if (FD_ISSET(ufds[i].fd, &wset)) {
+                               ufds[i].revents |= POLLOUT;
+                       }
+                       if (FD_ISSET(ufds[i].fd, &eset)) {
+                               ufds[i].revents |= POLLPRI;
+                       }
+               }
+       }
+
+       return n;
+}
+
+#endif
 
 
 /*
http://cvs.php.net/diff.php/php-src/main/php_network.h?r1=1.52&r2=1.53&ty=u
Index: php-src/main/php_network.h
diff -u php-src/main/php_network.h:1.52 php-src/main/php_network.h:1.53
--- php-src/main/php_network.h:1.52     Fri Feb 20 03:04:30 2004
+++ php-src/main/php_network.h  Fri Sep 17 08:44:56 2004
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: php_network.h,v 1.52 2004/02/20 08:04:30 hholzgra Exp $ */
+/* $Id: php_network.h,v 1.53 2004/09/17 12:44:56 wez Exp $ */
 
 #ifndef _PHP_NETWORK_H
 #define _PHP_NETWORK_H
@@ -105,6 +105,104 @@
 # define SOCK_CONN_ERR -1
 # define SOCK_RECV_ERR -1
 #endif
+
+/* uncomment this to debug poll(2) emulation on systems that have poll(2) */
+/* #define PHP_USE_POLL_2_EMULATION 1 */
+
+#if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
+# include <sys/poll.h>
+typedef struct pollfd php_pollfd;
+#else
+typedef struct _php_pollfd {
+       php_socket_t fd;
+       short events;
+       short revents;
+} php_pollfd;
+
+PHPAPI int php_poll2(php_pollfd *ufds, unsigned int nfds, int timeout);
+
+# define POLLIN      0x0001    /* There is data to read */
+# define POLLPRI     0x0002    /* There is urgent data to read */
+# define POLLOUT     0x0004    /* Writing now will not block */
+# define POLLERR     0x0008    /* Error condition */
+# define POLLHUP     0x0010    /* Hung up */
+# define POLLNVAL    0x0020    /* Invalid request: fd not open */
+
+# ifndef PHP_USE_POLL_2_EMULATION
+#  define PHP_USE_POLL_2_EMULATION 1
+# endif
+#endif
+
+#define PHP_POLLREADABLE       (POLLIN|POLLERR|POLLHUP)
+
+#ifndef PHP_USE_POLL_2_EMULATION
+# define php_poll2(ufds, nfds, timeout)                poll(ufds, nfds, timeout)
+#endif
+
+/* timeval-to-timeout (for poll(2)) */
+static inline int php_tvtoto(struct timeval *timeouttv)
+{
+       if (timeouttv) {
+               return (timeouttv->tv_sec * 1000) + (timeouttv->tv_usec / 1000);
+       }
+       return -1;
+}
+
+/* hybrid select(2)/poll(2) for a single descriptor.
+ * timeouttv follows same rules as select(2), but is reduced to millisecond accuracy.
+ * Returns 0 on timeout, -1 on error, or the event mask (ala poll(2)).
+ */
+static inline int php_pollfd_for(php_socket_t fd, int events, struct timeval 
*timeouttv)
+{
+       php_pollfd p;
+       int n;
+
+       p.fd = fd;
+       p.events = events;
+       p.revents = 0;
+
+       n = php_poll2(&p, 1, php_tvtoto(timeouttv));
+
+       if (n > 0) {
+               return p.revents;
+       }
+
+       return n;
+}
+
+static inline int php_pollfd_for_ms(php_socket_t fd, int events, int timeout)
+{
+       php_pollfd p;
+       int n;
+
+       p.fd = fd;
+       p.events = events;
+       p.revents = 0;
+
+       n = php_poll2(&p, 1, timeout);
+
+       if (n > 0) {
+               return p.revents;
+       }
+
+       return n;
+}
+
+/* emit warning and suggestion for unsafe select(2) usage */
+PHPAPI void _php_emit_fd_setsize_warning(int max_fd);
+
+#ifdef PHP_WIN32
+/* it is safe to FD_SET too many fd's under win32; the macro will simply ignore
+ * descriptors that go beyond the default FD_SETSIZE */
+# define PHP_SAFE_FD_SET(fd, set)      FD_SET(fd, set)
+# define PHP_SAFE_FD_ISSET(fd, set)    FD_ISSET(fd, set)
+# define PHP_SAFE_MAX_FD(m, n)         do { if (n + 1 >= FD_SETSIZE) { 
_php_emit_fd_setsize_warning(n); }} while(0)
+#else
+# define PHP_SAFE_FD_SET(fd, set)      do { if (fd < FD_SETSIZE) FD_SET(fd, set); } 
while(0)
+# define PHP_SAFE_FD_ISSET(fd, set)    ((fd < FD_SETSIZE) && FD_ISSET(fd, set))
+# define PHP_SAFE_MAX_FD(m, n)         do { if (m >= FD_SETSIZE) { 
_php_emit_fd_setsize_warning(m); m = FD_SETSIZE - 1; }} while(0)
+#endif
+
 
 #define PHP_SOCK_CHUNK_SIZE    8192
 
http://cvs.php.net/diff.php/php-src/main/streams/xp_socket.c?r1=1.28&r2=1.29&ty=u
Index: php-src/main/streams/xp_socket.c
diff -u php-src/main/streams/xp_socket.c:1.28 php-src/main/streams/xp_socket.c:1.29
--- php-src/main/streams/xp_socket.c:1.28       Sun Aug 22 14:05:24 2004
+++ php-src/main/streams/xp_socket.c    Fri Sep 17 08:44:56 2004
@@ -16,7 +16,7 @@
   +----------------------------------------------------------------------+
 */
 
-/* $Id: xp_socket.c,v 1.28 2004/08/22 18:05:24 iliaa Exp $ */
+/* $Id: xp_socket.c,v 1.29 2004/09/17 12:44:56 wez Exp $ */
 
 #include "php.h"
 #include "ext/standard/file.h"
@@ -47,11 +47,17 @@
 {
        php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
        int didwrite;
+       struct timeval *ptimeout;
 
        if (sock->socket == -1) {
                return 0;
        }
 
+       if (sock->timeout.tv_sec == -1)
+               ptimeout = NULL;
+       else
+               ptimeout = &sock->timeout;
+
 retry:
        didwrite = send(sock->socket, buf, count, 0);
 
@@ -60,24 +66,12 @@
                char *estr;
 
                if (sock->is_blocked && err == EWOULDBLOCK) {
-                       fd_set fdw, tfdw;
                        int retval;
-                       struct timeval timeout, *ptimeout;
 
-                       FD_ZERO(&fdw);
-                       FD_SET(sock->socket, &fdw);
                        sock->timeout_event = 0;
 
-                       if (sock->timeout.tv_sec == -1)
-                               ptimeout = NULL;
-                       else
-                               ptimeout = &timeout;
-
                        do {
-                               tfdw = fdw;
-                               timeout = sock->timeout;
-
-                               retval = select(sock->socket + 1, NULL, &tfdw, NULL, 
ptimeout);
+                               retval = php_pollfd_for(sock->socket, POLLOUT, 
ptimeout);
 
                                if (retval == 0) {
                                        sock->timeout_event = 1;
@@ -111,29 +105,22 @@
 
 static void php_sock_stream_wait_for_data(php_stream *stream, php_netstream_data_t 
*sock TSRMLS_DC)
 {
-       fd_set fdr, tfdr;
        int retval;
-       struct timeval timeout, *ptimeout;
+       struct timeval *ptimeout;
 
        if (sock->socket == -1) {
                return;
        }
        
-       FD_ZERO(&fdr);
-       FD_SET(sock->socket, &fdr);
        sock->timeout_event = 0;
 
        if (sock->timeout.tv_sec == -1)
                ptimeout = NULL;
        else
-               ptimeout = &timeout;
-
+               ptimeout = &sock->timeout;
 
        while(1) {
-               tfdr = fdr;
-               timeout = sock->timeout;
-
-               retval = select(sock->socket + 1, &tfdr, NULL, NULL, ptimeout);
+               retval = php_pollfd_for(sock->socket, PHP_POLLREADABLE, ptimeout);
 
                if (retval == 0)
                        sock->timeout_event = 1;
@@ -178,14 +165,12 @@
 {
        php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
 #ifdef PHP_WIN32
-       fd_set wrfds, efds;
        int n;
-       struct timeval timeout;
 #endif
 
        if (close_handle) {
 
-               if (sock->socket != -1) {
+               if (sock->socket != SOCK_ERR) {
 #ifdef PHP_WIN32
                        /* prevent more data from coming in */
                        shutdown(sock->socket, SHUT_RD);
@@ -197,19 +182,11 @@
                         * but at the same time avoid hanging indefintely.
                         * */
                        do {
-                               FD_ZERO(&wrfds);
-                               FD_SET(sock->socket, &wrfds);
-                               efds = wrfds;
-
-                               timeout.tv_sec = 0;
-                               timeout.tv_usec = 5000; /* arbitrary */
-
-                               n = select(sock->socket + 1, NULL, &wrfds, &efds, 
&timeout);
+                               n = php_pollfd_for_ms(sock->socket, POLLOUT, 500);
                        } while (n == -1 && php_socket_errno() == EINTR);
 #endif
-
                        closesocket(sock->socket);
-                       sock->socket = -1;
+                       sock->socket = SOCK_ERR;
                }
 
        }
@@ -274,7 +251,6 @@
        switch(option) {
                case PHP_STREAM_OPTION_CHECK_LIVENESS:
                        {
-                               fd_set rfds;
                                struct timeval tv;
                                char buf;
                                int alive = 1;
@@ -293,14 +269,9 @@
 
                                if (sock->socket == -1) {
                                        alive = 0;
-                               } else {
-                                       FD_ZERO(&rfds);
-                                       FD_SET(sock->socket, &rfds);
-
-                                       if (select(sock->socket + 1, &rfds, NULL, 
NULL, &tv) > 0 && FD_ISSET(sock->socket, &rfds)) {
-                                               if (0 == recv(sock->socket, &buf, 
sizeof(buf), MSG_PEEK) && php_socket_errno() != EAGAIN) {
-                                                       alive = 0;
-                                               }
+                               } else if (php_pollfd_for(sock->socket, 
PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
+                                       if (0 == recv(sock->socket, &buf, sizeof(buf), 
MSG_PEEK) && php_socket_errno() != EAGAIN) {
+                                               alive = 0;
                                        }
                                }
                                return alive ? PHP_STREAM_OPTION_RETURN_OK : 
PHP_STREAM_OPTION_RETURN_ERR;
http://cvs.php.net/diff.php/php-src/win32/build/config.w32?r1=1.30&r2=1.31&ty=u
Index: php-src/win32/build/config.w32
diff -u php-src/win32/build/config.w32:1.30 php-src/win32/build/config.w32:1.31
--- php-src/win32/build/config.w32:1.30 Mon Aug  2 21:03:32 2004
+++ php-src/win32/build/config.w32      Fri Sep 17 08:44:56 2004
@@ -1,5 +1,5 @@
 // vim:ft=javascript
-// $Id: config.w32,v 1.30 2004/08/03 01:03:32 wez Exp $
+// $Id: config.w32,v 1.31 2004/09/17 12:44:56 wez Exp $
 // "Master" config file; think of it as a configure.in
 // equivalent.
 
@@ -215,11 +215,17 @@
 AC_DEFINE('HAVE_GAI_STRERROR', main_network_has_ipv6);
 AC_DEFINE('HAVE_IPV6', main_network_has_ipv6);
 
+/* this allows up to 256 sockets to be select()ed in a single
+ * call to select(), instead of the usual 64 */
+ARG_ENABLE('fd-setsize', "Set maximum number of sockets for select(2)", "256");
+AC_DEFINE('FD_SETSIZE', PHP_FD_SETSIZE);
+
 ARG_ENABLE("memory-limit", "Enable memory limit checking code", "no");
 
 AC_DEFINE('MEMORY_LIMIT', PHP_MEMORY_LIMIT == "yes" ? 1 : 0);
 
 AC_DEFINE('HAVE_USLEEP', 1);
+AC_DEFINE('HAVE_STRCOLL', 1);
 
 /* For snapshot builders, where can we find the additional
  * files that make up the snapshot template? */

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to