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

net: lib: coap_client: Improve cancel function #1667

Closed
wants to merge 2 commits into from
Closed
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
12 changes: 12 additions & 0 deletions include/zephyr/net/coap_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ struct coap_client_internal_request {
uint32_t last_id;
uint8_t request_tkl;
bool request_ongoing;
atomic_t in_callback;
struct coap_block_context recv_blk_ctx;
struct coap_block_context send_blk_ctx;
struct coap_pending pending;
Expand Down Expand Up @@ -137,6 +138,17 @@ int coap_client_init(struct coap_client *client, const char *info);
int coap_client_req(struct coap_client *client, int sock, const struct sockaddr *addr,
struct coap_client_request *req, struct coap_transmission_parameters *params);

/**
* @brief Cancel all current requests.
*
* This is intended for canceling long-running requests (e.g. GETs with the OBSERVE option set,
* or a block transfer) which have gone stale for some reason. It is also intended for responding
* to network connectivity issues.
*
* @param client Client instance.
*/
void coap_client_cancel_requests(struct coap_client *client);

/**
* @}
*/
Expand Down
64 changes: 54 additions & 10 deletions subsys/net/lib/coap/coap_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ static atomic_t coap_client_recv_active;
static int send_request(int sock, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
{
LOG_HEXDUMP_DBG(buf, len, "Send CoAP Request:");
SeppoTakalo marked this conversation as resolved.
Show resolved Hide resolved
if (addrlen == 0) {
return zsock_sendto(sock, buf, len, flags, NULL, 0);
} else {
Expand All @@ -37,11 +38,17 @@ static int send_request(int sock, const void *buf, size_t len, int flags,
static int receive(int sock, void *buf, size_t max_len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen)
{
ssize_t err;

if (*addrlen == 0) {
return zsock_recvfrom(sock, buf, max_len, flags, NULL, NULL);
err = zsock_recvfrom(sock, buf, max_len, flags, NULL, NULL);
} else {
return zsock_recvfrom(sock, buf, max_len, flags, src_addr, addrlen);
err = zsock_recvfrom(sock, buf, max_len, flags, src_addr, addrlen);
}
if (err > 0) {
LOG_HEXDUMP_DBG(buf, err, "Receive CoAP Response:");
}
return err;
}

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

if (internal_req == NULL) {
LOG_DBG("No more free requests");
return -EAGAIN;
}

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

if (k_mutex_lock(&client->send_mutex, K_NO_WAIT)) {
LOG_DBG("Could not immediately lock send_mutex");
return -EAGAIN;
}

Expand Down Expand Up @@ -380,8 +389,13 @@ int coap_client_req(struct coap_client *client, int sock, const struct sockaddr
static void report_callback_error(struct coap_client_internal_request *internal_req, int error_code)
{
if (internal_req->coap_request.cb) {
internal_req->coap_request.cb(error_code, 0, NULL, 0, true,
internal_req->coap_request.user_data);
if (!atomic_set(&internal_req->in_callback, 1)) {
internal_req->coap_request.cb(error_code, 0, NULL, 0, true,
internal_req->coap_request.user_data);
atomic_clear(&internal_req->in_callback);
} else {
LOG_DBG("Cannot call the callback; already in it.");
}
}
}

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

if (internal_req->pending.timeout != 0 && coap_pending_cycle(&internal_req->pending)) {
if (internal_req->request_ongoing &&
internal_req->pending.timeout != 0 &&
coap_pending_cycle(&internal_req->pending)) {
LOG_ERR("Timeout in poll, retrying send");

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

/* Call user callback */
if (internal_req->coap_request.cb) {
internal_req->coap_request.cb(response_code, internal_req->offset, payload,
payload_len, last_block,
internal_req->coap_request.user_data);

if (!atomic_set(&internal_req->in_callback, 1)) {
internal_req->coap_request.cb(response_code, internal_req->offset, payload,
payload_len, last_block,
internal_req->coap_request.user_data);
atomic_clear(&internal_req->in_callback);
}
if (!internal_req->request_ongoing) {
/* User callback must have called coap_client_cancel_requests(). */
goto fail;
}
/* Update the offset for next callback in a blockwise transfer */
if (blockwise_transfer) {
internal_req->offset += payload_len;
Expand Down Expand Up @@ -811,10 +833,32 @@ static int handle_response(struct coap_client *client, const struct coap_packet
}
fail:
client->response_ready = false;
internal_req->request_ongoing = false;
if (ret != 0 || !coap_request_is_observe(&internal_req->request)) {
internal_req->request_ongoing = false;
}
return ret;
}

void coap_client_cancel_requests(struct coap_client *client)
{
for (int i = 0; i < ARRAY_SIZE(client->requests); i++) {
if (client->requests[i].request_ongoing == true) {
LOG_DBG("Cancelling request %d", i);
/* Report the request was cancelled. This will be skipped if
* this function was called from the user's callback so we
* do not reenter it. In that case, the user knows their
* request was cancelled anyway.
*/
report_callback_error(&client->requests[i], -ECANCELED);
client->requests[i].request_ongoing = false;
}
}
atomic_clear(&coap_client_recv_active);

/* Wait until after zsock_poll() can time out and return. */
k_sleep(K_MSEC(COAP_PERIODIC_TIMEOUT));
}

void coap_client_recv(void *coap_cl, void *a, void *b)
{
int ret;
Expand Down
Loading