c_ares_resolver/
futureresolver.rs

1use std::future::Future;
2use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
3use std::pin::Pin;
4use std::sync::Arc;
5use std::task::{Context, Poll};
6
7use crate::error::Error;
8use crate::host::HostResults;
9use crate::nameinfo::NameInfoResult;
10use crate::resolver::{Options, Resolver};
11
12#[cfg(cares1_24)]
13use c_ares::AresString;
14
15#[cfg(cares1_29)]
16use c_ares::ServerStateFlags;
17
18/// The type of future returned by methods on the `FutureResolver`.
19#[must_use]
20pub struct CAresFuture<T> {
21    inner: futures_channel::oneshot::Receiver<c_ares::Result<T>>,
22    _resolver: Arc<Resolver>,
23}
24
25impl<T> CAresFuture<T> {
26    fn new(
27        promise: futures_channel::oneshot::Receiver<c_ares::Result<T>>,
28        resolver: Arc<Resolver>,
29    ) -> Self {
30        Self {
31            inner: promise,
32            _resolver: resolver,
33        }
34    }
35
36    fn pin_get_inner(
37        self: Pin<&mut Self>,
38    ) -> Pin<&mut futures_channel::oneshot::Receiver<c_ares::Result<T>>> {
39        unsafe { self.map_unchecked_mut(|s| &mut s.inner) }
40    }
41}
42
43impl<T> Future for CAresFuture<T> {
44    type Output = c_ares::Result<T>;
45
46    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
47        self.pin_get_inner()
48            .poll(cx)
49            .map(|result| result.unwrap_or(Err(c_ares::Error::ECANCELLED)))
50    }
51}
52
53/// An asynchronous DNS resolver, which returns results as `futures::Future`s.
54///
55/// Note that dropping the `FutureResolver` does *not* cause outstanding queries to fail - contrast
56/// the `Resolver` - because the returned futures hold a reference to the underlying resolver.
57pub struct FutureResolver {
58    inner: Arc<Resolver>,
59}
60
61// Most query implementations follow the same pattern: call through to the `Resolver`, arranging
62// that the callback completes a future.
63macro_rules! futurize {
64    ($resolver:expr, $query:ident, $question:expr) => {{
65        let (sender, receiver) = futures_channel::oneshot::channel();
66        $resolver.$query($question, |result| {
67            let _ = sender.send(result);
68        });
69        let resolver = Arc::clone(&$resolver);
70        CAresFuture::new(receiver, resolver)
71    }};
72}
73
74impl FutureResolver {
75    /// Create a new `FutureResolver`, using default `Options`.
76    pub fn new() -> Result<Self, Error> {
77        let options = Options::default();
78        Self::with_options(options)
79    }
80
81    /// Create a new `FutureResolver`, with the given `Options`.
82    pub fn with_options(options: Options) -> Result<Self, Error> {
83        let inner = Resolver::with_options(options)?;
84        let resolver = Self {
85            inner: Arc::new(inner),
86        };
87        Ok(resolver)
88    }
89
90    /// Reinitialize a channel from system configuration.
91    #[cfg(cares1_22)]
92    pub fn reinit(&self) -> c_ares::Result<&Self> {
93        self.inner.reinit()?;
94        Ok(self)
95    }
96
97    /// Set the list of servers to contact, instead of the servers specified in resolv.conf or the
98    /// local named.
99    ///
100    /// String format is `host[:port]`.  IPv6 addresses with ports require square brackets eg
101    /// `[2001:4860:4860::8888]:53`.
102    pub fn set_servers(&self, servers: &[&str]) -> c_ares::Result<&Self> {
103        self.inner.set_servers(servers)?;
104        Ok(self)
105    }
106
107    /// Retrieves the list of servers in comma delimited format.
108    #[cfg(cares1_24)]
109    pub fn get_servers(&self) -> AresString {
110        self.inner.get_servers()
111    }
112
113    /// Set the local IPv4 address from which to make queries.
114    pub fn set_local_ipv4(&self, ipv4: Ipv4Addr) -> &Self {
115        self.inner.set_local_ipv4(ipv4);
116        self
117    }
118
119    /// Set the local IPv6 address from which to make queries.
120    pub fn set_local_ipv6(&self, ipv6: &Ipv6Addr) -> &Self {
121        self.inner.set_local_ipv6(ipv6);
122        self
123    }
124
125    /// Set the local device from which to make queries.
126    pub fn set_local_device(&self, device: &str) -> &Self {
127        self.inner.set_local_device(device);
128        self
129    }
130
131    /// Initializes an address sortlist configuration, so that addresses returned by
132    /// `get_host_by_name()` are sorted according to the sortlist.
133    ///
134    /// Each element of the sortlist holds an IP-address/netmask pair. The netmask is optional but
135    /// follows the address after a slash if present. For example: "130.155.160.0/255.255.240.0",
136    /// or "130.155.0.0".
137    pub fn set_sortlist(&self, sortlist: &[&str]) -> c_ares::Result<&Self> {
138        self.inner.set_sortlist(sortlist)?;
139        Ok(self)
140    }
141
142    /// Set a callback function to be invoked whenever a query on the channel completes.
143    ///
144    /// `callback(server, success, flags)` will be called when a query completes.
145    ///
146    /// - `server` indicates the DNS server that was used for the query.
147    /// - `success` indicates whether the query succeeded or not.
148    /// - `flags` is a bitmask of flags describing various aspects of the query.
149    #[cfg(cares1_29)]
150    pub fn set_server_state_callback<F>(&self, callback: F) -> &Self
151    where
152        F: FnMut(&str, bool, ServerStateFlags) + Send + 'static,
153    {
154        self.inner.set_server_state_callback(callback);
155        self
156    }
157
158    /// Look up the A records associated with `name`.
159    pub fn query_a(&self, name: &str) -> CAresFuture<c_ares::AResults> {
160        futurize!(self.inner, query_a, name)
161    }
162
163    /// Search for the A records associated with `name`.
164    pub fn search_a(&self, name: &str) -> CAresFuture<c_ares::AResults> {
165        futurize!(self.inner, search_a, name)
166    }
167
168    /// Look up the AAAA records associated with `name`.
169    pub fn query_aaaa(&self, name: &str) -> CAresFuture<c_ares::AAAAResults> {
170        futurize!(self.inner, query_aaaa, name)
171    }
172
173    /// Search for the AAAA records associated with `name`.
174    pub fn search_aaaa(&self, name: &str) -> CAresFuture<c_ares::AAAAResults> {
175        futurize!(self.inner, search_aaaa, name)
176    }
177
178    /// Look up the CAA records associated with `name`.
179    #[cfg(cares1_17)]
180    pub fn query_caa(&self, name: &str) -> CAresFuture<c_ares::CAAResults> {
181        futurize!(self.inner, query_caa, name)
182    }
183
184    /// Search for the CAA records associated with `name`.
185    #[cfg(cares1_17)]
186    pub fn search_caa(&self, name: &str) -> CAresFuture<c_ares::CAAResults> {
187        futurize!(self.inner, search_caa, name)
188    }
189
190    /// Look up the CNAME records associated with `name`.
191    pub fn query_cname(&self, name: &str) -> CAresFuture<c_ares::CNameResults> {
192        futurize!(self.inner, query_cname, name)
193    }
194
195    /// Search for the CNAME records associated with `name`.
196    pub fn search_cname(&self, name: &str) -> CAresFuture<c_ares::CNameResults> {
197        futurize!(self.inner, search_cname, name)
198    }
199
200    /// Look up the MX records associated with `name`.
201    pub fn query_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
202        futurize!(self.inner, query_mx, name)
203    }
204
205    /// Search for the MX records associated with `name`.
206    pub fn search_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
207        futurize!(self.inner, search_mx, name)
208    }
209
210    /// Look up the NAPTR records associated with `name`.
211    pub fn query_naptr(&self, name: &str) -> CAresFuture<c_ares::NAPTRResults> {
212        futurize!(self.inner, query_naptr, name)
213    }
214
215    /// Search for the NAPTR records associated with `name`.
216    pub fn search_naptr(&self, name: &str) -> CAresFuture<c_ares::NAPTRResults> {
217        futurize!(self.inner, search_naptr, name)
218    }
219
220    /// Look up the NS records associated with `name`.
221    pub fn query_ns(&self, name: &str) -> CAresFuture<c_ares::NSResults> {
222        futurize!(self.inner, query_ns, name)
223    }
224
225    /// Search for the NS records associated with `name`.
226    pub fn search_ns(&self, name: &str) -> CAresFuture<c_ares::NSResults> {
227        futurize!(self.inner, search_ns, name)
228    }
229
230    /// Look up the PTR records associated with `name`.
231    pub fn query_ptr(&self, name: &str) -> CAresFuture<c_ares::PTRResults> {
232        futurize!(self.inner, query_ptr, name)
233    }
234
235    /// Search for the PTR records associated with `name`.
236    pub fn search_ptr(&self, name: &str) -> CAresFuture<c_ares::PTRResults> {
237        futurize!(self.inner, search_ptr, name)
238    }
239
240    /// Look up the SOA records associated with `name`.
241    pub fn query_soa(&self, name: &str) -> CAresFuture<c_ares::SOAResult> {
242        futurize!(self.inner, query_soa, name)
243    }
244
245    /// Search for the SOA records associated with `name`.
246    pub fn search_soa(&self, name: &str) -> CAresFuture<c_ares::SOAResult> {
247        futurize!(self.inner, search_soa, name)
248    }
249
250    /// Look up the SRV records associated with `name`.
251    pub fn query_srv(&self, name: &str) -> CAresFuture<c_ares::SRVResults> {
252        futurize!(self.inner, query_srv, name)
253    }
254
255    /// Search for the SRV records associated with `name`.
256    pub fn search_srv(&self, name: &str) -> CAresFuture<c_ares::SRVResults> {
257        futurize!(self.inner, search_srv, name)
258    }
259
260    /// Look up the TXT records associated with `name`.
261    pub fn query_txt(&self, name: &str) -> CAresFuture<c_ares::TXTResults> {
262        futurize!(self.inner, query_txt, name)
263    }
264
265    /// Search for the TXT records associated with `name`.
266    pub fn search_txt(&self, name: &str) -> CAresFuture<c_ares::TXTResults> {
267        futurize!(self.inner, search_txt, name)
268    }
269
270    /// Look up the URI records associated with `name`.
271    pub fn query_uri(&self, name: &str) -> CAresFuture<c_ares::URIResults> {
272        futurize!(self.inner, query_uri, name)
273    }
274
275    /// Search for the URI records associated with `name`.
276    pub fn search_uri(&self, name: &str) -> CAresFuture<c_ares::URIResults> {
277        futurize!(self.inner, search_uri, name)
278    }
279
280    /// Perform a host query by address.
281    ///
282    /// This method is one of the very few places where this library performs strictly more
283    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
284    /// prefer to use the analogous method on the `Resolver`.
285    pub fn get_host_by_address(&self, address: &IpAddr) -> CAresFuture<HostResults> {
286        let (sender, receiver) = futures_channel::oneshot::channel();
287        self.inner.get_host_by_address(address, |result| {
288            let _ = sender.send(result.map(Into::into));
289        });
290        let resolver = Arc::clone(&self.inner);
291        CAresFuture::new(receiver, resolver)
292    }
293
294    /// Perform a host query by name.
295    ///
296    /// This method is one of the very few places where this library performs strictly more
297    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
298    /// prefer to use the analogous method on the `Resolver`.
299    pub fn get_host_by_name(
300        &self,
301        name: &str,
302        family: c_ares::AddressFamily,
303    ) -> CAresFuture<HostResults> {
304        let (sender, receiver) = futures_channel::oneshot::channel();
305        self.inner.get_host_by_name(name, family, |result| {
306            let _ = sender.send(result.map(Into::into));
307        });
308        let resolver = Arc::clone(&self.inner);
309        CAresFuture::new(receiver, resolver)
310    }
311
312    /// Address-to-nodename translation in protocol-independent manner.
313    ///
314    /// This method is one of the very few places where this library performs strictly more
315    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
316    /// prefer to use the analogous method on the `Resolver`.
317    pub fn get_name_info<F>(
318        &self,
319        address: &SocketAddr,
320        flags: c_ares::NIFlags,
321    ) -> CAresFuture<NameInfoResult> {
322        let (sender, receiver) = futures_channel::oneshot::channel();
323        self.inner.get_name_info(address, flags, |result| {
324            let _ = sender.send(result.map(Into::into));
325        });
326        let resolver = Arc::clone(&self.inner);
327        CAresFuture::new(receiver, resolver)
328    }
329
330    /// Initiate a single-question DNS query for `name`.  The class and type of the query are per
331    /// the provided parameters, taking values as defined in `arpa/nameser.h`.
332    ///
333    /// This method is one of the very few places where this library performs strictly more
334    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
335    /// prefer to use the analogous method on the `Resolver`.
336    ///
337    /// This method is provided so that users can query DNS types for which `c-ares` does not
338    /// provide a parser; or in case a third-party parser is preferred.  Usually, if a suitable
339    /// `query_xxx()` is available, that should be used.
340    pub fn query(&self, name: &str, dns_class: u16, query_type: u16) -> CAresFuture<Vec<u8>> {
341        let (sender, receiver) = futures_channel::oneshot::channel();
342        self.inner.query(name, dns_class, query_type, |result| {
343            let _ = sender.send(result.map(std::borrow::ToOwned::to_owned));
344        });
345        let resolver = Arc::clone(&self.inner);
346        CAresFuture::new(receiver, resolver)
347    }
348
349    /// Initiate a series of single-question DNS queries for `name`.  The class and type of the
350    /// query are per the provided parameters, taking values as defined in `arpa/nameser.h`.
351    ///
352    /// This method is one of the very few places where this library performs strictly more
353    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
354    /// prefer to use the analogous method on the `Resolver`.
355    ///
356    /// This method is provided so that users can search DNS types for which `c-ares` does not
357    /// provide a parser; or in case a third-party parser is preferred.  Usually, if a suitable
358    /// `search_xxx()` is available, that should be used.
359    pub fn search(&self, name: &str, dns_class: u16, query_type: u16) -> CAresFuture<Vec<u8>> {
360        let (sender, receiver) = futures_channel::oneshot::channel();
361        self.inner.search(name, dns_class, query_type, |result| {
362            let _ = sender.send(result.map(std::borrow::ToOwned::to_owned));
363        });
364        let resolver = Arc::clone(&self.inner);
365        CAresFuture::new(receiver, resolver)
366    }
367
368    /// Cancel all requests made on this `FutureResolver`.
369    pub fn cancel(&self) {
370        self.inner.cancel()
371    }
372}