Repo of no-std crates for my personal embedded projects
at main 112 lines 3.4 kB view raw
1use alloc::vec::Vec; 2use sachy_fmt::{error, info}; 3 4use crate::{ 5 dns::{ 6 flags::Flags, 7 query::{Answer, 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 let additional = match &answers[..] { 55 [] => return None, 56 [ 57 Answer { 58 atype: QType::PTR, 59 aclass, 60 .. 61 }, 62 ] => self.service.as_additional(*aclass).collect(), 63 _ => Vec::new(), 64 }; 65 66 let res = Response { 67 flags, 68 id, 69 queries, 70 answers, 71 additional, 72 }; 73 74 info!("MDNS RESPONSE: {}", res); 75 76 Encoder::new(outgoing) 77 .encode(res) 78 .inspect_err(|err| error!("Encoder errored: {}", err)) 79 .ok() 80 } 81 82 pub(crate) fn respond<'a>(&self, incoming: &[u8], outgoing: &'a mut [u8]) -> Option<&'a [u8]> { 83 Request::parse(&mut &incoming[..], incoming) 84 .ok() 85 .and_then(|req| { 86 let valid_queries = 87 req.queries 88 .iter() 89 .filter_map(|q| match q.qtype { 90 QType::A | QType::AAAA | QType::TXT | QType::SRV => { 91 (q.name == self.service.hostname()).then_some((q.qtype, q.qclass)) 92 } 93 QType::PTR => (q.name == self.service.service_type()) 94 .then_some((q.qtype, q.qclass)), 95 QType::Any | QType::Unknown(_) => None, 96 }) 97 .collect::<Vec<_>>(); 98 99 if !valid_queries.is_empty() { 100 self.broadcast( 101 ResponseKind::QueryResponse(valid_queries), 102 req.flags, 103 req.id, 104 req.queries, 105 outgoing, 106 ) 107 } else { 108 None 109 } 110 }) 111 } 112}