electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 2693d345f9c63b9f14000e80b0be13b09a809f5d
parent 402b49e76b9360edf6dc0af0bd30e2126f815f8e
Author: ThomasV <thomasv@electrum.org>
Date:   Mon,  2 Jul 2018 08:14:31 +0200

Merge pull request #4486 from SomberNight/getaddrinfo_take2

socket.getaddrinfo on win32: do our own dns resolution
Diffstat:
Mlib/network.py | 42+++++++++++++++++++++++++++++++++++++++++-
1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/lib/network.py b/lib/network.py @@ -31,9 +31,15 @@ from collections import defaultdict import threading import socket import json +import sys +import ipaddress +import dns +import dns.resolver import socks + from . import util +from .util import print_error from . import bitcoin from .bitcoin import COIN from . import constants @@ -444,7 +450,41 @@ class Network(util.DaemonThread): socket.getaddrinfo = lambda *args: [(socket.AF_INET, socket.SOCK_STREAM, 6, '', (args[0], args[1]))] else: socket.socket = socket._socketobject - socket.getaddrinfo = socket._getaddrinfo + if sys.platform == 'win32': + # 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. + # see #4421 + socket.getaddrinfo = self._fast_getaddrinfo + else: + socket.getaddrinfo = socket._getaddrinfo + + @staticmethod + def _fast_getaddrinfo(host, *args, **kwargs): + def needs_dns_resolving(host2): + try: + ipaddress.ip_address(host2) + return False # already valid IP + except ValueError: + pass # not an IP + if str(host) in ('localhost', 'localhost.',): + return False + return True + try: + if needs_dns_resolving(host): + answers = dns.resolver.query(host) + addr = str(answers[0]) + else: + addr = host + except dns.exception.DNSException: + # dns failed for some reason, e.g. dns.resolver.NXDOMAIN + # this is normal. Simply report back failure: + raise socket.gaierror(11001, 'getaddrinfo failed') + except BaseException as e: + # Possibly internal error in dnspython :( see #4483 + # Fall back to original socket.getaddrinfo to resolve dns. + print_error('dnspython failed to resolve dns with error:', e) + addr = host + return socket._getaddrinfo(addr, *args, **kwargs) @with_interface_lock def start_network(self, protocol, proxy):