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), ];
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); 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}