@@ -474,6 +474,14 @@ select_error(void)
474474 return NULL ;
475475}
476476
477+ #ifdef MS_WINDOWS
478+ #define CHECK_ERRNO (expected ) \
479+ (WSAGetLastError() == WSA ## expected)
480+ #else
481+ #define CHECK_ERRNO (expected ) \
482+ (errno == expected)
483+ #endif
484+
477485/* Convenience function to raise an error according to errno
478486 and return a NULL pointer from a function. */
479487
@@ -637,7 +645,7 @@ internal_setblocking(PySocketSockObject *s, int block)
637645 after they've reacquired the interpreter lock.
638646 Returns 1 on timeout, -1 on error, 0 otherwise. */
639647static int
640- internal_select (PySocketSockObject * s , int writing )
648+ internal_select_ex (PySocketSockObject * s , int writing , double interval )
641649{
642650 int n ;
643651
@@ -649,6 +657,10 @@ internal_select(PySocketSockObject *s, int writing)
649657 if (s -> sock_fd < 0 )
650658 return 0 ;
651659
660+ /* Handling this condition here simplifies the select loops */
661+ if (interval < 0.0 )
662+ return 1 ;
663+
652664 /* Prefer poll, if available, since you can poll() any fd
653665 * which can't be done with select(). */
654666#ifdef HAVE_POLL
@@ -660,16 +672,16 @@ internal_select(PySocketSockObject *s, int writing)
660672 pollfd .events = writing ? POLLOUT : POLLIN ;
661673
662674 /* s->sock_timeout is in seconds, timeout in ms */
663- timeout = (int )(s -> sock_timeout * 1000 + 0.5 );
675+ timeout = (int )(interval * 1000 + 0.5 );
664676 n = poll (& pollfd , 1 , timeout );
665677 }
666678#else
667679 {
668680 /* Construct the arguments to select */
669681 fd_set fds ;
670682 struct timeval tv ;
671- tv .tv_sec = (int )s -> sock_timeout ;
672- tv .tv_usec = (int )((s -> sock_timeout - tv .tv_sec ) * 1e6 );
683+ tv .tv_sec = (int )interval ;
684+ tv .tv_usec = (int )((interval - tv .tv_sec ) * 1e6 );
673685 FD_ZERO (& fds );
674686 FD_SET (s -> sock_fd , & fds );
675687
@@ -690,6 +702,53 @@ internal_select(PySocketSockObject *s, int writing)
690702 return 0 ;
691703}
692704
705+ static int
706+ internal_select (PySocketSockObject * s , int writing )
707+ {
708+ return internal_select_ex (s , writing , s -> sock_timeout );
709+ }
710+
711+ /*
712+ Two macros for automatic retry of select() in case of false positives
713+ (for example, select() could indicate a socket is ready for reading
714+ but the data then discarded by the OS because of a wrong checksum).
715+ Here is an example of use:
716+
717+ BEGIN_SELECT_LOOP(s)
718+ Py_BEGIN_ALLOW_THREADS
719+ timeout = internal_select_ex(s, 0, interval);
720+ if (!timeout)
721+ outlen = recv(s->sock_fd, cbuf, len, flags);
722+ Py_END_ALLOW_THREADS
723+ if (timeout == 1) {
724+ PyErr_SetString(socket_timeout, "timed out");
725+ return -1;
726+ }
727+ END_SELECT_LOOP(s)
728+ */
729+
730+ #define BEGIN_SELECT_LOOP (s ) \
731+ { \
732+ _PyTime_timeval now, deadline = {0, 0}; \
733+ double interval = s->sock_timeout; \
734+ int has_timeout = s->sock_timeout > 0.0; \
735+ if (has_timeout) { \
736+ _PyTime_gettimeofday(&now); \
737+ deadline = now; \
738+ _PyTime_ADD_SECONDS(deadline, s->sock_timeout); \
739+ } \
740+ while (1) { \
741+ errno = 0; \
742+
743+ #define END_SELECT_LOOP (s ) \
744+ if (!has_timeout || \
745+ (!CHECK_ERRNO(EWOULDBLOCK) && !CHECK_ERRNO(EAGAIN))) \
746+ break; \
747+ _PyTime_gettimeofday(&now); \
748+ interval = _PyTime_INTERVAL(now, deadline); \
749+ } \
750+ } \
751+
693752/* Initialize a new socket object. */
694753
695754static double defaulttimeout = -1.0 ; /* Default timeout for new sockets */
@@ -1591,8 +1650,9 @@ sock_accept(PySocketSockObject *s)
15911650 if (!IS_SELECTABLE (s ))
15921651 return select_error ();
15931652
1653+ BEGIN_SELECT_LOOP (s )
15941654 Py_BEGIN_ALLOW_THREADS
1595- timeout = internal_select (s , 0 );
1655+ timeout = internal_select_ex (s , 0 , interval );
15961656 if (!timeout )
15971657 newfd = accept (s -> sock_fd , SAS2SA (& addrbuf ), & addrlen );
15981658 Py_END_ALLOW_THREADS
@@ -1601,6 +1661,7 @@ sock_accept(PySocketSockObject *s)
16011661 PyErr_SetString (socket_timeout , "timed out" );
16021662 return NULL ;
16031663 }
1664+ END_SELECT_LOOP (s )
16041665
16051666 if (newfd == INVALID_SOCKET )
16061667 return s -> errorhandler ();
@@ -2151,6 +2212,7 @@ will allow before refusing new connections.");
21512212 * also possible that we return a number of bytes smaller than the request
21522213 * bytes.
21532214 */
2215+
21542216static Py_ssize_t
21552217sock_recv_guts (PySocketSockObject * s , char * cbuf , Py_ssize_t len , int flags )
21562218{
@@ -2171,8 +2233,9 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags)
21712233 }
21722234
21732235#ifndef __VMS
2236+ BEGIN_SELECT_LOOP (s )
21742237 Py_BEGIN_ALLOW_THREADS
2175- timeout = internal_select (s , 0 );
2238+ timeout = internal_select_ex (s , 0 , interval );
21762239 if (!timeout )
21772240 outlen = recv (s -> sock_fd , cbuf , len , flags );
21782241 Py_END_ALLOW_THREADS
@@ -2181,6 +2244,7 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags)
21812244 PyErr_SetString (socket_timeout , "timed out" );
21822245 return -1 ;
21832246 }
2247+ END_SELECT_LOOP (s )
21842248 if (outlen < 0 ) {
21852249 /* Note: the call to errorhandler() ALWAYS indirectly returned
21862250 NULL, so ignore its return value */
@@ -2202,16 +2266,18 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags)
22022266 segment = remaining ;
22032267 }
22042268
2269+ BEGIN_SELECT_LOOP (s )
22052270 Py_BEGIN_ALLOW_THREADS
2206- timeout = internal_select (s , 0 );
2271+ timeout = internal_select_ex (s , 0 , interval );
22072272 if (!timeout )
22082273 nread = recv (s -> sock_fd , read_buf , segment , flags );
22092274 Py_END_ALLOW_THREADS
2210-
22112275 if (timeout == 1 ) {
22122276 PyErr_SetString (socket_timeout , "timed out" );
22132277 return -1 ;
22142278 }
2279+ END_SELECT_LOOP (s )
2280+
22152281 if (nread < 0 ) {
22162282 s -> errorhandler ();
22172283 return -1 ;
@@ -2372,9 +2438,10 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags,
23722438 return -1 ;
23732439 }
23742440
2441+ BEGIN_SELECT_LOOP (s )
23752442 Py_BEGIN_ALLOW_THREADS
23762443 memset (& addrbuf , 0 , addrlen );
2377- timeout = internal_select (s , 0 );
2444+ timeout = internal_select_ex (s , 0 , interval );
23782445 if (!timeout ) {
23792446#ifndef MS_WINDOWS
23802447#if defined(PYOS_OS2 ) && !defined(PYCC_GCC )
@@ -2395,6 +2462,7 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags,
23952462 PyErr_SetString (socket_timeout , "timed out" );
23962463 return -1 ;
23972464 }
2465+ END_SELECT_LOOP (s )
23982466 if (n < 0 ) {
23992467 s -> errorhandler ();
24002468 return -1 ;
@@ -2532,22 +2600,24 @@ sock_send(PySocketSockObject *s, PyObject *args)
25322600 buf = pbuf .buf ;
25332601 len = pbuf .len ;
25342602
2603+ BEGIN_SELECT_LOOP (s )
25352604 Py_BEGIN_ALLOW_THREADS
2536- timeout = internal_select (s , 1 );
2605+ timeout = internal_select_ex (s , 1 , interval );
25372606 if (!timeout )
25382607#ifdef __VMS
25392608 n = sendsegmented (s -> sock_fd , buf , len , flags );
25402609#else
25412610 n = send (s -> sock_fd , buf , len , flags );
25422611#endif
25432612 Py_END_ALLOW_THREADS
2544-
2545- PyBuffer_Release (& pbuf );
2546-
25472613 if (timeout == 1 ) {
2614+ PyBuffer_Release (& pbuf );
25482615 PyErr_SetString (socket_timeout , "timed out" );
25492616 return NULL ;
25502617 }
2618+ END_SELECT_LOOP (s )
2619+
2620+ PyBuffer_Release (& pbuf );
25512621 if (n < 0 )
25522622 return s -> errorhandler ();
25532623 return PyLong_FromSsize_t (n );
@@ -2667,17 +2737,20 @@ sock_sendto(PySocketSockObject *s, PyObject *args)
26672737 return NULL ;
26682738 }
26692739
2740+ BEGIN_SELECT_LOOP (s )
26702741 Py_BEGIN_ALLOW_THREADS
2671- timeout = internal_select (s , 1 );
2742+ timeout = internal_select_ex (s , 1 , interval );
26722743 if (!timeout )
26732744 n = sendto (s -> sock_fd , buf , len , flags , SAS2SA (& addrbuf ), addrlen );
26742745 Py_END_ALLOW_THREADS
26752746
2676- PyBuffer_Release (& pbuf );
26772747 if (timeout == 1 ) {
2748+ PyBuffer_Release (& pbuf );
26782749 PyErr_SetString (socket_timeout , "timed out" );
26792750 return NULL ;
26802751 }
2752+ END_SELECT_LOOP (s )
2753+ PyBuffer_Release (& pbuf );
26812754 if (n < 0 )
26822755 return s -> errorhandler ();
26832756 return PyLong_FromSsize_t (n );
0 commit comments