oko_mdns/
lib.rs

1//! [Multicast DNS](https://en.wikipedia.org/wiki/Multicast_DNS) library with built-in networking.
2//!
3//! This crate can be used to discover mDNS devices that are listening
4//! on a network.
5//!
6//! # Basic usage
7//!
8//! This example finds all [Chromecast](https://en.wikipedia.org/wiki/Chromecast) devices on the
9//! same LAN as the executing computer.
10//!
11//! Once the devices are discovered, they respond with standard DNS records, with a few minor
12//! low-level protocol differences.
13//!
14//! The only Chromecast-specific piece of code here is the `SERVICE_NAME`. In order to discover
15//! other types of devices, simply change the service name to the one your device uses.
16//!
17//! This example obtains the IP addresses of the cast devices by looking up `A`/`AAAA` records.
18//!
19//! ```rust,no_run
20//! use futures_util::{pin_mut, stream::StreamExt};
21//! use mdns::{Error, Record, RecordKind};
22//! use std::{net::IpAddr, time::Duration};
23//!
24//! /// The hostname of the devices we are searching for.
25//! /// Every Chromecast will respond to the service name in this example.
26//! const SERVICE_NAME: &'static str = "_googlecast._tcp.local";
27//!
28//! #[cfg_attr(feature = "runtime-async-std", async_std::main)]
29//! #[cfg_attr(feature = "runtime-tokio", tokio::main)]
30//! async fn main() -> Result<(), Error> {
31//!     // Iterate through responses from each Cast device, asking for new devices every 15s
32//!     let stream = mdns::discover::all(SERVICE_NAME, Duration::from_secs(15))?.listen();
33//!     pin_mut!(stream);
34//!
35//!     while let Some(Ok(response)) = stream.next().await {
36//!         let addr = response.records()
37//!                            .filter_map(self::to_ip_addr)
38//!                            .next();
39//!
40//!         if let Some(addr) = addr {
41//!             println!("found cast device at {}", addr);
42//!         } else {
43//!             println!("cast device does not advertise address");
44//!         }
45//!     }
46//!
47//!     Ok(())
48//! }
49//!
50//! fn to_ip_addr(record: &Record) -> Option<IpAddr> {
51//!     match record.kind {
52//!         RecordKind::A(addr) => Some(addr.into()),
53//!         RecordKind::AAAA(addr) => Some(addr.into()),
54//!         _ => None,
55//!     }
56//! }
57//! ```
58
59#![recursion_limit = "1024"]
60
61#[cfg(all(feature = "runtime-async-std", feature = "runtime-tokio"))]
62compile_error!("\"runtime-async-std\" and \"runtime-tokio\" cannot be enabled simultaneously");
63
64#[cfg(not(any(feature = "runtime-async-std", feature = "runtime-tokio")))]
65compile_error!("At least one runtime (\"runtime-async-std\" or \"runtime-tokio\") cargo feature must be enabled");
66
67use std::net::SocketAddr;
68
69use async_trait::async_trait;
70use multicast_socket::MulticastSocket;
71
72pub use self::errors::Error;
73pub use self::response::{Record, RecordKind, Response, TxtRecordValue};
74
75pub mod discover;
76pub mod resolve;
77
78mod runtime;
79
80mod errors;
81mod mdns;
82mod response;
83
84pub(crate) enum IntermediateSocketType {
85    StdNetSocket(std::net::UdpSocket),
86    #[cfg(feature = "multihome")]
87    MultihomeSocket(MulticastSocket),
88}
89
90impl IntermediateSocket {
91    pub(crate) fn take_inner(self) -> IntermediateSocketType {
92        self.0
93    }
94}
95
96pub(crate) struct IntermediateSocket(IntermediateSocketType);
97
98impl From<std::net::UdpSocket> for IntermediateSocket {
99    fn from(value: std::net::UdpSocket) -> Self {
100        IntermediateSocket(IntermediateSocketType::StdNetSocket(value))
101    }
102}
103
104#[cfg(feature = "multihome")]
105impl From<multicast_socket::MulticastSocket> for IntermediateSocket {
106    fn from(value: multicast_socket::MulticastSocket) -> Self {
107        IntermediateSocket(IntermediateSocketType::MultihomeSocket(value))
108    }
109}
110
111#[async_trait]
112pub trait AsyncUdpSocket: Send + Clone {
113    async fn send_to(
114        &self,
115        buf: &[u8],
116        target: impl Into<SocketAddr> + Send,
117    ) -> std::io::Result<usize>;
118    async fn recv_from(&self, buf: &mut [u8]) -> std::io::Result<(usize, SocketAddr)>;
119}
120
121pub use self::mdns::mDNSListener;