Skip to main content

Mdns

Struct Mdns 

Source
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:

  1. Calling handle_read() when packets arrive
  2. Sending packets from poll_write()
  3. Calling handle_timeout() on schedule
  4. 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

Source

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)),
        )
);
Source

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:

§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));
Source

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 by query()
§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));
Source

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 by query()
§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));
Source

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

Source§

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>

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<()>

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>

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<()>

Handle external events (not used).

mDNS does not use external events. This method does nothing.

Source§

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:

§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<()>

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>

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 retries
  • None if 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<()>

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());
Source§

type Rout = ()

Output read message type Read more
Source§

type Wout = TransportMessage<BytesMut>

Output write message type Read more
Source§

type Eout = MdnsEvent

Output event type Read more
Source§

type Error = Error

Error type for protocol operations
Source§

type Time = Instant

Time/Instant type for timeout handling Read more

Auto Trait Implementations§

§

impl Freeze for Mdns

§

impl RefUnwindSafe for Mdns

§

impl Send for Mdns

§

impl Sync for Mdns

§

impl Unpin for Mdns

§

impl UnwindSafe for Mdns

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

Source§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

Source§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

Source§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V