Issue #23618: Enhance EINTR handling in socket.connect()

Call PyErr_CheckSignals() immediatly if connect() or select() fails with EINTR
in internal_connect().

Refactor also the code to limit indentaton and make it more readable.
This commit is contained in:
Victor Stinner 2015-03-31 22:03:59 +02:00
parent ee699e9d2b
commit 70a46f635f
1 changed files with 37 additions and 35 deletions

View File

@ -2461,52 +2461,54 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
# define TIMEOUT_ERR EWOULDBLOCK # define TIMEOUT_ERR EWOULDBLOCK
#endif #endif
int res, err, in_progress, timeout; int res, err, wait_connect, timeout;
socklen_t res_size;
timeout = 0; *timeoutp = 0;
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
res = connect(s->sock_fd, addr, addrlen); res = connect(s->sock_fd, addr, addrlen);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (res < 0) if (!res) {
err = GET_ERROR; /* connect() succeeded, the socket is connected */
else return 0;
err = res;
in_progress = (err == IN_PROGRESS_ERR);
if (s->sock_timeout > 0 && in_progress && IS_SELECTABLE(s)) {
timeout = internal_connect_select(s);
if (timeout == 1) {
/* timed out */
err = TIMEOUT_ERR;
}
else if (timeout == 0) {
socklen_t res_size = sizeof res;
if (!getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR,
(void *)&res, &res_size)) {
if (res == EISCONN)
res = 0;
err = res;
}
else {
/* getsockopt() failed */
err = GET_ERROR;
}
}
else {
/* select() failed */
err = GET_ERROR;
}
} }
*timeoutp = timeout;
err = GET_ERROR;
if (err == EINTR && PyErr_CheckSignals()) if (err == EINTR && PyErr_CheckSignals())
return -1; return -1;
assert(err >= 0); wait_connect = (s->sock_timeout > 0 && err == IN_PROGRESS_ERR
return err; && IS_SELECTABLE(s));
if (!wait_connect)
return err;
timeout = internal_connect_select(s);
if (timeout == -1) {
/* select() failed */
err = GET_ERROR;
if (err == EINTR && PyErr_CheckSignals())
return -1;
return err;
}
if (timeout == 1) {
/* select() timed out */
*timeoutp = 1;
return TIMEOUT_ERR;
}
res_size = sizeof res;
if (getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR,
(void *)&res, &res_size)) {
/* getsockopt() failed */
return GET_ERROR;
}
if (res == EISCONN)
return 0;
return res;
#undef GET_ERROR #undef GET_ERROR
#undef IN_PROGRESS_ERR #undef IN_PROGRESS_ERR