#[cfg(target_os = "windows")]
use std::borrow::ToOwned;
use std::io;
#[cfg(not(target_os = "windows"))]
use std::net::IpAddr;
#[cfg(target_os = "windows")]
use std::sync::Arc;
#[cfg(not(target_os = "windows"))]
use crate::{AddAddress, AddressInfo};
use crate::{DeviceState, Interface, Tun};
#[cfg(not(target_os = "windows"))]
use async_io::Async;
#[cfg(target_os = "windows")]
#[derive(Clone)]
struct TunWrapper(Arc<Tun>);
#[cfg(target_os = "windows")]
impl TunWrapper {
#[inline]
pub fn get_ref(&self) -> &Tun {
self.0.as_ref()
}
#[inline]
pub fn get_mut(&mut self) -> &mut Tun {
Arc::<Tun>::get_mut(&mut self.0).unwrap()
}
}
pub struct AsyncTun {
#[cfg(not(target_os = "windows"))]
tun: Async<Tun>,
#[cfg(target_os = "windows")]
tun: TunWrapper,
}
impl AsyncTun {
#[inline]
pub fn new() -> io::Result<Self> {
Self::new_impl()
}
#[cfg(not(target_os = "windows"))]
fn new_impl() -> io::Result<Self> {
let mut tun = Tun::new()?;
tun.set_nonblocking(true)?;
Ok(Self {
tun: Async::new(tun)?,
})
}
#[cfg(target_os = "windows")]
fn new_impl() -> io::Result<Self> {
let mut tun = Tun::new()?;
Ok(Self {
tun: TunWrapper(Arc::new(tun)),
})
}
#[inline]
pub fn new_named(if_name: Interface) -> io::Result<Self> {
Self::new_named_impl(if_name)
}
#[cfg(not(target_os = "windows"))]
pub fn new_named_impl(if_name: Interface) -> io::Result<Self> {
let mut tun = Tun::new_named(if_name)?;
tun.set_nonblocking(true)?;
Ok(Self {
tun: Async::new(tun)?,
})
}
#[cfg(target_os = "windows")]
pub fn new_named_impl(if_name: Interface) -> io::Result<Self> {
let mut tun = Tun::new_named(if_name)?;
Ok(Self {
tun: TunWrapper(Arc::new(tun)),
})
}
#[inline]
pub fn name(&self) -> io::Result<Interface> {
self.tun.get_ref().name()
}
#[inline]
pub fn set_state(&mut self, state: DeviceState) -> io::Result<()> {
unsafe { self.tun.get_mut().set_state(state) }
}
#[inline]
pub fn set_up(&mut self) -> io::Result<()> {
unsafe { self.tun.get_mut().set_state(DeviceState::Up) }
}
#[inline]
pub fn set_down(&mut self) -> io::Result<()> {
unsafe { self.tun.get_mut().set_state(DeviceState::Down) }
}
#[inline]
pub fn mtu(&self) -> io::Result<usize> {
self.tun.get_ref().mtu()
}
#[cfg(not(target_os = "windows"))]
#[inline]
pub fn addrs(&self) -> io::Result<Vec<AddressInfo>> {
self.tun.get_ref().addrs()
}
#[cfg(not(target_os = "windows"))]
#[inline]
pub fn add_addr<A: Into<AddAddress>>(&self, req: A) -> io::Result<()> {
self.tun.get_ref().add_addr(req)
}
#[cfg(not(target_os = "windows"))]
#[inline]
pub fn remove_addr(&self, addr: IpAddr) -> io::Result<()> {
self.tun.get_ref().remove_addr(addr)
}
#[inline]
pub async fn send(&self, buf: &[u8]) -> io::Result<usize> {
self.send_impl(buf).await
}
#[cfg(not(target_os = "windows"))]
#[inline]
async fn send_impl(&self, buf: &[u8]) -> io::Result<usize> {
self.tun.write_with(|inner| inner.send(buf)).await
}
#[cfg(target_os = "windows")]
#[inline]
async fn send_impl(&self, buf: &[u8]) -> io::Result<usize> {
let arc = self.tun.clone();
let buf = buf.to_owned();
smol::unblock(move || arc.get_ref().send(buf.as_slice())).await
}
#[inline]
pub async fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
self.recv_impl(buf).await
}
#[cfg(not(target_os = "windows"))]
pub async fn recv_impl(&self, buf: &mut [u8]) -> io::Result<usize> {
self.tun.read_with(|inner| inner.recv(buf)).await
}
#[cfg(target_os = "windows")]
pub async fn recv_impl(&self, buf: &mut [u8]) -> io::Result<usize> {
let arc = self.tun.clone();
let buflen = buf.len();
let (res, data) = smol::unblock(move || {
let mut buf = vec![0; buflen];
let res = arc.get_ref().recv(buf.as_mut_slice());
(res, buf)
})
.await;
match res {
Ok(len) => {
buf[..len].copy_from_slice(&data[..len]);
Ok(len)
}
err => err,
}
}
}