1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-28 07:51:19 +01:00

gcoap: Process CON responses

This generalizes the existing code for answering CoAP pings into general
message-layer responses. Such responses are now also sent as a reaction
to CON responses, which can otherwise follow the same code path as
existing other responses.

As a side effect, issues that would crop up when responding to odd empty
requests that have token length set are resolved.

Contributes-To: https://github.com/RIOT-OS/RIOT/issues/14169
This commit is contained in:
chrysn 2020-05-30 15:49:15 +02:00
parent 8c9bc2ada0
commit ff00d66d69

View File

@ -41,6 +41,9 @@
#define GCOAP_RESOURCE_WRONG_METHOD -1
#define GCOAP_RESOURCE_NO_PATH -2
/* Sentinel value indicating that no immediate response is required */
#define NO_IMMEDIATE_REPLY (-1)
/* End of the range to pick a random timeout */
#define TIMEOUT_RANGE_END (CONFIG_COAP_ACK_TIMEOUT * CONFIG_COAP_RANDOM_FACTOR_1000 / 1000)
@ -133,6 +136,15 @@ static void _on_sock_evt(sock_udp_t *sock, sock_async_flags_t type, void *arg)
coap_pkt_t pdu;
sock_udp_ep_t remote;
gcoap_request_memo_t *memo = NULL;
/* Code paths that necessitate a response on the message layer can set a
* response type here (COAP_TYPE_RST or COAP_TYPE_ACK). If set, at the end
* of the function there will be
* * that value will be put in the code field,
* * token length cleared,
* * code set to EMPTY, and
* * the message is returned with the rest of its header intact.
*/
int8_t messagelayer_emptyresponse_type = NO_IMMEDIATE_REPLY;
(void)arg;
if (type & SOCK_ASYNC_MSG_RECV) {
@ -157,13 +169,7 @@ static void _on_sock_evt(sock_udp_t *sock, sock_async_flags_t type, void *arg)
if (coap_get_code_raw(&pdu) == COAP_CODE_EMPTY) {
/* ping request */
if (coap_get_type(&pdu) == COAP_TYPE_CON) {
coap_hdr_set_type(pdu.hdr, COAP_TYPE_RST);
ssize_t bytes = sock_udp_send(sock, _listen_buf,
sizeof(coap_hdr_t), &remote);
if (bytes <= 0) {
DEBUG("gcoap: ping response failed: %d\n", (int)bytes);
}
messagelayer_emptyresponse_type = COAP_TYPE_RST;
} else if (coap_get_type(&pdu) == COAP_TYPE_NON) {
DEBUG("gcoap: empty NON msg\n");
}
@ -200,6 +206,10 @@ empty_as_response:
_find_req_memo(&memo, &pdu, &remote);
if (memo) {
switch (coap_get_type(&pdu)) {
case COAP_TYPE_CON:
messagelayer_emptyresponse_type = COAP_TYPE_ACK;
DEBUG("gcoap: Answering CON response with ACK\n");
/* fall through */
case COAP_TYPE_NON:
case COAP_TYPE_ACK:
if (memo->resp_evt_tmout.queue) {
@ -215,9 +225,6 @@ empty_as_response:
}
memo->state = GCOAP_MEMO_UNUSED;
break;
case COAP_TYPE_CON:
DEBUG("gcoap: separate CON response not handled yet\n");
break;
default:
DEBUG("gcoap: illegal response type: %u\n", coap_get_type(&pdu));
break;
@ -231,6 +238,23 @@ empty_as_response:
DEBUG("gcoap: illegal code class: %u\n", coap_get_code_class(&pdu));
}
}
if (messagelayer_emptyresponse_type != NO_IMMEDIATE_REPLY) {
coap_hdr_set_type(pdu.hdr, (uint8_t)messagelayer_emptyresponse_type);
coap_hdr_set_code(pdu.hdr, COAP_CODE_EMPTY);
/* Set the token length to 0, preserving the CoAP version as it was and
* the empty message type that was just set.
*
* FIXME: Introduce an internal function to set or truncate the token
* */
pdu.hdr->ver_t_tkl &= 0xf0;
ssize_t bytes = sock_udp_send(sock, _listen_buf,
sizeof(coap_hdr_t), &remote);
if (bytes <= 0) {
DEBUG("gcoap: empty response failed: %d\n", (int)bytes);
}
}
}
/* Handles response timeout for a request; resend confirmable if needed. */