]> granicus.if.org Git - python/commitdiff
#1494314: Fix a regression with high-numbered sockets in 2.4.3. This
authorAnthony Baxter <anthonybaxter@gmail.com>
Tue, 11 Jul 2006 02:04:09 +0000 (02:04 +0000)
committerAnthony Baxter <anthonybaxter@gmail.com>
Tue, 11 Jul 2006 02:04:09 +0000 (02:04 +0000)
means that select() on sockets > FD_SETSIZE (typically 1024) work again.
The patch makes sockets use poll() internally where available.

Misc/NEWS
Modules/_ssl.c
Modules/socketmodule.c

index fd6c17ce299b1dc06f564846dbe65f8db5e5f165..080f4a7f6f978818ea1cc4cc38b1326a3060e295 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -105,6 +105,10 @@ Library
 Extension Modules
 -----------------
 
+- #1494314: Fix a regression with high-numbered sockets in 2.4.3. This 
+  means that select() on sockets > FD_SETSIZE (typically 1024) work again. 
+  The patch makes sockets use poll() internally where available. 
+
 - Assigning None to pointer type fields in ctypes structures possible
   overwrote the wrong fields, this is fixed now.
 
index f49391d7f00a1bcb4cc446d8c0a56b80bdd1f2cc..3b91b24515f4268d1b9e22a88ed90eee3b9d1377 100644 (file)
@@ -26,6 +26,12 @@ enum py_ssl_error {
 /* Include symbols from _socket module */
 #include "socketmodule.h"
 
+#if defined(HAVE_POLL_H) 
+#include <poll.h>
+#elif defined(HAVE_SYS_POLL_H)
+#include <sys/poll.h>
+#endif
+
 /* Include OpenSSL header files */
 #include "openssl/rsa.h"
 #include "openssl/crypto.h"
@@ -351,7 +357,7 @@ static void PySSL_dealloc(PySSLObject *self)
        PyObject_Del(self);
 }
 
-/* If the socket has a timeout, do a select() on the socket.
+/* If the socket has a timeout, do a select()/poll() on the socket.
    The argument writing indicates the direction.
    Returns one of the possibilities in the timeout_state enum (above).
  */
@@ -373,6 +379,26 @@ check_socket_and_wait_for_timeout(PySocketSockObject *s, int writing)
        if (s->sock_fd < 0)
                return SOCKET_HAS_BEEN_CLOSED;
 
+       /* Prefer poll, if available, since you can poll() any fd
+        * which can't be done with select(). */
+#ifdef HAVE_POLL
+       {
+               struct pollfd pollfd;
+               int timeout;
+
+               pollfd.fd = s->sock_fd;
+               pollfd.events = writing ? POLLOUT : POLLIN;
+
+               /* s->sock_timeout is in seconds, timeout in ms */
+               timeout = (int)(s->sock_timeout * 1000 + 0.5);
+               Py_BEGIN_ALLOW_THREADS
+               rc = poll(&pollfd, 1, timeout);
+               Py_END_ALLOW_THREADS
+
+               goto normal_return;
+       }
+#endif
+
        /* Guard against socket too large for select*/
 #ifndef Py_SOCKET_FD_CAN_BE_GE_FD_SETSIZE
        if (s->sock_fd >= FD_SETSIZE)
@@ -393,6 +419,7 @@ check_socket_and_wait_for_timeout(PySocketSockObject *s, int writing)
                rc = select(s->sock_fd+1, &fds, NULL, NULL, &tv);
        Py_END_ALLOW_THREADS
 
+normal_return:
        /* Return SOCKET_TIMED_OUT on timeout, SOCKET_OPERATION_OK otherwise
           (when we are able to write or when there's something to read) */
        return rc == 0 ? SOCKET_HAS_TIMED_OUT : SOCKET_OPERATION_OK;
index 11b184ed0a5fab023dbaac2c9584dedaec3b0c98..d07ce350a7c7ed7abb2857a261c30e56bbced014 100644 (file)
@@ -411,14 +411,24 @@ static int taskwindow;
    there has to be a circular reference. */
 static PyTypeObject sock_type;
 
-/* Can we call select() with this socket without a buffer overrun? */
+#if defined(HAVE_POLL_H)
+#include <poll.h>
+#elif defined(HAVE_SYS_POLL_H)
+#include <sys/poll.h>
+#endif
+
 #ifdef Py_SOCKET_FD_CAN_BE_GE_FD_SETSIZE
 /* Platform can select file descriptors beyond FD_SETSIZE */
 #define IS_SELECTABLE(s) 1
+#elif defined(HAVE_POLL)
+/* Instead of select(), we'll use poll() since poll() works on any fd. */
+#define IS_SELECTABLE(s) 1
+/* Can we call select() with this socket without a buffer overrun? */
 #else
 /* POSIX says selecting file descriptors beyond FD_SETSIZE
-   has undefined behaviour. */
-#define IS_SELECTABLE(s) ((s)->sock_fd < FD_SETSIZE)
+   has undefined behaviour.  If there's no timeout left, we don't have to
+   call select, so it's a safe, little white lie. */
+#define IS_SELECTABLE(s) ((s)->sock_fd < FD_SETSIZE || s->sock_timeout <= 0.0)
 #endif
 
 static PyObject*
@@ -686,7 +696,7 @@ internal_setblocking(PySocketSockObject *s, int block)
        return 1;
 }
 
-/* Do a select() on the socket, if necessary (sock_timeout > 0).
+/* Do a select()/poll() on the socket, if necessary (sock_timeout > 0).
    The argument writing indicates the direction.
    This does not raise an exception; we'll let our caller do that
    after they've reacquired the interpreter lock.
@@ -694,8 +704,6 @@ internal_setblocking(PySocketSockObject *s, int block)
 static int
 internal_select(PySocketSockObject *s, int writing)
 {
-       fd_set fds;
-       struct timeval tv;
        int n;
 
        /* Nothing to do unless we're in timeout mode (not non-blocking) */
@@ -706,17 +714,37 @@ internal_select(PySocketSockObject *s, int writing)
        if (s->sock_fd < 0)
                return 0;
 
-       /* Construct the arguments to select */
-       tv.tv_sec = (int)s->sock_timeout;
-       tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6);
-       FD_ZERO(&fds);
-       FD_SET(s->sock_fd, &fds);
+       /* Prefer poll, if available, since you can poll() any fd
+        * which can't be done with select(). */
+#ifdef HAVE_POLL
+       {
+               struct pollfd pollfd;
+               int timeout;
 
-       /* See if the socket is ready */
-       if (writing)
-               n = select(s->sock_fd+1, NULL, &fds, NULL, &tv);
-       else
-               n = select(s->sock_fd+1, &fds, NULL, NULL, &tv);
+               pollfd.fd = s->sock_fd;
+               pollfd.events = writing ? POLLOUT : POLLIN;
+
+               /* s->sock_timeout is in seconds, timeout in ms */
+               timeout = (int)(s->sock_timeout * 1000 + 0.5); 
+               n = poll(&pollfd, 1, timeout);
+       }
+#else
+       {
+               /* Construct the arguments to select */
+               fd_set fds;
+               struct timeval tv;
+               tv.tv_sec = (int)s->sock_timeout;
+               tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6);
+               FD_ZERO(&fds);
+               FD_SET(s->sock_fd, &fds);
+
+               /* See if the socket is ready */
+               if (writing)
+                       n = select(s->sock_fd+1, NULL, &fds, NULL, &tv);
+               else
+                       n = select(s->sock_fd+1, &fds, NULL, NULL, &tv);
+       }
+#endif
        if (n == 0)
                return 1;
        return 0;