[Jython-checkins] jython: select.select and related socket.connect_ex fixes
jim.baker
jython-checkins at python.org
Mon Dec 29 08:00:07 CET 2014
https://hg.python.org/jython/rev/3c4adde9c083
changeset: 7475:3c4adde9c083
user: Jim Baker <jim.baker at rackspace.com>
date: Mon Dec 29 00:00:00 2014 -0700
summary:
select.select and related socket.connect_ex fixes
Fixed child socket handling such that if the parent socket is
blocking, the child socket will now immediately complete its setup.
Fixed socket.connect_ex so that it depends on the underlying connect
future, as well as catching any socket.error exceptions and returning
the corresponding errno. This change enables test_select_new.
Fixes http://bugs.jython.org/issue2242
files:
Lib/_socket.py | 24 ++++++++++++++++--------
Lib/test/regrtest.py | 1 -
Lib/test/test_select_new.py | 18 +++++++++---------
Lib/test/test_socket.py | 15 ++++++++++++++-
4 files changed, 39 insertions(+), 19 deletions(-)
diff --git a/Lib/_socket.py b/Lib/_socket.py
--- a/Lib/_socket.py
+++ b/Lib/_socket.py
@@ -615,6 +615,8 @@
# thread pool
child_channel.closeFuture().addListener(unlatch_child)
+ if self.parent_socket.timeout is None:
+ child._ensure_post_connect()
child._wait_on_latch()
log.debug("Socket initChannel completed waiting on latch", extra={"sock": child})
@@ -842,8 +844,8 @@
log.debug("Connect to %s", addr, extra={"sock": self})
self.channel = bootstrap.channel()
- connect_future = self.channel.connect(addr)
- self._handle_channel_future(connect_future, "connect")
+ self.connect_future = self.channel.connect(addr)
+ self._handle_channel_future(self.connect_future, "connect")
self.bind_timestamp = time.time()
def _post_connect(self):
@@ -871,12 +873,17 @@
log.debug("Completed connection to %s", addr, extra={"sock": self})
def connect_ex(self, addr):
- self.connect(addr)
- if self.timeout is None:
+ if not self.connected:
+ try:
+ self.connect(addr)
+ except error as e:
+ return e.errno
+ if not self.connect_future.isDone():
+ return errno.EINPROGRESS
+ elif self.connect_future.isSuccess():
return errno.EISCONN
else:
- return errno.EINPROGRESS
-
+ return errno.ENOTCONN
# SERVER METHODS
# Calling listen means this is a server socket
@@ -1033,11 +1040,11 @@
pass # already removed, can safely ignore (presumably)
if how & SHUT_WR:
self._can_write = False
-
+
def _readable(self):
if self.socket_type == CLIENT_SOCKET or self.socket_type == DATAGRAM_SOCKET:
log.debug("Incoming head=%s queue=%s", self.incoming_head, self.incoming, extra={"sock": self})
- return (
+ return bool(
(self.incoming_head is not None and self.incoming_head.readableBytes()) or
self.incoming.peek())
elif self.socket_type == SERVER_SOCKET:
@@ -1338,6 +1345,7 @@
self.active = AtomicBoolean()
self.active_latch = CountDownLatch(1)
self.accepted = False
+ self.timeout = parent_socket.timeout
def _ensure_post_connect(self):
do_post_connect = not self.active.getAndSet(True)
diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py
--- a/Lib/test/regrtest.py
+++ b/Lib/test/regrtest.py
@@ -1314,7 +1314,6 @@
test_peepholer
test_pyclbr
test_pyexpat
- test_select_new
test_stringprep
test_threadsignals
test_transformer
diff --git a/Lib/test/test_select_new.py b/Lib/test/test_select_new.py
--- a/Lib/test/test_select_new.py
+++ b/Lib/test/test_select_new.py
@@ -16,18 +16,15 @@
DATA_CHUNK = "." * DATA_CHUNK_SIZE
#
-# The timing of these tests depends on the how the unerlying OS socket library
+# The timing of these tests depends on the how the underlying OS socket library
# handles buffering. These values may need tweaking for different platforms
#
# The fundamental problem is that there is no reliable way to fill a socket with bytes
-#
+# To address this for running on Netty, we arbitrarily send 10000 bytes
-if test_support.is_jython:
- SELECT_TIMEOUT = 0
-else:
- # zero select timeout fails these tests on cpython (on windows 2003 anyway)
- SELECT_TIMEOUT = 0.001
-
+# zero select timeout fails these tests on cpython (on windows 2003 anyway);
+# on Jython with Netty it will result in flaky test runs
+SELECT_TIMEOUT = 0.001
READ_TIMEOUT = 5
class AsynchronousServer:
@@ -86,6 +83,9 @@
if self.select_writable():
bytes_sent = self.socket.send(DATA_CHUNK)
total_bytes += bytes_sent
+ if test_support.is_jython and total_bytes > 10000:
+ # Netty will buffer indefinitely, so just pick an arbitrary cutoff
+ return total_bytes
else:
return total_bytes
except socket.error, se:
@@ -149,7 +149,7 @@
def start_connect(self):
result = self.socket.connect_ex(SERVER_ADDRESS)
if result == errno.EISCONN:
- self.connected = 1
+ self.connected = True
else:
assert result == errno.EINPROGRESS
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -1125,6 +1125,20 @@
self.serv_conn.send(MSG)
self.serv_conn.send('and ' + MSG)
+ def testSelect(self):
+ # http://bugs.jython.org/issue2242
+ self.assertIs(self.cli_conn.gettimeout(), None, "Server socket is not blocking")
+ start_time = time.time()
+ r, w, x = select.select([self.cli_conn], [], [], 10)
+ if (time.time() - start_time) > 1:
+ self.fail("Child socket was not immediately available for read when set to blocking")
+ self.assertEqual(r[0], self.cli_conn)
+ self.assertEqual(self.cli_conn.recv(1024), MSG)
+
+ def _testSelect(self):
+ self.serv_conn.send(MSG)
+
+
class UDPBindTest(unittest.TestCase):
HOST = HOST
@@ -1396,7 +1410,6 @@
def _testRecvData(self):
self.cli.connect((self.HOST, self.PORT))
self.cli.send(MSG)
- #time.sleep(0.5)
def testRecvNoData(self):
# Testing non-blocking recv
--
Repository URL: https://hg.python.org/jython
More information about the Jython-checkins
mailing list