From 8a5268c5a77c2ab4b1ab96f8884dfa1c79d2b4a8 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 18 Jan 2021 13:13:26 +0100 Subject: [PATCH] net: coap: Rework pending retransmission logic Introduce retransmission counter to the coap_pending structure. This allows to simplify the retransmission logic and allows to keep track of the number of remaining retranmissions. Additionally, extend the `coap_pending_init()` function with `retries` parameter, which allows to set the retransmission count individually for each confirmable transaction. Fixes #28117 Signed-off-by: Robert Lubos --- doc/releases/release-notes-2.5.rst | 4 +++ include/net/coap.h | 7 +++- .../net/sockets/coap_server/src/coap-server.c | 3 +- subsys/net/lib/coap/coap.c | 34 ++++++++----------- subsys/net/lib/lwm2m/lwm2m_engine.c | 7 ++-- tests/net/lib/coap/src/main.c | 3 +- 6 files changed, 34 insertions(+), 24 deletions(-) diff --git a/doc/releases/release-notes-2.5.rst b/doc/releases/release-notes-2.5.rst index f7e2a5690cf1..dff368beead1 100644 --- a/doc/releases/release-notes-2.5.rst +++ b/doc/releases/release-notes-2.5.rst @@ -58,6 +58,10 @@ API Changes timeout usage must use the new-style k_timeout_t type and not the legacy/deprecated millisecond counts. +* The :c:func:`coap_pending_init` function now accepts an additional ``retries`` + parameter, allowing to specify the maximum retransmission count of the + confirmable message. + Deprecated in this release ========================== diff --git a/include/net/coap.h b/include/net/coap.h index 32bc989bf541..91e3b31d2c9a 100644 --- a/include/net/coap.h +++ b/include/net/coap.h @@ -233,6 +233,8 @@ typedef int (*coap_reply_t)(const struct coap_packet *response, struct coap_reply *reply, const struct sockaddr *from); +#define COAP_DEFAULT_MAX_RETRANSMIT 4 + /** * @brief Represents a request awaiting for an acknowledgment (ACK). */ @@ -243,6 +245,7 @@ struct coap_pending { uint16_t id; uint8_t *data; uint16_t len; + uint8_t retries; }; /** @@ -687,12 +690,14 @@ void coap_reply_init(struct coap_reply *reply, * confirmation message, initialized with data from @a request * @param request Message waiting for confirmation * @param addr Address to send the retransmission + * @param retries Maximum number of retransmissions of the message. * * @return 0 in case of success or negative in case of error. */ int coap_pending_init(struct coap_pending *pending, const struct coap_packet *request, - const struct sockaddr *addr); + const struct sockaddr *addr, + uint8_t retries); /** * @brief Returns the next available pending struct, that can be used diff --git a/samples/net/sockets/coap_server/src/coap-server.c b/samples/net/sockets/coap_server/src/coap-server.c index 2341618e643c..adc5be9d1ac9 100644 --- a/samples/net/sockets/coap_server/src/coap-server.c +++ b/samples/net/sockets/coap_server/src/coap-server.c @@ -995,7 +995,8 @@ static int create_pending_request(struct coap_packet *response, return -ENOMEM; } - r = coap_pending_init(pending, response, addr); + r = coap_pending_init(pending, response, addr, + COAP_DEFAULT_MAX_RETRANSMIT); if (r < 0) { return -EINVAL; } diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index 17767b2fabec..ff0a1f7d5bf3 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -1072,7 +1072,8 @@ size_t coap_next_block(const struct coap_packet *cpkt, int coap_pending_init(struct coap_pending *pending, const struct coap_packet *request, - const struct sockaddr *addr) + const struct sockaddr *addr, + uint8_t retries) { memset(pending, 0, sizeof(*pending)); @@ -1083,6 +1084,7 @@ int coap_pending_init(struct coap_pending *pending, pending->data = request->data; pending->len = request->offset; pending->t0 = k_uptime_get_32(); + pending->retries = retries; return 0; } @@ -1201,30 +1203,24 @@ struct coap_pending *coap_pending_next_to_expire( */ #define INIT_ACK_TIMEOUT CONFIG_COAP_INIT_ACK_TIMEOUT_MS -static int32_t next_timeout(int32_t previous) +bool coap_pending_cycle(struct coap_pending *pending) { - switch (previous) { - case INIT_ACK_TIMEOUT: - case (INIT_ACK_TIMEOUT * 2): - case (INIT_ACK_TIMEOUT * 4): - return previous << 1; - case (INIT_ACK_TIMEOUT * 8): - /* equal value is returned to end retransmit */ - return previous; - } + if (pending->timeout == 0) { + /* Initial transmission. */ + pending->timeout = INIT_ACK_TIMEOUT; - /* initial or unrecognized */ - return INIT_ACK_TIMEOUT; -} + return true; + } -bool coap_pending_cycle(struct coap_pending *pending) -{ - int32_t old = pending->timeout; + if (pending->retries == 0) { + return false; + } pending->t0 += pending->timeout; - pending->timeout = next_timeout(pending->timeout); + pending->timeout = pending->timeout << 1; + pending->retries--; - return (old != pending->timeout); + return true; } void coap_pending_clear(struct coap_pending *pending) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 7a138a6003d1..8c98fea8b63d 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -961,7 +961,8 @@ int lwm2m_init_message(struct lwm2m_message *msg) goto cleanup; } - r = coap_pending_init(msg->pending, &msg->cpkt, &msg->ctx->remote_addr); + r = coap_pending_init(msg->pending, &msg->cpkt, &msg->ctx->remote_addr, + COAP_DEFAULT_MAX_RETRANSMIT); if (r < 0) { LOG_ERR("Unable to initialize a pending " "retransmission (err:%d).", r); @@ -3996,7 +3997,9 @@ static int lwm2m_response_promote_to_con(struct lwm2m_message *msg) return -ENOMEM; } - ret = coap_pending_init(msg->pending, &msg->cpkt, &msg->ctx->remote_addr); + ret = coap_pending_init(msg->pending, &msg->cpkt, + &msg->ctx->remote_addr, + COAP_DEFAULT_MAX_RETRANSMIT); if (ret < 0) { LOG_ERR("Unable to initialize a pending " "retransmission (err:%d).", ret); diff --git a/tests/net/lib/coap/src/main.c b/tests/net/lib/coap/src/main.c index 0363ffe884b4..902613b216b4 100644 --- a/tests/net/lib/coap/src/main.c +++ b/tests/net/lib/coap/src/main.c @@ -1099,7 +1099,8 @@ static int test_retransmit_second_round(void) goto done; } - r = coap_pending_init(pending, &cpkt, (struct sockaddr *) &dummy_addr); + r = coap_pending_init(pending, &cpkt, (struct sockaddr *) &dummy_addr, + COAP_DEFAULT_MAX_RETRANSMIT); if (r < 0) { TC_PRINT("Could not initialize packet\n"); goto done;