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.
This commit is contained in:
Victor Stinner 2015-03-31 16:08:22 +02:00
parent 1bb0aef4d1
commit dd88d3db45
1 changed files with 57 additions and 35 deletions

View File

@ -2450,7 +2450,7 @@ static int
internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
int *timeoutp)
{
int res, timeout;
int err, res, timeout;
timeout = 0;
@ -2460,9 +2460,12 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
#ifdef MS_WINDOWS
if (s->sock_timeout > 0
&& res < 0 && WSAGetLastError() == WSAEWOULDBLOCK
&& IS_SELECTABLE(s)) {
if (res < 0)
err = WSAGetLastError();
else
err = res;
if (s->sock_timeout > 0 && err == WSAEWOULDBLOCK && IS_SELECTABLE(s)) {
/* This is a mess. Best solution: trust select */
fd_set fds;
fd_set fds_exc;
@ -2481,38 +2484,46 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
Py_END_ALLOW_THREADS
if (res == 0) {
res = WSAEWOULDBLOCK;
err = WSAEWOULDBLOCK;
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
means connected */
res = 0;
err = 0;
}
else {
/* As per MS docs, we need to call getsockopt()
to get the underlying error */
int res_size = sizeof res;
int res_size;
/* It must be in the exception set */
assert(FD_ISSET(s->sock_fd, &fds_exc));
if (0 == getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR,
(char *)&res, &res_size))
/* getsockopt also clears WSAGetLastError,
so reset it back. */
WSASetLastError(res);
else
res = WSAGetLastError();
res_size = sizeof res;
if (!getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR,
(char *)&res, &res_size)) {
err = res;
}
else {
err = WSAGetLastError();
}
}
}
/* else if (res < 0) an error occurred */
else {
/* select() failed */
err = WSAGetLastError();
}
}
if (res < 0)
res = WSAGetLastError();
#else
if (res < 0)
err = errno;
else
err = 0;
if (s->sock_timeout > 0
&& res < 0 && errno == EINPROGRESS && IS_SELECTABLE(s)) {
if (s->sock_timeout > 0 && err == EINPROGRESS && IS_SELECTABLE(s)) {
timeout = internal_connect_select(s);
@ -2521,27 +2532,31 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
use getsockopt(SO_ERROR) to get the real
error. */
socklen_t res_size = sizeof res;
(void)getsockopt(s->sock_fd, SOL_SOCKET,
SO_ERROR, &res, &res_size);
if (res == EISCONN)
res = 0;
errno = res;
if (!getsockopt(s->sock_fd, SOL_SOCKET,
SO_ERROR, &res, &res_size)) {
if (res == EISCONN)
res = 0;
err = res;
}
else {
/* getsockopt() failed */
err = errno;
}
}
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
*timeoutp = timeout;
assert(res >= 0);
return res;
assert(err >= 0);
return err;
}
/* s.connect(sockaddr) method */
@ -2566,6 +2581,13 @@ sock_connect(PySocketSockObject *s, PyObject *addro)
if (res < 0)
return NULL;
if (res != 0) {
#ifdef MS_WINDOWS
/* getsockopt also clears WSAGetLastError,
so reset it back. */
WSASetLastError(res);
#else
errno = res;
#endif
return s->errorhandler();
}
Py_INCREF(Py_None);