diff --git a/resolver/src/config.rs b/resolver/src/config.rs index f6527c979f..519c48df52 100644 --- a/resolver/src/config.rs +++ b/resolver/src/config.rs @@ -201,6 +201,8 @@ pub struct ResolverOpts { pub validate: bool, /// The ip_strategy for the Resolver to use when lookup Ipv4 or Ipv6 addresses pub ip_strategy: LookupIpStrategy, + /// Cache size is in number of records (some records can be large) + pub cache_size: usize, } impl Default for ResolverOpts { @@ -217,6 +219,7 @@ impl Default for ResolverOpts { edns0: false, validate: false, ip_strategy: LookupIpStrategy::default(), + cache_size: 32, } } } diff --git a/resolver/src/lookup_ip.rs b/resolver/src/lookup_ip.rs index 9b941575a4..33d8cb8845 100644 --- a/resolver/src/lookup_ip.rs +++ b/resolver/src/lookup_ip.rs @@ -74,18 +74,6 @@ impl ClientHandle for LookupIpEither { } } -// impl Future for LookupIpEither { -// type Item = LookupIp; -// type Error = io::Error; - -// fn poll(&mut self) -> Poll { -// match self { -// LookupIpEither::Retry(f) => f.poll(), -// LookupIpEither::Secure(f) => f.poll(), -// } -// } -// } - /// The Future returned from ResolverFuture when performing an A or AAAA lookup. pub type LookupIpFuture = InnerLookupIpFuture; @@ -253,9 +241,7 @@ impl Future for InsertCache { let name = mem::replace(&mut self.name, Name::root()); let ips = mem::replace(&mut self.ips, vec![]); - return Ok(Async::Ready( - lru.insert(name, ips, Instant::now()), - )); + return Ok(Async::Ready(lru.insert(name, ips, Instant::now()))); } } } @@ -389,7 +375,6 @@ impl Future for LookupIpState { } } -// TODO: rename this to query? /// returns a new future for lookup fn strategic_lookup( name: Name, @@ -567,7 +552,7 @@ mod tests { message.insert_answers(vec![ Record::from_rdata( Name::root(), - 0, + 86400, RecordType::A, RData::A(Ipv4Addr::new(127, 0, 0, 1)) ), @@ -580,7 +565,7 @@ mod tests { message.insert_answers(vec![ Record::from_rdata( Name::root(), - 0, + 86400, RecordType::AAAA, RData::AAAA(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)) ), @@ -747,4 +732,74 @@ mod tests { vec![Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)] ); } + + #[test] + fn test_empty_cache() { + let cache = Arc::new(Mutex::new(DnsLru::new(1))); + let mut client = mock(vec![empty()]); + + let ips = + LookupIpState::lookup(Name::root(), LookupIpStrategy::Ipv4Only, &mut client, cache) + .wait() + .unwrap(); + + assert!(ips.iter().next().is_none()); + } + + #[test] + fn test_from_cache() { + let cache = Arc::new(Mutex::new(DnsLru::new(1))); + cache.lock().unwrap().insert( + Name::root(), + vec![ + (IpAddr::from(Ipv4Addr::new(127, 0, 0, 1)), u32::max_value()), + ], + Instant::now(), + ); + + let mut client = mock(vec![empty()]); + + let ips = + LookupIpState::lookup(Name::root(), LookupIpStrategy::Ipv4Only, &mut client, cache) + .wait() + .unwrap(); + + assert_eq!( + ips.iter().cloned().collect::>(), + vec![Ipv4Addr::new(127, 0, 0, 1)] + ); + } + + #[test] + fn test_no_cache_insert() { + let cache = Arc::new(Mutex::new(DnsLru::new(1))); + // first should come from client... + let mut client = mock(vec![v4_message()]); + + let ips = LookupIpState::lookup( + Name::root(), + LookupIpStrategy::Ipv4Only, + &mut client, + cache.clone(), + ).wait() + .unwrap(); + + assert_eq!( + ips.iter().cloned().collect::>(), + vec![Ipv4Addr::new(127, 0, 0, 1)] + ); + + // next should come from cache... + let mut client = mock(vec![empty()]); + + let ips = + LookupIpState::lookup(Name::root(), LookupIpStrategy::Ipv4Only, &mut client, cache) + .wait() + .unwrap(); + + assert_eq!( + ips.iter().cloned().collect::>(), + vec![Ipv4Addr::new(127, 0, 0, 1)] + ); + } } \ No newline at end of file diff --git a/resolver/src/resolver_future.rs b/resolver/src/resolver_future.rs index 4145358ef9..917d404b81 100644 --- a/resolver/src/resolver_future.rs +++ b/resolver/src/resolver_future.rs @@ -32,12 +32,11 @@ impl ResolverFuture { /// Construct a new ResolverFuture with the associated Client. pub fn new(config: ResolverConfig, options: ResolverOpts, reactor: &Handle) -> Self { let pool = NameServerPool::from_config(&config, &options, reactor); - // FIXME: how to specify cache? optional? or just size? ResolverFuture { config, options, pool, - lru: Arc::new(Mutex::new(DnsLru::new(10))) + lru: Arc::new(Mutex::new(DnsLru::new(options.cache_size))), } } @@ -71,7 +70,6 @@ impl ResolverFuture { let names = if name.is_fqdn() { vec![name] } else { - // Otherwise we have to build the search list // Note: the vec is built in reverse order of precedence, for stack semantics let mut names = @@ -105,7 +103,12 @@ impl ResolverFuture { either = LookupIpEither::Retry(client); } - LookupIpFuture::lookup(names, self.options.ip_strategy, &mut either, self.lru.clone()) + LookupIpFuture::lookup( + names, + self.options.ip_strategy, + &mut either, + self.lru.clone(), + ) } fn push_name(name: Name, names: &mut Vec) {