From 3bff078e3f1c59454d8db14e5dc7603e6fdbeaba Mon Sep 17 00:00:00 2001 From: Mathias Hall-Andersen Date: Sun, 24 Nov 2019 18:41:43 +0100 Subject: Make IO traits suitable for Tun events (up/down) --- src/platform/bind.rs | 47 ---------------------------------------------- src/platform/dummy/bind.rs | 8 ++++---- src/platform/dummy/tun.rs | 35 ++++++++++++++++++++-------------- src/platform/linux/mod.rs | 2 +- src/platform/linux/tun.rs | 42 ++++++++++++++++++++++++----------------- src/platform/linux/udp.rs | 24 ++++++++++++----------- src/platform/mod.rs | 2 +- src/platform/tun.rs | 30 ++++++++++++++--------------- src/platform/udp.rs | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 127 insertions(+), 110 deletions(-) delete mode 100644 src/platform/bind.rs create mode 100644 src/platform/udp.rs (limited to 'src/platform') diff --git a/src/platform/bind.rs b/src/platform/bind.rs deleted file mode 100644 index 9487dfd..0000000 --- a/src/platform/bind.rs +++ /dev/null @@ -1,47 +0,0 @@ -use super::Endpoint; -use std::error::Error; - -pub trait Reader: Send + Sync { - type Error: Error; - - fn read(&self, buf: &mut [u8]) -> Result<(usize, E), Self::Error>; -} - -pub trait Writer: Send + Sync + Clone + 'static { - type Error: Error; - - fn write(&self, buf: &[u8], dst: &E) -> Result<(), Self::Error>; -} - -pub trait Bind: Send + Sync + 'static { - type Error: Error; - type Endpoint: Endpoint; - - /* Until Rust gets type equality constraints these have to be generic */ - type Writer: Writer; - type Reader: Reader; -} - -/// On platforms where fwmark can be set and the -/// implementation can bind to a new port during later configuration (UAPI support), -/// this type provides the ability to set the fwmark and close the socket (by dropping the instance) -pub trait Owner: Send { - type Error: Error; - - fn get_port(&self) -> u16; - - fn get_fwmark(&self) -> Option; - - fn set_fwmark(&mut self, value: Option) -> Result<(), Self::Error>; -} - -/// On some platforms the application can itself bind to a socket. -/// This enables configuration using the UAPI interface. -pub trait PlatformBind: Bind { - type Owner: Owner; - - /// Bind to a new port, returning the reader/writer and - /// an associated instance of the owner type, which closes the UDP socket upon "drop" - /// and enables configuration of the fwmark value. - fn bind(port: u16) -> Result<(Vec, Self::Writer, Self::Owner), Self::Error>; -} diff --git a/src/platform/dummy/bind.rs b/src/platform/dummy/bind.rs index d69e6a4..3146af8 100644 --- a/src/platform/dummy/bind.rs +++ b/src/platform/dummy/bind.rs @@ -11,7 +11,7 @@ use std::sync::mpsc::{sync_channel, Receiver, SyncSender}; use std::sync::Arc; use std::sync::Mutex; -use super::super::bind::*; +use super::super::udp::*; use super::UnitEndpoint; @@ -82,7 +82,7 @@ impl Writer for VoidBind { } } -impl Bind for VoidBind { +impl UDP for VoidBind { type Error = BindError; type Endpoint = UnitEndpoint; @@ -193,7 +193,7 @@ impl PairBind { } } -impl Bind for PairBind { +impl UDP for PairBind { type Error = BindError; type Endpoint = UnitEndpoint; type Reader = PairReader; @@ -216,7 +216,7 @@ impl Owner for VoidOwner { } } -impl PlatformBind for PairBind { +impl PlatformUDP for PairBind { type Owner = VoidOwner; fn bind(_port: u16) -> Result<(Vec, Self::Writer, Self::Owner), Self::Error> { Err(BindError::Disconnected) diff --git a/src/platform/dummy/tun.rs b/src/platform/dummy/tun.rs index 569bf1c..6ddf7d5 100644 --- a/src/platform/dummy/tun.rs +++ b/src/platform/dummy/tun.rs @@ -10,6 +10,8 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::mpsc::{sync_channel, Receiver, SyncSender}; use std::sync::Arc; use std::sync::Mutex; +use std::thread; +use std::time::Duration; use super::super::tun::*; @@ -83,9 +85,8 @@ pub struct TunWriter { tx: Mutex>>, } -#[derive(Clone)] -pub struct TunMTU { - mtu: Arc, +pub struct TunStatus { + first: bool, } impl Reader for TunReader { @@ -131,16 +132,25 @@ impl Writer for TunWriter { } } -impl MTU for TunMTU { - fn mtu(&self) -> usize { - self.mtu.load(Ordering::Acquire) +impl Status for TunStatus { + type Error = TunError; + + fn event(&mut self) -> Result { + if self.first { + self.first = false; + return Ok(TunEvent::Up(1420)); + } + + loop { + thread::sleep(Duration::from_secs(60 * 60)); + } } } impl Tun for TunTest { type Writer = TunWriter; type Reader = TunReader; - type MTU = TunMTU; + type Status = TunStatus; type Error = TunError; } @@ -157,7 +167,7 @@ impl TunFakeIO { } impl TunTest { - pub fn create(mtu: usize, store: bool) -> (TunFakeIO, TunReader, TunWriter, TunMTU) { + pub fn create(mtu: usize, store: bool) -> (TunFakeIO, TunReader, TunWriter, TunStatus) { let (tx1, rx1) = if store { sync_channel(32) } else { @@ -184,16 +194,13 @@ impl TunTest { tx: Mutex::new(tx2), store, }; - let mtu = TunMTU { - mtu: Arc::new(AtomicUsize::new(mtu)), - }; - - (fake, reader, writer, mtu) + let status = TunStatus { first: true }; + (fake, reader, writer, status) } } impl PlatformTun for TunTest { - fn create(_name: &str) -> Result<(Vec, Self::Writer, Self::MTU), Self::Error> { + fn create(_name: &str) -> Result<(Vec, Self::Writer, Self::Status), Self::Error> { Err(TunError::Disconnected) } } diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 82731de..d28391e 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -4,4 +4,4 @@ mod udp; pub use tun::LinuxTun as Tun; pub use uapi::LinuxUAPI as UAPI; -pub use udp::LinuxBind as Bind; +pub use udp::LinuxUDP as UDP; diff --git a/src/platform/linux/tun.rs b/src/platform/linux/tun.rs index 0bbae81..604fad9 100644 --- a/src/platform/linux/tun.rs +++ b/src/platform/linux/tun.rs @@ -6,8 +6,8 @@ use std::error::Error; use std::fmt; use std::os::raw::c_short; use std::os::unix::io::RawFd; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Arc; +use std::thread; +use std::time::Duration; const IFNAMSIZ: usize = 16; const TUNSETIFF: u64 = 0x4004_54ca; @@ -30,7 +30,9 @@ struct Ifreq { _pad: [u8; 64], } -pub struct LinuxTun {} +pub struct LinuxTun { + events: Vec, +} pub struct LinuxTunReader { fd: RawFd, @@ -44,8 +46,8 @@ pub struct LinuxTunWriter { * announcing an MTU update for the interface */ #[derive(Clone)] -pub struct LinuxTunMTU { - value: Arc, +pub struct LinuxTunStatus { + first: bool, } #[derive(Debug)] @@ -81,13 +83,6 @@ impl Error for LinuxTunError { } } -impl MTU for LinuxTunMTU { - #[inline(always)] - fn mtu(&self) -> usize { - self.value.load(Ordering::Relaxed) - } -} - impl Reader for LinuxTunReader { type Error = LinuxTunError; @@ -118,15 +113,30 @@ impl Writer for LinuxTunWriter { } } +impl Status for LinuxTunStatus { + type Error = LinuxTunError; + + fn event(&mut self) -> Result { + if self.first { + self.first = false; + return Ok(TunEvent::Up(1420)); + } + + loop { + thread::sleep(Duration::from_secs(60 * 60)); + } + } +} + impl Tun for LinuxTun { type Error = LinuxTunError; type Reader = LinuxTunReader; type Writer = LinuxTunWriter; - type MTU = LinuxTunMTU; + type Status = LinuxTunStatus; } impl PlatformTun for LinuxTun { - fn create(name: &str) -> Result<(Vec, Self::Writer, Self::MTU), Self::Error> { + fn create(name: &str) -> Result<(Vec, Self::Writer, Self::Status), Self::Error> { // construct request struct let mut req = Ifreq { name: [0u8; libc::IFNAMSIZ], @@ -157,9 +167,7 @@ impl PlatformTun for LinuxTun { Ok(( vec![LinuxTunReader { fd }], // TODO: enable multi-queue for Linux LinuxTunWriter { fd }, - LinuxTunMTU { - value: Arc::new(AtomicUsize::new(1500)), // TODO: fetch and update - }, + LinuxTunStatus { first: true }, )) } } diff --git a/src/platform/linux/udp.rs b/src/platform/linux/udp.rs index a291d1a..f871bce 100644 --- a/src/platform/linux/udp.rs +++ b/src/platform/linux/udp.rs @@ -1,4 +1,4 @@ -use super::super::bind::*; +use super::super::udp::*; use super::super::Endpoint; use std::io; @@ -6,7 +6,7 @@ use std::net::{SocketAddr, UdpSocket}; use std::sync::Arc; #[derive(Clone)] -pub struct LinuxBind(Arc); +pub struct LinuxUDP(Arc); pub struct LinuxOwner(Arc); @@ -22,7 +22,7 @@ impl Endpoint for SocketAddr { } } -impl Reader for LinuxBind { +impl Reader for LinuxUDP { type Error = io::Error; fn read(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr), Self::Error> { @@ -30,7 +30,7 @@ impl Reader for LinuxBind { } } -impl Writer for LinuxBind { +impl Writer for LinuxUDP { type Error = io::Error; fn write(&self, buf: &[u8], dst: &SocketAddr) -> Result<(), Self::Error> { @@ -56,17 +56,19 @@ impl Owner for LinuxOwner { } impl Drop for LinuxOwner { - fn drop(&mut self) {} + fn drop(&mut self) { + // TODO: close udp bind + } } -impl Bind for LinuxBind { +impl UDP for LinuxUDP { type Error = io::Error; type Endpoint = SocketAddr; - type Reader = LinuxBind; - type Writer = LinuxBind; + type Reader = Self; + type Writer = Self; } -impl PlatformBind for LinuxBind { +impl PlatformUDP for LinuxUDP { type Owner = LinuxOwner; fn bind(port: u16) -> Result<(Vec, Self::Writer, Self::Owner), Self::Error> { @@ -74,8 +76,8 @@ impl PlatformBind for LinuxBind { let socket = Arc::new(socket); Ok(( - vec![LinuxBind(socket.clone())], - LinuxBind(socket.clone()), + vec![LinuxUDP(socket.clone())], + LinuxUDP(socket.clone()), LinuxOwner(socket), )) } diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 99707e3..6b8fa0e 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -1,8 +1,8 @@ mod endpoint; -pub mod bind; pub mod tun; pub mod uapi; +pub mod udp; pub use endpoint::Endpoint; diff --git a/src/platform/tun.rs b/src/platform/tun.rs index c92304a..fda17fd 100644 --- a/src/platform/tun.rs +++ b/src/platform/tun.rs @@ -1,5 +1,18 @@ use std::error::Error; +pub enum TunEvent { + Up(usize), // interface is up (supply MTU) + Down, // interface is down +} + +pub trait Status: Send + 'static { + type Error: Error; + + /// Returns status updates for the interface + /// When the status is unchanged the method blocks + fn event(&mut self) -> Result; +} + pub trait Writer: Send + Sync + 'static { type Error: Error; @@ -35,27 +48,14 @@ pub trait Reader: Send + 'static { fn read(&self, buf: &mut [u8], offset: usize) -> Result; } -pub trait MTU: Send + Sync + Clone + 'static { - /// Returns the MTU of the device - /// - /// This function needs to be efficient (called for every read). - /// The goto implementation strategy is to .load an atomic variable, - /// then use e.g. netlink to update the variable in a separate thread. - /// - /// # Returns - /// - /// The MTU of the interface in bytes - fn mtu(&self) -> usize; -} - pub trait Tun: Send + Sync + 'static { type Writer: Writer; type Reader: Reader; - type MTU: MTU; + type Status: Status; type Error: Error; } /// On some platforms the application can create the TUN device itself. pub trait PlatformTun: Tun { - fn create(name: &str) -> Result<(Vec, Self::Writer, Self::MTU), Self::Error>; + fn create(name: &str) -> Result<(Vec, Self::Writer, Self::Status), Self::Error>; } diff --git a/src/platform/udp.rs b/src/platform/udp.rs new file mode 100644 index 0000000..3671229 --- /dev/null +++ b/src/platform/udp.rs @@ -0,0 +1,47 @@ +use super::Endpoint; +use std::error::Error; + +pub trait Reader: Send + Sync { + type Error: Error; + + fn read(&self, buf: &mut [u8]) -> Result<(usize, E), Self::Error>; +} + +pub trait Writer: Send + Sync + Clone + 'static { + type Error: Error; + + fn write(&self, buf: &[u8], dst: &E) -> Result<(), Self::Error>; +} + +pub trait UDP: Send + Sync + 'static { + type Error: Error; + type Endpoint: Endpoint; + + /* Until Rust gets type equality constraints these have to be generic */ + type Writer: Writer; + type Reader: Reader; +} + +/// On platforms where fwmark can be set and the +/// implementation can bind to a new port during later configuration (UAPI support), +/// this type provides the ability to set the fwmark and close the socket (by dropping the instance) +pub trait Owner: Send { + type Error: Error; + + fn get_port(&self) -> u16; + + fn get_fwmark(&self) -> Option; + + fn set_fwmark(&mut self, value: Option) -> Result<(), Self::Error>; +} + +/// On some platforms the application can itself bind to a socket. +/// This enables configuration using the UAPI interface. +pub trait PlatformUDP: UDP { + type Owner: Owner; + + /// Bind to a new port, returning the reader/writer and + /// an associated instance of the owner type, which closes the UDP socket upon "drop" + /// and enables configuration of the fwmark value. + fn bind(port: u16) -> Result<(Vec, Self::Writer, Self::Owner), Self::Error>; +} -- cgit v1.2.3-59-g8ed1b