Skip to content

Commit

Permalink
Display and std::error::Error for all errors; DHCP examples
Browse files Browse the repository at this point in the history
  • Loading branch information
ivmarkov committed Jan 19, 2024
1 parent 3397d5f commit aa6c728
Show file tree
Hide file tree
Showing 19 changed files with 271 additions and 40 deletions.
20 changes: 15 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ embedded-svc = { git = "https://github.com/esp-rs/embedded-svc" }
std-embedded-nal-async = { git = "https://gitlab.com/ivmarkov/std-embedded-nal" }

[features]
default = ["io"]
std = ["edge-http/std", "edge-captive/std", "edge-mdns/std", "edge-mqtt", "edge-std-nal-async"]
default = ["std"]
std = ["io", "edge-captive/std", "edge-dhcp/std", "edge-http/std", "edge-mdns/std", "edge-raw/std", "edge-mqtt", "edge-ws/std", "edge-std-nal-async"]
io = ["edge-captive/io", "edge-dhcp/io", "edge-http/io", "edge-mdns/io", "edge-raw/io", "edge-ws/io", "embedded-nal-async-xtra"]
nightly = []
embedded-svc = ["edge-http/embedded-svc", "edge-mqtt/embedded-svc", "edge-ws/embedded-svc"]
Expand All @@ -41,6 +41,8 @@ embedded-io-async = "0.6"
embedded-nal-async = "0.7"
std-embedded-nal-async = "0.1"
futures-lite = "1"
rand = "0.8"
embassy-time = { version = "0.3", features = ["std", "generic-queue"] }

[[example]]
name = "captive_portal"
Expand All @@ -51,12 +53,20 @@ name = "simple"
required-features = ["io", "std"]

[[example]]
name = "http_client"
name = "dhcp_client"
required-features = ["io", "std"]

[[example]]
name = "dhcp_server"
required-features = ["io", "std"]

[[example]]
name = "http_server"
required-features = ["io", "std", "turnoff"]
name = "http_client"
required-features = ["io", "std"]

#[[example]]
#name = "http_server"
#required-features = ["io", "std", "turnoff"]

[workspace]
members = [
Expand Down
4 changes: 2 additions & 2 deletions edge-captive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ edition = "2021"
rust-version = "1.75"

[features]
std = [] # TODO
default = ["io"]
default = ["std"]
std = ["io"]
io = ["embedded-nal-async"]

[dependencies]
Expand Down
16 changes: 16 additions & 0 deletions edge-captive/src/io.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use core::fmt;
use core::time::Duration;

use embedded_nal_async::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, UdpStack, UnconnectedUdp};
Expand All @@ -22,6 +23,21 @@ impl<E> From<DnsError> for DnsIoError<E> {
}
}

impl<E> fmt::Display for DnsIoError<E>
where
E: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::DnsError(err) => write!(f, "DNS error: {}", err),
Self::IoError(err) => write!(f, "IO error: {}", err),
}
}
}

#[cfg(feature = "std")]
impl<E> std::error::Error for DnsIoError<E> where E: std::error::Error {}

