pub struct Mdns { /* private fields */ }Expand description
Sans-I/O mDNS Connection.
This implements a sans-I/O mDNS client/server that can:
- Send mDNS queries and receive answers
- Respond to mDNS questions for configured local names
§Sans-I/O Pattern
This struct implements sansio::Protocol, which means it doesn’t perform
any I/O itself. Instead, the caller is responsible for:
- Calling
handle_read()when packets arrive - Sending packets from
poll_write() - Calling
handle_timeout()on schedule - Processing events from
poll_event()
§Example: Complete Event Loop
use rtc_mdns::{MdnsConfig, Mdns, MdnsEvent};
use sansio::Protocol;
use std::time::{Duration, Instant};
let mut mdns = Mdns::new(MdnsConfig::default());
// Start a query
let query_id = mdns.query("device.local");
// Simulate an event loop iteration
let now = Instant::now();
// 1. Send queued packets (would go to network in real code)
while let Some(packet) = mdns.poll_write() {
println!("Would send {} bytes to {}", packet.message.len(), packet.transport.peer_addr);
}
// 2. Handle timeout if due
if let Some(deadline) = mdns.poll_timeout() {
if deadline <= now {
mdns.handle_timeout(now).ok();
}
}
// 3. Process any events
while let Some(event) = mdns.poll_event() {
match event {
MdnsEvent::QueryAnswered(query_id, addr) => {
println!("Query {} answered: {}", query_id, addr);
}
MdnsEvent::QueryTimeout(id) => {
println!("Query {} timed out", id);
}
}
}§Example: Multiple Concurrent Queries
use rtc_mdns::{MdnsConfig, Mdns};
use sansio::Protocol;
let mut mdns = Mdns::new(MdnsConfig::default());
// Start multiple queries - each gets a unique ID
let id1 = mdns.query("printer.local");
let id2 = mdns.query("server.local");
let id3 = mdns.query("nas.local");
assert_eq!(mdns.pending_query_count(), 3);
assert!(mdns.is_query_pending(id1));
assert!(mdns.is_query_pending(id2));
assert!(mdns.is_query_pending(id3));
// Cancel one query
mdns.cancel_query(id2);
assert_eq!(mdns.pending_query_count(), 2);
assert!(!mdns.is_query_pending(id2));Implementations§
Source§impl Mdns
impl Mdns
Sourcepub fn new(config: MdnsConfig) -> Self
pub fn new(config: MdnsConfig) -> Self
Create a new mDNS connection with the given configuration.
§Arguments
config- MdnsConfiguration for the connection
§Example
use rtc_mdns::{MdnsConfig, Mdns};
use std::time::Duration;
// Client-only configuration
let client = Mdns::new(MdnsConfig::default());
// Server configuration
use std::net::{IpAddr, Ipv4Addr};
let server = Mdns::new(
MdnsConfig::default()
.with_local_names(vec!["myhost.local".to_string()])
.with_local_ip(
IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)),
)
);Sourcepub fn query(&mut self, name: &str) -> QueryId
pub fn query(&mut self, name: &str) -> QueryId
Start a new mDNS query for the given name.
This method queues an mDNS query packet to be sent. The query will be automatically retried at the configured interval until either:
- An answer is received (emits
MdnsEvent::QueryAnswered) - The query times out (emits
MdnsEvent::QueryTimeoutifquery_timeoutis set) - The query is cancelled with
cancel_query() - The connection is closed
§Arguments
name- The hostname to query (e.g.,"mydevice.local")
§Returns
A unique QueryId that can be used to track this query.
§Example
use rtc_mdns::{MdnsConfig, Mdns, MdnsEvent};
use sansio::Protocol;
let mut mdns = Mdns::new(MdnsConfig::default());
// Start a query
let query_id = mdns.query("printer.local");
// The query packet is now queued
let packet = mdns.poll_write().expect("query packet should be queued");
assert_eq!(packet.transport.peer_addr.to_string(), "224.0.0.251:5353");
// Track the query
assert!(mdns.is_query_pending(query_id));Sourcepub fn cancel_query(&mut self, query_id: QueryId)
pub fn cancel_query(&mut self, query_id: QueryId)
Cancel a pending query.
Removes the query from the pending list. No more retry packets will be sent and no events will be emitted for this query.
§Arguments
query_id- The ID returned byquery()
§Example
use rtc_mdns::{MdnsConfig, Mdns};
let mut mdns = Mdns::new(MdnsConfig::default());
let query_id = mdns.query("device.local");
assert!(mdns.is_query_pending(query_id));
mdns.cancel_query(query_id);
assert!(!mdns.is_query_pending(query_id));Sourcepub fn is_query_pending(&self, query_id: QueryId) -> bool
pub fn is_query_pending(&self, query_id: QueryId) -> bool
Check if a query is still pending.
A query is pending until it is either answered or cancelled.
§Arguments
query_id- The ID returned byquery()
§Returns
true if the query is still waiting for an answer, false otherwise.
§Example
use rtc_mdns::{MdnsConfig, Mdns};
let mut mdns = Mdns::new(MdnsConfig::default());
let query_id = mdns.query("device.local");
// Query is pending until answered or cancelled
assert!(mdns.is_query_pending(query_id));Sourcepub fn pending_query_count(&self) -> usize
pub fn pending_query_count(&self) -> usize
Get the number of pending queries.
§Returns
The count of queries that are still waiting for answers.
§Example
use rtc_mdns::{MdnsConfig, Mdns};
let mut mdns = Mdns::new(MdnsConfig::default());
assert_eq!(mdns.pending_query_count(), 0);
mdns.query("device1.local");
mdns.query("device2.local");
assert_eq!(mdns.pending_query_count(), 2);Trait Implementations§
Source§impl Protocol<TransportMessage<BytesMut>, (), ()> for Mdns
impl Protocol<TransportMessage<BytesMut>, (), ()> for Mdns
Source§fn handle_read(&mut self, msg: TaggedBytesMut) -> Result<()>
fn handle_read(&mut self, msg: TaggedBytesMut) -> Result<()>
Process an incoming mDNS packet.
Call this method when a UDP packet is received on the mDNS multicast address (224.0.0.251:5353).
The connection will:
- Parse the packet as an mDNS message
- If it contains questions for our
local_names, queue response packets - If it contains answers matching pending queries, emit events
§Arguments
msg- The received packet with transport context
§Errors
Returns Error::ErrConnectionClosed if the connection has been closed.
§Example
use bytes::BytesMut;
use shared::{TaggedBytesMut, TransportContext, TransportProtocol};
use std::time::Instant;
// When a packet arrives from the network:
let msg = TaggedBytesMut {
now: Instant::now(),
transport: TransportContext {
local_addr: "0.0.0.0:5353".parse().unwrap(),
peer_addr: src_addr,
transport_protocol: TransportProtocol::UDP,
ecn: None,
},
message: BytesMut::from(&packet_data[..]),
};
mdns.handle_read(msg)?;
// Check for events
while let Some(event) = mdns.poll_event() {
// handle event
}Source§fn poll_read(&mut self) -> Option<Self::Rout>
fn poll_read(&mut self) -> Option<Self::Rout>
mDNS doesn’t produce read outputs.
Answers to queries are delivered via poll_event()
as MdnsEvent::QueryAnswered events instead.
§Returns
Always returns None.
Source§fn handle_write(&mut self, _msg: ()) -> Result<()>
fn handle_write(&mut self, _msg: ()) -> Result<()>
Handle write requests (not used).
Queries are initiated via the query() method instead
of through this interface.
Source§fn poll_write(&mut self) -> Option<Self::Wout>
fn poll_write(&mut self) -> Option<Self::Wout>
Get the next packet to send.
Call this method repeatedly until it returns None to retrieve all
queued packets. Packets should be sent via UDP to the address specified
in packet.transport.peer_addr (typically 224.0.0.251:5353).
Packets are queued when:
- A query is started with
query() - A query retry is triggered by
handle_timeout() - A response is generated for a matching question
§Returns
The next packet to send, or None if the queue is empty.
§Example
use rtc_mdns::{MdnsConfig, Mdns};
use sansio::Protocol;
let mut mdns = Mdns::new(MdnsConfig::default());
mdns.query("device.local");
// Send all queued packets
while let Some(packet) = mdns.poll_write() {
// socket.send_to(&packet.message, packet.transport.peer_addr).await?;
println!("Send to {}", packet.transport.peer_addr);
}Source§fn handle_event(&mut self, _evt: ()) -> Result<()>
fn handle_event(&mut self, _evt: ()) -> Result<()>
Handle external events (not used).
mDNS does not use external events. This method does nothing.
Source§fn poll_event(&mut self) -> Option<Self::Eout>
fn poll_event(&mut self) -> Option<Self::Eout>
Get the next event.
Call this method repeatedly until it returns None to process all
queued events. Events are generated when:
- An mDNS answer matches a pending query (
MdnsEvent::QueryAnswered)
§Returns
The next event, or None if the queue is empty.
§Example
while let Some(event) = mdns.poll_event() {
match event {
MdnsEvent::QueryAnswered(query_id, addr) => {
println!("Query {} resolved to {}", query_id, addr);
}
MdnsEvent::QueryTimeout(id) => {
println!("Query {} timed out", id);
}
}
}Source§fn handle_timeout(&mut self, now: Self::Time) -> Result<()>
fn handle_timeout(&mut self, now: Self::Time) -> Result<()>
Handle timeout - retry pending queries.
Call this method when the deadline from poll_timeout()
is reached. This triggers retry logic for pending queries.
For each query whose retry time has passed, a new query packet will
be queued and can be retrieved with poll_write().
§Arguments
now- The current time
§Errors
Returns Error::ErrConnectionClosed if the connection has been closed.
§Example
use rtc_mdns::{MdnsConfig, Mdns};
use sansio::Protocol;
use std::time::{Duration, Instant};
let mut mdns = Mdns::new(
MdnsConfig::default().with_query_interval(Duration::from_millis(100))
);
mdns.query("device.local");
// Consume initial packet
mdns.poll_write();
// Simulate time passing
let future = Instant::now() + Duration::from_millis(150);
mdns.handle_timeout(future).unwrap();
// A retry packet should be queued
assert!(mdns.poll_write().is_some());Source§fn poll_timeout(&mut self) -> Option<Self::Time>
fn poll_timeout(&mut self) -> Option<Self::Time>
Get the next timeout deadline.
Returns the time at which handle_timeout() should
be called next. Use this to schedule your event loop’s sleep/wait.
§Returns
Some(instant)if there are pending queries that need retriesNoneif there are no pending queries
§Example
use rtc_mdns::{MdnsConfig, Mdns};
use sansio::Protocol;
let mut mdns = Mdns::new(MdnsConfig::default());
// No queries, no timeout
assert!(mdns.poll_timeout().is_none());
// Start a query
mdns.query("device.local");
// Now there's a timeout scheduled
assert!(mdns.poll_timeout().is_some());Source§fn close(&mut self) -> Result<()>
fn close(&mut self) -> Result<()>
Close the connection.
This clears all pending queries and queued packets/events.
After closing, handle_read() and
handle_timeout() will return
Error::ErrConnectionClosed.
§Example
use rtc_mdns::{MdnsConfig, Mdns};
use sansio::Protocol;
let mut mdns = Mdns::new(MdnsConfig::default());
mdns.query("device.local");
assert_eq!(mdns.pending_query_count(), 1);
mdns.close().unwrap();
// All state is cleared
assert_eq!(mdns.pending_query_count(), 0);
assert!(mdns.poll_write().is_none());
assert!(mdns.poll_timeout().is_none());