123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- # -*- test-case-name: twisted.names.test -*-
- # Copyright (c) Twisted Matrix Laboratories.
- # See LICENSE for details.
-
- """
- An in-memory caching resolver.
- """
-
-
- from twisted.internet import defer
- from twisted.names import common, dns
- from twisted.python import failure, log
-
-
- class CacheResolver(common.ResolverBase):
- """
- A resolver that serves records from a local, memory cache.
-
- @ivar _reactor: A provider of L{interfaces.IReactorTime}.
- """
-
- cache = None
-
- def __init__(self, cache=None, verbose=0, reactor=None):
- common.ResolverBase.__init__(self)
-
- self.cache = {}
- self.verbose = verbose
- self.cancel = {}
- if reactor is None:
- from twisted.internet import reactor
- self._reactor = reactor
-
- if cache:
- for query, (seconds, payload) in cache.items():
- self.cacheResult(query, payload, seconds)
-
- def __setstate__(self, state):
- self.__dict__ = state
-
- now = self._reactor.seconds()
- for (k, (when, (ans, add, ns))) in self.cache.items():
- diff = now - when
- for rec in ans + add + ns:
- if rec.ttl < diff:
- del self.cache[k]
- break
-
- def __getstate__(self):
- for c in self.cancel.values():
- c.cancel()
- self.cancel.clear()
- return self.__dict__
-
- def _lookup(self, name, cls, type, timeout):
- now = self._reactor.seconds()
- q = dns.Query(name, type, cls)
- try:
- when, (ans, auth, add) = self.cache[q]
- except KeyError:
- if self.verbose > 1:
- log.msg("Cache miss for " + repr(name))
- return defer.fail(failure.Failure(dns.DomainError(name)))
- else:
- if self.verbose:
- log.msg("Cache hit for " + repr(name))
- diff = now - when
-
- try:
- result = (
- [
- dns.RRHeader(
- r.name.name, r.type, r.cls, r.ttl - diff, r.payload
- )
- for r in ans
- ],
- [
- dns.RRHeader(
- r.name.name, r.type, r.cls, r.ttl - diff, r.payload
- )
- for r in auth
- ],
- [
- dns.RRHeader(
- r.name.name, r.type, r.cls, r.ttl - diff, r.payload
- )
- for r in add
- ],
- )
- except ValueError:
- return defer.fail(failure.Failure(dns.DomainError(name)))
- else:
- return defer.succeed(result)
-
- def lookupAllRecords(self, name, timeout=None):
- return defer.fail(failure.Failure(dns.DomainError(name)))
-
- def cacheResult(self, query, payload, cacheTime=None):
- """
- Cache a DNS entry.
-
- @param query: a L{dns.Query} instance.
-
- @param payload: a 3-tuple of lists of L{dns.RRHeader} records, the
- matching result of the query (answers, authority and additional).
-
- @param cacheTime: The time (seconds since epoch) at which the entry is
- considered to have been added to the cache. If L{None} is given,
- the current time is used.
- """
- if self.verbose > 1:
- log.msg("Adding %r to cache" % query)
-
- self.cache[query] = (cacheTime or self._reactor.seconds(), payload)
-
- if query in self.cancel:
- self.cancel[query].cancel()
-
- s = list(payload[0]) + list(payload[1]) + list(payload[2])
- if s:
- m = s[0].ttl
- for r in s:
- m = min(m, r.ttl)
- else:
- m = 0
-
- self.cancel[query] = self._reactor.callLater(m, self.clearEntry, query)
-
- def clearEntry(self, query):
- del self.cache[query]
- del self.cancel[query]
|