[Jython-checkins] jython (merge 2.5 -> default): merge w/2.5: Fixes for getaddrinfo
alan.kennedy
jython-checkins at python.org
Tue Aug 14 23:11:35 CEST 2012
http://hg.python.org/jython/rev/a423b9e08626
changeset: 6846:a423b9e08626
parent: 6844:d7e04f80af9a
parent: 6845:d56c4119fed1
user: Alan Kennedy <alan at xhaus.com>
date: Tue Aug 14 22:10:15 2012 +0100
summary:
merge w/2.5: Fixes for getaddrinfo
files:
Lib/socket.py | 159 ++++++++++++++++++++-------
Lib/test/test_socket.py | 79 +++++++++++--
2 files changed, 181 insertions(+), 57 deletions(-)
diff --git a/Lib/socket.py b/Lib/socket.py
--- a/Lib/socket.py
+++ b/Lib/socket.py
@@ -96,7 +96,7 @@
def java_net_socketexception_handler(exc):
if exc.message.startswith("Address family not supported by protocol family"):
return _add_exception_attrs(error(errno.EAFNOSUPPORT,
- 'Address family not supported by protocol family: See http://wiki.python.org/jython/NewSocketModule#IPV6addresssupport'))
+ 'Address family not supported by protocol family: See http://wiki.python.org/jython/NewSocketModule#IPV6_address_support'))
return _unmapped_exception(exc)
def would_block_error(exc=None):
@@ -220,8 +220,28 @@
SOCK_SEQPACKET = 5 # not supported
SOL_SOCKET = 0xFFFF
-IPPROTO_TCP = 6
-IPPROTO_UDP = 17
+
+IPPROTO_AH = 51 # not supported
+IPPROTO_DSTOPTS = 60 # not supported
+IPPROTO_ESP = 50 # not supported
+IPPROTO_FRAGMENT = 44 # not supported
+IPPROTO_GGP = 3 # not supported
+IPPROTO_HOPOPTS = 0 # not supported
+IPPROTO_ICMP = 1 # not supported
+IPPROTO_ICMPV6 = 58 # not supported
+IPPROTO_IDP = 22 # not supported
+IPPROTO_IGMP = 2 # not supported
+IPPROTO_IP = 0
+IPPROTO_IPV4 = 4 # not supported
+IPPROTO_IPV6 = 41 # not supported
+IPPROTO_MAX = 256 # not supported
+IPPROTO_ND = 77 # not supported
+IPPROTO_NONE = 59 # not supported
+IPPROTO_PUP = 12 # not supported
+IPPROTO_RAW = 255 # not supported
+IPPROTO_ROUTING = 43 # not supported
+IPPROTO_TCP = 6
+IPPROTO_UDP = 17
SO_BROADCAST = 1
SO_KEEPALIVE = 2
@@ -256,26 +276,58 @@
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',
- 'INADDR_ANY', 'INADDR_BROADCAST', 'IPPROTO_TCP', 'IPPROTO_UDP',
- 'SocketType', 'error', 'herror', 'gaierror', 'timeout',
- 'getfqdn', 'gethostbyaddr', 'gethostbyname', 'gethostname',
- 'socket', 'getaddrinfo', 'getdefaulttimeout', 'setdefaulttimeout',
- 'has_ipv6', 'htons', 'htonl', 'ntohs', 'ntohl',
- 'SHUT_RD', 'SHUT_WR', 'SHUT_RDWR',
- ]
+__all__ = [
+ # Families
+ 'AF_UNSPEC', 'AF_INET', 'AF_INET6',
+ # getaddrinfo and getnameinfo flags
+ 'AI_PASSIVE', 'AI_CANONNAME', 'AI_NUMERICHOST', 'AI_V4MAPPED',
+ 'AI_ALL', 'AI_ADDRCONFIG', 'AI_NUMERICSERV', 'EAI_NONAME',
+ 'EAI_SERVICE', 'EAI_ADDRFAMILY',
+ 'NI_NUMERICHOST', 'NI_NUMERICSERV', 'NI_NOFQDN', 'NI_NAMEREQD',
+ 'NI_DGRAM', 'NI_MAXSERV', 'NI_IDN', 'NI_IDN_ALLOW_UNASSIGNED',
+ 'NI_IDN_USE_STD3_ASCII_RULES', 'NI_MAXHOST',
+ # socket types
+ 'SOCK_DGRAM', 'SOCK_STREAM', 'SOCK_RAW', 'SOCK_RDM', 'SOCK_SEQPACKET',
+ # levels
+ 'SOL_SOCKET',
+ # protocols
+ 'IPPROTO_AH', 'IPPROTO_DSTOPTS', 'IPPROTO_ESP', 'IPPROTO_FRAGMENT',
+ 'IPPROTO_GGP', 'IPPROTO_HOPOPTS', 'IPPROTO_ICMP', 'IPPROTO_ICMPV6',
+ 'IPPROTO_IDP', 'IPPROTO_IGMP', 'IPPROTO_IP', 'IPPROTO_IPV4',
+ 'IPPROTO_IPV6', 'IPPROTO_MAX', 'IPPROTO_ND', 'IPPROTO_NONE',
+ 'IPPROTO_PUP', 'IPPROTO_RAW', 'IPPROTO_ROUTING', 'IPPROTO_TCP',
+ 'IPPROTO_UDP',
+ # Special hostnames
+ 'INADDR_ANY', 'INADDR_BROADCAST', 'IN6ADDR_ANY_INIT',
+ # support socket options
+ 'SO_BROADCAST', 'SO_KEEPALIVE', 'SO_LINGER', 'SO_OOBINLINE',
+ 'SO_RCVBUF', 'SO_REUSEADDR', 'SO_SNDBUF', 'SO_TIMEOUT', 'TCP_NODELAY',
+ # unsupported socket options
+ 'SO_ACCEPTCONN', 'SO_DEBUG', 'SO_DONTROUTE', 'SO_ERROR',
+ 'SO_EXCLUSIVEADDRUSE', 'SO_RCVLOWAT', 'SO_RCVTIMEO', 'SO_REUSEPORT',
+ 'SO_SNDLOWAT', 'SO_SNDTIMEO', 'SO_TYPE', 'SO_USELOOPBACK',
+ # functions
+ 'getfqdn', 'gethostname', 'gethostbyname', 'gethostbyaddr',
+ 'getservbyname', 'getservbyport', 'getprotobyname', 'getaddrinfo',
+ 'getnameinfo', 'getdefaulttimeout', 'setdefaulttimeout', 'htons',
+ 'htonl', 'ntohs', 'ntohl', 'inet_pton', 'inet_ntop', 'inet_aton',
+ 'inet_ntoa', 'create_connection', 'socket', 'ssl',
+ # exceptions
+ 'error', 'herror', 'gaierror', 'timeout', 'sslerror,
+ # classes
+ 'SocketType',
+ # Misc flags
+ 'has_ipv6', 'SHUT_RD', 'SHUT_WR', 'SHUT_RDWR',
+]
-def _constant_to_name(const_value):
+def _constant_to_name(const_value, expected_name_starts):
sock_module = sys.modules['socket']
try:
for name in dir(sock_module):
- if getattr(sock_module, name) is const_value and \
- (name.startswith('SO_') or name.startswith('SOL_') or \
- name.startswith('TCP_') or name.startswith('IPPROTO_')):
- return name
+ if getattr(sock_module, name) is const_value:
+ for name_start in expected_name_starts:
+ if name.startswith(name_start):
+ return name
return "Unknown"
finally:
sock_module = None
@@ -325,7 +377,8 @@
return struct.pack('ii', enabled, linger_time)
return result
else:
- raise error(errno.ENOPROTOOPT, "Socket option '%s' (level '%s') not supported on socket(%s)" % (_constant_to_name(option), _constant_to_name(level), str(self.jsocket)))
+ 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 (level, option) in self.options:
@@ -335,7 +388,8 @@
else:
getattr(self.jsocket, "set%s" % self.options[ (level, option) ])(value)
else:
- raise error(errno.ENOPROTOOPT, "Socket option '%s' (level '%s') not supported on socket(%s)" % (_constant_to_name(option), _constant_to_name(level), str(self.jsocket)))
+ 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 close(self):
self.jsocket.close()
@@ -785,15 +839,18 @@
error_message = "Address must be a 2-tuple (ipv4: (host, port)) or a 4-tuple (ipv6: (host, port, flow, scope))"
if not isinstance(address_object, tuple) or \
((family == AF_INET and len(address_object) != 2) or (family == AF_INET6 and len(address_object) not in [2,4] )) or \
- not isinstance(address_object[0], basestring) or \
+ not isinstance(address_object[0], (basestring, types.NoneType)) or \
not isinstance(address_object[1], (int, long)):
raise TypeError(error_message)
if len(address_object) == 4 and not isinstance(address_object[3], (int, long)):
raise TypeError(error_message)
- hostname, port = address_object[0].strip(), address_object[1]
+ hostname = address_object[0]
+ if hostname is not None:
+ hostname = hostname.strip()
+ port = address_object[1]
if family == AF_INET and sock_type == SOCK_DGRAM and hostname == "<broadcast>":
hostname = INADDR_BROADCAST
- if hostname == "":
+ if hostname in ["", None]:
if flags & AI_PASSIVE:
hostname = {AF_INET: INADDR_ANY, AF_INET6: IN6ADDR_ANY_INIT}[family]
else:
@@ -815,9 +872,7 @@
_ipv4_addresses_only = value
def _getaddrinfo_get_host(host, family, flags):
- if host is None:
- return host
- if not isinstance(host, basestring):
+ if not isinstance(host, basestring) and host is not None:
raise TypeError("getaddrinfo() argument 1 must be string or None")
if flags & AI_NUMERICHOST:
if not is_ip_address(host):
@@ -850,7 +905,7 @@
int_port = int(port)
return int_port % 65536
-def getaddrinfo(host, port, family=AF_INET, socktype=None, proto=0, flags=0):
+def getaddrinfo(host, port, family=AF_UNSPEC, socktype=0, proto=0, flags=0):
try:
if _ipv4_addresses_only:
family = AF_INET
@@ -858,29 +913,43 @@
raise gaierror(errno.EIO, 'ai_family not supported')
host = _getaddrinfo_get_host(host, family, flags)
port = _getaddrinfo_get_port(port, flags)
+ if socktype not in [0, SOCK_DGRAM, SOCK_STREAM]:
+ raise error(errno.ESOCKTNOSUPPORT, "Socket type %s is not supported" % _constant_to_name(socktype, ['SOCK_']))
filter_fns = []
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])
- passive_mode = flags is not None and flags & AI_PASSIVE
- canonname_mode = flags is not None and flags & AI_CANONNAME
+ if host in [None, ""]:
+ if flags & AI_PASSIVE:
+ hosts = {AF_INET: [INADDR_ANY], AF_INET6: [IN6ADDR_ANY_INIT], AF_UNSPEC: [INADDR_ANY, IN6ADDR_ANY_INIT]}[family]
+ else:
+ hosts = ["localhost"]
+ else:
+ hosts = [host]
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:
- sockaddr = INADDR_ANY
- else:
+ for h in hosts:
+ for a in java.net.InetAddress.getAllByName(h):
+ 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 flags & AI_CANONNAME:
+ canonname = asPyString(a.getCanonicalHostName())
+ else:
+ canonname = ""
sockaddr = asPyString(a.getHostAddress())
- # TODO: Include flowinfo and scopeid in a 4-tuple for IPv6 addresses
- sock_tuple = {AF_INET : _ipv4_address_t, AF_INET6 : _ipv6_address_t}[family](sockaddr, port, a)
- results.append((family, socktype, proto, canonname, sock_tuple))
+ # TODO: Include flowinfo and scopeid in a 4-tuple for IPv6 addresses
+ sock_tuple = {AF_INET : _ipv4_address_t, AF_INET6 : _ipv6_address_t}[family](sockaddr, port, a)
+ if socktype == 0:
+ socktypes = [SOCK_DGRAM, SOCK_STREAM]
+ else:
+ socktypes = [socktype]
+ for result_socktype in socktypes:
+ result_proto = {SOCK_DGRAM: IPPROTO_UDP, SOCK_STREAM: IPPROTO_TCP}[result_socktype]
+ if proto in [0, result_proto]:
+ # The returned socket will only support the result_proto
+ # If this does not match the requested proto, don't return it
+ results.append((family, result_socktype, result_proto, canonname, sock_tuple))
return results
except java.lang.Exception, jlx:
raise _map_exception(jlx)
@@ -1120,7 +1189,7 @@
assert not self.sock_impl
assert not self.local_addr
# Do the address format check
- _get_jsockaddr(addr, self.family, self.type, self.proto, 0)
+ _get_jsockaddr(addr, self.family, self.type, self.proto, AI_PASSIVE)
self.local_addr = addr
def listen(self, backlog):
@@ -1246,7 +1315,7 @@
assert not self.sock_impl
assert not self.local_addr
# Do the address format check
- _get_jsockaddr(addr, self.family, self.type, self.proto, 0)
+ _get_jsockaddr(addr, self.family, self.type, self.proto, AI_PASSIVE)
self.local_addr = addr
self.sock_impl = _datagram_socket_impl(_get_jsockaddr(self.local_addr, self.family, self.type, self.proto, AI_PASSIVE),
self.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ])
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
@@ -277,8 +277,20 @@
def testConstantToNameMapping(self):
# Testing for mission critical constants
- for name in ['SOL_SOCKET', 'IPPROTO_TCP', 'IPPROTO_UDP', 'SO_BROADCAST', 'SO_KEEPALIVE', 'TCP_NODELAY', 'SO_ACCEPTCONN', 'SO_DEBUG']:
- self.failUnlessEqual(socket._constant_to_name(getattr(socket, name)), name)
+ for name, expected_name_starts in [
+ ('IPPROTO_ICMP', ['IPPROTO_']),
+ ('IPPROTO_TCP', ['IPPROTO_']),
+ ('IPPROTO_UDP', ['IPPROTO_']),
+ ('SO_BROADCAST', ['SO_', 'TCP_']),
+ ('SO_KEEPALIVE', ['SO_', 'TCP_']),
+ ('SO_ACCEPTCONN', ['SO_', 'TCP_']),
+ ('SO_DEBUG', ['SO_', 'TCP_']),
+ ('SOCK_DGRAM', ['SOCK_']),
+ ('SOCK_RAW', ['SOCK_']),
+ ('SOL_SOCKET', ['SOL_', 'IPPROTO_']),
+ ('TCP_NODELAY', ['SO_', 'TCP_']),
+ ]:
+ self.failUnlessEqual(socket._constant_to_name(getattr(socket, name), expected_name_starts), name)
def testHostnameRes(self):
# Testing hostname resolution mechanisms
@@ -1638,6 +1650,46 @@
else:
self.fail("getaddrinfo with bad family should have raised exception")
+ def testBadSockType(self):
+ for socktype in [socket.SOCK_RAW, socket.SOCK_RDM, socket.SOCK_SEQPACKET]:
+ try:
+ socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socktype)
+ except socket.error, se:
+ self.failUnlessEqual(se[0], errno.ESOCKTNOSUPPORT)
+ except Exception, x:
+ self.fail("getaddrinfo with bad socktype raised wrong exception: %s" % x)
+ else:
+ self.fail("getaddrinfo with bad socktype should have raised exception")
+
+ def testBadSockTypeProtoCombination(self):
+ for socktype, proto in [
+ (socket.SOCK_STREAM, socket.IPPROTO_UDP),
+ (socket.SOCK_STREAM, socket.IPPROTO_ICMP),
+ (socket.SOCK_DGRAM, socket.IPPROTO_TCP),
+ (socket.SOCK_DGRAM, socket.IPPROTO_FRAGMENT),
+ ]:
+ try:
+ results = socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socktype, proto)
+ self.failUnless(len(results) == 0, "getaddrinfo with bad socktype/proto combo should not have returned results")
+ except Exception, x:
+ self.fail("getaddrinfo with bad socktype/proto combo should not have raised exception")
+
+ def testNoSockTypeWithProto(self):
+ for expect_results, proto in [
+ (True, socket.IPPROTO_UDP),
+ (False, socket.IPPROTO_ICMP),
+ (True, socket.IPPROTO_TCP),
+ (False, socket.IPPROTO_FRAGMENT),
+ ]:
+ try:
+ results = socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, 0, proto)
+ if expect_results:
+ self.failUnless(len(results) > 0, "getaddrinfo with no socktype and supported proto combo should have returned results")
+ else:
+ self.failUnless(len(results) == 0, "getaddrinfo with no socktype and unsupported proto combo should not have returned results")
+ except Exception, x:
+ self.fail("getaddrinfo with no socktype (un)supported proto combo should not have raised exception")
+
def testReturnsAreStrings(self):
addrinfos = socket.getaddrinfo(HOST, PORT)
for addrinfo in addrinfos:
@@ -1772,12 +1824,15 @@
self.fail("getaddrinfo for unknown service name failed to raise exception")
def testHostNames(self):
- # None is always acceptable
- for flags in [0, socket.AI_NUMERICHOST]:
+ # None is only acceptable if AI_NUMERICHOST is not specified
+ for flags, expect_exception in [(0, False), (socket.AI_NUMERICHOST, True)]:
try:
socket.getaddrinfo(None, 80, 0, 0, 0, flags)
+ if expect_exception:
+ self.fail("Non-numeric hostname == None should have raised exception")
except Exception, x:
- self.fail("hostname == None should not have raised exception: %s" % str(x))
+ if not expect_exception:
+ self.fail("hostname == None should not have raised exception: %s" % str(x))
# Check enforcement of AI_NUMERICHOST
for host in ["", " ", "localhost"]:
@@ -1905,7 +1960,7 @@
(socket.AF_INET, ("localhost", 80), java.net.Inet4Address, ["127.0.0.1"]),
(socket.AF_INET6, ("localhost", 80), java.net.Inet6Address, ["::1", "0:0:0:0:0:0:0:1"]),
]:
- sockaddr = socket._get_jsockaddr(addr_tuple, family, None, 0, 0)
+ sockaddr = socket._get_jsockaddr(addr_tuple, family, 0, 0, 0)
self.failUnless(isinstance(sockaddr, java.net.InetSocketAddress), "_get_jsockaddr returned wrong type: '%s'" % str(type(sockaddr)))
self.failUnless(isinstance(sockaddr.address, jaddress_type), "_get_jsockaddr returned wrong address type: '%s'(family=%d)" % (str(type(sockaddr.address)), family))
self.failUnless(sockaddr.address.hostAddress in expected)
@@ -1916,7 +1971,7 @@
("localhost", 80),
("localhost", 80, 0, 0),
]:
- sockaddr = socket._get_jsockaddr(addr_tuple, socket.AF_INET6, None, 0, 0)
+ sockaddr = socket._get_jsockaddr(addr_tuple, socket.AF_INET6, 0, 0, 0)
self.failUnless(isinstance(sockaddr, java.net.InetSocketAddress), "_get_jsockaddr returned wrong type: '%s'" % str(type(sockaddr)))
self.failUnless(isinstance(sockaddr.address, java.net.Inet6Address), "_get_jsockaddr returned wrong address type: '%s'" % str(type(sockaddr.address)))
self.failUnless(sockaddr.address.hostAddress in ["::1", "0:0:0:0:0:0:0:1"])
@@ -1925,10 +1980,10 @@
def testSpecialHostnames(self):
for family, sock_type, flags, addr_tuple, expected in [
- ( socket.AF_INET, None, 0, ("", 80), ["localhost"]),
- ( socket.AF_INET, None, socket.AI_PASSIVE, ("", 80), [socket.INADDR_ANY]),
- ( socket.AF_INET6, None, 0, ("", 80), ["localhost"]),
- ( socket.AF_INET6, None, socket.AI_PASSIVE, ("", 80), [socket.IN6ADDR_ANY_INIT, "0:0:0:0:0:0:0:0"]),
+ ( socket.AF_INET, 0, 0, ("", 80), ["localhost"]),
+ ( socket.AF_INET, 0, socket.AI_PASSIVE, ("", 80), [socket.INADDR_ANY]),
+ ( socket.AF_INET6, 0, 0, ("", 80), ["localhost"]),
+ ( socket.AF_INET6, 0, socket.AI_PASSIVE, ("", 80), [socket.IN6ADDR_ANY_INIT, "0:0:0:0:0:0:0:0"]),
( socket.AF_INET, socket.SOCK_DGRAM, 0, ("<broadcast>", 80), [socket.INADDR_BROADCAST]),
]:
sockaddr = socket._get_jsockaddr(addr_tuple, family, sock_type, 0, flags)
@@ -1941,7 +1996,7 @@
( socket.AF_INET6, 0, ["localhost"]),
( socket.AF_INET6, socket.AI_PASSIVE, [socket.IN6ADDR_ANY_INIT, "0:0:0:0:0:0:0:0"]),
]:
- sockaddr = socket._get_jsockaddr(None, family, None, 0, flags)
+ sockaddr = socket._get_jsockaddr(None, family, 0, 0, flags)
self.failUnless(sockaddr.hostName in expected, "_get_jsockaddr returned wrong hostname '%s' for sock tuple == None (family=%d)" % (sockaddr.hostName, family))
def testBadAddressTuples(self):
--
Repository URL: http://hg.python.org/jython
More information about the Jython-checkins
mailing list