Skip to content

Commit

Permalink
fixup! fixup! fixup! NanoCoAP: Add helper functions for NanoCBOR payl…
Browse files Browse the repository at this point in the history
…oads
  • Loading branch information
bergzand committed Oct 19, 2023
1 parent b659ea1 commit f62eb9f
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 23 deletions.
39 changes: 31 additions & 8 deletions sys/include/net/nanocoap/nanocbor_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@
* @ingroup net_nanocoap
* @brief Nanocbor helpers for CoAP block-wise
*
* This module wraps NanoCoAP and gcoap around the NanoCBOR stream-like interface to generate sliced
* block-wise payloads automatically from nanocbor encoder serialization calls. The content is
* serialized for every individual block-wise request. This module supports both block1 and block2
* payloads and will automatically generate and update the etag option in the packet.
* This module wraps NanoCoAP and gcoap around the NanoCBOR stream-like interface to generate single
* packets and sliced block-wise payloads automatically from nanocbor encoder serialization calls.
* The content is serialized for every individual (block-wise) request. This module supports single
* packets (without block-wise option) and block1/block2 payloads and will automatically update the
* etag option in the packet if a dummy etag header has been placed.
*
* This module assumes that the serialized content does not change between successive
* serializations. In case this happens it should be detected via the etag that can be included in
Expand Down Expand Up @@ -52,6 +53,11 @@
* ```
* This finishes the block-wise structure and writes the generated etag into the CoAP option.
*
* If a simple payload is required without supporting block-wise, the slicer does not have to be
* initialized and a `NULL` pointer can be passed in the @ref coap_nanocbor_slicer_helper_init call.
* In this case only the available payload space will be used, possibly truncating the CBOR
* structure.
*
* @{
*
* @file
Expand Down Expand Up @@ -85,8 +91,11 @@ extern "C" {
typedef struct {
coap_block_slicer_t *slicer; /**< coap block-wise slicer struct */
uint8_t *buf; /**< Buffer to slice into, usually the CoAP payload */
size_t sliced_length; /**< Number of bytes written into the current slice */
size_t resp_len; /**< Total length of the serialized response */
union {
size_t full_len; /**< Total length of the serialized response */
size_t buf_len; /**< Total available space in the payload buf */
}
size_t payload_len; /**< Number of bytes written into the current slice */
uint8_t fletcher_tmp; /**< Temporary storage for half a fletcher32 words */
fletcher32_ctx_t fletcher_ctx; /**< Fletcher32 context for etag generation */
} coap_nanocbor_slicer_helper_t;
Expand Down Expand Up @@ -114,7 +123,8 @@ void coap_nanocbor_encoder_blockwise_init(nanocbor_encoder_t *encoder,
/**
* @brief Finish the CoAP reply packet with the block2 option.
*
* Finishes the block2 option in the packet and writes the correct etag into the option if present
* Finishes the block2 option in the packet and writes the correct etag into the option if such
* option is already present in the packet.
*
* @param pdu CoAP packet to finish
* @param helper CoAP NanoCBOR slicer helper
Expand All @@ -127,7 +137,8 @@ ssize_t coap_nanocbor_block2_finish(coap_pkt_t *pdu, coap_nanocbor_slicer_helper
/**
* @brief Finish the CoAP request packet with the block1 option.
*
* Finishes the block1 option in the packet and writes the correct etag into the option if present
* Finishes the block1 option in the packet and writes the correct etag into the option if such
* option is already present in the packet.
*
* @param pdu CoAP packet to finish
* @param helper CoAP NanoCBOR slicer helper
Expand All @@ -137,6 +148,18 @@ ssize_t coap_nanocbor_block2_finish(coap_pkt_t *pdu, coap_nanocbor_slicer_helper
*/
ssize_t coap_nanocbor_block1_finish(coap_pkt_t *pdu, coap_nanocbor_slicer_helper_t *helper);

/**
* @brief Finish the CoAP request packet without any block option
*
* Writes the correct etag into the option if such option is already present in the packet
*
* @param pdu CoAP packet to finish
* @param helper CoAP NanoCBOR slicer helper
*
* @returns The full length of the CoAP packet
* @returns Negative on error
*/
ssize_t coap_nanocbor_finish(coap_pkt_t *pdu, coap_nanocbor_slicer_helper_t *helper);
#ifdef __cplusplus
}
#endif
Expand Down
62 changes: 47 additions & 15 deletions sys/net/application_layer/nanocoap/nanocbor_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,18 @@
#include "net/nanocoap.h"
#include "net/nanocoap/nanocbor_helper.h"

static bool _nanocbor_fits(nanocbor_encoder_t *enc, void *ctx, size_t len)
static bool _nanocbor_fits_block(nanocbor_encoder_t *enc, void *ctx, size_t len)
{
(void)enc;
(void)ctx;
(void)len;
return true; /* Always more space on the block2 */
return true; /* Always more space on the block */
}

static bool _nanocbor_fits_simple(nanocbor_encoder_t *enc, void *ctx, size_t len)
{
const coap_nanocbor_slicer_helper_t *helper = ctx;
return len + helper->payload_len <= helper->buf_len;
}

static inline bool _is_odd(size_t len)
Expand All @@ -40,38 +46,54 @@ static inline bool _is_odd(size_t len)

static void _update_fletcher(coap_nanocbor_slicer_helper_t *helper, const uint8_t *buf, size_t len)
{
if (_is_odd(helper->resp_len)) {
if (_is_odd(helper->full_len)) {
uint16_t tmp = (helper->fletcher_tmp << 8) | buf[0];
fletcher32_update(&helper->fletcher_ctx, &tmp, 1);
len--;
buf++;
helper->resp_len++;
helper->full_len++;
}
fletcher32_update(&helper->fletcher_ctx, buf, len / 2);
}

static void _nanocbor_append(nanocbor_encoder_t *enc, void *ctx, const uint8_t *buf, size_t len)
static void _nanocbor_append_blockwise(nanocbor_encoder_t *enc, void *ctx, const uint8_t *buf, size_t len)

Check warning on line 59 in sys/net/application_layer/nanocoap/nanocbor_helper.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
{
(void)enc;
coap_nanocbor_slicer_helper_t *helper = ctx;
if (len == 0) {
return;
}

helper->sliced_length +=
helper->payload_len +=
coap_blockwise_put_bytes(helper->slicer,
helper->buf + helper->sliced_length,
helper->buf + helper->payload_len,
buf, len);

_update_fletcher(helper, buf, len);

helper->resp_len += len;
if (_is_odd(helper->resp_len)) {
helper->full_len += len;
if (_is_odd(helper->full_len)) {
/* store the last byte for the next round */
helper->fletcher_tmp = buf[len - 1];
}
}

static void _nanocbor_append_simple(nanocbor_encoder_t *enc, void *ctx, const uint8_t *buf, size_t len)

Check warning on line 81 in sys/net/application_layer/nanocoap/nanocbor_helper.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
{
coap_nanocbor_slicer_helper_t *helper = ctx;
if (len == 0) {
return;
}

_update_fletcher(helper, buf, len);

/* This should have been checked before */
assert(len + helper->payload_len <= helper->buf_len);

memcpy(buf + helper->payload_len, buf, len);
helper->payload_len += len;
}

void coap_nanocbor_slicer_helper_init(coap_nanocbor_slicer_helper_t *helper, const coap_pkt_t *pkt,
coap_block_slicer_t *slicer)
{
Expand All @@ -80,26 +102,31 @@ void coap_nanocbor_slicer_helper_init(coap_nanocbor_slicer_helper_t *helper, con
helper->buf = pkt->payload;
}

void coap_nanocbor_encoder_blockwise_init(nanocbor_encoder_t *encoder,
coap_nanocbor_slicer_helper_t *helper)
void coap_nanocbor_encoder_init(nanocbor_encoder_t *encoder,
coap_nanocbor_slicer_helper_t *helper)
{
nanocbor_encoder_stream_init(encoder, helper, _nanocbor_append, _nanocbor_fits);
if (helper->slicer) {
nanocbor_encoder_stream_init(encoder, helper, _nanocbor_append_block, _nanocbor_fits_block);
}
else {
nanocbor_encoder_stream_init(encoder, helper, _nanocbor_append_simple, _nanocbor_fits_simple);

Check warning on line 112 in sys/net/application_layer/nanocoap/nanocbor_helper.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
}
}

static ssize_t _etag_finish(coap_pkt_t *pdu, coap_nanocbor_slicer_helper_t *helper)
{
/* Pad with an extra 0xff, which should not occur on its own at the end of a cbor stream */
if (_is_odd(helper->resp_len)) {
if (_is_odd(helper->full_len)) {
uint8_t extra = 0xFF;
_update_fletcher(helper, &extra, sizeof(extra));
}
/* And add the total length for good measure */
_update_fletcher(helper, (uint8_t*)&helper->resp_len, sizeof(helper->resp_len));
_update_fletcher(helper, (uint8_t*)&helper->full_len, sizeof(helper->full_len));

uint32_t etag = fletcher32_finish(&helper->fletcher_ctx);
coap_opt_replace_etag(pdu, &etag, sizeof(etag));
size_t header_options_len = pdu->payload - (uint8_t *)pdu->hdr;
return header_options_len + helper->sliced_length;
return header_options_len + helper->payload_leng;
}

ssize_t coap_nanocbor_block2_finish(coap_pkt_t *pdu, coap_nanocbor_slicer_helper_t *helper)
Expand All @@ -113,3 +140,8 @@ ssize_t coap_nanocbor_block1_finish(coap_pkt_t *pdu, coap_nanocbor_slicer_helper
coap_block1_finish(helper->slicer);
return _etag_finish(pdu, helper);
}

ssize_t coap_nanocbor_finish(coap_pkt_t *pdu, coap_nanocbor_slicer_helper_t *helper)
{
return _etag_finish(pdu, helper);
}

0 comments on commit f62eb9f

Please sign in to comment.