c_ares/
channel.rs

1use std::ffi::CString;
2use std::mem;
3use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
4#[allow(unused_imports)]
5use std::os::raw::{c_char, c_int, c_void};
6use std::ptr;
7use std::sync::Arc;
8
9use crate::Flags;
10#[cfg(cares1_29)]
11use crate::ServerStateFlags;
12use crate::a::{AResults, query_a_callback};
13use crate::aaaa::{AAAAResults, query_aaaa_callback};
14use crate::caa::{CAAResults, query_caa_callback};
15use crate::cname::{CNameResults, query_cname_callback};
16use crate::error::{Error, Result};
17#[cfg(cares1_34)]
18use crate::events::{FdEvents, ProcessFlags};
19use crate::host::{HostResults, get_host_callback};
20use crate::mx::{MXResults, query_mx_callback};
21use crate::nameinfo::{NameInfoResult, get_name_info_callback};
22use crate::naptr::{NAPTRResults, query_naptr_callback};
23use crate::ni_flags::NIFlags;
24use crate::ns::{NSResults, query_ns_callback};
25use crate::panic;
26use crate::ptr::{PTRResults, query_ptr_callback};
27use crate::query::query_callback;
28use crate::soa::{SOAResult, query_soa_callback};
29use crate::srv::{SRVResults, query_srv_callback};
30#[cfg(cares1_24)]
31use crate::string::AresString;
32use crate::txt::{TXTResults, query_txt_callback};
33use crate::types::{AddressFamily, DnsClass, QueryType, Socket};
34use crate::uri::{URIResults, query_uri_callback};
35#[allow(unused_imports)]
36use crate::utils::{
37    c_string_as_str_unchecked, ipv4_as_in_addr, ipv6_as_in6_addr, socket_addrv4_as_sockaddr_in,
38    socket_addrv6_as_sockaddr_in6,
39};
40use std::sync::Mutex;
41
42// ares_library_init is not thread-safe, so we put a lock around it.
43static ARES_LIBRARY_LOCK: Mutex<()> = Mutex::new(());
44
45type SocketStateCallback = dyn FnMut(Socket, bool, bool) + Send + 'static;
46
47#[cfg(cares1_29)]
48type ServerStateCallback = dyn FnMut(&str, bool, ServerStateFlags) + Send + 'static;
49
50#[cfg(cares1_34)]
51type PendingWriteCallback = dyn FnMut() + Send + 'static;
52
53/// Server failover options.
54///
55/// When a DNS server fails to respond to a query, c-ares will deprioritize the server.  On
56/// subsequent queries, servers with fewer consecutive failures will be selected in preference.
57/// However, in order to detect when such a server has recovered, c-ares will occasionally retry
58/// failed servers.  `ServerFailoverOptions` contains options to control this behaviour.
59#[cfg(cares1_29)]
60pub struct ServerFailoverOptions {
61    retry_chance: u16,
62    retry_delay: usize,
63}
64
65#[cfg(cares1_29)]
66impl Default for ServerFailoverOptions {
67    fn default() -> Self {
68        Self {
69            retry_chance: 10,
70            retry_delay: 5000,
71        }
72    }
73}
74
75#[cfg(cares1_29)]
76impl ServerFailoverOptions {
77    /// Returns a new `ServerFailoverOptions`.
78    pub fn new() -> Self {
79        Self::default()
80    }
81
82    /// The `retry_chance` sets the probability (1/N) of retrying a failed server on any given
83    /// query.  Setting to a value of 0 disables retries.
84    pub fn set_retry_chance(&mut self, retry_chance: u16) -> &mut Self {
85        self.retry_chance = retry_chance;
86        self
87    }
88
89    /// The `retry_delay` sets the minimum delay in milliseconds that c-ares will wait before
90    /// retrying a specific failed server.
91    pub fn set_retry_delay(&mut self, retry_delay: usize) -> &mut Self {
92        self.retry_delay = retry_delay;
93        self
94    }
95}
96
97/// Used to configure the behaviour of the name resolver.
98pub struct Options {
99    ares_options: c_ares_sys::ares_options,
100    optmask: c_int,
101    domains: Vec<CString>,
102    lookups: Option<CString>,
103    resolvconf_path: Option<CString>,
104    #[cfg(cares1_19)]
105    hosts_path: Option<CString>,
106    socket_state_callback: Option<Arc<SocketStateCallback>>,
107}
108
109impl Default for Options {
110    fn default() -> Self {
111        Self {
112            ares_options: unsafe { mem::MaybeUninit::zeroed().assume_init() },
113            optmask: 0,
114            domains: vec![],
115            lookups: None,
116            resolvconf_path: None,
117            #[cfg(cares1_19)]
118            hosts_path: None,
119            socket_state_callback: None,
120        }
121    }
122}
123
124impl Options {
125    /// Returns a fresh `Options`, on which no values are set.
126    pub fn new() -> Self {
127        Self::default()
128    }
129
130    /// Set flags controlling the behaviour of the resolver.  The available flags are documented
131    /// [here](flags/index.html).
132    pub fn set_flags(&mut self, flags: Flags) -> &mut Self {
133        self.ares_options.flags = flags.bits();
134        self.optmask |= c_ares_sys::ARES_OPT_FLAGS;
135        self
136    }
137
138    /// Set the number of milliseconds each name server is given to respond to a query on the first
139    /// try.  (After the first try, the timeout algorithm becomes more complicated, but scales
140    /// linearly with the value of timeout).  The default is 2000ms.
141    pub fn set_timeout(&mut self, ms: u32) -> &mut Self {
142        self.ares_options.timeout = ms as c_int;
143        self.optmask |= c_ares_sys::ARES_OPT_TIMEOUTMS;
144        self
145    }
146
147    /// Set the number of tries the resolver will try contacting each name server before giving up.
148    /// The default is three tries.
149    pub fn set_tries(&mut self, tries: u32) -> &mut Self {
150        self.ares_options.tries = tries as c_int;
151        self.optmask |= c_ares_sys::ARES_OPT_TRIES;
152        self
153    }
154
155    /// Set the number of dots which must be present in a domain name for it to be queried for "as
156    /// is" prior to querying for it with the default domain extensions appended.  The default
157    /// value is 1 unless set otherwise by resolv.conf or the RES_OPTIONS environment variable.
158    pub fn set_ndots(&mut self, ndots: u32) -> &mut Self {
159        self.ares_options.ndots = ndots as c_int;
160        self.optmask |= c_ares_sys::ARES_OPT_NDOTS;
161        self
162    }
163
164    /// Set the UDP port to use for queries.  The default value is 53, the standard name service
165    /// port.
166    pub fn set_udp_port(&mut self, udp_port: u16) -> &mut Self {
167        self.ares_options.udp_port = udp_port;
168        self.optmask |= c_ares_sys::ARES_OPT_UDP_PORT;
169        self
170    }
171
172    /// Set the TCP port to use for queries.  The default value is 53, the standard name service
173    /// port.
174    pub fn set_tcp_port(&mut self, tcp_port: u16) -> &mut Self {
175        self.ares_options.tcp_port = tcp_port;
176        self.optmask |= c_ares_sys::ARES_OPT_TCP_PORT;
177        self
178    }
179
180    /// Set the domains to search, instead of the domains specified in resolv.conf or the domain
181    /// derived from the kernel hostname variable.
182    pub fn set_domains(&mut self, domains: &[&str]) -> &mut Self {
183        self.domains = domains.iter().map(|&s| CString::new(s).unwrap()).collect();
184        self.optmask |= c_ares_sys::ARES_OPT_DOMAINS;
185        self
186    }
187
188    /// Set the lookups to perform for host queries. `lookups` should be set to a string of the
189    /// characters "b" or "f", where "b" indicates a DNS lookup and "f" indicates a lookup in the
190    /// hosts file.
191    pub fn set_lookups(&mut self, lookups: &str) -> &mut Self {
192        let c_lookups = CString::new(lookups).unwrap();
193        self.lookups = Some(c_lookups);
194        self.optmask |= c_ares_sys::ARES_OPT_LOOKUPS;
195        self
196    }
197
198    /// Set the callback function to be invoked when a socket changes state.
199    ///
200    /// `callback(socket, read, write)` will be called when a socket changes state:
201    ///
202    /// - `read` is set to true if the socket should listen for read events
203    /// - `write` is set to true if the socket should listen for write events.
204    pub fn set_socket_state_callback<F>(&mut self, callback: F) -> &mut Self
205    where
206        F: FnMut(Socket, bool, bool) + Send + 'static,
207    {
208        let boxed_callback = Arc::new(callback);
209        self.ares_options.sock_state_cb = Some(socket_state_callback::<F>);
210        self.ares_options.sock_state_cb_data = ptr::from_ref(&*boxed_callback).cast_mut().cast();
211        self.socket_state_callback = Some(boxed_callback);
212        self.optmask |= c_ares_sys::ARES_OPT_SOCK_STATE_CB;
213        self
214    }
215
216    /// Set the socket send buffer size.
217    pub fn set_sock_send_buffer_size(&mut self, size: u32) -> &mut Self {
218        self.ares_options.socket_send_buffer_size = size as c_int;
219        self.optmask |= c_ares_sys::ARES_OPT_SOCK_SNDBUF;
220        self
221    }
222
223    /// Set the socket receive buffer size.
224    pub fn set_sock_receive_buffer_size(&mut self, size: u32) -> &mut Self {
225        self.ares_options.socket_receive_buffer_size = size as c_int;
226        self.optmask |= c_ares_sys::ARES_OPT_SOCK_RCVBUF;
227        self
228    }
229
230    /// Configure round robin selection of nameservers.
231    pub fn set_rotate(&mut self) -> &mut Self {
232        self.optmask &= !c_ares_sys::ARES_OPT_NOROTATE;
233        self.optmask |= c_ares_sys::ARES_OPT_ROTATE;
234        self
235    }
236
237    /// Prevent round robin selection of nameservers.
238    pub fn set_no_rotate(&mut self) -> &mut Self {
239        self.optmask &= !c_ares_sys::ARES_OPT_ROTATE;
240        self.optmask |= c_ares_sys::ARES_OPT_NOROTATE;
241        self
242    }
243
244    /// Set the EDNS packet size.
245    pub fn set_ednspsz(&mut self, size: u32) -> &mut Self {
246        self.ares_options.ednspsz = size as c_int;
247        self.optmask |= c_ares_sys::ARES_OPT_EDNSPSZ;
248        self
249    }
250
251    /// Set the path to use for reading the resolv.conf file.  The `resolvconf_path` should be set
252    /// to a path string, and will be honoured on *nix like systems.  The default is
253    /// /etc/resolv.conf.
254    pub fn set_resolvconf_path(&mut self, resolvconf_path: &str) -> &mut Self {
255        let c_resolvconf_path = CString::new(resolvconf_path).unwrap();
256        self.resolvconf_path = Some(c_resolvconf_path);
257        self.optmask |= c_ares_sys::ARES_OPT_RESOLVCONF;
258        self
259    }
260
261    /// Set the path to use for reading the hosts file.  The `hosts_path` should be set to a path
262    /// string, and will be honoured on *nix like systems.  The default is /etc/hosts.
263    #[cfg(cares1_19)]
264    pub fn set_hosts_path(&mut self, hosts_path: &str) -> &mut Self {
265        let c_hosts_path = CString::new(hosts_path).unwrap();
266        self.hosts_path = Some(c_hosts_path);
267        self.optmask |= c_ares_sys::ARES_OPT_HOSTS_FILE;
268        self
269    }
270
271    /// Set the maximum number of udp queries that can be sent on a single ephemeral port to a
272    /// given DNS server before a new ephemeral port is assigned.  Any value of 0 or less will be
273    /// considered unlimited, and is the default.
274    #[cfg(cares1_20)]
275    pub fn set_udp_max_queries(&mut self, udp_max_queries: i32) -> &mut Self {
276        self.ares_options.udp_max_queries = udp_max_queries;
277        self.optmask |= c_ares_sys::ARES_OPT_UDP_MAX_QUERIES;
278        self
279    }
280
281    /// Set the upper bound for timeout between sequential retry attempts, in milliseconds.  When
282    /// retrying queries, the timeout is increased from the requested timeout parameter, this caps
283    /// the value.
284    #[cfg(cares1_22)]
285    pub fn set_max_timeout(&mut self, max_timeout: i32) -> &mut Self {
286        self.ares_options.maxtimeout = max_timeout;
287        self.optmask |= c_ares_sys::ARES_OPT_MAXTIMEOUTMS;
288        self
289    }
290
291    /// Enable the built-in query cache.  Will cache queries based on the returned TTL in the DNS
292    /// message.  Only fully successful and NXDOMAIN query results will be cached.
293    ///
294    /// The provided value is the maximum number of seconds a query result may be cached; this will
295    /// override a larger TTL in the response message. This must be a non-zero value otherwise the
296    /// cache will be disabled.
297    #[cfg(cares1_23)]
298    pub fn set_query_cache_max_ttl(&mut self, qcache_max_ttl: u32) -> &mut Self {
299        self.ares_options.qcache_max_ttl = qcache_max_ttl;
300        self.optmask |= c_ares_sys::ARES_OPT_QUERY_CACHE;
301        self
302    }
303
304    /// Set server failover options.
305    ///
306    /// If this option is not specified then c-ares will use a probability of 10% and a minimum
307    /// delay of 5 seconds.
308    #[cfg(cares1_29)]
309    pub fn set_server_failover_options(
310        &mut self,
311        server_failover_options: &ServerFailoverOptions,
312    ) -> &mut Self {
313        self.ares_options.server_failover_opts.retry_chance = server_failover_options.retry_chance;
314        self.ares_options.server_failover_opts.retry_delay = server_failover_options.retry_delay;
315        self.optmask |= c_ares_sys::ARES_OPT_SERVER_FAILOVER;
316        self
317    }
318}
319
320/// A channel for name service lookups.
321pub struct Channel {
322    ares_channel: c_ares_sys::ares_channel,
323
324    // For ownership only.
325    _socket_state_callback: Option<Arc<SocketStateCallback>>,
326
327    // For ownership only.
328    #[cfg(cares1_29)]
329    _server_state_callback: Option<Arc<ServerStateCallback>>,
330
331    // For ownership only.
332    #[cfg(cares1_34)]
333    _pending_write_callback: Option<Arc<PendingWriteCallback>>,
334}
335
336impl Channel {
337    /// Create a new channel for name service lookups, with default `Options`.
338    pub fn new() -> Result<Self> {
339        let options = Options::default();
340        Self::with_options(options)
341    }
342
343    /// Create a new channel for name service lookups, with the given `Options`.
344    pub fn with_options(mut options: Options) -> Result<Channel> {
345        // Initialize the library.
346        let ares_library_lock = ARES_LIBRARY_LOCK.lock().unwrap();
347        let lib_rc = unsafe { c_ares_sys::ares_library_init(c_ares_sys::ARES_LIB_INIT_ALL) };
348        std::mem::drop(ares_library_lock);
349        if lib_rc != c_ares_sys::ares_status_t::ARES_SUCCESS as i32 {
350            return Err(Error::from(lib_rc));
351        }
352
353        // We deferred setting up domains in the options - do it now.
354        let domains: Vec<_> = options.domains.iter().map(|s| s.as_ptr()).collect();
355        options.ares_options.domains = domains.as_ptr().cast_mut().cast();
356        options.ares_options.ndomains = domains.len() as c_int;
357
358        // Likewise for lookups.
359        if let Some(c_lookup) = &options.lookups {
360            options.ares_options.lookups = c_lookup.as_ptr().cast_mut()
361        }
362
363        // And the resolvconf_path.
364        if let Some(c_resolvconf_path) = &options.resolvconf_path {
365            options.ares_options.resolvconf_path = c_resolvconf_path.as_ptr().cast_mut()
366        }
367
368        // And the hosts_path.
369        #[cfg(cares1_19)]
370        if let Some(c_hosts_path) = &options.hosts_path {
371            options.ares_options.hosts_path = c_hosts_path.as_ptr().cast_mut()
372        }
373
374        // Initialize the channel.
375        let mut ares_channel = ptr::null_mut();
376        let channel_rc = unsafe {
377            c_ares_sys::ares_init_options(&mut ares_channel, &options.ares_options, options.optmask)
378        };
379        if channel_rc != c_ares_sys::ares_status_t::ARES_SUCCESS as i32 {
380            let ares_library_lock = ARES_LIBRARY_LOCK.lock().unwrap();
381            unsafe { c_ares_sys::ares_library_cleanup() }
382            std::mem::drop(ares_library_lock);
383            return Err(Error::from(channel_rc));
384        }
385
386        let channel = Channel {
387            ares_channel,
388            _socket_state_callback: options.socket_state_callback,
389            #[cfg(cares1_29)]
390            _server_state_callback: None,
391            #[cfg(cares1_34)]
392            _pending_write_callback: None,
393        };
394        Ok(channel)
395    }
396
397    /// Reinitialize a channel from system configuration.
398    #[cfg(cares1_22)]
399    pub fn reinit(&mut self) -> Result<&mut Self> {
400        let rc = unsafe { c_ares_sys::ares_reinit(self.ares_channel) };
401        panic::propagate();
402
403        if let Ok(err) = Error::try_from(rc) {
404            return Err(err);
405        }
406        Ok(self)
407    }
408
409    /// Duplicate a channel.
410    pub fn try_clone(&self) -> Result<Channel> {
411        let mut ares_channel = ptr::null_mut();
412        let rc = unsafe { c_ares_sys::ares_dup(&mut ares_channel, self.ares_channel) };
413        if rc != c_ares_sys::ares_status_t::ARES_SUCCESS as i32 {
414            return Err(Error::from(rc));
415        }
416
417        let socket_state_callback = self._socket_state_callback.as_ref().cloned();
418
419        #[cfg(cares1_29)]
420        let server_state_callback = self._server_state_callback.as_ref().cloned();
421
422        #[cfg(cares1_34)]
423        let pending_write_callback = self._pending_write_callback.as_ref().cloned();
424
425        let channel = Channel {
426            ares_channel,
427            _socket_state_callback: socket_state_callback,
428            #[cfg(cares1_29)]
429            _server_state_callback: server_state_callback,
430            #[cfg(cares1_34)]
431            _pending_write_callback: pending_write_callback,
432        };
433        Ok(channel)
434    }
435
436    /// Handle input, output, and timeout events associated with the specified file descriptors
437    /// (sockets).
438    ///
439    /// Providing a value for `read_fd` indicates that the identified socket is readable; likewise
440    /// providing a value for `write_fd` indicates that the identified socket is writable.  Use
441    /// `SOCKET_BAD` for "no action".
442    pub fn process_fd(&mut self, read_fd: Socket, write_fd: Socket) {
443        unsafe { c_ares_sys::ares_process_fd(self.ares_channel, read_fd, write_fd) }
444        panic::propagate();
445    }
446
447    /// Handle input and output events associated with the specified file descriptors (sockets).
448    /// Also handles timeouts associated with the `Channel`.
449    pub fn process(&mut self, read_fds: &mut c_types::fd_set, write_fds: &mut c_types::fd_set) {
450        unsafe { c_ares_sys::ares_process(self.ares_channel, read_fds, write_fds) }
451        panic::propagate();
452    }
453
454    /// Process events on multiple file descriptors based on the event mask associated with each
455    /// file descriptor.  Recommended over calling `process_fd()` multiple times since it would
456    /// trigger additional logic such as timeout processing on each call.
457    #[cfg(cares1_34)]
458    pub fn process_fds(&mut self, events: &[FdEvents], flags: ProcessFlags) -> Result<()> {
459        let rc = unsafe {
460            c_ares_sys::ares_process_fds(
461                self.ares_channel,
462                events.as_ptr().cast(),
463                events.len(),
464                flags.bits(),
465            )
466        };
467        panic::propagate();
468
469        if let Ok(err) = Error::try_from(rc) {
470            return Err(err);
471        }
472        Ok(())
473    }
474
475    /// Retrieve the set of socket descriptors which the calling application should wait on for
476    /// reading and / or writing.
477    pub fn get_sock(&self) -> GetSock {
478        let mut socks = [0; c_ares_sys::ARES_GETSOCK_MAXNUM];
479        let bitmask = unsafe {
480            c_ares_sys::ares_getsock(
481                self.ares_channel,
482                socks.as_mut_ptr(),
483                c_ares_sys::ARES_GETSOCK_MAXNUM as c_int,
484            )
485        };
486        GetSock::new(socks, bitmask as u32)
487    }
488
489    /// Retrieve the set of socket descriptors which the calling application should wait on for
490    /// reading and / or writing.
491    pub fn fds(&self, read_fds: &mut c_types::fd_set, write_fds: &mut c_types::fd_set) -> u32 {
492        unsafe { c_ares_sys::ares_fds(self.ares_channel, read_fds, write_fds) as u32 }
493    }
494
495    /// Set the list of servers to contact, instead of the servers specified in resolv.conf or the
496    /// local named.
497    ///
498    /// String format is `host[:port]`.  IPv6 addresses with ports require square brackets eg
499    /// `[2001:4860:4860::8888]:53`.
500    pub fn set_servers(&mut self, servers: &[&str]) -> Result<&mut Self> {
501        let servers_csv = servers.join(",");
502        let c_servers = CString::new(servers_csv).unwrap();
503        let ares_rc = unsafe {
504            c_ares_sys::ares_set_servers_ports_csv(self.ares_channel, c_servers.as_ptr())
505        };
506        if ares_rc == c_ares_sys::ares_status_t::ARES_SUCCESS as i32 {
507            Ok(self)
508        } else {
509            Err(Error::from(ares_rc))
510        }
511    }
512
513    /// Retrieves the list of servers in comma delimited format.
514    #[cfg(cares1_24)]
515    pub fn get_servers(&self) -> AresString {
516        let servers = unsafe { c_ares_sys::ares_get_servers_csv(self.ares_channel) };
517        AresString::new(servers)
518    }
519
520    /// Set the local IPv4 address from which to make queries.
521    pub fn set_local_ipv4(&mut self, ipv4: Ipv4Addr) -> &mut Self {
522        unsafe { c_ares_sys::ares_set_local_ip4(self.ares_channel, u32::from(ipv4)) }
523        self
524    }
525
526    /// Set the local IPv6 address from which to make queries.
527    pub fn set_local_ipv6(&mut self, ipv6: &Ipv6Addr) -> &mut Self {
528        let in6_addr = ipv6_as_in6_addr(ipv6);
529        unsafe {
530            c_ares_sys::ares_set_local_ip6(self.ares_channel, ptr::from_ref(&in6_addr).cast())
531        }
532        self
533    }
534
535    /// Set the local device from which to make queries.
536    pub fn set_local_device(&mut self, device: &str) -> &mut Self {
537        let c_dev = CString::new(device).unwrap();
538        unsafe { c_ares_sys::ares_set_local_dev(self.ares_channel, c_dev.as_ptr()) }
539        self
540    }
541
542    /// Initializes an address sortlist configuration, so that addresses returned by
543    /// `get_host_by_name()` are sorted according to the sortlist.
544    ///
545    /// Each element of the sortlist holds an IP-address/netmask pair. The netmask is optional but
546    /// follows the address after a slash if present. For example: "130.155.160.0/255.255.240.0",
547    /// or "130.155.0.0".
548    pub fn set_sortlist(&mut self, sortlist: &[&str]) -> Result<&mut Self> {
549        let sortlist_str = sortlist.join(" ");
550        let c_sortlist = CString::new(sortlist_str).unwrap();
551        let ares_rc =
552            unsafe { c_ares_sys::ares_set_sortlist(self.ares_channel, c_sortlist.as_ptr()) };
553        if ares_rc == c_ares_sys::ares_status_t::ARES_SUCCESS as i32 {
554            Ok(self)
555        } else {
556            Err(Error::from(ares_rc))
557        }
558    }
559
560    /// Set a callback function to be invoked whenever a query on the channel completes.
561    ///
562    /// `callback(server, success, flags)` will be called when a query completes.
563    ///
564    /// - `server` indicates the DNS server that was used for the query.
565    /// - `success` indicates whether the query succeeded or not.
566    /// - `flags` is a bitmask of flags describing various aspects of the query.
567    #[cfg(cares1_29)]
568    pub fn set_server_state_callback<F>(&mut self, callback: F) -> &mut Self
569    where
570        F: FnMut(&str, bool, ServerStateFlags) + Send + 'static,
571    {
572        let boxed_callback = Arc::new(callback);
573        let data = ptr::from_ref(&*boxed_callback).cast_mut().cast();
574        unsafe {
575            c_ares_sys::ares_set_server_state_callback(
576                self.ares_channel,
577                Some(server_state_callback::<F>),
578                data,
579            )
580        }
581        self._server_state_callback = Some(boxed_callback);
582        self
583    }
584
585    /// Set a callback function to be invoked when there is potential pending data
586    /// which needs to be written.
587    #[cfg(cares1_34)]
588    pub fn set_pending_write_callback<F>(&mut self, callback: F) -> &mut Self
589    where
590        F: FnMut() + Send + 'static,
591    {
592        let boxed_callback = Arc::new(callback);
593        let data = ptr::from_ref(&*boxed_callback).cast_mut().cast();
594        unsafe {
595            c_ares_sys::ares_set_pending_write_cb(
596                self.ares_channel,
597                Some(pending_write_callback::<F>),
598                data,
599            )
600        }
601        self._pending_write_callback = Some(boxed_callback);
602        self
603    }
604
605    /// Initiate a single-question DNS query for the A records associated with `name`.
606    ///
607    /// On completion, `handler` is called with the result.
608    pub fn query_a<F>(&mut self, name: &str, handler: F)
609    where
610        F: FnOnce(Result<AResults>) + Send + 'static,
611    {
612        ares_query!(
613            self.ares_channel,
614            name,
615            DnsClass::IN,
616            QueryType::A,
617            query_a_callback::<F>,
618            handler
619        );
620    }
621
622    /// Initiate a series of single-question DNS queries for the A records associated with `name`.
623    ///
624    /// On completion, `handler` is called with the result.
625    pub fn search_a<F>(&mut self, name: &str, handler: F)
626    where
627        F: FnOnce(Result<AResults>) + Send + 'static,
628    {
629        ares_search!(
630            self.ares_channel,
631            name,
632            DnsClass::IN,
633            QueryType::A,
634            query_a_callback::<F>,
635            handler
636        );
637    }
638
639    /// Initiate a single-question DNS query for the AAAA records associated with `name`.
640    ///
641    /// On completion, `handler` is called with the result.
642    pub fn query_aaaa<F>(&mut self, name: &str, handler: F)
643    where
644        F: FnOnce(Result<AAAAResults>) + Send + 'static,
645    {
646        ares_query!(
647            self.ares_channel,
648            name,
649            DnsClass::IN,
650            QueryType::AAAA,
651            query_aaaa_callback::<F>,
652            handler
653        );
654    }
655
656    /// Initiate a series of single-question DNS queries for the AAAA records associated with
657    /// `name`.
658    ///
659    /// On completion, `handler` is called with the result.
660    pub fn search_aaaa<F>(&mut self, name: &str, handler: F)
661    where
662        F: FnOnce(Result<AAAAResults>) + Send + 'static,
663    {
664        ares_search!(
665            self.ares_channel,
666            name,
667            DnsClass::IN,
668            QueryType::AAAA,
669            query_aaaa_callback::<F>,
670            handler
671        );
672    }
673
674    /// Initiate a single-question DNS query for the CAA records associated with `name`.
675    ///
676    /// On completion, `handler` is called with the result.
677    pub fn query_caa<F>(&mut self, name: &str, handler: F)
678    where
679        F: FnOnce(Result<CAAResults>) + Send + 'static,
680    {
681        ares_query!(
682            self.ares_channel,
683            name,
684            DnsClass::IN,
685            QueryType::CAA,
686            query_caa_callback::<F>,
687            handler
688        );
689    }
690
691    /// Initiate a series of single-question DNS queries for the CAA records associated with
692    /// `name`.
693    ///
694    /// On completion, `handler` is called with the result.
695    pub fn search_caa<F>(&mut self, name: &str, handler: F)
696    where
697        F: FnOnce(Result<CAAResults>) + Send + 'static,
698    {
699        ares_search!(
700            self.ares_channel,
701            name,
702            DnsClass::IN,
703            QueryType::CAA,
704            query_caa_callback::<F>,
705            handler
706        );
707    }
708
709    /// Initiate a single-question DNS query for the CNAME records associated with `name`.
710    ///
711    /// On completion, `handler` is called with the result.
712    pub fn query_cname<F>(&mut self, name: &str, handler: F)
713    where
714        F: FnOnce(Result<CNameResults>) + Send + 'static,
715    {
716        ares_query!(
717            self.ares_channel,
718            name,
719            DnsClass::IN,
720            QueryType::CNAME,
721            query_cname_callback::<F>,
722            handler
723        );
724    }
725
726    /// Initiate a series of single-question DNS queries for the CNAME records associated with
727    /// `name`.
728    ///
729    /// On completion, `handler` is called with the result.
730    pub fn search_cname<F>(&mut self, name: &str, handler: F)
731    where
732        F: FnOnce(Result<CNameResults>) + Send + 'static,
733    {
734        ares_search!(
735            self.ares_channel,
736            name,
737            DnsClass::IN,
738            QueryType::CNAME,
739            query_cname_callback::<F>,
740            handler
741        );
742    }
743
744    /// Initiate a single-question DNS query for the MX records associated with `name`.
745    ///
746    /// On completion, `handler` is called with the result.
747    pub fn query_mx<F>(&mut self, name: &str, handler: F)
748    where
749        F: FnOnce(Result<MXResults>) + Send + 'static,
750    {
751        ares_query!(
752            self.ares_channel,
753            name,
754            DnsClass::IN,
755            QueryType::MX,
756            query_mx_callback::<F>,
757            handler
758        );
759    }
760
761    /// Initiate a series of single-question DNS queries for the MX records associated with `name`.
762    ///
763    /// On completion, `handler` is called with the result.
764    pub fn search_mx<F>(&mut self, name: &str, handler: F)
765    where
766        F: FnOnce(Result<MXResults>) + Send + 'static,
767    {
768        ares_search!(
769            self.ares_channel,
770            name,
771            DnsClass::IN,
772            QueryType::MX,
773            query_mx_callback::<F>,
774            handler
775        );
776    }
777
778    /// Initiate a single-question DNS query for the NAPTR records associated with `name`.
779    ///
780    /// On completion, `handler` is called with the result.
781    pub fn query_naptr<F>(&mut self, name: &str, handler: F)
782    where
783        F: FnOnce(Result<NAPTRResults>) + Send + 'static,
784    {
785        ares_query!(
786            self.ares_channel,
787            name,
788            DnsClass::IN,
789            QueryType::NAPTR,
790            query_naptr_callback::<F>,
791            handler
792        );
793    }
794
795    /// Initiate a series of single-question DNS queries for the NAPTR records associated with
796    /// `name`.
797    ///
798    /// On completion, `handler` is called with the result.
799    pub fn search_naptr<F>(&mut self, name: &str, handler: F)
800    where
801        F: FnOnce(Result<NAPTRResults>) + Send + 'static,
802    {
803        ares_search!(
804            self.ares_channel,
805            name,
806            DnsClass::IN,
807            QueryType::NAPTR,
808            query_naptr_callback::<F>,
809            handler
810        );
811    }
812
813    /// Initiate a single-question DNS query for the NS records associated with `name`.
814    ///
815    /// On completion, `handler` is called with the result.
816    pub fn query_ns<F>(&mut self, name: &str, handler: F)
817    where
818        F: FnOnce(Result<NSResults>) + Send + 'static,
819    {
820        ares_query!(
821            self.ares_channel,
822            name,
823            DnsClass::IN,
824            QueryType::NS,
825            query_ns_callback::<F>,
826            handler
827        );
828    }
829
830    /// Initiate a series of single-question DNS queries for the NS records associated with `name`.
831    ///
832    /// On completion, `handler` is called with the result.
833    pub fn search_ns<F>(&mut self, name: &str, handler: F)
834    where
835        F: FnOnce(Result<NSResults>) + Send + 'static,
836    {
837        ares_search!(
838            self.ares_channel,
839            name,
840            DnsClass::IN,
841            QueryType::NS,
842            query_ns_callback::<F>,
843            handler
844        );
845    }
846
847    /// Initiate a single-question DNS query for the PTR records associated with `name`.
848    ///
849    /// On completion, `handler` is called with the result.
850    pub fn query_ptr<F>(&mut self, name: &str, handler: F)
851    where
852        F: FnOnce(Result<PTRResults>) + Send + 'static,
853    {
854        ares_query!(
855            self.ares_channel,
856            name,
857            DnsClass::IN,
858            QueryType::PTR,
859            query_ptr_callback::<F>,
860            handler
861        );
862    }
863
864    /// Initiate a series of single-question DNS queries for the PTR records associated with
865    /// `name`.
866    ///
867    /// On completion, `handler` is called with the result.
868    pub fn search_ptr<F>(&mut self, name: &str, handler: F)
869    where
870        F: FnOnce(Result<PTRResults>) + Send + 'static,
871    {
872        ares_search!(
873            self.ares_channel,
874            name,
875            DnsClass::IN,
876            QueryType::PTR,
877            query_ptr_callback::<F>,
878            handler
879        );
880    }
881
882    /// Initiate a single-question DNS query for the SOA records associated with `name`.
883    ///
884    /// On completion, `handler` is called with the result.
885    pub fn query_soa<F>(&mut self, name: &str, handler: F)
886    where
887        F: FnOnce(Result<SOAResult>) + Send + 'static,
888    {
889        ares_query!(
890            self.ares_channel,
891            name,
892            DnsClass::IN,
893            QueryType::SOA,
894            query_soa_callback::<F>,
895            handler
896        );
897    }
898
899    /// Initiate a series of single-question DNS queries for the SOA records associated with
900    /// `name`.
901    ///
902    /// On completion, `handler` is called with the result.
903    pub fn search_soa<F>(&mut self, name: &str, handler: F)
904    where
905        F: FnOnce(Result<SOAResult>) + Send + 'static,
906    {
907        ares_search!(
908            self.ares_channel,
909            name,
910            DnsClass::IN,
911            QueryType::SOA,
912            query_soa_callback::<F>,
913            handler
914        );
915    }
916
917    /// Initiate a single-question DNS query for the SRV records associated with `name`.
918    ///
919    /// On completion, `handler` is called with the result.
920    pub fn query_srv<F>(&mut self, name: &str, handler: F)
921    where
922        F: FnOnce(Result<SRVResults>) + Send + 'static,
923    {
924        ares_query!(
925            self.ares_channel,
926            name,
927            DnsClass::IN,
928            QueryType::SRV,
929            query_srv_callback::<F>,
930            handler
931        );
932    }
933
934    /// Initiate a series of single-question DNS queries for the SRV records associated with
935    /// `name`.
936    ///
937    /// On completion, `handler` is called with the result.
938    pub fn search_srv<F>(&mut self, name: &str, handler: F)
939    where
940        F: FnOnce(Result<SRVResults>) + Send + 'static,
941    {
942        ares_search!(
943            self.ares_channel,
944            name,
945            DnsClass::IN,
946            QueryType::SRV,
947            query_srv_callback::<F>,
948            handler
949        );
950    }
951
952    /// Initiate a single-question DNS query for the TXT records associated with `name`.
953    ///
954    /// On completion, `handler` is called with the result.
955    pub fn query_txt<F>(&mut self, name: &str, handler: F)
956    where
957        F: FnOnce(Result<TXTResults>) + Send + 'static,
958    {
959        ares_query!(
960            self.ares_channel,
961            name,
962            DnsClass::IN,
963            QueryType::TXT,
964            query_txt_callback::<F>,
965            handler
966        );
967    }
968
969    /// Initiate a series of single-question DNS queries for the TXT records associated with
970    /// `name`.
971    ///
972    /// On completion, `handler` is called with the result.
973    pub fn search_txt<F>(&mut self, name: &str, handler: F)
974    where
975        F: FnOnce(Result<TXTResults>) + Send + 'static,
976    {
977        ares_search!(
978            self.ares_channel,
979            name,
980            DnsClass::IN,
981            QueryType::TXT,
982            query_txt_callback::<F>,
983            handler
984        );
985    }
986
987    /// Initiate a single-question DNS query for the URI records associated with `name`.
988    ///
989    /// On completion, `handler` is called with the result.
990    pub fn query_uri<F>(&mut self, name: &str, handler: F)
991    where
992        F: FnOnce(Result<URIResults>) + Send + 'static,
993    {
994        ares_query!(
995            self.ares_channel,
996            name,
997            DnsClass::IN,
998            QueryType::URI,
999            query_uri_callback::<F>,
1000            handler
1001        );
1002    }
1003
1004    /// Initiate a series of single-question DNS queries for the URI records associated with
1005    /// `name`.
1006    ///
1007    /// On completion, `handler` is called with the result.
1008    pub fn search_uri<F>(&mut self, name: &str, handler: F)
1009    where
1010        F: FnOnce(Result<URIResults>) + Send + 'static,
1011    {
1012        ares_search!(
1013            self.ares_channel,
1014            name,
1015            DnsClass::IN,
1016            QueryType::URI,
1017            query_uri_callback::<F>,
1018            handler
1019        );
1020    }
1021
1022    /// Perform a host query by address.
1023    ///
1024    /// On completion, `handler` is called with the result.
1025    pub fn get_host_by_address<F>(&mut self, address: &IpAddr, handler: F)
1026    where
1027        F: FnOnce(Result<HostResults>) + Send + 'static,
1028    {
1029        let in_addr: c_types::in_addr;
1030        let in6_addr: c_types::in6_addr;
1031        let c_addr = match *address {
1032            IpAddr::V4(v4) => {
1033                in_addr = ipv4_as_in_addr(v4);
1034                ptr::from_ref(&in_addr).cast()
1035            }
1036            IpAddr::V6(ref v6) => {
1037                in6_addr = ipv6_as_in6_addr(v6);
1038                ptr::from_ref(&in6_addr).cast()
1039            }
1040        };
1041        let (family, length) = match *address {
1042            IpAddr::V4(_) => (AddressFamily::INET, mem::size_of::<c_types::in_addr>()),
1043            IpAddr::V6(_) => (AddressFamily::INET6, mem::size_of::<c_types::in6_addr>()),
1044        };
1045        let c_arg = Box::into_raw(Box::new(handler));
1046        unsafe {
1047            c_ares_sys::ares_gethostbyaddr(
1048                self.ares_channel,
1049                c_addr,
1050                length as c_int,
1051                family as c_int,
1052                Some(get_host_callback::<F>),
1053                c_arg.cast(),
1054            )
1055        }
1056        panic::propagate();
1057    }
1058
1059    /// Perform a host query by name.
1060    ///
1061    /// On completion, `handler` is called with the result.
1062    pub fn get_host_by_name<F>(&mut self, name: &str, family: AddressFamily, handler: F)
1063    where
1064        F: FnOnce(Result<HostResults>) + Send + 'static,
1065    {
1066        let c_name = CString::new(name).unwrap();
1067        let c_arg = Box::into_raw(Box::new(handler));
1068        unsafe {
1069            c_ares_sys::ares_gethostbyname(
1070                self.ares_channel,
1071                c_name.as_ptr(),
1072                family as c_int,
1073                Some(get_host_callback::<F>),
1074                c_arg.cast(),
1075            )
1076        }
1077        panic::propagate();
1078    }
1079
1080    /// Address-to-nodename translation in protocol-independent manner.
1081    ///
1082    /// The valid values for `flags` are documented [here](ni_flags/index.html).
1083    ///
1084    /// On completion, `handler` is called with the result.
1085    pub fn get_name_info<F>(&mut self, address: &SocketAddr, flags: NIFlags, handler: F)
1086    where
1087        F: FnOnce(Result<NameInfoResult>) + Send + 'static,
1088    {
1089        let sockaddr_in: c_types::sockaddr_in;
1090        let sockaddr_in6: c_types::sockaddr_in6;
1091        let c_addr = match *address {
1092            SocketAddr::V4(ref v4) => {
1093                sockaddr_in = socket_addrv4_as_sockaddr_in(v4);
1094                ptr::from_ref(&sockaddr_in).cast()
1095            }
1096            SocketAddr::V6(ref v6) => {
1097                sockaddr_in6 = socket_addrv6_as_sockaddr_in6(v6);
1098                ptr::from_ref(&sockaddr_in6).cast()
1099            }
1100        };
1101        let length = match *address {
1102            SocketAddr::V4(_) => mem::size_of::<c_types::sockaddr_in>(),
1103            SocketAddr::V6(_) => mem::size_of::<c_types::sockaddr_in6>(),
1104        };
1105        let c_arg = Box::into_raw(Box::new(handler));
1106        unsafe {
1107            c_ares_sys::ares_getnameinfo(
1108                self.ares_channel,
1109                c_addr,
1110                length as c_ares_sys::ares_socklen_t,
1111                flags.bits(),
1112                Some(get_name_info_callback::<F>),
1113                c_arg.cast(),
1114            )
1115        }
1116        panic::propagate();
1117    }
1118
1119    /// Initiate a single-question DNS query for `name`.  The class and type of the query are per
1120    /// the provided parameters, taking values as defined in `arpa/nameser.h`.
1121    ///
1122    /// On completion, `handler` is called with the result.
1123    ///
1124    /// This method is provided so that users can query DNS types for which `c-ares` does not
1125    /// provide a parser.  This is expected to be a last resort; if a suitable `query_xxx()` is
1126    /// available, that should be preferred.
1127    pub fn query<F>(&mut self, name: &str, dns_class: u16, query_type: u16, handler: F)
1128    where
1129        F: FnOnce(Result<&[u8]>) + Send + 'static,
1130    {
1131        ares_query!(
1132            self.ares_channel,
1133            name,
1134            c_int::from(dns_class),
1135            c_int::from(query_type),
1136            query_callback::<F>,
1137            handler
1138        );
1139    }
1140
1141    /// Initiate a series of single-question DNS queries for `name`.  The class and type of the
1142    /// query are per the provided parameters, taking values as defined in `arpa/nameser.h`.
1143    ///
1144    /// On completion, `handler` is called with the result.
1145    ///
1146    /// This method is provided so that users can search DNS types for which `c-ares` does not
1147    /// provide a parser.  This is expected to be a last resort; if a suitable `search_xxx()` is
1148    /// available, that should be preferred.
1149    pub fn search<F>(&mut self, name: &str, dns_class: u16, query_type: u16, handler: F)
1150    where
1151        F: FnOnce(Result<&[u8]>) + Send + 'static,
1152    {
1153        ares_search!(
1154            self.ares_channel,
1155            name,
1156            c_int::from(dns_class),
1157            c_int::from(query_type),
1158            query_callback::<F>,
1159            handler
1160        );
1161    }
1162
1163    /// Cancel all requests made on this `Channel`.
1164    ///
1165    /// Callbacks will be invoked for each pending query, passing a result
1166    /// `Err(Error::ECANCELLED)`.
1167    pub fn cancel(&mut self) {
1168        unsafe { c_ares_sys::ares_cancel(self.ares_channel) }
1169        panic::propagate();
1170    }
1171
1172    /// Kick c-ares to process a pending write.
1173    #[cfg(cares1_34)]
1174    pub fn process_pending_write(&mut self) {
1175        unsafe { c_ares_sys::ares_process_pending_write(self.ares_channel) }
1176        panic::propagate();
1177    }
1178}
1179
1180impl Drop for Channel {
1181    fn drop(&mut self) {
1182        unsafe { c_ares_sys::ares_destroy(self.ares_channel) }
1183        let ares_library_lock = ARES_LIBRARY_LOCK.lock().unwrap();
1184        unsafe { c_ares_sys::ares_library_cleanup() }
1185        std::mem::drop(ares_library_lock);
1186        panic::propagate();
1187    }
1188}
1189
1190unsafe impl Send for Channel {}
1191unsafe impl Sync for Channel {}
1192unsafe impl Send for Options {}
1193unsafe impl Sync for Options {}
1194
1195unsafe extern "C" fn socket_state_callback<F>(
1196    data: *mut c_void,
1197    socket_fd: c_ares_sys::ares_socket_t,
1198    readable: c_int,
1199    writable: c_int,
1200) where
1201    F: FnMut(Socket, bool, bool) + Send + 'static,
1202{
1203    let handler = data.cast::<F>();
1204    let handler = unsafe { &mut *handler };
1205    panic::catch(|| handler(socket_fd, readable != 0, writable != 0));
1206}
1207
1208#[cfg(cares1_29)]
1209unsafe extern "C" fn server_state_callback<F>(
1210    server_string: *const c_char,
1211    success: c_ares_sys::ares_bool_t,
1212    flags: c_int,
1213    data: *mut c_void,
1214) where
1215    F: FnMut(&str, bool, ServerStateFlags) + Send + 'static,
1216{
1217    let handler = data.cast::<F>();
1218    let handler = unsafe { &mut *handler };
1219    let server = unsafe { c_string_as_str_unchecked(server_string) };
1220    panic::catch(|| {
1221        handler(
1222            server,
1223            success != c_ares_sys::ares_bool_t::ARES_FALSE,
1224            ServerStateFlags::from_bits_truncate(flags),
1225        )
1226    });
1227}
1228
1229#[cfg(cares1_34)]
1230unsafe extern "C" fn pending_write_callback<F>(data: *mut c_void)
1231where
1232    F: FnMut() + Send + 'static,
1233{
1234    let handler = data.cast::<F>();
1235    let handler = unsafe { &mut *handler };
1236    panic::catch(handler);
1237}
1238
1239/// Information about the set of sockets that `c-ares` is interested in, as returned by
1240/// `get_sock()`.
1241#[derive(Clone, Copy, Debug)]
1242pub struct GetSock {
1243    socks: [c_ares_sys::ares_socket_t; c_ares_sys::ARES_GETSOCK_MAXNUM],
1244    bitmask: u32,
1245}
1246
1247impl GetSock {
1248    fn new(
1249        socks: [c_ares_sys::ares_socket_t; c_ares_sys::ARES_GETSOCK_MAXNUM],
1250        bitmask: u32,
1251    ) -> Self {
1252        GetSock { socks, bitmask }
1253    }
1254
1255    /// Returns an iterator over the sockets that `c-ares` is interested in.
1256    pub fn iter(&self) -> GetSockIter<'_> {
1257        GetSockIter {
1258            next: 0,
1259            getsock: self,
1260        }
1261    }
1262}
1263
1264/// Iterator for sockets of interest to `c-ares`.
1265///
1266/// Iterator items are `(socket, readable, writable)`.
1267#[derive(Clone, Copy, Debug)]
1268pub struct GetSockIter<'a> {
1269    next: usize,
1270    getsock: &'a GetSock,
1271}
1272
1273impl Iterator for GetSockIter<'_> {
1274    type Item = (Socket, bool, bool);
1275    fn next(&mut self) -> Option<Self::Item> {
1276        let index = self.next;
1277        self.next += 1;
1278        if index >= c_ares_sys::ARES_GETSOCK_MAXNUM {
1279            None
1280        } else {
1281            let bit = 1 << index;
1282            let readable = (self.getsock.bitmask & bit) != 0;
1283            let bit = bit << c_ares_sys::ARES_GETSOCK_MAXNUM;
1284            let writable = (self.getsock.bitmask & bit) != 0;
1285            if readable || writable {
1286                let fd = self.getsock.socks[index];
1287                Some((fd, readable, writable))
1288            } else {
1289                None
1290            }
1291        }
1292    }
1293}
1294
1295impl<'a> IntoIterator for &'a GetSock {
1296    type Item = (Socket, bool, bool);
1297    type IntoIter = GetSockIter<'a>;
1298
1299    fn into_iter(self) -> Self::IntoIter {
1300        self.iter()
1301    }
1302}