c_ares/
hostent.rs

1use std::marker::PhantomData;
2use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
3use std::os::raw::c_char;
4use std::{fmt, ptr, slice};
5
6use itertools::Itertools;
7
8use crate::types::AddressFamily;
9use crate::utils::{address_family, hostname_as_str};
10
11fn hostname(hostent: &c_types::hostent) -> &str {
12    unsafe { hostname_as_str(hostent.h_name.cast()) }
13}
14
15fn addresses(hostent: &c_types::hostent) -> HostAddressResultsIter {
16    let addrtype = hostent.h_addrtype as c_types::ADDRESS_FAMILY;
17    HostAddressResultsIter {
18        family: address_family(addrtype),
19        next: unsafe { &*(hostent.h_addr_list.cast()) },
20    }
21}
22
23fn aliases(hostent: &c_types::hostent) -> HostAliasResultsIter {
24    HostAliasResultsIter {
25        next: unsafe { &*(hostent.h_aliases.cast()) },
26    }
27}
28
29fn display(hostent: &c_types::hostent, fmt: &mut fmt::Formatter) -> fmt::Result {
30    write!(fmt, "Hostname: {}, ", hostname(hostent))?;
31    let addresses = addresses(hostent).format(", ");
32    write!(fmt, "Addresses: [{addresses}], ")?;
33    let aliases = aliases(hostent).format(", ");
34    write!(fmt, "Aliases: [{aliases}]")
35}
36
37pub trait HasHostent<'a>: Sized {
38    fn hostent(self) -> &'a c_types::hostent;
39
40    fn hostname(self) -> &'a str {
41        let hostent = self.hostent();
42        hostname(hostent)
43    }
44
45    fn addresses(self) -> HostAddressResultsIter<'a> {
46        let hostent = self.hostent();
47        addresses(hostent)
48    }
49
50    fn aliases(self) -> HostAliasResultsIter<'a> {
51        let hostent = self.hostent();
52        aliases(hostent)
53    }
54}
55
56#[derive(Debug)]
57pub struct HostentOwned {
58    inner: *mut c_types::hostent,
59    phantom: PhantomData<c_types::hostent>,
60}
61
62impl HostentOwned {
63    pub fn new(hostent: *mut c_types::hostent) -> Self {
64        HostentOwned {
65            inner: hostent,
66            phantom: PhantomData,
67        }
68    }
69}
70
71impl<'a> HasHostent<'a> for &'a HostentOwned {
72    fn hostent(self) -> &'a c_types::hostent {
73        unsafe { &*self.inner }
74    }
75}
76
77impl fmt::Display for HostentOwned {
78    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
79        let hostent = self.hostent();
80        display(hostent, fmt)
81    }
82}
83
84impl Drop for HostentOwned {
85    fn drop(&mut self) {
86        unsafe {
87            c_ares_sys::ares_free_hostent(self.inner);
88        }
89    }
90}
91
92unsafe impl Send for HostentOwned {}
93unsafe impl Sync for HostentOwned {}
94
95#[derive(Clone, Copy)]
96pub struct HostentBorrowed<'a> {
97    inner: &'a c_types::hostent,
98}
99
100impl<'a> HostentBorrowed<'a> {
101    pub fn new(hostent: &'a c_types::hostent) -> Self {
102        HostentBorrowed { inner: hostent }
103    }
104}
105
106impl<'a> HasHostent<'a> for HostentBorrowed<'a> {
107    fn hostent(self) -> &'a c_types::hostent {
108        self.inner
109    }
110}
111
112impl fmt::Display for HostentBorrowed<'_> {
113    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
114        let hostent = self.hostent();
115        display(hostent, fmt)
116    }
117}
118
119unsafe impl Send for HostentBorrowed<'_> {}
120unsafe impl Sync for HostentBorrowed<'_> {}
121
122// Get an IpAddr from a family and an array of bytes, as found in a `hostent`.
123unsafe fn ip_address_from_bytes(family: AddressFamily, h_addr: *const u8) -> Option<IpAddr> {
124    match family {
125        AddressFamily::INET => {
126            let source = unsafe { slice::from_raw_parts(h_addr, 4) };
127            let bytes: [u8; 4] = source.try_into().unwrap();
128            let ipv4 = Ipv4Addr::from(bytes);
129            Some(IpAddr::V4(ipv4))
130        }
131        AddressFamily::INET6 => {
132            let source = unsafe { slice::from_raw_parts(h_addr, 16) };
133            let bytes: [u8; 16] = source.try_into().unwrap();
134            let ipv6 = Ipv6Addr::from(bytes);
135            Some(IpAddr::V6(ipv6))
136        }
137        _ => None,
138    }
139}
140
141/// Iterator of `IpAddr`s.
142#[derive(Clone, Copy, Debug)]
143pub struct HostAddressResultsIter<'a> {
144    family: Option<AddressFamily>,
145    next: &'a *const c_char,
146}
147
148impl Iterator for HostAddressResultsIter<'_> {
149    type Item = IpAddr;
150    fn next(&mut self) -> Option<Self::Item> {
151        let h_addr = *self.next;
152        if h_addr.is_null() {
153            None
154        } else {
155            unsafe {
156                self.next = &*ptr::from_ref(self.next).offset(1);
157                self.family
158                    .and_then(|family| ip_address_from_bytes(family, h_addr.cast()))
159            }
160        }
161    }
162}
163
164unsafe impl Send for HostAddressResultsIter<'_> {}
165unsafe impl Sync for HostAddressResultsIter<'_> {}
166
167/// Iterator of `&'a str`s.
168#[derive(Clone, Copy, Debug)]
169pub struct HostAliasResultsIter<'a> {
170    next: &'a *const c_char,
171}
172
173impl<'a> Iterator for HostAliasResultsIter<'a> {
174    type Item = &'a str;
175    fn next(&mut self) -> Option<Self::Item> {
176        let h_alias = *self.next;
177        if h_alias.is_null() {
178            None
179        } else {
180            self.next = unsafe { &*ptr::from_ref(self.next).offset(1) };
181            let string = unsafe { hostname_as_str(h_alias) };
182            Some(string)
183        }
184    }
185}
186
187unsafe impl Send for HostAliasResultsIter<'_> {}
188unsafe impl Sync for HostAliasResultsIter<'_> {}