/*
 * resource.h -- generic resource handling
 *
 * Copyright (C) 2010,2011,2014-2022 Olaf Bergmann <bergmann@tzi.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 *
 * This file is part of the CoAP library libcoap. Please see README for terms
 * of use.
 */

/**
 * @file resource.h
 * @brief Generic resource handling
 */

#ifndef COAP_RESOURCE_H_
#define COAP_RESOURCE_H_

#ifndef COAP_RESOURCE_CHECK_TIME
/** The interval in seconds to check if resources have changed. */
#define COAP_RESOURCE_CHECK_TIME 2
#endif /* COAP_RESOURCE_CHECK_TIME */

#include "coap_async.h"
#include "block.h"
#include "str.h"
#include "pdu.h"
#include "net.h"
#include "coap_subscribe.h"

/**
 * @ingroup application_api
 * @defgroup coap_resource Resource Configuraton
 * API for setting up resources
 * @{
 */

/**
 * Definition of message handler function
 */
typedef void (*coap_method_handler_t)
  (coap_resource_t *,
   coap_session_t *,
   const coap_pdu_t * /* request */,
   const coap_string_t * /* query string */,
   coap_pdu_t * /* response */);

#define COAP_ATTR_FLAGS_RELEASE_NAME  0x1
#define COAP_ATTR_FLAGS_RELEASE_VALUE 0x2

/** The URI passed to coap_resource_init() is free'd by coap_delete_resource(). */
#define COAP_RESOURCE_FLAGS_RELEASE_URI 0x1

/**
 * Observe Notifications will be sent non-confirmable by default. RFC 7641
 * Section 4.5
 * https://tools.ietf.org/html/rfc7641#section-4.5
 * Libcoap will always send every fifth packet as confirmable.
 */
#define COAP_RESOURCE_FLAGS_NOTIFY_NON  0x0

/**
 * Observe Notifications will be sent confirmable. RFC 7641 Section 4.5
 * https://tools.ietf.org/html/rfc7641#section-4.5
 */
#define COAP_RESOURCE_FLAGS_NOTIFY_CON  0x2

/**
 * Observe Notifications will always be sent non-confirmable. This is in
 * violation of RFC 7641 Section 4.5
 * https://tools.ietf.org/html/rfc7641#section-4.5
 * but required by the DOTS signal channel protocol which needs to operate in
 * lossy DDoS attack environments.
 * https://tools.ietf.org/html/rfc8782#section-4.4.2.1
 */
#define COAP_RESOURCE_FLAGS_NOTIFY_NON_ALWAYS  0x4

/**
 * This resource has support for multicast requests.
 * https://datatracker.ietf.org/doc/html/rfc7252#section-11.3
 * https://datatracker.ietf.org/doc/html/rfc7390#section-2.8
 * https://datatracker.ietf.org/doc/html/draft-ietf-core-groupcomm-bis-06.txt#section-3.6
 * Note: ".well-known/core" always supports multicast.
 * Note: Only tested if coap_mcast_per_resource() has been called.
 */
#define COAP_RESOURCE_FLAGS_HAS_MCAST_SUPPORT 0x8

/**
 * Disable libcoap library from adding in delays to multicast requests before
 * releasing the response back to the client.  It is then the responsibility of
 * the app to delay the responses for multicast requests.
 * https://datatracker.ietf.org/doc/html/rfc7252#section-8.2
 * https://datatracker.ietf.org/doc/html/rfc7390#section-2.8
 * https://datatracker.ietf.org/doc/html/draft-ietf-core-groupcomm-bis-06.txt#section-3.6
 * Note: Only tested if coap_mcast_per_resource() has been called.
 */
#define COAP_RESOURCE_FLAGS_LIB_DIS_MCAST_DELAYS 0x10

/**
 * Enable libcoap library suppression of 205 multicast responses that are empty
 * (overridden by RFC7969 No-Response option) for multicast requests.
 * https://datatracker.ietf.org/doc/html/rfc7390#section-2.7
 * https://datatracker.ietf.org/doc/html/draft-ietf-core-groupcomm-bis-06.txt#section-3.1.2
 * Note: Only tested if coap_mcast_per_resource() has been called.
 */
