async_dns_lookup/
async_dns_lookup.rs1use 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; 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}