Revision: 6506
http://jython.svn.sourceforge.net/jython/?rev=6506&view=rev
Author: amak
Date: 2009-07-03 15:45:08 +0000 (Fri, 03 Jul 2009)
Log Message:
-----------
1. Added support for the AI_PASSIVE flag
2. Added support for the AI_CANONNAME flag
3. Added unit tests for same
4. Split out getaddrinfo unit tests into their own test case class
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 2009-06-30 06:11:20 UTC (rev 6505)
+++ trunk/jython/Lib/socket.py 2009-07-03 15:45:08 UTC (rev 6506)
@@ -76,12 +76,12 @@
# Javax.net.ssl classes
import javax.net.ssl.SSLSocketFactory
-# Javax.net.ssl exceptions
-javax.net.ssl.SSLException
-javax.net.ssl.SSLHandshakeException
-javax.net.ssl.SSLKeyException
-javax.net.ssl.SSLPeerUnverifiedException
-javax.net.ssl.SSLProtocolException
+# Javax.net.ssl exceptions
+javax.net.ssl.SSLException
+javax.net.ssl.SSLHandshakeException
+javax.net.ssl.SSLKeyException
+javax.net.ssl.SSLPeerUnverifiedException
+javax.net.ssl.SSLProtocolException
import org.python.core.io.DatagramSocketIO
import org.python.core.io.ServerSocketIO
@@ -128,16 +128,16 @@
(java.nio.channels.NotYetConnectedException, ALL) : None,
(java.nio.channels.UnresolvedAddressException, ALL) : lambda: gaierror(errno.EGETADDRINFOFAILED, 'getaddrinfo failed'),
(java.nio.channels.UnsupportedAddressTypeException, ALL) : None,
-
-# These error codes are currently wrong: getting them correct is going to require
-# some investigation. Cpython 2.6 introduced extensive SSL support.
-
-(javax.net.ssl.SSLException, ALL) : lambda: sslerror(-1, 'SSL exception'),
-(javax.net.ssl.SSLHandshakeException, ALL) : lambda: sslerror(-1, 'SSL handshake exception'),
-(javax.net.ssl.SSLKeyException, ALL) : lambda: sslerror(-1, 'SSL key exception'),
-(javax.net.ssl.SSLPeerUnverifiedException, ALL) : lambda: sslerror(-1, 'SSL peer unverified exception'),
-(javax.net.ssl.SSLProtocolException, ALL) : lambda: sslerror(-1, 'SSL protocol exception'),
+# These error codes are currently wrong: getting them correct is going to require
+# some investigation. Cpython 2.6 introduced extensive SSL support.
+
+(javax.net.ssl.SSLException, ALL) : lambda: sslerror(-1, 'SSL exception'),
+(javax.net.ssl.SSLHandshakeException, ALL) : lambda: sslerror(-1, 'SSL handshake exception'),
+(javax.net.ssl.SSLKeyException, ALL) : lambda: sslerror(-1, 'SSL key exception'),
+(javax.net.ssl.SSLPeerUnverifiedException, ALL) : lambda: sslerror(-1, 'SSL peer unverified exception'),
+(javax.net.ssl.SSLProtocolException, ALL) : lambda: sslerror(-1, 'SSL protocol exception'),
+
}
def would_block_error(exc=None):
@@ -168,7 +168,14 @@
AF_INET6 = 23
AI_PASSIVE=1
+AI_CANONNAME=2
+# For some reason, probably historical, SOCK_DGRAM and SOCK_STREAM are opposite values of what they are on cpython.
+# I.E. The following is the way they are on cpython
+# SOCK_STREAM = 1
+# SOCK_DGRAM = 2
+# At some point, we should probably switch them around, which *should* not affect anybody
+
SOCK_DGRAM = 1
SOCK_STREAM = 2
SOCK_RAW = 3 # not supported
@@ -189,10 +196,10 @@
SO_TIMEOUT = 128
TCP_NODELAY = 256
-
-INADDR_ANY = "0.0.0.0"
-INADDR_BROADCAST = "255.255.255.255"
+INADDR_ANY = "0.0.0.0"
+INADDR_BROADCAST = "255.255.255.255"
+
# Options with negative constants are not supported
# They are being added here so that code that refers to them
# will not break with an AttributeError
@@ -209,11 +216,11 @@
SO_SNDTIMEO = -512
SO_TYPE = -1024
SO_USELOOPBACK = -2048
-
+
__all__ = ['AF_UNSPEC', 'AF_INET', 'AF_INET6', 'AI_PASSIVE', 'SOCK_DGRAM',
'SOCK_RAW', 'SOCK_RDM', 'SOCK_SEQPACKET', 'SOCK_STREAM', 'SOL_SOCKET',
'SO_BROADCAST', 'SO_ERROR', 'SO_KEEPALIVE', 'SO_LINGER', 'SO_OOBINLINE',
- 'SO_RCVBUF', 'SO_REUSEADDR', 'SO_SNDBUF', 'SO_TIMEOUT', 'TCP_NODELAY',
+ 'SO_RCVBUF', 'SO_REUSEADDR', 'SO_SNDBUF', 'SO_TIMEOUT', 'TCP_NODELAY',
'INADDR_ANY', 'INADDR_BROADCAST', 'IPPROTO_TCP', 'IPPROTO_UDP',
'SocketType', 'error', 'herror', 'gaierror', 'timeout',
'getfqdn', 'gethostbyaddr', 'gethostbyname', 'gethostname',
@@ -222,15 +229,15 @@
'SHUT_RD', 'SHUT_WR', 'SHUT_RDWR',
]
-def _constant_to_name(const_value):
- sock_module = sys.modules['socket']
- try:
- for name in dir(sock_module):
- if getattr(sock_module, name) is const_value:
- return name
- return "Unknown"
- finally:
- sock_module = None
+def _constant_to_name(const_value):
+ sock_module = sys.modules['socket']
+ try:
+ for name in dir(sock_module):
+ if getattr(sock_module, name) is const_value:
+ return name
+ return "Unknown"
+ finally:
+ sock_module = None
class _nio_impl:
@@ -285,15 +292,15 @@
class _client_socket_impl(_nio_impl):
- options = {
+ options = {
(SOL_SOCKET, SO_KEEPALIVE): 'KeepAlive',
(SOL_SOCKET, SO_LINGER): 'SoLinger',
(SOL_SOCKET, SO_OOBINLINE): 'OOBInline',
(SOL_SOCKET, SO_RCVBUF): 'ReceiveBufferSize',
(SOL_SOCKET, SO_REUSEADDR): 'ReuseAddress',
(SOL_SOCKET, SO_SNDBUF): 'SendBufferSize',
- (SOL_SOCKET, SO_TIMEOUT): 'SoTimeout',
- (IPPROTO_TCP, TCP_NODELAY): 'TcpNoDelay',
+ (SOL_SOCKET, SO_TIMEOUT): 'SoTimeout',
+ (IPPROTO_TCP, TCP_NODELAY): 'TcpNoDelay',
}
def __init__(self, socket=None):
@@ -361,10 +368,10 @@
class _server_socket_impl(_nio_impl):
- options = {
+ options = {
(SOL_SOCKET, SO_RCVBUF): 'ReceiveBufferSize',
(SOL_SOCKET, SO_REUSEADDR): 'ReuseAddress',
- (SOL_SOCKET, SO_TIMEOUT): 'SoTimeout',
+ (SOL_SOCKET, SO_TIMEOUT): 'SoTimeout',
}
def __init__(self, host, port, backlog, reuse_addr):
@@ -399,12 +406,12 @@
class _datagram_socket_impl(_nio_impl):
- options = {
+ options = {
(SOL_SOCKET, SO_BROADCAST): 'Broadcast',
(SOL_SOCKET, SO_RCVBUF): 'ReceiveBufferSize',
(SOL_SOCKET, SO_REUSEADDR): 'ReuseAddress',
(SOL_SOCKET, SO_SNDBUF): 'SendBufferSize',
- (SOL_SOCKET, SO_TIMEOUT): 'SoTimeout',
+ (SOL_SOCKET, SO_TIMEOUT): 'SoTimeout',
}
def __init__(self, port=None, address=None, reuse_addr=0):
@@ -515,7 +522,7 @@
has_ipv6 = False
# Name and address functions
-
+
def _gethostbyaddr(name):
# This is as close as I can get; at least the types are correct...
addresses = java.net.InetAddress.getAllByName(gethostbyname(name))
@@ -576,12 +583,12 @@
assert family == AF_INET, "Only AF_INET sockets are currently supported on jython"
assert type in (SOCK_DGRAM, SOCK_STREAM), "Only SOCK_STREAM and SOCK_DGRAM sockets are currently supported on jython"
if type == SOCK_STREAM:
- if protocol != 0:
- assert protocol == IPPROTO_TCP, "Only IPPROTO_TCP supported on SOCK_STREAM sockets"
+ if protocol != 0:
+ assert protocol == IPPROTO_TCP, "Only IPPROTO_TCP supported on SOCK_STREAM sockets"
return _tcpsocket()
else:
- if protocol != 0:
- assert protocol == IPPROTO_UDP, "Only IPPROTO_UDP supported on SOCK_DGRAM sockets"
+ if protocol != 0:
+ assert protocol == IPPROTO_UDP, "Only IPPROTO_UDP supported on SOCK_DGRAM sockets"
return _udpsocket()
def getaddrinfo(host, port, family=AF_INET, socktype=None, proto=0, flags=None):
@@ -594,16 +601,23 @@
AF_INET6: lambda x: isinstance(x, java.net.Inet6Address),
AF_UNSPEC: lambda x: isinstance(x, java.net.InetAddress),
}[family])
- # Cant see a way to support AI_PASSIVE right now.
- # if flags and flags & AI_PASSIVE:
- # pass
+ if host == "":
+ host = java.net.InetAddress.getLocalHost().getHostName()
+ passive_mode = flags is not None and flags & AI_PASSIVE
+ canonname_mode = flags is not None and flags & AI_CANONNAME
results = []
for a in java.net.InetAddress.getAllByName(host):
if len([f for f in filter_fns if f(a)]):
family = {java.net.Inet4Address: AF_INET, java.net.Inet6Address: AF_INET6}[a.getClass()]
+ if passive_mode and not canonname_mode:
+ canonname = ""
+ else:
+ canonname = asPyString(a.getCanonicalHostName())
+ if host is None and passive_mode and not canonname_mode:
+ sockname = INADDR_ANY
+ else:
+ sockname = asPyString(a.getHostAddress())
# TODO: Include flowinfo and scopeid in a 4-tuple for IPv6 addresses
- canonname = asPyString(a.getCanonicalHostName())
- sockname = asPyString(a.getHostAddress())
results.append((family, socktype, proto, canonname, (sockname, port)))
return results
except java.lang.Exception, jlx:
@@ -674,9 +688,9 @@
close_lock = threading.Lock()
def __init__(self):
- self.timeout = _defaulttimeout
- if self.timeout is not None:
- self.mode = MODE_TIMEOUT
+ self.timeout = _defaulttimeout
+ if self.timeout is not None:
+ self.mode = MODE_TIMEOUT
self.pending_options = {
(SOL_SOCKET, SO_REUSEADDR): 0,
}
@@ -844,7 +858,7 @@
self.sock_impl.bind(bind_host, bind_port, self.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ])
self._config() # Configure timeouts, etc, now that the socket exists
self.sock_impl.connect(host, port)
- except java.lang.Exception, jlx:
+ except java.lang.Exception, jlx:
raise _map_exception(jlx)
def connect(self, addr):
@@ -952,8 +966,8 @@
def bind(self, addr):
try:
assert not self.sock_impl
- host, port = _unpack_address_tuple(addr)
- if host == "":
+ host, port = _unpack_address_tuple(addr)
+ if host == "":
host = INADDR_ANY
host_address = java.net.InetAddress.getByName(host)
self.sock_impl = _datagram_socket_impl(port, host_address, self.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ])
@@ -994,8 +1008,8 @@
if not self.sock_impl:
self.sock_impl = _datagram_socket_impl()
self._config()
- host, port = _unpack_address_tuple(addr)
- if host == "<broadcast>":
+ host, port = _unpack_address_tuple(addr)
+ if host == "<broadcast>":
host = INADDR_BROADCAST
byte_array = java.lang.String(data).getBytes('iso-8859-1')
result = self.sock_impl.sendto(byte_array, host, port, flags)
@@ -1409,11 +1423,11 @@
class ssl:
- def __init__(self, plain_sock, keyfile=None, certfile=None):
+ def __init__(self, plain_sock, keyfile=None, certfile=None):
try:
self.ssl_sock = self._make_ssl_socket(plain_sock)
self._in_buf = java.io.BufferedInputStream(self.ssl_sock.getInputStream())
- self._out_buf = java.io.BufferedOutputStream(self.ssl_sock.getOutputStream())
+ self._out_buf = java.io.BufferedOutputStream(self.ssl_sock.getOutputStream())
except java.lang.Exception, jlx:
raise _map_exception(jlx)
@@ -1429,7 +1443,7 @@
return ssl_socket
def read(self, n=4096):
- try:
+ try:
data = jarray.zeros(n, 'b')
m = self._in_buf.read(data, 0, n)
if m <= 0:
@@ -1441,7 +1455,7 @@
raise _map_exception(jlx)
def write(self, s):
- try:
+ try:
self._out_buf.write(s)
self._out_buf.flush()
return len(s)
@@ -1449,7 +1463,7 @@
raise _map_exception(jlx)
def _get_server_cert(self):
- try:
+ try:
return self.ssl_sock.getSession().getPeerCertificates()[0]
except java.lang.Exception, jlx:
raise _map_exception(jlx)
Modified: trunk/jython/Lib/test/test_socket.py
===================================================================
--- trunk/jython/Lib/test/test_socket.py 2009-06-30 06:11:20 UTC (rev 6505)
+++ trunk/jython/Lib/test/test_socket.py 2009-07-03 15:45:08 UTC (rev 6506)
@@ -2,6 +2,8 @@
AMAK: 20050515: This module is the test_socket.py from cpython 2.4, ported to jython.
"""
+import java
+
import unittest
from test import test_support
@@ -308,22 +310,6 @@
if not fqhn in all_host_names:
self.fail("Error testing host resolution mechanisms.")
- def testGetAddrInfo(self):
- try:
- socket.getaddrinfo(HOST, PORT, 9999)
- except socket.gaierror, gaix:
- self.failUnlessEqual(gaix[0], errno.EIO)
- except Exception, x:
- self.fail("getaddrinfo with bad family raised wrong exception: %s" % x)
- else:
- self.fail("getaddrinfo with bad family should have raised exception")
-
- addrinfos = socket.getaddrinfo(HOST, PORT)
- for addrinfo in addrinfos:
- family, socktype, proto, canonname, sockaddr = addrinfo
- self.assert_(isinstance(canonname, str))
- self.assert_(isinstance(sockaddr[0], str))
-
def testRefCountGetNameInfo(self):
# Testing reference count for getnameinfo
import sys
@@ -529,7 +515,7 @@
class TestSocketOptions(unittest.TestCase):
- def setUp(self):
+ def setUp(self):
self.test_udp = self.test_tcp_client = self.test_tcp_server = 0
def _testSetAndGetOption(self, sock, level, option, values):
@@ -621,7 +607,7 @@
class TestSupportedOptions(TestSocketOptions):
- def testSO_BROADCAST(self):
+ def testSO_BROADCAST(self):
self.test_udp = 1
self._testOption(socket.SOL_SOCKET, socket.SO_BROADCAST, [0, 1])
@@ -821,32 +807,32 @@
def _testDup(self):
self.serv_conn.send(MSG)
self.serv_conn.send('and ' + MSG)
-
-class UDPBindTest(unittest.TestCase):
-
+
+class UDPBindTest(unittest.TestCase):
+
HOST = HOST
PORT = PORT
- def setUp(self):
+ def setUp(self):
self.sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
-
+
def testBindSpecific(self):
self.sock.bind( (self.HOST, self.PORT) ) # Use a specific port
actual_port = self.sock.getsockname()[1]
self.failUnless(actual_port == self.PORT,
"Binding to specific port number should have returned same number: %d != %d" % (actual_port, self.PORT))
- def testBindEphemeral(self):
+ def testBindEphemeral(self):
self.sock.bind( (self.HOST, 0) ) # let system choose a free port
- self.failUnless(self.sock.getsockname()[1] != 0, "Binding to port zero should have allocated an ephemeral port number")
+ self.failUnless(self.sock.getsockname()[1] != 0, "Binding to port zero should have allocated an ephemeral port number")
def testShutdown(self):
self.sock.bind( (self.HOST, self.PORT) )
self.sock.shutdown(socket.SHUT_RDWR)
- def tearDown(self):
- self.sock.close()
-
+ def tearDown(self):
+ self.sock.close()
+
class BasicUDPTest(ThreadedUDPSocketTest):
def __init__(self, methodName='runTest'):
@@ -1354,7 +1340,7 @@
used, but if it is on your network this failure is bogus.''' % host)
def testConnectDefaultTimeout(self):
- _saved_timeout = socket.getdefaulttimeout()
+ _saved_timeout = socket.getdefaulttimeout()
socket.setdefaulttimeout(0.1)
cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = '192.168.192.168'
@@ -1437,6 +1423,49 @@
if not ok:
self.fail("recv() returned success when we did not expect it")
+class TestGetAddrInfo(unittest.TestCase):
+
+ def testBadFamily(self):
+ try:
+ socket.getaddrinfo(HOST, PORT, 9999)
+ except socket.gaierror, gaix:
+ self.failUnlessEqual(gaix[0], errno.EIO)
+ except Exception, x:
+ self.fail("getaddrinfo with bad family raised wrong exception: %s" % x)
+ else:
+ self.fail("getaddrinfo with bad family should have raised exception")
+
+ def testReturnsAreStrings(self):
+ addrinfos = socket.getaddrinfo(HOST, PORT)
+ for addrinfo in addrinfos:
+ family, socktype, proto, canonname, sockaddr = addrinfo
+ self.assert_(isinstance(canonname, str))
+ self.assert_(isinstance(sockaddr[0], str))
+
+ def testAI_PASSIVE(self):
+ IPV4_LOOPBACK = "127.0.0.1"
+ local_hostname = java.net.InetAddress.getLocalHost().getHostName()
+ local_ip_address = java.net.InetAddress.getLocalHost().getHostAddress()
+ for flags, host_param, expected_canonname, expected_sockaddr in [
+ # First passive flag
+ (socket.AI_PASSIVE, None, "", socket.INADDR_ANY),
+ (socket.AI_PASSIVE, "", "", local_ip_address),
+ (socket.AI_PASSIVE, "localhost", "", IPV4_LOOPBACK),
+ (socket.AI_PASSIVE, local_hostname, "", local_ip_address),
+ # Now passive flag AND canonname flag
+ (socket.AI_PASSIVE|socket.AI_CANONNAME, None, "127.0.0.1", "127.0.0.1"),
+ (socket.AI_PASSIVE|socket.AI_CANONNAME, "", local_hostname, local_ip_address),
+ # The following result seems peculiar to me, and may be to do with my local machine setup
+ # Also may be caused by a security permission failure.
+ # If you have problems with the following result, just comment it out.
+ (socket.AI_PASSIVE|socket.AI_CANONNAME, "localhost", IPV4_LOOPBACK, IPV4_LOOPBACK),
+ (socket.AI_PASSIVE|socket.AI_CANONNAME, local_hostname, local_hostname, local_ip_address),
+ ]:
+ addrinfos = socket.getaddrinfo(host_param, 0, socket.AF_INET, socket.SOCK_STREAM, 0, flags)
+ for family, socktype, proto, canonname, sockaddr in addrinfos:
+ self.failUnlessEqual(expected_canonname, canonname, "For hostname '%s' and flags %d, canonname '%s' != '%s'" % (host_param, flags, expected_canonname, canonname) )
+ self.failUnlessEqual(expected_sockaddr, sockaddr[0], "For hostname '%s' and flags %d, sockaddr '%s' != '%s'" % (host_param, flags, expected_sockaddr, sockaddr[0]) )
+
class TestExceptions(unittest.TestCase):
def testExceptionTree(self):
@@ -1640,6 +1669,7 @@
TCPClientTimeoutTest,
TestExceptions,
TestInvalidUsage,
+ TestGetAddrInfo,
TestTCPAddressParameters,
TestUDPAddressParameters,
UDPBindTest,
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|