1mod broadcast;
2mod constants;
3mod packet;
4mod query;
5mod socket;
6
7use std::io;
8use std::net::Ipv4Addr;
9use std::sync::Arc;
10use std::time::Duration;
11use socket2::Socket;
12use tokio::sync::mpsc;
13
14use socket::{create_send_socket, create_recv_socket};
15
16#[derive(Debug, Clone, PartialEq)]
18pub struct MdnsResponse {
19 pub hostname: String,
21 pub ip: Ipv4Addr,
23}
24
25pub struct MdnsHandle {
27 send_socket: Arc<Socket>,
28 domain: String,
29 pub discoveries: mpsc::Receiver<MdnsResponse>,
31 pub responses: mpsc::Receiver<MdnsResponse>,
33}
34
35impl MdnsHandle {
36 pub async fn query(&self, hostname: &str) {
42 query::query(&self.send_socket, hostname, &self.domain).await;
43 }
44}
45
46pub struct Mdns {
48 name: String,
49 domain: String,
50 broadcast_interval: Duration,
51 send_socket: Arc<Socket>,
52 recv_socket: Arc<Socket>,
53 local_ip: Ipv4Addr,
54}
55
56impl Mdns {
57 pub fn new<S: Into<String>>(name: S, ip: Ipv4Addr) -> io::Result<Self> {
73 Self::with_interval(name, ip, Duration::from_secs(120))
74 }
75
76 pub fn with_interval<S: Into<String>>(name: S, ip: Ipv4Addr, interval: Duration) -> io::Result<Self> {
84 let send_socket = create_send_socket()?;
85 let recv_socket = create_recv_socket()?;
86
87 Ok(Self {
88 name: name.into(),
89 domain: "local".to_string(),
90 broadcast_interval: interval,
91 send_socket: Arc::new(send_socket),
92 recv_socket: Arc::new(recv_socket),
93 local_ip: ip,
94 })
95 }
96
97 pub fn with_domain<S: Into<String>>(mut self, domain: S) -> Self {
103 self.domain = domain.into();
104 self
105 }
106
107 pub fn name(&self) -> &str {
109 &self.name
110 }
111
112 pub fn broadcast_interval(&self) -> Duration {
114 self.broadcast_interval
115 }
116
117 pub fn run(self) -> MdnsHandle {
123 let (disc_tx, disc_rx) = mpsc::channel(100);
124 let (resp_tx, resp_rx) = mpsc::channel(100);
125
126 let send_socket = self.send_socket.clone();
127 let recv_socket = self.recv_socket.clone();
128 let name = Arc::new(self.name);
129 let domain = Arc::new(self.domain.clone());
130 let local_ip = self.local_ip;
131 let broadcast_interval = self.broadcast_interval;
132
133 let send_socket_clone = send_socket.clone();
135 let name_clone = name.clone();
136 let domain_clone = domain.clone();
137 tokio::spawn(async move {
138 broadcast::broadcast_loop(&send_socket_clone, &name_clone, &domain_clone, local_ip, broadcast_interval).await;
139 });
140
141 let send_socket_clone = send_socket.clone();
143 let name_clone = name.clone();
144 let domain_clone = domain.clone();
145 tokio::spawn(async move {
146 query::listen(&recv_socket, &send_socket_clone, &name_clone, &domain_clone, local_ip, disc_tx, resp_tx).await;
147 });
148
149 MdnsHandle {
150 send_socket,
151 domain: self.domain,
152 discoveries: disc_rx,
153 responses: resp_rx,
154 }
155 }
156
157 pub fn local_ip(&self) -> Ipv4Addr {
159 self.local_ip
160 }
161
162 pub async fn goodbye(&self) {
167 broadcast::send_goodbye(&self.send_socket, &self.name, &self.domain, self.local_ip).await;
168 }
169}
170
171#[cfg(test)]
172mod tests {
173 use super::*;
174
175 #[test]
176 fn test_new_with_name() {
177 let ip = Ipv4Addr::new(192, 168, 1, 100);
178 let mdns = Mdns::new("myhost", ip).unwrap();
179 assert_eq!(mdns.name(), "myhost");
180 assert_eq!(mdns.local_ip(), ip);
181 assert_eq!(mdns.broadcast_interval(), Duration::from_secs(120));
182 }
183
184 #[test]
185 fn test_with_custom_interval() {
186 let ip = Ipv4Addr::new(10, 0, 0, 5);
187 let mdns = Mdns::with_interval("myhost", ip, Duration::from_secs(60)).unwrap();
188 assert_eq!(mdns.name(), "myhost");
189 assert_eq!(mdns.local_ip(), ip);
190 assert_eq!(mdns.broadcast_interval(), Duration::from_secs(60));
191 }
192}