veecle_osal_api/net/
udp.rs

1//! UDP socket abstractions.
2
3use core::fmt::Display;
4use core::fmt::Formatter;
5use core::net::SocketAddr;
6
7/// UDP socket for sending and receiving datagrams.
8///
9/// UDP is connectionless - each send/receive operation can target different addresses.
10///
11/// # Example
12///
13/// ```no_run
14/// use veecle_osal_api::net::udp::UdpSocket;
15/// use core::net::SocketAddr;
16///
17/// async fn udp_echo<S>(mut socket: S)
18/// where
19///     S: UdpSocket
20/// {
21///     let addr: SocketAddr = "0.0.0.0:8080".parse().unwrap();
22///     socket.bind(addr).await.unwrap();
23///
24///     let mut buffer = [0u8; 1500];
25///     loop {
26///         let (size, peer) = socket.recv_from(&mut buffer).await.unwrap();
27///         socket.send_to(&buffer[..size], peer).await.unwrap();
28///     }
29/// }
30/// ```
31#[expect(async_fn_in_trait)]
32pub trait UdpSocket {
33    /// Binds the socket to a local address.
34    ///
35    /// If the specified port is `0`, the port is assigned automatically and can be queried with [`Self::local_addr`].
36    async fn bind(&mut self, address: SocketAddr) -> Result<(), Error>;
37
38    /// Returns the local address this socket is bound to.
39    fn local_addr(&self) -> Result<SocketAddr, Error>;
40
41    /// Receives a datagram.
42    ///
43    /// Returns the number of bytes received and the sender's address.
44    /// If the datagram is larger than the buffer, excess bytes may be discarded.
45    async fn recv_from(&self, buffer: &mut [u8]) -> Result<(usize, SocketAddr), Error>;
46
47    /// Sends a datagram to the specified address.
48    ///
49    /// Returns the number of bytes sent.
50    async fn send_to(&self, buffer: &[u8], address: SocketAddr) -> Result<usize, Error>;
51
52    /// Closes the UDP socket.
53    fn close(&mut self);
54}
55
56/// Errors that can occur when using UDP sockets.
57#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Copy, Clone, Hash)]
58pub enum Error {
59    /// The provided buffer was too small for the received datagram.
60    ///
61    /// The datagram may have been dropped.
62    BufferTooSmall,
63    /// The provided buffer was too large for internal buffer.
64    BufferTooLarge,
65    /// The socket is in an invalid state.
66    InvalidState,
67    /// No permission to access the resource.
68    PermissionDenied,
69    /// No route to host.
70    NoRoute,
71    /// The provided port is invalid.
72    InvalidPort,
73    /// The provided address is invalid.
74    ///
75    /// This can occur if the address is already in use or doesn't exist.
76    InvalidAddress,
77    /// The network stack is down.
78    NetworkDown,
79    /// The socket is not bound to an outgoing address and port.
80    SocketNotBound,
81    /// Currently unhandled error occurred.
82    /// Please open a bug report if you encounter this error.
83    Other,
84}
85
86impl Display for Error {
87    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
88        match self {
89            Error::InvalidState => {
90                write!(f, "The socket is in an invalid state.")
91            }
92            Error::BufferTooSmall => {
93                write!(
94                    f,
95                    "The provided buffer was too small for the received datagram."
96                )
97            }
98            Error::BufferTooLarge => {
99                write!(f, "The provided buffer was too large for internal buffer.")
100            }
101            Error::NoRoute => {
102                write!(f, "No route to host.")
103            }
104            Error::PermissionDenied => {
105                write!(f, "No permission to access the resource.")
106            }
107            Error::InvalidPort => {
108                write!(f, "The provided port is invalid.")
109            }
110            Error::InvalidAddress => {
111                write!(f, "The provided address is invalid.")
112            }
113            Error::NetworkDown => {
114                write!(f, "The network stack is down.")
115            }
116            Error::Other => {
117                write!(
118                    f,
119                    "Unspecified error, please open a bug report if you encounter this error."
120                )
121            }
122            Error::SocketNotBound => {
123                write!(
124                    f,
125                    "The socket is not bound to an outgoing address and port."
126                )
127            }
128        }
129    }
130}
131
132impl core::error::Error for Error {}
133
134#[doc(hidden)]
135#[cfg(feature = "test-suites")]
136#[cfg_attr(coverage_nightly, coverage(off))]
137pub mod test_suite {
138    #![expect(missing_docs, reason = "tests")]
139    //! Test suite for UDP sockets.
140
141    use crate::net::udp::{Error, UdpSocket};
142    use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
143
144    pub async fn test_bind_all_zero_address_v4(mut socket: impl UdpSocket) {
145        let address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
146
147        socket.bind(address).await.unwrap();
148
149        let bound_addr = socket.local_addr().unwrap();
150
151        assert_eq!(bound_addr.ip(), IpAddr::V4(std::net::Ipv4Addr::UNSPECIFIED));
152
153        assert_ne!(
154            bound_addr.port(),
155            0,
156            "port should be automatically assigned"
157        );
158
159        socket.close();
160    }
161
162    pub async fn test_bind_all_zero_address_v6(mut socket: impl UdpSocket) {
163        let address = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), 0);
164
165        socket.bind(address).await.unwrap();
166
167        let bound_addr = socket.local_addr().unwrap();
168
169        assert_eq!(bound_addr.ip(), IpAddr::V6(std::net::Ipv6Addr::UNSPECIFIED));
170
171        assert_ne!(
172            bound_addr.port(),
173            0,
174            "port should be automatically assigned"
175        );
176
177        socket.close();
178    }
179
180    pub async fn test_bind_specific_port(mut socket: impl UdpSocket, ip_address: &str) {
181        let ip_address = ip_address.parse().unwrap();
182        let address = SocketAddr::new(ip_address, 58080);
183
184        socket.bind(address).await.unwrap();
185
186        let bound_addr = socket.local_addr().unwrap();
187
188        assert_eq!(bound_addr.ip(), ip_address);
189        assert_eq!(bound_addr.port(), 58080, "port should match requested port");
190
191        socket.close();
192    }
193
194    pub async fn test_send_recv(
195        mut socket1: impl UdpSocket,
196        mut socket2: impl UdpSocket,
197        ip_address: &str,
198    ) {
199        let ip_address = ip_address.parse().unwrap();
200        let addr1 = SocketAddr::new(ip_address, 58081);
201        let addr2 = SocketAddr::new(ip_address, 58082);
202
203        socket1.bind(addr1).await.unwrap();
204        socket2.bind(addr2).await.unwrap();
205
206        let send_data = b"Hello, UDP!";
207        let mut recv_buffer = [0u8; 64];
208
209        let sent = socket1.send_to(send_data, addr2).await.unwrap();
210        assert_eq!(sent, send_data.len());
211
212        let (received, sender_addr) = socket2.recv_from(&mut recv_buffer).await.unwrap();
213        assert_eq!(received, send_data.len());
214        assert_eq!(&recv_buffer[..received], send_data);
215        assert_eq!(sender_addr, addr1);
216
217        let response = b"Hello back!";
218        let sent = socket2.send_to(response, addr1).await.unwrap();
219        assert_eq!(sent, response.len());
220
221        let (received, sender_addr) = socket1.recv_from(&mut recv_buffer).await.unwrap();
222        assert_eq!(received, response.len());
223        assert_eq!(&recv_buffer[..received], response);
224        assert_eq!(sender_addr, addr2);
225
226        socket1.close();
227        socket2.close();
228    }
229
230    pub async fn test_local_addr_before_bind(socket: impl UdpSocket) {
231        assert_eq!(socket.local_addr(), Err(Error::SocketNotBound));
232    }
233
234    pub async fn test_close_socket(mut socket: impl UdpSocket, ip_address: &str) {
235        let ip_address = ip_address.parse().unwrap();
236        let address = SocketAddr::new(ip_address, 58085);
237
238        socket.bind(address).await.unwrap();
239        let bound_addr = socket.local_addr().unwrap();
240        assert_eq!(bound_addr, address);
241
242        socket.close();
243
244        assert_eq!(socket.local_addr(), Err(Error::SocketNotBound));
245    }
246
247    pub async fn test_recv_without_bind(socket: impl UdpSocket) {
248        let mut buffer = [0u8; 64];
249        assert_eq!(
250            socket.recv_from(&mut buffer).await,
251            Err(Error::SocketNotBound)
252        );
253    }
254
255    pub async fn test_send_without_bind(socket: impl UdpSocket, ip_address: &str) {
256        let ip_address = ip_address.parse().unwrap();
257        let target_addr = SocketAddr::new(ip_address, 58086);
258        let data = b"test data";
259
260        assert_eq!(
261            socket.send_to(data, target_addr).await,
262            Err(Error::SocketNotBound)
263        );
264    }
265
266    pub async fn test_bind_multiple_sockets_same_ip(
267        mut socket1: impl UdpSocket,
268        mut socket2: impl UdpSocket,
269        ip_address: &str,
270    ) {
271        let ip_address = ip_address.parse().unwrap();
272        let address = SocketAddr::new(ip_address, 58087);
273
274        socket1.bind(address).await.unwrap();
275        socket2.bind(address).await.unwrap();
276    }
277
278    pub async fn test_zero_length_datagram(
279        mut socket1: impl UdpSocket,
280        mut socket2: impl UdpSocket,
281        ip_address: &str,
282    ) {
283        let ip_address = ip_address.parse().unwrap();
284        let addr1 = SocketAddr::new(ip_address, 58088);
285        let addr2 = SocketAddr::new(ip_address, 58089);
286
287        socket1.bind(addr1).await.unwrap();
288        socket2.bind(addr2).await.unwrap();
289
290        let empty_data = &[];
291        let sent = socket1.send_to(empty_data, addr2).await.unwrap();
292        assert_eq!(sent, 0);
293
294        let mut recv_buffer = [0u8; 64];
295        let (received, sender_addr) = socket2.recv_from(&mut recv_buffer).await.unwrap();
296        assert_eq!(received, 0);
297        assert_eq!(sender_addr, addr1);
298
299        socket1.close();
300        socket2.close();
301    }
302
303    pub async fn test_max_datagram_size(
304        mut socket1: impl UdpSocket,
305        mut socket2: impl UdpSocket,
306        ip_address: &str,
307    ) {
308        let ip_address = ip_address.parse().unwrap();
309        let addr1 = SocketAddr::new(ip_address, 58090);
310        let addr2 = SocketAddr::new(ip_address, 58091);
311
312        socket1.bind(addr1).await.unwrap();
313        socket2.bind(addr2).await.unwrap();
314
315        // Test maximum practical UDP payload size.
316        // 65507 = 65535 - 8 (UDP header) - 20 (IPv4 header).
317        const MAX_SIZE: usize = 65507;
318        let mut send_data = [0u8; MAX_SIZE];
319        for (i, byte) in send_data.iter_mut().enumerate() {
320            *byte = (i % 256) as u8;
321        }
322
323        let sent = socket1.send_to(&send_data, addr2).await.unwrap();
324        assert_eq!(sent, MAX_SIZE);
325
326        let mut recv_buffer = [0u8; MAX_SIZE];
327        let (received, sender_addr) = socket2.recv_from(&mut recv_buffer).await.unwrap();
328        assert_eq!(received, MAX_SIZE);
329        assert_eq!(&recv_buffer[..], &send_data[..]);
330        assert_eq!(sender_addr, addr1);
331
332        socket1.close();
333        socket2.close();
334    }
335
336    pub async fn test_multiple_binds(mut socket: impl UdpSocket, ip_address: &str) {
337        let ip_address = ip_address.parse().unwrap();
338        let addr1 = SocketAddr::new(ip_address, 58092);
339        let addr2 = SocketAddr::new(ip_address, 58093);
340
341        socket.bind(addr1).await.unwrap();
342        assert_eq!(socket.local_addr().unwrap(), addr1);
343
344        assert_eq!(socket.bind(addr2).await, Err(Error::InvalidState));
345
346        socket.close();
347    }
348
349    pub async fn test_rebind_after_close(mut socket: impl UdpSocket, ip_address: &str) {
350        let ip_address = ip_address.parse().unwrap();
351        let addr1 = SocketAddr::new(ip_address, 58094);
352        let addr2 = SocketAddr::new(ip_address, 58095);
353
354        socket.bind(addr1).await.unwrap();
355        assert_eq!(socket.local_addr().unwrap(), addr1);
356
357        socket.close();
358
359        assert_eq!(socket.local_addr(), Err(Error::SocketNotBound));
360
361        socket.bind(addr2).await.unwrap();
362        assert_eq!(socket.local_addr().unwrap(), addr2);
363
364        socket.close();
365    }
366}