Skip to content

Commit bfed8d0

Browse files
fgervaismmahadevan108
authored andcommitted
net: lib: coap_client: wait for all acknowledgements
This commit makes sure we continue to wait for extra confirmations even after the request is done so we can handle duplicate confirmations if any. Detailed description: rfc7252#section-4.5 specifies that: "The recipient SHOULD acknowledge each duplicate copy of a Confirmable message". So if, for example, the client sends to a multicast destination address, the server will get multiple requests and will confirm all of them. Without this commit, the client will set the request to done after receiving the first answer. From here the request object will be marked as free and the duplicate acknowledgements will stay buffered in the network stack. Once the client tries to send a new request, it will unbuffer those duplicate acknowledgements but now the request object is unallocated so the client won't be able to handle those acknowledgements as duplicates. It will instead treat it as an unexpected ACK. To work around this issue, rfc7252#section-4.8.2 states that: "EXCHANGE_LIFETIME is the time from starting to send a Confirmable message to the time when an acknowledgement is no longer expected, i.e., message-layer information about the message exchange can be purged." Keeping the request object allocated for EXCHANGE_LIFETIME ensures that duplicate acknowledgements can be handled accordingly. This commit adds a basic implementation of what is stated in the RFC. EXCHANGE_LIFETIME has been arbitrarily set to 3 * ACK_TIMEOUT which seems more reasonable than the 247 seconds stated in the RFC. Signed-off-by: Francois Gervais <[email protected]>
1 parent aa185c7 commit bfed8d0

File tree

1 file changed

+47
-6
lines changed

1 file changed

+47
-6
lines changed

subsys/net/lib/coap/coap_client.c

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ LOG_MODULE_DECLARE(net_coap, CONFIG_COAP_LOG_LEVEL);
1616
#define COAP_VERSION 1
1717
#define COAP_SEPARATE_TIMEOUT 6000
1818
#define COAP_PERIODIC_TIMEOUT 500
19+
#define COAP_EXCHANGE_LIFETIME_FACTOR 3
1920
#define BLOCK1_OPTION_SIZE 4
2021
#define PAYLOAD_MARKER_SIZE 1
2122

@@ -86,6 +87,21 @@ static int coap_client_schedule_poll(struct coap_client *client, int sock,
8687
return 0;
8788
}
8889

90+
static bool exchange_lifetime_exceeded(struct coap_client_internal_request *internal_req)
91+
{
92+
int64_t time_since_t0, exchange_lifetime;
93+
94+
if (coap_header_get_type(&internal_req->request) == COAP_TYPE_NON_CON) {
95+
return true;
96+
}
97+
98+
time_since_t0 = k_uptime_get() - internal_req->pending.t0;
99+
exchange_lifetime =
100+
(internal_req->pending.params.ack_timeout * COAP_EXCHANGE_LIFETIME_FACTOR);
101+
102+
return time_since_t0 > exchange_lifetime;
103+
}
104+
89105
static bool has_ongoing_request(struct coap_client *client)
90106
{
91107
for (int i = 0; i < CONFIG_COAP_CLIENT_MAX_REQUESTS; i++) {
@@ -97,10 +113,23 @@ static bool has_ongoing_request(struct coap_client *client)
97113
return false;
98114
}
99115

116+
static bool has_ongoing_exchange(struct coap_client *client)
117+
{
118+
for (int i = 0; i < CONFIG_COAP_CLIENT_MAX_REQUESTS; i++) {
119+
if (client->requests[i].request_ongoing == true ||
120+
!exchange_lifetime_exceeded(&client->requests[i])) {
121+
return true;
122+
}
123+
}
124+
125+
return false;
126+
}
127+
100128
static struct coap_client_internal_request *get_free_request(struct coap_client *client)
101129
{
102130
for (int i = 0; i < CONFIG_COAP_CLIENT_MAX_REQUESTS; i++) {
103-
if (client->requests[i].request_ongoing == false) {
131+
if (client->requests[i].request_ongoing == false &&
132+
exchange_lifetime_exceeded(&client->requests[i])) {
104133
return &client->requests[i];
105134
}
106135
}
@@ -110,13 +139,24 @@ static struct coap_client_internal_request *get_free_request(struct coap_client
110139

111140
static bool has_ongoing_requests(void)
112141
{
113-
bool has_requests = false;
142+
for (int i = 0; i < num_clients; i++) {
143+
if (has_ongoing_request(clients[i])) {
144+
return true;
145+
}
146+
}
114147

148+
return false;
149+
}
150+
151+
static bool has_ongoing_exchanges(void)
152+
{
115153
for (int i = 0; i < num_clients; i++) {
116-
has_requests |= has_ongoing_request(clients[i]);
154+
if (has_ongoing_exchange(clients[i])) {
155+
return true;
156+
}
117157
}
118158

119-
return has_requests;
159+
return false;
120160
}
121161

122162
static enum coap_block_size coap_client_default_block_size(void)
@@ -611,7 +651,8 @@ static struct coap_client_internal_request *get_request_with_token(
611651
response_tkl = coap_header_get_token(resp, response_token);
612652

613653
for (int i = 0; i < CONFIG_COAP_CLIENT_MAX_REQUESTS; i++) {
614-
if (client->requests[i].request_ongoing) {
654+
if (client->requests[i].request_ongoing ||
655+
!exchange_lifetime_exceeded(&client->requests[i])) {
615656
if (client->requests[i].request_tkl != response_tkl) {
616657
continue;
617658
}
@@ -910,7 +951,7 @@ static void coap_client_recv(void *coap_cl, void *a, void *b)
910951
}
911952

912953
/* There are more messages coming */
913-
if (has_ongoing_requests()) {
954+
if (has_ongoing_exchanges()) {
914955
continue;
915956
} else {
916957
idle:

0 commit comments

Comments
 (0)