1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
//! # rtc-mdns
//!
//! A sans-I/O implementation of mDNS (Multicast DNS) for Rust.
//!
//! This crate provides an mDNS client/server that implements the [`sansio::Protocol`] trait,
//! allowing it to be integrated with any I/O framework (tokio, async-std, smol, or synchronous I/O).
//!
//! ## What is mDNS?
//!
//! Multicast DNS (mDNS) is a protocol that allows devices on a local network to discover
//! each other without a central DNS server. It's commonly used for:
//!
//! - Service discovery (finding printers, media servers, etc.)
//! - WebRTC ICE candidate gathering (resolving `.local` hostnames)
//! - Zero-configuration networking (Bonjour, Avahi)
//!
//! ## Sans-I/O Design
//!
//! This crate follows the [sans-I/O](https://sans-io.readthedocs.io/) pattern, which means:
//!
//! - **No runtime dependency**: Works with tokio, async-std, smol, or blocking I/O
//! - **Testable**: Protocol logic can be tested without network I/O
//! - **Predictable**: No hidden threads, timers, or background tasks
//! - **Composable**: Easy to integrate with existing event loops
//!
//! The caller is responsible for:
//! 1. Reading packets from the network and calling `handle_read()`
//! 2. Sending packets returned by `poll_write()`
//! 3. Calling `handle_timeout()` when `poll_timeout()` expires
//! 4. Processing events from `poll_event()`
//!
//! ## Features
//!
//! - **Query Support**: Send mDNS queries and receive answers
//! - **Server Support**: Respond to mDNS questions for configured local names
//! - **Automatic Retries**: Queries are automatically retried at configurable intervals
//! - **Multiple Queries**: Track multiple concurrent queries by ID
//!
//! ## Quick Start
//!
//! ### Client: Query for a hostname
//!
//! ```rust
//! use rtc_mdns::{MdnsConfig, Mdns, MdnsEvent};
//! use sansio::Protocol;
//! use std::time::{Duration, Instant};
//!
//! // Create an mDNS connection
//! let config = MdnsConfig::default()
//! .with_query_interval(Duration::from_secs(1));
//! let mut conn = Mdns::new(config);
//!
//! // Start a query - returns a unique ID to track this query
//! let query_id = conn.query("mydevice.local");
//! assert!(conn.is_query_pending(query_id));
//!
//! // Get the packet to send (would be sent via UDP to 224.0.0.251:5353)
//! let packet = conn.poll_write().expect("should have a query packet");
//! assert_eq!(packet.transport.peer_addr.to_string(), "224.0.0.251:5353");
//!
//! // When a response arrives, call handle_read() and check for events
//! // Events will contain QueryAnswered with the resolved address
//! ```
//!
//! ### Server: Respond to queries
//!
//! ```rust
//! use rtc_mdns::{MdnsConfig, Mdns};
//! use std::net::{IpAddr, Ipv4Addr};
//!
//! // MdnsConfigure with local names to respond to
//! let config = MdnsConfig::default()
//! .with_local_names(vec!["myhost.local".to_string()])
//! .with_local_ip(
//! IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)),
//! );
//!
//! let conn = Mdns::new(config);
//!
//! // When queries for "myhost.local" arrive via handle_read(),
//! // the connection will automatically queue response packets
//! // that can be retrieved via poll_write()
//! ```
//!
//! ## Integration with Tokio
//!
//! Here's a complete example showing how to integrate with tokio:
//!
//! ```rust,ignore
//! use bytes::BytesMut;
//! use rtc_mdns::{MdnsConfig, Mdns, MdnsEvent, MDNS_DEST_ADDR};
//! use sansio::Protocol;
//! use shared::{TaggedBytesMut, TransportContext, TransportProtocol};
//! use std::net::SocketAddr;
//! use std::time::{Duration, Instant};
//! use tokio::net::UdpSocket;
//!
//! async fn run_mdns_query(name: &str) -> Option<SocketAddr> {
//! let bind_addr: SocketAddr = "0.0.0.0:5353".parse().unwrap();
//! let socket = UdpSocket::bind(bind_addr).await.unwrap();
//!
//! let mut conn = Mdns::new(MdnsConfig::default());
//! let query_id = conn.query(name);
//!
//! let timeout = Instant::now() + Duration::from_secs(5);
//! let mut buf = vec![0u8; 1500];
//!
//! loop {
//! // Send queued packets
//! while let Some(pkt) = conn.poll_write() {
//! socket.send_to(&pkt.message, pkt.transport.peer_addr).await.ok();
//! }
//!
//! if Instant::now() >= timeout {
//! return None; // Query timed out
//! }
//!
//! // Wait for packets or timeout
//! tokio::select! {
//! Ok((len, src)) = socket.recv_from(&mut buf) => {
//! let msg = TaggedBytesMut {
//! now: Instant::now(),
//! transport: TransportContext {
//! local_addr: bind_addr,
//! peer_addr: src,
//! transport_protocol: TransportProtocol::UDP,
//! ecn: None,
//! },
//! message: BytesMut::from(&buf[..len]),
//! };
//! conn.handle_read(msg).ok();
//! }
//! _ = tokio::time::sleep(Duration::from_millis(100)) => {
//! conn.handle_timeout(Instant::now()).ok();
//! }
//! }
//!
//! // Check for answers
//! while let Some(event) = conn.poll_event() {
//! if let MdnsEvent::QueryAnswered(id, addr) = event {
//! if id == query_id {
//! return Some(addr);
//! }
//! }
//! }
//! }
//! }
//! ```
//!
//! ## Event Loop Pattern
//!
//! The typical event loop for using this crate:
//!
//! ```text
//! loop {
//! // 1. Send any queued packets
//! while let Some(packet) = conn.poll_write() {
//! socket.send_to(&packet.message, packet.transport.peer_addr);
//! }
//!
//! // 2. Wait for network activity or timeout
//! select! {
//! packet = socket.recv_from() => {
//! conn.handle_read(packet);
//! }
//! _ = sleep_until(conn.poll_timeout()) => {
//! conn.handle_timeout(Instant::now());
//! }
//! }
//!
//! // 3. Process events
//! while let Some(event) = conn.poll_event() {
//! match event {
//! MdnsEvent::QueryAnswered(id, addr) => { /* handle answer */ }
//! MdnsEvent::QueryTimeout(id) => { /* handle timeout */ }
//! }
//! }
//! }
//! ```
//!
//! ## Protocol Details
//!
//! - **Multicast Address**: 224.0.0.251:5353 (IPv4)
//! - **Record Types**: Supports A (IPv4) and AAAA (IPv6) queries
//! - **TTL**: Responses use a default TTL of 120 seconds
//! - **Compression**: DNS name compression is supported for efficiency
pub
pub
pub
pub
pub use MdnsConfig;
pub use ;
// Re-export socket utilities for convenience
pub use ifaces;
pub use MulticastSocket;