1#[allow(unused_imports)]
2use core::ffi::{c_char, c_int, c_void};
3use std::ffi::CString;
4use std::fmt;
5use std::mem;
6use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
7use std::ptr;
8use std::sync::Arc;
9use std::time::Duration;
10
11mod options;
12mod sockets;
13
14pub use options::Options;
15#[cfg(cares1_29)]
16pub use options::ServerFailoverOptions;
17pub use sockets::{Sockets, SocketsIter};
18
19use options::SocketStateCallback;
20
21#[cfg(cares1_29)]
22use crate::ServerStateFlags;
23use crate::a::AResults;
24use crate::aaaa::AAAAResults;
25use crate::addrinfo::{AddrInfoHints, AddrInfoResults, get_addrinfo_callback};
26use crate::caa::CAAResults;
27use crate::cname::CNameResults;
28#[cfg(cares1_28)]
29use crate::dns::callback::dnsrec_callback;
30#[cfg(cares1_28)]
31use crate::dns::{DnsCls, DnsRecord, DnsRecordType};
32use crate::error::{Error, Result};
33#[cfg(cares1_34)]
34use crate::events::{FdEvents, ProcessFlags};
35use crate::host::HostResults;
36use crate::host::get_host_callback;
37use crate::mx::MXResults;
38use crate::nameinfo::{NameInfoResult, get_name_info_callback};
39use crate::naptr::NAPTRResults;
40use crate::ni_flags::NIFlags;
41use crate::ns::NSResults;
42use crate::panic;
43use crate::ptr::PTRResults;
44use crate::query::{query_callback, raw_query_callback};
45use crate::record::QueryRecord;
46use crate::soa::SOAResult;
47use crate::srv::SRVResults;
48#[cfg(cares1_24)]
49use crate::string::AresString;
50use crate::txt::TXTResults;
51use crate::types::{AddressFamily, DnsClass, Socket};
52use crate::uri::URIResults;
53#[allow(unused_imports)]
54use crate::utils::{
55 c_string_as_str_unchecked, ipv4_as_in_addr, ipv6_as_in6_addr, socket_addrv4_as_sockaddr_in,
56 socket_addrv6_as_sockaddr_in6, status_to_result,
57};
58use std::sync::Mutex;
59
60static ARES_LIBRARY_LOCK: Mutex<()> = Mutex::new(());
62
63#[cfg(cares1_29)]
64type ServerStateCallback = dyn Fn(&str, bool, ServerStateFlags) + Send + Sync + 'static;
65
66#[cfg(cares1_34)]
67type PendingWriteCallback = dyn Fn() + Send + Sync + 'static;
68
69pub struct Channel {
71 #[allow(clippy::struct_field_names)]
74 ares_channel: c_ares_sys::ares_channel,
75
76 socket_state_callback: Option<Arc<SocketStateCallback>>,
78
79 #[cfg(cares1_29)]
81 server_state_callback: Option<Arc<ServerStateCallback>>,
82
83 #[cfg(cares1_34)]
85 pending_write_callback: Option<Arc<PendingWriteCallback>>,
86}
87
88impl Channel {
89 pub fn as_raw(&self) -> c_ares_sys::ares_channel {
97 self.ares_channel
98 }
99
100 pub fn new() -> Result<Self> {
108 let options = Options::default();
109 Self::with_options(options)
110 }
111
112 pub fn with_options(mut options: Options) -> Result<Channel> {
123 let lib_rc = {
125 let _lock = ARES_LIBRARY_LOCK.lock().unwrap();
126 unsafe { c_ares_sys::ares_library_init(c_ares_sys::ARES_LIB_INIT_ALL) }
127 };
128 if lib_rc != c_ares_sys::ares_status_t::ARES_SUCCESS as i32 {
129 return Err(Error::from(lib_rc));
130 }
131
132 let domains: Vec<_> = options.domains.iter().map(|s| s.as_ptr()).collect();
134 options.ares_options.domains = domains.as_ptr().cast_mut().cast();
135 options.ares_options.ndomains = domains.len() as i32;
136
137 if let Some(c_lookup) = &options.lookups {
139 options.ares_options.lookups = c_lookup.as_ptr().cast_mut();
140 }
141
142 if let Some(c_resolvconf_path) = &options.resolvconf_path {
144 options.ares_options.resolvconf_path = c_resolvconf_path.as_ptr().cast_mut();
145 }
146
147 #[cfg(cares1_19)]
149 if let Some(c_hosts_path) = &options.hosts_path {
150 options.ares_options.hosts_path = c_hosts_path.as_ptr().cast_mut();
151 }
152
153 let mut ares_channel = ptr::null_mut();
155 let channel_rc = unsafe {
156 c_ares_sys::ares_init_options(
157 &raw mut ares_channel,
158 &raw const options.ares_options,
159 options.optmask,
160 )
161 };
162 if channel_rc != c_ares_sys::ares_status_t::ARES_SUCCESS as i32 {
163 let _lock = ARES_LIBRARY_LOCK.lock().unwrap();
164 unsafe { c_ares_sys::ares_library_cleanup() }
165 return Err(Error::from(channel_rc));
166 }
167
168 let channel = Channel {
169 ares_channel,
170 socket_state_callback: options.socket_state_callback,
171 #[cfg(cares1_29)]
172 server_state_callback: None,
173 #[cfg(cares1_34)]
174 pending_write_callback: None,
175 };
176 Ok(channel)
177 }
178
179 #[cfg(cares1_22)]
181 pub fn reinit(&mut self) -> Result<&mut Self> {
182 let rc = unsafe { c_ares_sys::ares_reinit(self.ares_channel) };
183 status_to_result(rc)?;
184 Ok(self)
185 }
186
187 pub fn try_clone(&self) -> Result<Channel> {
189 let lib_rc = {
191 let _lock = ARES_LIBRARY_LOCK.lock().unwrap();
192 unsafe { c_ares_sys::ares_library_init(c_ares_sys::ARES_LIB_INIT_ALL) }
193 };
194 if lib_rc != c_ares_sys::ares_status_t::ARES_SUCCESS as i32 {
195 return Err(Error::from(lib_rc));
196 }
197
198 let mut ares_channel = ptr::null_mut();
199 let rc = unsafe { c_ares_sys::ares_dup(&raw mut ares_channel, self.ares_channel) };
200 if rc != c_ares_sys::ares_status_t::ARES_SUCCESS as i32 {
201 let _lock = ARES_LIBRARY_LOCK.lock().unwrap();
202 unsafe { c_ares_sys::ares_library_cleanup() }
203 return Err(Error::from(rc));
204 }
205
206 let socket_state_callback = self.socket_state_callback.clone();
207
208 #[cfg(cares1_29)]
209 let server_state_callback = self.server_state_callback.clone();
210
211 #[cfg(cares1_34)]
212 let pending_write_callback = self.pending_write_callback.clone();
213
214 let channel = Channel {
215 ares_channel,
216 socket_state_callback,
217 #[cfg(cares1_29)]
218 server_state_callback,
219 #[cfg(cares1_34)]
220 pending_write_callback,
221 };
222 Ok(channel)
223 }
224
225 pub fn process_fd(&mut self, read_fd: Option<Socket>, write_fd: Option<Socket>) {
232 let rfd = read_fd.unwrap_or(c_ares_sys::ARES_SOCKET_BAD);
233 let wfd = write_fd.unwrap_or(c_ares_sys::ARES_SOCKET_BAD);
234 unsafe { c_ares_sys::ares_process_fd(self.ares_channel, rfd, wfd) }
235 }
236
237 pub fn process(&mut self, read_fds: &mut c_types::fd_set, write_fds: &mut c_types::fd_set) {
240 unsafe { c_ares_sys::ares_process(self.ares_channel, read_fds, write_fds) }
241 }
242
243 #[cfg(cares1_34)]
247 pub fn process_fds(&mut self, events: &[FdEvents], flags: ProcessFlags) -> Result<()> {
248 let rc = unsafe {
249 c_ares_sys::ares_process_fds(
250 self.ares_channel,
251 events.as_ptr().cast(),
252 events.len(),
253 flags.bits(),
254 )
255 };
256 status_to_result(rc)
257 }
258
259 pub fn sockets(&self) -> Sockets {
271 let mut socks = [0; c_ares_sys::ARES_GETSOCK_MAXNUM];
272 let bitmask = unsafe {
273 c_ares_sys::ares_getsock(
274 self.ares_channel,
275 socks.as_mut_ptr(),
276 c_ares_sys::ARES_GETSOCK_MAXNUM as i32,
277 )
278 };
279 Sockets::new(socks, bitmask as u32)
280 }
281
282 pub fn fds(&self, read_fds: &mut c_types::fd_set, write_fds: &mut c_types::fd_set) -> u32 {
285 unsafe { c_ares_sys::ares_fds(self.ares_channel, read_fds, write_fds) as u32 }
286 }
287
288 pub fn set_servers<I, S>(&mut self, servers: I) -> Result<&mut Self>
301 where
302 I: IntoIterator<Item = S>,
303 S: AsRef<str>,
304 {
305 let mut servers_csv = String::new();
306 for (i, s) in servers.into_iter().enumerate() {
307 if i > 0 {
308 servers_csv.push(',');
309 }
310 servers_csv.push_str(s.as_ref());
311 }
312 let c_servers = CString::new(servers_csv).map_err(|_| Error::EBADSTR)?;
313 let ares_rc = unsafe {
314 c_ares_sys::ares_set_servers_ports_csv(self.ares_channel, c_servers.as_ptr())
315 };
316 if ares_rc == c_ares_sys::ares_status_t::ARES_SUCCESS as i32 {
317 Ok(self)
318 } else {
319 Err(Error::from(ares_rc))
320 }
321 }
322
323 #[cfg(cares1_24)]
328 pub fn servers(&self) -> Vec<String> {
329 let csv = unsafe { c_ares_sys::ares_get_servers_csv(self.ares_channel) };
330 Self::parse_servers_csv(csv)
331 }
332
333 #[cfg(cares1_24)]
336 fn parse_servers_csv(csv: *mut c_char) -> Vec<String> {
337 if csv.is_null() {
339 return Vec::new();
340 }
341 let csv = AresString::new(csv);
342 let csv: &str = &csv;
343 if csv.is_empty() {
344 Vec::new()
345 } else {
346 csv.split(',').map(String::from).collect()
347 }
348 }
349
350 pub fn set_local_ipv4(&mut self, ipv4: Ipv4Addr) -> &mut Self {
352 unsafe { c_ares_sys::ares_set_local_ip4(self.ares_channel, u32::from(ipv4)) }
353 self
354 }
355
356 pub fn set_local_ipv6(&mut self, ipv6: Ipv6Addr) -> &mut Self {
358 let in6_addr = ipv6_as_in6_addr(&ipv6);
359 unsafe {
360 c_ares_sys::ares_set_local_ip6(self.ares_channel, ptr::from_ref(&in6_addr).cast());
361 }
362 self
363 }
364
365 pub fn set_local_device(&mut self, device: &str) -> Result<&mut Self> {
367 let c_dev = CString::new(device).map_err(|_| Error::EBADSTR)?;
368 unsafe { c_ares_sys::ares_set_local_dev(self.ares_channel, c_dev.as_ptr()) }
369 Ok(self)
370 }
371
372 pub fn set_sortlist<I, S>(&mut self, sortlist: I) -> Result<&mut Self>
379 where
380 I: IntoIterator<Item = S>,
381 S: AsRef<str>,
382 {
383 let mut sortlist_str = String::new();
384 for (i, s) in sortlist.into_iter().enumerate() {
385 if i > 0 {
386 sortlist_str.push(' ');
387 }
388 sortlist_str.push_str(s.as_ref());
389 }
390 let c_sortlist = CString::new(sortlist_str).map_err(|_| Error::EBADSTR)?;
391 let ares_rc =
392 unsafe { c_ares_sys::ares_set_sortlist(self.ares_channel, c_sortlist.as_ptr()) };
393 if ares_rc == c_ares_sys::ares_status_t::ARES_SUCCESS as i32 {
394 Ok(self)
395 } else {
396 Err(Error::from(ares_rc))
397 }
398 }
399
400 #[cfg(cares1_29)]
408 pub fn set_server_state_callback<F>(&mut self, callback: F) -> &mut Self
409 where
410 F: Fn(&str, bool, ServerStateFlags) + Send + Sync + 'static,
411 {
412 let boxed_callback = Arc::new(callback);
413 let data = Arc::as_ptr(&boxed_callback).cast_mut().cast();
414 unsafe {
415 c_ares_sys::ares_set_server_state_callback(
416 self.ares_channel,
417 Some(server_state_callback::<F>),
418 data,
419 );
420 }
421 self.server_state_callback = Some(boxed_callback);
422 self
423 }
424
425 #[cfg(cares1_34)]
428 pub fn set_pending_write_callback<F>(&mut self, callback: F) -> &mut Self
429 where
430 F: Fn() + Send + Sync + 'static,
431 {
432 let boxed_callback = Arc::new(callback);
433 let data = Arc::as_ptr(&boxed_callback).cast_mut().cast();
434 unsafe {
435 c_ares_sys::ares_set_pending_write_cb(
436 self.ares_channel,
437 Some(pending_write_callback::<F>),
438 data,
439 );
440 }
441 self.pending_write_callback = Some(boxed_callback);
442 self
443 }
444
445 pub fn query_a<F>(&mut self, name: &str, handler: F)
449 where
450 F: FnOnce(Result<AResults>) + Send + 'static,
451 {
452 self.do_query(name, handler);
453 }
454
455 pub fn search_a<F>(&mut self, name: &str, handler: F)
459 where
460 F: FnOnce(Result<AResults>) + Send + 'static,
461 {
462 self.do_search(name, handler);
463 }
464
465 pub fn query_aaaa<F>(&mut self, name: &str, handler: F)
469 where
470 F: FnOnce(Result<AAAAResults>) + Send + 'static,
471 {
472 self.do_query(name, handler);
473 }
474
475 pub fn search_aaaa<F>(&mut self, name: &str, handler: F)
480 where
481 F: FnOnce(Result<AAAAResults>) + Send + 'static,
482 {
483 self.do_search(name, handler);
484 }
485
486 pub fn query_caa<F>(&mut self, name: &str, handler: F)
490 where
491 F: FnOnce(Result<CAAResults>) + Send + 'static,
492 {
493 self.do_query(name, handler);
494 }
495
496 pub fn search_caa<F>(&mut self, name: &str, handler: F)
501 where
502 F: FnOnce(Result<CAAResults>) + Send + 'static,
503 {
504 self.do_search(name, handler);
505 }
506
507 pub fn query_cname<F>(&mut self, name: &str, handler: F)
511 where
512 F: FnOnce(Result<CNameResults>) + Send + 'static,
513 {
514 self.do_query(name, handler);
515 }
516
517 pub fn search_cname<F>(&mut self, name: &str, handler: F)
522 where
523 F: FnOnce(Result<CNameResults>) + Send + 'static,
524 {
525 self.do_search(name, handler);
526 }
527
528 pub fn query_mx<F>(&mut self, name: &str, handler: F)
532 where
533 F: FnOnce(Result<MXResults>) + Send + 'static,
534 {
535 self.do_query(name, handler);
536 }
537
538 pub fn search_mx<F>(&mut self, name: &str, handler: F)
542 where
543 F: FnOnce(Result<MXResults>) + Send + 'static,
544 {
545 self.do_search(name, handler);
546 }
547
548 pub fn query_naptr<F>(&mut self, name: &str, handler: F)
552 where
553 F: FnOnce(Result<NAPTRResults>) + Send + 'static,
554 {
555 self.do_query(name, handler);
556 }
557
558 pub fn search_naptr<F>(&mut self, name: &str, handler: F)
563 where
564 F: FnOnce(Result<NAPTRResults>) + Send + 'static,
565 {
566 self.do_search(name, handler);
567 }
568
569 pub fn query_ns<F>(&mut self, name: &str, handler: F)
573 where
574 F: FnOnce(Result<NSResults>) + Send + 'static,
575 {
576 self.do_query(name, handler);
577 }
578
579 pub fn search_ns<F>(&mut self, name: &str, handler: F)
583 where
584 F: FnOnce(Result<NSResults>) + Send + 'static,
585 {
586 self.do_search(name, handler);
587 }
588
589 pub fn query_ptr<F>(&mut self, name: &str, handler: F)
593 where
594 F: FnOnce(Result<PTRResults>) + Send + 'static,
595 {
596 self.do_query(name, handler);
597 }
598
599 pub fn search_ptr<F>(&mut self, name: &str, handler: F)
604 where
605 F: FnOnce(Result<PTRResults>) + Send + 'static,
606 {
607 self.do_search(name, handler);
608 }
609
610 pub fn query_soa<F>(&mut self, name: &str, handler: F)
614 where
615 F: FnOnce(Result<SOAResult>) + Send + 'static,
616 {
617 self.do_query(name, handler);
618 }
619
620 pub fn search_soa<F>(&mut self, name: &str, handler: F)
625 where
626 F: FnOnce(Result<SOAResult>) + Send + 'static,
627 {
628 self.do_search(name, handler);
629 }
630
631 pub fn query_srv<F>(&mut self, name: &str, handler: F)
635 where
636 F: FnOnce(Result<SRVResults>) + Send + 'static,
637 {
638 self.do_query(name, handler);
639 }
640
641 pub fn search_srv<F>(&mut self, name: &str, handler: F)
646 where
647 F: FnOnce(Result<SRVResults>) + Send + 'static,
648 {
649 self.do_search(name, handler);
650 }
651
652 pub fn query_txt<F>(&mut self, name: &str, handler: F)
656 where
657 F: FnOnce(Result<TXTResults>) + Send + 'static,
658 {
659 self.do_query(name, handler);
660 }
661
662 pub fn search_txt<F>(&mut self, name: &str, handler: F)
667 where
668 F: FnOnce(Result<TXTResults>) + Send + 'static,
669 {
670 self.do_search(name, handler);
671 }
672
673 pub fn query_uri<F>(&mut self, name: &str, handler: F)
677 where
678 F: FnOnce(Result<URIResults>) + Send + 'static,
679 {
680 self.do_query(name, handler);
681 }
682
683 pub fn search_uri<F>(&mut self, name: &str, handler: F)
688 where
689 F: FnOnce(Result<URIResults>) + Send + 'static,
690 {
691 self.do_search(name, handler);
692 }
693
694 fn do_query<R, F>(&mut self, name: &str, handler: F)
695 where
696 R: QueryRecord,
697 F: FnOnce(Result<R>) + Send + 'static,
698 {
699 ares_query!(
700 self.ares_channel,
701 name,
702 DnsClass::IN,
703 R::QUERY_TYPE,
704 query_callback::<R, F>,
705 handler
706 );
707 }
708
709 fn do_search<R, F>(&mut self, name: &str, handler: F)
710 where
711 R: QueryRecord,
712 F: FnOnce(Result<R>) + Send + 'static,
713 {
714 ares_search!(
715 self.ares_channel,
716 name,
717 DnsClass::IN,
718 R::QUERY_TYPE,
719 query_callback::<R, F>,
720 handler
721 );
722 }
723
724 #[allow(clippy::similar_names)]
730 pub fn get_host_by_address<F>(&mut self, address: &IpAddr, handler: F)
731 where
732 F: FnOnce(Result<&HostResults>) + Send + 'static,
733 {
734 let in_addr: c_types::in_addr;
735 let in6_addr: c_types::in6_addr;
736 let c_addr = match *address {
737 IpAddr::V4(v4) => {
738 in_addr = ipv4_as_in_addr(v4);
739 ptr::from_ref(&in_addr).cast()
740 }
741 IpAddr::V6(ref v6) => {
742 in6_addr = ipv6_as_in6_addr(v6);
743 ptr::from_ref(&in6_addr).cast()
744 }
745 };
746 let (family, length) = match *address {
747 IpAddr::V4(_) => (AddressFamily::INET, mem::size_of::<c_types::in_addr>()),
748 IpAddr::V6(_) => (AddressFamily::INET6, mem::size_of::<c_types::in6_addr>()),
749 };
750 let c_arg = Box::into_raw(Box::new(handler));
751 unsafe {
752 c_ares_sys::ares_gethostbyaddr(
753 self.ares_channel,
754 c_addr,
755 length as i32,
756 family as i32,
757 Some(get_host_callback::<F>),
758 c_arg.cast(),
759 );
760 }
761 }
762
763 pub fn get_host_by_name<F>(&mut self, name: &str, family: AddressFamily, handler: F)
767 where
768 F: FnOnce(Result<&HostResults>) + Send + 'static,
769 {
770 let Ok(c_name) = CString::new(name) else {
771 handler(Err(Error::EBADNAME));
772 return;
773 };
774 let c_arg = Box::into_raw(Box::new(handler));
775 unsafe {
776 c_ares_sys::ares_gethostbyname(
777 self.ares_channel,
778 c_name.as_ptr(),
779 family as i32,
780 Some(get_host_callback::<F>),
781 c_arg.cast(),
782 );
783 }
784 }
785
786 pub fn get_name_info<F>(&mut self, address: &SocketAddr, flags: NIFlags, handler: F)
792 where
793 F: FnOnce(Result<NameInfoResult>) + Send + 'static,
794 {
795 let sockaddr_in: c_types::sockaddr_in;
796 let sockaddr_in6: c_types::sockaddr_in6;
797 let c_addr = match *address {
798 SocketAddr::V4(ref v4) => {
799 sockaddr_in = socket_addrv4_as_sockaddr_in(v4);
800 ptr::from_ref(&sockaddr_in).cast()
801 }
802 SocketAddr::V6(ref v6) => {
803 sockaddr_in6 = socket_addrv6_as_sockaddr_in6(v6);
804 ptr::from_ref(&sockaddr_in6).cast()
805 }
806 };
807 let length = match *address {
808 SocketAddr::V4(_) => mem::size_of::<c_types::sockaddr_in>(),
809 SocketAddr::V6(_) => mem::size_of::<c_types::sockaddr_in6>(),
810 };
811 let c_arg = Box::into_raw(Box::new(handler));
812 unsafe {
813 c_ares_sys::ares_getnameinfo(
814 self.ares_channel,
815 c_addr,
816 length as c_ares_sys::ares_socklen_t,
817 flags.bits(),
818 Some(get_name_info_callback::<F>),
819 c_arg.cast(),
820 );
821 }
822 }
823
824 pub fn get_addrinfo<F>(
831 &mut self,
832 name: &str,
833 service: Option<&str>,
834 hints: &AddrInfoHints,
835 handler: F,
836 ) where
837 F: FnOnce(Result<AddrInfoResults>) + Send + 'static,
838 {
839 let Ok(c_name) = CString::new(name) else {
840 handler(Err(Error::EBADNAME));
841 return;
842 };
843 let Ok(c_service) = service.map(CString::new).transpose() else {
844 handler(Err(Error::EBADNAME));
845 return;
846 };
847 let c_hints: c_ares_sys::ares_addrinfo_hints = hints.into();
848 let c_arg = Box::into_raw(Box::new(handler));
849 unsafe {
850 c_ares_sys::ares_getaddrinfo(
851 self.ares_channel,
852 c_name.as_ptr(),
853 c_service.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
854 &raw const c_hints,
855 Some(get_addrinfo_callback::<F>),
856 c_arg.cast(),
857 );
858 }
859 }
860
861 pub fn query<F>(&mut self, name: &str, dns_class: u16, query_type: u16, handler: F)
870 where
871 F: FnOnce(Result<&[u8]>) + Send + 'static,
872 {
873 ares_query!(
874 self.ares_channel,
875 name,
876 c_int::from(dns_class),
877 c_int::from(query_type),
878 raw_query_callback::<F>,
879 handler
880 );
881 }
882
883 pub fn search<F>(&mut self, name: &str, dns_class: u16, query_type: u16, handler: F)
892 where
893 F: FnOnce(Result<&[u8]>) + Send + 'static,
894 {
895 ares_search!(
896 self.ares_channel,
897 name,
898 c_int::from(dns_class),
899 c_int::from(query_type),
900 raw_query_callback::<F>,
901 handler
902 );
903 }
904
905 #[cfg(cares1_28)]
931 pub fn send_dnsrec<F>(&mut self, dnsrec: &DnsRecord, handler: F) -> Result<u16>
932 where
933 F: FnOnce(Result<&DnsRecord>) + Send + 'static,
934 {
935 let mut qid: u16 = 0;
936 let c_arg = Box::into_raw(Box::new(handler));
937 let status = unsafe {
938 c_ares_sys::ares_send_dnsrec(
939 self.ares_channel,
940 dnsrec.as_raw(),
941 Some(dnsrec_callback::<F>),
942 c_arg.cast(),
943 &raw mut qid,
944 )
945 };
946
947 status_to_result(status)?;
948 Ok(qid)
949 }
950
951 #[cfg(cares1_28)]
978 pub fn query_dnsrec<F>(
979 &mut self,
980 name: &str,
981 dns_class: DnsCls,
982 query_type: DnsRecordType,
983 handler: F,
984 ) -> Result<u16>
985 where
986 F: FnOnce(Result<&DnsRecord>) + Send + 'static,
987 {
988 let c_name = CString::new(name).map_err(|_| Error::EBADNAME)?;
989 let mut qid: u16 = 0;
990 let c_arg = Box::into_raw(Box::new(handler));
991 let status = unsafe {
992 c_ares_sys::ares_query_dnsrec(
993 self.ares_channel,
994 c_name.as_ptr(),
995 dns_class.into(),
996 query_type.into(),
997 Some(dnsrec_callback::<F>),
998 c_arg.cast(),
999 &raw mut qid,
1000 )
1001 };
1002
1003 status_to_result(status)?;
1004 Ok(qid)
1005 }
1006
1007 #[cfg(cares1_28)]
1029 pub fn search_dnsrec<F>(&mut self, dnsrec: &DnsRecord, handler: F) -> Result<()>
1030 where
1031 F: FnOnce(Result<&DnsRecord>) + Send + 'static,
1032 {
1033 let c_arg = Box::into_raw(Box::new(handler));
1034 let status = unsafe {
1035 c_ares_sys::ares_search_dnsrec(
1036 self.ares_channel,
1037 dnsrec.as_raw(),
1038 Some(dnsrec_callback::<F>),
1039 c_arg.cast(),
1040 )
1041 };
1042
1043 status_to_result(status)
1044 }
1045
1046 pub fn cancel(&mut self) {
1051 unsafe { c_ares_sys::ares_cancel(self.ares_channel) }
1052 }
1053
1054 #[cfg(cares1_34)]
1056 pub fn process_pending_write(&mut self) {
1057 unsafe { c_ares_sys::ares_process_pending_write(self.ares_channel) }
1058 }
1059
1060 pub fn timeout(&self, max_timeout: Option<Duration>) -> Option<Duration> {
1066 let mut maxtv;
1067 let maxtv_ptr = match max_timeout {
1068 Some(d) => {
1069 maxtv = c_ares_sys::timeval {
1070 tv_sec: d.as_secs() as _,
1071 #[allow(clippy::cast_lossless, clippy::cast_possible_wrap)]
1074 tv_usec: d.subsec_micros() as _,
1075 };
1076 &mut maxtv
1077 }
1078 None => ptr::null_mut(),
1079 };
1080 let mut tv = c_ares_sys::timeval {
1081 tv_sec: 0,
1082 tv_usec: 0,
1083 };
1084 let result = unsafe { c_ares_sys::ares_timeout(self.ares_channel, maxtv_ptr, &raw mut tv) };
1085 unsafe { result.as_ref() }
1086 .map(|tv| Duration::new(tv.tv_sec as u64, (tv.tv_usec as u32) * 1000))
1087 }
1088
1089 #[cfg(cares1_27)]
1094 pub fn queue_wait_empty(&self, timeout: Option<Duration>) -> Result<()> {
1095 let timeout_ms = match timeout {
1096 None => -1,
1097 Some(d) => d.as_millis().try_into().unwrap_or(c_int::MAX),
1098 };
1099 let rc = unsafe { c_ares_sys::ares_queue_wait_empty(self.ares_channel, timeout_ms) };
1100 status_to_result(rc)
1101 }
1102
1103 #[cfg(cares1_27)]
1109 pub fn queue_active_queries(&self) -> usize {
1110 unsafe { c_ares_sys::ares_queue_active_queries(self.ares_channel) }
1111 }
1112}
1113
1114impl Drop for Channel {
1115 fn drop(&mut self) {
1116 unsafe { c_ares_sys::ares_destroy(self.ares_channel) }
1117 {
1118 let _lock = ARES_LIBRARY_LOCK.lock().unwrap();
1119 unsafe { c_ares_sys::ares_library_cleanup() }
1120 }
1121 }
1122}
1123
1124unsafe impl Send for Channel {}
1125unsafe impl Sync for Channel {}
1126
1127impl fmt::Debug for Channel {
1128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1129 f.debug_struct("Channel").finish_non_exhaustive()
1130 }
1131}
1132
1133unsafe extern "C" fn socket_state_callback<F>(
1134 data: *mut c_void,
1135 socket_fd: c_ares_sys::ares_socket_t,
1136 readable: c_int,
1137 writable: c_int,
1138) where
1139 F: Fn(Socket, bool, bool) + Send + Sync + 'static,
1140{
1141 let handler = data.cast::<F>();
1142 let handler = unsafe { &*handler };
1143 panic::abort_on_panic(|| handler(socket_fd, readable != 0, writable != 0));
1144}
1145
1146#[cfg(cares1_29)]
1147unsafe extern "C" fn server_state_callback<F>(
1148 server_string: *const c_char,
1149 success: c_ares_sys::ares_bool_t,
1150 flags: c_int,
1151 data: *mut c_void,
1152) where
1153 F: Fn(&str, bool, ServerStateFlags) + Send + Sync + 'static,
1154{
1155 let handler = data.cast::<F>();
1156 let handler = unsafe { &*handler };
1157 let server = unsafe { c_string_as_str_unchecked(server_string) };
1158 panic::abort_on_panic(|| {
1159 handler(
1160 server,
1161 success != c_ares_sys::ares_bool_t::ARES_FALSE,
1162 ServerStateFlags::from_bits_truncate(flags),
1163 );
1164 });
1165}
1166
1167#[cfg(cares1_34)]
1168unsafe extern "C" fn pending_write_callback<F>(data: *mut c_void)
1169where
1170 F: Fn() + Send + Sync + 'static,
1171{
1172 let handler = data.cast::<F>();
1173 let handler = unsafe { &*handler };
1174 panic::abort_on_panic(handler);
1175}
1176
1177#[cfg(test)]
1178mod tests {
1179 use super::*;
1180 use std::net::{Ipv4Addr, Ipv6Addr};
1181
1182 #[test]
1183 fn channel_new_default() {
1184 let channel = Channel::new();
1185 assert!(channel.is_ok());
1186 }
1187
1188 #[test]
1189 fn channel_with_options() {
1190 let mut options = Options::new();
1191 options.set_flags(crate::Flags::STAYOPEN).set_tries(2);
1192 let channel = Channel::with_options(options);
1193 assert!(channel.is_ok());
1194 }
1195
1196 #[test]
1197 fn channel_set_servers_empty() {
1198 let mut channel = Channel::new().unwrap();
1199 let result = channel.set_servers(Vec::<&str>::new());
1200 assert!(result.is_ok());
1201 }
1202
1203 #[test]
1204 fn channel_set_servers_ipv4() {
1205 let mut channel = Channel::new().unwrap();
1206 let result = channel.set_servers(["8.8.8.8", "8.8.4.4"]);
1207 assert!(result.is_ok());
1208 }
1209
1210 #[test]
1211 fn channel_set_servers_ipv6() {
1212 let mut channel = Channel::new().unwrap();
1213 let result = channel.set_servers(["[2001:4860:4860::8888]"]);
1214 assert!(result.is_ok());
1215 }
1216
1217 #[test]
1218 fn channel_set_servers_with_port() {
1219 let mut channel = Channel::new().unwrap();
1220 let result = channel.set_servers(["8.8.8.8:53", "[2001:4860:4860::8888]:53"]);
1221 assert!(result.is_ok());
1222 }
1223
1224 #[test]
1225 fn channel_sockets() {
1226 let channel = Channel::new().unwrap();
1227 let sockets = channel.sockets();
1228 assert_eq!(sockets.iter().count(), 0);
1229 }
1230
1231 #[test]
1232 fn channel_cancel() {
1233 let mut channel = Channel::new().unwrap();
1234 channel.cancel();
1235 }
1236
1237 #[test]
1238 fn channel_process_fd_none() {
1239 let mut channel = Channel::new().unwrap();
1240 channel.process_fd(None, None);
1241 }
1242
1243 #[test]
1244 fn channel_try_clone() {
1245 let channel = Channel::new().unwrap();
1246 let cloned = channel.try_clone();
1247 assert!(cloned.is_ok());
1248 }
1249
1250 #[test]
1251 fn channel_set_local_ipv4() {
1252 let mut channel = Channel::new().unwrap();
1253 channel.set_local_ipv4(Ipv4Addr::UNSPECIFIED);
1254 }
1255
1256 #[test]
1257 fn channel_set_local_ipv6() {
1258 let mut channel = Channel::new().unwrap();
1259 channel.set_local_ipv6(Ipv6Addr::UNSPECIFIED);
1260 }
1261
1262 #[test]
1263 fn channel_set_local_device() {
1264 let mut channel = Channel::new().unwrap();
1265 channel.set_local_device("lo").unwrap();
1266 }
1267
1268 #[test]
1269 fn channel_set_sortlist() {
1270 let mut channel = Channel::new().unwrap();
1271 let result = channel.set_sortlist(["130.155.160.0/255.255.240.0", "130.155.0.0"]);
1272 assert!(result.is_ok());
1273 }
1274
1275 #[cfg(cares1_24)]
1276 #[test]
1277 fn parse_servers_csv_null_is_empty() {
1278 assert!(Channel::parse_servers_csv(std::ptr::null_mut()).is_empty());
1281 }
1282
1283 #[cfg(cares1_24)]
1284 #[test]
1285 fn channel_servers_round_trip() {
1286 let mut channel = Channel::new().unwrap();
1287 channel.set_servers(["8.8.8.8:53"]).unwrap();
1288 let servers = channel.servers();
1289 assert!(servers.iter().any(|s| s.contains("8.8.8.8")));
1290 }
1291
1292 #[test]
1293 fn channel_set_servers_owned_strings() {
1294 let mut channel = Channel::new().unwrap();
1295 let servers: Vec<String> = vec!["8.8.8.8".into(), "8.8.4.4".into()];
1296 channel.set_servers(servers).unwrap();
1297 }
1298
1299 #[test]
1300 fn channel_set_sortlist_owned_strings() {
1301 let mut channel = Channel::new().unwrap();
1302 let sortlist: Vec<String> = vec!["130.155.0.0".into()];
1303 channel.set_sortlist(sortlist).unwrap();
1304 }
1305
1306 #[cfg(cares1_22)]
1307 #[test]
1308 fn channel_reinit() {
1309 let mut channel = Channel::new().unwrap();
1310 let result = channel.reinit();
1311 assert!(result.is_ok());
1312 }
1313
1314 #[cfg(cares1_24)]
1315 #[test]
1316 fn channel_servers() {
1317 let mut channel = Channel::new().unwrap();
1318 channel.set_servers(["8.8.8.8"]).unwrap();
1319 let servers = channel.servers();
1320 assert!(!servers.is_empty());
1321 }
1322
1323 #[cfg(cares1_24)]
1324 #[test]
1325 fn channel_servers_empty() {
1326 let mut channel = Channel::new().unwrap();
1327 channel.set_servers(Vec::<&str>::new()).unwrap();
1328 let servers = channel.servers();
1329 assert!(servers.is_empty());
1330 }
1331
1332 #[cfg(cares1_34)]
1333 #[test]
1334 fn channel_process_fds_empty() {
1335 use crate::ProcessFlags;
1336 let mut channel = Channel::new().unwrap();
1337 let result = channel.process_fds(&[], ProcessFlags::empty());
1338 assert!(result.is_ok());
1339 }
1340
1341 #[cfg(cares1_34)]
1342 #[test]
1343 fn channel_process_pending_write() {
1344 let mut channel = Channel::new().unwrap();
1345 channel.process_pending_write();
1346 }
1347
1348 #[cfg(cares1_28)]
1349 #[test]
1350 fn query_dnsrec_rejects_nul_in_name_with_ebadname() {
1351 let mut channel = Channel::new().unwrap();
1352 let result = channel.query_dnsrec("ex\0ample.com", DnsCls::IN, DnsRecordType::A, |_| {});
1353 assert_eq!(result, Err(Error::EBADNAME));
1354 }
1355
1356 #[test]
1357 fn channel_is_send() {
1358 fn assert_send<T: Send>() {}
1359 assert_send::<Channel>();
1360 }
1361
1362 #[test]
1363 fn channel_is_sync() {
1364 fn assert_sync<T: Sync>() {}
1365 assert_sync::<Channel>();
1366 }
1367
1368 #[test]
1369 fn channel_fds() {
1370 use std::mem::MaybeUninit;
1371 let channel = Channel::new().unwrap();
1372 unsafe {
1373 let mut read_fds: c_types::fd_set = MaybeUninit::zeroed().assume_init();
1374 let mut write_fds: c_types::fd_set = MaybeUninit::zeroed().assume_init();
1375 let nfds = channel.fds(&mut read_fds, &mut write_fds);
1376 assert_eq!(nfds, 0);
1378 }
1379 }
1380
1381 #[test]
1382 fn set_servers_invalid() {
1383 let mut channel = Channel::new().unwrap();
1384 let result = channel.set_servers(["not-a-valid-ip"]);
1386 assert!(result.is_err());
1387 }
1388
1389 #[test]
1390 fn set_sortlist_invalid() {
1391 let mut channel = Channel::new().unwrap();
1392 let result = channel.set_sortlist(["not-a-valid-address"]);
1394 assert!(result.is_err());
1396 }
1397
1398 #[cfg(cares1_29)]
1399 #[test]
1400 fn channel_set_server_state_callback() {
1401 use crate::ServerStateFlags;
1402 let mut channel = Channel::new().unwrap();
1403 channel.set_server_state_callback(
1404 |_server: &str, _success: bool, _flags: ServerStateFlags| {
1405 },
1407 );
1408 }
1409
1410 #[cfg(cares1_34)]
1411 #[test]
1412 fn channel_set_pending_write_callback() {
1413 let mut channel = Channel::new().unwrap();
1414 channel.set_pending_write_callback(|| {
1415 });
1417 }
1418
1419 #[test]
1420 fn channel_process() {
1421 use std::mem::MaybeUninit;
1422 let mut channel = Channel::new().unwrap();
1423 unsafe {
1424 let mut read_fds: c_types::fd_set = MaybeUninit::zeroed().assume_init();
1425 let mut write_fds: c_types::fd_set = MaybeUninit::zeroed().assume_init();
1426 channel.process(&mut read_fds, &mut write_fds);
1427 }
1428 }
1429
1430 #[cfg(cares1_27)]
1431 #[test]
1432 fn channel_queue_active_queries() {
1433 let channel = Channel::new().unwrap();
1434 assert_eq!(channel.queue_active_queries(), 0);
1435 }
1436
1437 #[cfg(cares1_27)]
1438 #[test]
1439 fn channel_queue_wait_empty() {
1440 let channel = Channel::new().unwrap();
1441 let result = channel.queue_wait_empty(Some(Duration::ZERO));
1444 assert!(result.is_ok() || result == Err(Error::ENOTIMP));
1445 }
1446
1447 #[cfg(cares1_27)]
1448 #[test]
1449 fn channel_queue_wait_empty_none_timeout() {
1450 let channel = Channel::new().unwrap();
1451 let result = channel.queue_wait_empty(None);
1453 assert!(result.is_ok() || result == Err(Error::ENOTIMP));
1454 }
1455
1456 #[test]
1457 fn debug_channel() {
1458 let channel = Channel::new().unwrap();
1459 let debug = format!("{channel:?}");
1460 assert!(debug.contains("Channel"));
1461 }
1462
1463 #[test]
1464 fn timeout_no_queries_with_max() {
1465 let channel = Channel::new().unwrap();
1466 let max = Duration::from_secs(5);
1468 let result = channel.timeout(Some(max));
1469 assert_eq!(result, Some(max));
1470 }
1471
1472 #[test]
1473 fn timeout_no_queries_without_max() {
1474 let channel = Channel::new().unwrap();
1475 let result = channel.timeout(None);
1477 assert_eq!(result, None);
1478 }
1479}