Uses new Rust 2021
|0.1.2||Nov 11, 2021|
|0.1.1||Nov 10, 2021|
|0.1.0||Nov 2, 2021|
#21 in #coap
37 downloads per month
Used in coap-message-demos
A minimal CoAP-over-TCP server implementation built on [embedded_nal].
This is the TCP equivalent of embedded-nal-minimal-coapserver; it serves to illustrate differences, and as a benchmarking tool to pitch CoAP-over-TCP against CoAP-over-UDP. It may, on the long run, also be useful where CoAP-over-TCP is practical for constrained devices (which is in NAT traversal); for that, it will need to gain some basic client capabilities to send requests.
Usage and operation
See also the equivalent section: Have a [ServerPool] and [ServerPool::poll] it whenever there might have been network activity.
Some (small) state is needed per TCP connection, which is stored along with the socket in a [ConnectionState]. All the [ServerPool] does is accept, poll the connections individually and drop the state (includeing a socket that is, by then, closed) when receiving an error. When other means of managing the connections are desired, including opening connections actively, that can just be done by replacing the ServerPool and calling [ConnectionState::poll_connection] manually.
Manual per-connection polling is currently also the way to go if you don't want to afford the stack allocation of the receive and send buffer, replacing it with some scratch memory are: [ConnectionState::poll_connection_with_buffer] can be used with a locked scratch area then.
See the equivalent section of embedded-nal-minimal-coapserver, with the following alterations:
As a TCP server, this is not prone to amplification mitigation, does not need to perform message deduplication and is not prone to the subtle response address issues.
While this was the reason idempotency was required in the CoAP-over-UDP server, idempotency is still required for reasons below.
Unlike in CoAP-over-UDP, the server has no leeway to just "miss" requests.
If a request was read but sending the response fails (because the send buffer is not ready), the request still needs to be processed without creating too much of a suspension point; what this server does is to respond 5.03 and wait for the client to retry. Thus, it is still advised that handlers need to be idempotent.
(With completely full send buffers, even sending the 5.03 can fail, in which case the connection is terminated).
Fortunately, such events (needing to send 5.03, let alone aborting) can be expected to be rare, at least while the client sends requests in lockstep (which the client has all rights not to, but many applications simply lockstep).
This could be mitigated if the TCP socket indicated that some size of outbuffer is guaranteed to be available; this implementation could then just not start reading requests until whichever response it maximally sends is available.
(A more elaborate server might hope that handlers' response data is small as it should be in the [coap-handler]; ecosystem. Then, it could have a suspension point (state machine state) for a request that has been processed, and could wait for the exact size requested to build the response is available. This implementation will not do this. A less elaborate server could store the token and at least reliably send the 5.03 even later.)
The underlying stack must be capable of providing a full CoAP request (up to some size) in a single nonblocking read. Otherwise, the CoAP library would need to keep a buffer of its own for each connection that may be trickling in arbitrarily slowly.
This is only provided by TCP stacks that additionally implement the [embedded_nal_tcpextensions::TcpExactStack] trait discussed in https://github.com/rust-embedded-community/embedded-nal/issues/59.
The server is work in progress, but minimally functional.
The goal of this server is to stay a simple and minimal component, with somewhat less ambitions on production readiness than embedded-nal-minimal-coapserver.
License: MIT OR Apache-2.0