Skip to main content

async_rs/implementors/
hickory.rs

1use crate::{
2    traits::AsyncToSocketAddrs,
3    util::{self, SocketAddrsFromIpAddrs},
4};
5use hickory_resolver::{Resolver, proto::rr::IntoName};
6use std::{
7    io,
8    net::{IpAddr, SocketAddr, ToSocketAddrs},
9    str::FromStr,
10    vec,
11};
12
13/// Perform async DNS resolution using hickory-dns
14#[derive(Debug, Clone)]
15pub struct HickoryToSocketAddrs<T: IntoName + Send + 'static> {
16    host: T,
17    port: u16,
18}
19
20impl<H: IntoName + Send + 'static> HickoryToSocketAddrs<H> {
21    /// Create a `HickoryToSocketAddrs` from split host and port components.
22    pub fn new(host: H, port: u16) -> Self {
23        Self { host, port }
24    }
25
26    async fn lookup(self) -> io::Result<SocketAddrsFromIpAddrs<vec::IntoIter<IpAddr>>> {
27        if !util::inside_tokio() {
28            return Err(io::Error::other(
29                "hickory-dns is only supported in a tokio context",
30            ));
31        }
32
33        Ok(SocketAddrsFromIpAddrs(
34            Resolver::builder_tokio()
35                .map_err(io::Error::other)?
36                .build()
37                .map_err(io::Error::other)?
38                .lookup_ip(self.host)
39                .await
40                .map_err(io::Error::other)?
41                .iter()
42                .collect::<Vec<_>>() // FIXME: don't collect if we get back into_iter
43                .into_iter(),
44            self.port,
45        ))
46    }
47}
48
49impl FromStr for HickoryToSocketAddrs<String> {
50    type Err = io::Error;
51
52    fn from_str(s: &str) -> io::Result<Self> {
53        let (host, port_str) = s
54            .rsplit_once(':')
55            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "invalid socket address"))?;
56        let port = port_str
57            .parse()
58            .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid port value"))?;
59        Ok(Self::new(host.to_owned(), port))
60    }
61}
62
63impl<T: IntoName + Clone + Send + 'static> ToSocketAddrs for HickoryToSocketAddrs<T> {
64    type Iter = SocketAddrsFromIpAddrs<vec::IntoIter<IpAddr>>;
65
66    fn to_socket_addrs(&self) -> io::Result<Self::Iter> {
67        util::block_on_tokio(self.clone().lookup())
68    }
69}
70
71impl<T: IntoName + Send + 'static> AsyncToSocketAddrs for HickoryToSocketAddrs<T> {
72    fn to_socket_addrs(
73        self,
74    ) -> impl Future<Output = io::Result<impl Iterator<Item = SocketAddr> + Send + 'static>>
75    + Send
76    + 'static {
77        self.lookup()
78    }
79}