--- /dev/null
+import pycares
+import socket
+
+from tornado.concurrent import return_future
+from tornado import gen
+from tornado.ioloop import IOLoop
+from tornado.netutil import Resolver, is_valid_ip
+
+class CaresResolver(Resolver):
+ """Name resolver based on the c-ares library.
+
+ This is a non-blocking and non-threaded resolver. It may not produce
+ the same results as the system resolver, but can be used for non-blocking
+ resolution when threads cannot be used.
+ """
+ def initialize(self, io_loop=None):
+ self.io_loop = io_loop or IOLoop.instance()
+ self.channel = pycares.Channel(sock_state_cb=self._sock_state_cb)
+ self.fds = {}
+
+ def _sock_state_cb(self, fd, readable, writable):
+ state = ((IOLoop.READ if readable else 0) |
+ (IOLoop.WRITE if writable else 0))
+ if not state:
+ self.io_loop.remove_handler(fd)
+ del self.fds[fd]
+ elif fd in self.fds:
+ self.io_loop.update_handler(fd, state)
+ self.fds[fd] = state
+ else:
+ self.io_loop.add_handler(fd, self._handle_events, state)
+ self.fds[fd] = state
+
+ def _handle_events(self, fd, events):
+ read_fd = pycares.ARES_SOCKET_BAD
+ write_fd = pycares.ARES_SOCKET_BAD
+ if events & IOLoop.READ:
+ read_fd = fd
+ if events & IOLoop.WRITE:
+ write_fd = fd
+ self.channel.process_fd(read_fd, write_fd)
+
+ @return_future
+ @gen.engine
+ def getaddrinfo(self, host, port, family=0, socktype=0, proto=0,
+ flags=0, callback=None):
+ if is_valid_ip(host):
+ addresses = [host]
+ else:
+ # gethostbyname doesn't take callback as a kwarg
+ self.channel.gethostbyname(host, family, (yield gen.Callback(1)))
+ callback_args = yield gen.Wait(1)
+ assert isinstance(callback_args, gen.Arguments)
+ assert not callback_args.kwargs
+ result, error = callback_args.args
+ if error:
+ raise Exception('C-Ares returned error %s: %s while resolving %s' %
+ (error, pycares.errno.strerror(error), host))
+ addresses = result.addresses
+ addrinfo = []
+ for address in addresses:
+ if '.' in address:
+ address_family = socket.AF_INET
+ elif ':' in address:
+ address_family = socket.AF_INET6
+ else:
+ address_family = socket.AF_UNSPEC
+ if family != socket.AF_UNSPEC and family != address_family:
+ raise Exception('Requested socket family %d but got %d' %
+ (family, address_family))
+ addrinfo.append((address_family, socktype, proto, '', (address, port)))
+ callback(addrinfo)
[tox]
# "-full" variants include optional dependencies, to ensure
# that things work both in a bare install and with all the extras.
-envlist = py27-full, py27-curl, py32-full, pypy, py26, py26-full, py27, py32, py32-utf8, py33, py27-opt, py32-opt, pypy-full, py27-select, py27-monotonic, py33-monotonic, py27-twisted, py27-threadedresolver, py27-twistedresolver, py27-twistedlayered
+envlist = py27-full, py27-curl, py32-full, pypy, py26, py26-full, py27, py32, py32-utf8, py33, py27-opt, py32-opt, pypy-full, py27-select, py27-monotonic, py33-monotonic, py27-twisted, py27-threadedresolver, py27-twistedresolver, py27-twistedlayered, py27-caresresolver, py32-caresresolver
[testenv]
commands = python -m tornado.test.runtests {posargs:}
twisted
commands = python -m tornado.test.runtests --ioloop=tornado.test.twisted_test.LayeredTwistedIOLoop --resolver=tornado.platform.twisted.TwistedResolver {posargs:}
+[testenv:py27-caresresolver]
+basepython = python2.7
+deps =
+ futures
+ mock
+ pycares
+ pycurl
+ twisted
+commands = python -m tornado.test.runtests --resolver=tornado.platform.caresresolver.CaresResolver {posargs:}
+
[testenv:pypy-full]
# This configuration works with pypy 1.9. pycurl installs ok but
# curl_httpclient doesn't work. Twisted works most of the time, but
basepython = python3.3
commands = python -m tornado.test.runtests --ioloop_time_monotonic {posargs:}
+[testenv:py32-caresresolver]
+basepython = python3.2
+deps =
+ pycares
+commands = python -m tornado.test.runtests --resolver=tornado.platform.caresresolver.CaresResolver {posargs:}
+
+
# Python's optimized mode disables the assert statement, so run the
# tests in this mode to ensure we haven't fallen into the trap of relying
# on an assertion's side effects or using them for things that should be