From ef4ba58f3f50e8f864e10fe6aa2981a1f6f6af8e Mon Sep 17 00:00:00 2001 From: Hugo Osvaldo Barrera Date: Mon, 16 Sep 2024 16:10:55 +0200 Subject: [PATCH] Use an Arc to share stub resolver This somewhat simplifies usage for call sites. They no longer need to use `&&StubResolver` for some APIs, and a future can be handed off without being tied to the lifetime of the resolver. The documentation already mentioned that the StubResolver was behind an Arc so I did not need to updated it. StubResolver now implements clone, which is cheap since it merely clones the Arc with the inner data. This change is backwards-incompatible, and necessitates a bump in minor for the next unstable release. Fixes: https://github.com/NLnetLabs/domain/issues/175 --- src/resolv/stub/mod.rs | 64 ++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/src/resolv/stub/mod.rs b/src/resolv/stub/mod.rs index f80ee0691..69797e922 100644 --- a/src/resolv/stub/mod.rs +++ b/src/resolv/stub/mod.rs @@ -73,8 +73,11 @@ pub mod conf; /// [`query`]: #method.query /// [`run`]: #method.run /// [`run_with_conf`]: #method.run_with_conf +#[derive(Debug, Clone)] +pub struct StubResolver(Arc); + #[derive(Debug)] -pub struct StubResolver { +struct StubResolverInner { transport: Mutex>>>>, /// Resolver options. @@ -91,20 +94,19 @@ impl StubResolver { /// Creates a new resolver using the given configuraiton. pub fn from_conf(conf: ResolvConf) -> Self { - StubResolver { + StubResolver(Arc::new(StubResolverInner { transport: None.into(), options: conf.options, - servers: conf.servers, - } + })) } pub fn options(&self) -> &ResolvOptions { - &self.options + &self.0.options } pub async fn query>>( - &self, + self, question: Q, ) -> Result { Query::new(self)? @@ -113,7 +115,7 @@ impl StubResolver { } async fn query_message( - &self, + self, message: QueryMessage, ) -> Result { Query::new(self)?.run(message).await @@ -147,10 +149,10 @@ impl StubResolver { // We have 3 modes of operation: use_vc: only use TCP, ign_tc: only // UDP no fallback to TCP, and normal with is UDP falling back to TCP. - for s in &self.servers { + for s in &self.0.servers { // This assumes that Transport only has UdpTcp and Tcp. Sadly, a // match doesn’t work here because of the use_cv flag. - if self.options.use_vc || matches!(s.transport, Transport::Tcp) { + if self.0.options.use_vc || matches!(s.transport, Transport::Tcp) { let (conn, tran) = multi_stream::Connection::new(TcpConnect::new(s.addr)); // Start the run function on a separate task. @@ -177,7 +179,7 @@ impl StubResolver { async fn get_transport( &self, ) -> Result>>, Error> { - let mut opt_transport = self.transport.lock().await; + let mut opt_transport = self.0.transport.lock().await; match &*opt_transport { Some(transport) => Ok(transport.clone()), @@ -215,22 +217,22 @@ impl StubResolver { pub async fn lookup_addr( &self, addr: IpAddr, - ) -> Result, io::Error> { - lookup_addr(&self, addr).await + ) -> Result, io::Error> { + lookup_addr(self, addr).await } pub async fn lookup_host( &self, qname: impl ToName, - ) -> Result, io::Error> { - lookup_host(&self, qname).await + ) -> Result, io::Error> { + lookup_host(self, qname).await } pub async fn search_host( &self, qname: impl ToRelativeName, - ) -> Result, io::Error> { - search_host(&self, qname).await + ) -> Result, io::Error> { + search_host(self, qname).await } /// Performs an SRV lookup using this resolver. @@ -242,7 +244,7 @@ impl StubResolver { name: impl ToName, fallback_port: u16, ) -> Result, SrvError> { - lookup_srv(&self, service, name, fallback_port).await + lookup_srv(self, service, name, fallback_port).await } } @@ -294,11 +296,11 @@ impl Default for StubResolver { } } -impl<'a> Resolver for &'a StubResolver { +impl Resolver for StubResolver { type Octets = Bytes; type Answer = Answer; type Query = - Pin> + Send + 'a>>; + Pin> + Send >>; fn query(&self, question: Q) -> Self::Query where @@ -306,17 +308,17 @@ impl<'a> Resolver for &'a StubResolver { Q: Into>, { let message = Query::create_message(question.into()); - Box::pin(self.query_message(message)) + Box::pin(self.clone().query_message(message)) } } -impl<'a> SearchNames for &'a StubResolver { +impl SearchNames for StubResolver { type Name = SearchSuffix; - type Iter = SearchIter<'a>; + type Iter = SearchIter; fn search_iter(&self) -> Self::Iter { SearchIter { - resolver: self, + resolver: self.clone(), pos: 0, } } @@ -324,9 +326,9 @@ impl<'a> SearchNames for &'a StubResolver { //------------ Query --------------------------------------------------------- -pub struct Query<'a> { +pub struct Query { /// The resolver whose configuration we are using. - resolver: &'a StubResolver, + resolver: StubResolver, edns: Arc, @@ -340,8 +342,8 @@ pub struct Query<'a> { error: Result, } -impl<'a> Query<'a> { - pub fn new(resolver: &'a StubResolver) -> Result { +impl Query { + pub fn new(resolver: StubResolver) -> Result { Ok(Query { resolver, edns: Arc::new(AtomicBool::new(true)), @@ -404,7 +406,7 @@ impl<'a> Query<'a> { })?; let mut gr_fut = transport.send_request(request_msg); let reply = - timeout(self.resolver.options.timeout, gr_fut.get_response()) + timeout(self.resolver.0.options.timeout, gr_fut.get_response()) .await? .map_err(|e| { io::Error::new(io::ErrorKind::Other, e.to_string()) @@ -491,12 +493,12 @@ impl AsRef> for Answer { //------------ SearchIter ---------------------------------------------------- #[derive(Clone, Debug)] -pub struct SearchIter<'a> { - resolver: &'a StubResolver, +pub struct SearchIter { + resolver: StubResolver, pos: usize, } -impl<'a> Iterator for SearchIter<'a> { +impl Iterator for SearchIter { type Item = SearchSuffix; fn next(&mut self) -> Option {