net: coap_client: Use buffers instead of pointers for path and options
Use buffers instead of pointers for path and extra options provided in
the struct coap_client_request, so that the library keeps a copy of the
path/options instead of pointers. That way, the library can still work
correctly in case of retransmissions or block transfer in case when the
original path or options were automatic variables that went out of
context.
Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
diff --git a/doc/connectivity/networking/api/coap_client.rst b/doc/connectivity/networking/api/coap_client.rst
index d345f5a..ae90eac 100644
--- a/doc/connectivity/networking/api/coap_client.rst
+++ b/doc/connectivity/networking/api/coap_client.rst
@@ -31,7 +31,7 @@
req.method = COAP_METHOD_GET;
req.confirmable = true;
- req.path = "test";
+ strcpy(req.path, "test");
req.fmt = COAP_CONTENT_FORMAT_TEXT_PLAIN;
req.cb = response_cb;
req.payload = NULL;
@@ -88,18 +88,14 @@
static struct coap_client;
struct coap_client_request req = { 0 };
- /* static, since options must remain valid throughout the whole execution of the request */
- static struct coap_client_option block2_option;
-
coap_client_init(&client, NULL);
- block2_option = coap_client_option_initial_block2();
req.method = COAP_METHOD_GET;
req.confirmable = true;
- req.path = "test";
+ strcpy(req.path, "test");
req.fmt = COAP_CONTENT_FORMAT_TEXT_PLAIN;
req.cb = response_cb;
- req.options = &block2_option;
+ req.options[0] = coap_client_option_initial_block2();
req.num_options = 1;
req.payload = NULL;
req.len = 0;
@@ -144,7 +140,7 @@
req.method = COAP_METHOD_PUT;
req.confirmable = true;
- req.path = "lorem-ipsum";
+ strcpy(req.path, "lorem-ipsum");
req.fmt = COAP_CONTENT_FORMAT_TEXT_PLAIN;
req.cb = response_cb;
req.payload_cb = lore_ipsum_cb,
diff --git a/include/zephyr/net/coap_client.h b/include/zephyr/net/coap_client.h
index 16cc7da..b3065f6 100644
--- a/include/zephyr/net/coap_client.h
+++ b/include/zephyr/net/coap_client.h
@@ -100,23 +100,6 @@
void *user_data);
/**
- * @brief Representation of a CoAP client request.
- */
-struct coap_client_request {
- enum coap_method method; /**< Method of the request */
- bool confirmable; /**< CoAP Confirmable/Non-confirmable message */
- const char *path; /**< Path of the requested resource */
- enum coap_content_format fmt; /**< Content format to be used */
- const uint8_t *payload; /**< User allocated buffer for send request */
- size_t len; /**< Length of the payload */
- coap_client_payload_cb_t payload_cb; /**< Optional payload callback */
- coap_client_response_cb_t cb; /**< Callback when response received */
- const struct coap_client_option *options; /**< Extra options to be added to request */
- uint8_t num_options; /**< Number of extra options */
- void *user_data; /**< User provided context */
-};
-
-/**
* @brief Representation of extra options for the CoAP client request
*/
struct coap_client_option {
@@ -136,6 +119,29 @@
};
/** @cond INTERNAL_HIDDEN */
+#define MAX_PATH_SIZE (CONFIG_COAP_CLIENT_MAX_PATH_LENGTH + 1)
+#define MAX_EXTRA_OPTIONS CONFIG_COAP_CLIENT_MAX_EXTRA_OPTIONS
+/** @endcond */
+
+/**
+ * @brief Representation of a CoAP client request.
+ */
+struct coap_client_request {
+ enum coap_method method; /**< Method of the request */
+ bool confirmable; /**< CoAP Confirmable/Non-confirmable message */
+ char path[MAX_PATH_SIZE]; /**< Path of the requested resource */
+ enum coap_content_format fmt; /**< Content format to be used */
+ const uint8_t *payload; /**< User allocated buffer for send request */
+ size_t len; /**< Length of the payload */
+ coap_client_payload_cb_t payload_cb; /**< Optional payload callback */
+ coap_client_response_cb_t cb; /**< Callback when response received */
+ struct coap_client_option
+ options[MAX_EXTRA_OPTIONS]; /**< Extra options to be added to request */
+ uint8_t num_options; /**< Number of extra options */
+ void *user_data; /**< User provided context */
+};
+
+/** @cond INTERNAL_HIDDEN */
struct coap_client_internal_request {
uint8_t request_token[COAP_TOKEN_MAX_LEN];
uint32_t offset;
diff --git a/samples/net/sockets/coap_download/src/main.c b/samples/net/sockets/coap_download/src/main.c
index 1ce4ad1..73345d4 100644
--- a/samples/net/sockets/coap_download/src/main.c
+++ b/samples/net/sockets/coap_download/src/main.c
@@ -59,7 +59,7 @@
.payload = NULL,
.len = 0,
.cb = on_coap_response,
- .options = NULL,
+ .options = { },
.num_options = 0,
.user_data = NULL};
diff --git a/subsys/net/lib/coap/Kconfig b/subsys/net/lib/coap/Kconfig
index 3dce7fd..4224b7a 100644
--- a/subsys/net/lib/coap/Kconfig
+++ b/subsys/net/lib/coap/Kconfig
@@ -136,6 +136,16 @@
help
Extra room allocated to handle CoAP header data
+config COAP_CLIENT_MAX_PATH_LENGTH
+ int "Maximum length of the path string"
+ default 64
+ range 1 128
+
+config COAP_CLIENT_MAX_EXTRA_OPTIONS
+ int "Maximum number of application-provided extra CoAP options"
+ default 2
+ range 1 16
+
config COAP_CLIENT_STACK_SIZE
int "Stack size of the CoAP client thread"
default 1024
diff --git a/subsys/net/lib/coap/coap_client.c b/subsys/net/lib/coap/coap_client.c
index 2c1df8c..cdd20a8 100644
--- a/subsys/net/lib/coap/coap_client.c
+++ b/subsys/net/lib/coap/coap_client.c
@@ -4,6 +4,9 @@
* SPDX-License-Identifier: Apache-2.0
*/
+#undef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 200809L /* Required for strnlen() */
+
#include <string.h>
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(net_coap, CONFIG_COAP_LOG_LEVEL);
@@ -416,8 +419,10 @@
{
int ret;
struct coap_client_internal_request *internal_req;
+ size_t pathlen = strnlen(req->path, MAX_PATH_SIZE);
- if (client == NULL || sock < 0 || req == NULL || req->path == NULL) {
+ if (client == NULL || sock < 0 || req == NULL || pathlen == 0 ||
+ pathlen == MAX_PATH_SIZE || req->num_options > MAX_EXTRA_OPTIONS) {
return -EINVAL;
}
@@ -1138,7 +1143,7 @@
if (a->method && b->method && a->method != b->method) {
return false;
}
- if (a->path && b->path && strcmp(a->path, b->path) != 0) {
+ if (a->path[0] != '\0' && b->path[0] != '\0' && strcmp(a->path, b->path) != 0) {
return false;
}
if (a->cb && b->cb && a->cb != b->cb) {
diff --git a/tests/net/lib/coap_client/CMakeLists.txt b/tests/net/lib/coap_client/CMakeLists.txt
index 9ed7926..88f1b99 100644
--- a/tests/net/lib/coap_client/CMakeLists.txt
+++ b/tests/net/lib/coap_client/CMakeLists.txt
@@ -23,6 +23,8 @@
add_compile_definitions(CONFIG_COAP_CLIENT_BLOCK_SIZE=256)
add_compile_definitions(CONFIG_COAP_CLIENT_MESSAGE_SIZE=256)
add_compile_definitions(CONFIG_COAP_CLIENT_MESSAGE_HEADER_SIZE=48)
+add_compile_definitions(CONFIG_COAP_CLIENT_MAX_PATH_LENGTH=32)
+add_compile_definitions(CONFIG_COAP_CLIENT_MAX_EXTRA_OPTIONS=2)
add_compile_definitions(CONFIG_COAP_CLIENT_STACK_SIZE=1024)
add_compile_definitions(CONFIG_COAP_CLIENT_THREAD_PRIORITY=10)
add_compile_definitions(CONFIG_COAP_LOG_LEVEL=4)
diff --git a/tests/net/lib/coap_client/src/main.c b/tests/net/lib/coap_client/src/main.c
index 273504a..2efd567 100644
--- a/tests/net/lib/coap_client/src/main.c
+++ b/tests/net/lib/coap_client/src/main.c
@@ -26,11 +26,11 @@
#define COAP_SEPARATE_TIMEOUT (6000 * 2) /* Needs a safety marging, tests run faster than -rt */
#define VALID_MESSAGE_ID BIT(31)
#define TOKEN_OFFSET 4
+#define TEST_PATH "test"
void coap_callback(const struct coap_client_response_data *data, void *user_data);
static int16_t last_response_code;
-static const char test_path[] = "test";
static uint32_t messages_needing_response[2];
static uint8_t last_token[2][COAP_TOKEN_MAX_LEN];
@@ -48,7 +48,7 @@
static struct coap_client_request short_request = {
.method = COAP_METHOD_GET,
.confirmable = true,
- .path = test_path,
+ .path = TEST_PATH,
.fmt = COAP_CONTENT_FORMAT_TEXT_PLAIN,
.cb = coap_callback,
.payload = short_payload,
@@ -58,7 +58,7 @@
static struct coap_client_request long_request = {
.method = COAP_METHOD_GET,
.confirmable = true,
- .path = test_path,
+ .path = TEST_PATH,
.fmt = COAP_CONTENT_FORMAT_TEXT_PLAIN,
.cb = coap_callback,
.payload = long_payload,
@@ -586,7 +586,7 @@
{
struct coap_client_request req = short_request;
- req.path = NULL;
+ req.path[0] = '\0';
zassert_equal(coap_client_req(&client, 0, &dst_address, &req, NULL), -EINVAL, "");
}
@@ -780,20 +780,19 @@
ZTEST(coap_client, test_observe)
{
- struct coap_client_option options = {
- .code = COAP_OPTION_OBSERVE,
- .value[0] = 0,
- .len = 1,
- };
struct coap_client_request req = {
.method = COAP_METHOD_GET,
.confirmable = true,
- .path = test_path,
+ .path = TEST_PATH,
.fmt = COAP_CONTENT_FORMAT_TEXT_PLAIN,
.cb = coap_callback,
.payload = short_payload,
.len = strlen(short_payload),
- .options = &options,
+ .options = { {
+ .code = COAP_OPTION_OBSERVE,
+ .value[0] = 0,
+ .len = 1,
+ } },
.num_options = 1,
.user_data = &sem1,
};
@@ -858,7 +857,7 @@
req1.user_data = &sem1;
req2.user_data = &sem2;
- req2.path = "another";
+ strcpy(req2.path, "another");
z_impl_zsock_sendto_fake.custom_fake = z_impl_zsock_sendto_custom_fake_no_reply;
@@ -869,7 +868,7 @@
/* match only one */
coap_client_cancel_request(&client, &(struct coap_client_request) {
- .path = test_path
+ .path = TEST_PATH
});
zassert_ok(k_sem_take(&sem1, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
zassert_not_ok(k_sem_take(&sem2, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
@@ -879,7 +878,7 @@
/* should not match */
coap_client_cancel_request(&client, &(struct coap_client_request) {
- .path = test_path,
+ .path = TEST_PATH,
.user_data = &sem2,
});
zassert_not_ok(k_sem_take(&sem1, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
@@ -907,7 +906,7 @@
struct coap_client_request req = {
.method = COAP_METHOD_GET,
.confirmable = false,
- .path = test_path,
+ .path = TEST_PATH,
.fmt = COAP_CONTENT_FORMAT_TEXT_PLAIN,
.cb = coap_callback,
.payload = short_payload,