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

nanocoap: add support for no-response option #18154

Merged
merged 3 commits into from
Oct 15, 2022
Merged
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
5 changes: 5 additions & 0 deletions sys/include/net/coap.h
Original file line number Diff line number Diff line change
@@ -53,6 +53,11 @@ extern "C" {
#define COAP_OPT_BLOCK1 (27)
#define COAP_OPT_PROXY_URI (35)
#define COAP_OPT_PROXY_SCHEME (39)
/**
* @brief suppress CoAP response
* @see [RFC 7968](https://datatracker.ietf.org/doc/html/rfc7967)
*/
#define COAP_OPT_NO_RESPONSE (258)
/** @} */

/**
7 changes: 7 additions & 0 deletions sys/include/net/nanocoap.h
Original file line number Diff line number Diff line change
@@ -1817,6 +1817,13 @@ ssize_t coap_build_hdr(coap_hdr_t *hdr, unsigned type, uint8_t *token,
* @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
* 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
*/
38 changes: 38 additions & 0 deletions sys/include/net/nanocoap_sock.h
Original file line number Diff line number Diff line change
@@ -240,6 +240,25 @@ ssize_t nanocoap_sock_put(nanocoap_sock_t *sock, const char *path,
const void *request, size_t len,
void *response, size_t len_max);

/**
* @brief Simple non-confirmable PUT
*
* @param[in] sock socket to use for the request
* @param[in] path remote path
* @param[in] request buffer containing the payload
* @param[in] len length of the payload to send
* @param[out] response buffer for the response, may be NULL
* @param[in] len_max length of @p response
*
* @returns length of response payload on success
* @returns 0 if the request was sent and no response buffer was provided,
* independently of success (because no response is requested in that case)
* @returns <0 on error
*/
ssize_t nanocoap_sock_put_non(nanocoap_sock_t *sock, const char *path,
const void *request, size_t len,
void *response, size_t len_max);

/**
* @brief Simple synchronous CoAP (confirmable) PUT to URL
*
@@ -273,6 +292,25 @@ ssize_t nanocoap_sock_post(nanocoap_sock_t *sock, const char *path,
const void *request, size_t len,
void *response, size_t len_max);

/**
* @brief Simple non-confirmable POST
*
* @param[in] sock socket to use for the request
* @param[in] path remote path
* @param[in] request buffer containing the payload
* @param[in] len length of the payload to send
* @param[out] response buffer for the response, may be NULL
* @param[in] len_max length of @p response
*
* @returns length of response payload on success
* @returns 0 if the request was sent and no response buffer was provided,
* independently of success (because no response is requested in that case)
* @returns <0 on error
*/
ssize_t nanocoap_sock_post_non(nanocoap_sock_t *sock, const char *path,
const void *request, size_t len,
void *response, size_t len_max);

/**
* @brief Simple synchronous CoAP (confirmable) POST to URL
*
26 changes: 26 additions & 0 deletions sys/net/application_layer/nanocoap/nanocoap.c
Original file line number Diff line number Diff line change
@@ -513,6 +513,32 @@ ssize_t coap_build_reply(coap_pkt_t *pkt, unsigned code,
}
}

uint32_t no_response;
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 */
assert(no_response_index < 7);

const uint8_t mask = 1 << no_response_index;

/* 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;
}
}
}

coap_build_hdr((coap_hdr_t *)rbuf, type, coap_get_token(pkt), tkl, code,
ntohs(pkt->hdr->id));
coap_hdr_set_type((coap_hdr_t *)rbuf, type);
35 changes: 30 additions & 5 deletions sys/net/application_layer/nanocoap/sock.c
Original file line number Diff line number Diff line change
@@ -311,7 +311,7 @@ ssize_t nanocoap_sock_get(nanocoap_sock_t *sock, const char *path, void *buf, si
}

ssize_t _sock_put_post(nanocoap_sock_t *sock, const char *path, unsigned code,
const void *request, size_t len,
uint8_t type, const void *request, size_t len,
void *response, size_t max_len)
{
/* buffer for CoAP header */
@@ -333,9 +333,15 @@ ssize_t _sock_put_post(nanocoap_sock_t *sock, const char *path, unsigned code,
.iov_len = max_len,
};

pktpos += coap_build_hdr(pkt.hdr, COAP_TYPE_CON, NULL, 0, code, _get_id());
pktpos += coap_build_hdr(pkt.hdr, type, NULL, 0, code, _get_id());
pktpos += coap_opt_put_uri_path(pktpos, 0, path);

if (response == NULL && type == COAP_TYPE_NON) {
/* all responses (2.xx, 4.xx and 5.xx) are ignored */
pktpos += coap_opt_put_uint(pktpos, COAP_OPT_URI_PATH,
COAP_OPT_NO_RESPONSE, 26);
}

if (len) {
/* set payload marker */
*pktpos++ = 0xFF;
@@ -351,14 +357,32 @@ ssize_t nanocoap_sock_put(nanocoap_sock_t *sock, const char *path,
const void *request, size_t len,
void *response, size_t len_max)
{
return _sock_put_post(sock, path, COAP_METHOD_PUT, request, len, response, len_max);
return _sock_put_post(sock, path, COAP_METHOD_PUT, COAP_TYPE_CON, request, len,
response, len_max);
}

ssize_t nanocoap_sock_post(nanocoap_sock_t *sock, const char *path,
const void *request, size_t len,
void *response, size_t len_max)
{
return _sock_put_post(sock, path, COAP_METHOD_POST, request, len, response, len_max);
return _sock_put_post(sock, path, COAP_METHOD_POST, COAP_TYPE_CON, request, len,
response, len_max);
}

ssize_t nanocoap_sock_put_non(nanocoap_sock_t *sock, const char *path,
const void *request, size_t len,
void *response, size_t len_max)
{
return _sock_put_post(sock, path, COAP_METHOD_PUT, COAP_TYPE_NON, request, len,
response, len_max);
}

ssize_t nanocoap_sock_post_non(nanocoap_sock_t *sock, const char *path,
const void *request, size_t len,
void *response, size_t len_max)
{
return _sock_put_post(sock, path, COAP_METHOD_POST, COAP_TYPE_NON, request, len,
response, len_max);
}

static ssize_t _sock_put_post_url(const char *url, unsigned code,
@@ -371,7 +395,8 @@ static ssize_t _sock_put_post_url(const char *url, unsigned code,
return res;
}

res = _sock_put_post(&sock, sock_urlpath(url), code, request, len, response, len_max);
res = _sock_put_post(&sock, sock_urlpath(url), code, COAP_TYPE_CON,
request, len, response, len_max);
nanocoap_sock_close(&sock);

return res;
2 changes: 2 additions & 0 deletions tests/nanocoap_cli/main.c
Original file line number Diff line number Diff line change
@@ -32,12 +32,14 @@ extern int nanotest_client_cmd(int argc, char **argv);
extern int nanotest_client_url_cmd(int argc, char **argv);
extern int nanotest_server_cmd(int argc, char **argv);
extern int nanotest_client_put_cmd(int argc, char **argv);
extern int nanotest_client_put_non_cmd(int argc, char **argv);
static int _list_all_inet6(int argc, char **argv);

static const shell_command_t shell_commands[] = {
{ "client", "CoAP client", nanotest_client_cmd },
{ "url", "CoAP client URL request", nanotest_client_url_cmd },
{ "put", "experimental put", nanotest_client_put_cmd },
{ "put_non", "non-confirmable put", nanotest_client_put_non_cmd },
{ "server", "CoAP server", nanotest_server_cmd },
{ "inet6", "IPv6 addresses", _list_all_inet6 },
{ NULL, NULL, NULL }
19 changes: 19 additions & 0 deletions tests/nanocoap_cli/nanocli_client.c
Original file line number Diff line number Diff line change
@@ -298,3 +298,22 @@ int nanotest_client_put_cmd(int argc, char **argv)
nanocoap_block_request_done(&ctx);
return res;
}

int nanotest_client_put_non_cmd(int argc, char **argv)
{
int res;

if (argc < 3) {
printf("usage: %s <url> <data>\n", argv[0]);
return 1;
}

nanocoap_sock_t sock;
nanocoap_sock_url_connect(argv[1], &sock);

res = nanocoap_sock_put_non(&sock, sock_urlpath(argv[1]), argv[2], strlen(argv[2]),
NULL, 0);
nanocoap_sock_close(&sock);

return res;
}