diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2015-03-31 16:35:35 +0200 |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2015-03-31 16:35:35 +0200 |
commit | 29005b4e1c33e608bac03344c851b541306a6145 (patch) | |
tree | a2cb4601b9ff58c10ff14dcf1f7af4ee2f3b49ec /Modules | |
parent | dfd099ab5fa516d18d6edb34cff10eb1ae09dde5 (diff) | |
download | cpython-29005b4e1c33e608bac03344c851b541306a6145.tar.gz |
Issue #23618: Refactor internal_connect()
On Windows, internal_connect() now reuses internal_connect_select() and always
calls getsockopt().
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/socketmodule.c | 109 |
1 files changed, 30 insertions, 79 deletions
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index b58e134121..ab3e913dbc 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -2299,7 +2299,8 @@ sock_setsockopt(PySocketSockObject *s, PyObject *args) 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 @@ static int 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 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen, 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; + in_progress = (err == IN_PROGRESS_ERR); - 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; - } - 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)) { - + if (s->sock_timeout > 0 && in_progress && 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. */ + 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, &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 { - err = EWOULDBLOCK; /* timed out */ + /* select() failed */ + err = GET_ERROR; } } - -#endif *timeoutp = timeout; assert(err >= 0); return err; + +#undef GET_ERROR +#undef IN_PROGRESS_ERR +#undef TIMEOUT_ERR } /* s.connect(sockaddr) method */ |