Skip to main content

esp_hal_mdns/
lib.rs

1#![no_std]
2
3use dns_protocol::{Flags, LabelSegment, Message, Question, ResourceRecord, ResourceType};
4
5const MDNS_BUF_SIZE: usize = 4096;
6
7pub struct MdnsQuery<'a> {
8    pub query_str: &'a str,
9    buff: [u8; MDNS_BUF_SIZE],
10    n: usize,
11
12    resend_interval: u64,
13    last_mdns_sent: u64,
14    curr_time_ms_func: fn() -> u64,
15}
16
17impl<'a> MdnsQuery<'a> {
18    pub fn new(query: &'a str, resend_interval: u64, curr_time_ms_func: fn() -> u64) -> Self {
19        let mut questions = [
20            Question::new(query, dns_protocol::ResourceType::Ptr, 1 | 0x8000), //1-IN
21                                                                               //0x8000 - prefer unicast
22        ];
23
24        let msg = Message::new(
25            0,
26            *Flags::default().set_recursive(false),
27            &mut questions,
28            &mut [],
29            &mut [],
30            &mut [],
31        );
32
33        let mut buff = [0; MDNS_BUF_SIZE];
34        let n = msg.write(&mut buff).unwrap();
35
36        Self {
37            query_str: query,
38
39            buff,
40            n,
41
42            resend_interval,
43            last_mdns_sent: 0,
44            curr_time_ms_func,
45        }
46    }
47
48    pub fn should_send_mdns_packet(&mut self) -> Option<&[u8]> {
49        if (self.curr_time_ms_func)() - self.last_mdns_sent > self.resend_interval {
50            self.last_mdns_sent = (self.curr_time_ms_func)();
51
52            return Some(&self.buff[..self.n]);
53        }
54
55        None
56    }
57
58    pub fn parse_mdns_query(
59        &mut self,
60        data: &[u8],
61        key: Option<&str>,
62    ) -> ([u8; 4], u16, Option<heapless::String<255>>) {
63        let mut tmp_txt = None;
64        let mut tmp_ip = [0; 4];
65        let mut tmp_port = 0;
66
67        let mut answers = [ResourceRecord::default(); 16];
68        let mut additional = [ResourceRecord::default(); 16];
69
70        let res = Message::read(&data, &mut [], &mut answers, &mut [], &mut additional);
71
72        if let Ok(res) = res {
73            if res.answers().len() > 0 && res.additional().len() > 0 {
74                let mut segments = res.answers()[0].name().segments();
75                let mut is_ans = true;
76
77                for seg in self.query_str.split(".") {
78                    if let Some(segment) = segments.next() {
79                        if let LabelSegment::String(segment) = segment {
80                            if seg == segment {
81                                continue;
82                            }
83                        } else if let LabelSegment::Empty = segment {
84                            if seg.is_empty() {
85                                continue;
86                            }
87                        }
88                    }
89
90                    is_ans = false;
91                    break;
92                }
93
94                if is_ans {
95                    for add in res.additional() {
96                        if add.ty() == ResourceType::Txt {
97                            let data = add.data();
98                            let mut offset = 0;
99                            loop {
100                                if offset >= data.len() {
101                                    break;
102                                }
103
104                                let len = data[offset] as usize;
105                                offset += 1;
106
107                                let mut splitted =
108                                    data[offset..offset + len].splitn(2, |&x| x == 0x3d); // 0x3d "="
109
110                                let sp_key = splitted.next().unwrap_or(&[]);
111                                let sp_value = splitted.next().unwrap_or(&[]);
112
113                                if let Some(key) = key {
114                                    if key.as_bytes() == sp_key {
115                                        let value = core::str::from_utf8(sp_value).unwrap_or("");
116                                        tmp_txt = Some(
117                                            value.try_into().unwrap_or(heapless::String::new()),
118                                        );
119                                    }
120                                }
121
122                                offset += len;
123                            }
124                        } else if add.ty() == ResourceType::Srv {
125                            let port = u16::from_be_bytes(add.data()[4..6].try_into().unwrap());
126                            tmp_port = port;
127                        } else if add.ty() == ResourceType::A {
128                            let ip = add.data()[0..4].try_into().unwrap_or([0; 4]);
129                            tmp_ip = ip;
130                        }
131                    }
132                }
133            }
134        }
135
136        (tmp_ip, tmp_port, tmp_txt)
137    }
138}