aboutsummaryrefslogtreecommitdiff
path: root/embassy-net/src
diff options
context:
space:
mode:
authorEasyoakland <[email protected]>2025-01-24 18:45:43 -0700
committerEasyoakland <[email protected]>2025-01-24 18:45:43 -0700
commit2fe299cc538c28711fd838b5f2c3da6143a7335e (patch)
treebba0017b2442bad552e9430fc2cb6d307acb3935 /embassy-net/src
parent51d87c6603631fda6fb59ca1a65a99c08138b081 (diff)
don't infinite loop if udp::send methods receive a buffer too large to ever be sent
Diffstat (limited to 'embassy-net/src')
-rw-r--r--embassy-net/src/udp.rs28
1 files changed, 26 insertions, 2 deletions
diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs
index 64a22d45b..7baa89ea0 100644
--- a/embassy-net/src/udp.rs
+++ b/embassy-net/src/udp.rs
@@ -21,7 +21,7 @@ pub enum BindError {
21 NoRoute, 21 NoRoute,
22} 22}
23 23
24/// Error returned by [`UdpSocket::recv_from`] and [`UdpSocket::send_to`]. 24/// Error returned by [`UdpSocket::send_to`].
25#[derive(PartialEq, Eq, Clone, Copy, Debug)] 25#[derive(PartialEq, Eq, Clone, Copy, Debug)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))] 26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
27pub enum SendError { 27pub enum SendError {
@@ -29,9 +29,11 @@ pub enum SendError {
29 NoRoute, 29 NoRoute,
30 /// Socket not bound to an outgoing port. 30 /// Socket not bound to an outgoing port.
31 SocketNotBound, 31 SocketNotBound,
32 /// There is not enough transmit buffer capacity to ever send this packet.
33 Truncated,
32} 34}
33 35
34/// Error returned by [`UdpSocket::recv_from`] and [`UdpSocket::send_to`]. 36/// Error returned by [`UdpSocket::recv_from`].
35#[derive(PartialEq, Eq, Clone, Copy, Debug)] 37#[derive(PartialEq, Eq, Clone, Copy, Debug)]
36#[cfg_attr(feature = "defmt", derive(defmt::Format))] 38#[cfg_attr(feature = "defmt", derive(defmt::Format))]
37pub enum RecvError { 39pub enum RecvError {
@@ -224,6 +226,8 @@ impl<'a> UdpSocket<'a> {
224 /// 226 ///
225 /// This method will wait until the datagram has been sent. 227 /// This method will wait until the datagram has been sent.
226 /// 228 ///
229 /// If the socket's send buffer is too small to fit `buf`, this method will return `Poll::Ready(Err(SendError::Truncated))`
230 ///
227 /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)` 231 /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)`
228 pub async fn send_to<T>(&self, buf: &[u8], remote_endpoint: T) -> Result<(), SendError> 232 pub async fn send_to<T>(&self, buf: &[u8], remote_endpoint: T) -> Result<(), SendError>
229 where 233 where
@@ -240,11 +244,21 @@ impl<'a> UdpSocket<'a> {
240 /// When the socket's send buffer is full, this method will return `Poll::Pending` 244 /// When the socket's send buffer is full, this method will return `Poll::Pending`
241 /// and register the current task to be notified when the buffer has space available. 245 /// and register the current task to be notified when the buffer has space available.
242 /// 246 ///
247 /// If the socket's send buffer is too small to fit `buf`, this method will return `Poll::Ready(Err(SendError::Truncated))`
248 ///
243 /// When the remote endpoint is not reachable, this method will return `Poll::Ready(Err(Error::NoRoute))`. 249 /// When the remote endpoint is not reachable, this method will return `Poll::Ready(Err(Error::NoRoute))`.
244 pub fn poll_send_to<T>(&self, buf: &[u8], remote_endpoint: T, cx: &mut Context<'_>) -> Poll<Result<(), SendError>> 250 pub fn poll_send_to<T>(&self, buf: &[u8], remote_endpoint: T, cx: &mut Context<'_>) -> Poll<Result<(), SendError>>
245 where 251 where
246 T: Into<UdpMetadata>, 252 T: Into<UdpMetadata>,
247 { 253 {
254 // Don't need to wake waker in `with_mut` if the buffer will never fit the udp tx_buffer.
255 let send_capacity_too_small = self
256 .stack
257 .with(|i| i.sockets.get::<udp::Socket>(self.handle).payload_send_capacity() < buf.len());
258 if send_capacity_too_small {
259 return Poll::Ready(Err(SendError::Truncated));
260 }
261
248 self.with_mut(|s, _| match s.send_slice(buf, remote_endpoint) { 262 self.with_mut(|s, _| match s.send_slice(buf, remote_endpoint) {
249 // Entire datagram has been sent 263 // Entire datagram has been sent
250 Ok(()) => Poll::Ready(Ok(())), 264 Ok(()) => Poll::Ready(Ok(())),
@@ -268,12 +282,22 @@ impl<'a> UdpSocket<'a> {
268 /// This method will wait until the buffer can fit the requested size before 282 /// This method will wait until the buffer can fit the requested size before
269 /// calling the function to fill its contents. 283 /// calling the function to fill its contents.
270 /// 284 ///
285 /// If the socket's send buffer is too small to fit `size`, this method will return `Poll::Ready(Err(SendError::Truncated))`
286 ///
271 /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)` 287 /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)`
272 pub async fn send_to_with<T, F, R>(&mut self, size: usize, remote_endpoint: T, f: F) -> Result<R, SendError> 288 pub async fn send_to_with<T, F, R>(&mut self, size: usize, remote_endpoint: T, f: F) -> Result<R, SendError>
273 where 289 where
274 T: Into<UdpMetadata> + Copy, 290 T: Into<UdpMetadata> + Copy,
275 F: FnOnce(&mut [u8]) -> R, 291 F: FnOnce(&mut [u8]) -> R,
276 { 292 {
293 // Don't need to wake waker in `with_mut` if the buffer will never fit the udp tx_buffer.
294 let send_capacity_too_small = self
295 .stack
296 .with(|i| i.sockets.get::<udp::Socket>(self.handle).payload_send_capacity() < size);
297 if send_capacity_too_small {
298 return Err(SendError::Truncated);
299 }
300
277 let mut f = Some(f); 301 let mut f = Some(f);
278 poll_fn(move |cx| { 302 poll_fn(move |cx| {
279 self.with_mut(|s, _| { 303 self.with_mut(|s, _| {