1use std::fmt;
2use std::marker::PhantomData;
3use std::os::raw::{c_int, c_uchar, c_void};
4use std::ptr;
5use std::slice;
6
7use itertools::Itertools;
8
9use crate::error::{Error, Result};
10use crate::panic;
11use crate::utils::hostname_as_str;
12
13#[derive(Debug)]
15pub struct SRVResults {
16 srv_reply: *mut c_ares_sys::ares_srv_reply,
17 phantom: PhantomData<c_ares_sys::ares_srv_reply>,
18}
19
20#[derive(Clone, Copy)]
22pub struct SRVResult<'a> {
23 srv_reply: &'a c_ares_sys::ares_srv_reply,
25}
26
27impl SRVResults {
28 pub fn parse_from(data: &[u8]) -> Result<SRVResults> {
30 let mut srv_reply: *mut c_ares_sys::ares_srv_reply = ptr::null_mut();
31 let parse_status = unsafe {
32 c_ares_sys::ares_parse_srv_reply(data.as_ptr(), data.len() as c_int, &mut srv_reply)
33 };
34 if parse_status == c_ares_sys::ares_status_t::ARES_SUCCESS as i32 {
35 let srv_result = SRVResults::new(srv_reply);
36 Ok(srv_result)
37 } else {
38 Err(Error::from(parse_status))
39 }
40 }
41
42 fn new(srv_reply: *mut c_ares_sys::ares_srv_reply) -> Self {
43 SRVResults {
44 srv_reply,
45 phantom: PhantomData,
46 }
47 }
48
49 pub fn iter(&self) -> SRVResultsIter {
51 SRVResultsIter {
52 next: unsafe { self.srv_reply.as_ref() },
53 }
54 }
55}
56
57impl fmt::Display for SRVResults {
58 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
59 let results = self.iter().format("}, {");
60 write!(fmt, "[{{{results}}}]")
61 }
62}
63
64#[derive(Clone, Copy)]
66pub struct SRVResultsIter<'a> {
67 next: Option<&'a c_ares_sys::ares_srv_reply>,
68}
69
70impl<'a> Iterator for SRVResultsIter<'a> {
71 type Item = SRVResult<'a>;
72 fn next(&mut self) -> Option<Self::Item> {
73 let opt_reply = self.next;
74 self.next = opt_reply.and_then(|reply| unsafe { reply.next.as_ref() });
75 opt_reply.map(|reply| SRVResult { srv_reply: reply })
76 }
77}
78
79impl<'a> IntoIterator for &'a SRVResults {
80 type Item = SRVResult<'a>;
81 type IntoIter = SRVResultsIter<'a>;
82
83 fn into_iter(self) -> Self::IntoIter {
84 self.iter()
85 }
86}
87
88impl Drop for SRVResults {
89 fn drop(&mut self) {
90 unsafe { c_ares_sys::ares_free_data(self.srv_reply.cast()) }
91 }
92}
93
94unsafe impl Send for SRVResults {}
95unsafe impl Sync for SRVResults {}
96unsafe impl Send for SRVResult<'_> {}
97unsafe impl Sync for SRVResult<'_> {}
98unsafe impl Send for SRVResultsIter<'_> {}
99unsafe impl Sync for SRVResultsIter<'_> {}
100
101impl<'a> SRVResult<'a> {
102 pub fn host(self) -> &'a str {
104 unsafe { hostname_as_str(self.srv_reply.host) }
105 }
106
107 pub fn weight(self) -> u16 {
109 self.srv_reply.weight
110 }
111
112 pub fn priority(self) -> u16 {
114 self.srv_reply.priority
115 }
116
117 pub fn port(self) -> u16 {
119 self.srv_reply.port
120 }
121}
122
123impl fmt::Display for SRVResult<'_> {
124 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
125 write!(fmt, "Host: {}, ", self.host())?;
126 write!(fmt, "Port: {}, ", self.port())?;
127 write!(fmt, "Priority: {}, ", self.priority())?;
128 write!(fmt, "Weight: {}", self.weight())
129 }
130}
131
132pub(crate) unsafe extern "C" fn query_srv_callback<F>(
133 arg: *mut c_void,
134 status: c_int,
135 _timeouts: c_int,
136 abuf: *mut c_uchar,
137 alen: c_int,
138) where
139 F: FnOnce(Result<SRVResults>) + Send + 'static,
140{
141 ares_callback!(arg.cast::<F>(), status, abuf, alen, SRVResults::parse_from);
142}