multicast_discovery_socket/
interfaces.rs

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