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