summaryrefslogtreecommitdiff
path: root/Modules/socketmodule.c
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2015-03-31 16:35:35 +0200
committerVictor Stinner <victor.stinner@gmail.com>2015-03-31 16:35:35 +0200
commit29005b4e1c33e608bac03344c851b541306a6145 (patch)
treea2cb4601b9ff58c10ff14dcf1f7af4ee2f3b49ec /Modules/socketmodule.c
parentdfd099ab5fa516d18d6edb34cff10eb1ae09dde5 (diff)
downloadcpython-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/socketmodule.c')
-rw-r--r--Modules/socketmodule.c109
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 */