wez             Tue Sep 28 05:13:40 2004 EDT

  Modified files:              (Branch: PHP_5_0)
    /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/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:
  MFH: Fix for Bug #24189: possibly unsafe select(2) usage.
  
  
http://cvs.php.net/diff.php/php-src/configure.in?r1=1.514.2.10&r2=1.514.2.11&ty=u
Index: php-src/configure.in
diff -u php-src/configure.in:1.514.2.10 php-src/configure.in:1.514.2.11
--- php-src/configure.in:1.514.2.10     Sat Sep 25 21:13:43 2004
+++ php-src/configure.in        Tue Sep 28 05:13:32 2004
@@ -1,4 +1,4 @@
-dnl ## $Id: configure.in,v 1.514.2.10 2004/09/26 01:13:43 wez Exp $ -*- sh -*-
+dnl ## $Id: configure.in,v 1.514.2.11 2004/09/28 09:13:32 wez Exp $ -*- sh -*-
 dnl ## Process this file with autoconf to produce a configure script.
 
 divert(1)
@@ -767,6 +767,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.103.2.1&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.103.2.1
--- php-src/ext/ftp/ftp.c:1.103 Wed Mar 31 15:43:40 2004
+++ php-src/ext/ftp/ftp.c       Tue Sep 28 05:13:35 2004
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: ftp.c,v 1.103 2004/03/31 20:43:40 iliaa Exp $ */
+/* $Id: ftp.c,v 1.103.2.1 2004/09/28 09:13:35 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.16.2.1&r2=1.16.2.2&ty=u
Index: php-src/ext/openssl/xp_ssl.c
diff -u php-src/ext/openssl/xp_ssl.c:1.16.2.1 php-src/ext/openssl/xp_ssl.c:1.16.2.2
--- php-src/ext/openssl/xp_ssl.c:1.16.2.1       Fri Sep 10 07:44:09 2004
+++ php-src/ext/openssl/xp_ssl.c        Tue Sep 28 05:13:36 2004
@@ -16,7 +16,7 @@
   +----------------------------------------------------------------------+
 */
 
-/* $Id: xp_ssl.c,v 1.16.2.1 2004/09/10 11:44:09 wez Exp $ */
+/* $Id: xp_ssl.c,v 1.16.2.2 2004/09/28 09:13:36 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.55.2.1&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.55.2.1
--- php-src/ext/soap/php_http.c:1.55    Tue Jun 22 08:42:17 2004
+++ php-src/ext/soap/php_http.c Tue Sep 28 05:13:36 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.55.2.1 2004/09/28 09:13:36 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/standard/streamsfuncs.c?r1=1.35.2.3&r2=1.35.2.4&ty=u
Index: php-src/ext/standard/streamsfuncs.c
diff -u php-src/ext/standard/streamsfuncs.c:1.35.2.3 
php-src/ext/standard/streamsfuncs.c:1.35.2.4
--- php-src/ext/standard/streamsfuncs.c:1.35.2.3        Fri Aug  6 10:18:49 2004
+++ php-src/ext/standard/streamsfuncs.c Tue Sep 28 05:13:36 2004
@@ -17,7 +17,7 @@
   +----------------------------------------------------------------------+
 */
 
-/* $Id: streamsfuncs.c,v 1.35.2.3 2004/08/06 14:18:49 wez Exp $ */
+/* $Id: streamsfuncs.c,v 1.35.2.4 2004/09/28 09:13:36 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.109.2.1&r2=1.109.2.2&ty=u
Index: php-src/main/network.c
diff -u php-src/main/network.c:1.109.2.1 php-src/main/network.c:1.109.2.2
--- php-src/main/network.c:1.109.2.1    Wed Jul 28 19:53:04 2004
+++ php-src/main/network.c      Tue Sep 28 05:13:37 2004
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: network.c,v 1.109.2.1 2004/07/28 23:53:04 wez Exp $ */
+/* $Id: network.c,v 1.109.2.2 2004/09/28 09:13:37 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,93 @@
 #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].events & PHP_POLLREADABLE) {
+                       PHP_SAFE_FD_SET(ufds[i].fd, &rset);
+               }
+               if (ufds[i].events & POLLOUT) {
+                       PHP_SAFE_FD_SET(ufds[i].fd, &wset);
+               }
+               if (ufds[i].events & POLLPRI) {
+                       PHP_SAFE_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++) {
+                       ufds[i].revents = 0;
+
+                       if (PHP_SAFE_FD_ISSET(ufds[i].fd, &rset)) {
+                               /* could be POLLERR or POLLHUP but can't tell without 
probing */
+                               ufds[i].revents |= POLLIN;
+                       }
+                       if (PHP_SAFE_FD_ISSET(ufds[i].fd, &wset)) {
+                               ufds[i].revents |= POLLOUT;
+                       }
+                       if (PHP_SAFE_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.52.2.1&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.52.2.1
--- php-src/main/php_network.h:1.52     Fri Feb 20 03:04:30 2004
+++ php-src/main/php_network.h  Tue Sep 28 05:13:37 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.52.2.1 2004/09/28 09:13:37 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.23.2.4&r2=1.23.2.5&ty=u
Index: php-src/main/streams/xp_socket.c
diff -u php-src/main/streams/xp_socket.c:1.23.2.4 
php-src/main/streams/xp_socket.c:1.23.2.5
--- php-src/main/streams/xp_socket.c:1.23.2.4   Sun Aug 22 14:05:27 2004
+++ php-src/main/streams/xp_socket.c    Tue Sep 28 05:13:37 2004
@@ -16,7 +16,7 @@
   +----------------------------------------------------------------------+
 */
 
-/* $Id: xp_socket.c,v 1.23.2.4 2004/08/22 18:05:27 iliaa Exp $ */
+/* $Id: xp_socket.c,v 1.23.2.5 2004/09/28 09:13:37 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,35 +105,31 @@
 
 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;
 
                if (retval >= 0)
                        break;
+
+               if (php_socket_errno() != EINTR)
+                       break;
        }
 }
 
@@ -178,14 +168,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 +185,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 +254,6 @@
        switch(option) {
                case PHP_STREAM_OPTION_CHECK_LIVENESS:
                        {
-                               fd_set rfds;
                                struct timeval tv;
                                char buf;
                                int alive = 1;
@@ -293,14 +272,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.26.2.2&r2=1.26.2.3&ty=u
Index: php-src/win32/build/config.w32
diff -u php-src/win32/build/config.w32:1.26.2.2 php-src/win32/build/config.w32:1.26.2.3
--- php-src/win32/build/config.w32:1.26.2.2     Sat Jul 31 20:35:11 2004
+++ php-src/win32/build/config.w32      Tue Sep 28 05:13:38 2004
@@ -1,5 +1,5 @@
 // vim:ft=javascript
-// $Id: config.w32,v 1.26.2.2 2004/08/01 00:35:11 wez Exp $
+// $Id: config.w32,v 1.26.2.3 2004/09/28 09:13:38 wez Exp $
 // "Master" config file; think of it as a configure.in
 // equivalent.
 
@@ -214,11 +214,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");
+ADD_FLAG("CFLAGS", "/D FD_SETSIZE=" + parseInt(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