veecle_osal_embassy/net/
udp.rs

1//! UDP socket implementation for Embassy.
2
3use crate::IntoOsalError;
4use core::net::IpAddr;
5use core::net::SocketAddr;
6use embassy_net::IpAddress;
7use embassy_net::udp::{BindError, RecvError, SendError};
8use veecle_osal_api::net::udp::Error;
9
10/// UDP socket for sending and receiving datagrams.
11pub struct UdpSocket<'a> {
12    socket: embassy_net::udp::UdpSocket<'a>,
13    /// Whether the socket is bound.
14    is_bound: bool,
15}
16
17impl<'a> core::fmt::Debug for UdpSocket<'a> {
18    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
19        f.debug_struct("UdpSocket").finish()
20    }
21}
22
23impl<'a> UdpSocket<'a> {
24    /// Creates a new `UdpSocket`.
25    ///
26    /// The socket must be closed.
27    pub fn new(socket: embassy_net::udp::UdpSocket<'a>) -> Result<Self, Error> {
28        if socket.is_open() {
29            return Err(Error::InvalidState);
30        }
31        Ok(Self {
32            socket,
33            is_bound: false,
34        })
35    }
36}
37
38impl<'a> veecle_osal_api::net::udp::UdpSocket for UdpSocket<'a> {
39    async fn bind(&mut self, address: SocketAddr) -> Result<(), Error> {
40        self.socket
41            .bind(address)
42            .map_err(IntoOsalError::into_osal_error)?;
43        self.is_bound = true;
44        Ok(())
45    }
46
47    fn local_addr(&self) -> Result<SocketAddr, Error> {
48        self.socket
49            .endpoint()
50            .addr
51            .ok_or(Error::SocketNotBound)
52            .map(|address| {
53                let address = match address {
54                    IpAddress::Ipv4(address) => IpAddr::V4(address),
55                    IpAddress::Ipv6(address) => IpAddr::V6(address),
56                };
57                SocketAddr::new(address, self.socket.endpoint().port)
58            })
59    }
60
61    async fn recv_from(&self, buffer: &mut [u8]) -> Result<(usize, SocketAddr), Error> {
62        if !self.is_bound {
63            return Err(Error::SocketNotBound);
64        }
65        let (read, metadata) = self
66            .socket
67            .recv_from(buffer)
68            .await
69            .map_err(IntoOsalError::into_osal_error)?;
70        let address = match metadata.endpoint.addr {
71            IpAddress::Ipv4(address) => IpAddr::V4(address),
72            IpAddress::Ipv6(address) => IpAddr::V6(address),
73        };
74        let address: SocketAddr = SocketAddr::new(address, metadata.endpoint.port);
75        Ok((read, address))
76    }
77
78    async fn send_to(&self, buffer: &[u8], address: SocketAddr) -> Result<usize, Error> {
79        if !self.is_bound {
80            return Err(Error::SocketNotBound);
81        }
82        self.socket
83            .send_to(buffer, address)
84            .await
85            .map_err(IntoOsalError::into_osal_error)?;
86        Ok(buffer.len())
87    }
88
89    fn close(&mut self) {
90        self.socket.close();
91        self.is_bound = false;
92    }
93}
94
95impl IntoOsalError<Error> for BindError {
96    fn into_osal_error(self) -> Error {
97        match self {
98            BindError::InvalidState => Error::InvalidState,
99            BindError::NoRoute => Error::NoRoute,
100        }
101    }
102}
103
104impl IntoOsalError<Error> for RecvError {
105    fn into_osal_error(self) -> Error {
106        match self {
107            RecvError::Truncated => Error::BufferTooSmall,
108        }
109    }
110}
111
112impl IntoOsalError<Error> for SendError {
113    fn into_osal_error(self) -> Error {
114        match self {
115            SendError::NoRoute => Error::NoRoute,
116            SendError::SocketNotBound => Error::SocketNotBound,
117            SendError::PacketTooLarge => Error::BufferTooLarge,
118        }
119    }
120}