net: lib: coap: Add resources length based variants

Add length variant for the well known core resource and parsing.

Signed-off-by: Pieter De Gendt <pieter.degendt@basalte.be>
This commit is contained in:
Pieter De Gendt 2023-09-25 22:05:54 +02:00 committed by Carles Cufí
parent 1158c5dc01
commit bea29cf631
4 changed files with 141 additions and 45 deletions

View file

@ -583,12 +583,36 @@ int coap_packet_append_payload(struct coap_packet *cpkt, const uint8_t *payload,
*
* @param cpkt Packet received
* @param resources Array of known resources
* @param resources_len Number of resources in the array
* @param options Parsed options from coap_packet_parse()
* @param opt_num Number of options
* @param addr Peer address
* @param addr_len Peer address length
*
* @retval 0 in case of success.
* @retval >= 0 in case of success.
* @retval -ENOTSUP in case of invalid request code.
* @retval -EPERM in case resource handler is not implemented.
* @retval -ENOENT in case the resource is not found.
*/
int coap_handle_request_len(struct coap_packet *cpkt,
struct coap_resource *resources,
size_t resources_len,
struct coap_option *options,
uint8_t opt_num,
struct sockaddr *addr, socklen_t addr_len);
/**
* @brief When a request is received, call the appropriate methods of
* the matching resources.
*
* @param cpkt Packet received
* @param resources Array of known resources (terminated with empty resource)
* @param options Parsed options from coap_packet_parse()
* @param opt_num Number of options
* @param addr Peer address
* @param addr_len Peer address length
*
* @retval >= 0 in case of success.
* @retval -ENOTSUP in case of invalid request code.
* @retval -EPERM in case resource handler is not implemented.
* @retval -ENOENT in case the resource is not found.

View file

@ -24,15 +24,45 @@ extern "C" {
/**
* This resource should be added before all other resources that should be
* included in the responses of the .well-known/core resource.
* included in the responses of the .well-known/core resource if is to be used with
* coap_well_known_core_get.
*/
#define COAP_WELL_KNOWN_CORE_PATH \
((const char * const[]) { ".well-known", "core", NULL })
/**
* @brief Build a CoAP response for a .well-known/core CoAP request.
*
* @param resource Array of known resources, terminated with an empty resource
* @param request A pointer to the .well-known/core CoAP request
* @param response A pointer to a CoAP response, will be initialized
* @param data A data pointer to be used to build the CoAP response
* @param data_len The maximum length of the data buffer
*
* @return 0 in case of success or negative in case of error.
*/
int coap_well_known_core_get(struct coap_resource *resource,
struct coap_packet *request,
const struct coap_packet *request,
struct coap_packet *response,
uint8_t *data, uint16_t len);
uint8_t *data, uint16_t data_len);
/**
* @brief Build a CoAP response for a .well-known/core CoAP request.
*
* @param resources Array of known resources
* @param resources_len Number of resources in the array
* @param request A pointer to the .well-known/core CoAP request
* @param response A pointer to a CoAP response, will be initialized
* @param data A data pointer to be used to build the CoAP response
* @param data_len The maximum length of the data buffer
*
* @return 0 in case of success or negative in case of error.
*/
int coap_well_known_core_get_len(struct coap_resource *resources,
size_t resources_len,
const struct coap_packet *request,
struct coap_packet *response,
uint8_t *data, uint16_t data_len);
/**
* In case you want to add attributes to the resources included in the

View file

@ -1147,29 +1147,28 @@ static bool is_request(const struct coap_packet *cpkt)
return !(code & ~COAP_REQUEST_MASK);
}
int coap_handle_request(struct coap_packet *cpkt,
struct coap_resource *resources,
struct coap_option *options,
uint8_t opt_num,
struct sockaddr *addr, socklen_t addr_len)
int coap_handle_request_len(struct coap_packet *cpkt,
struct coap_resource *resources,
size_t resources_len,
struct coap_option *options,
uint8_t opt_num,
struct sockaddr *addr, socklen_t addr_len)
{
struct coap_resource *resource;
if (!is_request(cpkt)) {
return 0;
}
/* FIXME: deal with hierarchical resources */
for (resource = resources; resource && resource->path; resource++) {
for (size_t i = 0; i < resources_len; i++) {
coap_method_t method;
uint8_t code;
if (!uri_path_eq(cpkt, resource->path, options, opt_num)) {
if (!uri_path_eq(cpkt, resources[i].path, options, opt_num)) {
continue;
}
code = coap_header_get_code(cpkt);
if (method_from_code(resource, code, &method) < 0) {
if (method_from_code(&resources[i], code, &method) < 0) {
return -ENOTSUP;
}
@ -1177,13 +1176,29 @@ int coap_handle_request(struct coap_packet *cpkt,
return -EPERM;
}
return method(resource, cpkt, addr, addr_len);
return method(&resources[i], cpkt, addr, addr_len);
}
NET_DBG("%d", __LINE__);
return -ENOENT;
}
int coap_handle_request(struct coap_packet *cpkt,
struct coap_resource *resources,
struct coap_option *options,
uint8_t opt_num,
struct sockaddr *addr, socklen_t addr_len)
{
size_t resources_len = 0;
struct coap_resource *resource;
for (resource = resources; resource && resource->path; resource++) {
resources_len++;
}
return coap_handle_request_len(cpkt, resources, resources_len, options, opt_num, addr,
addr_len);
}
int coap_block_transfer_init(struct coap_block_context *ctx,
enum coap_block_size block_size,
size_t total_size)

View file

@ -432,10 +432,11 @@ int clear_more_flag(struct coap_packet *cpkt)
return 0;
}
int coap_well_known_core_get(struct coap_resource *resource,
struct coap_packet *request,
struct coap_packet *response,
uint8_t *data, uint16_t len)
int coap_well_known_core_get_len(struct coap_resource *resources,
size_t resources_len,
struct coap_packet *request,
struct coap_packet *response,
uint8_t *data, uint16_t len)
{
static struct coap_block_context ctx;
struct coap_option query;
@ -446,9 +447,9 @@ int coap_well_known_core_get(struct coap_resource *resource,
uint16_t id;
uint8_t tkl;
int r;
bool more = false;
bool more = false, first = true;
if (!resource || !request || !response || !data || !len) {
if (!resources || !request || !response || !data || !len) {
return -EINVAL;
}
@ -505,29 +506,31 @@ int coap_well_known_core_get(struct coap_resource *resource,
offset = 0;
remaining = coap_block_size_to_bytes(ctx.block_size);
while (resource++ && resource->path) {
for (size_t i = 0; i < resources_len; ++i) {
if (!remaining) {
more = true;
break;
}
if (!match_queries_resource(resource, &query, num_queries)) {
if (!match_queries_resource(&resources[i], &query, num_queries)) {
continue;
}
r = format_resource(resource, response, &remaining, &offset,
ctx.current, &more);
if (r < 0) {
goto end;
}
if ((resource + 1) && (resource + 1)->path) {
if (first) {
first = false;
} else {
r = append_to_coap_pkt(response, ",", 1, &remaining,
&offset, ctx.current);
if (!r) {
goto end;
}
}
r = format_resource(&resources[i], response, &remaining, &offset,
ctx.current, &more);
if (r < 0) {
goto end;
}
}
/* Offset is the total size now, but block2 option is already
@ -631,10 +634,11 @@ static int format_resource(const struct coap_resource *resource,
return format_attributes(attributes, response);
}
int coap_well_known_core_get(struct coap_resource *resource,
struct coap_packet *request,
struct coap_packet *response,
uint8_t *data, uint16_t len)
int coap_well_known_core_get_len(struct coap_resource *resources,
size_t resources_len,
const struct coap_packet *request,
struct coap_packet *response,
uint8_t *data, uint16_t data_len)
{
struct coap_option query;
uint8_t token[COAP_TOKEN_MAX_LEN];
@ -642,8 +646,9 @@ int coap_well_known_core_get(struct coap_resource *resource,
uint8_t tkl;
uint8_t num_queries;
int r;
bool first = true;
if (!resource || !request || !response || !data || !len) {
if (!resources || !request || !response || !data || !data_len) {
return -EINVAL;
}
@ -660,7 +665,7 @@ int coap_well_known_core_get(struct coap_resource *resource,
num_queries = r;
r = coap_packet_init(response, data, len, COAP_VERSION_1, COAP_TYPE_ACK,
r = coap_packet_init(response, data, data_len, COAP_VERSION_1, COAP_TYPE_ACK,
tkl, token, COAP_RESPONSE_CODE_CONTENT, id);
if (r < 0) {
return r;
@ -677,28 +682,50 @@ int coap_well_known_core_get(struct coap_resource *resource,
return -EINVAL;
}
while (resource++ && resource->path) {
if (!match_queries_resource(resource, &query, num_queries)) {
for (size_t i = 0; i < resources_len; ++i) {
if (!match_queries_resource(&resources[i], &query, num_queries)) {
continue;
}
r = format_resource(resource, response);
if (r < 0) {
return r;
}
if ((resource + 1)->path) {
if (first) {
first = false;
} else {
r = append_u8(response, (uint8_t) ',');
if (!r) {
return -ENOMEM;
}
}
r = format_resource(&resources[i], response);
if (r < 0) {
return r;
}
}
return 0;
}
#endif
int coap_well_known_core_get(struct coap_resource *resource,
const struct coap_packet *request,
struct coap_packet *response,
uint8_t *data, uint16_t data_len)
{
struct coap_resource *resources = resource + 1;
size_t resources_len = 0;
if (resource == NULL) {
return -EINVAL;
}
while (resources[resources_len].path) {
resources_len++;
}
return coap_well_known_core_get_len(resources, resources_len, request, response, data,
data_len);
}
/* Exposing some of the APIs to CoAP unit tests in tests/net/lib/coap */
#if defined(CONFIG_COAP_TEST_API_ENABLE)
bool _coap_match_path_uri(const char * const *path,