diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2015-03-31 16:08:22 +0200 |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2015-03-31 16:08:22 +0200 |
commit | dfd099ab5fa516d18d6edb34cff10eb1ae09dde5 (patch) | |
tree | 9962dc8254117b2660f191580fe1c6f9e05df339 /Modules | |
parent | b069be5549e7ba18837a6a03b74002a3162f064a (diff) | |
download | cpython-dfd099ab5fa516d18d6edb34cff10eb1ae09dde5.tar.gz |
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.
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/socketmodule.c | 92 |
1 files changed, 57 insertions, 35 deletions
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index a33c12740c..b58e134121 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -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); |