[Jython-checkins] jython: Fixing inheritance on socket options: #1309

alan.kennedy jython-checkins at python.org
Tue Aug 21 00:52:35 CEST 2012


http://hg.python.org/jython/rev/cb7e31929f49
changeset:   6848:cb7e31929f49
user:        Alan Kennedy <alan at xhaus.com>
date:        Mon Aug 20 23:50:46 2012 +0100
summary:
  Fixing inheritance on socket options: #1309

files:
  Lib/socket.py           |  28 ++++++++-
  Lib/test/test_socket.py |  81 +++++++++++++++++++++++-----
  2 files changed, 92 insertions(+), 17 deletions(-)


diff --git a/Lib/socket.py b/Lib/socket.py
--- a/Lib/socket.py
+++ b/Lib/socket.py
@@ -413,13 +413,16 @@
         (IPPROTO_TCP, TCP_NODELAY):    'TcpNoDelay',
     }
 
-    def __init__(self, socket=None):
+    def __init__(self, socket=None, pending_options=None):
         if socket:
             self.jchannel = socket.getChannel()
         else:
             self.jchannel = java.nio.channels.SocketChannel.open()
         self.jsocket = self.jchannel.socket()
         self.socketio = org.python.core.io.SocketIO(self.jchannel, 'rw')
+        if pending_options:
+            for level, optname in pending_options.keys():
+                self.setsockopt(level, optname, pending_options[ (level, optname) ])
 
     def bind(self, jsockaddr, reuse_addr):
         self.jsocket.setReuseAddress(reuse_addr)
@@ -485,6 +488,7 @@
     }
 
     def __init__(self, jsockaddr, backlog, reuse_addr):
+        self.pending_client_options = {}
         self.jchannel = java.nio.channels.ServerSocketChannel.open()
         self.jsocket = self.jchannel.socket()
         self.jsocket.setReuseAddress(reuse_addr)
@@ -495,13 +499,13 @@
         if self.mode in (MODE_BLOCKING, MODE_NONBLOCKING):
             new_cli_chan = self.jchannel.accept()
             if new_cli_chan is not None:
-                return _client_socket_impl(new_cli_chan.socket())
+                return _client_socket_impl(new_cli_chan.socket(), self.pending_client_options)
             else:
                 return None
         else:
             # In timeout mode now
             new_cli_sock = self.jsocket.accept()
-            return _client_socket_impl(new_cli_sock)
+            return _client_socket_impl(new_cli_sock, self.pending_client_options)
 
     def shutdown(self, how):
         # This is no-op on java, for server sockets.
@@ -510,6 +514,24 @@
         # later cause the user explicit close() call to fail
         pass
 
+    def getsockopt(self, level, option):
+        if self.options.has_key( (level, option) ):
+            return _nio_impl.getsockopt(self, level, option)
+        elif _client_socket_impl.options.has_key( (level, option) ):
+            return self.pending_client_options.get( (level, option), None)
+        else:
+            raise error(errno.ENOPROTOOPT, "Socket option '%s' (level '%s') not supported on socket(%s)" % \
+                (_constant_to_name(option, ['SO_', 'TCP_']), _constant_to_name(level,  ['SOL_', 'IPPROTO_']), str(self.jsocket)))
+
+    def setsockopt(self, level, option, value):
+        if self.options.has_key( (level, option) ):
+            _nio_impl.setsockopt(self, level, option, value)
+        elif _client_socket_impl.options.has_key( (level, option) ):
+            self.pending_client_options[ (level, option) ] = value
+        else:
+            raise error(errno.ENOPROTOOPT, "Socket option '%s' (level '%s') not supported on socket(%s)" % \
+                (_constant_to_name(option, ['SO_', 'TCP_']), _constant_to_name(level,  ['SOL_', 'IPPROTO_']), str(self.jsocket)))
+
     def getsockname(self):
         return (self.jsocket.getInetAddress().getHostAddress(), self.jsocket.getLocalPort())
 
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
@@ -727,8 +727,9 @@
             self._testSetAndGetOption(sock, level, option, values)
             # now bind the socket i.e. cause the implementation socket to be created
             sock.bind( (HOST, PORT) )
-            self.failUnlessEqual(sock.getsockopt(level, option), values[-1], \
-                 "Option value '(%s, %s)'='%s' did not propagate to implementation socket" % (level, option, values[-1]) )
+            retrieved_option_value = sock.getsockopt(level, option)
+            self.failUnlessEqual(retrieved_option_value, values[-1], \
+                 "Option value '(%s, %s)'='%s' did not propagate to implementation socket: got %s" % (level, option, values[-1], retrieved_option_value) )
             self._testSetAndGetOption(sock, level, option, values)
         finally:
             sock.close()
@@ -738,6 +739,7 @@
         try:
             # First listen on a server socket, so that the connection won't be refused.
             server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
             server_sock.bind( (HOST, PORT) )
             server_sock.listen(50)
             # Now do the tests
@@ -747,35 +749,66 @@
             # First bind, so that the SO_REUSEADDR setting propagates
             sock.bind( (HOST, PORT+1) )
             sock.connect( (HOST, PORT) )
-            msg = "Option value '%s'='%s' did not propagate to implementation socket" % (option, values[-1])
+            retrieved_option_value = sock.getsockopt(level, option)
+            msg = "Option value '%s'='%s' did not propagate to implementation socket: got %s" % (option, values[-1], retrieved_option_value)
             if option in (socket.SO_RCVBUF, socket.SO_SNDBUF):
                 # NOTE: there's no guarantee that bufsize will be the
                 # exact setsockopt value, particularly after
                 # establishing a connection. seems it will be *at least*
                 # the values we test (which are rather small) on
                 # BSDs.
-                self.assert_(sock.getsockopt(level, option) >= values[-1], msg)
+                self.assert_(retrieved_option_value >= values[-1], msg)
             else:
-                self.failUnlessEqual(sock.getsockopt(level, option), values[-1], msg)
+                self.failUnlessEqual(retrieved_option_value, values[-1], msg)
             self._testSetAndGetOption(sock, level, option, values)
         finally:
             server_sock.close()
             if sock:
                 sock.close()
 
+    def _testTCPClientInheritedOption(self, level, option, values):
+        cli_sock = accepted_sock = None
+        try:
+            server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+            self._testSetAndGetOption(server_sock, level, option, values)
+            # now bind and listen on the socket i.e. cause the implementation socket to be created
+            server_sock.bind( (HOST, PORT) )
+            server_sock.listen(50)
+            # Now create client socket to connect to server
+            cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            cli_sock.connect( (HOST, PORT) )
+            accepted_sock = server_sock.accept()[0]
+            retrieved_option_value = accepted_sock.getsockopt(level, option)
+            msg = "Option value '(%s,%s)'='%s' did not propagate to accepted socket: got %s" % (level, option, values[-1], retrieved_option_value)
+            if option == socket.SO_RCVBUF:
+                # NOTE: see similar bsd/solaris workaround above
+                self.assert_(retrieved_option_value >= values[-1], msg)
+            else:
+                self.failUnlessEqual(retrieved_option_value, values[-1], msg)
+            self._testSetAndGetOption(accepted_sock, level, option, values)
+        finally:
+            server_sock.close()
+            if cli_sock:
+                cli_sock.close()
+            if accepted_sock:
+                accepted_sock.close()
+
     def _testTCPServerOption(self, level, option, values):
         try:
             sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
             self._testSetAndGetOption(sock, level, option, values)
             # now bind and listen on the socket i.e. cause the implementation socket to be created
             sock.bind( (HOST, PORT) )
             sock.listen(50)
-            msg = "Option value '(%s,%s)'='%s' did not propagate to implementation socket" % (level, option, values[-1])
-            if is_solaris and option == socket.SO_RCVBUF:
+            retrieved_option_value = sock.getsockopt(level, option)
+            msg = "Option value '(%s,%s)'='%s' did not propagate to implementation socket. Got %s" % (level, option, values[-1], retrieved_option_value)
+            if option == socket.SO_RCVBUF:
                 # NOTE: see similar bsd/solaris workaround above
-                self.assert_(sock.getsockopt(level, option) >= values[-1], msg)
+                self.assert_(retrieved_option_value >= values[-1], msg)
             else:
-                self.failUnlessEqual(sock.getsockopt(level, option), values[-1], msg)
+                self.failUnlessEqual(retrieved_option_value, values[-1], msg)
             self._testSetAndGetOption(sock, level, option, values)
         finally:
             sock.close()
