[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