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 sock: stop retransmissions after empty ACK #20697

Merged
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
2 changes: 1 addition & 1 deletion examples/nanocoap_server/coap_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@
(uint8_t *)sub_uri, sub_uri_len);
}

static ssize_t _riot_board_handler(coap_pkt_t *pkt, uint8_t *buf, size_t len, coap_request_ctx_t *context)

Check warning on line 44 in examples/nanocoap_server/coap_handler.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
{
(void)context;
return coap_reply_simple(pkt, COAP_CODE_205, buf, len,
COAP_FORMAT_TEXT, (uint8_t*)RIOT_BOARD, strlen(RIOT_BOARD));
}

static ssize_t _riot_block2_handler(coap_pkt_t *pkt, uint8_t *buf, size_t len, coap_request_ctx_t *context)

Check warning on line 51 in examples/nanocoap_server/coap_handler.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
{
(void)context;
coap_block_slicer_t slicer;
Expand All @@ -63,7 +63,7 @@

/* Add actual content */
bufpos += coap_blockwise_put_bytes(&slicer, bufpos, block2_intro, sizeof(block2_intro)-1);
bufpos += coap_blockwise_put_bytes(&slicer, bufpos, (uint8_t*)RIOT_VERSION, strlen(RIOT_VERSION));

Check warning on line 66 in examples/nanocoap_server/coap_handler.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
bufpos += coap_blockwise_put_char(&slicer, bufpos, ')');
bufpos += coap_blockwise_put_bytes(&slicer, bufpos, block2_board, sizeof(block2_board)-1);
bufpos += coap_blockwise_put_bytes(&slicer, bufpos, (uint8_t*)RIOT_BOARD, strlen(RIOT_BOARD));
Expand All @@ -81,7 +81,7 @@
buf, len, payload_len, &slicer);
}

static ssize_t _riot_value_handler(coap_pkt_t *pkt, uint8_t *buf, size_t len, coap_request_ctx_t *context)

Check warning on line 84 in examples/nanocoap_server/coap_handler.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
{
(void) context;

Expand All @@ -92,7 +92,7 @@
/* read coap method type in packet */
unsigned method_flag = coap_method2flag(coap_get_code_detail(pkt));

switch(method_flag) {

Check warning on line 95 in examples/nanocoap_server/coap_handler.c

View workflow job for this annotation

GitHub Actions / static-tests

keyword 'switch' not followed by a single space
case COAP_GET:
/* write the response buffer with the internal value */
p += fmt_u32_dec(rsp, internal_value);
Expand Down Expand Up @@ -177,7 +177,7 @@
.path = "/riot/board", .methods = COAP_GET, .handler = _riot_board_handler
};
NANOCOAP_RESOURCE(value) {
.path = "/riot/value", .methods = COAP_GET | COAP_PUT | COAP_POST, .handler = _riot_value_handler

Check warning on line 180 in examples/nanocoap_server/coap_handler.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
};
NANOCOAP_RESOURCE(ver) {
.path = "/riot/ver", .methods = COAP_GET, .handler = _riot_block2_handler
Expand All @@ -199,12 +199,12 @@
response, sizeof(response));
}

static ssize_t _separate_handler(coap_pkt_t *pkt, uint8_t *buf, size_t len, coap_request_ctx_t *context)

