ayncio, Tulip issue 129: BaseEventLoop.sock_connect() now raises an error if

the address is not resolved (hostname instead of an IP address) for AF_INET and
AF_INET6 address families.
This commit is contained in:
Victor Stinner 2014-02-13 09:24:37 +01:00
parent 7dfaa27fdd
commit 28773465e6
5 changed files with 59 additions and 13 deletions

View file

@ -41,6 +41,31 @@ class _StopError(BaseException):
"""Raised to stop the event loop."""
def _check_resolved_address(sock, address):
# Ensure that the address is already resolved to avoid the trap of hanging
# the entire event loop when the address requires doing a DNS lookup.
family = sock.family
if family not in (socket.AF_INET, socket.AF_INET6):
return
host, port = address
type_mask = 0
if hasattr(socket, 'SOCK_NONBLOCK'):
type_mask |= socket.SOCK_NONBLOCK
if hasattr(socket, 'SOCK_CLOEXEC'):
type_mask |= socket.SOCK_CLOEXEC
# Use getaddrinfo(AI_NUMERICHOST) to ensure that the address is
# already resolved.
try:
socket.getaddrinfo(host, port,
family=family,
type=(sock.type & ~type_mask),
proto=sock.proto,
flags=socket.AI_NUMERICHOST)
except socket.gaierror as err:
raise ValueError("address must be resolved (IP address), got %r: %s"
% (address, err))
def _raise_stop_error(*args):
raise _StopError

View file

@ -404,7 +404,14 @@ class BaseProactorEventLoop(base_events.BaseEventLoop):
return self._proactor.send(sock, data)
def sock_connect(self, sock, address):
return self._proactor.connect(sock, address)
try:
base_events._check_resolved_address(sock, address)
except ValueError as err:
fut = futures.Future(loop=self)
fut.set_exception(err)
return fut
else:
return self._proactor.connect(sock, address)
def sock_accept(self, sock):
return self._proactor.accept(sock)

View file

@ -208,6 +208,8 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop):
return fut
def _sock_recv(self, fut, registered, sock, n):
# _sock_recv() can add itself as an I/O callback if the operation can't
# be done immediatly. Don't use it directly, call sock_recv().
fd = sock.fileno()
if registered:
# Remove the callback early. It should be rare that the
@ -260,22 +262,16 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop):
def sock_connect(self, sock, address):
"""XXX"""
# That address better not require a lookup! We're not calling
# self.getaddrinfo() for you here. But verifying this is
# complicated; the socket module doesn't have a pattern for
# IPv6 addresses (there are too many forms, apparently).
fut = futures.Future(loop=self)
self._sock_connect(fut, False, sock, address)
try:
base_events._check_resolved_address(sock, address)
except ValueError as err:
fut.set_exception(err)
else:
self._sock_connect(fut, False, sock, address)
return fut
def _sock_connect(self, fut, registered, sock, address):
# TODO: Use getaddrinfo() to look up the address, to avoid the
# trap of hanging the entire event loop when the address
# requires doing a DNS lookup. (OTOH, the caller should
# already have done this, so it would be nice if we could
# easily tell whether the address needs looking up or not. I
# know how to do this for IPv4, but IPv6 addresses have many
# syntaxes.)
fd = sock.fileno()
if registered:
self.remove_writer(fd)