Repo of no-std crates for my personal embedded projects
1use alloc::vec::Vec;
2use sachy_fmt::{error, info};
3
4use crate::{
5 dns::{
6 flags::Flags,
7 query::{QClass, Query},
8 records::QType,
9 reqres::{Request, Response},
10 traits::DnsParse,
11 },
12 encoder::Encoder,
13 service::Service,
14};
15
16pub(crate) enum ResponseKind {
17 Announcement,
18 QueryResponse(Vec<(QType, QClass)>),
19}
20
21#[derive(Debug)]
22#[cfg_attr(feature = "defmt", derive(defmt::Format))]
23pub(crate) struct Server {
24 service: Service,
25}
26
27impl Server {
28 pub(crate) fn new(service: Service) -> Self {
29 Self { service }
30 }
31
32 pub(crate) fn broadcast<'a, 'b>(
33 &self,
34 response_kind: ResponseKind,
35 flags: Flags,
36 id: u16,
37 queries: Vec<Query<'b>>,
38 outgoing: &'a mut [u8],
39 ) -> Option<&'a [u8]> {
40 let answers: Vec<_> = match response_kind {
41 ResponseKind::Announcement => self.service.as_answers(QClass::Multicast).collect(),
42 ResponseKind::QueryResponse(valid) => valid
43 .iter()
44 .flat_map(|&(qtype, qclass)| match qtype {
45 QType::A | QType::AAAA => self.service.ip_answer(qclass),
46 QType::PTR => self.service.ptr_answer(qclass),
47 QType::TXT => self.service.txt_answer(qclass),
48 QType::SRV => self.service.srv_answer(qclass),
49 QType::Any | QType::Unknown(_) => None,
50 })
51 .collect(),
52 };
53
54 if !answers.is_empty() {
55 let res = Response {
56 flags,
57 id,
58 queries,
59 answers,
60 };
61
62 info!("MDNS RESPONSE: {}", res);
63
64 return Encoder::new(outgoing)
65 .encode(res)
66 .inspect_err(|err| error!("Encoder errored: {}", err))
67 .ok();
68 }
69
70 None
71 }
72
73 pub(crate) fn respond<'a>(&self, incoming: &[u8], outgoing: &'a mut [u8]) -> Option<&'a [u8]> {
74 Request::parse(&mut &incoming[..], incoming)
75 .ok()
76 .and_then(|req| {
77 let valid_queries =
78 req.queries
79 .iter()
80 .filter_map(|q| match q.qtype {
81 QType::A | QType::AAAA | QType::TXT | QType::SRV => {
82 (q.name == self.service.hostname()).then_some((q.qtype, q.qclass))
83 }
84 QType::PTR => (q.name == self.service.service_type())
85 .then_some((q.qtype, q.qclass)),
86 QType::Any | QType::Unknown(_) => None,
87 })
88 .collect::<Vec<_>>();
89
90 if !valid_queries.is_empty() {
91 self.broadcast(
92 ResponseKind::QueryResponse(valid_queries),
93 req.flags,
94 req.id,
95 req.queries,
96 outgoing,
97 )
98 } else {
99 None
100 }
101 })
102 }
103}