From 2465816c24b3d26101ecd000531214cc4409ced5 Mon Sep 17 00:00:00 2001 From: ivmarkov Date: Thu, 2 Jan 2025 09:17:38 +0000 Subject: [PATCH] Make embassy-time optional --- edge-dhcp/Cargo.toml | 4 ++-- edge-dhcp/README.md | 2 +- edge-dhcp/src/io/server.rs | 5 +++-- edge-dhcp/src/server.rs | 44 +++++++++++++++++++++++++++----------- examples/dhcp_server.rs | 2 +- 5 files changed, 39 insertions(+), 18 deletions(-) diff --git a/edge-dhcp/Cargo.toml b/edge-dhcp/Cargo.toml index 511588f..1ead75c 100644 --- a/edge-dhcp/Cargo.toml +++ b/edge-dhcp/Cargo.toml @@ -17,14 +17,14 @@ categories = [ [features] default = ["io"] std = ["io"] -io = ["embassy-futures", "edge-nal"] +io = ["embassy-futures", "embassy-time", "edge-nal"] [dependencies] heapless = { workspace = true } log = { workspace = true } rand_core = "0.6" embassy-futures = { workspace = true, optional = true } -embassy-time = { workspace = true, default-features = false } # TODO: Make optional +embassy-time = { workspace = true, default-features = false, optional = true } edge-nal = { workspace = true, optional = true } num_enum = { version = "0.7", default-features = false } edge-raw = { workspace = true, default-features = false } diff --git a/edge-dhcp/README.md b/edge-dhcp/README.md index c953c95..62e874a 100644 --- a/edge-dhcp/README.md +++ b/edge-dhcp/README.md @@ -113,7 +113,7 @@ async fn run(if_index: u32) -> Result<(), anyhow::Error> { let mut gw_buf = [Ipv4Addr::UNSPECIFIED]; io::server::run( - &mut Server::<64>::new(ip), // Will give IP addresses in the range 192.168.0.50 - 192.168.0.200, subnet 255.255.255.0 + &mut Server::<_, 64>::new_with_et(ip), // Will give IP addresses in the range 192.168.0.50 - 192.168.0.200, subnet 255.255.255.0 &ServerOptions::new(ip, Some(&mut gw_buf)), &mut socket, &mut buf, diff --git a/edge-dhcp/src/io/server.rs b/edge-dhcp/src/io/server.rs index f8152cb..3302414 100644 --- a/edge-dhcp/src/io/server.rs +++ b/edge-dhcp/src/io/server.rs @@ -23,14 +23,15 @@ pub use super::*; /// /// This is currently only possible with STD's BSD raw sockets' implementation. Unfortunately, `smoltcp` and thus `embassy-net` /// do not have an equivalent (yet). -pub async fn run( - server: &mut dhcp::server::Server, +pub async fn run( + server: &mut dhcp::server::Server, server_options: &dhcp::server::ServerOptions<'_>, socket: &mut T, buf: &mut [u8], ) -> Result<(), Error> where T: UdpReceive + UdpSend, + F: FnMut() -> u64, { info!( "Running DHCP server for addresses {}-{} with configuration {server_options:?}", diff --git a/edge-dhcp/src/server.rs b/edge-dhcp/src/server.rs index 07c8fb7..ac531db 100644 --- a/edge-dhcp/src/server.rs +++ b/edge-dhcp/src/server.rs @@ -1,7 +1,5 @@ use core::fmt::Debug; -use embassy_time::{Duration, Instant}; - use log::{debug, warn}; use super::*; @@ -9,7 +7,7 @@ use super::*; #[derive(Clone, Debug)] pub struct Lease { mac: [u8; 16], - expires: Instant, + expires: u64, } #[derive(Clone, Debug)] @@ -168,17 +166,27 @@ impl<'a> ServerOptions<'a> { /// The server is unaware of the IP/UDP transport layer and operates purely in terms of packets /// represented as Rust slices. #[derive(Clone, Debug)] -pub struct Server { +pub struct Server { + pub now: F, pub range_start: Ipv4Addr, pub range_end: Ipv4Addr, pub leases: heapless::LinearMap, } -impl Server { - pub const fn new(ip: Ipv4Addr) -> Self { +impl Server +where + F: FnMut() -> u64, +{ + /// Create a new DHCP server. + /// + /// # Arguments + /// - `now`: A closure that returns the current time in seconds since some epoch. + /// - `ip`: The IP address of the server. + pub const fn new(now: F, ip: Ipv4Addr) -> Self { let octets = ip.octets(); Self { + now, range_start: Ipv4Addr::new(octets[0], octets[1], octets[2], 50), range_end: Ipv4Addr::new(octets[0], octets[1], octets[2], 200), leases: heapless::LinearMap::new(), @@ -203,12 +211,13 @@ impl Server { ip.map(|ip| server_options.offer(request, ip, opt_buf)) } Action::Request(ip, mac) => { + let now = (self.now)(); + let ip = (self.is_available(mac, ip) && self.add_lease( ip, request.chaddr, - Instant::now() - + Duration::from_secs(server_options.lease_duration_secs as _), + now + server_options.lease_duration_secs as u64, )) .then_some(ip); @@ -222,7 +231,7 @@ impl Server { }) } - fn is_available(&self, mac: &[u8; 16], addr: Ipv4Addr) -> bool { + fn is_available(&mut self, mac: &[u8; 16], addr: Ipv4Addr) -> bool { let pos: u32 = addr.into(); let start: u32 = self.range_start.into(); @@ -231,7 +240,7 @@ impl Server { pos >= start && pos <= end && match self.leases.get(&addr) { - Some(lease) => lease.mac == *mac || Instant::now() > lease.expires, + Some(lease) => lease.mac == *mac || (self.now)() > lease.expires, None => true, } } @@ -251,7 +260,7 @@ impl Server { if let Some(addr) = self .leases .iter() - .find_map(|(addr, lease)| (Instant::now() > lease.expires).then_some(*addr)) + .find_map(|(addr, lease)| ((self.now)() > lease.expires).then_some(*addr)) { self.leases.remove(&addr); @@ -267,7 +276,7 @@ impl Server { .find_map(|(addr, lease)| (lease.mac == *mac).then_some(*addr)) } - fn add_lease(&mut self, addr: Ipv4Addr, mac: [u8; 16], expires: Instant) -> bool { + fn add_lease(&mut self, addr: Ipv4Addr, mac: [u8; 16], expires: u64) -> bool { self.remove_lease(&mac); self.leases.insert(addr, Lease { mac, expires }).is_ok() @@ -283,3 +292,14 @@ impl Server { } } } + +#[cfg(feature = "io")] +impl Server u64, N> { + /// Create a new DHCP server using `embassy-time::Instant::now` as the currtent time epoch provider. + /// + /// # Arguments + /// - `ip`: The IP address of the server. + pub const fn new_with_et(ip: Ipv4Addr) -> Self { + Self::new(|| embassy_time::Instant::now().as_secs(), ip) + } +} diff --git a/examples/dhcp_server.rs b/examples/dhcp_server.rs index 5ca939d..0d7fd28 100644 --- a/examples/dhcp_server.rs +++ b/examples/dhcp_server.rs @@ -41,7 +41,7 @@ async fn run(if_index: u32) -> Result<(), anyhow::Error> { let mut gw_buf = [Ipv4Addr::UNSPECIFIED]; io::server::run( - &mut Server::<64>::new(ip), // Will give IP addresses in the range 192.168.0.50 - 192.168.0.200, subnet 255.255.255.0 + &mut Server::<_, 64>::new_with_et(ip), // Will give IP addresses in the range 192.168.0.50 - 192.168.0.200, subnet 255.255.255.0 &ServerOptions::new(ip, Some(&mut gw_buf)), &mut socket, &mut buf,