Check warning on line 202 in examples/nanocoap_server/coap_handler.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
{
static event_timeout_t event_timeout;
static event_callback_t event_timed = EVENT_CALLBACK_INIT(_send_response, &_separate_ctx);

if (event_timeout_is_pending(&event_timeout)) {
if (event_timeout_is_pending(&event_timeout) && !sock_udp_ep_equal(context->remote, &_separate_ctx.remote)) {

Check warning on line 207 in examples/nanocoap_server/coap_handler.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
puts("_separate_handler(): response already scheduled");
return coap_build_reply(pkt, COAP_CODE_SERVICE_UNAVAILABLE, buf, len, 0);
}
Expand Down
53 changes: 34 additions & 19 deletions sys/net/application_layer/nanocoap/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include "atomic_utils.h"
#include "net/credman.h"
#include "net/nanocoap.h"
#include "net/nanocoap_sock.h"
#include "net/sock/util.h"
#include "net/sock/udp.h"
Expand All @@ -52,7 +53,7 @@

enum {
STATE_REQUEST_SEND, /**< request was just sent or will be sent again */
STATE_RESPONSE_RCVD, /**< response received but might be invalid */
STATE_STOP_RETRANSMIT, /**< stop retransmissions due to a matching empty ACK */
STATE_RESPONSE_OK, /**< valid response was received */
};

Expand Down Expand Up @@ -157,12 +158,24 @@
switch (coap_get_type(pkt)) {
case COAP_TYPE_RST:
case COAP_TYPE_ACK:
return coap_get_id(pkt) != id;
default:
if (coap_get_token_len(pkt) != token_len) {
/* message ID only has to match for RST and ACK */
if (coap_get_id(pkt) != id) {
return true;
}
return memcmp(coap_get_token(pkt), token, token_len);
/* falls through */
default:
/* token has to match if message is not empty */
if (pkt->hdr->code != 0) {
if (coap_get_token_len(pkt) != token_len) {
return true;
}
return memcmp(coap_get_token(pkt), token, token_len);
}
else {
/* but only RST and ACK may be empty */
return coap_get_type(pkt) != COAP_TYPE_RST &&
coap_get_type(pkt) != COAP_TYPE_ACK;
}
}
}

Expand Down Expand Up @@ -193,7 +206,7 @@

/* random timeout, deadline for receive retries */
uint32_t timeout = random_uint32_range((uint32_t)CONFIG_COAP_ACK_TIMEOUT_MS * US_PER_MS,
(uint32_t)CONFIG_COAP_ACK_TIMEOUT_MS * CONFIG_COAP_RANDOM_FACTOR_1000);

Check warning on line 209 in sys/net/application_layer/nanocoap/sock.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
uint32_t deadline = _deadline_from_interval(timeout);

/* check if we expect a reply */
Expand All @@ -212,10 +225,7 @@
while (1) {
switch (state) {
case STATE_REQUEST_SEND:
if (tries_left == 0) {
DEBUG("nanocoap: maximum retries reached\n");
return -ETIMEDOUT;
}
assert(tries_left > 0);
--tries_left;

DEBUG("nanocoap: send %u bytes (%u tries left)\n",
Expand All @@ -235,7 +245,7 @@
/* ctx must have been released at this point */
assert(ctx == NULL);
/* fall-through */
case STATE_RESPONSE_RCVD:
case STATE_STOP_RETRANSMIT:
case STATE_RESPONSE_OK:
if (ctx == NULL) {
DEBUG("nanocoap: waiting for response (timeout: %"PRIu32" µs)\n",
Expand All @@ -257,17 +267,20 @@
/* no more data */
/* sock_udp_recv_buf() needs to be called in a loop until ctx is NULL again
* to release the buffer */
if (state == STATE_RESPONSE_RCVD) {
if (state == STATE_STOP_RETRANSMIT) {
continue;
}
return res;
}
res = tmp;
if (res == -ETIMEDOUT) {
if (tries_left == 0) {
DEBUG("nanocoap: maximum retries reached\n");
return -ETIMEDOUT;
}
DEBUG("nanocoap: timeout waiting for response\n");
timeout *= 2;
deadline = _deadline_from_interval(timeout);
state = STATE_REQUEST_SEND;
benpicco marked this conversation as resolved.
Show resolved Hide resolved
continue;
benpicco marked this conversation as resolved.
Show resolved Hide resolved
}
if (res < 0) {
Expand All @@ -276,7 +289,6 @@
}

/* parse response */
state = STATE_RESPONSE_RCVD;
if (coap_parse(pkt, payload, res) < 0) {
DEBUG("nanocoap: error parsing packet\n");
continue;
Expand All @@ -286,27 +298,30 @@
continue;
}

state = STATE_RESPONSE_OK;
DEBUG("nanocoap: response code=%i\n", coap_get_code_decimal(pkt));
switch (coap_get_type(pkt)) {
case COAP_TYPE_RST:
/* TODO: handle different? */
res = -EBADMSG;
break;
case COAP_TYPE_CON:
_send_ack(sock, pkt);
/* fall-through */
case COAP_TYPE_ACK:
if (cb && coap_get_code_raw(pkt) == COAP_CODE_EMPTY) {
if (coap_get_code_raw(pkt) == COAP_CODE_EMPTY) {
/* empty ACK, wait for separate response */
state = STATE_RESPONSE_RCVD;
state = STATE_STOP_RETRANSMIT;
deadline = _deadline_from_interval(CONFIG_COAP_SEPARATE_RESPONSE_TIMEOUT_MS
* US_PER_MS);
tries_left = 0; /* stop retransmissions */
DEBUG("nanocoap: wait for separate response\n");
continue;
}
/* fall-through */
case COAP_TYPE_CON:
case COAP_TYPE_NON:
state = STATE_RESPONSE_OK;
if (coap_get_type(pkt) == COAP_TYPE_CON) {
/* send ACK */
_send_ack(sock, pkt);
}
/* call user callback */
if (cb) {
res = cb(arg, pkt);
Expand Down
Loading