diff --git a/embassy-net/CHANGELOG.md b/embassy-net/CHANGELOG.md index 64b3ddaf00..b67783a4e5 100644 --- a/embassy-net/CHANGELOG.md +++ b/embassy-net/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 0.9.0 - 2026-03-10 - raw: Removed unnecessary Driver type parameter from `RawSocket::new` +- `{UdpSocket, IcmpSocket}::send_to_with` support writing less than `max_size` into the buffer by returning the number of bytes written from the closure - Update embassy-sync 0.8.0 ## 0.8.0 - 2026-01-04 diff --git a/embassy-net/src/icmp.rs b/embassy-net/src/icmp.rs index 09e91a1ae2..7829ed5cdb 100644 --- a/embassy-net/src/icmp.rs +++ b/embassy-net/src/icmp.rs @@ -275,14 +275,15 @@ impl<'a> IcmpSocket<'a> { /// Enqueue a packet to be sent to a given remote address with a zero-copy function. /// /// This method will wait until the buffer can fit the requested size before - /// calling the function to fill its contents. - pub async fn send_to_with(&mut self, size: usize, remote_endpoint: T, f: F) -> Result + /// passing it to the closure. The closure returns the number of bytes + /// written into the buffer. + pub async fn send_to_with(&mut self, max_size: usize, remote_endpoint: T, f: F) -> Result where T: Into, - F: FnOnce(&mut [u8]) -> R, + F: FnOnce(&mut [u8]) -> (usize, R), { // Don't need to wake waker in `with_mut` if the buffer will never fit the icmp tx_buffer. - let send_capacity_too_small = self.with(|s, _| s.payload_send_capacity() < size); + let send_capacity_too_small = self.with(|s, _| s.payload_send_capacity() < max_size); if send_capacity_too_small { return Err(SendError::PacketTooLarge); } @@ -290,13 +291,21 @@ impl<'a> IcmpSocket<'a> { let mut f = Some(f); let remote_endpoint = remote_endpoint.into(); poll_fn(move |cx| { - self.with_mut(|s, _| match s.send(size, remote_endpoint) { - Ok(buf) => Poll::Ready(Ok({ unwrap!(f.take())(buf) })), - Err(icmp::SendError::BufferFull) => { - s.register_send_waker(cx.waker()); - Poll::Pending + self.with_mut(|s, _| { + let mut ret = None; + + match s.send_with(max_size, remote_endpoint, |buf| { + let (size, r) = unwrap!(f.take())(buf); + ret = Some(r); + size + }) { + Ok(_n) => Poll::Ready(Ok(unwrap!(ret))), + Err(icmp::SendError::BufferFull) => { + s.register_send_waker(cx.waker()); + Poll::Pending + } + Err(icmp::SendError::Unaddressable) => Poll::Ready(Err(SendError::NoRoute)), } - Err(icmp::SendError::Unaddressable) => Poll::Ready(Err(SendError::NoRoute)), }) }) .await @@ -580,7 +589,7 @@ pub mod ping { // Send with timeout the ICMP packet filling it with the helper function let send_result = socket .send_to_with(ping_repr.buffer_len(), params.target.unwrap(), |buf| { - fill_packet_buffer(buf, ping_repr) + (buf.len(), fill_packet_buffer(buf, ping_repr)) }) .with_timeout(Duration::from_millis(100)) .await; @@ -651,7 +660,7 @@ pub mod ping { // Send with timeout the ICMP packet filling it with the helper function let send_result = socket .send_to_with(ping_repr.buffer_len(), params.target.unwrap(), |buf| { - fill_packet_buffer(buf, ping_repr, params) + (buf.len(), fill_packet_buffer(buf, ping_repr, params)) }) .with_timeout(Duration::from_millis(100)) .await; diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 448c25eccc..9e4bb05968 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -278,18 +278,19 @@ impl<'a> UdpSocket<'a> { /// Send a datagram to the specified remote endpoint with a zero-copy function. /// /// This method will wait until the buffer can fit the requested size before - /// calling the function to fill its contents. + /// passing it to the closure. The closure returns the number of bytes + /// written into the buffer. /// - /// If the socket's send buffer is too small to fit `size`, this method will return `Err(SendError::PacketTooLarge)` + /// If the socket's send buffer is too small to fit `max_size`, this method will return `Err(SendError::PacketTooLarge)` /// /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)` - pub async fn send_to_with(&mut self, size: usize, remote_endpoint: T, f: F) -> Result + pub async fn send_to_with(&mut self, max_size: usize, remote_endpoint: T, f: F) -> Result where T: Into + Copy, - F: FnOnce(&mut [u8]) -> R, + F: FnOnce(&mut [u8]) -> (usize, R), { // Don't need to wake waker in `with_mut` if the buffer will never fit the udp tx_buffer. - let send_capacity_too_small = self.with(|s, _| s.payload_send_capacity() < size); + let send_capacity_too_small = self.with(|s, _| s.payload_send_capacity() < max_size); if send_capacity_too_small { return Err(SendError::PacketTooLarge); } @@ -297,8 +298,14 @@ impl<'a> UdpSocket<'a> { let mut f = Some(f); poll_fn(move |cx| { self.with_mut(|s, _| { - match s.send(size, remote_endpoint) { - Ok(buffer) => Poll::Ready(Ok(unwrap!(f.take())(buffer))), + let mut ret = None; + + match s.send_with(max_size, remote_endpoint, |buf| { + let (size, r) = unwrap!(f.take())(buf); + ret = Some(r); + size + }) { + Ok(_n) => Poll::Ready(Ok(unwrap!(ret))), Err(udp::SendError::BufferFull) => { s.register_send_waker(cx.waker()); Poll::Pending diff --git a/examples/rp/src/bin/ethernet_w5500_icmp.rs b/examples/rp/src/bin/ethernet_w5500_icmp.rs index f362cb5526..9b0bc8c909 100644 --- a/examples/rp/src/bin/ethernet_w5500_icmp.rs +++ b/examples/rp/src/bin/ethernet_w5500_icmp.rs @@ -114,7 +114,7 @@ async fn main(spawner: Spawner) { // Create and populate the packet buffer allocated by `send_to_with` let mut icmp_packet = Icmpv4Packet::new_unchecked(buf); icmp_repr.emit(&mut icmp_packet, &ChecksumCapabilities::default()); - Instant::now() // Return the instant where the packet was sent + (icmp_repr.buffer_len(), Instant::now()) // Return the instant where the packet was sent }) .await .unwrap(); diff --git a/examples/rp235x/src/bin/ethernet_w5500_icmp.rs b/examples/rp235x/src/bin/ethernet_w5500_icmp.rs index c321ffcd36..3be3f9665a 100644 --- a/examples/rp235x/src/bin/ethernet_w5500_icmp.rs +++ b/examples/rp235x/src/bin/ethernet_w5500_icmp.rs @@ -114,7 +114,7 @@ async fn main(spawner: Spawner) { // Create and populate the packet buffer allocated by `send_to_with` let mut icmp_packet = Icmpv4Packet::new_unchecked(buf); icmp_repr.emit(&mut icmp_packet, &ChecksumCapabilities::default()); - Instant::now() // Return the instant where the packet was sent + (icmp_repr.buffer_len(), Instant::now()) // Return the instant where the packet was sent }) .await .unwrap();