embedded_nal_tcpextensions/lib.rs
1#![no_std]
2//! Extensions to [embedded_nal]'s TCP traits to make more precise use of TCP buffers.
3//!
4//! This is not intended to be a long-term extension of embedded-nal,
5//! but more an experimenation playground for [#59]
6//! where users and implementations can play (ideally behind unstable feature gates);
7//! once this is mature it is hoped that it'll be taken up into embedded-nal.
8//!
9//! # Maintenance status
10//!
11//! This crate has not been updated since embedded-hal 0.6 (as of late 2024, that trait crate is at
12//! 0.9), and is not expected to be updated any further. The experiment has shown that while it may
13//! be possible to implement this on embedded platforms, there can be significant pushback from TCP
14//! stack maintainers to expose this capability (see [#16850]), as it can mess with expectations
15//! around when to ACK and what the usable vs. communicated window size is.
16//!
17//! There may still be some way to implement this optimization, but for the time being, this is not
18//! being followed any further.
19//!
20//! [#59]: https://github.com/rust-embedded-community/embedded-nal/issues/59
21//! [#16850]: https://github.com/RIOT-OS/RIOT/pull/16850
22
23use embedded_nal::nb;
24
25mod wrappers;
26pub use wrappers::*;
27
28/// A specialization of [embedded_nal::TcpClientStack] that allows nonblocking until a given number of bytes can
29/// be read, and writing in an all-or-nothing way.
30///
31/// Stacks that can not provide this can be wrapped in [`BufferedStack::<_, 1152>::new()`] to gain
32/// this capability at the cost of per-socket allocated buffers.
33///
34/// It is an early form of what should resolve
35/// <https://github.com/rust-embedded-community/embedded-nal/issues/59>.
36pub trait TcpExactStack: embedded_nal::TcpClientStack {
37 /// Capacity of the connection's TCP buffer.
38 ///
39 /// Calls to [`receive_exact()`](TcpExactStack::receive_exact) can ask up to this many
40 /// bytes to be returned.
41 ///
42 /// Checking this (possibly in static assertions) is important because applications that'd wait
43 /// for larger chunks of data than the TCP socket can buffer will deadlock -- the application
44 /// waits for the server to send more, but the stack tells the server to stop sending more
45 /// until the application processes the data.
46 ///
47 /// (This is a per-stack-type property. Stacks where this is configurable per socket need to
48 /// report the smallest value, which is guaranteed to be usable with [`receive_exact()`](TcpExactStack::receive_exact) on every
49 /// instance. It is exposed this way to allow users to have suitable const-sized allocations
50 /// for the sockets they are built for.)
51 const RECVBUFLEN: usize;
52
53 /// Receive data from the stream.
54 ///
55 /// Returns `Ok(())` if the whole buffer could be filled, or an error. If a packet has not been
56 /// received when called, or not enough data is present, then [`nb::Error::WouldBlock`] should
57 /// be returned.
58 ///
59 /// # Panics
60 ///
61 /// This may panic when buffer is larger than RECVBUFLEN.
62 fn receive_exact(
63 &mut self,
64 socket: &mut Self::TcpSocket,
65 buffer: &mut [u8],
66 ) -> nb::Result<(), Self::Error>;
67
68 /// Capacity of the connection's TCP send buffer.
69 ///
70 /// Calls to [`send_All()`](TcpExactStack::send_all) can send up to this many bytes.
71 const SENDBUFLEN: usize;
72
73 /// Send all this data to the stream.
74 ///
75 /// Returns `Ok(())` if the whole buffer could be submitted, or an error. If the data can not
76 /// fit into the send buffer when called (especially, but not only, if the send buffer is
77 /// full), then [`nb::Error::WouldBlock`'] is returned.
78 ///
79 /// # Panics
80 ///
81 /// When the passed slice is larger than the advertised SENDBUFLEN, this may panic -- for the
82 /// worse alternative is to return WouldBlock indefinitely, as the message can't be put in the
83 /// send buffer no matter how empty it becomes.
84 fn send_all(
85 &mut self,
86 socket: &mut Self::TcpSocket,
87 buffer: &[u8],
88 ) -> Result<(), embedded_nal::nb::Error<Self::Error>>;
89}