1use std::io;
2use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, UdpSocket};
3use std::sync::{Arc, Barrier};
4use std::sync::atomic::{AtomicBool, Ordering};
5use std::thread::{self, JoinHandle};
6use std::time::Duration;
7
8use socket2::{Domain, Protocol, SockAddr, Socket, Type};
9
10lazy_static! {
11 pub static ref STOP: &'static str = "stop";
14}
15
16fn new_socket(addr: &SocketAddr) -> io::Result<Socket> {
18 let domain = if addr.is_ipv4() {
19 Domain::ipv4()
20 } else {
21 Domain::ipv6()
22 };
23
24 let socket = Socket::new(domain, Type::dgram(), Some(Protocol::udp()))?;
25
26 socket.set_read_timeout(Some(Duration::from_millis(100)))?;
28
29 Ok(socket)
30}
31
32#[cfg(windows)]
36fn bind_multicast(socket: &Socket, addr: &SocketAddr) -> io::Result<()> {
37 let addr = match *addr {
38 SocketAddr::V4(addr) => SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), addr.port()),
39 SocketAddr::V6(addr) => {
40 SocketAddr::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).into(), addr.port())
41 }
42 };
43 socket.bind(&socket2::SockAddr::from(addr))
44}
45
46#[cfg(unix)]
48fn bind_multicast(socket: &Socket, addr: &SocketAddr) -> io::Result<()> {
49 socket.bind(&socket2::SockAddr::from(*addr))
50}
51
52fn join_multicast(addr: SocketAddr) -> io::Result<UdpSocket> {
53 let ip_addr = addr.ip();
54
55 let socket = new_socket(&addr)?;
56
57 match ip_addr {
59 IpAddr::V4(ref mdns_v4) => {
60 socket.join_multicast_v4(mdns_v4, &Ipv4Addr::new(0, 0, 0, 0))?;
62 }
63 IpAddr::V6(ref mdns_v6) => {
64 socket.join_multicast_v6(mdns_v6, 0)?;
66 socket.set_only_v6(true)?;
67 }
68 };
69
70 socket.set_reuse_address(true);
71
72 #[cfg(unix)]
73 socket.set_reuse_port(true);
74
75 #[cfg(unix)]
76 info!("Warning: Cannot set reuse of ports on Windows.");
77
78 bind_multicast(&socket, &addr)?;
80
81 Ok(socket.into_udp_socket())
83}
84
85pub fn multicast_listener(
86 addr: SocketAddr,
87) -> JoinHandle<()> {
88 let server_barrier = Arc::new(Barrier::new(2));
90 let client_barrier = Arc::clone(&server_barrier);
91
92 let join_handle = std::thread::Builder::new()
93 .name(format!("dot:listener"))
94 .spawn(move || {
95 let listener = join_multicast(addr).expect("failed to create listener");
97 println!("dot:listener: joined: {}", addr);
98
99 server_barrier.wait();
100 println!("dot:listener: is ready");
101
102 let mut stop = false;
103 while !stop {
105 let mut buf = [0u8; 1024]; match listener.recv_from(&mut buf) {
109 Ok((len, remote_addr)) => {
110 let data = &buf[..len];
111
112 if *STOP.as_bytes() == *data.clone() {
114 stop = true;
115 }
116
117 println!(
118 "dot:listener: received request: {} from: {}",
119 String::from_utf8_lossy(data),
120 remote_addr
121 );
122 }
123 Err(err) => {
124 }
126 }
127 }
128
129 println!("dot:listener: stopped!");
130 })
131 .unwrap();
132
133 client_barrier.wait();
134 join_handle
135}
136
137pub fn new_sender(addr: &SocketAddr) -> io::Result<UdpSocket> {
138 let socket = new_socket(addr)?;
139
140 if addr.is_ipv4() {
141 socket.set_multicast_if_v4(&Ipv4Addr::new(0, 0, 0, 0))?;
142
143 socket.bind(&SockAddr::from(SocketAddr::new(
144 Ipv4Addr::new(0, 0, 0, 0).into(),
145 0,
146 )))?;
147 } else {
148 socket.set_multicast_if_v6(5)?;
151
152 socket.bind(&SockAddr::from(SocketAddr::new(
153 Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).into(),
154 0,
155 )))?;
156 }
157
158 Ok(socket.into_udp_socket())
160}