c_ares/
hostent.rs

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