1use std::fmt;
2use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
3
4use crate::error::Error;
5use crate::host::HostResults;
6use crate::nameinfo::NameInfoResult;
7use crate::resolver::{Options, Resolver};
8
9#[cfg(cares1_29)]
10use c_ares::ServerStateFlags;
11
12use std::sync::mpsc;
13
14pub struct BlockingResolver {
23 inner: Resolver,
24}
25
26impl fmt::Debug for BlockingResolver {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 f.debug_struct("BlockingResolver").finish_non_exhaustive()
29 }
30}
31
32macro_rules! blockify {
35 ($resolver:expr, $query:ident, $($arg:expr),+ $(,)?) => {{
36 let (tx, rx) = mpsc::sync_channel(1);
37 $resolver.$query($($arg,)+ move |result| {
38 let _ = tx.send(result);
39 });
40 rx.recv().unwrap()
41 }};
42}
43
44impl BlockingResolver {
45 pub fn new() -> Result<Self, Error> {
61 let options = Options::default();
62 Self::with_options(options)
63 }
64
65 pub fn with_options(options: Options) -> Result<Self, Error> {
67 let inner = Resolver::with_options(options)?;
68 let resolver = Self { inner };
69 Ok(resolver)
70 }
71
72 #[cfg(cares1_22)]
74 pub fn reinit(&self) -> c_ares::Result<&Self> {
75 self.inner.reinit()?;
76 Ok(self)
77 }
78
79 pub fn set_servers<I, S>(&self, servers: I) -> c_ares::Result<&Self>
85 where
86 I: IntoIterator<Item = S>,
87 S: AsRef<str>,
88 {
89 self.inner.set_servers(servers)?;
90 Ok(self)
91 }
92
93 #[cfg(cares1_24)]
98 pub fn servers(&self) -> Vec<String> {
99 self.inner.servers()
100 }
101
102 pub fn set_local_ipv4(&self, ipv4: Ipv4Addr) -> &Self {
104 self.inner.set_local_ipv4(ipv4);
105 self
106 }
107
108 pub fn set_local_ipv6(&self, ipv6: Ipv6Addr) -> &Self {
110 self.inner.set_local_ipv6(ipv6);
111 self
112 }
113
114 pub fn set_local_device(&self, device: &str) -> c_ares::Result<&Self> {
116 self.inner.set_local_device(device)?;
117 Ok(self)
118 }
119
120 pub fn set_sortlist<I, S>(&self, sortlist: I) -> c_ares::Result<&Self>
127 where
128 I: IntoIterator<Item = S>,
129 S: AsRef<str>,
130 {
131 self.inner.set_sortlist(sortlist)?;
132 Ok(self)
133 }
134
135 #[cfg(cares1_29)]
143 pub fn set_server_state_callback<F>(&self, callback: F) -> &Self
144 where
145 F: Fn(&str, bool, ServerStateFlags) + Send + Sync + 'static,
146 {
147 self.inner.set_server_state_callback(callback);
148 self
149 }
150
151 pub fn query_a(&self, name: &str) -> c_ares::Result<c_ares::AResults> {
153 blockify!(self.inner, query_a, name)
154 }
155
156 pub fn search_a(&self, name: &str) -> c_ares::Result<c_ares::AResults> {
158 blockify!(self.inner, search_a, name)
159 }
160
161 pub fn query_aaaa(&self, name: &str) -> c_ares::Result<c_ares::AAAAResults> {
163 blockify!(self.inner, query_aaaa, name)
164 }
165
166 pub fn search_aaaa(&self, name: &str) -> c_ares::Result<c_ares::AAAAResults> {
168 blockify!(self.inner, search_aaaa, name)
169 }
170
171 pub fn query_caa(&self, name: &str) -> c_ares::Result<c_ares::CAAResults> {
173 blockify!(self.inner, query_caa, name)
174 }
175
176 pub fn search_caa(&self, name: &str) -> c_ares::Result<c_ares::CAAResults> {
178 blockify!(self.inner, search_caa, name)
179 }
180
181 pub fn query_cname(&self, name: &str) -> c_ares::Result<c_ares::CNameResults> {
183 blockify!(self.inner, query_cname, name)
184 }
185
186 pub fn search_cname(&self, name: &str) -> c_ares::Result<c_ares::CNameResults> {
188 blockify!(self.inner, search_cname, name)
189 }
190
191 pub fn query_mx(&self, name: &str) -> c_ares::Result<c_ares::MXResults> {
193 blockify!(self.inner, query_mx, name)
194 }
195
196 pub fn search_mx(&self, name: &str) -> c_ares::Result<c_ares::MXResults> {
198 blockify!(self.inner, search_mx, name)
199 }
200
201 pub fn query_naptr(&self, name: &str) -> c_ares::Result<c_ares::NAPTRResults> {
203 blockify!(self.inner, query_naptr, name)
204 }
205
206 pub fn search_naptr(&self, name: &str) -> c_ares::Result<c_ares::NAPTRResults> {
208 blockify!(self.inner, search_naptr, name)
209 }
210
211 pub fn query_ns(&self, name: &str) -> c_ares::Result<c_ares::NSResults> {
213 blockify!(self.inner, query_ns, name)
214 }
215
216 pub fn search_ns(&self, name: &str) -> c_ares::Result<c_ares::NSResults> {
218 blockify!(self.inner, search_ns, name)
219 }
220
221 pub fn query_ptr(&self, name: &str) -> c_ares::Result<c_ares::PTRResults> {
223 blockify!(self.inner, query_ptr, name)
224 }
225
226 pub fn search_ptr(&self, name: &str) -> c_ares::Result<c_ares::PTRResults> {
228 blockify!(self.inner, search_ptr, name)
229 }
230
231 pub fn query_soa(&self, name: &str) -> c_ares::Result<c_ares::SOAResult> {
233 blockify!(self.inner, query_soa, name)
234 }
235
236 pub fn search_soa(&self, name: &str) -> c_ares::Result<c_ares::SOAResult> {
238 blockify!(self.inner, search_soa, name)
239 }
240
241 pub fn query_srv(&self, name: &str) -> c_ares::Result<c_ares::SRVResults> {
243 blockify!(self.inner, query_srv, name)
244 }
245
246 pub fn search_srv(&self, name: &str) -> c_ares::Result<c_ares::SRVResults> {
248 blockify!(self.inner, search_srv, name)
249 }
250
251 pub fn query_txt(&self, name: &str) -> c_ares::Result<c_ares::TXTResults> {
253 blockify!(self.inner, query_txt, name)
254 }
255
256 pub fn search_txt(&self, name: &str) -> c_ares::Result<c_ares::TXTResults> {
258 blockify!(self.inner, search_txt, name)
259 }
260
261 pub fn query_uri(&self, name: &str) -> c_ares::Result<c_ares::URIResults> {
263 blockify!(self.inner, query_uri, name)
264 }
265
266 pub fn search_uri(&self, name: &str) -> c_ares::Result<c_ares::URIResults> {
268 blockify!(self.inner, search_uri, name)
269 }
270
271 pub fn get_host_by_address(&self, address: &IpAddr) -> c_ares::Result<HostResults> {
273 let (tx, rx) = mpsc::sync_channel(1);
274 self.inner.get_host_by_address(address, move |result| {
275 let _ = tx.send(result.map(Into::into));
276 });
277 rx.recv().unwrap()
278 }
279
280 pub fn get_host_by_name(
282 &self,
283 name: &str,
284 family: c_ares::AddressFamily,
285 ) -> c_ares::Result<HostResults> {
286 let (tx, rx) = mpsc::sync_channel(1);
287 self.inner.get_host_by_name(name, family, move |result| {
288 let _ = tx.send(result.map(Into::into));
289 });
290 rx.recv().unwrap()
291 }
292
293 pub fn get_name_info(
295 &self,
296 address: &SocketAddr,
297 flags: c_ares::NIFlags,
298 ) -> c_ares::Result<NameInfoResult> {
299 let (tx, rx) = mpsc::sync_channel(1);
300 self.inner.get_name_info(address, flags, move |result| {
301 let _ = tx.send(result.map(Into::into));
302 });
303 rx.recv().unwrap()
304 }
305
306 pub fn get_addrinfo(
308 &self,
309 name: &str,
310 service: Option<&str>,
311 hints: &c_ares::AddrInfoHints,
312 ) -> c_ares::Result<c_ares::AddrInfoResults> {
313 blockify!(self.inner, get_addrinfo, name, service, hints)
314 }
315
316 pub fn query(&self, name: &str, dns_class: u16, query_type: u16) -> c_ares::Result<Vec<u8>> {
323 let (tx, rx) = mpsc::sync_channel(1);
324 self.inner
325 .query(name, dns_class, query_type, move |result| {
326 let _ = tx.send(result.map(std::borrow::ToOwned::to_owned));
327 });
328 rx.recv().unwrap()
329 }
330
331 pub fn search(&self, name: &str, dns_class: u16, query_type: u16) -> c_ares::Result<Vec<u8>> {
338 let (tx, rx) = mpsc::sync_channel(1);
339 self.inner
340 .search(name, dns_class, query_type, move |result| {
341 let _ = tx.send(result.map(std::borrow::ToOwned::to_owned));
342 });
343 rx.recv().unwrap()
344 }
345
346 #[cfg(cares1_28)]
364 pub fn send_dnsrec(&self, dnsrec: &c_ares::DnsRecord) -> c_ares::Result<c_ares::DnsRecord> {
365 let (tx, rx) = mpsc::sync_channel(1);
366 self.inner.send_dnsrec(dnsrec, move |result| {
367 let _ = tx.send(result.and_then(c_ares::DnsRecord::try_clone));
368 })?;
369 rx.recv().unwrap()
370 }
371
372 #[cfg(cares1_28)]
391 pub fn query_dnsrec(
392 &self,
393 name: &str,
394 dns_class: c_ares::DnsCls,
395 query_type: c_ares::DnsRecordType,
396 ) -> c_ares::Result<c_ares::DnsRecord> {
397 let (tx, rx) = mpsc::sync_channel(1);
398 self.inner
399 .query_dnsrec(name, dns_class, query_type, move |result| {
400 let _ = tx.send(result.and_then(c_ares::DnsRecord::try_clone));
401 })?;
402 rx.recv().unwrap()
403 }
404
405 #[cfg(cares1_28)]
424 pub fn search_dnsrec(&self, dnsrec: &c_ares::DnsRecord) -> c_ares::Result<c_ares::DnsRecord> {
425 let (tx, rx) = mpsc::sync_channel(1);
426 self.inner.search_dnsrec(dnsrec, move |result| {
427 let _ = tx.send(result.and_then(c_ares::DnsRecord::try_clone));
428 })?;
429 rx.recv().unwrap()
430 }
431
432 #[cfg(cares1_27)]
437 pub fn queue_wait_empty(&self, timeout: Option<std::time::Duration>) -> c_ares::Result<()> {
438 self.inner.queue_wait_empty(timeout)
439 }
440
441 #[cfg(cares1_27)]
443 pub fn queue_active_queries(&self) -> usize {
444 self.inner.queue_active_queries()
445 }
446}
447
448#[cfg(test)]
449mod tests {
450 use super::*;
451 use std::time::Duration;
452
453 fn assert_send<T: Send>() {}
454 fn assert_sync<T: Sync>() {}
455
456 #[test]
457 fn blocking_resolver_is_send() {
458 assert_send::<BlockingResolver>();
459 }
460
461 #[test]
462 fn blocking_resolver_is_sync() {
463 assert_sync::<BlockingResolver>();
464 }
465
466 #[test]
467 fn blocking_resolver_new() {
468 let resolver = BlockingResolver::new();
469 assert!(resolver.is_ok());
470 }
471
472 #[test]
473 fn blocking_resolver_with_options() {
474 let options = Options::new();
475 let resolver = BlockingResolver::with_options(options);
476 assert!(resolver.is_ok());
477 }
478
479 #[test]
480 fn blocking_resolver_with_custom_options() {
481 let mut options = Options::new();
482 options.set_timeout(Duration::from_secs(2)).set_tries(2);
483 let resolver = BlockingResolver::with_options(options);
484 assert!(resolver.is_ok());
485 }
486
487 #[test]
488 fn blocking_resolver_set_local_ipv4() {
489 let resolver = BlockingResolver::new().unwrap();
490 let result = resolver.set_local_ipv4(Ipv4Addr::LOCALHOST);
491 assert!(std::ptr::eq(result, &raw const resolver));
492 }
493
494 #[test]
495 fn blocking_resolver_set_local_ipv6() {
496 let resolver = BlockingResolver::new().unwrap();
497 let ipv6 = Ipv6Addr::LOCALHOST;
498 let result = resolver.set_local_ipv6(ipv6);
499 assert!(std::ptr::eq(result, &raw const resolver));
500 }
501
502 #[test]
503 fn blocking_resolver_set_local_device() {
504 let resolver = BlockingResolver::new().unwrap();
505 let result = resolver.set_local_device("lo").unwrap();
506 assert!(std::ptr::eq(result, &raw const resolver));
507 }
508
509 #[test]
510 fn blocking_resolver_set_servers_valid() {
511 let resolver = BlockingResolver::new().unwrap();
512 let result = resolver.set_servers(["8.8.8.8", "8.8.4.4"]);
513 assert!(result.is_ok());
514 }
515
516 #[test]
517 fn blocking_resolver_set_sortlist_valid() {
518 let resolver = BlockingResolver::new().unwrap();
519 let result = resolver.set_sortlist(["130.155.160.0/255.255.240.0"]);
520 assert!(result.is_ok());
521 }
522
523 #[test]
524 #[cfg(cares1_22)]
525 fn blocking_resolver_reinit() {
526 let resolver = BlockingResolver::new().unwrap();
527 let result = resolver.reinit();
528 assert!(result.is_ok());
529 }
530
531 #[test]
532 #[cfg(cares1_24)]
533 fn blocking_resolver_servers() {
534 let resolver = BlockingResolver::new().unwrap();
535 let _ = resolver.set_servers(["8.8.8.8"]);
536 let servers = resolver.servers();
537 assert!(!servers.is_empty());
538 }
539
540 #[test]
541 #[cfg(cares1_27)]
542 fn blocking_resolver_queue_active_queries() {
543 let resolver = BlockingResolver::new().unwrap();
544 assert_eq!(resolver.queue_active_queries(), 0);
545 }
546
547 #[test]
548 #[cfg(cares1_27)]
549 fn blocking_resolver_queue_wait_empty() {
550 let resolver = BlockingResolver::new().unwrap();
551 let result = resolver.queue_wait_empty(Some(std::time::Duration::ZERO));
552 assert!(result.is_ok() || result == Err(c_ares::Error::ENOTIMP));
553 }
554
555 #[test]
556 #[cfg(cares1_29)]
557 fn blocking_resolver_set_server_state_callback() {
558 let resolver = BlockingResolver::new().unwrap();
559 let result = resolver.set_server_state_callback(|_server, _success, _flags| {});
560 assert!(std::ptr::eq(result, &raw const resolver));
561 }
562
563 #[test]
564 fn debug_blocking_resolver() {
565 let resolver = BlockingResolver::new().unwrap();
566 let debug = format!("{resolver:?}");
567 assert!(debug.contains("BlockingResolver"));
568 }
569}