Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7b8bac1

Browse files
committed
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).
1 parent 129b17d commit 7b8bac1

2 files changed

Lines changed: 42 additions & 39 deletions

File tree

Lib/test/test_socket.py

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -416,18 +416,8 @@ def testConnect(self):
416416
conn, addr = self.serv.accept()
417417

418418
def _testConnect(self):
419-
self.cli.setblocking(0)
420-
try:
421-
self.cli.connect((HOST, PORT))
422-
except socket.error:
423-
pass
424-
else:
425-
self.fail("Error trying to do non-blocking connect.")
426-
read, write, err = select.select([self.cli], [], [])
427-
if self.cli in read:
428-
self.cli.connect((HOST, PORT))
429-
else:
430-
self.fail("Error trying to do connect after select.")
419+
self.cli.settimeout(10)
420+
self.cli.connect((HOST, PORT))
431421

432422
def testRecv(self):
433423
"""Testing non-blocking recv."""

Modules/socketmodule.c

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,43 @@ static char close_doc[] =
12701270
\n\
12711271
Close the socket. It cannot be used after this call.";
12721272

1273+
static int
1274+
internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen)
1275+
{
1276+
int res;
1277+
1278+
res = connect(s->sock_fd, addr, addrlen);
1279+
1280+
#ifdef MS_WINDOWS
1281+
1282+
if (s->sock_timeout > 0.0) {
1283+
if (res < 0 && WSAGetLastError() == WSAEWOULDBLOCK) {
1284+
internal_select(s, 1);
1285+
res = connect(s->sock_fd, addr, addrlen);
1286+
if (res < 0 && WSAGetLastError() == WSAEISCONN)
1287+
res = 0;
1288+
}
1289+
}
1290+
1291+
if (res < 0)
1292+
res = WSAGetLastError();
1293+
1294+
#else
1295+
1296+
if (s->sock_timeout > 0.0) {
1297+
if (res < 0 && errno == EINPROGRESS) {
1298+
internal_select(s, 1);
1299+
res = connect(s->sock_fd, addr, addrlen);
1300+
}
1301+
}
1302+
1303+
if (res < 0)
1304+
res = errno;
1305+
1306+
#endif
1307+
1308+
return res;
1309+
}
12731310

12741311
/* s.connect(sockaddr) method */
12751312

@@ -1284,18 +1321,10 @@ sock_connect(PySocketSockObject *s, PyObject *addro)
12841321
return NULL;
12851322

12861323
Py_BEGIN_ALLOW_THREADS
1287-
if (s->sock_timeout > 0.0) {
1288-
res = connect(s->sock_fd, addr, addrlen);
1289-
if (res == EINPROGRESS) {
1290-
internal_select(s, 1);
1291-
res = connect(s->sock_fd, addr, addrlen);
1292-
}
1293-
}
1294-
else
1295-
res = connect(s->sock_fd, addr, addrlen);
1324+
res = internal_connect(s, addr, addrlen);
12961325
Py_END_ALLOW_THREADS
12971326

1298-
if (res < 0)
1327+
if (res != 0)
12991328
return s->errorhandler();
13001329
Py_INCREF(Py_None);
13011330
return Py_None;
@@ -1321,25 +1350,9 @@ sock_connect_ex(PySocketSockObject *s, PyObject *addro)
13211350
return NULL;
13221351

13231352
Py_BEGIN_ALLOW_THREADS
1324-
if (s->sock_timeout > 0.0) {
1325-
res = connect(s->sock_fd, addr, addrlen);
1326-
if (res == EINPROGRESS) {
1327-
internal_select(s, 1);
1328-
res = connect(s->sock_fd, addr, addrlen);
1329-
}
1330-
}
1331-
else
1332-
res = connect(s->sock_fd, addr, addrlen);
1353+
res = internal_connect(s, addr, addrlen);
13331354
Py_END_ALLOW_THREADS
13341355

1335-
if (res != 0) {
1336-
#ifdef MS_WINDOWS
1337-
res = WSAGetLastError();
1338-
#else
1339-
res = errno;
1340-
#endif
1341-
}
1342-
13431356
return PyInt_FromLong((long) res);
13441357
}
13451358

0 commit comments

Comments
 (0)