#define COAP_RESOURCE_FLAGS_LIB_ENA_MCAST_SUPPRESS_2_05 0x20

/**
 * Enable libcoap library suppressing 2.xx multicast responses (overridden by
 * RFC7969 No-Response option) for multicast requests.
 * https://datatracker.ietf.org/doc/html/rfc7390#section-2.7
 * https://datatracker.ietf.org/doc/html/draft-ietf-core-groupcomm-bis-06.txt#section-3.1.2
 * Note: Only tested if coap_mcast_per_resource() has been called.
 */
#define COAP_RESOURCE_FLAGS_LIB_ENA_MCAST_SUPPRESS_2_XX 0x40

/**
 * Disable libcoap library suppressing 4.xx multicast responses (overridden by
 * RFC7969 No-Response option) for multicast requests.
 * https://datatracker.ietf.org/doc/html/rfc7390#section-2.7
 * https://datatracker.ietf.org/doc/html/draft-ietf-core-groupcomm-bis-06.txt#section-3.1.2
 * Note: Only tested if coap_mcast_per_resource() has been called.
 */
#define COAP_RESOURCE_FLAGS_LIB_DIS_MCAST_SUPPRESS_4_XX 0x80

/**
 * Disable libcoap library suppressing 5.xx multicast responses (overridden by
 * RFC7969 No-Response option) for multicast requests.
 * https://datatracker.ietf.org/doc/html/rfc7390#section-2.7
 * https://datatracker.ietf.org/doc/html/draft-ietf-core-groupcomm-bis-06.txt#section-3.1.2
 * Note: Only tested if coap_mcast_per_resource() has been called.
 */
#define COAP_RESOURCE_FLAGS_LIB_DIS_MCAST_SUPPRESS_5_XX 0x100

#define COAP_RESOURCE_FLAGS_MCAST_LIST \
  (COAP_RESOURCE_FLAGS_HAS_MCAST_SUPPORT | \
   COAP_RESOURCE_FLAGS_LIB_DIS_MCAST_DELAYS | \
   COAP_RESOURCE_FLAGS_LIB_ENA_MCAST_SUPPRESS_2_05 | \
   COAP_RESOURCE_FLAGS_LIB_ENA_MCAST_SUPPRESS_2_XX | \
   COAP_RESOURCE_FLAGS_LIB_DIS_MCAST_SUPPRESS_4_XX | \
   COAP_RESOURCE_FLAGS_LIB_DIS_MCAST_SUPPRESS_5_XX)

/**
 * 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.
 *
 * If the string is going to be freed off by coap_delete_resource() when
 * COAP_RESOURCE_FLAGS_RELEASE_URI is set in @p flags, then either the 's'
 * variable of coap_str_const_t has to point to constant text, or point to data
 * within the allocated coap_str_const_t parameter.
 *
 * @param uri_path The string URI path of the new resource. The leading '/' is
 *                 not normally required - e.g. just "full/path/for/resource".
 * @param flags    Flags for memory management, observe handling and multicast
 *                 support, comprising of zero or more COAP_RESOURCE_FLAGS_*
 *                 ored together.
 *                 If flags is set to 0 then the
 *                 COAP_RESOURCE_FLAGS_NOTIFY_NON is assumed.
 *
 * @return         A pointer to the new object or @c NULL on error.
 */
coap_resource_t *coap_resource_init(coap_str_const_t *uri_path,
                                    int flags);

