diff --git a/include/coap3/coap_net.h b/include/coap3/coap_net.h index ce292ec3de..ebb650aa8e 100644 --- a/include/coap3/coap_net.h +++ b/include/coap3/coap_net.h @@ -37,7 +37,6 @@ #include "coap_pdu.h" #include "coap_session.h" #include "coap_debug.h" -#include "coap_resource.h" /** * @ingroup application_api @@ -608,28 +607,6 @@ 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 6646ce95f3..0c0b28547f 100644 --- a/include/coap3/coap_net_internal.h +++ b/include/coap3/coap_net_internal.h @@ -59,8 +59,6 @@ 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 30d463c560..b4661dcaa4 100644 --- a/include/coap3/coap_resource.h +++ b/include/coap3/coap_resource.h @@ -150,6 +150,13 @@ typedef void (*coap_method_handler_t)(coap_resource_t *resource, */ #define COAP_RESOURCE_FLAGS_OSCORE_ONLY 0x400 +/** + * Define this when invoking *coap_resource_unknown_init2*() if .well-known/core + * is to be passed to the unknown URI handler rather than processed locally. + * Used for easily passing on a request as a reverse-proxy request. + */ +#define COAP_RESOURCE_HANDLE_WELLKNOWN_CORE 0x800 + /** * Creates a new resource object and initializes the link field to the string * @p uri_path. This function returns the new coap_resource_t object. @@ -497,8 +504,9 @@ coap_print_status_t coap_print_link(const coap_resource_t *resource, /** * 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. + * @c COAP_PRINT_STATUS_ERROR on error. On error, the value in @p buflen is undefined. + * 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. * * @param context The context with the resource map. * @param buf The buffer to write the result. diff --git a/include/coap3/coap_resource_internal.h b/include/coap3/coap_resource_internal.h index 6bb5a49eb3..923e7cbc34 100644 --- a/include/coap3/coap_resource_internal.h +++ b/include/coap3/coap_resource_internal.h @@ -185,8 +185,11 @@ void coap_delete_attr(coap_attr_t *attr); /** * 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. + * @c COAP_PRINT_STATUS_ERROR on error. On error, the value in @p buflen is undefined. + * 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. + * + * Note: This function must be called in the locked state. * * @param context The context with the resource map. * @param buf The buffer to write the result. diff --git a/libcoap-3.map b/libcoap-3.map index 502cc2e3b4..6bb004e117 100644 --- a/libcoap-3.map +++ b/libcoap-3.map @@ -202,7 +202,6 @@ 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 efee3edd0d..71df243876 100644 --- a/libcoap-3.sym +++ b/libcoap-3.sym @@ -200,7 +200,6 @@ 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/coap_handler.txt.in b/man/coap_handler.txt.in index 0dd73b9e4d..59e95da016 100644 --- a/man/coap_handler.txt.in +++ b/man/coap_handler.txt.in @@ -16,8 +16,7 @@ coap_register_response_handler, coap_register_nack_handler, coap_register_ping_handler, coap_register_pong_handler, -coap_register_event_handler, -coap_register_print_wellknown_callback +coap_register_event_handler - Work with CoAP handlers SYNOPSIS @@ -42,9 +41,6 @@ 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*, @@ -392,39 +388,6 @@ 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 41adeba102..057119ab83 100644 --- a/man/coap_resource.txt.in +++ b/man/coap_resource.txt.in @@ -155,13 +155,22 @@ to the request handler. *COAP_RESOURCE_FLAGS_OSCORE_ONLY*:: Define this resource as an OSCORE enabled access only. +*COAP_RESOURCE_HANDLE_WELLKNOWN_CORE*:: +Define this when invoking *coap_resource_unknown_init2*() if .well-known/core +is to be passed to the unknown URI handler rather than processed locally. +Used for easily passing on a request as a reverse-proxy request. + *NOTE:* The following flags are only tested against if *coap_mcast_per_resource*() has been called. If *coap_mcast_per_resource*() has not been called, then all resources have multicast support, libcoap adds in random delays to the responses, and 4.xx / 5.xx responses are dropped. *NOTE:* The pseudo resource for ".well-known/core" always has multicast -support enabled and is not configurable. +support enabled and is not configurable. It is possible for a server to +create a resource for ".well-known/core" that can then control the +multicast support and the provided GET request handler can call +*coap_print_wellknown*() to produce the same information as the pseudo +resource. [horizontal] *COAP_RESOURCE_FLAGS_HAS_MCAST_SUPPORT*:: @@ -173,7 +182,7 @@ sending the response back to the client. It is then the responsibility of the app to delay the responses for multicast requests. See "https://rfc-editor.org/rfc/rfc7252#section-8.2[RFC7252 8.2. Request/Response Layer]". - However, the pseudo resource for ".well-known/core" always has multicast +However, the pseudo resource for ".well-known/core" always has multicast support enabled. *COAP_RESOURCE_FLAGS_LIB_ENA_MCAST_SUPPRESS_2_05*:: @@ -302,6 +311,9 @@ identified by the unique string _uri_path_ associated with _context_. 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. +Setting _offset_ to 0 means the entire (matching) information is output. +Setting _offset_ to UINT_MAX skips, but calculates the size of, the (matching) +output. The _query_filter_ is usually defined by the CoAP Uri-Query options as a query. RETURN VALUES diff --git a/src/coap_net.c b/src/coap_net.c index 7df2e21bee..f5c958a910 100644 --- a/src/coap_net.c +++ b/src/coap_net.c @@ -2713,40 +2713,6 @@ coap_new_error_response(const coap_pdu_t *request, coap_pdu_code_t code, } #if COAP_SERVER_SUPPORT -/** - * Quick hack to determine the size of the resource description for - * .well-known/core. - */ -COAP_STATIC_INLINE ssize_t -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 (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; - } - - return len; -} - #define SZX_TO_BYTES(SZX) ((size_t)(1 << ((SZX) + 4))) static void @@ -2755,40 +2721,38 @@ free_wellknown_response(coap_session_t *session COAP_UNUSED, void *app_ptr) { } /* - * Caution - this handler is being treated as if in app space. + * Caution: As this handler is in libcoap space, it is called with + * context locked. */ static void -hnd_get_wellknown(coap_resource_t *resource, - coap_session_t *session, - const coap_pdu_t *request, - const coap_string_t *query, - coap_pdu_t *response) { +hnd_get_wellknown_lkd(coap_resource_t *resource, + coap_session_t *session, + const coap_pdu_t *request, + const coap_string_t *query, + coap_pdu_t *response) { size_t len = 0; coap_string_t *data_string = NULL; - int result = 0; - ssize_t wkc_len = get_wkc_len(session->context, session, request, query); + coap_print_status_t result = 0; + size_t wkc_len = 0; + uint8_t buf[4]; - if (wkc_len) { - if (wkc_len < 0) - goto error; + /* + * Quick hack to determine the size of the resource descriptions for + * .well-known/core. + */ + result = coap_print_wellknown_lkd(session->context, buf, &wkc_len, UINT_MAX, query); + if (result & COAP_PRINT_STATUS_ERROR) { + coap_log_warn("cannot determine length of /.well-known/core\n"); + goto error; + } + + if (wkc_len > 0) { data_string = coap_new_string(wkc_len); if (!data_string) goto error; len = wkc_len; - 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); - } + result = coap_print_wellknown_lkd(session->context, data_string->s, &len, 0, query); if ((result & COAP_PRINT_STATUS_ERROR) != 0) { coap_log_debug("coap_print_wellknown failed\n"); goto error; @@ -2797,8 +2761,6 @@ hnd_get_wellknown(coap_resource_t *resource, data_string->length = len; if (!(session->block_mode & COAP_BLOCK_USE_LIBCOAP)) { - uint8_t buf[4]; - if (!coap_insert_option(response, COAP_OPTION_CONTENT_FORMAT, coap_encode_var_safe(buf, sizeof(buf), COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), buf)) { @@ -2826,6 +2788,12 @@ hnd_get_wellknown(coap_resource_t *resource, data_string)) { goto error_released; } + } else { + if (!coap_insert_option(response, COAP_OPTION_CONTENT_FORMAT, + coap_encode_var_safe(buf, sizeof(buf), + COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), buf)) { + goto error; + } } response->code = COAP_RESPONSE_CODE(205); return; @@ -3215,20 +3183,31 @@ handle_request(coap_context_t *context, coap_session_t *session, coap_pdu_t *pdu * if configured, for the unknown handler. * * if a PROXY URI/Scheme request and proxy URI handler defined, call the - * proxy URI handler + * proxy URI handler. * - * else if well-known URI generate a default response + * else if unknown URI handler defined and COAP_RESOURCE_HANDLE_WELLKNOWN_CORE + * set, call the unknown URI handler with any unknown URI (including + * .well-known/core) if the appropriate method is defined. + * + * else if well-known URI generate a default response. * * else if unknown URI handler defined, call the unknown * URI handler (to allow for potential generation of resource * [RFC7272 5.8.3]) if the appropriate method is defined. * - * else if DELETE return 2.02 (RFC7252: 5.8.4. DELETE) + * else if DELETE return 2.02 (RFC7252: 5.8.4. DELETE). * - * else return 4.04 */ + * else return 4.04. + */ if (is_proxy_uri || is_proxy_scheme) { resource = context->proxy_uri_resource; + } else if (context->unknown_resource != NULL && + context->unknown_resource->flags & COAP_RESOURCE_HANDLE_WELLKNOWN_CORE && + ((size_t)pdu->code - 1 < + (sizeof(resource->handler) / sizeof(coap_method_handler_t))) && + (context->unknown_resource->handler[pdu->code - 1])) { + resource = context->unknown_resource; } else if (coap_string_equal(uri_path, &coap_default_uri_wellknown)) { /* request for .well-known/core */ resource = &resource_uri_wellknown; @@ -3446,13 +3425,21 @@ handle_request(coap_context_t *context, coap_session_t *session, coap_pdu_t *pdu /* * Call the request handler with everything set up */ - coap_log_debug("call custom handler for resource '%*.*s' (3)\n", - (int)resource->uri_path->length, (int)resource->uri_path->length, - resource->uri_path->s); - coap_lock_callback_release(context, - h(resource, session, pdu, query, response), - /* context is being freed off */ - goto finish); + if (resource == &resource_uri_wellknown) { + /* Leave context locked */ + coap_log_debug("call handler for pseudo resource '%*.*s' (3)\n", + (int)resource->uri_path->length, (int)resource->uri_path->length, + resource->uri_path->s); + h(resource, session, pdu, query, response); + } else { + coap_log_debug("call custom handler for resource '%*.*s' (3)\n", + (int)resource->uri_path->length, (int)resource->uri_path->length, + resource->uri_path->s); + coap_lock_callback_release(context, + h(resource, session, pdu, query, response), + /* context is being freed off */ + goto finish); + } /* Check validity of response code */ if (!coap_check_code_class(session, response)) { @@ -4411,7 +4398,7 @@ coap_startup(void) { (const uint8_t *)".well-known/core" }; memset(&resource_uri_wellknown, 0, sizeof(resource_uri_wellknown)); - resource_uri_wellknown.handler[COAP_REQUEST_GET-1] = hnd_get_wellknown; + resource_uri_wellknown.handler[COAP_REQUEST_GET-1] = hnd_get_wellknown_lkd; resource_uri_wellknown.flags = COAP_RESOURCE_FLAGS_HAS_MCAST_SUPPORT; resource_uri_wellknown.uri_path = &well_known; #endif /* COAP_SERVER_SUPPORT */ @@ -4731,12 +4718,6 @@ 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 8f48c83e34..589e9d3e8d 100644 --- a/src/coap_resource.c +++ b/src/coap_resource.c @@ -101,29 +101,7 @@ match(const coap_str_const_t *text, const coap_str_const_t *pattern, memcmp(text->s, pattern->s, pattern->length) == 0; } -/** - * 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. - * @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_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) { @@ -134,6 +112,11 @@ coap_print_wellknown(coap_context_t *context, unsigned char *buf, return result; } +static coap_str_const_t coap_default_uri_wellknown = { + sizeof(COAP_DEFAULT_URI_WELLKNOWN)-1, + (const uint8_t *)COAP_DEFAULT_URI_WELLKNOWN +}; + coap_print_status_t coap_print_wellknown_lkd(coap_context_t *context, unsigned char *buf, size_t *buflen, size_t offset, @@ -161,6 +144,7 @@ coap_print_wellknown_lkd(coap_context_t *context, unsigned char *buf, }; #endif /* WITHOUT_QUERY_FILTER */ + coap_lock_check_locked(context); #ifndef WITHOUT_QUERY_FILTER /* split query filter, if any */ if (query_filter) { @@ -207,6 +191,10 @@ coap_print_wellknown_lkd(coap_context_t *context, unsigned char *buf, RESOURCES_ITER(context->resources, r) { + if (coap_string_equal(r->uri_path, &coap_default_uri_wellknown)) { + /* server app has defined a resource for .well-known/core - ignore */ + continue; + } #ifndef WITHOUT_QUERY_FILTER if (resource_param.length) { /* there is a query filter */ @@ -314,7 +302,7 @@ coap_resource_unknown_init2(coap_method_handler_t put_handler, int flags) { r->is_unknown = 1; /* Something unlikely to be used, but it shows up in the logs */ r->uri_path = coap_new_str_const(coap_unknown_resource_uri, sizeof(coap_unknown_resource_uri)-1); - r->flags = flags & COAP_RESOURCE_FLAGS_MCAST_LIST; + r->flags = flags & ~COAP_RESOURCE_FLAGS_RELEASE_URI; coap_register_handler(r, COAP_REQUEST_PUT, put_handler); } else { coap_log_debug("coap_resource_unknown_init: no memory left\n"); @@ -372,7 +360,7 @@ coap_resource_proxy_uri_init2(coap_method_handler_t handler, r->proxy_name_count = i; } } - r->flags = flags & COAP_RESOURCE_FLAGS_MCAST_LIST; + r->flags = flags & ~COAP_RESOURCE_FLAGS_RELEASE_URI; } else { coap_log_debug("coap_resource_proxy_uri_init2: no memory left\n"); }