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    pub fn query_caa(&self, name: &str) -> CAresFuture<c_ares::CAAResults> {
180        futurize!(self.inner, query_caa, name)
181    }
182
183    /// Search for the CAA records associated with `name`.
184    pub fn search_caa(&self, name: &str) -> CAresFuture<c_ares::CAAResults> {
185        futurize!(self.inner, search_caa, name)
186    }
187
188    /// Look up the CNAME records associated with `name`.
189    pub fn query_cname(&self, name: &str) -> CAresFuture<c_ares::CNameResults> {
190        futurize!(self.inner, query_cname, name)
191    }
192
193    /// Search for the CNAME records associated with `name`.
194    pub fn search_cname(&self, name: &str) -> CAresFuture<c_ares::CNameResults> {
195        futurize!(self.inner, search_cname, name)
196    }
197
198    /// Look up the MX records associated with `name`.
199    pub fn query_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
200        futurize!(self.inner, query_mx, name)
201    }
202
203    /// Search for the MX records associated with `name`.
204    pub fn search_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
205        futurize!(self.inner, search_mx, name)
206    }
207
208    /// Look up the NAPTR records associated with `name`.
209    pub fn query_naptr(&self, name: &str) -> CAresFuture<c_ares::NAPTRResults> {
210        futurize!(self.inner, query_naptr, name)
211    }
212
213    /// Search for the NAPTR records associated with `name`.
214    pub fn search_naptr(&self, name: &str) -> CAresFuture<c_ares::NAPTRResults> {
215        futurize!(self.inner, search_naptr, name)
216    }
217
218    /// Look up the NS records associated with `name`.
219    pub fn query_ns(&self, name: &str) -> CAresFuture<c_ares::NSResults> {
220        futurize!(self.inner, query_ns, name)
221    }
222
223    /// Search for the NS records associated with `name`.
224    pub fn search_ns(&self, name: &str) -> CAresFuture<c_ares::NSResults> {
225        futurize!(self.inner, search_ns, name)
226    }
227
228    /// Look up the PTR records associated with `name`.
229    pub fn query_ptr(&self, name: &str) -> CAresFuture<c_ares::PTRResults> {
230        futurize!(self.inner, query_ptr, name)
231    }
232
233    /// Search for the PTR records associated with `name`.
234    pub fn search_ptr(&self, name: &str) -> CAresFuture<c_ares::PTRResults> {
235        futurize!(self.inner, search_ptr, name)
236    }
237
238    /// Look up the SOA records associated with `name`.
239    pub fn query_soa(&self, name: &str) -> CAresFuture<c_ares::SOAResult> {
240        futurize!(self.inner, query_soa, name)
241    }
242
243    /// Search for the SOA records associated with `name`.
244    pub fn search_soa(&self, name: &str) -> CAresFuture<c_ares::SOAResult> {
245        futurize!(self.inner, search_soa, name)
246    }
247
248    /// Look up the SRV records associated with `name`.
249    pub fn query_srv(&self, name: &str) -> CAresFuture<c_ares::SRVResults> {
250        futurize!(self.inner, query_srv, name)
251    }
252
253    /// Search for the SRV records associated with `name`.
254    pub fn search_srv(&self, name: &str) -> CAresFuture<c_ares::SRVResults> {
255        futurize!(self.inner, search_srv, name)
256    }
257
258    /// Look up the TXT records associated with `name`.
259    pub fn query_txt(&self, name: &str) -> CAresFuture<c_ares::TXTResults> {
260        futurize!(self.inner, query_txt, name)
261    }
262
263    /// Search for the TXT records associated with `name`.
264    pub fn search_txt(&self, name: &str) -> CAresFuture<c_ares::TXTResults> {
265        futurize!(self.inner, search_txt, name)
266    }
267
268    /// Look up the URI records associated with `name`.
269    pub fn query_uri(&self, name: &str) -> CAresFuture<c_ares::URIResults> {
270        futurize!(self.inner, query_uri, name)
271    }
272
273    /// Search for the URI records associated with `name`.
274    pub fn search_uri(&self, name: &str) -> CAresFuture<c_ares::URIResults> {
275        futurize!(self.inner, search_uri, name)
276    }
277
278    /// Perform a host query by address.
279    ///
280    /// This method is one of the very few places where this library performs strictly more
281    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
282    /// prefer to use the analogous method on the `Resolver`.
283    pub fn get_host_by_address(&self, address: &IpAddr) -> CAresFuture<HostResults> {
284        let (sender, receiver) = futures_channel::oneshot::channel();
285        self.inner.get_host_by_address(address, |result| {
286            let _ = sender.send(result.map(Into::into));
287        });
288        let resolver = Arc::clone(&self.inner);
289        CAresFuture::new(receiver, resolver)
290    }
291
292    /// Perform a host query by name.
293    ///
294    /// This method is one of the very few places where this library performs strictly more
295    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
296    /// prefer to use the analogous method on the `Resolver`.
297    pub fn get_host_by_name(
298        &self,
299        name: &str,
300        family: c_ares::AddressFamily,
301    ) -> CAresFuture<HostResults> {
302        let (sender, receiver) = futures_channel::oneshot::channel();
303        self.inner.get_host_by_name(name, family, |result| {
304            let _ = sender.send(result.map(Into::into));
305        });
306        let resolver = Arc::clone(&self.inner);
307        CAresFuture::new(receiver, resolver)
308    }
309
310    /// Address-to-nodename translation in protocol-independent manner.
311    ///
312    /// This method is one of the very few places where this library performs strictly more
313    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
314    /// prefer to use the analogous method on the `Resolver`.
315    pub fn get_name_info<F>(
316        &self,
317        address: &SocketAddr,
318        flags: c_ares::NIFlags,
319    ) -> CAresFuture<NameInfoResult> {
320        let (sender, receiver) = futures_channel::oneshot::channel();
321        self.inner.get_name_info(address, flags, |result| {
322            let _ = sender.send(result.map(Into::into));
323        });
324        let resolver = Arc::clone(&self.inner);
325        CAresFuture::new(receiver, resolver)
326    }
327
328    /// Initiate a single-question DNS query for `name`.  The class and type of the query are per
329    /// the provided parameters, taking values as defined in `arpa/nameser.h`.
330    ///
331    /// This method is one of the very few places where this library performs strictly more
332    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
333    /// prefer to use the analogous method on the `Resolver`.
334    ///
335    /// This method is provided so that users can query DNS types for which `c-ares` does not
336    /// provide a parser; or in case a third-party parser is preferred.  Usually, if a suitable
337    /// `query_xxx()` is available, that should be used.
338    pub fn query(&self, name: &str, dns_class: u16, query_type: u16) -> CAresFuture<Vec<u8>> {
339        let (sender, receiver) = futures_channel::oneshot::channel();
340        self.inner.query(name, dns_class, query_type, |result| {
341            let _ = sender.send(result.map(std::borrow::ToOwned::to_owned));
342        });
343        let resolver = Arc::clone(&self.inner);
344        CAresFuture::new(receiver, resolver)
345    }
346
347    /// Initiate a series of single-question DNS queries for `name`.  The class and type of the
348    /// query are per the provided parameters, taking values as defined in `arpa/nameser.h`.
349    ///
350    /// This method is one of the very few places where this library performs strictly more
351    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
352    /// prefer to use the analogous method on the `Resolver`.
353    ///
354    /// This method is provided so that users can search DNS types for which `c-ares` does not
355    /// provide a parser; or in case a third-party parser is preferred.  Usually, if a suitable
356    /// `search_xxx()` is available, that should be used.
357    pub fn search(&self, name: &str, dns_class: u16, query_type: u16) -> CAresFuture<Vec<u8>> {
358        let (sender, receiver) = futures_channel::oneshot::channel();
359        self.inner.search(name, dns_class, query_type, |result| {
360            let _ = sender.send(result.map(std::borrow::ToOwned::to_owned));
361        });
362        let resolver = Arc::clone(&self.inner);
363        CAresFuture::new(receiver, resolver)
364    }
365
366    /// Cancel all requests made on this `FutureResolver`.
367    pub fn cancel(&self) {
368        self.inner.cancel()
369    }
370}