1use heapless::Vec;
8pub use smoltcp::socket::dns::{DnsQuery, Socket};
9pub(crate) use smoltcp::socket::dns::{GetQueryResultError, StartQueryError};
10pub use smoltcp::wire::{DnsQueryType, IpAddress};
11
12use crate::Stack;
13
14#[derive(Debug, PartialEq, Eq, Clone, Copy)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub enum Error {
18 InvalidName,
20 NameTooLong,
22 Failed,
24}
25
26impl From<GetQueryResultError> for Error {
27 fn from(_: GetQueryResultError) -> Self {
28 Self::Failed
29 }
30}
31
32impl From<StartQueryError> for Error {
33 fn from(e: StartQueryError) -> Self {
34 match e {
35 StartQueryError::NoFreeSlot => Self::Failed,
36 StartQueryError::InvalidName => Self::InvalidName,
37 StartQueryError::NameTooLong => Self::NameTooLong,
38 }
39 }
40}
41
42pub struct DnsSocket<'a> {
48 stack: Stack<'a>,
49}
50
51impl<'a> DnsSocket<'a> {
52 pub fn new(stack: Stack<'a>) -> Self {
56 Self { stack }
57 }
58
59 pub async fn query(
61 &self,
62 name: &str,
63 qtype: DnsQueryType,
64 ) -> Result<Vec<IpAddress, { smoltcp::config::DNS_MAX_RESULT_COUNT }>, Error> {
65 self.stack.dns_query(name, qtype).await
66 }
67}
68
69impl<'a> embedded_nal_async::Dns for DnsSocket<'a> {
70 type Error = Error;
71
72 async fn get_host_by_name(
73 &self,
74 host: &str,
75 addr_type: embedded_nal_async::AddrType,
76 ) -> Result<core::net::IpAddr, Self::Error> {
77 use core::net::IpAddr;
78
79 use embedded_nal_async::AddrType;
80
81 let (qtype, secondary_qtype) = match addr_type {
82 AddrType::IPv4 => (DnsQueryType::A, None),
83 AddrType::IPv6 => (DnsQueryType::Aaaa, None),
84 AddrType::Either => {
85 #[cfg(not(feature = "proto-ipv6"))]
86 let v6_first = false;
87 #[cfg(feature = "proto-ipv6")]
88 let v6_first = self.stack.config_v6().is_some();
89 match v6_first {
90 true => (DnsQueryType::Aaaa, Some(DnsQueryType::A)),
91 false => (DnsQueryType::A, Some(DnsQueryType::Aaaa)),
92 }
93 }
94 };
95 let mut addrs = self.query(host, qtype).await?;
96 if addrs.is_empty() {
97 if let Some(qtype) = secondary_qtype {
98 addrs = self.query(host, qtype).await?
99 }
100 }
101 if let Some(first) = addrs.get(0) {
102 Ok(match first {
103 #[cfg(feature = "proto-ipv4")]
104 IpAddress::Ipv4(addr) => IpAddr::V4(*addr),
105 #[cfg(feature = "proto-ipv6")]
106 IpAddress::Ipv6(addr) => IpAddr::V6(*addr),
107 })
108 } else {
109 Err(Error::Failed)
110 }
111 }
112
113 async fn get_host_by_address(&self, _addr: core::net::IpAddr, _result: &mut [u8]) -> Result<usize, Self::Error> {
114 todo!()
115 }
116}
117
118fn _assert_covariant<'a, 'b: 'a>(x: DnsSocket<'b>) -> DnsSocket<'a> {
119 x
120}