[Jython-checkins] jython (merge 2.5 -> default): merge with 2.5: Fixing the getaddrinfo API to be closer to the C API.
alan.kennedy
jython-checkins at python.org
Wed Nov 2 01:32:32 CET 2011
http://hg.python.org/jython/rev/95a08a9556f0
changeset: 6267:95a08a9556f0
parent: 6265:1651fbbecffd
parent: 6266:7306b9651a3a
user: Alan Kennedy <jython-dev at xhaus.com>
date: Wed Nov 02 00:31:05 2011 +0000
summary:
merge with 2.5: Fixing the getaddrinfo API to be closer to the C API.
Fixes http://bugs.jython.org/issue1809
files:
Lib/socket.py | 70 ++++++++++++++++----
Lib/test/test_socket.py | 93 +++++++++++++++++++++++++++++
2 files changed, 147 insertions(+), 16 deletions(-)
diff --git a/Lib/socket.py b/Lib/socket.py
--- a/Lib/socket.py
+++ b/Lib/socket.py
@@ -1,5 +1,5 @@
"""
-This is an updated socket module for use on JVMs > 1.5; it is derived from the old jython socket module.
+This is an updated socket module for use on JVMs >= 1.5; it is derived from the old jython socket module.
It is documented, along with known issues and workarounds, on the jython wiki.
http://wiki.python.org/jython/NewSocketModule
"""
@@ -174,11 +174,19 @@
SHUT_RDWR = 2
AF_UNSPEC = 0
-AF_INET = 2
-AF_INET6 = 23
+AF_INET = 2
+AF_INET6 = 23
-AI_PASSIVE=1
-AI_CANONNAME=2
+AI_PASSIVE = 1
+AI_CANONNAME = 2
+AI_NUMERICHOST = 4
+AI_V4MAPPED = 8
+AI_ALL = 16
+AI_ADDRCONFIG = 32
+AI_NUMERICSERV = 1024
+
+EAI_NONAME = -2
+EAI_SERVICE = -8
# 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
@@ -565,21 +573,30 @@
from jnr.netdb import Service
except ImportError:
return None
- return Service.getServiceByName(service_name, protocol_name).getPort()
+ service = Service.getServiceByName(service_name, protocol_name)
+ if service is None:
+ raise error('service/proto not found')
+ return service.getPort()
def getservbyport(port, protocol_name=None):
try:
from jnr.netdb import Service
except ImportError:
return None
- return Service.getServiceByPort(port, protocol_name).getName()
+ service = Service.getServiceByPort(port, protocol_name)
+ if service is None:
+ raise error('port/proto not found')
+ return service.getName()
def getprotobyname(protocol_name=None):
try:
from jnr.netdb import Protocol
except ImportError:
return None
- return Protocol.getProtocolByName(protocol_name).getProto()
+ proto = Protocol.getProtocolByName(protocol_name)
+ if proto is None:
+ raise error('protocol not found')
+ return proto.getProto()
def _realsocket(family = AF_INET, sock_type = SOCK_STREAM, protocol=0):
assert family in (AF_INET, AF_INET6), "Only AF_INET and AF_INET6 sockets are currently supported on jython"
@@ -723,19 +740,39 @@
global _ipv4_addresses_only
_ipv4_addresses_only = value
+def _get_port_number(port, flags):
+ if isinstance(port, basestring):
+ try:
+ int_port = int(port)
+ except ValueError:
+ if flags and flags & AI_NUMERICSERV:
+ raise gaierror(EAI_NONAME, "Name or service not known")
+ # Lookup the service by name
+ try:
+ int_port = getservbyname(port)
+ except error:
+ raise gaierror(EAI_SERVICE, "Servname not supported for ai_socktype")
+ elif port is None:
+ int_port = 0
+ elif not isinstance(port, (int, long)):
+ raise error("Int or String expected")
+ else:
+ int_port = int(port)
+ return int_port % 65536
+
def getaddrinfo(host, port, family=AF_INET, socktype=None, proto=0, flags=None):
try:
+ if _ipv4_addresses_only:
+ family = AF_INET
if not family in [AF_INET, AF_INET6, AF_UNSPEC]:
raise gaierror(errno.EIO, 'ai_family not supported')
+ port = _get_port_number(port, flags)
filter_fns = []
- if _ipv4_addresses_only:
- filter_fns.append( lambda x: isinstance(x, java.net.Inet4Address) )
- else:
- filter_fns.append({
- AF_INET: lambda x: isinstance(x, java.net.Inet4Address),
- AF_INET6: lambda x: isinstance(x, java.net.Inet6Address),
- AF_UNSPEC: lambda x: isinstance(x, java.net.InetAddress),
- }[family])
+ filter_fns.append({
+ AF_INET: lambda x: isinstance(x, java.net.Inet4Address),
+ AF_INET6: lambda x: isinstance(x, java.net.Inet6Address),
+ AF_UNSPEC: lambda x: isinstance(x, java.net.InetAddress),
+ }[family])
if host == "":
host = java.net.InetAddress.getLocalHost().getHostName()
if isinstance(host, unicode):
@@ -793,6 +830,7 @@
def ntohl(x): return x
def inet_pton(family, ip_string):
+ # FIXME: java.net.InetAddress.getByName also accepts hostnames
try:
ia = java.net.InetAddress.getByName(ip_string)
bytes = []
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
@@ -379,6 +379,39 @@
if udpport is not None:
eq(socket.getservbyport(udpport, 'udp'), service)
+ def testGetServByExceptions(self):
+ # First getservbyname
+ try:
+ result = socket.getservbyname("nosuchservice")
+ except socket.error:
+ pass
+ except Exception, x:
+ self.fail("getservbyname raised wrong exception for non-existent service: %s" % str(x))
+ else:
+ self.fail("getservbyname failed to raise exception for non-existent service: %s" % str(result))
+
+ # Now getservbyport
+ try:
+ result = socket.getservbyport(55555)
+ except socket.error:
+ pass
+ except Exception, x:
+ self.fail("getservbyport raised wrong exception for unknown port: %s" % str(x))
+ else:
+ self.fail("getservbyport failed to raise exception for unknown port: %s" % str(result))
+
+ def testGetProtoByName(self):
+ self.failUnlessEqual(socket.IPPROTO_TCP, socket.getprotobyname("tcp"))
+ self.failUnlessEqual(socket.IPPROTO_UDP, socket.getprotobyname("udp"))
+ try:
+ result = socket.getprotobyname("nosuchproto")
+ except socket.error:
+ pass
+ except Exception, x:
+ self.fail("getprotobyname raised wrong exception for unknown protocol: %s" % str(x))
+ else:
+ self.fail("getprotobyname failed to raise exception for unknown protocol: %s" % str(result))
+
def testDefaultTimeout(self):
# Testing default timeout
# The default timeout should initially be None
@@ -1537,6 +1570,66 @@
self.failUnless(str(ipv6_address_tuple) in ["('::1', 80, 0, 0)", "('0:0:0:0:0:0:0:1', 80, 0, 0)"])
self.failUnless(repr(ipv6_address_tuple) in ["('::1', 80, 0, 0)", "('0:0:0:0:0:0:0:1', 80, 0, 0)"])
+ def testNonIntPort(self):
+ hostname = "localhost"
+
+ # Port value of None should map to 0
+ addrs = socket.getaddrinfo(hostname, None)
+ for a in addrs:
+ self.failUnlessEqual(a[4][1], 0, "Port value of None should have returned 0")
+
+ # Port value can be a string rep of the port number
+ addrs = socket.getaddrinfo(hostname, "80")
+ for a in addrs:
+ self.failUnlessEqual(a[4][1], 80, "Port value of '80' should have returned 80")
+
+ # Can also specify a service name
+ # This test assumes that service http will always be at port 80
+ addrs = socket.getaddrinfo(hostname, "http")
+ for a in addrs:
+ self.failUnlessEqual(a[4][1], 80, "Port value of 'http' should have returned 80")
+
+ # Check treatment of non-integer numeric port
+ try:
+ socket.getaddrinfo(hostname, 79.99)
+ except socket.error, se:
+ self.failUnlessEqual(se[0], "Int or String expected")
+ except Exception, x:
+ self.fail("getaddrinfo for float port number raised wrong exception: %s" % str(x))
+ else:
+ self.fail("getaddrinfo for float port number failed to raise exception")
+
+ # Check treatment of non-integer numeric port, as a string
+ # The result is that it should fail in the same way as a non-existent service
+ try:
+ socket.getaddrinfo(hostname, "79.99")
+ except socket.gaierror, g:
+ self.failUnlessEqual(g[0], socket.EAI_SERVICE)
+ except Exception, x:
+ self.fail("getaddrinfo for non-integer numeric port, as a string raised wrong exception: %s" % str(x))
+ else:
+ self.fail("getaddrinfo for non-integer numeric port, as a string failed to raise exception")
+
+ # Check enforcement of AI_NUMERICSERV
+ try:
+ socket.getaddrinfo(hostname, "http", 0, 0, 0, socket.AI_NUMERICSERV)
+ except socket.gaierror, g:
+ self.failUnlessEqual(g[0], socket.EAI_NONAME)
+ except Exception, x:
+ self.fail("getaddrinfo for service name with AI_NUMERICSERV raised wrong exception: %s" % str(x))
+ else:
+ self.fail("getaddrinfo for service name with AI_NUMERICSERV failed to raise exception")
+
+ # Check treatment of non-existent service
+ try:
+ socket.getaddrinfo(hostname, "nosuchservice")
+ except socket.gaierror, g:
+ self.failUnlessEqual(g[0], socket.EAI_SERVICE)
+ except Exception, x:
+ self.fail("getaddrinfo for unknown service name raised wrong exception: %s" % str(x))
+ else:
+ self.fail("getaddrinfo for unknown service name failed to raise exception")
+
class TestJython_get_jsockaddr(unittest.TestCase):
"These tests are specific to jython: they test a key internal routine"
--
Repository URL: http://hg.python.org/jython
More information about the Jython-checkins
mailing list