use std::{
cell::RefCell,
error::Error,
io,
net::{IpAddr, Ipv4Addr, Ipv6Addr},
sync::{Mutex, PoisonError},
};
use crossbeam_channel::{Receiver, Sender};
use crate::Route;
pub(crate) trait SystemRouteOperate {
fn new(sender: Sender<RouteEvent>) -> Self
where
Self: Sized;
fn init(&mut self) -> io::Result<()>;
fn read_all_routes(&self) -> io::Result<Vec<Route>>;
fn add_route(&self, route: &Route) -> io::Result<()>;
fn delete_route(&self, route: &Route) -> io::Result<()>;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RouteEvent {
Add(Route),
Delete(Route),
Change(Route),
}
pub struct RouteManager {
routes: Mutex<RefCell<Vec<Route>>>,
operator: Box<dyn SystemRouteOperate>,
operator_receiver: Receiver<RouteEvent>,
subscribers: Receiver<RouteEvent>,
producer: Sender<RouteEvent>,
}
impl RouteManager {
#[cfg(windows)]
pub fn new() -> io::Result<Self> {
use crate::windows::WindowsOperator;
let (tx, rx) = crossbeam_channel::unbounded();
let (tx_loop, rx_loop) = crossbeam_channel::unbounded();
let mut operator = Box::new(WindowsOperator::new(tx));
operator.init()?;
let routes = operator.read_all_routes().unwrap();
let manager = RouteManager {
routes: Mutex::new(RefCell::new(routes)),
operator,
operator_receiver: rx,
subscribers: rx_loop,
producer: tx_loop,
};
Ok(manager)
}
#[cfg(not(windows))]
pub fn new() -> io::Result<Self> {
Err(io::Error::new(io::ErrorKind::Other, "None windows system not supported"))
}
pub fn poll(&self) -> Result<(), Box<dyn Error>> {
let event: RouteEvent = self.operator_receiver.recv()?;
{
match self.routes.lock() { Ok(guard) => {
let mut routes = guard.borrow_mut();
match event.clone() {
RouteEvent::Add(route) => routes.push(route),
RouteEvent::Delete(route) => {
if let Some(index) = routes.iter().position(|v| *v == route) {
routes.remove(index);
}
}
RouteEvent::Change(route) => {
if let Some(index) = routes.iter().position(|v| {
v.destination == route.destination && v.prefix == route.prefix
}) {
routes.remove(index);
routes.push(route);
}
}
}
} _ => {
return Err(Box::new(PoisonError::new(
"Can not lock private field routes",
)));
}}
}
if let Err(e) = self.producer.send(event.clone()) {
return Err(Box::new(e));
}
Ok(())
}
pub fn subscribe_route_change(&self) -> Receiver<RouteEvent> {
self.subscribers.clone()
}
pub fn routes(&self) -> io::Result<Vec<Route>> {
match self.routes.lock() { Ok(guard) => {
Ok(guard.borrow_mut().clone())
} _ => {
Err(io::Error::new(io::ErrorKind::Other, "Can not lock inner data, this is a thread safe error"))
}}
}
pub fn add_route(&self, route: &Route) -> io::Result<()> {
self.operator.add_route(route)?;
Ok(())
}
pub fn delete_route(&self, route: &Route) -> io::Result<()> {
self.operator.delete_route(route)?;
Ok(())
}
pub fn default_route(&self) -> io::Result<Option<Route>> {
match self.routes.lock() { Ok(guard) => {
let guard = guard.borrow_mut();
let itr = guard.iter();
for route in itr {
if (route.destination == Ipv4Addr::UNSPECIFIED
|| route.destination == Ipv6Addr::UNSPECIFIED)
&& route.gateway != IpAddr::V4(Ipv4Addr::UNSPECIFIED)
&& route.gateway != IpAddr::V6(Ipv6Addr::UNSPECIFIED)
&& route.prefix == 0
{
return Ok(Some(route.clone()));
}
}
} _ => {
return Err(io::Error::new(
io::ErrorKind::NotFound,
"can not found defualt route",
));
}}
Ok(None)
}
}
impl Drop for RouteManager {
fn drop(&mut self) {}
}
unsafe impl Sync for RouteManager {}
unsafe impl Send for RouteManager {}