async_rs/implementors/
hickory.rs

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