From 7c3380827119850fec66b71f9b68f3819b385a05 Mon Sep 17 00:00:00 2001 From: Mario Kicherer Date: Wed, 29 May 2024 15:08:14 +0200 Subject: [PATCH] enable application control over .well-known/core responses --- include/coap3/coap_net.h | 23 ++++++++++++ include/coap3/coap_net_internal.h | 2 ++ include/coap3/coap_resource.h | 27 +++++++++++++++ include/coap3/coap_resource_internal.h | 30 +++++++++++++--- libcoap-3.map | 2 ++ libcoap-3.sym | 2 ++ man/Makefile.am | 1 + man/coap_handler.txt.in | 39 ++++++++++++++++++++- man/coap_resource.txt.in | 17 ++++++++- man/examples-code-check.c | 1 + src/coap_net.c | 48 ++++++++++++++++++++++---- src/coap_resource.c | 28 +++++++++------ 12 files changed, 198 insertions(+), 22 deletions(-) diff --git a/include/coap3/coap_net.h b/include/coap3/coap_net.h index ebb650aa8e..ce292ec3de 100644 --- a/include/coap3/coap_net.h +++ b/include/coap3/coap_net.h @@ -37,6 +37,7 @@ #include "coap_pdu.h" #include "coap_session.h" #include "coap_debug.h" +#include "coap_resource.h" /** * @ingroup application_api @@ -607,6 +608,28 @@ void coap_context_set_app_data(coap_context_t *context, void *data); */ void *coap_context_get_app_data(const coap_context_t *context); +/** + * Definition of get .well-known/core string callback function + */ +typedef coap_print_status_t (*coap_print_wellknown_t)(coap_context_t *context, + coap_session_t *session, + const coap_pdu_t *request, + unsigned char *buf, + size_t *buflen, + size_t offset, + const coap_string_t *query_filter); + +/** + * Defines the callback that is called when the .well-known/core resource is requested. + * + * @param context The context to associate the print_wellknown callback with + * @param callback The callback to invoke when the .well-known/core resource is requested + * or NULL to unregister a previously registered callback. + * + */ +void coap_register_print_wellknown_callback(coap_context_t *context, + coap_print_wellknown_t callback); + /**@}*/ /** diff --git a/include/coap3/coap_net_internal.h b/include/coap3/coap_net_internal.h index 0c0b28547f..6646ce95f3 100644 --- a/include/coap3/coap_net_internal.h +++ b/include/coap3/coap_net_internal.h @@ -59,6 +59,8 @@ struct coap_context_t { coap_resource_release_userdata_handler_t release_userdata; /**< function to release user_data when resource is deleted */ + coap_print_wellknown_t print_wellknown_userdata; /**< custom response for + well-known/core resource */ #endif /* COAP_SERVER_SUPPORT */ #if COAP_ASYNC_SUPPORT diff --git a/include/coap3/coap_resource.h b/include/coap3/coap_resource.h index 395fb9ef48..30d463c560 100644 --- a/include/coap3/coap_resource.h +++ b/include/coap3/coap_resource.h @@ -494,6 +494,33 @@ coap_print_status_t coap_print_link(const coap_resource_t *resource, size_t *len, size_t *offset); +/** + * Prints the names of all known resources for @p context to @p buf. This function + * sets @p buflen to the number of bytes actually written and returns + * @c 1 on success. On error, the value in @p buflen is undefined and + * the return value will be @c 0. + * + * @param context The context with the resource map. + * @param buf The buffer to write the result. + * @param buflen Must be initialized to the maximum length of @p buf and will be + * set to the length of the well-known response on return. + * @param offset The offset in bytes where the output shall start and is + * shifted accordingly with the characters that have been + * processed. This parameter is used to support the block + * option. + * @param query_filter A filter query according to Link Format + * + * @return COAP_PRINT_STATUS_ERROR on error. Otherwise, the lower 28 bits are + * set to the number of bytes that have actually been written to + * @p buf. COAP_PRINT_STATUS_TRUNC is set when the output has been + * truncated. + */ +COAP_API coap_print_status_t coap_print_wellknown(coap_context_t *context, + unsigned char *buf, + size_t *buflen, + size_t offset, + const coap_string_t *query_filter); + /** @} */ /** diff --git a/include/coap3/coap_resource_internal.h b/include/coap3/coap_resource_internal.h index 40811504b9..6bb5a49eb3 100644 --- a/include/coap3/coap_resource_internal.h +++ b/include/coap3/coap_resource_internal.h @@ -182,10 +182,32 @@ coap_resource_t *coap_get_resource_from_uri_path_lkd(coap_context_t *context, */ void coap_delete_attr(coap_attr_t *attr); -coap_print_status_t coap_print_wellknown(coap_context_t *, - unsigned char *, - size_t *, size_t, - const coap_string_t *); +/** + * Prints the names of all known resources for @p context to @p buf. This function + * sets @p buflen to the number of bytes actually written and returns + * @c 1 on success. On error, the value in @p buflen is undefined and + * the return value will be @c 0. + * + * @param context The context with the resource map. + * @param buf The buffer to write the result. + * @param buflen Must be initialized to the maximum length of @p buf and will be + * set to the length of the well-known response on return. + * @param offset The offset in bytes where the output shall start and is + * shifted accordingly with the characters that have been + * processed. This parameter is used to support the block + * option. + * @param query_filter A filter query according to Link Format + * + * @return COAP_PRINT_STATUS_ERROR on error. Otherwise, the lower 28 bits are + * set to the number of bytes that have actually been written to + * @p buf. COAP_PRINT_STATUS_TRUNC is set when the output has been + * truncated. + */ +coap_print_status_t coap_print_wellknown_lkd(coap_context_t *context, + unsigned char *buf, + size_t *buflen, + size_t offset, + const coap_string_t *query_filter); /** @} */ diff --git a/libcoap-3.map b/libcoap-3.map index c5dc03d5f2..502cc2e3b4 100644 --- a/libcoap-3.map +++ b/libcoap-3.map @@ -190,6 +190,7 @@ global: coap_print_addr; coap_print_ip_addr; coap_print_link; + coap_print_wellknown; coap_prng; coap_prng_init; coap_q_block_is_supported; @@ -201,6 +202,7 @@ global: coap_register_option; coap_register_ping_handler; coap_register_pong_handler; + coap_register_print_wellknown_callback; coap_register_request_handler; coap_register_response_handler; coap_resize_binary; diff --git a/libcoap-3.sym b/libcoap-3.sym index 348e82a43c..efee3edd0d 100644 --- a/libcoap-3.sym +++ b/libcoap-3.sym @@ -188,6 +188,7 @@ coap_persist_track_funcs coap_print_addr coap_print_ip_addr coap_print_link +coap_print_wellknown coap_prng coap_prng_init coap_q_block_is_supported @@ -199,6 +200,7 @@ coap_register_nack_handler coap_register_option coap_register_ping_handler coap_register_pong_handler +coap_register_print_wellknown_callback coap_register_request_handler coap_register_response_handler coap_resize_binary diff --git a/man/Makefile.am b/man/Makefile.am index 7c7f024cc2..6025929680 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -196,6 +196,7 @@ install-man: install-man3 install-man5 install-man7 @echo ".so man3/coap_resource.3" > coap_resource_release_userdata_handler.3 @echo ".so man3/coap_resource.3" > coap_resource_get_uri_path.3 @echo ".so man3/coap_resource.3" > coap_get_resource_from_uri_path.3 + @echo ".so man3/coap_resource.3" > coap_print_wellknown.3 @echo ".so man3/coap_session.3" > coap_session_get_addr_remote.3 @echo ".so man3/coap_session.3" > coap_session_get_context.3 @echo ".so man3/coap_session.3" > coap_session_get_ifindex.3 diff --git a/man/coap_handler.txt.in b/man/coap_handler.txt.in index 59e95da016..0dd73b9e4d 100644 --- a/man/coap_handler.txt.in +++ b/man/coap_handler.txt.in @@ -16,7 +16,8 @@ coap_register_response_handler, coap_register_nack_handler, coap_register_ping_handler, coap_register_pong_handler, -coap_register_event_handler +coap_register_event_handler, +coap_register_print_wellknown_callback - Work with CoAP handlers SYNOPSIS @@ -41,6 +42,9 @@ coap_pong_handler_t _handler_)*; *void coap_register_event_handler(coap_context_t *_context_, coap_event_handler_t _handler_)*; +*void coap_register_print_wellknown_callback(coap_context_t *context, +coap_print_wellknown_t callback);* + For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls*, @@ -388,6 +392,39 @@ typedef enum { } coap_event_t; ---- +*Function: coap_register_print_wellknown_callback()* + +The *coap_register_print_wellknown_callback*() function registers a +callback function that is called instead of the default *coap_print_wellknown*() +function when the implicit .well-known/core resource is requested. + +The callback function prototype is defined as: +[source, c] +---- +/** + * @param context The context with the resource map. + * @param session The CoAP session. + * @param buf The buffer to write the result. + * @param buflen Must be initialized to the maximum length of buf and will be + * set to the length of the well-known response on return. + * @param offset The offset in bytes where the output shall start and is shifted + * accordingly with the characters that have been processed. This + * parameter is used to support the block option. + * @param query_filter A filter query according to Link Format + * + * @return COAP_PRINT_STATUS_ERROR on error. Otherwise, the lower 28 bits are + * set to the number of bytes that have actually been written to + * @p buf. COAP_PRINT_STATUS_TRUNC is set when the output has been + * truncated. + */ +typedef coap_print_status_t (*coap_print_wellknown_t)(coap_context_t *context, + coap_session_t *session, + unsigned char *buf, + size_t *buflen, + size_t offset, + const coap_string_t *query_filter); +---- + EXAMPLES -------- *GET Resource Callback Handler* diff --git a/man/coap_resource.txt.in b/man/coap_resource.txt.in index cb881eb738..41adeba102 100644 --- a/man/coap_resource.txt.in +++ b/man/coap_resource.txt.in @@ -23,7 +23,8 @@ coap_resource_set_userdata, coap_resource_get_userdata, coap_resource_release_userdata_handler, coap_resource_get_uri_path, -coap_get_resource_from_uri_path +coap_get_resource_from_uri_path, +coap_print_wellknown - Work with CoAP resources SYNOPSIS @@ -66,6 +67,10 @@ coap_resource_release_userdata_handler_t _callback_);* *coap_resource_t *coap_get_resource_from_uri_path(coap_context_t *_context_, coap_str_const_t *_uri_path_);* +*coap_print_status_t coap_print_wellknown(coap_context_t *context, +unsigned char *buf, size_t *buflen, size_t offset, +const coap_string_t *query_filter);* + For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls*, @@ -292,6 +297,12 @@ the _resource_ definion. The *coap_get_resource_from_uri_path*() function is used to return the resource identified by the unique string _uri_path_ associated with _context_. +*Function: coap_print_wellknown()* + +The *coap_print_wellknown*() function prints the names of all known resources +of the given _context_ into _buf_ which has a maximum size of _buflen_. The +first _offset_ bytes are skipped from the output to handle block transfers. +The _query_filter_ is usually defined by the CoAP Uri-Query options as a query. RETURN VALUES ------------- @@ -312,6 +323,10 @@ there was a failure. *coap_get_resource_from_uri_path*() returns the resource or NULL if not found. +*coap_print_wellknown*() returns COAP_PRINT_STATUS_ERROR on error. Otherwise, +the lower 28 bits are set to the number of bytes that have actually been +written. COAP_PRINT_STATUS_TRUNC is set when the output has been truncated. + EXAMPLES -------- *Fixed Resources Set Up* diff --git a/man/examples-code-check.c b/man/examples-code-check.c index abf7dfb94b..ea5987dd6e 100644 --- a/man/examples-code-check.c +++ b/man/examples-code-check.c @@ -125,6 +125,7 @@ const char *number_list[] = { "coap_pdu_type_t ", "coap_mid_t ", "coap_pdu_code_t ", + "coap_print_status_t ", "coap_proto_t ", "coap_session_state_t ", "coap_session_type_t ", diff --git a/src/coap_net.c b/src/coap_net.c index 875274b278..7df2e21bee 100644 --- a/src/coap_net.c +++ b/src/coap_net.c @@ -2718,12 +2718,28 @@ coap_new_error_response(const coap_pdu_t *request, coap_pdu_code_t code, * .well-known/core. */ COAP_STATIC_INLINE ssize_t -get_wkc_len(coap_context_t *context, const coap_string_t *query_filter) { +get_wkc_len(coap_context_t *context, + coap_session_t *session, + const coap_pdu_t *request, + const coap_string_t *query_filter) { unsigned char buf[1]; size_t len = 0; + int result = 0; - if (coap_print_wellknown(context, buf, &len, UINT_MAX, query_filter) & - COAP_PRINT_STATUS_ERROR) { + if (context->print_wellknown_userdata) { + result = context->print_wellknown_userdata(context, + session, + request, + buf, + &len, + UINT_MAX, + query_filter); + } else { + coap_lock_lock(session->context, return COAP_PRINT_STATUS_ERROR); + result = coap_print_wellknown_lkd(context, buf, &len, UINT_MAX, query_filter); + coap_lock_unlock(session->context); + } + if (result & COAP_PRINT_STATUS_ERROR) { coap_log_warn("cannot determine length of /.well-known/core\n"); return -1L; } @@ -2738,6 +2754,9 @@ free_wellknown_response(coap_session_t *session COAP_UNUSED, void *app_ptr) { coap_delete_string(app_ptr); } +/* + * Caution - this handler is being treated as if in app space. + */ static void hnd_get_wellknown(coap_resource_t *resource, coap_session_t *session, @@ -2747,7 +2766,7 @@ hnd_get_wellknown(coap_resource_t *resource, size_t len = 0; coap_string_t *data_string = NULL; int result = 0; - ssize_t wkc_len = get_wkc_len(session->context, query); + ssize_t wkc_len = get_wkc_len(session->context, session, request, query); if (wkc_len) { if (wkc_len < 0) @@ -2757,8 +2776,19 @@ hnd_get_wellknown(coap_resource_t *resource, goto error; len = wkc_len; - result = coap_print_wellknown(session->context, data_string->s, &len, 0, - query); + if (session->context->print_wellknown_userdata) { + result = session->context->print_wellknown_userdata(session->context, + session, + request, + data_string->s, + &len, + 0, + query); + } else { + coap_lock_lock(session->context, goto error); + result = coap_print_wellknown_lkd(session->context, data_string->s, &len, 0, query); + coap_lock_unlock(session->context); + } if ((result & COAP_PRINT_STATUS_ERROR) != 0) { coap_log_debug("coap_print_wellknown failed\n"); goto error; @@ -4701,6 +4731,12 @@ coap_mcast_per_resource(coap_context_t *context) { context->mcast_per_resource = 1; } +void +coap_register_print_wellknown_callback(coap_context_t *context, + coap_print_wellknown_t hnd) { + context->print_wellknown_userdata = hnd; +} + #endif /* ! COAP_SERVER_SUPPORT */ #if COAP_CLIENT_SUPPORT diff --git a/src/coap_resource.c b/src/coap_resource.c index fe34acd183..8f48c83e34 100644 --- a/src/coap_resource.c +++ b/src/coap_resource.c @@ -102,12 +102,13 @@ match(const coap_str_const_t *text, const coap_str_const_t *pattern, } /** - * Prints the names of all known resources to @p buf. This function + * Prints the names of all known resources for @p context to @p buf. This function * sets @p buflen to the number of bytes actually written and returns * @c 1 on succes. On error, the value in @p buflen is undefined and * the return value will be @c 0. * * @param context The context with the resource map. + * @param session The CoAP session. * @param buf The buffer to write the result. * @param buflen Must be initialized to the maximum length of @p buf and will be * set to the length of the well-known response on return. @@ -122,16 +123,21 @@ match(const coap_str_const_t *text, const coap_str_const_t *pattern, * @p buf. COAP_PRINT_STATUS_TRUNC is set when the output has been * truncated. */ -#if defined(__GNUC__) && defined(WITHOUT_QUERY_FILTER) coap_print_status_t -coap_print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen, - size_t offset, - const coap_string_t *query_filter COAP_UNUSED) { -#else /* not a GCC */ +coap_print_wellknown(coap_context_t *context, unsigned char *buf, + size_t *buflen, size_t offset, + const coap_string_t *query_filter) { + coap_print_status_t result; + coap_lock_lock(context, return COAP_PRINT_STATUS_ERROR); + result = coap_print_wellknown_lkd(context, buf, buflen, offset, query_filter); + coap_lock_unlock(context); + return result; +} + coap_print_status_t -coap_print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen, - size_t offset, const coap_string_t *query_filter) { -#endif /* GCC */ +coap_print_wellknown_lkd(coap_context_t *context, unsigned char *buf, + size_t *buflen, size_t offset, + const coap_string_t *query_filter) { coap_print_status_t output_length = 0; unsigned char *p = buf; const uint8_t *bufend = buf + *buflen; @@ -139,7 +145,9 @@ coap_print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen coap_print_status_t result; const size_t old_offset = offset; int subsequent_resource = 0; -#ifndef WITHOUT_QUERY_FILTER +#ifdef WITHOUT_QUERY_FILTER + (void)query_filter; +#else coap_str_const_t resource_param = { 0, NULL }, query_pattern = { 0, NULL }; int flags = 0; /* MATCH_SUBSTRING, MATCH_PREFIX, MATCH_URI */ #define MATCH_URI 0x01