Skip to content

Commit

Permalink
Add fallback.
Browse files Browse the repository at this point in the history
  • Loading branch information
dvc94ch committed Nov 30, 2020
1 parent 1b0aa48 commit c11b354
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 8 deletions.
14 changes: 8 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@ repository = "https://github.com/dvc94ch/if-watch"
[dependencies]
futures-lite = "1.11.2"
ipnet = "2.3.0"
libc = "0.2.66"
libc = "0.2.80"
log = "0.4.11"

[target.'cfg(unix)'.dependencies]
async-io = "1.2.0"
[target.'cfg(not(windows))'.dependencies]
async-io = "1.3.0"

[target.'cfg(not(target_os = "linux"))'.dependencies]
if-addrs = "0.6.5"

[target.'cfg(windows)'.dependencies]
futures = { version = "0.3.8", default-features = false }
if-addrs = "0.6.5"
winapi = { version = "0.3.8", features = ["netioapi", "ntdef", "winerror", "ws2def"] }
winapi = { version = "0.3.9", features = ["netioapi", "ntdef", "winerror", "ws2def"] }

[dev-dependencies]
env_logger = "0.8.1"
env_logger = "0.8.2"
82 changes: 82 additions & 0 deletions src/fallback.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use crate::IfEvent;
use async_io::Timer;
use futures_lite::StreamExt;
use if_addrs::IfAddr;
use ipnet::{IpNet, Ipv4Net, Ipv6Net};
use std::io::Result;
use std::{
collections::{HashSet, VecDeque},
time::{Duration, Instant},
};

/// An address set/watcher
#[derive(Debug)]
pub struct IfWatcher {
addrs: HashSet<IpNet>,
queue: VecDeque<IfEvent>,
ticker: Timer,
}

impl IfWatcher {
/// Create a watcher
pub async fn new() -> Result<Self> {
Ok(Self {
addrs: Default::default(),
queue: Default::default(),
ticker: Timer::interval_at(Instant::now(), Duration::from_secs(10)),
})
}

fn resync(&mut self) -> Result<()> {
let addrs = if_addrs::get_if_addrs()?;
for old_addr in self.addrs.clone() {
if addrs
.iter()
.find(|addr| addr.ip() == old_addr.addr())
.is_none()
{
self.addrs.remove(&old_addr);
self.queue.push_back(IfEvent::Down(old_addr));
}
}
for new_addr in addrs {
let ipnet = ifaddr_to_ipnet(new_addr.addr);
if self.addrs.insert(ipnet) {
self.queue.push_back(IfEvent::Up(ipnet));
}
}
Ok(())
}

pub fn iter(&self) -> impl Iterator<Item = &IpNet> {
self.addrs.iter()
}

/// Returns a future for the next event.
pub async fn next(&mut self) -> Result<IfEvent> {
loop {
if let Some(event) = self.queue.pop_front() {
return Ok(event);
}
self.ticker.next().await;
self.resync()?;
}
}
}

fn ifaddr_to_ipnet(addr: IfAddr) -> IpNet {
match addr {
IfAddr::V4(ip) => {
let prefix_len = (!u32::from_be_bytes(ip.netmask.octets())).leading_zeros();
IpNet::V4(
Ipv4Net::new(ip.ip, prefix_len as u8).expect("if_addrs returned a valid prefix"),
)
}
IfAddr::V6(ip) => {
let prefix_len = (!u128::from_be_bytes(ip.netmask.octets())).leading_zeros();
IpNet::V6(
Ipv6Net::new(ip.ip, prefix_len as u8).expect("if_addrs returned a valid prefix"),
)
}
}
}
8 changes: 6 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,19 @@ use std::io::Result;
#[cfg(not(any(unix, windows)))]
compile_error!("Only Unix and Windows are supported");

#[cfg(unix)]
#[cfg(target_os = "linux")]
mod unix;
#[cfg(windows)]
mod windows;
#[cfg(not(any(target_os = "linux", windows)))]
mod fallback;

#[cfg(unix)]
#[cfg(target_os = "linux")]
use unix as platform_impl;
#[cfg(windows)]
use windows as platform_impl;
#[cfg(not(any(target_os = "linux", windows)))]
use fallback as platform_impl;

/// An address change event.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
Expand Down

0 comments on commit c11b354

Please sign in to comment.