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:
parent
ee699e9d2b
commit
70a46f635f
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue