use alloc::vec::Vec; use sachy_fmt::{error, info}; use crate::{ dns::{ flags::Flags, query::{QClass, Query}, records::QType, reqres::{Request, Response}, traits::DnsParse, }, encoder::Encoder, service::Service, }; pub(crate) enum ResponseKind { Announcement, QueryResponse(Vec<(QType, QClass)>), } #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub(crate) struct Server { service: Service, } impl Server { pub(crate) fn new(service: Service) -> Self { Self { service } } pub(crate) fn broadcast<'a, 'b>( &self, response_kind: ResponseKind, flags: Flags, id: u16, queries: Vec>, outgoing: &'a mut [u8], ) -> Option<&'a [u8]> { let answers: Vec<_> = match response_kind { ResponseKind::Announcement => self.service.as_answers(QClass::Multicast).collect(), ResponseKind::QueryResponse(valid) => valid .iter() .flat_map(|&(qtype, qclass)| match qtype { QType::A | QType::AAAA => self.service.ip_answer(qclass), QType::PTR => self.service.ptr_answer(qclass), QType::TXT => self.service.txt_answer(qclass), QType::SRV => self.service.srv_answer(qclass), QType::Any | QType::Unknown(_) => None, }) .collect(), }; if !answers.is_empty() { let res = Response { flags, id, queries, answers, }; info!("MDNS RESPONSE: {}", res); return Encoder::new(outgoing) .encode(res) .inspect_err(|err| error!("Encoder errored: {}", err)) .ok(); } None } pub(crate) fn respond<'a>(&self, incoming: &[u8], outgoing: &'a mut [u8]) -> Option<&'a [u8]> { Request::parse(&mut &incoming[..], incoming) .ok() .and_then(|req| { let valid_queries = req.queries .iter() .filter_map(|q| match q.qtype { QType::A | QType::AAAA | QType::TXT | QType::SRV => { (q.name == self.service.hostname()).then_some((q.qtype, q.qclass)) } QType::PTR => (q.name == self.service.service_type()) .then_some((q.qtype, q.qclass)), QType::Any | QType::Unknown(_) => None, }) .collect::>(); if !valid_queries.is_empty() { self.broadcast( ResponseKind::QueryResponse(valid_queries), req.flags, req.id, req.queries, outgoing, ) } else { None } }) } }