summaryrefslogtreecommitdiff
path: root/main/php_network.h
diff options
context:
space:
mode:
authorWez Furlong <wez@php.net>2004-09-17 12:44:56 +0000
committerWez Furlong <wez@php.net>2004-09-17 12:44:56 +0000
commit99e290f882c9116e74418b9271a75d557533c4f5 (patch)
tree737c6e4ec61d02067b60372407542e3235d511e6 /main/php_network.h
parent9085689d6faec9eeae6802638ff2dea233d536b8 (diff)
downloadphp-git-99e290f882c9116e74418b9271a75d557533c4f5.tar.gz
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.
Diffstat (limited to 'main/php_network.h')
-rw-r--r--main/php_network.h98
1 files changed, 98 insertions, 0 deletions
diff --git a/main/php_network.h b/main/php_network.h
index 3d791e8fa7..d88fbc890d 100644
--- a/main/php_network.h
+++ b/main/php_network.h
@@ -106,6 +106,104 @@ typedef int php_socket_t;
# 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
#ifdef HAVE_SOCKADDR_STORAGE