async_dns_lookup/
async_dns_lookup.rs

1use std::{
2    io,
3    net::{IpAddr, Ipv4Addr, SocketAddr},
4};
5
6use tokio::{
7    runtime::Builder,
8    sync::{
9        mpsc::{self, Sender},
10        oneshot,
11    },
12    task::LocalSet,
13};
14
15#[derive(Debug)]
16pub struct Request(Ipv4Addr, oneshot::Sender<Result<String, std::io::Error>>);
17
18#[derive(Clone)]
19pub struct AsyncDnsResolver {
20    request_sender: Sender<Request>,
21}
22
23impl Default for AsyncDnsResolver {
24    fn default() -> Self {
25        Self::new()
26    }
27}
28
29impl AsyncDnsResolver {
30    pub fn new() -> Self {
31        let (request_sender, mut request_receiver) = mpsc::channel::<Request>(1);
32        let runtime = Builder::new_current_thread().enable_all().build().unwrap();
33
34        std::thread::spawn(move || {
35            let local = LocalSet::new();
36            local.spawn_local(async move {
37                while let Some(Request(ipv4, oneshot_sender)) = request_receiver.recv().await {
38                    tokio::task::spawn_local(async move {
39                        let response = reverse_lookup_async(&ipv4).await;
40                        if let Err(res) = oneshot_sender.send(response) {
41                            log::warn!("Warning! The receiver has been dropped. {:?}", res);
42                        }
43                    });
44                }
45            });
46            runtime.block_on(local);
47        });
48
49        Self { request_sender }
50    }
51
52    pub async fn reverse_lookup(&self, ipv4: Ipv4Addr) -> Result<String, std::io::Error> {
53        let (oneshot_sender, oneshot_receiver) =
54            oneshot::channel::<Result<String, std::io::Error>>();
55        self.request_sender
56            .send(Request(ipv4, oneshot_sender))
57            .await
58            .map_err(io::Error::other)?;
59        oneshot_receiver.await.map_err(io::Error::other)?
60    }
61}
62
63async fn reverse_lookup_async(ip: &Ipv4Addr) -> Result<String, io::Error> {
64    let ip = *ip; // copy since Ipv4Addr is Copy
65    tokio::task::spawn_blocking(move || {
66        let sa = SocketAddr::new(IpAddr::V4(ip), 0);
67        let host = dns_lookup::getnameinfo(&sa, 0)?;
68        Ok::<_, io::Error>(host.0)
69    })
70    .await
71    .map_err(io::Error::other)?
72}