Skip to content

Commit

Permalink
Make embassy-time optional
Browse files Browse the repository at this point in the history
  • Loading branch information
ivmarkov committed Jan 2, 2025
1 parent 4c0940b commit 2465816
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 18 deletions.
4 changes: 2 additions & 2 deletions edge-dhcp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
2 changes: 1 addition & 1 deletion edge-dhcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 3 additions & 2 deletions edge-dhcp/src/io/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T, const N: usize>(
server: &mut dhcp::server::Server<N>,
pub async fn run<T, F, const N: usize>(
server: &mut dhcp::server::Server<F, N>,
server_options: &dhcp::server::ServerOptions<'_>,
socket: &mut T,
buf: &mut [u8],
) -> Result<(), Error<T::Error>>
where
T: UdpReceive + UdpSend,
F: FnMut() -> u64,
{
info!(
"Running DHCP server for addresses {}-{} with configuration {server_options:?}",
Expand Down
44 changes: 32 additions & 12 deletions edge-dhcp/src/server.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
use core::fmt::Debug;

use embassy_time::{Duration, Instant};

use log::{debug, warn};

use super::*;

#[derive(Clone, Debug)]
pub struct Lease {
mac: [u8; 16],
expires: Instant,
expires: u64,
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -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<const N: usize> {
pub struct Server<F, const N: usize> {
pub now: F,
pub range_start: Ipv4Addr,
pub range_end: Ipv4Addr,
pub leases: heapless::LinearMap<Ipv4Addr, Lease, N>,
}

impl<const N: usize> Server<N> {
pub const fn new(ip: Ipv4Addr) -> Self {
impl<F, const N: usize> Server<F, N>
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(),
Expand All @@ -203,12 +211,13 @@ impl<const N: usize> Server<N> {
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);

Expand All @@ -222,7 +231,7 @@ impl<const N: usize> Server<N> {
})
}

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();
Expand All @@ -231,7 +240,7 @@ impl<const N: usize> Server<N> {
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,
}
}
Expand All @@ -251,7 +260,7 @@ impl<const N: usize> Server<N> {
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);

Expand All @@ -267,7 +276,7 @@ impl<const N: usize> Server<N> {
.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()
Expand All @@ -283,3 +292,14 @@ impl<const N: usize> Server<N> {
}
}
}

#[cfg(feature = "io")]
impl<const N: usize> Server<fn() -> 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)
}
}
2 changes: 1 addition & 1 deletion examples/dhcp_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 2465816

Please sign in to comment.