1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #20284 from benpicco/coap_build_reply_header

nanocoap: add coap_build_reply_header()
This commit is contained in:
benpicco 2024-01-24 22:00:57 +00:00 committed by GitHub
commit 2d459157f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 107 additions and 16 deletions

View File

@ -535,6 +535,11 @@ typedef enum {
#define COAP_ETAG_LENGTH_MAX (8U) /**< maximum length of the ETag option */
/** @} */
/**
* @brief Marks the boundary between header and payload
*/
#define COAP_PAYLOAD_MARKER (0xFF)
/**
* @defgroup net_coap_conf CoAP compile configurations
* @ingroup net_coap

View File

@ -2115,6 +2115,36 @@ ssize_t coap_payload_put_bytes(coap_pkt_t *pkt, const void *data, size_t len);
*/
ssize_t coap_payload_put_char(coap_pkt_t *pkt, char c);
/**
* @brief Create CoAP reply header (convenience function)
*
* This function generates the reply CoAP header and sets
* the payload pointer inside the response buffer to point to
* the start of the payload, so that it can be written directly
* after the header.
*
* @param[in] pkt packet to reply to
* @param[in] code reply code (e.g., COAP_CODE_204)
* @param[out] buf buffer to write reply to
* @param[in] len size of @p buf
* @param[in] ct content type of payload
* if ct < 0 this will be ignored
* @param[out] payload Will be set to the start of the payload inside
* @p buf.
* May be set to NULL if no payload response is
* wanted (no-reply option)
* @param[out] payload_len_max max length of payload left in @p buf
*
* @returns size of reply header on success
* @returns 0 if no reply should be sent
* @returns <0 on error
* @returns -ENOSPC if @p buf too small
*/
ssize_t coap_build_reply_header(coap_pkt_t *pkt, unsigned code,
void *buf, size_t len,
int ct,
void **payload, size_t *payload_len_max);
/**
* @brief Create CoAP reply (convenience function)
*

View File

@ -119,7 +119,7 @@ int coap_parse(coap_pkt_t *pkt, uint8_t *buf, size_t len)
while (pkt_pos < pkt_end) {
uint8_t *option_start = pkt_pos;
uint8_t option_byte = *pkt_pos++;
if (option_byte == 0xff) {
if (option_byte == COAP_PAYLOAD_MARKER) {
pkt->payload = pkt_pos;
pkt->payload_len = buf + len - pkt_pos;
DEBUG("payload len = %u\n", pkt->payload_len);
@ -232,7 +232,7 @@ static uint8_t *_parse_option(const coap_pkt_t *pkt,
uint8_t *hdr_end = pkt->payload;
if ((pkt_pos >= hdr_end)
|| (((pkt_pos + 1) == hdr_end) && (*pkt_pos == 0xFF))) {
|| (((pkt_pos + 1) == hdr_end) && (*pkt_pos == COAP_PAYLOAD_MARKER))) {
return NULL;
}
@ -545,29 +545,85 @@ ssize_t coap_tree_handler(coap_pkt_t *pkt, uint8_t *resp_buf, unsigned resp_buf_
return coap_build_reply(pkt, COAP_CODE_404, resp_buf, resp_buf_len, 0);
}
ssize_t coap_build_reply_header(coap_pkt_t *pkt, unsigned code,
void *buf, size_t len,
int ct,
void **payload, size_t *payload_len_max)
{
uint8_t *bufpos = buf;
uint32_t no_response;
unsigned tkl = coap_get_token_len(pkt);
size_t hdr_len = sizeof(coap_hdr_t) + tkl;
uint8_t type = coap_get_type(pkt) == COAP_TYPE_CON
? COAP_TYPE_ACK
: COAP_TYPE_NON;
if (hdr_len > len) {
return -ENOBUFS;
}
bufpos += coap_build_hdr(buf, type, coap_get_token(pkt), tkl,
code, ntohs(pkt->hdr->id));
if (coap_opt_get_uint(pkt, COAP_OPT_NO_RESPONSE, &no_response) == 0) {
const uint8_t no_response_index = (code >> 5) - 1;
/* If the handler code misbehaved here, we'd face UB otherwise */
assume(no_response_index < 7);
const uint8_t mask = 1 << no_response_index;
if (no_response & mask) {
if (payload) {
*payload = NULL;
*payload_len_max = 0;
payload = NULL;
}
/* no-response requested, only send empty ACK or nothing */
if (type != COAP_TYPE_ACK) {
return 0;
}
}
}
if (payload) {
if (ct >= 0) {
bufpos += coap_put_option_ct(bufpos, 0, ct);
}
*bufpos++ = COAP_PAYLOAD_MARKER;
*payload = bufpos;
hdr_len = bufpos - (uint8_t *)buf;
*payload_len_max = len - hdr_len;
}
/* with the nanoCoAP API we can't detect the overflow before it happens */
assert(hdr_len <= len);
return hdr_len;
}
ssize_t coap_reply_simple(coap_pkt_t *pkt,
unsigned code,
uint8_t *buf, size_t len,
unsigned ct,
const void *payload, size_t payload_len)
{
uint8_t *payload_start = buf + coap_get_total_hdr_len(pkt);
uint8_t *bufpos = payload_start;
void *payload_start;
size_t payload_len_max;
if (payload_len) {
bufpos += coap_put_option_ct(bufpos, 0, ct);
*bufpos++ = 0xff;
ssize_t header_len = coap_build_reply_header(pkt, code, buf, len, ct,
payload ? &payload_start : NULL,
&payload_len_max);
if (payload == NULL || header_len <= 0) {
return header_len;
}
ssize_t res = coap_build_reply(pkt, code, buf, len,
bufpos - payload_start + payload_len);
if (payload_len && (res > 0)) {
assert(payload);
memcpy(bufpos, payload, payload_len);
if (payload_len > payload_len_max) {
return -ENOBUFS;
}
return res;
memcpy(payload_start, payload, payload_len);
return header_len + payload_len;
}
ssize_t coap_build_reply(coap_pkt_t *pkt, unsigned code,
@ -1112,7 +1168,7 @@ ssize_t coap_opt_finish(coap_pkt_t *pkt, uint16_t flags)
return -ENOSPC;
}
*pkt->payload++ = 0xFF;
*pkt->payload++ = COAP_PAYLOAD_MARKER;
pkt->payload_len--;
}
else {
@ -1337,7 +1393,7 @@ ssize_t coap_well_known_core_default_handler(coap_pkt_t *pkt, uint8_t *buf, \
bufpos += coap_put_option_ct(bufpos, 0, COAP_FORMAT_LINK);
bufpos += coap_opt_put_block2(bufpos, COAP_OPT_CONTENT_FORMAT, &slicer, 1);
*bufpos++ = 0xff;
*bufpos++ = COAP_PAYLOAD_MARKER;
for (unsigned i = 0; i < coap_resources_numof; i++) {
if (i) {