Skip to content

Commit 92454e3

Browse files
committed
[nrf fromtree] net: lib: coap_client: Add API to cancel specific request
Add a new API to cancel just one, or mathing requests, instead of cancelling all ongoing requests. Signed-off-by: Seppo Takalo <[email protected]> (cherry picked from commit b3f3bce)
1 parent b0402a1 commit 92454e3

File tree

3 files changed

+158
-0
lines changed

3 files changed

+158
-0
lines changed

include/zephyr/net/coap_client.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,21 @@ int coap_client_req(struct coap_client *client, int sock, const struct sockaddr
158158
*/
159159
void coap_client_cancel_requests(struct coap_client *client);
160160

161+
/**
162+
* @brief Cancel matching requests.
163+
*
164+
* This function cancels all CoAP client request that matches the given request.
165+
* The request is matched based on the method, path, callback and user_data, if provided.
166+
* Any field set to NULL is considered a wildcard.
167+
*
168+
* (struct coap_client_request){0} cancels all requests.
169+
* (struct coap_client_request){.method = COAP_METHOD_GET} cancels all GET requests.
170+
*
171+
* @param client Pointer to the CoAP client instance.
172+
* @param req Pointer to the CoAP client request to be canceled.
173+
*/
174+
void coap_client_cancel_request(struct coap_client *client, struct coap_client_request *req);
175+
161176
/**
162177
* @brief Initialise a Block2 option to be added to a request
163178
*

subsys/net/lib/coap/coap_client.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,41 @@ void coap_client_cancel_requests(struct coap_client *client)
10161016
k_sleep(K_MSEC(COAP_PERIODIC_TIMEOUT));
10171017
}
10181018

1019+
static bool requests_match(struct coap_client_request *a, struct coap_client_request *b)
1020+
{
1021+
/* enum coap_method does not have value for zero, so differentiate valid values */
1022+
if (a->method && b->method && a->method != b->method) {
1023+
return false;
1024+
}
1025+
if (a->path && b->path && strcmp(a->path, b->path) != 0) {
1026+
return false;
1027+
}
1028+
if (a->cb && b->cb && a->cb != b->cb) {
1029+
return false;
1030+
}
1031+
if (a->user_data && b->user_data && a->user_data != b->user_data) {
1032+
return false;
1033+
}
1034+
/* It is intentional that (struct coap_client_request){0} matches all */
1035+
return true;
1036+
}
1037+
1038+
void coap_client_cancel_request(struct coap_client *client, struct coap_client_request *req)
1039+
{
1040+
k_mutex_lock(&client->lock, K_FOREVER);
1041+
1042+
for (int i = 0; i < CONFIG_COAP_CLIENT_MAX_REQUESTS; i++) {
1043+
if (client->requests[i].request_ongoing &&
1044+
requests_match(&client->requests[i].coap_request, req)) {
1045+
LOG_DBG("Cancelling request %d", i);
1046+
report_callback_error(&client->requests[i], -ECANCELED);
1047+
release_internal_request(&client->requests[i]);
1048+
}
1049+
}
1050+
1051+
k_mutex_unlock(&client->lock);
1052+
}
1053+
10191054
void coap_client_recv(void *coap_cl, void *a, void *b)
10201055
{
10211056
int ret;

tests/net/lib/coap_client/src/main.c

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,3 +1142,111 @@ ZTEST(coap_client, test_request_rst)
11421142
zassert_ok(k_sem_take(&sem, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
11431143
zassert_equal(last_response_code, -ECONNRESET, "");
11441144
}
1145+
1146+
ZTEST(coap_client, test_cancel)
1147+
{
1148+
struct k_sem sem1, sem2;
1149+
struct sockaddr address = {0};
1150+
struct coap_client_request req1 = {
1151+
.method = COAP_METHOD_GET,
1152+
.confirmable = true,
1153+
.path = test_path,
1154+
.fmt = COAP_CONTENT_FORMAT_TEXT_PLAIN,
1155+
.cb = coap_callback,
1156+
.payload = short_payload,
1157+
.len = strlen(short_payload),
1158+
.user_data = &sem1
1159+
};
1160+
struct coap_client_request req2 = req1;
1161+
1162+
req2.user_data = &sem2;
1163+
1164+
k_sem_init(&sem1, 0, 1);
1165+
k_sem_init(&sem2, 0, 1);
1166+
1167+
z_impl_zsock_sendto_fake.custom_fake = z_impl_zsock_sendto_custom_fake_no_reply;
1168+
1169+
k_sleep(K_MSEC(1));
1170+
1171+
zassert_ok(coap_client_req(&client, 0, &address, &req1, NULL));
1172+
zassert_ok(coap_client_req(&client, 0, &address, &req2, NULL));
1173+
1174+
k_sleep(K_SECONDS(1));
1175+
1176+
coap_client_cancel_request(&client, &req1);
1177+
zassert_ok(k_sem_take(&sem1, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
1178+
zassert_not_ok(k_sem_take(&sem2, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
1179+
zassert_equal(last_response_code, -ECANCELED, "");
1180+
1181+
set_socket_events(client.fd, ZSOCK_POLLIN); /* First response is the cancelled one */
1182+
zassert_not_ok(k_sem_take(&sem1, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
1183+
set_socket_events(client.fd, ZSOCK_POLLIN);
1184+
zassert_ok(k_sem_take(&sem2, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
1185+
zassert_equal(last_response_code, COAP_RESPONSE_CODE_OK, "");
1186+
}
1187+
1188+
ZTEST(coap_client, test_cancel_match)
1189+
{
1190+
struct k_sem sem1, sem2;
1191+
struct sockaddr address = {0};
1192+
struct coap_client_request req1 = {
1193+
.method = COAP_METHOD_GET,
1194+
.confirmable = true,
1195+
.path = test_path,
1196+
.fmt = COAP_CONTENT_FORMAT_TEXT_PLAIN,
1197+
.cb = coap_callback,
1198+
.payload = short_payload,
1199+
.len = strlen(short_payload),
1200+
.user_data = &sem1
1201+
};
1202+
struct coap_client_request req2 = req1;
1203+
1204+
req2.user_data = &sem2;
1205+
req2.path = "another";
1206+
1207+
k_sem_init(&sem1, 0, 1);
1208+
k_sem_init(&sem2, 0, 1);
1209+
1210+
z_impl_zsock_sendto_fake.custom_fake = z_impl_zsock_sendto_custom_fake_no_reply;
1211+
1212+
k_sleep(K_MSEC(1));
1213+
1214+
zassert_ok(coap_client_req(&client, 0, &address, &req1, NULL));
1215+
zassert_ok(coap_client_req(&client, 0, &address, &req2, NULL));
1216+
1217+
k_sleep(K_SECONDS(1));
1218+
1219+
/* match only one */
1220+
coap_client_cancel_request(&client, &(struct coap_client_request) {
1221+
.path = test_path
1222+
});
1223+
zassert_ok(k_sem_take(&sem1, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
1224+
zassert_not_ok(k_sem_take(&sem2, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
1225+
zassert_equal(last_response_code, -ECANCELED, "");
1226+
1227+
zassert_ok(coap_client_req(&client, 0, &address, &req1, NULL));
1228+
1229+
/* should not match */
1230+
coap_client_cancel_request(&client, &(struct coap_client_request) {
1231+
.path = test_path,
1232+
.user_data = &sem2,
1233+
});
1234+
zassert_not_ok(k_sem_take(&sem1, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
1235+
zassert_not_ok(k_sem_take(&sem2, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
1236+
1237+
/* match both (all GET queries) */
1238+
coap_client_cancel_request(&client, &(struct coap_client_request) {
1239+
.method = COAP_METHOD_GET,
1240+
});
1241+
zassert_ok(k_sem_take(&sem1, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
1242+
zassert_ok(k_sem_take(&sem2, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
1243+
1244+
zassert_ok(coap_client_req(&client, 0, &address, &req1, NULL));
1245+
zassert_ok(coap_client_req(&client, 0, &address, &req2, NULL));
1246+
1247+
/* match both (wildcard)*/
1248+
coap_client_cancel_request(&client, &(struct coap_client_request) {0});
1249+
zassert_ok(k_sem_take(&sem1, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
1250+
zassert_ok(k_sem_take(&sem2, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
1251+
1252+
}

0 commit comments

Comments
 (0)