@@ -783,8 +816,8 @@
     def _testOption(self, level, option, values):
         for flag, func in [
             (self.test_udp,        self._testUDPOption),
+            (self.test_tcp_client, self._testTCPClientOption),
             (self.test_tcp_server, self._testTCPServerOption),
-            (self.test_tcp_client, self._testTCPClientOption),
         ]:
             if flag:
                 func(level, option, values)
@@ -798,6 +831,12 @@
                 else:
                     self.fail("Setting unsupported option should have raised an exception")
 
+    def _testInheritedOption(self, level, option, values):
+        try:
+            self._testTCPClientInheritedOption(level, option, values)
+        except Exception, x:
+            self.fail("Inherited option should not have raised exception: %s" % str(x))
+
 class TestSupportedOptions(TestSocketOptions):
 
     def testSO_BROADCAST(self):
@@ -806,44 +845,58 @@
 
     def testSO_KEEPALIVE(self):
         self.test_tcp_client = 1
+        self.test_tcp_server = 1
         self._testOption(socket.SOL_SOCKET, socket.SO_KEEPALIVE, [0, 1])
+        self._testInheritedOption(socket.SOL_SOCKET, socket.SO_KEEPALIVE, [0, 1])
 
     def testSO_LINGER(self):
         self.test_tcp_client = 1
+        self.test_tcp_server = 1
         off = struct.pack('ii', 0, 0)
         on_2_seconds = struct.pack('ii', 1, 2)
         self._testOption(socket.SOL_SOCKET, socket.SO_LINGER, [off, on_2_seconds])
+        self._testInheritedOption(socket.SOL_SOCKET, socket.SO_LINGER, [off, on_2_seconds])
 
     def testSO_OOBINLINE(self):
         self.test_tcp_client = 1
+        self.test_tcp_server = 1
         self._testOption(socket.SOL_SOCKET, socket.SO_OOBINLINE, [0, 1])
+        self._testInheritedOption(socket.SOL_SOCKET, socket.SO_OOBINLINE, [0, 1])
 
     def testSO_RCVBUF(self):
-        self.test_udp = 1
+        self.test_udp        = 1
         self.test_tcp_client = 1
         self.test_tcp_server = 1
         self._testOption(socket.SOL_SOCKET, socket.SO_RCVBUF, [1024, 4096, 16384])
+        self._testInheritedOption(socket.SOL_SOCKET, socket.SO_RCVBUF, [1024, 4096, 16384])
 
     def testSO_REUSEADDR(self):
-        self.test_udp = 1
+        self.test_udp        = 1
         self.test_tcp_client = 1
         self.test_tcp_server = 1
         self._testOption(socket.SOL_SOCKET, socket.SO_REUSEADDR, [0, 1])
+        self._testInheritedOption(socket.SOL_SOCKET, socket.SO_REUSEADDR, [0, 1])
 
     def testSO_SNDBUF(self):
-        self.test_udp = 1
+        self.test_udp        = 1
         self.test_tcp_client = 1
+        self.test_tcp_server = 1
         self._testOption(socket.SOL_SOCKET, socket.SO_SNDBUF, [1024, 4096, 16384])
+        self._testInheritedOption(socket.SOL_SOCKET, socket.SO_SNDBUF, [1024, 4096, 16384])
 
     def testSO_TIMEOUT(self):
-        self.test_udp = 1
+        self.test_udp        = 1
         self.test_tcp_client = 1
         self.test_tcp_server = 1
         self._testOption(socket.SOL_SOCKET, socket.SO_TIMEOUT, [0, 1, 1000])
+        # We don't test inheritance here because both server and client sockets have SO_TIMEOUT
+        # but it doesn't inherit.
 
     def testTCP_NODELAY(self):
         self.test_tcp_client = 1
+        self.test_tcp_server = 1
         self._testOption(socket.IPPROTO_TCP, socket.TCP_NODELAY, [0, 1])
+        self._testInheritedOption(socket.IPPROTO_TCP, socket.TCP_NODELAY, [0, 1])
 
 class TestUnsupportedOptions(TestSocketOptions):
 

-- 
Repository URL: http://hg.python.org/jython


More information about the Jython-checkins mailing list