From: <am...@us...> - 2008-12-21 22:28:33
|
Revision: 5783 http://jython.svn.sourceforge.net/jython/?rev=5783&view=rev Author: amak Date: 2008-12-21 22:28:30 +0000 (Sun, 21 Dec 2008) Log Message: ----------- 1. Fixed a bug whereby timeouts were not being honoured when recv()ing (http://bugs.jython.com/issue1154) 2. Fixed another (previously unreported) bug that resulted in an exception when switching from non-blocking to timeout mode. Modified Paths: -------------- trunk/jython/Lib/socket.py trunk/jython/Lib/test/test_socket.py Modified: trunk/jython/Lib/socket.py =================================================================== --- trunk/jython/Lib/socket.py 2008-12-19 17:02:10 UTC (rev 5782) +++ trunk/jython/Lib/socket.py 2008-12-21 22:28:30 UTC (rev 5783) @@ -6,8 +6,6 @@ XXX Restrictions: - Only INET sockets -- No asynchronous behavior -- No socket options - Can't do a very good gethostbyaddr() right... AMAK: 20050527: added socket timeouts AMAK: 20070515: Added non-blocking (asynchronous) support @@ -210,16 +208,6 @@ timeout = None mode = MODE_BLOCKING - def read(self, buf): - bytebuf = java.nio.ByteBuffer.wrap(buf) - count = self.jchannel.read(bytebuf) - return count - - def write(self, buf): - bytebuf = java.nio.ByteBuffer.wrap(buf) - count = self.jchannel.write(bytebuf) - return count - def getpeername(self): return (self.jsocket.getInetAddress().getHostAddress(), self.jsocket.getPort() ) @@ -230,6 +218,7 @@ if self.mode == MODE_NONBLOCKING: self.jchannel.configureBlocking(0) if self.mode == MODE_TIMEOUT: + self.jchannel.configureBlocking(1) self._timeout_millis = int(timeout*1000) self.jsocket.setSoTimeout(self._timeout_millis) @@ -321,6 +310,36 @@ def finish_connect(self): return self.jchannel.finishConnect() + def _do_read_net(self, buf): + # Need two separate implementations because the java.nio APIs do not support timeouts + return self.jsocket.getInputStream().read(buf) + + def _do_read_nio(self, buf): + bytebuf = java.nio.ByteBuffer.wrap(buf) + count = self.jchannel.read(bytebuf) + return count + + def _do_write_net(self, buf): + self.jsocket.getOutputStream().write(buf) + return len(buf) + + def _do_write_nio(self, buf): + bytebuf = java.nio.ByteBuffer.wrap(buf) + count = self.jchannel.write(bytebuf) + return count + + def read(self, buf): + if self.mode == MODE_TIMEOUT: + return self._do_read_net(buf) + else: + return self._do_read_nio(buf) + + def write(self, buf): + if self.mode == MODE_TIMEOUT: + return self._do_write_net(buf) + else: + return self._do_write_nio(buf) + class _server_socket_impl(_nio_impl): options = { @@ -824,6 +843,8 @@ if self.sock_impl.jchannel.isConnectionPending(): self.sock_impl.jchannel.finishConnect() numwritten = self.sock_impl.write(s) + if numwritten == 0 and self.mode == MODE_NONBLOCKING: + raise would_block_error() return numwritten except java.lang.Exception, jlx: raise _map_exception(jlx) Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2008-12-19 17:02:10 UTC (rev 5782) +++ trunk/jython/Lib/test/test_socket.py 2008-12-21 22:28:30 UTC (rev 5783) @@ -714,6 +714,16 @@ def _testRecv(self): self.serv_conn.send(MSG) + def testRecvTimeoutMode(self): + # Do this test in timeout mode, because the code path is different + self.cli_conn.settimeout(10) + msg = self.cli_conn.recv(1024) + self.assertEqual(msg, MSG) + + def _testRecvTimeoutMode(self): + self.serv_conn.settimeout(10) + self.serv_conn.send(MSG) + def testOverFlowRecv(self): # Testing receive in chunks over TCP seg1 = self.cli_conn.recv(len(MSG) - 3) @@ -1270,14 +1280,14 @@ bufsize = 2 # Exercise the buffering code -class TCPTimeoutTest(SocketTCPTest): +class TCPServerTimeoutTest(SocketTCPTest): - def testTCPTimeout(self): + def testAcceptTimeout(self): def raise_timeout(*args, **kwargs): self.serv.settimeout(1.0) self.serv.accept() self.failUnlessRaises(socket.timeout, raise_timeout, - "Error generating a timeout exception (TCP)") + "TCP socket accept failed to generate a timeout exception (TCP)") def testTimeoutZero(self): ok = False @@ -1293,9 +1303,9 @@ if not ok: self.fail("accept() returned success when we did not expect it") -class TCPClientTimeoutTest(unittest.TestCase): +class TCPClientTimeoutTest(SocketTCPTest): - def testClientTimeout(self): + def testConnectTimeout(self): cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM) cli.settimeout(0.1) host = '192.168.192.168' @@ -1310,8 +1320,45 @@ socket.timeout. This tries to connect to %s in the assumption that it isn't used, but if it is on your network this failure is bogus.''' % host) - + def testRecvTimeout(self): + def raise_timeout(*args, **kwargs): + cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + cli_sock.connect( (HOST, PORT) ) + cli_sock.settimeout(1) + cli_sock.recv(1024) + self.failUnlessRaises(socket.timeout, raise_timeout, + "TCP socket recv failed to generate a timeout exception (TCP)") + # Disable this test, but leave it present for documentation purposes + # socket timeouts only work for read and accept, not for write + # http://java.sun.com/j2se/1.4.2/docs/api/java/net/SocketTimeoutException.html + def estSendTimeout(self): + def raise_timeout(*args, **kwargs): + cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + cli_sock.connect( (HOST, PORT) ) + # First fill the socket + cli_sock.settimeout(1) + sent = 0 + while True: + bytes_sent = cli_sock.send(MSG) + sent += bytes_sent + self.failUnlessRaises(socket.timeout, raise_timeout, + "TCP socket send failed to generate a timeout exception (TCP)") + + def testSwitchModes(self): + cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + cli_sock.connect( (HOST, PORT) ) + # set non-blocking mode + cli_sock.setblocking(0) + # then set timeout mode + cli_sock.settimeout(1) + try: + cli_sock.send(MSG) + except Exception, x: + self.fail("Switching mode from non-blocking to timeout raised exception: %s" % x) + else: + pass + # # AMAK: 20070307 # Corrected the superclass of UDPTimeoutTest @@ -1539,7 +1586,7 @@ TestSupportedOptions, TestUnsupportedOptions, BasicTCPTest, - TCPTimeoutTest, + TCPServerTimeoutTest, TCPClientTimeoutTest, TestExceptions, TestInvalidUsage, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |