eculocate

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit c03e1814d55e85e21010928d397d7e2517068091
parent 9dc22f2a86a8d58b2f5db1607932b92e519c8d87
Author: Daniel Barlow <dan@telent.net>
Date:   Mon, 29 Dec 2025 12:27:53 +0000

move all mdns stuff to MdnsResponder

Diffstat:
Mecu-esp32/src/wifi.rs | 252+++++++++++++++++++++++++++++++++++--------------------------------------------
1 file changed, 112 insertions(+), 140 deletions(-)

diff --git a/ecu-esp32/src/wifi.rs b/ecu-esp32/src/wifi.rs @@ -44,7 +44,6 @@ const DISCOVERY_NAME : &str = "_services._dns-sd._udp.local"; use dns_protocol::{Message, Question, MessageType, - Label, ResourceRecord, ResourceType, Flags}; // When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html @@ -101,15 +100,123 @@ impl<'a> MdnsResponder<'a> { async fn advertise(&self) { let db = &self.database; - send_response(&self.sock, 0, MDNS_ENDPOINT, db, None, db.advertised()).await; + self.send_response(0, MDNS_ENDPOINT, None, db.advertised()).await; } fn may_recv(&self) -> bool { self.sock.may_recv() } - fn sock(&self) -> &UdpSocket<'a> { - &self.sock + async fn send_response(&self, + id: u16, + endpoint: IpEndpoint, + question: Option<&Question<'_>>, + answers: Vec<&DnsResource>) { + + let questions = match question { + Some(q) =>&mut [*q][..], + None => &mut [][..] + }; + + let db = &self.database; + let mut flags = Flags::new(); + + + flags.set_qr(MessageType::Reply); + flags.set_authoritative(true); + + let mut additional : BTreeSet<ResourceRecord> = BTreeSet::new(); + let mut answers : Vec<ResourceRecord> = { + let mut rrs = Vec::new(); + for a in answers { + rrs.push(a.to_resource_record()); + for r in db.all_additional(a).into_iter() { + additional.insert(r.to_resource_record()); + }; + } + rrs + }; + + // don't send anything in "additional" that's already in the answers + for rr in &answers { + additional.remove(&rr); + } + + let mut additional : Vec<ResourceRecord> = additional.into_iter().collect(); + let message = Message::new( + id, + flags, + questions, + &mut answers, + &mut [], + &mut additional); + + let mut data_buf = [0; 4096]; + // Serialize the message into the buffer + assert!(message.space_needed() <= data_buf.len()); + + info!("ready to send to {:?}", endpoint); + + match message.write(&mut data_buf) { + Result::Ok(len) => { + if let Result::Err(x) = self.sock.send_to(&data_buf[..len], endpoint).await { + info!("sock.send failed: {:?}", x); + } + }, + Result::Err(err) => { + error!("message.write {:?}", err); + } + } + } + + async fn send_responses(&self, + message: &Message<'_,'_>, + meta: &UdpMetadata) { + + let q_id = message.id(); + + for q in message.questions() { + let relevant = self.database.find(q.name().to_string(), q.ty()); + if relevant.len() > 0 { + log::info!("question {:?} {:?} {:?} flags {:?} from {:?}", + q.name(), q.ty(), q.class(), + message.flags().raw(), + meta.endpoint); + + self.send_response(q_id, MDNS_ENDPOINT, None, relevant).await + } + } + } + + async fn process_packet(&self) { + let mut questions = [Question::default(); 64]; + let mut answers = [ResourceRecord::default(); 64]; + let mut authorities = [ResourceRecord::default(); 64]; + let mut addl = [ResourceRecord::default(); 64]; + + let mut data_buf = [0; 4096]; + + let res = self.sock.recv_from(&mut data_buf).await; + if let Ok((n, meta)) = res { + let message = Message::read( + &data_buf[..n], + &mut questions, + &mut answers, + &mut authorities, + &mut addl, + ); + + match message { + Result::Ok(message) => { + self.send_responses(&message, &meta).await; + }, + Result::Err(err) => { + log::error!("parsing dns message from {:?} : {:?}", + meta.endpoint, + err); + } + } + } } } @@ -289,110 +396,6 @@ impl DnsDatabase { } } -// RFC: "Multicast DNS responses MUST NOT contain any questions in the -// Question Section. ". However, responses to "legacy" queries (port != 5353) -// should have a question section just like traditional DNS - -async fn send_response(sock: &UdpSocket<'_>, - id: u16, - endpoint: IpEndpoint, - db: &DnsDatabase, - question: Option<&Question<'_>>, - answers: Vec<&DnsResource>) { - - let questions = match question { - Some(q) =>&mut [*q][..], - None => &mut [][..] - }; - - - - let mut flags = Flags::new(); - - flags.set_qr(MessageType::Reply); - flags.set_authoritative(true); - - let mut additional : BTreeSet<ResourceRecord> = BTreeSet::new(); - let mut answers : Vec<ResourceRecord> = { - let mut rrs = Vec::new(); - for a in answers { - rrs.push(a.to_resource_record()); - for r in db.all_additional(a).into_iter() { - additional.insert(r.to_resource_record()); - }; - } - rrs - }; - - // don't send anything in "additional" that's already in the answers - for rr in &answers { - additional.remove(&rr); - } - - let mut additional : Vec<ResourceRecord> = additional.into_iter().collect(); - let message = Message::new( - id, - flags, - questions, - &mut answers, - &mut [], - &mut additional); - - let mut data_buf = [0; 4096]; - // Serialize the message into the buffer - assert!(message.space_needed() <= data_buf.len()); - - info!("ready to send to {:?}", endpoint); - - match message.write(&mut data_buf) { - Result::Ok(len) => { - if let Result::Err(x) = sock.send_to(&data_buf[..len], endpoint).await { - info!("sock.send failed: {:?}", x); - } - }, - Result::Err(err) => { - error!("message.write {:?}", err); - } - } -} - -async fn send_responses(sock: &UdpSocket<'_>, - db: &DnsDatabase, - message: &Message<'_,'_>, - meta: &UdpMetadata) { - - let q_id = message.id(); - - // for each relevant question we want to add RRs (as answers - // or additional) to the reply packet. I'm uncertain whether - // it's ok to do this for legacy queries but they probably - // don't have multiple questions anyway - for q in message.questions() { - let relevant = db.find(q.name().to_string(), q.ty()); - if relevant.len() > 0 { - log::info!("question {:?} {:?} {:?} flags {:?} from {:?}", - q.name(), q.ty(), q.class(), - message.flags().raw(), - meta.endpoint); - - send_response(&sock, q_id, MDNS_ENDPOINT, &db, None, relevant).await - } - - - if q.name().eq(&Label::from("&my_hostname")) { - // if meta.endpoint.port == 5353 { - // send_advert(&sock, q_id, MDNS_ENDPOINT, None, &my_address).await; - // } else if (q.class() & 0x8000) != 0 { - // log::info!("unicast"); - // send_advert(&sock, q_id, meta.endpoint, None, &my_address).await; - // } else { - // // legacy unicast, send questions - // send_advert(&sock, q_id, meta.endpoint, Some(q), &my_address).await; - // } - // log::info!("IT ME"); - } - } -} pub async fn start_wifi(spawner: &Spawner, wifi_peripheral: esp_hal::peripherals::WIFI<'static>) -> ! { @@ -453,42 +456,11 @@ pub async fn start_wifi(spawner: &Spawner, &mut tx_buffer, my_address); - let mut data_buf = [0; 4096]; - - let dns_db = &mdns_responder.database; - let sock = mdns_responder.sock(); - mdns_responder.advertise().await; loop { if mdns_responder.may_recv() { - let mut questions = [Question::default(); 64]; - let mut answers = [ResourceRecord::default(); 64]; - let mut authorities = [ResourceRecord::default(); 64]; - let mut addl = [ResourceRecord::default(); 64]; - - let res = sock.recv_from(&mut data_buf).await; - if let Ok((n, meta)) = res { - // log::info!("received packet len {n}"); - let message = Message::read( - &data_buf[..n], - &mut questions, - &mut answers, - &mut authorities, - &mut addl, - ); - - match message { - Result::Ok(message) => { - send_responses(&sock, &dns_db, &message, &meta).await; - }, - Result::Err(err) => { - log::error!("parsing dns message from {:?} : {:?}", - meta.endpoint, - err); - } - } - } + mdns_responder.process_packet().await; } Timer::after(Duration::from_millis(80)).await;