multicast_discovery_socket/
interfaces.rs

1use 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    /// Iterate through index-ip_address pairs. The same index may be paired with multiple ip addresses!
25    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}