1 #[cfg(test)] 2 mod resolver_test; 3 4 use crate::error::*; 5 6 use std::collections::HashMap; 7 use std::future::Future; 8 use std::net::IpAddr; 9 use std::pin::Pin; 10 use std::str::FromStr; 11 use std::sync::Arc; 12 use tokio::sync::Mutex; 13 14 #[derive(Default)] 15 pub(crate) struct Resolver { 16 parent: Option<Arc<Mutex<Resolver>>>, 17 hosts: HashMap<String, IpAddr>, 18 } 19 20 impl Resolver { new() -> Self21 pub(crate) fn new() -> Self { 22 let mut r = Resolver { 23 parent: None, 24 hosts: HashMap::new(), 25 }; 26 27 if let Err(err) = r.add_host("localhost".to_owned(), "127.0.0.1".to_owned()) { 28 log::warn!("failed to add localhost to Resolver: {}", err); 29 } 30 r 31 } 32 set_parent(&mut self, p: Arc<Mutex<Resolver>>)33 pub(crate) fn set_parent(&mut self, p: Arc<Mutex<Resolver>>) { 34 self.parent = Some(p); 35 } 36 add_host(&mut self, name: String, ip_addr: String) -> Result<()>37 pub(crate) fn add_host(&mut self, name: String, ip_addr: String) -> Result<()> { 38 if name.is_empty() { 39 return Err(Error::ErrHostnameEmpty); 40 } 41 let ip = IpAddr::from_str(&ip_addr)?; 42 self.hosts.insert(name, ip); 43 44 Ok(()) 45 } 46 lookup( &self, host_name: String, ) -> Pin<Box<dyn Future<Output = Option<IpAddr>> + Send + 'static>>47 pub(crate) fn lookup( 48 &self, 49 host_name: String, 50 ) -> Pin<Box<dyn Future<Output = Option<IpAddr>> + Send + 'static>> { 51 if let Some(ip) = self.hosts.get(&host_name) { 52 let ip2 = *ip; 53 return Box::pin(async move { Some(ip2) }); 54 } 55 56 // mutex must be unlocked before calling into parent Resolver 57 if let Some(parent) = &self.parent { 58 let parent2 = Arc::clone(parent); 59 Box::pin(async move { 60 let p = parent2.lock().await; 61 p.lookup(host_name).await 62 }) 63 } else { 64 Box::pin(async move { None }) 65 } 66 } 67 } 68