Commit 88a40b64 authored by Victor Stinner's avatar Victor Stinner

Issue #23618: Refactor internal_connect()

The function now returns the error code instead of using the global errno
(POSIX) or WSAGetLastError() (Windows).

internal_connect() now returns errno if getsockopt() fails.
parent ae4e3790
...@@ -2450,7 +2450,7 @@ static int ...@@ -2450,7 +2450,7 @@ static int
internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen, internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
int *timeoutp) int *timeoutp)
{ {
int res, timeout; int err, res, timeout;
timeout = 0; timeout = 0;
...@@ -2460,9 +2460,12 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen, ...@@ -2460,9 +2460,12 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
if (s->sock_timeout > 0 if (res < 0)
&& res < 0 && WSAGetLastError() == WSAEWOULDBLOCK err = WSAGetLastError();
&& IS_SELECTABLE(s)) { else
err = res;
if (s->sock_timeout > 0 && err == WSAEWOULDBLOCK && IS_SELECTABLE(s)) {
/* This is a mess. Best solution: trust select */ /* This is a mess. Best solution: trust select */
fd_set fds; fd_set fds;
fd_set fds_exc; fd_set fds_exc;
...@@ -2481,38 +2484,46 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen, ...@@ -2481,38 +2484,46 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (res == 0) { if (res == 0) {
res = WSAEWOULDBLOCK; err = WSAEWOULDBLOCK;
timeout = 1; timeout = 1;
} else if (res > 0) { }
if (FD_ISSET(s->sock_fd, &fds)) else if (res > 0) {
if (FD_ISSET(s->sock_fd, &fds)) {
/* The socket is in the writable set - this /* The socket is in the writable set - this
means connected */ means connected */
res = 0; err = 0;
}
else { else {
/* As per MS docs, we need to call getsockopt() /* As per MS docs, we need to call getsockopt()
to get the underlying error */ to get the underlying error */
int res_size = sizeof res; int res_size;
/* It must be in the exception set */ /* It must be in the exception set */
assert(FD_ISSET(s->sock_fd, &fds_exc)); assert(FD_ISSET(s->sock_fd, &fds_exc));
if (0 == getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR,
(char *)&res, &res_size)) res_size = sizeof res;
/* getsockopt also clears WSAGetLastError, if (!getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR,
so reset it back. */ (char *)&res, &res_size)) {
WSASetLastError(res); err = res;
else
res = WSAGetLastError();
} }
else {
err = WSAGetLastError();
}
}
}
else {
/* select() failed */
err = WSAGetLastError();
} }
/* else if (res < 0) an error occurred */
} }
if (res < 0)
res = WSAGetLastError();
#else #else
if (res < 0)
err = errno;
else
err = 0;
if (s->sock_timeout > 0 if (s->sock_timeout > 0 && err == EINPROGRESS && IS_SELECTABLE(s)) {
&& res < 0 && errno == EINPROGRESS && IS_SELECTABLE(s)) {
timeout = internal_connect_select(s); timeout = internal_connect_select(s);
...@@ -2521,27 +2532,31 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen, ...@@ -2521,27 +2532,31 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
use getsockopt(SO_ERROR) to get the real use getsockopt(SO_ERROR) to get the real
error. */ error. */
socklen_t res_size = sizeof res; socklen_t res_size = sizeof res;
(void)getsockopt(s->sock_fd, SOL_SOCKET, if (!getsockopt(s->sock_fd, SOL_SOCKET,
SO_ERROR, &res, &res_size); SO_ERROR, &res, &res_size)) {
if (res == EISCONN) if (res == EISCONN)
res = 0; res = 0;
errno = res; err = res;
}
else {
/* getsockopt() failed */
err = errno;
}
} }
else if (timeout == -1) { else if (timeout == -1) {
res = errno; /* had error */ /* select failed */
err = errno;
}
else {
err = EWOULDBLOCK; /* timed out */
} }
else
res = EWOULDBLOCK; /* timed out */
} }
if (res < 0)
res = errno;
#endif #endif
*timeoutp = timeout; *timeoutp = timeout;
assert(res >= 0); assert(err >= 0);
return res; return err;
} }
/* s.connect(sockaddr) method */ /* s.connect(sockaddr) method */
...@@ -2566,6 +2581,13 @@ sock_connect(PySocketSockObject *s, PyObject *addro) ...@@ -2566,6 +2581,13 @@ sock_connect(PySocketSockObject *s, PyObject *addro)
if (res < 0) if (res < 0)
return NULL; return NULL;
if (res != 0) { if (res != 0) {
#ifdef MS_WINDOWS
/* getsockopt also clears WSAGetLastError,
so reset it back. */
WSASetLastError(res);
#else
errno = res;
#endif
return s->errorhandler(); return s->errorhandler();
} }
Py_INCREF(Py_None); Py_INCREF(Py_None);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment