#[cfg(feature = "std")]
use std::{
io::{self, ErrorKind},
net::{SocketAddr, UdpSocket},
};
use crate::{consts::PROTOCOL_MAXIMUM_MTU, Address};
macro_rules! socket_error {
($(#[$($attrss:tt)*])*) => {
#[cfg(feature = "std")]
$(#[$($attrss)*])*
pub trait SocketError: std::error::Error {}
#[cfg(feature = "std")]
impl<T: std::error::Error> SocketError for T {}
#[cfg(not(feature = "std"))]
$(#[$($attrss)*])*
pub trait SocketError: core::fmt::Debug {}
#[cfg(not(feature = "std"))]
impl<T: core::fmt::Debug> SocketError for T {}
};
}
socket_error!(
);
pub const MTU_MAX: usize = PROTOCOL_MAXIMUM_MTU;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SocketOptions {
pub receive_buffer: usize,
pub send_buffer: usize,
}
#[allow(clippy::type_complexity, clippy::missing_errors_doc)]
pub trait Socket: Sized {
type Address: Address;
type Error: SocketError;
fn init(&mut self, _socket_options: SocketOptions) -> Result<(), Self::Error> {
Ok(())
}
fn send(&mut self, address: Self::Address, buffer: &[u8]) -> Result<usize, Self::Error>;
fn receive(
&mut self,
buffer: &mut [u8; MTU_MAX],
) -> Result<Option<(Self::Address, PacketReceived)>, Self::Error>;
}
#[derive(Debug)]
pub enum PacketReceived {
Complete(usize),
Partial,
}
#[cfg(feature = "std")]
impl Socket for UdpSocket {
type Address = SocketAddr;
type Error = io::Error;
fn init(&mut self, _socket_options: SocketOptions) -> Result<(), io::Error> {
self.set_nonblocking(true)?;
self.set_broadcast(true)?;
Ok(())
}
fn send(&mut self, address: SocketAddr, buffer: &[u8]) -> Result<usize, io::Error> {
match self.send_to(buffer, address) {
Ok(sent_length) => Ok(sent_length),
Err(err) if err.kind() == ErrorKind::WouldBlock => Ok(0),
Err(err) => Err(err),
}
}
fn receive(
&mut self,
buffer: &mut [u8; MTU_MAX],
) -> Result<Option<(SocketAddr, PacketReceived)>, io::Error> {
match self.recv_from(buffer) {
Ok((recv_length, recv_addr)) => {
Ok(Some((recv_addr, PacketReceived::Complete(recv_length))))
}
Err(err) if err.kind() == ErrorKind::WouldBlock => Ok(None),
Err(err) => Err(err),
}
}
}