cpython: Issue #23618: Refactor internal_connect()

https://hg.python.org/cpython/rev/c59d81b802f8 changeset: 95332:c59d81b802f8 user: Victor Stinner <victor.stinner@gmail.com> date: Tue Mar 31 16:35:35 2015 +0200 summary: Issue #23618: Refactor internal_connect() On Windows, internal_connect() now reuses internal_connect_select() and always calls getsockopt(). files: Modules/socketmodule.c | 117 ++++++++-------------------- 1 files changed, 34 insertions(+), 83 deletions(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -2299,7 +2299,8 @@ if (PyArg_ParseTuple(args, "iii:setsockopt", &level, &optname, &flag)) { - res = setsockopt(s->sock_fd, level, optname, &flag, sizeof flag); + res = setsockopt(s->sock_fd, level, optname, + (char*)&flag, sizeof flag); } else { PyErr_Clear(); @@ -2450,7 +2451,17 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen, int *timeoutp) { - int err, res, timeout; +#ifdef MS_WINDOWS +# define GET_ERROR WSAGetLastError() +# define IN_PROGRESS_ERR WSAEWOULDBLOCK +# define TIMEOUT_ERR WSAEWOULDBLOCK +#else +# define GET_ERROR errno +# define IN_PROGRESS_ERR EINPROGRESS +# define TIMEOUT_ERR EWOULDBLOCK +#endif + + int res, err, in_progress, timeout; timeout = 0; @@ -2458,105 +2469,45 @@ res = connect(s->sock_fd, addr, addrlen); Py_END_ALLOW_THREADS -#ifdef MS_WINDOWS - if (res < 0) - err = WSAGetLastError(); + err = GET_ERROR; 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; - struct timeval tv; - int conv; - - _PyTime_AsTimeval_noraise(s->sock_timeout, &tv, _PyTime_ROUND_CEILING); - - Py_BEGIN_ALLOW_THREADS - FD_ZERO(&fds); - FD_SET(s->sock_fd, &fds); - FD_ZERO(&fds_exc); - FD_SET(s->sock_fd, &fds_exc); - res = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int), - NULL, &fds, &fds_exc, &tv); - Py_END_ALLOW_THREADS - - if (res == 0) { - err = WSAEWOULDBLOCK; - timeout = 1; + 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 (res > 0) { - if (FD_ISSET(s->sock_fd, &fds)) { - /* The socket is in the writable set - this - means connected */ - err = 0; - } - else { - /* As per MS docs, we need to call getsockopt() - to get the underlying error */ - int res_size; - - /* It must be in the exception set */ - assert(FD_ISSET(s->sock_fd, &fds_exc)); - - res_size = sizeof res; - if (!getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR, - (char *)&res, &res_size)) { - err = res; - } - else { - err = WSAGetLastError(); - } - } - } - else { - /* select() failed */ - err = WSAGetLastError(); - } - } - -#else - if (res < 0) - err = errno; - else - err = 0; - - if (s->sock_timeout > 0 && err == EINPROGRESS && IS_SELECTABLE(s)) { - - timeout = internal_connect_select(s); - - if (timeout == 0) { - /* Bug #1019808: in case of an EINPROGRESS, - use getsockopt(SO_ERROR) to get the real - error. */ + else if (timeout == 0) { socklen_t res_size = sizeof res; - if (!getsockopt(s->sock_fd, SOL_SOCKET, - SO_ERROR, &res, &res_size)) { + if (!getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR, + (char*)&res, &res_size)) { if (res == EISCONN) res = 0; err = res; } else { /* getsockopt() failed */ - err = errno; + err = GET_ERROR; } } - else if (timeout == -1) { - /* select failed */ - err = errno; + else { + /* select() failed */ + err = GET_ERROR; } - else { - err = EWOULDBLOCK; /* timed out */ - } - } - -#endif + } *timeoutp = timeout; assert(err >= 0); return err; + +#undef GET_ERROR +#undef IN_PROGRESS_ERR +#undef TIMEOUT_ERR } /* s.connect(sockaddr) method */ -- Repository URL: https://hg.python.org/cpython
participants (1)
-
victor.stinner