multicast_discovery_socket/
interfaces.rs1use std::collections::HashMap;
2use std::net::{IpAddr, Ipv4Addr};
3use log::info;
4
5pub use if_addrs::Interface;
6
7pub struct InterfaceTracker<D> {
8 interfaces: HashMap<Ipv4Addr, (Interface, D)>,
9}
10
11impl<D: Default> InterfaceTracker<D> {
12 pub fn new() -> Self {
13 Self {
14 interfaces: get_ipv4_interfaces()
15 .map(|i| (i.0, (i.1, D::default())))
16 .collect(),
17 }
18 }
19 pub fn iter_mut(&mut self) -> impl Iterator<Item=(&Interface, &mut D)> {
20 self.interfaces.values_mut()
21 .map(|(i, d)| (&*i, d))
22 }
23
24 pub fn iter_mapping(&self) -> impl Iterator<Item=(u32, Ipv4Addr)> {
26 self.interfaces.iter()
27 .filter_map(|(ip, i)| i.0.index.map(|i| (i, *ip)))
28 }
29
30 pub fn poll_updates(&mut self, mut on_new_ip: impl FnMut(Ipv4Addr)) {
31 let mut original_ips: Vec<Ipv4Addr> = self.interfaces.keys().cloned().collect();
32 for (new_ip, new_interface) in get_ipv4_interfaces() {
33 if let Some(pos) = original_ips.iter().position(|x| *x == new_ip) {
34 original_ips.swap_remove(pos);
35 }
36 if let Some((interface, _)) = self.interfaces.get_mut(&new_ip) {
37 if interface != &new_interface {
38 if interface.name != new_interface.name {
39 info!("[{:?}] Interface name updated: {:?} -> {:?}", new_ip, interface.name, new_interface.name);
40 }
41 if interface.index != new_interface.index {
42 info!("[{:?}] Interface index updated: {:?} -> {:?}", new_ip, interface.index, new_interface.index);
43 }
44 *interface = new_interface;
45 }
46 }
47 else {
48 info!("New interface added: [{:?}] - {}", new_interface.ip(), new_interface.name);
49 on_new_ip(new_ip);
50 self.interfaces.insert(new_ip, (new_interface, D::default()));
51 }
52 }
53
54 for interface in original_ips {
55 info!("Interface removed: [{interface:?}]");
56 self.interfaces.remove(&interface);
57 }
58 }
59}
60
61fn get_ipv4_interfaces() -> impl Iterator<Item=(Ipv4Addr, Interface)> {
62 if_addrs::get_if_addrs()
63 .unwrap_or_default()
64 .into_iter()
65 .filter_map(|i| {
66 if let IpAddr::V4(ip) = &i.ip() {
67 if ip.is_private() {
68 Some((*ip, i))
69 }
70 else {
71 None
72 }
73 }
74 else {
75 None
76 }
77 })
78}