#[cfg(all(feature = "std", not(feature = "embassy-net")))]
pub use self::async_io::*;
#[cfg(feature = "embassy-net")]
pub use self::embassy_net::*;
#[cfg(feature = "std")]
pub mod async_io {
use crate::error::*;
use std::net::UdpSocket;
use async_io::Async;
use log::{debug, info, warn};
use crate::transport::network::std_stack::{NetworkStack, NetworkStackDriver};
use crate::transport::network::{Ipv4Addr, Ipv6Addr, SocketAddr};
pub struct UdpBuffers(());
impl UdpBuffers {
pub const fn new() -> Self {
Self(())
}
}
pub struct UdpListener<'a, D>(Async<UdpSocket>, &'a NetworkStack<D>)
where
D: NetworkStackDriver + 'static;
impl<'a, D> UdpListener<'a, D>
where
D: NetworkStackDriver + 'a + 'static,
{
pub async fn new(
stack: &'a NetworkStack<D>,
addr: SocketAddr,
_buffers: &'a mut UdpBuffers,
) -> Result<UdpListener<'a, D>, Error> {
let listener = UdpListener(Async::<UdpSocket>::bind(addr)?, stack);
info!("Listening on {:?}", addr);
Ok(listener)
}
pub async fn join_multicast_v6(
&mut self,
multiaddr: Ipv6Addr,
interface: u32,
) -> Result<(), Error> {
self.0.get_ref().join_multicast_v6(&multiaddr, interface)?;
info!("Joined IPV6 multicast {}/{}", multiaddr, interface);
Ok(())
}
pub async fn join_multicast_v4(
&mut self,
multiaddr: Ipv4Addr,
interface: Ipv4Addr,
) -> Result<(), Error> {
#[cfg(not(target_os = "espidf"))]
self.0.get_ref().join_multicast_v4(&multiaddr, &interface)?;
#[cfg(target_os = "espidf")]
{
fn esp_setsockopt<T>(
socket: &UdpSocket,
proto: u32,
option: u32,
value: T,
) -> Result<(), Error> {
use std::os::fd::AsRawFd;
esp_idf_sys::esp!(unsafe {
esp_idf_sys::lwip_setsockopt(
socket.as_raw_fd(),
proto as _,
option as _,
&value as *const _ as *const _,
core::mem::size_of::<T>() as _,
)
})
.map_err(|_| ErrorCode::StdIoError)?;
Ok(())
}
let mreq = esp_idf_sys::ip_mreq {
imr_multiaddr: esp_idf_sys::in_addr {
s_addr: u32::from_ne_bytes(multiaddr.octets()),
},
imr_interface: esp_idf_sys::in_addr {
s_addr: u32::from_ne_bytes(interface.octets()),
},
};
esp_setsockopt(
&mut self.0.get_ref(),
esp_idf_sys::IPPROTO_IP,
esp_idf_sys::IP_ADD_MEMBERSHIP,
mreq,
)?;
}
info!("Joined IP multicast {}/{}", multiaddr, interface);
Ok(())
}
pub async fn recv(&self, in_buf: &mut [u8]) -> Result<(usize, SocketAddr), Error> {
let (len, addr) = self.0.recv_from(in_buf).await.map_err(|e| {
warn!("Error on the network: {:?}", e);
ErrorCode::Network
})?;
debug!("Got packet {:?} from addr {:?}", &in_buf[..len], addr);
Ok((len, addr))
}
pub async fn send(&self, addr: SocketAddr, out_buf: &[u8]) -> Result<usize, Error> {
let len = self.0.send_to(out_buf, addr).await.map_err(|e| {
warn!("Error on the network: {:?}", e);
ErrorCode::Network
})?;
debug!(
"Send packet {:?} ({}/{}) to addr {:?}",
out_buf,
out_buf.len(),
len,
addr
);
Ok(len)
}
}
}
#[cfg(feature = "embassy-net")]
pub mod embassy_net {
use core::mem::MaybeUninit;
use embassy_net::udp::{PacketMetadata, UdpSocket};
use smoltcp::wire::{IpAddress, IpEndpoint, Ipv4Address, Ipv6Address};
use crate::error::*;
use log::{debug, info, warn};
use crate::transport::network::embassy_net_stack::{NetworkStack, NetworkStackDriver};
use crate::transport::network::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
const RX_BUF_SIZE: usize = 4096;
const TX_BUF_SIZE: usize = 4096;
pub struct UdpBuffers {
rx_buffer: MaybeUninit<[u8; RX_BUF_SIZE]>,
tx_buffer: MaybeUninit<[u8; TX_BUF_SIZE]>,
rx_meta: [PacketMetadata; 16],
tx_meta: [PacketMetadata; 16],
}
impl UdpBuffers {
pub const fn new() -> Self {
Self {
rx_buffer: MaybeUninit::uninit(),
tx_buffer: MaybeUninit::uninit(),
rx_meta: [PacketMetadata::EMPTY; 16],
tx_meta: [PacketMetadata::EMPTY; 16],
}
}
}
pub struct UdpListener<'a, D>(UdpSocket<'a>, &'a NetworkStack<D>)
where
D: NetworkStackDriver + 'static;
impl<'a, D> UdpListener<'a, D>
where
D: NetworkStackDriver + 'a + 'static,
{
pub async fn new(
stack: &'a NetworkStack<D>,
addr: SocketAddr,
buffers: &'a mut UdpBuffers,
) -> Result<UdpListener<'a, D>, Error> {
let mut socket = UdpSocket::new(
stack,
&mut buffers.rx_meta,
unsafe { buffers.rx_buffer.assume_init_mut() },
&mut buffers.tx_meta,
unsafe { buffers.tx_buffer.assume_init_mut() },
);
socket.bind(addr.port()).map_err(|e| {
warn!("Error on the network: {:?}", e);
ErrorCode::Network
})?;
info!("Listening on {:?}", addr);
Ok(UdpListener(socket, stack))
}
pub async fn join_multicast_v6(
&mut self,
multiaddr: Ipv6Addr,
_interface: u32,
) -> Result<(), Error> {
self.1
.join_multicast_group(Self::from_ip_addr(IpAddr::V6(multiaddr)))
.await
.map_err(|e| {
warn!("Error on the network: {:?}", e);
ErrorCode::Network
})?;
info!("Joined IP multicast {}", multiaddr);
Ok(())
}
pub async fn join_multicast_v4(
&mut self,
multiaddr: Ipv4Addr,
_interface: Ipv4Addr,
) -> Result<(), Error> {
self.1
.join_multicast_group(Self::from_ip_addr(IpAddr::V4(multiaddr)))
.await
.map_err(|e| {
warn!("Error on the network: {:?}", e);
ErrorCode::Network
})?;
info!("Joined IP multicast {}", multiaddr);
Ok(())
}
pub async fn recv(&self, in_buf: &mut [u8]) -> Result<(usize, SocketAddr), Error> {
let (len, ep) = self.0.recv_from(in_buf).await.map_err(|e| {
warn!("Error on the network: {:?}", e);
ErrorCode::Network
})?;
let addr = Self::to_socket_addr(ep);
debug!("Got packet {:?} from addr {:?}", &in_buf[..len], addr);
Ok((len, addr))
}
pub async fn send(&self, addr: SocketAddr, out_buf: &[u8]) -> Result<usize, Error> {
self.0
.send_to(out_buf, Self::from_socket_addr(addr))
.await
.map_err(|e| {
warn!("Error on the network: {:?}", e);
ErrorCode::Network
})?;
debug!(
"Send packet {:?} ({}/{}) to addr {:?}",
out_buf,
out_buf.len(),
out_buf.len(),
addr
);
Ok(out_buf.len())
}
fn to_socket_addr(ep: IpEndpoint) -> SocketAddr {
SocketAddr::new(Self::to_ip_addr(ep.addr), ep.port)
}
fn from_socket_addr(addr: SocketAddr) -> IpEndpoint {
IpEndpoint::new(Self::from_ip_addr(addr.ip()), addr.port())
}
fn to_ip_addr(ip: IpAddress) -> IpAddr {
match ip {
IpAddress::Ipv4(addr) => IpAddr::V4(Ipv4Addr::from(addr.0)),
IpAddress::Ipv6(addr) => IpAddr::V6(Ipv6Addr::from(addr.0)),
}
}
fn from_ip_addr(ip: IpAddr) -> IpAddress {
match ip {
IpAddr::V4(v4) => IpAddress::Ipv4(Ipv4Address::from_bytes(&v4.octets())),
IpAddr::V6(v6) => IpAddress::Ipv6(Ipv6Address::from_bytes(&v6.octets())),
}
}
}
}