1pub mod addr;
19pub mod gather;
20pub mod ifaces;
21pub mod portmap;
22pub mod socket;
23pub mod stun;
24
25pub use addr::{format_host, is_global};
26pub use gather::{gather, Candidate, GatherOpts, Gathered, Hint, NatReport};
27pub use portmap::{map_port, renew, MapProtocol, PortMapping};
28pub use socket::bind_sockets;
29pub use stun::{discover, NatDiscovery, NatType};
30
31pub struct NetworkWatch {
33 pub events: tokio::sync::mpsc::Receiver<String>,
35 pub force: tokio::sync::mpsc::Sender<String>,
38}
39
40pub fn watch_network_changes() -> NetworkWatch {
45 watch_network_changes_with(ifaces::interfaces, std::time::Duration::from_secs(10))
46}
47
48pub fn watch_network_changes_with<F>(mut provider: F, period: std::time::Duration) -> NetworkWatch
50where
51 F: FnMut() -> Vec<std::net::IpAddr> + Send + 'static,
52{
53 let (ev_tx, events) = tokio::sync::mpsc::channel(4);
54 let (force, mut force_rx) = tokio::sync::mpsc::channel::<String>(4);
55 let keep = force.clone();
58 tokio::spawn(async move {
59 let _keep = keep;
60 let mut prev: std::collections::BTreeSet<std::net::IpAddr> =
61 provider().into_iter().collect();
62 let mut tick = tokio::time::interval(period);
63 tick.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
64 tick.tick().await; loop {
66 tokio::select! {
67 _ = tick.tick() => {
68 let now: std::collections::BTreeSet<std::net::IpAddr> =
69 provider().into_iter().collect();
70 if now != prev {
71 let added = now.difference(&prev).count();
72 let removed = prev.difference(&now).count();
73 prev = now;
74 let _ = ev_tx.try_send(format!(
77 "interface addresses changed (+{added} -{removed})"
78 ));
79 }
80 }
81 reason = force_rx.recv() => {
82 if let Some(reason) = reason {
83 let _ = ev_tx.try_send(reason);
84 }
85 }
86 }
87 }
88 });
89 NetworkWatch { events, force }
90}
91
92#[cfg(test)]
93mod watch_tests {
94 use std::net::IpAddr;
95 use std::sync::{Arc, Mutex};
96 use std::time::Duration;
97
98 #[tokio::test]
99 async fn fires_on_address_change_and_force_only() {
100 let addrs: Arc<Mutex<Vec<IpAddr>>> =
101 Arc::new(Mutex::new(vec!["192.168.1.2".parse().unwrap()]));
102 let p = addrs.clone();
103 let mut w = super::watch_network_changes_with(
104 move || p.lock().unwrap().clone(),
105 Duration::from_millis(20),
106 );
107 assert!(
109 tokio::time::timeout(Duration::from_millis(120), w.events.recv())
110 .await
111 .is_err(),
112 "no event expected while addresses are stable"
113 );
114 addrs.lock().unwrap().push("10.0.0.7".parse().unwrap());
116 let reason = tokio::time::timeout(Duration::from_millis(500), w.events.recv())
117 .await
118 .expect("event expected after change")
119 .unwrap();
120 assert!(reason.contains("+1"), "{reason}");
121 w.force.send("renewal failed".into()).await.unwrap();
123 let reason = tokio::time::timeout(Duration::from_millis(500), w.events.recv())
124 .await
125 .expect("forced event expected")
126 .unwrap();
127 assert_eq!(reason, "renewal failed");
128 }
129}