multicast_discovery_socket/
interfaces.rs1use 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 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}