From 660564a1b1490f71cd18a4861b521396b6bdb67d Mon Sep 17 00:00:00 2001 Message-Id: <660564a1b1490f71cd18a4861b521396b6bdb67d.1714566094.git.mdw@distorted.org.uk> From: Mark Wooding Date: Tue, 26 Sep 2017 22:37:16 +0100 Subject: [PATCH] peerdb/tripe-newpeers.in: Split out a class for a host's resolved names. Organization: Straylight/Edgeware From: Mark Wooding This becomes the primary kind of object maintained in the resolver's dictionary. Also formalize the arrangements for reporting whether name resolution failed. This is an initial step towards introducing IPv6 support, initially in this program, and later across the entire project. --- peerdb/tripe-newpeers.in | 69 +++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/peerdb/tripe-newpeers.in b/peerdb/tripe-newpeers.in index 81e62f75..502492d9 100644 --- a/peerdb/tripe-newpeers.in +++ b/peerdb/tripe-newpeers.in @@ -60,6 +60,32 @@ class ResolverFailure (ExpectedError): def __str__(me): return "failed to resolve `%s': %s" % (me.host, me.msg) +class ResolvingHost (object): + """ + A host name which is being looked up by a bulk-resolver instance. + """ + + def __init__(me, name): + """Make a new resolving-host object for the host NAME.""" + me.name = name + me.addr = None + me.failure = None + + def setaddr(me, addr): + """Add the address ADDR.""" + me.addr = addr + + def failed(me, msg): + """ + Report that resolution of this host failed, with a human-readable MSG. + """ + me.failure = msg + + def get(me): + """Return the resolved address.""" + if me.failure is not None: raise ResolverFailure(me.name, me.failure) + return me.addr + class BulkResolver (object): """ Resolve a number of DNS names in parallel. @@ -78,36 +104,35 @@ class BulkResolver (object): def __init__(me): """Initialize the resolver.""" - me._resolvers = {} me._namemap = {} - - def prepare(me, host): - """Prime the resolver to resolve the name HOST.""" - if host not in me._resolvers: - me._resolvers[host] = M.SelResolveByName \ - (host, - lambda name, alias, addr: - me._resolved(host, addr[0]), - lambda: me._resolved(host, None)) + me._noutstand = 0 + + def prepare(me, name): + """Prime the resolver to resolve the given host NAME.""" + if name not in me._namemap: + me._namemap[name] = host = ResolvingHost(name) + host._resolv = M.SelResolveByName( + name, + lambda cname, alias, addr: me._resolved(host, addr[0]), + lambda: me._resolved(host, None)) + me._noutstand += 1 def run(me): """Run the background DNS resolver until it's finished.""" - while me._resolvers: - M.select() + while me._noutstand: M.select() - def lookup(me, host): - """ - Fetch the address corresponding to HOST. - """ - addr = me._namemap[host] - if addr is None: - raise ResolverFailure(host, '(unknown failure)') - return addr + def lookup(me, name): + """Fetch the address corresponding to the host NAME.""" + return me._namemap[name].get() def _resolved(me, host, addr): """Callback function: remember that ADDR is the address for HOST.""" - me._namemap[host] = addr - del me._resolvers[host] + if addr is None: + host.failed('(unknown failure)') + else: + host.setaddr(addr) + host._resolv = None + me._noutstand -= 1 ###-------------------------------------------------------------------------- ### The configuration parser. -- [mdw]