diff -r 7ed567ad8b4c Modules/socketmodule.c --- a/Modules/socketmodule.c Tue Mar 31 22:03:59 2015 +0200 +++ b/Modules/socketmodule.c Tue Mar 31 22:15:02 2015 +0200 @@ -612,18 +612,10 @@ internal_select_impl(PySocketSockObject /* Error condition is for output only */ assert(!(error && !writing)); - /* Nothing to do unless we're in timeout mode (not non-blocking) */ - if (s->sock_timeout <= 0) - return 0; - /* Guard against closed socket */ if (s->sock_fd < 0) return 0; - /* Handling this condition here simplifies the select loops */ - if (interval < 0) - return 1; - /* Prefer poll, if available, since you can poll() any fd * which can't be done with select(). */ #ifdef HAVE_POLL @@ -633,14 +625,23 @@ internal_select_impl(PySocketSockObject pollfd.events |= POLLERR; /* s->sock_timeout is in seconds, timeout in ms */ - ms = _PyTime_AsMilliseconds(interval, _PyTime_ROUND_CEILING); - assert(ms <= INT_MAX); + if (interval >= 0) { + ms = _PyTime_AsMilliseconds(interval, _PyTime_ROUND_CEILING); + assert(ms <= INT_MAX); + } + else + ms = -1; Py_BEGIN_ALLOW_THREADS; n = poll(&pollfd, 1, (int)ms); Py_END_ALLOW_THREADS; #else - _PyTime_AsTimeval_noraise(interval, &tv, _PyTime_ROUND_CEILING); + if (interval >= 0) + _PyTime_AsTimeval_noraise(interval, &tv, _PyTime_ROUND_CEILING); + else { + tv.tv_sec = -1; + tv.tv_usec = 0; + } FD_ZERO(&fds); FD_SET(s->sock_fd, &fds); @@ -674,6 +675,14 @@ internal_select_impl(PySocketSockObject static int internal_select(PySocketSockObject *s, int writing, _PyTime_t interval) { + /* Nothing to do unless we're in timeout mode (not non-blocking) */ + if (s->sock_timeout <= 0) + return 0; + + /* Handling this condition here simplifies the select loops */ + if (interval < 0) + return 1; + return internal_select_impl(s, writing, interval, 0); } @@ -2476,21 +2485,43 @@ internal_connect(PySocketSockObject *s, } err = GET_ERROR; - if (err == EINTR && PyErr_CheckSignals()) - return -1; - - wait_connect = (s->sock_timeout > 0 && err == IN_PROGRESS_ERR - && IS_SELECTABLE(s)); - if (!wait_connect) + if (err == EINTR) { + if (PyErr_CheckSignals()) + return -1; + + /* Issue #23618: when connect() fails with EINTR, the connection is + running asynchronously. + + If the socket is blocking or has a timeout, wait until the socket is + writable using select(), and then get the status of the connection + using getsockopt(SO_ERROR). + + If the socket is non-blocking, the caller is responsible to + implement similar code (it's the case in asyncio for example). */ + } + + wait_connect = ((s->sock_timeout > 0 && err == IN_PROGRESS_ERR) + || (s->sock_timeout != 0 && err == EINTR)); + if (!wait_connect || !IS_SELECTABLE(s)) return err; + BEGIN_SELECT_LOOP(s) timeout = internal_connect_select(s); + + err = GET_ERROR; + if (err == EINTR) { + /* select() was interrupted by a signal */ + if (PyErr_CheckSignals()) + return err; + + /* retry interrupted select() with the recomputed timeout */ + continue; + } + END_SELECT_LOOP(s) + if (timeout == -1) { /* select() failed */ - err = GET_ERROR; - if (err == EINTR && PyErr_CheckSignals()) - return -1; - return err; + return GET_ERROR; } if (timeout == 1) {