axnet/smoltcp_impl/
dns.rs

1use alloc::vec::Vec;
2use axerrno::{AxError, AxResult, ax_err_type};
3use core::net::IpAddr;
4
5use smoltcp::iface::SocketHandle;
6use smoltcp::socket::dns::{self, GetQueryResultError, StartQueryError};
7use smoltcp::wire::DnsQueryType;
8
9use super::addr::into_core_ipaddr;
10use super::{ETH0, SOCKET_SET, SocketSetWrapper};
11
12/// A DNS socket.
13struct DnsSocket {
14    handle: Option<SocketHandle>,
15}
16
17impl DnsSocket {
18    #[allow(clippy::new_without_default)]
19    /// Creates a new DNS socket.
20    pub fn new() -> Self {
21        let socket = SocketSetWrapper::new_dns_socket();
22        let handle = Some(SOCKET_SET.add(socket));
23        Self { handle }
24    }
25
26    #[allow(dead_code)]
27    /// Update the list of DNS servers, will replace all existing servers.
28    pub fn update_servers(self, servers: &[smoltcp::wire::IpAddress]) {
29        SOCKET_SET.with_socket_mut::<dns::Socket, _, _>(self.handle.unwrap(), |socket| {
30            socket.update_servers(servers)
31        });
32    }
33
34    /// Query a address with given DNS query type.
35    pub fn query(&self, name: &str, query_type: DnsQueryType) -> AxResult<Vec<IpAddr>> {
36        // let local_addr = self.local_addr.unwrap_or_else(f);
37        let handle = self.handle.ok_or_else(|| ax_err_type!(InvalidInput))?;
38        let iface = &ETH0.iface;
39        let query_handle = SOCKET_SET
40            .with_socket_mut::<dns::Socket, _, _>(handle, |socket| {
41                socket.start_query(iface.lock().context(), name, query_type)
42            })
43            .map_err(|e| match e {
44                StartQueryError::NoFreeSlot => {
45                    ax_err_type!(ResourceBusy, "socket query() failed: no free slot")
46                }
47                StartQueryError::InvalidName => {
48                    ax_err_type!(InvalidInput, "socket query() failed: invalid name")
49                }
50                StartQueryError::NameTooLong => {
51                    ax_err_type!(InvalidInput, "socket query() failed: too long name")
52                }
53            })?;
54        loop {
55            SOCKET_SET.poll_interfaces();
56            match SOCKET_SET.with_socket_mut::<dns::Socket, _, _>(handle, |socket| {
57                socket.get_query_result(query_handle).map_err(|e| match e {
58                    GetQueryResultError::Pending => AxError::WouldBlock,
59                    GetQueryResultError::Failed => {
60                        ax_err_type!(ConnectionRefused, "socket query() failed")
61                    }
62                })
63            }) {
64                Ok(n) => {
65                    let mut res = Vec::with_capacity(n.capacity());
66                    for ip in n {
67                        res.push(into_core_ipaddr(ip))
68                    }
69                    return Ok(res);
70                }
71                Err(AxError::WouldBlock) => axtask::yield_now(),
72                Err(e) => return Err(e),
73            }
74        }
75    }
76}
77
78impl Drop for DnsSocket {
79    fn drop(&mut self) {
80        if let Some(handle) = self.handle {
81            SOCKET_SET.remove(handle);
82        }
83    }
84}
85
86/// Public function for DNS query.
87pub fn dns_query(name: &str) -> AxResult<alloc::vec::Vec<IpAddr>> {
88    let socket = DnsSocket::new();
89    socket.query(name, DnsQueryType::A)
90}