net: lwm2m: Fix separate response handling
Separate response handling implemented in the engine was faulty. The separate response was not acknowledged by the client, resulting in spurious retransmissions from the server side. Also, the pending CON message was retransmitted by the client even after it was acknowledged by an empty ACK, but the respnse haven't arrived yet. Fix this by adding a new `acknowledged` flag to the `lwm2m_message` structure. Once acknowledged, the flag is set and the confirmable message is no longer retransmitted. We keep the message on the pending list in order to timeout properly in case separate response does not arrive in time. Finally, prevent the reply callback from being called twice in case the response is transmitted separately from ACk. The callback should only be called on the actual reply, not the empty ACK. Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
parent
94d62ca151
commit
37681a7bef
2 changed files with 41 additions and 27 deletions
|
@ -3710,14 +3710,30 @@ static void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx,
|
|||
tkl = coap_header_get_token(&response, token);
|
||||
pending = coap_pending_received(&response, client_ctx->pendings,
|
||||
CONFIG_LWM2M_ENGINE_MAX_PENDING);
|
||||
/*
|
||||
* Clear pending pointer because coap_pending_received() calls
|
||||
* coap_pending_clear, and later when we call lwm2m_reset_message()
|
||||
* it will try and call coap_pending_clear() again if msg->pending
|
||||
* is != NULL.
|
||||
*/
|
||||
if (pending) {
|
||||
if (pending && coap_header_get_type(&response) == COAP_TYPE_ACK) {
|
||||
msg = find_msg(pending, NULL);
|
||||
if (msg == NULL) {
|
||||
LOG_DBG("Orphaned pending %p.", pending);
|
||||
return;
|
||||
}
|
||||
|
||||
msg->acknowledged = true;
|
||||
|
||||
if (msg->reply == NULL) {
|
||||
/* No response expected, release the message. */
|
||||
lwm2m_reset_message(msg, true);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the original message was a request and an empty
|
||||
* ACK was received, expect separate response later.
|
||||
*/
|
||||
if ((msg->code >= COAP_METHOD_GET) &&
|
||||
(msg->code <= COAP_METHOD_DELETE) &&
|
||||
(coap_header_get_code(&response) == COAP_CODE_EMPTY)) {
|
||||
LOG_DBG("Empty ACK, expect separate response.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DBG("checking for reply from [%s]",
|
||||
|
@ -3726,28 +3742,16 @@ static void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx,
|
|||
client_ctx->replies,
|
||||
CONFIG_LWM2M_ENGINE_MAX_REPLIES);
|
||||
if (reply) {
|
||||
/*
|
||||
* Separate response is composed of 2 messages, empty ACK with
|
||||
* no token and an additional message with a matching token id
|
||||
* (based on the token used by the CON request).
|
||||
*
|
||||
* Since the ACK received by the notify CON messages are also
|
||||
* empty with no token (consequence of always using the same
|
||||
* token id for all notifications), we have to use an
|
||||
* additional flag to decide when to clear the reply callback.
|
||||
*/
|
||||
if (client_ctx->handle_separate_response && !tkl &&
|
||||
coap_header_get_type(&response) == COAP_TYPE_ACK) {
|
||||
LOG_DBG("separated response, not removing reply");
|
||||
return;
|
||||
msg = find_msg(NULL, reply);
|
||||
|
||||
if (coap_header_get_type(&response) == COAP_TYPE_CON) {
|
||||
r = lwm2m_send_empty_ack(client_ctx,
|
||||
coap_header_get_id(&response));
|
||||
if (r < 0) {
|
||||
LOG_ERR("Error transmitting ACK");
|
||||
}
|
||||
}
|
||||
|
||||
if (!msg) {
|
||||
msg = find_msg(pending, reply);
|
||||
}
|
||||
}
|
||||
|
||||
if (reply || pending) {
|
||||
/* skip release if reply->user_data has error condition */
|
||||
if (reply && reply->user_data != COAP_REPLY_STATUS_NONE) {
|
||||
/* reset reply->user_data for next time */
|
||||
|
@ -3845,6 +3849,13 @@ static void retransmit_request(struct k_work *work)
|
|||
goto next;
|
||||
}
|
||||
|
||||
if (msg->acknowledged) {
|
||||
/* No need to retransmit, just keep the timer running to
|
||||
* timeout in case no response arrives.
|
||||
*/
|
||||
goto next;
|
||||
}
|
||||
|
||||
LOG_INF("Resending message: %p", msg);
|
||||
msg->send_attempts++;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue