Exemple #1
0
 def __init__(self, loop):
     self._loop = loop
     self._hosts = load_hosts_conf()
     self._servers = load_resolv_conf()
     self._callbacks = {}
     self._cache = LRUCache(timeout=300, **self._hosts)
     self._sock = None
     # TODO monitor hosts change and reload hosts
     # TODO parse /etc/gai.conf and follow its rules
     self._register_to_loop()
Exemple #2
0
 def __init__(self, loop):
     self._loop = loop
     self._hosts = load_hosts_conf()
     self._servers = load_resolv_conf()
     self._callbacks = {}
     self._cache = LRUCache(timeout=300, **self._hosts)
     self._sock = None
     # TODO monitor hosts change and reload hosts
     # TODO parse /etc/gai.conf and follow its rules
     self._register_to_loop()
Exemple #3
0
class DNSResolver(object):

    def __init__(self, loop):
        self._loop = loop
        self._hosts = load_hosts_conf()
        self._servers = load_resolv_conf()
        self._callbacks = {}
        self._cache = LRUCache(timeout=300, **self._hosts)
        self._sock = None
        # TODO monitor hosts change and reload hosts
        # TODO parse /etc/gai.conf and follow its rules
        self._register_to_loop()

    def _register_to_loop(self):
        self._sock = Socket(self._servers)
        self._sock.setblocking(False)
        self._loop.register(self._sock, MainLoop.EVENT_READ, self.handle_event)
        self._loop.add_timeout(self._handle_timeout, 20)

    def _call_callback(self, hostname, ipaddr, error=None):
        """domain resolved, execute the callbacks"""
        DEBUG('DNS callback %s:%s' % (hostname, ipaddr))
        for callback in self._callbacks.get(hostname, []):
            if ipaddr or error:
                callback((hostname, ipaddr), error)
            else:
                callback((hostname, None),
                         Exception('unknown hostname %s' % hostname))
        if hostname in self._callbacks:
            del self._callbacks[hostname]

    def _send_request(self, hostname):
        DEBUG('query DNS %s' % hostname)
        self._sock.send_dns_request(hostname)

    def _handle_response(self, response):
        if response is None:
            """wait another response"""
            return
        if response.is_valid():
            self._cache[response.hostname] = response.answer
        self._call_callback(response.hostname, response.answer)

    def handle_event(self, sock, event):
        if sock != self._sock:
            return
        if event & MainLoop.EVENT_ERROR:
            ERROR('dns socket error')
            self._loop.remove(self._sock)
            self._sock.close()
            self._refresh()
        elif event & MainLoop.EVENT_READ:
            response = sock.recv_dns_response()
            self._handle_response(response)

    def _handle_timeout(self):
        self._cache.sweep()

    def resolve(self, host, callback):
        """resolve a domain names"""
        hostname = tobytes(host)
        if not hostname or not check_hostname(hostname):
            callback(None, Exception('invalid hostname: %s' % hostname))
        elif ip_address(hostname):
            callback((hostname, hostname), None)
        elif hostname in self._cache:
            DEBUG('hit cache: %s' % host)
            ip = self._cache[hostname]
            callback((hostname, ip), None)
        else:
            arr = self._callbacks.get(hostname, None)
            if not arr:
                self._callbacks[hostname] = [callback]
                self._send_request(hostname)
            else:
                arr.append(callback)
                # TODO send again only if waited too long
                self._send_request(hostname)

    def close(self):
        if self._sock:
            if self._loop:
                self._loop.remove_timeout(self._handle_timeout)
                self._loop.unregister(self._sock)
            self._sock.close()
            self._sock = None
Exemple #4
0
class DNSResolver(object):
    def __init__(self, loop):
        self._loop = loop
        self._hosts = load_hosts_conf()
        self._servers = load_resolv_conf()
        self._callbacks = {}
        self._cache = LRUCache(timeout=300, **self._hosts)
        self._sock = None
        # TODO monitor hosts change and reload hosts
        # TODO parse /etc/gai.conf and follow its rules
        self._register_to_loop()

    def _register_to_loop(self):
        self._sock = Socket(self._servers)
        self._sock.setblocking(False)
        self._loop.register(self._sock, MainLoop.EVENT_READ, self.handle_event)
        self._loop.add_timeout(self._handle_timeout, 20)

    def _call_callback(self, hostname, ipaddr, error=None):
        """domain resolved, execute the callbacks"""
        DEBUG('DNS callback %s:%s' % (hostname, ipaddr))
        for callback in self._callbacks.get(hostname, []):
            if ipaddr or error:
                callback((hostname, ipaddr), error)
            else:
                callback((hostname, None),
                         Exception('unknown hostname %s' % hostname))
        if hostname in self._callbacks:
            del self._callbacks[hostname]

    def _send_request(self, hostname):
        DEBUG('query DNS %s' % hostname)
        self._sock.send_dns_request(hostname)

    def _handle_response(self, response):
        if response is None:
            """wait another response"""
            return
        if response.is_valid():
            self._cache[response.hostname] = response.answer
        self._call_callback(response.hostname, response.answer)

    def handle_event(self, sock, event):
        if sock != self._sock:
            return
        if event & MainLoop.EVENT_ERROR:
            ERROR('dns socket error')
            self._loop.remove(self._sock)
            self._sock.close()
            self._refresh()
        elif event & MainLoop.EVENT_READ:
            response = sock.recv_dns_response()
            self._handle_response(response)

    def _handle_timeout(self):
        self._cache.sweep()

    def resolve(self, host, callback):
        """resolve a domain names"""
        hostname = tobytes(host)
        if not hostname or not check_hostname(hostname):
            callback(None, Exception('invalid hostname: %s' % hostname))
        elif ip_address(hostname):
            callback((hostname, hostname), None)
        elif hostname in self._cache:
            DEBUG('hit cache: %s' % host)
            ip = self._cache[hostname]
            callback((hostname, ip), None)
        else:
            arr = self._callbacks.get(hostname, None)
            if not arr:
                self._callbacks[hostname] = [callback]
                self._send_request(hostname)
            else:
                arr.append(callback)
                # TODO send again only if waited too long
                self._send_request(hostname)

    def close(self):
        if self._sock:
            if self._loop:
                self._loop.remove_timeout(self._handle_timeout)
                self._loop.unregister(self._sock)
            self._sock.close()
            self._sock = None