Browse Source

dns hacks on windows: resolve A and AAAA records in parallel

hard-fail-on-bad-server-string
SomberNight 5 years ago
committed by ghost43
parent
commit
cb88a3b6e4
  1. 20
      electrum/network.py

20
electrum/network.py

@ -228,6 +228,8 @@ class UntrustedServerReturnedError(NetworkException):
return f"<UntrustedServerReturnedError original_exception: {repr(self.original_exception)}>" return f"<UntrustedServerReturnedError original_exception: {repr(self.original_exception)}>"
_dns_threads_executor = None # type: Optional[concurrent.futures.Executor]
_INSTANCE = None _INSTANCE = None
@ -567,10 +569,13 @@ class Network(Logger):
# On Windows, socket.getaddrinfo takes a mutex, and might hold it for up to 10 seconds # On Windows, socket.getaddrinfo takes a mutex, and might hold it for up to 10 seconds
# when dns-resolving. To speed it up drastically, we resolve dns ourselves, outside that lock. # when dns-resolving. To speed it up drastically, we resolve dns ourselves, outside that lock.
# see #4421 # see #4421
socket.getaddrinfo = self._fast_getaddrinfo
resolver = dns.resolver.get_default_resolver() resolver = dns.resolver.get_default_resolver()
if resolver.cache is None: if resolver.cache is None:
resolver.cache = dns.resolver.Cache() resolver.cache = dns.resolver.Cache()
global _dns_threads_executor
if _dns_threads_executor is None:
_dns_threads_executor = concurrent.futures.ThreadPoolExecutor(max_workers=20)
socket.getaddrinfo = self._fast_getaddrinfo
else: else:
socket.getaddrinfo = socket._getaddrinfo socket.getaddrinfo = socket._getaddrinfo
self.trigger_callback('proxy_set', self.proxy) self.trigger_callback('proxy_set', self.proxy)
@ -588,20 +593,23 @@ class Network(Logger):
return True return True
def resolve_with_dnspython(host): def resolve_with_dnspython(host):
addrs = [] addrs = []
expected_dnspython_errors = (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer) expected_errors = (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer,
concurrent.futures.CancelledError, concurrent.futures.TimeoutError)
ipv6_fut = _dns_threads_executor.submit(dns.resolver.query, host, dns.rdatatype.AAAA)
ipv4_fut = _dns_threads_executor.submit(dns.resolver.query, host, dns.rdatatype.A)
# try IPv6 # try IPv6
try: try:
answers = dns.resolver.query(host, dns.rdatatype.AAAA) answers = ipv6_fut.result()
addrs += [str(answer) for answer in answers] addrs += [str(answer) for answer in answers]
except expected_dnspython_errors as e: except expected_errors as e:
pass pass
except BaseException as e: except BaseException as e:
_logger.info(f'dnspython failed to resolve dns (AAAA) for {repr(host)} with error: {repr(e)}') _logger.info(f'dnspython failed to resolve dns (AAAA) for {repr(host)} with error: {repr(e)}')
# try IPv4 # try IPv4
try: try:
answers = dns.resolver.query(host, dns.rdatatype.A) answers = ipv4_fut.result()
addrs += [str(answer) for answer in answers] addrs += [str(answer) for answer in answers]
except expected_dnspython_errors as e: except expected_errors as e:
# dns failed for some reason, e.g. dns.resolver.NXDOMAIN this is normal. # dns failed for some reason, e.g. dns.resolver.NXDOMAIN this is normal.
# Simply report back failure; except if we already have some results. # Simply report back failure; except if we already have some results.
if not addrs: if not addrs:

Loading…
Cancel
Save