/**
 * Creates a new resource object for the unknown resource handler with support
 * for PUT.
 *
 * In the same way that additional handlers can be added to the resource
 * created by coap_resource_init() by using coap_register_handler(), POST,
 * GET, DELETE etc. handlers can be added to this resource. It is the
 * responsibility of the application to manage the unknown resources by either
 * creating new resources with coap_resource_init() (which should have a
 * DELETE handler specified for the resource removal) or by maintaining an
 * active resource list.
 *
 * Note: There can only be one unknown resource handler per context - attaching
 *       a new one overrides the previous definition.
 *
 * Note: It is not possible to observe the unknown resource with a GET request
 *       - a separate resource needs to be created by the PUT (or POST)
 *       handler, and make that resource observable.
 *
 * This function returns the new coap_resource_t object.
 *
 * @param put_handler The PUT handler to register with @p resource for
 *                    unknown Uri-Path.
 *
 * @return       A pointer to the new object or @c NULL on error.
 */
coap_resource_t *coap_resource_unknown_init(coap_method_handler_t put_handler);

/**
 * Creates a new resource object for the unknown resource handler with support
 * for PUT and configurable control over multicast requests packets.
 *
 * In the same way that additional handlers can be added to the resource
 * created by coap_resource_init() by using coap_register_handler(), POST,
 * GET, DELETE etc. handlers can be added to this resource. It is the
 * responsibility of the application to manage the unknown resources by either
 * creating new resources with coap_resource_init() (which should have a
 * DELETE handler specified for the resource removal) or by maintaining an
 * active resource list.
 *
 * Note: There can only be one unknown resource handler per context - attaching
 *       a new one overrides the previous definition.
 *
 * Note: It is not possible to observe the unknown resource with a GET request
 *       - a separate resource needs to be created by the PUT (or POST)
 *       handler, and make that resource observable.
 *
 * This function returns the new coap_resource_t object.
 *
 * @param put_handler The PUT handler to register with @p resource for
 *                    unknown Uri-Path.
 * @param flags Zero or more COAP_RESOURCE_FLAGS_*MCAST* ored together to
 *              indicate what to do with multicast packets.
 *
 * @return       A pointer to the new object or @c NULL on error.
 */
coap_resource_t *coap_resource_unknown_init2(coap_method_handler_t put_handler,
                                             int flags);

/**
 * Creates a new resource object for handling proxy URIs.
 * This function returns the new coap_resource_t object.
 *
 * Note: There can only be one proxy resource handler per context - attaching
 *       a new one overrides the previous definition.
 *
 * @param handler The PUT/POST/GET etc. handler that handles all request types.
 * @param host_name_count The number of provided host_name_list entries. A
 *                        minimum of 1 must be provided.
 * @param host_name_list Array of depth host_name_count names that this proxy
 *                       is known by.
 *
 * @return         A pointer to the new object or @c NULL on error.
 */
coap_resource_t *coap_resource_proxy_uri_init(coap_method_handler_t handler,
                      size_t host_name_count, const char *host_name_list[]);

/**
 * Creates a new resource object for handling proxy URIs with configurable
 * control over multicast request packets.
 * This function returns the new coap_resource_t object.
 *
 * Note: There can only be one proxy resource handler per context - attaching
 *       a new one overrides the previous definition.
 *
 * @param handler The PUT/POST/GET etc. handler that handles all request types.
 * @param host_name_count The number of provided host_name_list entries. A
 *                        minimum of 1 must be provided.
 * @param host_name_list Array of depth host_name_count names that this proxy
 *                       is known by.
 * @param flags Zero or more COAP_RESOURCE_FLAGS_*MCAST* ored together to
 *              indicate what to do with multicast packets.
 *
 * @return         A pointer to the new object or @c NULL on error.
 */
coap_resource_t *coap_resource_proxy_uri_init2(coap_method_handler_t handler,
                                              size_t host_name_count,
                                              const char *host_name_list[],
                                              int flags);

/**
 * Returns the resource identified by the unique string @p uri_path. If no
 * resource was found, this function returns @c NULL.
 *
 * @param context  The context to look for this resource.
 * @param uri_path  The unique string uri of the resource.
 *
 * @return         A pointer to the resource or @c NULL if not found.
 */
coap_resource_t *coap_get_resource_from_uri_path(coap_context_t *context,
                                                coap_str_const_t *uri_path);

