about summary refs log tree commit diff
path: root/library/std/src/sys/pal/xous/net/dns.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys/pal/xous/net/dns.rs')
-rw-r--r--library/std/src/sys/pal/xous/net/dns.rs127
1 files changed, 127 insertions, 0 deletions
diff --git a/library/std/src/sys/pal/xous/net/dns.rs b/library/std/src/sys/pal/xous/net/dns.rs
new file mode 100644
index 00000000000..63056324bfb
--- /dev/null
+++ b/library/std/src/sys/pal/xous/net/dns.rs
@@ -0,0 +1,127 @@
+use crate::io;
+use crate::net::{Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
+use crate::os::xous::ffi::lend_mut;
+use crate::os::xous::services::{dns_server, DnsLendMut};
+use core::convert::{TryFrom, TryInto};
+
+pub struct DnsError {
+    pub code: u8,
+}
+
+#[repr(C, align(4096))]
+struct LookupHostQuery([u8; 4096]);
+
+pub struct LookupHost {
+    data: LookupHostQuery,
+    port: u16,
+    offset: usize,
+    count: usize,
+}
+
+impl LookupHost {
+    pub fn port(&self) -> u16 {
+        self.port
+    }
+}
+
+impl Iterator for LookupHost {
+    type Item = SocketAddr;
+    fn next(&mut self) -> Option<SocketAddr> {
+        if self.offset >= self.data.0.len() {
+            return None;
+        }
+        match self.data.0.get(self.offset) {
+            Some(&4) => {
+                self.offset += 1;
+                if self.offset + 4 > self.data.0.len() {
+                    return None;
+                }
+                let result = Some(SocketAddr::V4(SocketAddrV4::new(
+                    Ipv4Addr::new(
+                        self.data.0[self.offset],
+                        self.data.0[self.offset + 1],
+                        self.data.0[self.offset + 2],
+                        self.data.0[self.offset + 3],
+                    ),
+                    self.port,
+                )));
+                self.offset += 4;
+                result
+            }
+            Some(&6) => {
+                self.offset += 1;
+                if self.offset + 16 > self.data.0.len() {
+                    return None;
+                }
+                let mut new_addr = [0u8; 16];
+                for (src, octet) in self.data.0[(self.offset + 1)..(self.offset + 16 + 1)]
+                    .iter()
+                    .zip(new_addr.iter_mut())
+                {
+                    *octet = *src;
+                }
+                let result =
+                    Some(SocketAddr::V6(SocketAddrV6::new(new_addr.into(), self.port, 0, 0)));
+                self.offset += 16;
+                result
+            }
+            _ => None,
+        }
+    }
+}
+
+pub fn lookup(query: &str, port: u16) -> Result<LookupHost, DnsError> {
+    let mut result = LookupHost { data: LookupHostQuery([0u8; 4096]), offset: 0, count: 0, port };
+
+    // Copy the query into the message that gets sent to the DNS server
+    for (query_byte, result_byte) in query.as_bytes().iter().zip(result.data.0.iter_mut()) {
+        *result_byte = *query_byte;
+    }
+
+    lend_mut(
+        dns_server(),
+        DnsLendMut::RawLookup.into(),
+        &mut result.data.0,
+        0,
+        query.as_bytes().len(),
+    )
+    .unwrap();
+    if result.data.0[0] != 0 {
+        return Err(DnsError { code: result.data.0[1] });
+    }
+    assert_eq!(result.offset, 0);
+    result.count = result.data.0[1] as usize;
+
+    // Advance the offset to the first record
+    result.offset = 2;
+    Ok(result)
+}
+
+impl TryFrom<&str> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from(s: &str) -> io::Result<LookupHost> {
+        macro_rules! try_opt {
+            ($e:expr, $msg:expr) => {
+                match $e {
+                    Some(r) => r,
+                    None => return Err(io::const_io_error!(io::ErrorKind::InvalidInput, &$msg)),
+                }
+            };
+        }
+
+        // split the string by ':' and convert the second part to u16
+        let (host, port_str) = try_opt!(s.rsplit_once(':'), "invalid socket address");
+        let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value");
+        (host, port).try_into()
+    }
+}
+
+impl TryFrom<(&str, u16)> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from(v: (&str, u16)) -> io::Result<LookupHost> {
+        lookup(v.0, v.1)
+            .map_err(|_e| io::const_io_error!(io::ErrorKind::InvalidInput, &"DNS failure"))
+    }
+}