pub async fn run<S>(
stack: &S,
socket: SocketAddr,
Expand Down
3 changes: 2 additions & 1 deletion edge-dhcp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ edition = "2021"
rust-version = "1.75"

[features]
default = ["io"]
default = ["std"]
std = ["io"]
io = ["embassy-futures", "embedded-nal-async", "embedded-nal-async-xtra"]

[dependencies]
Expand Down
57 changes: 38 additions & 19 deletions edge-dhcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,47 @@ Async + `no_std` + no-alloc implementation of the DHCP protocol.
### DHCP client

```rust
use edge_raw::{StdRawStack, Udp2RawStack};
use edge_dhcp::{DEFAULT_CLIENT_PORT, Client, io::Lease, io::Error};
use edge_raw::io::Udp2RawStack;
use edge_std_nal_async::StdRawStack;

use embedded_nal_async::Ipv4Addr;
use edge_dhcp::client::Client;
use edge_dhcp::io::{self, client::Lease, client::DEFAULT_CLIENT_PORT};

use embedded_nal_async::{Ipv4Addr, SocketAddrV4};

use log::info;

fn main() {
futures_lite::task::block_on(0, run([0; 6]/* Your MAC addr here */)).unwrap();
env_logger::init_from_env(
env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
);

futures_lite::future::block_on(run(
2, // The interface index of the interface (e.g. eno0) to use; run `ip addr` to see it
[0x4c, 0xcc, 0x6a, 0xa2, 0x23, 0xf5], // Your MAC addr here; run `ip addr` to see it
))
.unwrap();
}

async fn run(if_index: u8, if_mac: [u8; 6]) -> Result<(), impl Debug> {
let mut client = Client::new(thread_rng(), if_mac);
async fn run(if_index: u32, if_mac: [u8; 6]) -> Result<(), anyhow::Error> {
let mut client = Client::new(rand::thread_rng(), if_mac);

let stack: Udp2RawStack<_> = Udp2RawStack::new(StdRawStack::new(if_index));
let mut buf = [0; 1500];

loop {
let mut socket = bind(
let mut socket = io::bind(
&stack,
SocketAddrV4::new(
Ipv4Addr::UNSPECIFIED,
DEFAULT_CLIENT_PORT,
),
SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, DEFAULT_CLIENT_PORT),
)
.await?;

let (mut lease, options) =
Lease::new(&mut client, &mut socket, &mut buf).await?;
let (mut lease, options) = Lease::new(&mut client, &mut socket, &mut buf).await?;

info!("Got lease {lease:?} with options {options:?}");

info!("Entering an endless loop to keep the lease...");

lease.keep(&mut client, &mut socket, &mut buf).await?;
}
}
Expand All @@ -49,16 +60,22 @@ async fn run(if_index: u8, if_mac: [u8; 6]) -> Result<(), impl Debug> {
### DHCP server

```rust
use edge_raw::{StdRawStack, Udp2RawStack};
use edge_dhcp::{self, DEFAULT_SERVER_PORT, Server, ServerOptions, io::Error};
use edge_raw::io::Udp2RawStack;
use edge_std_nal_async::StdRawStack;

use edge_dhcp::io::{self, DEFAULT_SERVER_PORT};
use edge_dhcp::server::{Server, ServerOptions};

use embedded_nal_async::{Ipv4Addr, SocketAddrV4};

fn main() {
futures_lite::task::block_on(run(0)).unwrap();
futures_lite::future::block_on(run(
0, // The interface index of the interface (e.g. eno0) to use; run `ip addr` to see it
))
.unwrap();
}

async fn run(if_index: u8) -> Result<(), impl Debug> {
async fn run(if_index: u32) -> Result<(), anyhow::Error> {
let stack: Udp2RawStack<_> = Udp2RawStack::new(StdRawStack::new(if_index));

let mut buf = [0; 1500];
Expand All @@ -69,12 +86,14 @@ async fn run(if_index: u8) -> Result<(), impl Debug> {

let mut gw_buf = [Ipv4Addr::UNSPECIFIED];

io::run(
io::server::run(
&mut Server::<64>::new(ip), // Will give IP addresses in the rage 192.168.0.50 - 192.168.0.200, subnet 255.255.255.0
&ServerOptions::new(ip, Some(&mut gw_buf)),
&mut socket,
&mut buf,
)
.await
.await?;

Ok(())
}
```
17 changes: 16 additions & 1 deletion edge-dhcp/src/io.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use core::fmt::Debug;
use core::fmt::{self, Debug};

use embedded_nal_async::{SocketAddr, SocketAddrV4, UdpStack, UnconnectedUdp};
use embedded_nal_async_xtra::UnconnectedUdpWithMac;
Expand All @@ -23,6 +23,21 @@ impl<E> From<dhcp::Error> for Error<E> {
}
}

impl<E> fmt::Display for Error<E>
where
E: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(err) => write!(f, "IO error: {err}"),
Self::Format(err) => write!(f, "Format error: {err}"),
}
}
}

#[cfg(feature = "std")]
impl<E> std::error::Error for Error<E> where E: std::error::Error {}

/// A fallback implementation of `UnconnectedUdpWithMac` that does not support MAC addresses.
/// Might or might not work depending on the DHCP client.
pub struct UnconnectedUdpWithMacFallback<T>(pub T);
Expand Down
23 changes: 21 additions & 2 deletions edge-dhcp/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![no_std]
#![cfg_attr(not(feature = "std"), no_std)]

use core::fmt;
/// This code is a `no_std` and no-alloc modification of https://github.com/krolaw/dhcp4r
use core::fmt;
use core::str::Utf8Error;

pub use no_std_net::Ipv4Addr;
Expand Down Expand Up @@ -37,6 +37,25 @@ impl From<bytes::Error> for Error {
}
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let str = match self {
Self::DataUnderflow => "Data underflow",
Self::BufferOverflow => "Buffer overflow",
Self::InvalidPacket => "Invalid packet",
Self::InvalidUtf8Str(_) => "Invalid Utf8 string",
Self::InvalidMessageType => "Invalid message type",
Self::MissingCookie => "Missing cookie",
Self::InvalidHlen => "Invalid hlen",
};

write!(f, "{}", str)
}
}

#[cfg(feature = "std")]
impl std::error::Error for Error {}

///
/// DHCP Message Type.
///
Expand Down
4 changes: 2 additions & 2 deletions edge-mdns/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ version = "0.1.0"
edition = "2021"

[features]
default = ["io"]
std = []
default = ["std"]
std = ["io"]
io = ["embassy-futures", "embassy-sync", "embassy-time", "embedded-nal-async", "embedded-nal-async-xtra"]

[dependencies]
Expand Down
16 changes: 16 additions & 0 deletions edge-mdns/src/io.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use core::fmt;
use core::pin::pin;

use embassy_futures::select::{select, Either};
Expand Down Expand Up @@ -40,6 +41,21 @@ impl<E> From<MdnsError> for MdnsIoError<E> {
}
}

impl<E> fmt::Display for MdnsIoError<E>
where
E: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::MdnsError(err) => write!(f, "mDNS error: {}", err),
Self::IoError(err) => write!(f, "IO error: {}", err),
}
}
}

#[cfg(feature = "std")]
impl<E> std::error::Error for MdnsIoError<E> where E: std::error::Error {}

pub struct MdnsRunBuffers {
tx_buf: core::mem::MaybeUninit<[u8; MAX_TX_BUF_SIZE]>,
rx_buf: core::mem::MaybeUninit<[u8; MAX_RX_BUF_SIZE]>,
Expand Down
3 changes: 2 additions & 1 deletion edge-raw/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ edition = "2021"
rust-version = "1.75"

[features]
default = ["io"]
default = ["std"]
std = ["io"]
io = ["embedded-io-async", "embedded-nal-async", "embedded-nal-async-xtra"]

[dependencies]
Expand Down
19 changes: 18 additions & 1 deletion edge-raw/src/io.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use core::{fmt::Debug, mem::MaybeUninit};
use core::fmt::{self, Debug};
use core::mem::MaybeUninit;

use embedded_io_async::ErrorKind;

Expand Down Expand Up @@ -34,6 +35,22 @@ where
}
}

impl<E> fmt::Display for Error<E>
where
E: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(err) => write!(f, "IO error: {err}"),
Self::UnsupportedProtocol => write!(f, "Unsupported protocol"),
Self::RawError(err) => write!(f, "Raw error: {err}"),
}
}
}

#[cfg(feature = "std")]
impl<E> std::error::Error for Error<E> where E: std::error::Error {}

pub struct ConnectedUdp2RawSocket<T, const N: usize>(T, SocketAddrV4, SocketAddrV4);

impl<T, const N: usize> ConnectedUdp for ConnectedUdp2RawSocket<T, N>
Expand Down
18 changes: 18 additions & 0 deletions edge-raw/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![allow(async_fn_in_trait)]

use core::fmt;

use no_std_net::{Ipv4Addr, SocketAddrV4};

use self::udp::UdpPacketHeader;
Expand Down Expand Up @@ -32,6 +34,22 @@ impl From<bytes::Error> for Error {
}
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let str = match self {
Self::DataUnderflow => "Data underflow",
Self::BufferOverflow => "Buffer overflow",
Self::InvalidFormat => "Invalid format",
Self::InvalidChecksum => "Invalid checksum",
};

write!(f, "{}", str)
}
}

#[cfg(feature = "std")]
impl std::error::Error for Error {}

#[allow(clippy::type_complexity)]
pub fn ip_udp_decode(
packet: &[u8],
Expand Down
7 changes: 2 additions & 5 deletions edge-std-nal-async/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,7 @@ impl TcpConnect for StdTcpConnect {

type Connection<'a> = StdTcpConnection where Self: 'a;

async fn connect<'a>(
&'a self,
remote: SocketAddr,
) -> Result<Self::Connection<'a>, Self::Error> {
async fn connect(&self, remote: SocketAddr) -> Result<Self::Connection<'_>, Self::Error> {
let connection = Async::<TcpStream>::connect(to_std_addr(remote)).await?;

Ok(StdTcpConnection(connection))
Expand Down Expand Up @@ -424,7 +421,7 @@ impl RawStack for StdRawStack {
fn as_sockaddr_ll(storage: &libc::sockaddr_storage, len: usize) -> io::Result<&libc::sockaddr_ll> {
match storage.ss_family as core::ffi::c_int {
libc::AF_PACKET => {
assert!(len as usize >= core::mem::size_of::<libc::sockaddr_ll>());
assert!(len >= core::mem::size_of::<libc::sockaddr_ll>());
Ok(unsafe { (storage as *const _ as *const libc::sockaddr_ll).as_ref() }.unwrap())
}
_ => Err(io::Error::new(ErrorKind::InvalidInput, "invalid argument")),
Expand Down
Loading

0 comments on commit aa6c728

Please sign in to comment.