/**
 * Get the uri_path from a @p resource.
 *
 * @param resource The CoAP resource to check.
 *
 * @return         The uri_path if it exists or @c NULL otherwise.
 */
coap_str_const_t* coap_resource_get_uri_path(coap_resource_t *resource);

/**
 * Sets the notification message type of resource @p resource to given
 * @p mode

 * @param resource The resource to update.
 * @param mode     Must be one of @c COAP_RESOURCE_FLAGS_NOTIFY_NON
 *                 or @c COAP_RESOURCE_FLAGS_NOTIFY_CON.
 */
void coap_resource_set_mode(coap_resource_t *resource, int mode);

/**
 * Sets the user_data. The user_data is exclusively used by the library-user
 * and can be used as user defined context in the handler functions.
 *
 * @param resource Resource to attach the data to
 * @param data     Data to attach to the user_data field. This pointer is
 *                 only used for storage, the data remains under user control
 */
void coap_resource_set_userdata(coap_resource_t *resource, void *data);

/**
 * Gets the user_data. The user_data is exclusively used by the library-user
 * and can be used as context in the handler functions.
 *
 * @param resource Resource to retrieve the user_data from
 *
 * @return        The user_data pointer
 */
void *coap_resource_get_userdata(coap_resource_t *resource);

/**
 * Definition of release resource user_data callback function
 */
typedef void (*coap_resource_release_userdata_handler_t)(void *user_data);

/**
 * Defines the context wide callback to use to when the resource is deleted
 * to release the data held in the resource's user_data.
 *
 * @param context  The context to associate the release callback with
 * @param callback The callback to invoke when the resource is deleted or NULL
 *
 */
void coap_resource_release_userdata_handler(coap_context_t *context,
                          coap_resource_release_userdata_handler_t callback);

/**
 * Registers the given @p resource for @p context. The resource must have been
 * created by coap_resource_init() or coap_resource_unknown_init(), the
 * storage allocated for the resource will be released by coap_delete_resource().
 *
 * @param context  The context to use.
 * @param resource The resource to store.
 */
void coap_add_resource(coap_context_t *context, coap_resource_t *resource);

/**
 * Deletes a resource identified by @p resource. The storage allocated for that
 * resource is freed, and removed from the context.
 *
 * @param context  This parameter is ignored, but kept for backward
 *                 compatability.
 * @param resource The resource to delete.
 *
 * @return         @c 1 if the resource was found (and destroyed),
 *                 @c 0 otherwise.
 */
int coap_delete_resource(coap_context_t *context, coap_resource_t *resource);

/**
 * Registers the specified @p handler as message handler for the request type
 * @p method
 *
 * @param resource The resource for which the handler shall be registered.
 * @param method   The CoAP request method to handle.
 * @param handler  The handler to register with @p resource.
 */
void coap_register_handler(coap_resource_t *resource,
                           coap_request_t method,
                           coap_method_handler_t handler);

/**
 * Registers the specified @p handler as message handler for the request type
 * @p method
 *
 * @param resource The resource for which the handler shall be registered.
 * @param method   The CoAP request method to handle.
 * @param handler  The handler to register with @p resource.
 */
void coap_register_request_handler(coap_resource_t *resource,
                           coap_request_t method,
                           coap_method_handler_t handler);

/**
 * Registers a new attribute with the given @p resource. As the
 * attribute's coap_str_const_ fields will point to @p name and @p value the
 * caller must ensure that these pointers are valid during the
 * attribute's lifetime.

 * If the @p name and/or @p value string is going to be freed off at attribute
 * removal time by the setting of COAP_ATTR_FLAGS_RELEASE_NAME or
 * COAP_ATTR_FLAGS_RELEASE_VALUE in @p flags, then either the 's'
 * variable of coap_str_const_t has to point to constant text, or point to data
 * within the allocated coap_str_const_t parameter.
 *
 * @param resource The resource to register the attribute with.
 * @param name     The attribute's name as a string.
 * @param value    The attribute's value as a string or @c NULL if none.
 * @param flags    Flags for memory management (in particular release of
 *                 memory). Possible values:@n
 *
 *                 COAP_ATTR_FLAGS_RELEASE_NAME
 *                  If this flag is set, the name passed to
 *                  coap_add_attr_release() is free'd
 *                  when the attribute is deleted@n
 *
 *                 COAP_ATTR_FLAGS_RELEASE_VALUE
 *                  If this flag is set, the value passed to
 *                  coap_add_attr_release() is free'd
 *                  when the attribute is deleted@n
 *
 * @return         A pointer to the new attribute or @c NULL on error.
 */
