Skip to content

Commit

Permalink
Merge pull request #186 from ivmarkov/mdns-update
Browse files Browse the repository at this point in the history
mDNS: update domain lib; fix various issues
  • Loading branch information
kedars committed Jun 13, 2024
2 parents d337387 + d6f9c5e commit 3fbc047
Show file tree
Hide file tree
Showing 8 changed files with 845 additions and 244 deletions.
2 changes: 1 addition & 1 deletion examples/onoff_light/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ async fn run_mdns(matter: &Matter<'_>) -> Result<(), Error> {
.run_builtin_mdns(
&socket,
&socket,
Host {
&Host {
id: 0,
hostname: "rs-matter-demo",
ip: ipv4_addr.octets(),
Expand Down
6 changes: 2 additions & 4 deletions rs-matter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ readme = "README.md"
keywords = ["matter", "smart", "smart-home", "IoT", "ESP32"]
categories = ["embedded", "network-programming"]
license = "Apache-2.0"
rust-version = "1.77"
rust-version = "1.78"

[features]
default = ["os", "mbedtls"]
Expand All @@ -27,7 +27,6 @@ rs-matter-macros = { version = "0.1", path = "../rs-matter-macros" }
bitflags = { version = "2.5", default-features = false } # TODO: Update to 2.x
byteorder = { version = "1.5", default-features = false }
heapless = "0.8"
heapless07 = { package = "heapless", version = "0.7" } # Necessary for domain 0.9
num = { version = "0.4", default-features = false }
num-derive = "0.4"
num-traits = { version = "0.2", default-features = false }
Expand All @@ -42,8 +41,7 @@ embassy-futures = "0.1"
embassy-time = "0.3"
embassy-sync = "0.5"
critical-section = "1.1"
domain = { version = "0.9", default-features = false, features = ["heapless"] }
octseq = { version = "0.3", default-features = false }
domain = { version = "0.10", default-features = false, features = ["heapless"] }
portable-atomic = "1"
qrcodegen-no-heap = "1.8"
scopeguard = "1"
Expand Down
6 changes: 3 additions & 3 deletions rs-matter/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ impl<'a> Matter<'a> {
///
/// # Parameters
/// * dev_att: An object that implements the trait [DevAttDataFetcher]. Any Matter device
/// requires a set of device attestation certificates and keys. It is the responsibility of
/// this object to return the device attestation details when queried upon.
/// requires a set of device attestation certificates and keys. It is the responsibility of
/// this object to return the device attestation details when queried upon.
#[inline(always)]
pub const fn new(
dev_det: &'a BasicInfoConfig<'a>,
Expand Down Expand Up @@ -203,7 +203,7 @@ impl<'a> Matter<'a> {
&self,
send: S,
recv: R,
host: crate::mdns::Host<'_>,
host: &crate::mdns::Host<'_>,
interface: Option<u32>,
) -> Result<(), Error>
where
Expand Down
4 changes: 2 additions & 2 deletions rs-matter/src/data_model/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ where
/// The parameters are as follows:
/// * `buffers` - a reference to an implementation of `BufferAccess<IMBuffer>` which is used for allocating RX and TX buffers on the fly, when necessary
/// * `subscriptions` - a reference to a `Subscriptions<N>` struct which is used for managing subscriptions. `N` designates the maximum
/// number of subscriptions that can be managed by this handler.
/// number of subscriptions that can be managed by this handler.
/// * `handler` - an instance of type `T` which implements the `DataModelHandler` trait. This instance is used for interacting with the underlying
/// clusters of the data model.
/// clusters of the data model.
#[inline(always)]
pub const fn new(buffers: &'a B, subscriptions: &'a Subscriptions<N>, handler: T) -> Self {
Self {
Expand Down
6 changes: 3 additions & 3 deletions rs-matter/src/data_model/objects/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ impl EmptyHandler {
///
/// The returned chained handler works as follows:
/// - It will call the provided `handler` instance if the endpoint and cluster
/// of the incoming request do match the `handler_endpoint` and `handler_cluster` provided here.
/// of the incoming request do match the `handler_endpoint` and `handler_cluster` provided here.
/// - Otherwise, the empty handler would be invoked, causing the operation to error out.
pub const fn chain<H>(
self,
Expand Down Expand Up @@ -185,7 +185,7 @@ pub struct ChainedHandler<H, T> {
impl<H, T> ChainedHandler<H, T> {
/// Construct a chained handler that works as follows:
/// - It will call the provided `handler` instance if the endpoint and cluster
/// of the incoming request do match the `handler_endpoint` and `handler_cluster` provided here.
/// of the incoming request do match the `handler_endpoint` and `handler_cluster` provided here.
/// - Otherwise, it will call the `next` handler
pub const fn new(handler_endpoint: u16, handler_cluster: u32, handler: H, next: T) -> Self {
Self {
Expand All @@ -200,7 +200,7 @@ impl<H, T> ChainedHandler<H, T> {
///
/// The returned chained handler works as follows:
/// - It will call the provided `handler` instance if the endpoint and cluster
/// of the incoming request do match the `handler_endpoint` and `handler_cluster` provided here.
/// of the incoming request do match the `handler_endpoint` and `handler_cluster` provided here.
/// - Otherwise, it will call the `self` handler
pub const fn chain<H2>(
self,
Expand Down
70 changes: 51 additions & 19 deletions rs-matter/src/mdns/builtin.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use core::{cell::RefCell, pin::pin};
use core::cell::RefCell;
use core::net::IpAddr;
use core::pin::pin;

use embassy_futures::select::select;
use embassy_sync::blocking_mutex::raw::{NoopRawMutex, RawMutex};
Expand All @@ -12,6 +14,7 @@ use crate::transport::network::{
Address, Ipv4Addr, Ipv6Addr, NetworkReceive, NetworkSend, SocketAddr, SocketAddrV4,
SocketAddrV6,
};
use crate::utils::rand::Rand;
use crate::utils::{buf::BufferAccess, notification::Notification, select::Coalesce};

use super::{Service, ServiceMode};
Expand Down Expand Up @@ -91,14 +94,16 @@ impl<'a> MdnsImpl<'a> {
Ok(())
}

#[allow(clippy::too_many_arguments)]
pub async fn run<S, R, SB, RB>(
&self,
send: S,
recv: R,
tx_buf: SB,
rx_buf: RB,
host: Host<'_>,
host: &Host<'_>,
interface: Option<u32>,
rand: Rand,
) -> Result<(), Error>
where
S: NetworkSend,
Expand All @@ -108,8 +113,8 @@ impl<'a> MdnsImpl<'a> {
{
let send = Mutex::<NoopRawMutex, _>::new(send);

let mut broadcast = pin!(self.broadcast(&send, &tx_buf, &host, interface));
let mut respond = pin!(self.respond(&send, recv, &tx_buf, &rx_buf, &host, interface));
let mut broadcast = pin!(self.broadcast(&send, &tx_buf, host, interface));
let mut respond = pin!(self.respond(&send, recv, &tx_buf, &rx_buf, host, interface, rand));

select(&mut broadcast, &mut respond).coalesce().await
}
Expand Down Expand Up @@ -160,14 +165,16 @@ impl<'a> MdnsImpl<'a> {
}
}

#[allow(clippy::too_many_arguments)]
async fn respond<S, R, SB, RB>(
&self,
send: &Mutex<impl RawMutex, S>,
mut recv: R,
tx_buf: SB,
rx_buf: RB,
host: &Host<'_>,
_interface: Option<u32>,
interface: Option<u32>,
rand: Rand,
) -> Result<(), Error>
where
S: NetworkSend,
Expand All @@ -185,28 +192,53 @@ impl<'a> MdnsImpl<'a> {
let mut tx = tx_buf.get().await.ok_or(ErrorCode::NoSpace)?;
let mut send = send.lock().await;

let len = match host.respond(self, &rx[..len], &mut tx, 60) {
Ok(len) => len,
let (len, delay) = match host.respond(self, &rx[..len], &mut tx, 60) {
Ok((len, delay)) => (len, delay),
Err(err) => {
warn!("mDNS protocol error {err} while replying to {addr}");
continue;
}
};

if len > 0 {
info!("Replying to mDNS query from {addr}");

match send.send_to(&tx[..len], addr).await {
Ok(_) => (),
Err(err) => {
// Turns out we might receive queries from Ipv6 addresses which are actually unreachable by us
// Still to be investigated why, but it does seem that we are receiving packets which contain
// non-link-local Ipv6 addresses, to which we cannot respond
//
// A possible reason for this might be that we are receiving these packets via the broadcast group
// - yet - it is still unclear how these arrive given that we are only listening on the link-local address
warn!("IO error {err:?} while replying to {addr}");
let ipv4 = addr
.udp()
.map(|addr| matches!(addr.ip(), IpAddr::V4(_)))
.unwrap_or(true);

let reply_addr = if ipv4 {
Some(SocketAddr::V4(SocketAddrV4::new(
MDNS_IPV4_BROADCAST_ADDR,
MDNS_PORT,
)))
} else {
interface.map(|interface| {
SocketAddr::V6(SocketAddrV6::new(
MDNS_IPV6_BROADCAST_ADDR,
MDNS_PORT,
0,
interface,
))
})
};

if let Some(reply_addr) = reply_addr {
if delay {
let mut b = [0];
rand(&mut b);

// Generate a delay between 20 and 120 ms, as per spec
let delay_ms = 20 + (b[0] as u32 * 100 / 256);

info!("Replying to mDNS query from {addr} on {reply_addr}, delay {delay_ms}ms");
Timer::after(Duration::from_millis(delay_ms as _)).await;
} else {
info!("Replying to mDNS query from {addr} on {reply_addr}");
}

send.send_to(&tx[..len], Address::Udp(reply_addr)).await?;
} else {
info!("Cannot reply to mDNS query from {addr}: no suitable broadcast address found");
}
}
}
Expand Down
Loading

0 comments on commit 3fbc047

Please sign in to comment.