Skip to content

Commit f04f8b2

Browse files
plskeggscarlescufi
authored andcommitted
net: lib: coap_client: Improve cancel function
Improve coap_client_cancel_requests(). Ensure it can be called from a callback. Report error to waiting callbacks. Clear active flag. This is useful when the network becomes unavailable or prior to disconnecting in order to save power. Signed-off-by: Pete Skeggs <[email protected]>
1 parent 90b654e commit f04f8b2

File tree

2 files changed

+49
-13
lines changed

2 files changed

+49
-13
lines changed

include/zephyr/net/coap_client.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ struct coap_client_internal_request {
8484
uint32_t last_id;
8585
uint8_t request_tkl;
8686
bool request_ongoing;
87+
atomic_t in_callback;
8788
struct coap_block_context recv_blk_ctx;
8889
struct coap_block_context send_blk_ctx;
8990
struct coap_pending pending;
@@ -140,14 +141,14 @@ int coap_client_req(struct coap_client *client, int sock, const struct sockaddr
140141
/**
141142
* @brief Cancel all current requests.
142143
*
143-
* This is intended for canceling long-running requests (e.g. GETs with the OBSERVE option set)
144-
* which has gone stale for some reason.
144+
* This is intended for canceling long-running requests (e.g. GETs with the OBSERVE option set,
145+
* or a block transfer) which have gone stale for some reason. It is also intended for responding
146+
* to network connectivity issues.
145147
*
146148
* @param client Client instance.
147149
*/
148150
void coap_client_cancel_requests(struct coap_client *client);
149151

150-
151152
/**
152153
* @}
153154
*/

subsys/net/lib/coap/coap_client.c

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ static atomic_t coap_client_recv_active;
2727
static int send_request(int sock, const void *buf, size_t len, int flags,
2828
const struct sockaddr *dest_addr, socklen_t addrlen)
2929
{
30+
LOG_HEXDUMP_DBG(buf, len, "Send CoAP Request:");
3031
if (addrlen == 0) {
3132
return zsock_sendto(sock, buf, len, flags, NULL, 0);
3233
} else {
@@ -37,11 +38,17 @@ static int send_request(int sock, const void *buf, size_t len, int flags,
3738
static int receive(int sock, void *buf, size_t max_len, int flags,
3839
struct sockaddr *src_addr, socklen_t *addrlen)
3940
{
41+
ssize_t err;
42+
4043
if (*addrlen == 0) {
41-
return zsock_recvfrom(sock, buf, max_len, flags, NULL, NULL);
44+
err = zsock_recvfrom(sock, buf, max_len, flags, NULL, NULL);
4245
} else {
43-
return zsock_recvfrom(sock, buf, max_len, flags, src_addr, addrlen);
46+
err = zsock_recvfrom(sock, buf, max_len, flags, src_addr, addrlen);
47+
}
48+
if (err > 0) {
49+
LOG_HEXDUMP_DBG(buf, err, "Receive CoAP Response:");
4450
}
51+
return err;
4552
}
4653

4754
static void reset_block_contexts(struct coap_client_internal_request *request)
@@ -282,6 +289,7 @@ int coap_client_req(struct coap_client *client, int sock, const struct sockaddr
282289
struct coap_client_internal_request *internal_req = get_free_request(client);
283290

284291
if (internal_req == NULL) {
292+
LOG_DBG("No more free requests");
285293
return -EAGAIN;
286294
}
287295

@@ -320,6 +328,7 @@ int coap_client_req(struct coap_client *client, int sock, const struct sockaddr
320328
reset_internal_request(internal_req);
321329

322330
if (k_mutex_lock(&client->send_mutex, K_NO_WAIT)) {
331+
LOG_DBG("Could not immediately lock send_mutex");
323332
return -EAGAIN;
324333
}
325334

@@ -380,8 +389,13 @@ int coap_client_req(struct coap_client *client, int sock, const struct sockaddr
380389
static void report_callback_error(struct coap_client_internal_request *internal_req, int error_code)
381390
{
382391
if (internal_req->coap_request.cb) {
383-
internal_req->coap_request.cb(error_code, 0, NULL, 0, true,
384-
internal_req->coap_request.user_data);
392+
if (!atomic_set(&internal_req->in_callback, 1)) {
393+
internal_req->coap_request.cb(error_code, 0, NULL, 0, true,
394+
internal_req->coap_request.user_data);
395+
atomic_clear(&internal_req->in_callback);
396+
} else {
397+
LOG_DBG("Cannot call the callback; already in it.");
398+
}
385399
}
386400
}
387401

@@ -400,7 +414,9 @@ static int resend_request(struct coap_client *client,
400414
{
401415
int ret = 0;
402416

403-
if (internal_req->pending.timeout != 0 && coap_pending_cycle(&internal_req->pending)) {
417+
if (internal_req->request_ongoing &&
418+
internal_req->pending.timeout != 0 &&
419+
coap_pending_cycle(&internal_req->pending)) {
404420
LOG_ERR("Timeout in poll, retrying send");
405421

406422
/* Reset send block context as it was updated in previous init from packet */
@@ -765,10 +781,16 @@ static int handle_response(struct coap_client *client, const struct coap_packet
765781

766782
/* Call user callback */
767783
if (internal_req->coap_request.cb) {
768-
internal_req->coap_request.cb(response_code, internal_req->offset, payload,
769-
payload_len, last_block,
770-
internal_req->coap_request.user_data);
771-
784+
if (!atomic_set(&internal_req->in_callback, 1)) {
785+
internal_req->coap_request.cb(response_code, internal_req->offset, payload,
786+
payload_len, last_block,
787+
internal_req->coap_request.user_data);
788+
atomic_clear(&internal_req->in_callback);
789+
}
790+
if (!internal_req->request_ongoing) {
791+
/* User callback must have called coap_client_cancel_requests(). */
792+
goto fail;
793+
}
772794
/* Update the offset for next callback in a blockwise transfer */
773795
if (blockwise_transfer) {
774796
internal_req->offset += payload_len;
@@ -820,8 +842,21 @@ static int handle_response(struct coap_client *client, const struct coap_packet
820842
void coap_client_cancel_requests(struct coap_client *client)
821843
{
822844
for (int i = 0; i < ARRAY_SIZE(client->requests); i++) {
823-
client->requests[i].request_ongoing = false;
845+
if (client->requests[i].request_ongoing == true) {
846+
LOG_DBG("Cancelling request %d", i);
847+
/* Report the request was cancelled. This will be skipped if
848+
* this function was called from the user's callback so we
849+
* do not reenter it. In that case, the user knows their
850+
* request was cancelled anyway.
851+
*/
852+
report_callback_error(&client->requests[i], -ECANCELED);
853+
client->requests[i].request_ongoing = false;
854+
}
824855
}
856+
atomic_clear(&coap_client_recv_active);
857+
858+
/* Wait until after zsock_poll() can time out and return. */
859+
k_sleep(K_MSEC(COAP_PERIODIC_TIMEOUT));
825860
}
826861

827862
void coap_client_recv(void *coap_cl, void *a, void *b)

0 commit comments

Comments
 (0)