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