aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-10-21 00:35:13 +0000
committerGitHub <[email protected]>2024-10-21 00:35:13 +0000
commite8ba9696f140e604344d84fba93bd9854de56c0a (patch)
tree6c71a4a57dea927d82ca5842bcb9f4c0c9d1f720
parentd8ae5861db3ae5b7e96226d4a525d0d8e20c1816 (diff)
parent712fa08363067d0a0e3ff07b3bd0633bee3ba07e (diff)
Merge pull request #3368 from AnthonyGrondin/main
feat(embassy-net): Implement `wait_recv_ready()` + `wait_send_ready()` for UdpSocket and `wait_read_ready()` + `wait_write_ready()` for TcpSocket
-rw-r--r--embassy-net/src/tcp.rs62
-rw-r--r--embassy-net/src/udp.rs53
2 files changed, 112 insertions, 3 deletions
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs
index 043062e06..a00ced8f4 100644
--- a/embassy-net/src/tcp.rs
+++ b/embassy-net/src/tcp.rs
@@ -10,7 +10,7 @@
10 10
11use core::future::poll_fn; 11use core::future::poll_fn;
12use core::mem; 12use core::mem;
13use core::task::Poll; 13use core::task::{Context, Poll};
14 14
15use embassy_time::Duration; 15use embassy_time::Duration;
16use smoltcp::iface::{Interface, SocketHandle}; 16use smoltcp::iface::{Interface, SocketHandle};
@@ -274,6 +274,16 @@ impl<'a> TcpSocket<'a> {
274 .await 274 .await
275 } 275 }
276 276
277 /// Wait until the socket becomes readable.
278 ///
279 /// A socket becomes readable when the receive half of the full-duplex connection is open
280 /// (see [may_recv](#method.may_recv)), and there is some pending data in the receive buffer.
281 ///
282 /// This is the equivalent of [read](#method.read), without buffering any data.
283 pub async fn wait_read_ready(&self) {
284 poll_fn(move |cx| self.io.poll_read_ready(cx)).await
285 }
286
277 /// Read data from the socket. 287 /// Read data from the socket.
278 /// 288 ///
279 /// Returns how many bytes were read, or an error. If no data is available, it waits 289 /// Returns how many bytes were read, or an error. If no data is available, it waits
@@ -285,6 +295,16 @@ impl<'a> TcpSocket<'a> {
285 self.io.read(buf).await 295 self.io.read(buf).await
286 } 296 }
287 297
298 /// Wait until the socket becomes writable.
299 ///
300 /// A socket becomes writable when the transmit half of the full-duplex connection is open
301 /// (see [may_send](#method.may_send)), and the transmit buffer is not full.
302 ///
303 /// This is the equivalent of [write](#method.write), without sending any data.
304 pub async fn wait_write_ready(&self) {
305 poll_fn(move |cx| self.io.poll_write_ready(cx)).await
306 }
307
288 /// Write data to the socket. 308 /// Write data to the socket.
289 /// 309 ///
290 /// Returns how many bytes were written, or an error. If the socket is not ready to 310 /// Returns how many bytes were written, or an error. If the socket is not ready to
@@ -376,11 +396,25 @@ impl<'a> TcpSocket<'a> {
376 self.io.with_mut(|s, _| s.abort()) 396 self.io.with_mut(|s, _| s.abort())
377 } 397 }
378 398
379 /// Get whether the socket is ready to send data, i.e. whether there is space in the send buffer. 399 /// Return whether the transmit half of the full-duplex connection is open.
400 ///
401 /// This function returns true if it's possible to send data and have it arrive
402 /// to the remote endpoint. However, it does not make any guarantees about the state
403 /// of the transmit buffer, and even if it returns true, [write](#method.write) may
404 /// not be able to enqueue any octets.
405 ///
406 /// In terms of the TCP state machine, the socket must be in the `ESTABLISHED` or
407 /// `CLOSE-WAIT` state.
380 pub fn may_send(&self) -> bool { 408 pub fn may_send(&self) -> bool {
381 self.io.with(|s, _| s.may_send()) 409 self.io.with(|s, _| s.may_send())
382 } 410 }
383 411
412 /// Check whether the transmit half of the full-duplex connection is open
413 /// (see [may_send](#method.may_send)), and the transmit buffer is not full.
414 pub fn can_send(&self) -> bool {
415 self.io.with(|s, _| s.can_send())
416 }
417
384 /// return whether the receive half of the full-duplex connection is open. 418 /// return whether the receive half of the full-duplex connection is open.
385 /// This function returns true if it’s possible to receive data from the remote endpoint. 419 /// This function returns true if it’s possible to receive data from the remote endpoint.
386 /// It will return true while there is data in the receive buffer, and if there isn’t, 420 /// It will return true while there is data in the receive buffer, and if there isn’t,
@@ -427,7 +461,7 @@ impl<'d> TcpIo<'d> {
427 }) 461 })
428 } 462 }
429 463
430 fn with_mut<R>(&mut self, f: impl FnOnce(&mut tcp::Socket, &mut Interface) -> R) -> R { 464 fn with_mut<R>(&self, f: impl FnOnce(&mut tcp::Socket, &mut Interface) -> R) -> R {
431 self.stack.with_mut(|i| { 465 self.stack.with_mut(|i| {
432 let socket = i.sockets.get_mut::<tcp::Socket>(self.handle); 466 let socket = i.sockets.get_mut::<tcp::Socket>(self.handle);
433 let res = f(socket, &mut i.iface); 467 let res = f(socket, &mut i.iface);
@@ -436,6 +470,17 @@ impl<'d> TcpIo<'d> {
436 }) 470 })
437 } 471 }
438 472
473 fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<()> {
474 self.with_mut(|s, _| {
475 if s.can_recv() {
476 Poll::Ready(())
477 } else {
478 s.register_recv_waker(cx.waker());
479 Poll::Pending
480 }
481 })
482 }
483
439 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { 484 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
440 poll_fn(move |cx| { 485 poll_fn(move |cx| {
441 // CAUTION: smoltcp semantics around EOF are different to what you'd expect 486 // CAUTION: smoltcp semantics around EOF are different to what you'd expect
@@ -464,6 +509,17 @@ impl<'d> TcpIo<'d> {
464 .await 509 .await
465 } 510 }
466 511
512 fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll<()> {
513 self.with_mut(|s, _| {
514 if s.can_send() {
515 Poll::Ready(())
516 } else {
517 s.register_send_waker(cx.waker());
518 Poll::Pending
519 }
520 })
521 }
522
467 async fn write(&mut self, buf: &[u8]) -> Result<usize, Error> { 523 async fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
468 poll_fn(move |cx| { 524 poll_fn(move |cx| {
469 self.with_mut(|s, _| match s.send_slice(buf) { 525 self.with_mut(|s, _| match s.send_slice(buf) {
diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs
index ac650364e..76602edc2 100644
--- a/embassy-net/src/udp.rs
+++ b/embassy-net/src/udp.rs
@@ -103,6 +103,32 @@ impl<'a> UdpSocket<'a> {
103 }) 103 })
104 } 104 }
105 105
106 /// Wait until the socket becomes readable.
107 ///
108 /// A socket is readable when a packet has been received, or when there are queued packets in
109 /// the buffer.
110 pub async fn wait_recv_ready(&self) {
111 poll_fn(move |cx| self.poll_recv_ready(cx)).await
112 }
113
114 /// Wait until a datagram can be read.
115 ///
116 /// When no datagram is readable, this method will return `Poll::Pending` and
117 /// register the current task to be notified when a datagram is received.
118 ///
119 /// When a datagram is received, this method will return `Poll::Ready`.
120 pub fn poll_recv_ready(&self, cx: &mut Context<'_>) -> Poll<()> {
121 self.with_mut(|s, _| {
122 if s.can_recv() {
123 Poll::Ready(())
124 } else {
125 // socket buffer is empty wait until at least one byte has arrived
126 s.register_recv_waker(cx.waker());
127 Poll::Pending
128 }
129 })
130 }
131
106 /// Receive a datagram. 132 /// Receive a datagram.
107 /// 133 ///
108 /// This method will wait until a datagram is received. 134 /// This method will wait until a datagram is received.
@@ -164,6 +190,33 @@ impl<'a> UdpSocket<'a> {
164 .await 190 .await
165 } 191 }
166 192
193 /// Wait until the socket becomes writable.
194 ///
195 /// A socket becomes writable when there is space in the buffer, from initial memory or after
196 /// dispatching datagrams on a full buffer.
197 pub async fn wait_send_ready(&self) {
198 poll_fn(move |cx| self.poll_send_ready(cx)).await
199 }
200
201 /// Wait until a datagram can be sent.
202 ///
203 /// When no datagram can be sent (i.e. the buffer is full), this method will return
204 /// `Poll::Pending` and register the current task to be notified when
205 /// space is freed in the buffer after a datagram has been dispatched.
206 ///
207 /// When a datagram can be sent, this method will return `Poll::Ready`.
208 pub fn poll_send_ready(&self, cx: &mut Context<'_>) -> Poll<()> {
209 self.with_mut(|s, _| {
210 if s.can_send() {
211 Poll::Ready(())
212 } else {
213 // socket buffer is full wait until a datagram has been dispatched
214 s.register_send_waker(cx.waker());
215 Poll::Pending
216 }
217 })
218 }
219
167 /// Send a datagram to the specified remote endpoint. 220 /// Send a datagram to the specified remote endpoint.
168 /// 221 ///
169 /// This method will wait until the datagram has been sent. 222 /// This method will wait until the datagram has been sent.