owned this note
owned this note
Published
Linked with GitHub
# CoAP API (re-)design
## Teaser
Gcoap and nanocoap not only exist in parallel, they also share data structures like the pdu_t or the handler. Changes to Gcoap have accumulated Gcoap-specific fields in the pdu_t, but also make it hard to use Gcoap where even larger changes would be needed (handlers being told which transport data arrived from), and to utilize the underlying socket API to its full extent (thoughts of zero-copy access to data). Is the current level of entangelment sustainable? If not, how can we migrate? What's the fall-out? And once we've done that, can we just swap around CoAP transports and implementations like we swap network stacks? Is composability a topic to include (block-wise in userspace)?
## Current design
2 APIs
- `nanocoap`:
- Designed for _low memory footprint_
- `nanocoap.h`: message parsing and composition
- `nanocoap_sock.h`: simple client/server functionality
- `gcoap`:
- Designed for _user-friendliness_
- Uses `nanocoap` for message parsing and composition
- currently not top-down, but gCoAP-specific stuff `#ifdef`'d into `nanocoap` (see `coap_pkt_t` e.g.)
## Problems and wishlist
### Problems
- Co-dependency of `gcoap` and `nanocoap` requires touching both for even small protocol improvements, even at API side (handler signatures, member access, case and point [#16827](https://github.com/RIOT-OS/RIOT/pull/16827) from yesterday)
- Transport pretty much decided at compile-time (see [#16688](https://github.com/RIOT-OS/RIOT/pull/16688))
- Using zero-copy capabilities of `sock` not possible/used atm
- Everyone capitalizes Gcoap/gCoAP/gcoap differently ;-)
### Wishlist
- Transparent swap-out of CoAP transport
- Might need distinction between "message of which I know where it's from and how transported" and "message received that'll tell me where it's from"
- Even with Gcoap this works easily on the Rust side: [demos](https://docs.rs/coap-message-demos/0.1.0/coap_message_demos/) running unmodified on Linux, Gcoap or on RIOT sockets but using a Rust CoAP server.
- Expose payload-read-function to userspace / make `pkt->payload` private
- Could help solving zero-copy problem
- Could simplify block-wise transfer in user space (see [#16715](https://github.com/RIOT-OS/RIOT/issues/16715))
- Identify other direct-to-struct access patterns, build (transport-portable) API for them
- Some can identify non-portable behavior.
- When done, OSCORE.
### Challenges
- API breakage fall-out
- Migration
### Possible steps
- Survey API use?
- Deprecate field access??
## Usage examples
* Kaspar: nanocoap on minimal network stack through CDC-ECM (4k RAM or less)
* no security needs, no alternative transports
* could also be used for slipmux
* might make sense in separate implementations
* server-only, "Class-0" environments (RFC7228)
* Any advanced features used? (blockwise, observe etc)
* stateless: blockwise but not observe
* Koen: Updates OTA
* all stateless; POST/GET, RIOT client, some RAM available
* block-wise used; manifest would be nice to have handled but other things callback-per-block
* MCR: onboarding API
* identical needs as Updates OTA
* would like either DTLS or EDHOC+OSCORE (not runtime configured)
## approaches forward
* benpicco: fork gcoap, break all?
* hcoap?
* Martine: long-term clean gcoap stuff out of nanocoap (or move to extra struct inheriting from nanocoap, maybe already)
Keep using nanocoap for message parsing
(Move from accessing static fields to inline accessors)
Deprecate member access through documentation
* maribu: Careful about "not changing API too often", not "too much"
* chrysn: experimental for start, but then stable
* Koen: cochinelle script for simlpe changes?
Hashing out the API
* Martine
* chrysn
* Kaspar (to keep nanocoap from too much breakage)
* discuss at next VMAs more details