eculocate

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

commit 604e227bba685c7a51cafaf881adcc01d79cbee6
parent 68d65ebf2faa018388e10fa7d63eb307bbc436c2
Author: Daniel Barlow <dan@telent.net>
Date:   Sun,  7 Dec 2025 18:02:10 +0000

use mdns to publish our hostname

this is not spec-compliant, but it works

Diffstat:
MCargo.lock | 10++++++++++
MCargo.toml | 8+++++++-
Msrc/wifi.rs | 158++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
3 files changed, 133 insertions(+), 43 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -272,6 +272,15 @@ dependencies = [ ] [[package]] +name = "dns-protocol" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96e95919581371ae96cbf05b0aeec65cdc20bd3a2dca282ab6af808fbddaddb4" +dependencies = [ + "memchr", +] + +[[package]] name = "document-features" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -286,6 +295,7 @@ version = "0.1.0" dependencies = [ "bleps", "bt-hci", + "dns-protocol", "embassy-executor", "embassy-futures", "embassy-net", diff --git a/Cargo.toml b/Cargo.toml @@ -62,9 +62,15 @@ trouble-host = { version = "0.5.0", features = [ "derive", "scan", ] } embassy-net = { version = "0.7.1", features = [ -"medium-ethernet", "proto-ipv4", "tcp", "dhcpv4", + "medium-ethernet", "proto-ipv4", "tcp", "dhcpv4", "udp", + "dns", "mdns", "multicast" ] } +dns-protocol = { version = "0.1.2", default-features = false, features = [ + # no "std" feature +] } + + [profile.dev] # Rust debug is too slow. diff --git a/src/wifi.rs b/src/wifi.rs @@ -1,22 +1,22 @@ //! Set SSID and PASSWORD env variable before running this example. //! -//! This gets an ip address via DHCP then performs an HTTP get request to some -//! "random" server +//! This gets an ip address via DHCP and advertises it with mdns -use core::net::Ipv4Addr; - use embassy_executor::Spawner; -use embassy_net::{Runner, StackResources, tcp::TcpSocket}; +use embassy_net::{ + Runner, + StackResources, + udp::{PacketMetadata, UdpSocket}, + IpAddress, + IpEndpoint +}; + use embassy_time::{Duration, Timer}; use esp_alloc as _; use esp_backtrace as _; use esp_hal::{ - // clock::CpuClock, - // interrupt::software::SoftwareInterruptControl, - // ram, rng::Rng, - // timer::timg::TimerGroup, }; use esp_println::println; use esp_radio::{ @@ -32,6 +32,11 @@ use esp_radio::{ }, }; + +use dns_protocol::{Message, Question, + MessageType, + 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 macro_rules! mk_static { ($t:ty,$val:expr) => {{ @@ -45,6 +50,11 @@ macro_rules! mk_static { const SSID: &str = env!("SSID"); const PASSWORD: &str = env!("PASSWORD"); +const MDNS_IP: IpAddress = IpAddress::v4(224, 0, 0, 251); +const MDNS_PORT: u16 = 5353; +const MDNS_ENDPOINT: IpEndpoint = IpEndpoint::new(MDNS_IP, MDNS_PORT); + + pub async fn start_wifi(spawner: &Spawner, wifi_peripheral: esp_hal::peripherals::WIFI<'static>) -> ! { @@ -74,6 +84,7 @@ pub async fn start_wifi(spawner: &Spawner, let mut rx_buffer = [0; 4096]; let mut tx_buffer = [0; 4096]; + let my_address; loop { if stack.is_link_up() { @@ -86,51 +97,114 @@ pub async fn start_wifi(spawner: &Spawner, loop { if let Some(config) = stack.config_v4() { println!("Got IP: {}", config.address); + my_address = config.address.address().octets(); break; } Timer::after(Duration::from_millis(500)).await; } + let mut rx_meta = [PacketMetadata::EMPTY; 512]; + let mut tx_meta = [PacketMetadata::EMPTY; 512]; + let mut sock = UdpSocket::new( + stack, + &mut rx_meta, + &mut rx_buffer, + &mut tx_meta, + &mut tx_buffer, + ); + + log::info!("sock.bind(5353) res: {:?}", sock.bind(MDNS_PORT)); + log::info!( + "multicast_res: {:?}", + stack.join_multicast_group(MDNS_IP) + ); + + let mut answer = [ + ResourceRecord::new( + "eculogical.local", + ResourceType::A, + 1, // class + 60, // ttl + &my_address + ) + ]; + + let mut flags = Flags::new(); + flags.set_qr(MessageType::Reply); + flags.set_authoritative(true); + + // RFC: Multicast DNS responses MUST NOT contain any questions in the + // RFC: Question Section. + + let message = Message::new((rng.random() as u16), + flags, + &mut [], + &mut answer, + &mut [], + &mut []); + + + let mut data_buf = [0; 4096]; + // Serialize the message into the buffer + assert!(message.space_needed() <= data_buf.len()); + loop { - Timer::after(Duration::from_millis(1_000)).await; + match message.write(&mut data_buf) { + Result::Ok(len) => { + log::info!("sock.send: {:?}", sock.send_to(&data_buf[..len], MDNS_ENDPOINT).await); + }, + Result::Err(err) => { + log::error!("message.write {:?}", err); + } + } - let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + if sock.may_recv() { - socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); + let mut questions = [Question::default(); 16]; + let mut answers = [ResourceRecord::default(); 16]; + let mut authorities = [ResourceRecord::default(); 16]; + let mut addl = [ResourceRecord::default(); 16]; - let remote_endpoint = (Ipv4Addr::new(142, 250, 185, 115), 80); - println!("connecting..."); - let r = socket.connect(remote_endpoint).await; - if let Err(e) = r { - println!("connect error: {:?}", e); - continue; - } - println!("connected!"); - let mut buf = [0; 1024]; - loop { - use embedded_io_async::Write; - let r = socket - .write(b"GET / HTTP/1.0\r\nHost: www.mobile-j.de\r\n\r\n") - .await; - if let Err(e) = r { - println!("write error: {:?}", e); - break; + let res = sock.recv_from(&mut data_buf).await; + if let Ok((n, _endpoint)) = 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) => { + log::info!("message receivefd"); + for q in message.questions() { + log::info!("question {:?}", q.name()); + } + + for q in message.answers() { + log::info!("answer {:?}", q.data()); + } + }, + Result::Err(err) => { + log::error!("parsing dns message: {:?}", err); + } + } } - let n = match socket.read(&mut buf).await { - Ok(0) => { - println!("read EOF"); - break; - } - Ok(n) => n, - Err(e) => { - println!("read error: {:?}", e); - break; - } - }; - println!("{}", core::str::from_utf8(&buf[..n]).unwrap()); } - Timer::after(Duration::from_millis(3000)).await; + + Timer::after(Duration::from_millis(30 * 1000)).await; } + + // _ = stack.leave_multicast_group(MDNS_IP); + // sock.close(); + // drop(sock); + + // loop { + // Timer::after(Duration::from_millis(1_000)).await; + // log::info!("bump"); + // } + } #[embassy_executor::task]