Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sys/net/nanocoap: improve coap_build_reply() #21155

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sys/include/net/coap.h
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,7 @@ typedef enum {
* @brief Marks the boundary between header and payload
*/
#define COAP_PAYLOAD_MARKER (0xFF)
#define COAP_PAYLOAD_MARKER_SIZE (1U) /**< Size of the payload marker */

/**
* @defgroup net_coap_conf CoAP compile configurations
Expand Down
73 changes: 52 additions & 21 deletions sys/include/net/nanocoap.h
Original file line number Diff line number Diff line change
Expand Up @@ -2077,29 +2077,60 @@ ssize_t coap_build_hdr(coap_hdr_t *hdr, unsigned type, const void *token,
* will create the reply packet header based on parameters from the request
* (e.g., id, token).
*
* Passing a non-zero @p payload_len will ensure the payload fits into the
* buffer along with the header. For this validation, payload_len must include
* any options, the payload marker, as well as the payload proper.
*
* @param[in] pkt packet to reply to
* @param[in] code reply code (e.g., COAP_CODE_204)
* @param[out] rbuf buffer to write reply to
* @param[in] rlen size of @p rbuf
* @param[in] payload_len length of payload
*
* @returns size of reply packet on success
*
* Note that this size can be severely shortened if due to a No-Response option there
mguetschow marked this conversation as resolved.
Show resolved Hide resolved
* is only an empty ACK to be sent back. The caller may just continue populating the
* payload (the space was checked to suffice), but may also skip that needless step
* if the returned length is less than the requested payload length.
*
* @returns 0 if no response should be sent due to a No-Response option in the request
* @returns <0 on error
* @returns -ENOSPC if @p rbuf too small
* Passing a non-zero @p max_data_len will ensure the remaining data fits into
* the buffer along with the header. For this validation, @p max_data_len must
* include any CoAP Options, the payload marker, as well as the payload proper.
*
* @param[in] pkt packet to reply to
* @param[in] code reply code (e.g., COAP_CODE_204)
* @param[out] rbuf buffer to write reply to
* @param[in] rlen size of @p rbuf
* @param[in] max_data_len Length of additional CoAP options, the payload marker and payload
*
* @warning CoAP request handlers *must* check the return value for being
* negative. If it is, they must stop further processing of the
* request and pass on the return value unmodified.
*
* @return @p max_data_len + size of the header written in bytes
*
* @retval -ECANCELED No-Response Option present and matching
* @retval -ENOSPC @p rbuf too small
* @retval <0 other error
*
* Usage:
*
* ```C
* static ssize_t _foo_handler(coap_pkt_t *pkt, uint8_t *buf, size_t len,
* coap_request_ctx_t *context)
* {
* static const char *payload = "Hello World";
* const payload_len = strlen(payload);
* // Worst case estimation of the data to add:
* size_t max_data_len = COAP_OPT_FOO_MAX_LEN + COAP_OPT_BAR_MAX_LEN
* + COAP_PAYLOAD_MARKER_SIZE + payload_len;
* ssize_t hdr_len = coap_build_reply(pkt, COAP_CODE_CONTENT, buf, len, max_data_len);
*
* if (hdr_len < 0) {
* return hdr_len; // pass through error
* }
*
* // This step is needed due to an API design flaw
* hdr_len -= max_data_len;
*
* uint8_t *pos = buf + hdr_len;
* uint16_t lastonum = 0;
* pos += coap_opt_put_uint(buf, lastonum, COAP_OPT_FOO, 42);
* lastonum = COAP_OPT_FOO;
* pos += coap_opt_put_uint(buf, lastonum, COAP_OPT_BAR, 1337);
* *pos++ = COAP_PAYLOAD_MARKER;
* memcpy(pos, payload, payload_len);
mguetschow marked this conversation as resolved.
Show resolved Hide resolved
* pos += payload_len;
* return (uintptr_t)pos - (uintptr_t)buf;
* }
* ```
*/
ssize_t coap_build_reply(coap_pkt_t *pkt, unsigned code,
uint8_t *rbuf, unsigned rlen, unsigned payload_len);
uint8_t *rbuf, unsigned rlen, unsigned max_data_len);

/**
* @brief Build empty reply to CoAP request
Expand Down
34 changes: 16 additions & 18 deletions sys/net/application_layer/nanocoap/nanocoap.c
Original file line number Diff line number Diff line change
Expand Up @@ -508,8 +508,20 @@ ssize_t coap_handle_req(coap_pkt_t *pkt, uint8_t *resp_buf, unsigned resp_buf_le
if (pkt->hdr->code == 0) {
return coap_build_reply(pkt, COAP_CODE_EMPTY, resp_buf, resp_buf_len, 0);
}
return coap_tree_handler(pkt, resp_buf, resp_buf_len, ctx,
coap_resources, coap_resources_numof);

ssize_t retval = coap_tree_handler(pkt, resp_buf, resp_buf_len, ctx,
coap_resources, coap_resources_numof);

if (retval == -ECANCELED) {
benpicco marked this conversation as resolved.
Show resolved Hide resolved
DEBUG_PUTS("nanocoap: No-Reponse Option present and matching");
/* ==> reply with empty ACK, if needed */
if (coap_get_type(pkt) == COAP_TYPE_CON) {
return coap_build_empty_ack(pkt, (void *)resp_buf);
}
return 0;
}

return retval;
}

ssize_t coap_subtree_handler(coap_pkt_t *pkt, uint8_t *buf, size_t len,
Expand Down Expand Up @@ -591,10 +603,7 @@ ssize_t coap_build_reply_header(coap_pkt_t *pkt, unsigned code,
payload = NULL;
}

/* no-response requested, only send empty ACK or nothing */
if (type != COAP_TYPE_ACK) {
return 0;
}
return -ECANCELED;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation of coap_build_reply_header() (and coap_reply_simple() which makes use of this) will now also need an update.

}
}

Expand Down Expand Up @@ -690,18 +699,7 @@ ssize_t coap_build_reply(coap_pkt_t *pkt, unsigned code,

/* option contains bitmap of disinterest */
if (no_response & mask) {
switch (coap_get_type(pkt)) {
case COAP_TYPE_NON:
/* no response and no ACK */
return 0;
default:
/* There is an immediate ACK response, but it is an empty response */
code = COAP_CODE_EMPTY;
len = sizeof(coap_hdr_t);
tkl = 0;
payload_len = 0;
break;
}
return -ECANCELED;
}
}

Expand Down
Loading