1use std::fmt;
2use std::os::raw::{c_int, c_uchar, c_void};
3use std::ptr;
4use std::slice;
5
6use itertools::Itertools;
7
8use crate::error::{Error, Result};
9use crate::hostent::{HasHostent, HostAliasResultsIter, HostentOwned};
10use crate::panic;
11
12#[derive(Debug)]
14pub struct PTRResults {
15 hostent: HostentOwned,
16}
17
18impl PTRResults {
19 pub fn parse_from(data: &[u8]) -> Result<PTRResults> {
21 let mut hostent: *mut c_types::hostent = ptr::null_mut();
22 let dummy_ip = [0, 0, 0, 0];
23 let parse_status = unsafe {
24 #[allow(clippy::useless_conversion)]
25 c_ares_sys::ares_parse_ptr_reply(
26 data.as_ptr(),
27 data.len() as c_int,
28 dummy_ip.as_ptr().cast(),
29 dummy_ip.len() as c_int,
30 c_types::AF_INET.into(),
31 &mut hostent,
32 )
33 };
34 if parse_status == c_ares_sys::ares_status_t::ARES_SUCCESS as i32 {
35 let result = PTRResults::new(hostent);
36 Ok(result)
37 } else {
38 Err(Error::from(parse_status))
39 }
40 }
41
42 fn new(hostent: *mut c_types::hostent) -> Self {
43 PTRResults {
44 hostent: HostentOwned::new(hostent),
45 }
46 }
47
48 pub fn hostname(&self) -> &str {
50 self.hostent.hostname()
51 }
52
53 pub fn aliases(&self) -> HostAliasResultsIter {
55 self.hostent.aliases()
56 }
57}
58
59impl fmt::Display for PTRResults {
60 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
61 write!(fmt, "Hostname: {}, ", self.hostname())?;
62 let aliases = self.aliases().format(", ");
63 write!(fmt, "Aliases: [{aliases}]")
64 }
65}
66
67pub(crate) unsafe extern "C" fn query_ptr_callback<F>(
68 arg: *mut c_void,
69 status: c_int,
70 _timeouts: c_int,
71 abuf: *mut c_uchar,
72 alen: c_int,
73) where
74 F: FnOnce(Result<PTRResults>) + Send + 'static,
75{
76 ares_callback!(arg.cast::<F>(), status, abuf, alen, PTRResults::parse_from);
77}