c_ares/
utils.rs

1use crate::types::AddressFamily;
2use std::ffi::{c_char, CStr};
3use std::mem;
4use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
5use std::os::raw::c_int;
6use std::str;
7
8// Convert an address family into a more strongly typed AddressFamily.
9pub fn address_family(family: c_types::ADDRESS_FAMILY) -> Option<AddressFamily> {
10    match family {
11        c_types::AF_INET => Some(AddressFamily::INET),
12        c_types::AF_INET6 => Some(AddressFamily::INET6),
13        c_types::AF_UNSPEC => Some(AddressFamily::UNSPEC),
14        _ => None,
15    }
16}
17
18// Get an in_addr from an Ipv4Addr.
19#[cfg(unix)]
20pub fn ipv4_as_in_addr(ipv4: Ipv4Addr) -> c_types::in_addr {
21    c_types::in_addr {
22        s_addr: u32::from(ipv4).to_be(),
23    }
24}
25
26#[cfg(windows)]
27pub fn ipv4_as_in_addr(ipv4: Ipv4Addr) -> c_types::in_addr {
28    let octets = ipv4.octets();
29    let mut in_addr: c_types::in_addr = unsafe { mem::zeroed() };
30    in_addr.S_un.S_un_b.s_b1 = octets[0];
31    in_addr.S_un.S_un_b.s_b2 = octets[1];
32    in_addr.S_un.S_un_b.s_b3 = octets[2];
33    in_addr.S_un.S_un_b.s_b4 = octets[3];
34    in_addr
35}
36
37// Get an Ipv4Addr from an in_addr.
38#[cfg(unix)]
39pub fn ipv4_from_in_addr(in_addr: c_types::in_addr) -> Ipv4Addr {
40    Ipv4Addr::from(u32::from_be(in_addr.s_addr))
41}
42
43#[cfg(windows)]
44pub fn ipv4_from_in_addr(in_addr: c_types::in_addr) -> Ipv4Addr {
45    let bytes = unsafe { in_addr.S_un.S_un_b };
46    Ipv4Addr::new(bytes.s_b1, bytes.s_b2, bytes.s_b3, bytes.s_b4)
47}
48
49// Get an in6_addr from an Ipv6Addr.
50#[cfg(unix)]
51pub fn ipv6_as_in6_addr(ipv6: &Ipv6Addr) -> c_types::in6_addr {
52    let octets = ipv6.octets();
53    let mut in6_addr: c_types::in6_addr = unsafe { mem::zeroed() };
54    in6_addr.s6_addr.copy_from_slice(&octets);
55    in6_addr
56}
57
58#[cfg(windows)]
59pub fn ipv6_as_in6_addr(ipv6: &Ipv6Addr) -> c_types::in6_addr {
60    let octets = ipv6.octets();
61    let mut in6_addr: c_types::in6_addr = unsafe { mem::zeroed() };
62    unsafe { in6_addr.u.Byte.copy_from_slice(&octets) }
63    in6_addr
64}
65
66// Get a sockaddr_in from a SocketAddrV4.
67#[cfg(any(
68    target_os = "macos",
69    target_os = "ios",
70    target_os = "freebsd",
71    target_os = "dragonfly",
72    target_os = "openbsd",
73    target_os = "netbsd",
74))]
75pub fn socket_addrv4_as_sockaddr_in(sock_v4: &SocketAddrV4) -> c_types::sockaddr_in {
76    let in_addr = ipv4_as_in_addr(*sock_v4.ip());
77    c_types::sockaddr_in {
78        sin_len: mem::size_of::<c_types::sockaddr_in>() as u8,
79        sin_family: c_types::AF_INET as c_types::sa_family_t,
80        sin_port: sock_v4.port().to_be(),
81        sin_addr: in_addr,
82        sin_zero: [0; 8],
83    }
84}
85
86#[cfg(not(any(
87    target_os = "macos",
88    target_os = "ios",
89    target_os = "freebsd",
90    target_os = "dragonfly",
91    target_os = "openbsd",
92    target_os = "netbsd",
93)))]
94pub fn socket_addrv4_as_sockaddr_in(sock_v4: &SocketAddrV4) -> c_types::sockaddr_in {
95    let in_addr = ipv4_as_in_addr(*sock_v4.ip());
96    c_types::sockaddr_in {
97        sin_family: c_types::AF_INET as c_types::sa_family_t,
98        sin_port: sock_v4.port().to_be(),
99        sin_addr: in_addr,
100        sin_zero: [0; 8],
101    }
102}
103
104// Get a sockaddr_in6 from a SocketAddrV6.
105#[cfg(any(
106    target_os = "macos",
107    target_os = "ios",
108    target_os = "freebsd",
109    target_os = "dragonfly",
110    target_os = "openbsd",
111    target_os = "netbsd",
112))]
113pub fn socket_addrv6_as_sockaddr_in6(sock_v6: &SocketAddrV6) -> c_types::sockaddr_in6 {
114    let in6_addr = ipv6_as_in6_addr(sock_v6.ip());
115    c_types::sockaddr_in6 {
116        sin6_len: mem::size_of::<c_types::sockaddr_in6>() as u8,
117        sin6_family: c_types::AF_INET6 as c_types::sa_family_t,
118        sin6_port: sock_v6.port().to_be(),
119        sin6_addr: in6_addr,
120        sin6_flowinfo: sock_v6.flowinfo(),
121        sin6_scope_id: sock_v6.scope_id(),
122    }
123}
124
125#[cfg(all(
126    unix,
127    not(any(
128        target_os = "macos",
129        target_os = "ios",
130        target_os = "freebsd",
131        target_os = "dragonfly",
132        target_os = "openbsd",
133        target_os = "netbsd",
134    ))
135))]
136pub fn socket_addrv6_as_sockaddr_in6(sock_v6: &SocketAddrV6) -> c_types::sockaddr_in6 {
137    let in6_addr = ipv6_as_in6_addr(sock_v6.ip());
138    c_types::sockaddr_in6 {
139        sin6_family: c_types::AF_INET6 as c_types::sa_family_t,
140        sin6_port: sock_v6.port().to_be(),
141        sin6_addr: in6_addr,
142        sin6_flowinfo: sock_v6.flowinfo(),
143        sin6_scope_id: sock_v6.scope_id(),
144    }
145}
146
147#[cfg(windows)]
148pub fn socket_addrv6_as_sockaddr_in6(sock_v6: &SocketAddrV6) -> c_types::sockaddr_in6 {
149    let mut sockaddr_in6: c_types::sockaddr_in6 = unsafe { mem::zeroed() };
150    sockaddr_in6.sin6_family = c_types::AF_INET6 as c_types::sa_family_t;
151    sockaddr_in6.sin6_port = sock_v6.port().to_be();
152    sockaddr_in6.sin6_addr = ipv6_as_in6_addr(sock_v6.ip());
153    sockaddr_in6.sin6_flowinfo = sock_v6.flowinfo();
154    sockaddr_in6.Anonymous.sin6_scope_id = sock_v6.scope_id();
155    sockaddr_in6
156}
157
158pub unsafe fn c_string_as_str_unchecked<'a>(c_str: *const c_char) -> &'a str {
159    let bytes = unsafe { CStr::from_ptr(c_str) }.to_bytes();
160    unsafe { str::from_utf8_unchecked(bytes) }
161}
162
163#[cfg(not(cares1_30))]
164pub unsafe fn c_string_as_str_checked<'a>(c_str: *const c_char) -> &'a str {
165    let c_str = unsafe { CStr::from_ptr(c_str) };
166    c_str.to_str().unwrap()
167}
168
169#[cfg(not(cares1_17_2))]
170pub unsafe fn hostname_as_str<'a>(hostname: *const c_char) -> &'a str {
171    c_string_as_str_checked(hostname)
172}
173
174#[cfg(cares1_17_2)]
175pub unsafe fn hostname_as_str<'a>(hostname: *const c_char) -> &'a str {
176    unsafe { c_string_as_str_unchecked(hostname) }
177}
178
179#[cfg(not(cares1_30))]
180pub unsafe fn dns_string_as_str<'a>(hostname: *const c_char) -> &'a str {
181    unsafe { c_string_as_str_checked(hostname) }
182}
183
184#[cfg(cares1_30)]
185pub unsafe fn dns_string_as_str<'a>(hostname: *const c_char) -> &'a str {
186    c_string_as_str_unchecked(hostname)
187}
188
189/// Get the version number of the underlying `c-ares` library.
190///
191/// The version is returned as both a string and an integer.  The integer is built up as 24bit
192/// number, with 8 separate bits used for major number, minor number and patch number.  For
193/// example, the version string "1.2.3" is returned as hexadecimal number 0x010203 (decimal 66051).
194pub fn version() -> (&'static str, u32) {
195    let mut int_version: c_int = 0;
196    let str_version = unsafe {
197        let ptr = c_ares_sys::ares_version(&mut int_version);
198        c_string_as_str_unchecked(ptr)
199    };
200    (str_version, int_version as u32)
201}
202
203/// Whether the underlying `c-ares` library was built with thread safety enabled or not.
204///
205/// This is unlikely to be of interest to users of this crate.  Our API assumes that c-ares was not
206/// built with thread safety, and uses Rust's safety features to prevent errors.
207#[cfg(cares1_23)]
208pub fn thread_safety() -> bool {
209    let safety = unsafe { c_ares_sys::ares_threadsafety() };
210    safety != c_ares_sys::ares_bool_t::ARES_FALSE
211}