c_ares/
channel.rs

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