Commit 7b8bac10 authored by Guido van Rossum's avatar Guido van Rossum

Fix non-blocking connect() for Windows. Refactored the code

that retries the connect() call in timeout mode so it can be shared
between connect() and connect_ex(), and needs only a single #ifdef.

The test for this was doing funky stuff I don't approve of,
so I removed it in favor of a simpler test.  This allowed me
to implement a simpler, "purer" form of the timeout retry code.
Hopefully that's enough (if you want to be fancy, use non-blocking
mode and decode the errors yourself, like before).
parent 129b17d5
...@@ -416,18 +416,8 @@ class NonBlockingTCPTests(ThreadedTCPSocketTest): ...@@ -416,18 +416,8 @@ class NonBlockingTCPTests(ThreadedTCPSocketTest):
conn, addr = self.serv.accept() conn, addr = self.serv.accept()
def _testConnect(self): def _testConnect(self):
self.cli.setblocking(0) self.cli.settimeout(10)
try:
self.cli.connect((HOST, PORT))
except socket.error:
pass
else:
self.fail("Error trying to do non-blocking connect.")
read, write, err = select.select([self.cli], [], [])
if self.cli in read:
self.cli.connect((HOST, PORT)) self.cli.connect((HOST, PORT))
else:
self.fail("Error trying to do connect after select.")
def testRecv(self): def testRecv(self):
"""Testing non-blocking recv.""" """Testing non-blocking recv."""
......
...@@ -1270,6 +1270,43 @@ static char close_doc[] = ...@@ -1270,6 +1270,43 @@ static char close_doc[] =
\n\ \n\
Close the socket. It cannot be used after this call."; Close the socket. It cannot be used after this call.";
static int
internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen)
{
int res;
res = connect(s->sock_fd, addr, addrlen);
#ifdef MS_WINDOWS
if (s->sock_timeout > 0.0) {
if (res < 0 && WSAGetLastError() == WSAEWOULDBLOCK) {
internal_select(s, 1);
res = connect(s->sock_fd, addr, addrlen);
if (res < 0 && WSAGetLastError() == WSAEISCONN)
res = 0;
}
}
if (res < 0)
res = WSAGetLastError();
#else
if (s->sock_timeout > 0.0) {
if (res < 0 && errno == EINPROGRESS) {
internal_select(s, 1);
res = connect(s->sock_fd, addr, addrlen);
}
}
if (res < 0)
res = errno;
#endif
return res;
}
/* s.connect(sockaddr) method */ /* s.connect(sockaddr) method */
...@@ -1284,18 +1321,10 @@ sock_connect(PySocketSockObject *s, PyObject *addro) ...@@ -1284,18 +1321,10 @@ sock_connect(PySocketSockObject *s, PyObject *addro)
return NULL; return NULL;
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
if (s->sock_timeout > 0.0) { res = internal_connect(s, addr, addrlen);
res = connect(s->sock_fd, addr, addrlen);
if (res == EINPROGRESS) {
internal_select(s, 1);
res = connect(s->sock_fd, addr, addrlen);
}
}
else
res = connect(s->sock_fd, addr, addrlen);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (res < 0) if (res != 0)
return s->errorhandler(); return s->errorhandler();
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
...@@ -1321,25 +1350,9 @@ sock_connect_ex(PySocketSockObject *s, PyObject *addro) ...@@ -1321,25 +1350,9 @@ sock_connect_ex(PySocketSockObject *s, PyObject *addro)
return NULL; return NULL;
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
if (s->sock_timeout > 0.0) { res = internal_connect(s, addr, addrlen);
res = connect(s->sock_fd, addr, addrlen);
if (res == EINPROGRESS) {
internal_select(s, 1);
res = connect(s->sock_fd, addr, addrlen);
}
}
else
res = connect(s->sock_fd, addr, addrlen);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (res != 0) {
#ifdef MS_WINDOWS
res = WSAGetLastError();
#else
res = errno;
#endif
}
return PyInt_FromLong((long) res); return PyInt_FromLong((long) res);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment