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 cpkt Packet received
* @param resources Array of known resources * @param resources Array of known resources
* @param resources_len Number of resources in the array
* @param options Parsed options from coap_packet_parse() * @param options Parsed options from coap_packet_parse()
* @param opt_num Number of options * @param opt_num Number of options
* @param addr Peer address * @param addr Peer address
* @param addr_len Peer address length * @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 -ENOTSUP in case of invalid request code.
* @retval -EPERM in case resource handler is not implemented. * @retval -EPERM in case resource handler is not implemented.
* @retval -ENOENT in case the resource is not found. * @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 * 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 \ #define COAP_WELL_KNOWN_CORE_PATH \
((const char * const[]) { ".well-known", "core", NULL }) ((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, int coap_well_known_core_get(struct coap_resource *resource,
struct coap_packet *request, const struct coap_packet *request,
struct coap_packet *response, 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 * 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); return !(code & ~COAP_REQUEST_MASK);
} }
int coap_handle_request(struct coap_packet *cpkt, int coap_handle_request_len(struct coap_packet *cpkt,
struct coap_resource *resources, struct coap_resource *resources,
struct coap_option *options, size_t resources_len,
uint8_t opt_num, struct coap_option *options,
struct sockaddr *addr, socklen_t addr_len) uint8_t opt_num,
struct sockaddr *addr, socklen_t addr_len)
{ {
struct coap_resource *resource;
if (!is_request(cpkt)) { if (!is_request(cpkt)) {
return 0; return 0;
} }
/* FIXME: deal with hierarchical resources */ /* 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; coap_method_t method;
uint8_t code; 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; continue;
} }
code = coap_header_get_code(cpkt); 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; return -ENOTSUP;
} }
@ -1177,13 +1176,29 @@ int coap_handle_request(struct coap_packet *cpkt,
return -EPERM; return -EPERM;
} }
return method(resource, cpkt, addr, addr_len); return method(&resources[i], cpkt, addr, addr_len);
} }
NET_DBG("%d", __LINE__);
return -ENOENT; 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, int coap_block_transfer_init(struct coap_block_context *ctx,
enum coap_block_size block_size, enum coap_block_size block_size,
size_t total_size) size_t total_size)

View file

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