coap_attr_t *coap_add_attr(coap_resource_t *resource,
                           coap_str_const_t *name,
                           coap_str_const_t *value,
                           int flags);

/**
 * Returns @p resource's coap_attr_t object with given @p name if found, @c NULL
 * otherwise.
 *
 * @param resource The resource to search for attribute @p name.
 * @param name     Name of the requested attribute as a string.
 * @return         The first attribute with specified @p name or @c NULL if none
 *                 was found.
 */
coap_attr_t *coap_find_attr(coap_resource_t *resource,
                            coap_str_const_t *name);

/**
 * Returns @p attribute's value.
 *
 * @param attribute Pointer to attribute.
 *
 * @return Attribute's value or @c NULL.
 */
coap_str_const_t *coap_attr_get_value(coap_attr_t *attribute);

/**
 * Status word to encode the result of conditional print or copy operations such
 * as coap_print_link(). The lower 28 bits of coap_print_status_t are used to
 * encode the number of characters that has actually been printed, bits 28 to 31
 * encode the status.  When COAP_PRINT_STATUS_ERROR is set, an error occurred
 * during output. In this case, the other bits are undefined.
 * COAP_PRINT_STATUS_TRUNC indicates that the output is truncated, i.e. the
 * printing would have exceeded the current buffer.
 */
typedef unsigned int coap_print_status_t;

#define COAP_PRINT_STATUS_MASK  0xF0000000u
#define COAP_PRINT_OUTPUT_LENGTH(v) ((v) & ~COAP_PRINT_STATUS_MASK)
#define COAP_PRINT_STATUS_ERROR 0x80000000u
#define COAP_PRINT_STATUS_TRUNC 0x40000000u

/**
 * Writes a description of this resource in link-format to given text buffer. @p
 * len must be initialized to the maximum length of @p buf and will be set to
 * the number of characters actually written if successful. This function
 * returns @c 1 on success or @c 0 on error.
 *
 * @param resource The resource to describe.
 * @param buf      The output buffer to write the description to.
 * @param len      Must be initialized to the length of @p buf and
 *                 will be set to the length of the printed link description.
 * @param offset   The offset within the resource description where to
 *                 start writing into @p buf. This is useful for dealing
 *                 with the Block2 option. @p offset is updated during
 *                 output as it is consumed.
 *
 * @return If COAP_PRINT_STATUS_ERROR is set, an error occured. Otherwise,
 *         the lower 28 bits will indicate the number of characters that
 *         have actually been output into @p buffer. The flag
 *         COAP_PRINT_STATUS_TRUNC indicates that the output has been
 *         truncated.
 */
coap_print_status_t coap_print_link(const coap_resource_t *resource,
                                    unsigned char *buf,
                                    size_t *len,
                                    size_t *offset);

/** @} */

/**
 * Returns the resource identified by the unique string @p uri_path. If no
 * resource was found, this function returns @c NULL.
 *
 * @param context  The context to look for this resource.
 * @param uri_path  The unique string uri of the resource.
 *
 * @return         A pointer to the resource or @c NULL if not found.
 */
coap_resource_t *coap_get_resource_from_uri_path(coap_context_t *context,
                                                coap_str_const_t *uri_path);

/**
 * @deprecated use coap_resource_notify_observers() instead.
 */
COAP_DEPRECATED int
coap_resource_set_dirty(coap_resource_t *r,
                        const coap_string_t *query);

#endif /* COAP_RESOURCE_H_ */
