Commit 58058cca authored by Vincent Pelletier's avatar Vincent Pelletier

Always call getaddrinfo on split host.

Fixes two bugs:
- IPv6 addresses are now put in canonical form.
- non-IPv6 port-less addresses are resolved.
Also, simplify url-style IPv6 parsing.
Also, rename "ip" into more generic naming "host".
parent 1c4cf8aa
......@@ -55,17 +55,6 @@ def makeChecksum(s):
return sha1(s).digest()
def resolve(hostname):
"""
Returns the first IP address that match with the given hostname
"""
try:
# an IP resolves to itself
_, _, address_list = socket.gethostbyname_ex(hostname)
except socket.gaierror:
return None
return address_list[0]
def getAddressType(address):
"Return the type (IPv4 or IPv6) of an ip"
(host, port) = address
......@@ -86,22 +75,22 @@ def getConnectorFromAddress(address):
return SOCKET_CONNECTORS_DICT[address_type]
def parseNodeAddress(address, port_opt=None):
if ']' in address:
(ip, port) = address.split(']')
ip = ip.lstrip('[')
port = port.lstrip(':')
if port == '':
if address[:1] == '[':
(host, port) = address[1:].split(']')
if port[:1] == ':':
port = port[1:]
else:
port = port_opt
elif ':' in address:
(ip, port) = address.split(':')
ip = resolve(ip)
elif address.count(':') == 1:
(host, port) = address.split(':')
else:
ip = address
host = address
port = port_opt
if port is None:
raise ValueError
return (ip, int(port))
# Resolve (maybe) and cast to cannonical form
# XXX: Always pick the first result. This might not be what is desired, and
# if so this function should either take a hint on the desired address type
# or return either raw host & port or getaddrinfo return value.
return socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)[0][4][:2]
def parseMasterList(masters, except_node=None):
assert masters, 'At least one master must be defined'
......
......@@ -44,22 +44,24 @@ class UtilTests(NeoUnitTestBase):
address_type = getAddressType(('127.0.0.1', 0))
self.assertEqual(address_type, socket.AF_INET)
def _assertEqualParsedAddress(self, parsed, *args, **kw):
self.assertEqual(parsed, parseNodeAddress(*args, **kw))
def test_parseNodeAddress(self):
""" Parsing of addesses """
ip_address = parseNodeAddress('127.0.0.1:0')
self.assertEqual(('127.0.0.1', 0), ip_address)
ip_address = parseNodeAddress('127.0.0.1:0', 100)
self.assertEqual(('127.0.0.1', 0), ip_address)
ip_address = parseNodeAddress('127.0.0.1', 500)
self.assertEqual(('127.0.0.1', 500), ip_address)
self.assertRaises(ValueError, parseNodeAddress, '127.0.0.1')
ip_address = parseNodeAddress('[::1]:0')
self.assertEqual(('::1', 0), ip_address)
ip_address = parseNodeAddress('[::1]:0', 100)
self.assertEqual(('::1', 0), ip_address)
ip_address = parseNodeAddress('[::1]', 500)
self.assertEqual(('::1', 500), ip_address)
self.assertRaises(ValueError, parseNodeAddress, ('[::1]'))
test = self._assertEqualParsedAddress
local_address = socket.gethostbyname('localhost')
http_port = socket.getservbyname('http')
test(('127.0.0.1', 0), '127.0.0.1')
test(('127.0.0.1', 10), '127.0.0.1:10', 500)
test(('127.0.0.1', 500), '127.0.0.1', 500)
test(('::1', 0), '[::1]')
test(('::1', 10), '[::1]:10', 500)
test(('::1', 500), '[::1]', 500)
test(('::1', http_port), '[::1]:http')
test(('::1', 0), '[0::01]')
test((local_address, 0), 'localhost')
test((local_address, 10), 'localhost:10')
def testReadBufferRead(self):
""" Append some chunk then consume the data """
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment