mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
2218 lines
75 KiB
C
2218 lines
75 KiB
C
/*
|
|
* Copyright (C) 2016-18 Kaspar Schleiser <kaspar@schleiser.de>
|
|
* 2018 Freie Universität Berlin
|
|
* 2018 Inria
|
|
* 2018 Ken Bannister <kb2ma@runbox.com>
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
* directory for more details.
|
|
*/
|
|
|
|
/**
|
|
* @defgroup net_nanocoap nanoCoAP small CoAP library
|
|
* @ingroup net
|
|
* @brief CoAP library optimized for minimal resource usage
|
|
*
|
|
* nanocoap is a toolbox for reading and writing CoAP messages. It provides
|
|
* functions for core header attributes like message type and code. It also
|
|
* provides high and low level interfaces to CoAP options, including Block.
|
|
*
|
|
* nanocoap includes the core structs to store message information. It also
|
|
* provides helper functions for use before sending and after receiving a
|
|
* message, such as coap_parse() to read an incoming message.
|
|
*
|
|
* ## Application APIs
|
|
*
|
|
* This page provides reference documentation for the contents of nanocoap. To
|
|
* use nanocoap in an application, see the functional APIs that are built with
|
|
* it. [nanocoap sock](group__net__nanosock.html) is for a targeted client or
|
|
* server with lesser resource requirements, and [gcoap](group__net__gcoap.html)
|
|
* provides a more featureful messaging hub.
|
|
*
|
|
* ### Option APIs
|
|
*
|
|
* For both server responses and client requests, CoAP uses an Option mechanism
|
|
* to encode message metadata that is not required for each message. For
|
|
* example, the resource URI path is required only for a request, and is encoded
|
|
* as the Uri-Path option.
|
|
*
|
|
* nanocoap sock uses the simpler Buffer API, described in the section
|
|
* _Options Write Buffer API_. gcoap uses the more convenient Packet API,
|
|
* described in the section _Options Write Packet API_.
|
|
*
|
|
* For either API, the caller *must* write options in order by option number
|
|
* (see "CoAP option numbers" in [CoAP defines](group__net__coap.html)).
|
|
*
|
|
* ## Server path matching
|
|
*
|
|
* By default the URI-path of an incoming request should match exactly one of
|
|
* the registered resources. But also, a resource can be configured to
|
|
* match just a prefix of the URI-path of the request by adding the
|
|
* @ref COAP_MATCH_SUBTREE option to coap_resource_t::methods.
|
|
*
|
|
* For example, if a resource is configured with a
|
|
* @ref coap_resource_t::path "path" `/resource01` and the
|
|
* @ref COAP_MATCH_SUBTREE option is used it would match any of `/resource01/`,
|
|
* `/resource01/sub/path`, `/resource01alt`.
|
|
*
|
|
* If the behavior of matching `/resource01alt` is not wanted and only subtrees
|
|
* are wanted to match, the path should be `/resource01/`.
|
|
*
|
|
* If in addition just `/resource01` is wanted to match, together with any
|
|
* subtrees of `/resource01/`, then a first resource with the path `/resource01`
|
|
* and exact matching should be register, and then a second one with the path
|
|
* `/resource01/` and subtree matching.
|
|
*
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief nanocoap API
|
|
*
|
|
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
|
* @author Ken Bannister <kb2ma@runbox.com>
|
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
|
*/
|
|
|
|
#ifndef NET_NANOCOAP_H
|
|
#define NET_NANOCOAP_H
|
|
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#ifdef RIOT_VERSION
|
|
#include "bitarithm.h"
|
|
#include "bitfield.h"
|
|
#include "byteorder.h"
|
|
#include "iolist.h"
|
|
#include "macros/utils.h"
|
|
#include "net/coap.h"
|
|
#include "modules.h"
|
|
#else
|
|
#include "coap.h"
|
|
#include <arpa/inet.h>
|
|
#endif
|
|
|
|
#if defined(MODULE_SOCK_UDP) || defined(DOXYGEN)
|
|
#include "net/sock/udp.h"
|
|
#else
|
|
typedef void sock_udp_ep_t;
|
|
#endif
|
|
|
|
#if defined(MODULE_NANOCOAP_RESOURCES)
|
|
#include "xfa.h"
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**
|
|
* @name nanoCoAP specific CoAP method flags used in coap_handlers array
|
|
* @anchor nanocoap_method_flags
|
|
* @{
|
|
*/
|
|
#define COAP_GET (0x01)
|
|
#define COAP_POST (0x02)
|
|
#define COAP_PUT (0x04)
|
|
#define COAP_DELETE (0x08)
|
|
#define COAP_FETCH (0x10)
|
|
#define COAP_PATCH (0x20)
|
|
#define COAP_IPATCH (0x40)
|
|
#define COAP_IGNORE (0xFF) /**< For situations where the method
|
|
is not important */
|
|
#define COAP_MATCH_SUBTREE (0x8000) /**< Path is considered as a prefix
|
|
when matching */
|
|
/** @} */
|
|
|
|
/**
|
|
* @brief nanoCoAP-specific value to indicate no format specified
|
|
*/
|
|
#define COAP_FORMAT_NONE (UINT16_MAX)
|
|
|
|
/**
|
|
* @defgroup net_nanocoap_conf nanoCoAP compile configurations
|
|
* @ingroup net_nanocoap
|
|
* @ingroup config
|
|
* @{
|
|
*/
|
|
/** @brief Maximum number of Options in a message */
|
|
#ifndef CONFIG_NANOCOAP_NOPTS_MAX
|
|
#define CONFIG_NANOCOAP_NOPTS_MAX (16)
|
|
#endif
|
|
|
|
/**
|
|
* @brief Maximum length of a resource path string read from or written to
|
|
* a message
|
|
*/
|
|
#ifndef CONFIG_NANOCOAP_URI_MAX
|
|
#define CONFIG_NANOCOAP_URI_MAX (64)
|
|
#endif
|
|
|
|
/**
|
|
* @brief Maximum size for a blockwise transfer as a power of 2
|
|
*/
|
|
#ifndef CONFIG_NANOCOAP_BLOCK_SIZE_EXP_MAX
|
|
#define CONFIG_NANOCOAP_BLOCK_SIZE_EXP_MAX (6)
|
|
#endif
|
|
|
|
/**
|
|
* @brief CoAP block-wise-transfer size that should be used by default
|
|
*/
|
|
#ifndef CONFIG_NANOCOAP_BLOCKSIZE_DEFAULT
|
|
#define CONFIG_NANOCOAP_BLOCKSIZE_DEFAULT COAP_BLOCKSIZE_64
|
|
#endif
|
|
|
|
/** @brief Maximum length of a query string written to a message */
|
|
#ifndef CONFIG_NANOCOAP_QS_MAX
|
|
#define CONFIG_NANOCOAP_QS_MAX (64)
|
|
#endif
|
|
/** @} */
|
|
|
|
/**
|
|
* @brief Maximum length of a CoAP header for a blockwise message
|
|
*
|
|
* Value obtained experimentally when using SUIT
|
|
*/
|
|
#ifndef CONFIG_NANOCOAP_BLOCK_HEADER_MAX
|
|
#define CONFIG_NANOCOAP_BLOCK_HEADER_MAX (80)
|
|
#endif
|
|
|
|
/**
|
|
* @name coap_opt_finish() flag parameter values
|
|
*
|
|
* Directs packet/buffer updates when user finishes adding options
|
|
* @{
|
|
*/
|
|
/** @brief no special handling required */
|
|
#define COAP_OPT_FINISH_NONE (0x0000)
|
|
/** @brief expect a payload to follow */
|
|
#define COAP_OPT_FINISH_PAYLOAD (0x0001)
|
|
/** @} */
|
|
|
|
/**
|
|
* @brief Raw CoAP PDU header structure
|
|
*/
|
|
typedef struct __attribute__((packed)) {
|
|
uint8_t ver_t_tkl; /**< version, token, token length */
|
|
uint8_t code; /**< CoAP code (e.g.m 205) */
|
|
uint16_t id; /**< Req/resp ID */
|
|
} coap_hdr_t;
|
|
|
|
/**
|
|
* @brief CoAP option array entry
|
|
*/
|
|
typedef struct {
|
|
uint16_t opt_num; /**< full CoAP option number */
|
|
uint16_t offset; /**< offset in packet */
|
|
} coap_optpos_t;
|
|
|
|
/**
|
|
* @brief CoAP PDU parsing context structure
|
|
*
|
|
* When this struct is used to assemble the header, @p payload is used as the
|
|
* write pointer and @p payload_len contains the number of free bytes left in
|
|
* then packet buffer pointed to by @ref coap_pkt_t::hdr
|
|
*
|
|
* When the header was written, @p payload must not be changed, it must remain
|
|
* pointing to the end of the header.
|
|
* @p payload_len must then be set to the size of the payload that was further
|
|
* copied into the packet buffer, after the header.
|
|
*
|
|
* @ref coap_pkt_t::snips can be used to attach further payload buffers without copying them
|
|
* into the CoAP packet buffer.
|
|
* If there are any, they will be attached in order after the last payload byte
|
|
* (or header byte) in the original CoAP packet buffer.
|
|
*/
|
|
typedef struct {
|
|
coap_hdr_t *hdr; /**< pointer to raw packet */
|
|
uint8_t *payload; /**< pointer to end of the header */
|
|
iolist_t *snips; /**< payload snips (optional)*/
|
|
uint16_t payload_len; /**< length of payload */
|
|
uint16_t options_len; /**< length of options array */
|
|
coap_optpos_t options[CONFIG_NANOCOAP_NOPTS_MAX]; /**< option offset array */
|
|
BITFIELD(opt_crit, CONFIG_NANOCOAP_NOPTS_MAX); /**< unhandled critical option */
|
|
#ifdef MODULE_GCOAP
|
|
uint32_t observe_value; /**< observe value */
|
|
#endif
|
|
} coap_pkt_t;
|
|
|
|
/**
|
|
* @brief Forward declaration of internal CoAP resource request handler context
|
|
*/
|
|
typedef struct _coap_request_ctx coap_request_ctx_t;
|
|
|
|
/**
|
|
* @brief Resource handler type
|
|
*
|
|
* Functions that implement this must be prepared to be called multiple times
|
|
* for the same request, as the server implementations do not perform message
|
|
* deduplication. That optimization is [described in the CoAP
|
|
* specification](https://tools.ietf.org/html/rfc7252#section-4.5).
|
|
*
|
|
* This should be trivial for requests of the GET, PUT, DELETE, FETCH and
|
|
* iPATCH methods, as they are defined as idempotent methods in CoAP.
|
|
*
|
|
* For POST, PATCH and other non-idempotent methods, this is an additional
|
|
* requirement introduced by the contract of this type.
|
|
*
|
|
* @param[in] pkt The request packet
|
|
* @param[out] buf Buffer for the response
|
|
* @param[in] len Size of the response buffer
|
|
* @param[in] context Request context
|
|
*
|
|
* @return Number of response bytes written on success
|
|
* Negative error on failure
|
|
*/
|
|
typedef ssize_t (*coap_handler_t)(coap_pkt_t *pkt, uint8_t *buf, size_t len,
|
|
coap_request_ctx_t *context);
|
|
|
|
/**
|
|
* @brief Coap blockwise request callback descriptor
|
|
*
|
|
* @param[in] arg Pointer to be passed as arguments to the callback
|
|
* @param[in] offset Offset of received data
|
|
* @param[in] buf Pointer to the received data
|
|
* @param[in] len Length of the received data
|
|
* @param[in] more -1 for no option, 0 for last block, 1 for more blocks
|
|
*
|
|
* @returns >=0 on success
|
|
* @returns <0 on error
|
|
*/
|
|
typedef int (*coap_blockwise_cb_t)(void *arg, size_t offset, uint8_t *buf, size_t len, int more);
|
|
|
|
/**
|
|
* @brief Coap request callback descriptor
|
|
*
|
|
* @param[in] arg Pointer to be passed as arguments to the callback
|
|
* @param[in] pkt The received CoAP response.
|
|
* Buffers point to network stack internal memory.
|
|
*
|
|
* @returns >=0 on success
|
|
* @returns <0 on error
|
|
*/
|
|
typedef int (*coap_request_cb_t)(void *arg, coap_pkt_t *pkt);
|
|
|
|
/**
|
|
* @brief Method flag type
|
|
*
|
|
* Must be large enough to contain all @ref nanocoap_method_flags "CoAP method flags"
|
|
*/
|
|
typedef uint16_t coap_method_flags_t;
|
|
|
|
/**
|
|
* @brief Type for CoAP resource entry
|
|
*/
|
|
typedef struct {
|
|
const char *path; /**< URI path of resource */
|
|
coap_method_flags_t methods; /**< OR'ed methods this resource allows */
|
|
coap_handler_t handler; /**< ptr to resource handler */
|
|
void *context; /**< ptr to user defined context data */
|
|
} coap_resource_t;
|
|
|
|
/**
|
|
* @brief Type for CoAP resource subtrees
|
|
*/
|
|
typedef const struct {
|
|
const coap_resource_t *resources; /**< ptr to resource array */
|
|
const size_t resources_numof; /**< number of entries in array */
|
|
} coap_resource_subtree_t;
|
|
|
|
/**
|
|
* @brief Initialize CoAP request context
|
|
*
|
|
* @param[in] ctx Pointer to the request context to initialize
|
|
* @param[in] remote Remote endpoint that made the request
|
|
*/
|
|
void coap_request_ctx_init(coap_request_ctx_t *ctx, sock_udp_ep_t *remote);
|
|
|
|
/**
|
|
* @brief CoAP resource request handler context
|
|
* @internal
|
|
*/
|
|
struct _coap_request_ctx {
|
|
const coap_resource_t *resource; /**< resource of the request */
|
|
sock_udp_ep_t *remote; /**< remote endpoint of the request */
|
|
#if defined(MODULE_GCOAP) || DOXYGEN
|
|
/**
|
|
* @brief transport the packet was received over
|
|
* @see @ref gcoap_socket_type_t for values.
|
|
* @note @ref gcoap_socket_type_t can not be used, as this would
|
|
* cyclically include the @ref net_gcoap header.
|
|
*/
|
|
uint32_t tl_type;
|
|
#endif
|
|
};
|
|
|
|
/**
|
|
* @brief Get resource path associated with a CoAP request
|
|
*
|
|
* @param[in] ctx The request context
|
|
*
|
|
* @return Resource path of the request
|
|
*/
|
|
const char *coap_request_ctx_get_path(const coap_request_ctx_t *ctx);
|
|
|
|
/**
|
|
* @brief Get resource context associated with a CoAP request
|
|
*
|
|
* @param[in] ctx The request context
|
|
*
|
|
* @return Resource context of the request
|
|
*/
|
|
void *coap_request_ctx_get_context(const coap_request_ctx_t *ctx);
|
|
|
|
/**
|
|
* @brief Get transport the packet was received over
|
|
* @see @ref gcoap_socket_type_t for values.
|
|
*
|
|
* @param[in] ctx The request context
|
|
*
|
|
* @return Transport Layer type of the request
|
|
*/
|
|
uint32_t coap_request_ctx_get_tl_type(const coap_request_ctx_t *ctx);
|
|
|
|
/**
|
|
* @brief Get the remote endpoint from which the request was received
|
|
*
|
|
* @param[in] ctx The request context
|
|
*
|
|
* @return Remote endpoint from which the request originated
|
|
* @return NULL The request was not received via UDP
|
|
*/
|
|
const sock_udp_ep_t *coap_request_ctx_get_remote_udp(const coap_request_ctx_t *ctx);
|
|
|
|
/**
|
|
* @brief Block1 helper struct
|
|
*/
|
|
typedef struct {
|
|
size_t offset; /**< offset of received data */
|
|
uint32_t blknum; /**< block number */
|
|
uint8_t szx; /**< szx value */
|
|
int8_t more; /**< -1 for no option, 0 for last block,
|
|
1 for more blocks coming */
|
|
} coap_block1_t;
|
|
|
|
/**
|
|
* @brief Blockwise transfer helper struct
|
|
*/
|
|
typedef struct {
|
|
size_t start; /**< Start offset of the current block */
|
|
size_t end; /**< End offset of the current block */
|
|
size_t cur; /**< Offset of the generated content */
|
|
uint8_t *opt; /**< Pointer to the placed option */
|
|
} coap_block_slicer_t;
|
|
|
|
#if defined(MODULE_NANOCOAP_RESOURCES) || DOXYGEN
|
|
/**
|
|
* @brief CoAP XFA resource entry
|
|
*
|
|
* @param name internal name of the resource entry, must be unique
|
|
*/
|
|
#define NANOCOAP_RESOURCE(name) \
|
|
XFA_CONST(coap_resources_xfa, 0) coap_resource_t CONCAT(coap_resource_, name) =
|
|
#else
|
|
/**
|
|
* @brief Global CoAP resource list
|
|
* @deprecated Use @ref NANOCOAP_RESOURCE instead.
|
|
* The function will be removed after the 2024.01 release.
|
|
*/
|
|
extern const coap_resource_t coap_resources[];
|
|
|
|
/**
|
|
* @brief Number of entries in global CoAP resource list
|
|
* @deprecated Use @ref NANOCOAP_RESOURCE instead.
|
|
* The function will be removed after the 2024.01 release.
|
|
*/
|
|
extern const unsigned coap_resources_numof;
|
|
#endif
|
|
|
|
/**
|
|
* @name Functions -- Header Read/Write
|
|
*
|
|
* Includes message ID, code, type, token, CoAP version
|
|
*/
|
|
/**@{*/
|
|
/**
|
|
* @brief Encode given code class and code detail to raw code
|
|
*
|
|
* @param[in] cls message code class
|
|
* @param[in] detail message code detail
|
|
*
|
|
* @returns raw message code
|
|
*/
|
|
static inline uint8_t coap_code(unsigned cls, unsigned detail)
|
|
{
|
|
return (cls << 5) | detail;
|
|
}
|
|
|
|
/**
|
|
* @brief Get a message's code class (3 most significant bits of code)
|
|
*
|
|
* @param[in] pkt CoAP packet
|
|
*
|
|
* @returns message code class
|
|
*/
|
|
static inline unsigned coap_get_code_class(const coap_pkt_t *pkt)
|
|
{
|
|
return pkt->hdr->code >> 5;
|
|
}
|
|
|
|
/**
|
|
* @brief Get a message's code detail (5 least significant bits of code)
|
|
*
|
|
* @param[in] pkt CoAP packet
|
|
*
|
|
* @returns message code detail
|
|
*/
|
|
static inline unsigned coap_get_code_detail(const coap_pkt_t *pkt)
|
|
{
|
|
return pkt->hdr->code & 0x1f;
|
|
}
|
|
|
|
/**
|
|
* @brief Get a message's code in decimal format ((class * 100) + detail)
|
|
*
|
|
* @param[in] pkt CoAP packet
|
|
*
|
|
* @returns message code in decimal format
|
|
*/
|
|
static inline unsigned coap_get_code_decimal(const coap_pkt_t *pkt)
|
|
{
|
|
return (coap_get_code_class(pkt) * 100) + coap_get_code_detail(pkt);
|
|
}
|
|
|
|
/**
|
|
* @brief Get a message's raw code (class + detail)
|
|
*
|
|
* @param[in] pkt CoAP packet
|
|
*
|
|
* @returns raw message code
|
|
*/
|
|
static inline unsigned coap_get_code_raw(const coap_pkt_t *pkt)
|
|
{
|
|
return (unsigned)pkt->hdr->code;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the message ID of the given CoAP packet
|
|
*
|
|
* @param[in] pkt CoAP packet
|
|
*
|
|
* @returns message ID
|
|
*/
|
|
static inline unsigned coap_get_id(const coap_pkt_t *pkt)
|
|
{
|
|
return ntohs(pkt->hdr->id);
|
|
}
|
|
|
|
/**
|
|
* @brief Get a message's token length [in byte]
|
|
*
|
|
* If the `nanocoap_token_ext` module is enabled, this will include
|
|
* the extended token length.
|
|
*
|
|
* @param[in] pkt CoAP packet
|
|
*
|
|
* @returns length of token in the given message (0-8 byte)
|
|
*/
|
|
static inline unsigned coap_get_token_len(const coap_pkt_t *pkt)
|
|
{
|
|
uint8_t tkl = pkt->hdr->ver_t_tkl & 0xf;
|
|
|
|
if (!IS_USED(MODULE_NANOCOAP_TOKEN_EXT)) {
|
|
return tkl;
|
|
}
|
|
|
|
void *ext = pkt->hdr + 1;
|
|
switch (tkl) {
|
|
case 13:
|
|
return tkl + *(uint8_t *)ext;
|
|
case 14:
|
|
return tkl + 255 + byteorder_bebuftohs(ext);
|
|
case 15:
|
|
assert(0);
|
|
/* fall-through */
|
|
default:
|
|
return tkl;
|
|
}
|
|
}
|
|
|
|
static inline uint8_t *coap_hdr_data_ptr(const coap_hdr_t *hdr);
|
|
|
|
/**
|
|
* @brief Get pointer to a message's token
|
|
*
|
|
* @param[in] pkt CoAP packet
|
|
*
|
|
* @returns pointer to the token position
|
|
*/
|
|
static inline void *coap_get_token(const coap_pkt_t *pkt)
|
|
{
|
|
return coap_hdr_data_ptr(pkt->hdr);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the total header length (4-byte header + token length)
|
|
*
|
|
* @param[in] pkt CoAP packet
|
|
*
|
|
* @returns total header length
|
|
*/
|
|
static inline unsigned coap_get_total_hdr_len(const coap_pkt_t *pkt)
|
|
{
|
|
return sizeof(coap_hdr_t) + coap_get_token_len(pkt);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the total length of a CoAP packet in the packet buffer
|
|
*
|
|
* @note This does not include possible payload snips.
|
|
*
|
|
* @param[in] pkt CoAP packet
|
|
*
|
|
* @returns total CoAP length
|
|
*/
|
|
static inline unsigned coap_get_total_len(const coap_pkt_t *pkt)
|
|
{
|
|
return (uintptr_t)pkt->payload - (uintptr_t)pkt->hdr + pkt->payload_len;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the message type
|
|
*
|
|
* @param[in] pkt CoAP packet
|
|
*
|
|
* @returns COAP_TYPE_CON
|
|
* @returns COAP_TYPE_NON
|
|
* @returns COAP_TYPE_ACK
|
|
* @returns COAP_TYPE_RST
|
|
*/
|
|
static inline unsigned coap_get_type(const coap_pkt_t *pkt)
|
|
{
|
|
return (pkt->hdr->ver_t_tkl & 0x30) >> 4;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the CoAP version number
|
|
*
|
|
* @param[in] pkt CoAP packet
|
|
*
|
|
* @returns CoAP version number
|
|
*/
|
|
static inline unsigned coap_get_ver(const coap_pkt_t *pkt)
|
|
{
|
|
return (pkt->hdr->ver_t_tkl & 0x60) >> 6;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the size of the extended Token length field
|
|
* (RFC 8974)
|
|
*
|
|
* @note This requires the `nanocoap_token_ext` module to be enabled
|
|
*
|
|
* @param[in] hdr CoAP header
|
|
*
|
|
* @returns number of bytes used for extended token length
|
|
*/
|
|
static inline uint8_t coap_hdr_tkl_ext_len(const coap_hdr_t *hdr)
|
|
{
|
|
if (!IS_USED(MODULE_NANOCOAP_TOKEN_EXT)) {
|
|
return 0;
|
|
}
|
|
|
|
switch (hdr->ver_t_tkl & 0xf) {
|
|
case 13:
|
|
return 1;
|
|
case 14:
|
|
return 2;
|
|
case 15:
|
|
assert(0);
|
|
/* fall-through */
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Get the start of data after the header
|
|
*
|
|
* @param[in] hdr Header of CoAP packet in contiguous memory
|
|
*
|
|
* @returns pointer to first byte after the header
|
|
*/
|
|
static inline uint8_t *coap_hdr_data_ptr(const coap_hdr_t *hdr)
|
|
{
|
|
return ((uint8_t *)hdr) + sizeof(coap_hdr_t) + coap_hdr_tkl_ext_len(hdr);
|
|
}
|
|
|
|
/**
|
|
* @brief Write the given raw message code to given CoAP header
|
|
*
|
|
* @param[out] hdr CoAP header to write to
|
|
* @param[in] code raw message code
|
|
*/
|
|
static inline void coap_hdr_set_code(coap_hdr_t *hdr, uint8_t code)
|
|
{
|
|
hdr->code = code;
|
|
}
|
|
|
|
/**
|
|
* @brief Set the message type for the given CoAP header
|
|
*
|
|
* @pre (type := [0-3])
|
|
*
|
|
* @param[out] hdr CoAP header to write
|
|
* @param[in] type message type as integer value [0-3]
|
|
*/
|
|
static inline void coap_hdr_set_type(coap_hdr_t *hdr, unsigned type)
|
|
{
|
|
/* assert correct range of type */
|
|
assert(!(type & ~0x3));
|
|
|
|
hdr->ver_t_tkl &= ~0x30;
|
|
hdr->ver_t_tkl |= type << 4;
|
|
}
|
|
/**@}*/
|
|
|
|
/**
|
|
* @name Functions -- Options Read
|
|
*
|
|
* Read options from a parsed packet.
|
|
*
|
|
* Packets accessed through @ref coap_find_option or any of the `coap_opt_get_*` functions
|
|
* track their access in bit field created at parsing time to enable checking for critical
|
|
* options in @ref coap_has_unprocessed_critical_options.
|
|
* These functions thus have a side effect, and code that calls them on critical options
|
|
* needs to ensure that failure to process the accessed option is propagated into failure
|
|
* to process the message.
|
|
* For example, a server helper that tries to read the If-None-Match option (which is critical)
|
|
* and finds it to be longer than it can process must not return as if no If-None-Match option
|
|
* was present, as it has already triggered the side effect of marking the option as processed.
|
|
*/
|
|
/**@{*/
|
|
|
|
/**
|
|
* @brief Get pointer to an option field by type
|
|
*
|
|
* @param[in] pkt packet to work on
|
|
* @param[in] opt_num the option number to search for
|
|
*
|
|
* @returns pointer to the option data
|
|
* NULL if option number was not found
|
|
*/
|
|
uint8_t *coap_find_option(coap_pkt_t *pkt, unsigned opt_num);
|
|
|
|
/**
|
|
* @brief Get pointer to an option field, can be called in a loop
|
|
* if there are multiple options with the same number
|
|
*
|
|
* @param[in] pkt packet to work on
|
|
* @param[in] opt_num the option number to search for
|
|
* @param[out] opt_pos opaque, must be set to `NULL` on first call
|
|
* @param[out] opt_len size of the current option data
|
|
*
|
|
* @returns pointer to the option data
|
|
* NULL if option number was not found
|
|
*/
|
|
uint8_t *coap_iterate_option(coap_pkt_t *pkt, unsigned opt_num,
|
|
uint8_t **opt_pos, int *opt_len);
|
|
|
|
/**
|
|
* @brief Get content type from packet
|
|
*
|
|
* @param[in] pkt packet to work on
|
|
*
|
|
* @returns the packet's content type value if included,
|
|
* COAP_FORMAT_NONE otherwise
|
|
*/
|
|
unsigned coap_get_content_type(coap_pkt_t *pkt);
|
|
|
|
/**
|
|
* @brief Get the Accept option value from a packet if present
|
|
*
|
|
* @param[in] pkt packet to work on
|
|
*
|
|
* @returns the packet's Accept option value if included,
|
|
* COAP_FORMAT_NONE otherwise
|
|
*/
|
|
unsigned coap_get_accept(coap_pkt_t *pkt);
|
|
|
|
/**
|
|
* @brief Get a uint32 option value
|
|
*
|
|
* @param[in] pkt packet to read from
|
|
* @param[in] optnum absolute option number
|
|
* @param[out] value the parsed option value
|
|
*
|
|
* @return 0 if the option was found and the value was parsed correctly
|
|
* @return -ENOENT if the option was not found in @p pkt
|
|
* @return -ENOSPC if option length is greater than 4 octets
|
|
* @return -EBADMSG if option value is invalid
|
|
*/
|
|
int coap_opt_get_uint(coap_pkt_t *pkt, uint16_t optnum, uint32_t *value);
|
|
|
|
/**
|
|
* @brief Read a full option as null terminated string into the target buffer
|
|
*
|
|
* This function is for reading and concatenating string based, multi-part CoAP
|
|
* options like COAP_OPT_URI_PATH or COAP_OPT_LOCATION_PATH. It will write all
|
|
* parts of the given option into the target buffer, separating the parts using
|
|
* the given @p separator. The resulting string is `\0` terminated.
|
|
*
|
|
* @param[in] pkt packet to read from
|
|
* @param[in] optnum absolute option number
|
|
* @param[out] target target buffer
|
|
* @param[in] max_len size of @p target
|
|
* @param[in] separator character used for separating the option parts
|
|
*
|
|
* @return -ENOSPC if the complete option does not fit into @p target
|
|
* @return nr of bytes written to @p target (including '\0')
|
|
*/
|
|
ssize_t coap_opt_get_string(coap_pkt_t *pkt, uint16_t optnum,
|
|
uint8_t *target, size_t max_len, char separator);
|
|
|
|
/**
|
|
* @brief Convenience function for getting the packet's LOCATION_PATH option
|
|
*
|
|
* This function decodes the pkt's LOCATION_PATH option into a '/'-separated and
|
|
* '\0'-terminated string.
|
|
*
|
|
* Caller must ensure @p target can hold at least 2 bytes!
|
|
*
|
|
* @param[in] pkt pkt to work on
|
|
* @param[out] target buffer for location path
|
|
* @param[in] max_len size of @p target in bytes
|
|
*
|
|
* @returns -ENOSPC if URI option is larger than @p max_len
|
|
* @returns nr of bytes written to @p target (including '\0')
|
|
*/
|
|
static inline ssize_t coap_get_location_path(coap_pkt_t *pkt,
|
|
uint8_t *target, size_t max_len)
|
|
{
|
|
return coap_opt_get_string(pkt, COAP_OPT_LOCATION_PATH,
|
|
target, max_len, '/');
|
|
}
|
|
|
|
/**
|
|
* @brief Convenience function for getting the packet's LOCATION_QUERY option
|
|
*
|
|
* This function decodes the pkt's LOCATION_PATH option into a '&'-separated and
|
|
* '\0'-terminated string.
|
|
*
|
|
* Caller must ensure @p target can hold at least 2 bytes!
|
|
*
|
|
* @param[in] pkt pkt to work on
|
|
* @param[out] target buffer for location path
|
|
* @param[in] max_len size of @p target in bytes
|
|
*
|
|
* @returns -ENOSPC if URI option is larger than @p max_len
|
|
* @returns nr of bytes written to @p target (including '\0')
|
|
*/
|
|
static inline ssize_t coap_get_location_query(coap_pkt_t *pkt,
|
|
uint8_t *target, size_t max_len)
|
|
{
|
|
return coap_opt_get_string(pkt, COAP_OPT_LOCATION_QUERY,
|
|
target, max_len, '&');
|
|
}
|
|
|
|
/**
|
|
* @brief Convenience function for getting the packet's URI_PATH
|
|
*
|
|
* This function decodes the pkt's URI option into a "/"-separated and
|
|
* '\0'-terminated string.
|
|
*
|
|
* Caller must ensure @p target can hold at least CONFIG_NANOCOAP_URI_MAX bytes!
|
|
*
|
|
* @param[in] pkt pkt to work on
|
|
* @param[out] target buffer for target URI
|
|
*
|
|
* @returns -ENOSPC if URI option is larger than CONFIG_NANOCOAP_URI_MAX
|
|
* @returns nr of bytes written to @p target (including '\0')
|
|
*/
|
|
static inline ssize_t coap_get_uri_path(coap_pkt_t *pkt, uint8_t *target)
|
|
{
|
|
return coap_opt_get_string(pkt, COAP_OPT_URI_PATH, target,
|
|
CONFIG_NANOCOAP_URI_MAX, '/');
|
|
}
|
|
|
|
/**
|
|
* @brief Convenience function for getting the packet's URI_QUERY option
|
|
*
|
|
* This function decodes the pkt's URI_QUERY option into a "&"-separated and
|
|
* '\0'-terminated string.
|
|
*
|
|
* Caller must ensure @p target can hold at least CONFIG_NANOCOAP_URI_MAX bytes!
|
|
*
|
|
* @param[in] pkt pkt to work on
|
|
* @param[out] target buffer for target URI
|
|
*
|
|
* @returns -ENOSPC if URI option is larger than CONFIG_NANOCOAP_URI_MAX
|
|
* @returns nr of bytes written to @p target (including '\0')
|
|
*/
|
|
static inline ssize_t coap_get_uri_query(coap_pkt_t *pkt, uint8_t *target)
|
|
{
|
|
return coap_opt_get_string(pkt, COAP_OPT_URI_QUERY, target,
|
|
CONFIG_NANOCOAP_URI_MAX, '&');
|
|
}
|
|
|
|
/**
|
|
* @brief Iterate over a packet's options
|
|
*
|
|
* To start iteration from the first option, set @p init_opt to true. To start
|
|
* iteration from a specific option, set @p init_opt to false, set
|
|
* @p opt->offset to the offset of the desired option from pkt->hdr, and
|
|
* @p opt->opt_num as required. See below for how @p opt->opt_num is modified.
|
|
*
|
|
* With each invocation, this function returns the length of the option value
|
|
* and sets @p value to point to the start of the value. The value for
|
|
* @p opt->opt_num is increased by the delta in the option number value over
|
|
* the preceding option in the packet. So, @p opt->opt_num is accurate if
|
|
* iteration started with the first option. Otherwise, it is useful for
|
|
* identification of repeated options. Finally, @p opt->offset is set to the
|
|
* offset for any following option, to prepare for the next iteration.
|
|
*
|
|
* The end of the options is indicated by a -ENOENT return value. In this case
|
|
* @p value and @p opt are unchanged from their input values.
|
|
*
|
|
* @param[in] pkt packet to read from
|
|
* @param[in,out] opt option attributes; read on input if @p init_opt
|
|
* is false
|
|
* @param[out] value start of the option value
|
|
* @param[in] init_opt true to retrieve first option; false to retrieve
|
|
* option at opt->offset
|
|
*
|
|
* @return length of option value
|
|
* @return -ENOENT if option not found
|
|
*/
|
|
ssize_t coap_opt_get_next(const coap_pkt_t *pkt, coap_optpos_t *opt,
|
|
uint8_t **value, bool init_opt);
|
|
|
|
/**
|
|
* @brief Retrieve the value for an option as an opaque array of bytes
|
|
*
|
|
* Retrieves the location and length of the option value of any type. Useful for
|
|
* an opaque option, which essentially is an array of bytes. If more than one
|
|
* option for a given option number, retrieves the first option. To retrieve
|
|
* subsequent options, see coap_opt_get_next().
|
|
*
|
|
* @param[in] pkt packet to read from
|
|
* @param[in] opt_num option number to retrieve
|
|
* @param[out] value start of the option value
|
|
*
|
|
* @return length of option; 0 if the option exists but is empty
|
|
* @return -ENOENT if option not found
|
|
* @return -EINVAL if option cannot be parsed
|
|
*/
|
|
ssize_t coap_opt_get_opaque(coap_pkt_t *pkt, unsigned opt_num, uint8_t **value);
|
|
/**@}*/
|
|
|
|
/**
|
|
* @brief Convenience function for getting the packet's Proxy-Uri option
|
|
*
|
|
* @param[in] pkt pkt to work on
|
|
* @param[out] target pointer to the PROXY_URI in @p pkt
|
|
*
|
|
* @pre ((pkt != NULL) && (target != NULL))
|
|
*
|
|
* @return length of the Proxy-Uri option
|
|
* @return -ENOENT if Proxy-Uri option not found
|
|
* @return -EINVAL if Proxy-Uri option cannot be parsed
|
|
*/
|
|
static inline ssize_t coap_get_proxy_uri(coap_pkt_t *pkt, char **target)
|
|
{
|
|
return coap_opt_get_opaque(pkt, COAP_OPT_PROXY_URI, (uint8_t **)target);
|
|
}
|
|
|
|
/**
|
|
* @name Functions -- Options for Block
|
|
*
|
|
* Read Block1 (POST/PUT request) or Block2 (GET response) options, and
|
|
* generally useful functions to write block options.
|
|
*/
|
|
/**@{*/
|
|
/**
|
|
* @brief Initialize a block struct from content information
|
|
*
|
|
* @param[out] block block struct to initialize
|
|
* @param[in] blknum offset from the beginning of content, in terms of
|
|
@p blksize byte blocks
|
|
* @param[in] blksize size of each block; must be a power of 2 between 16
|
|
* and 2 raised to #CONFIG_NANOCOAP_BLOCK_SIZE_EXP_MAX
|
|
* @param[in] more more blocks? use 1 if yes; 0 if no or unknown
|
|
*/
|
|
void coap_block_object_init(coap_block1_t *block, size_t blknum, size_t blksize,
|
|
int more);
|
|
|
|
/**
|
|
* @brief Finish a block request (block1 or block2)
|
|
*
|
|
* This function finalizes the block response header
|
|
*
|
|
* Checks whether the `more` bit should be set in the block option and
|
|
* sets/clears it if required. Doesn't return the number of bytes, as this
|
|
* function overwrites bytes in the packet rather than adding new.
|
|
*
|
|
* @param[in] slicer Preallocated slicer struct to use
|
|
* @param[in] option option number (block1 or block2)
|
|
*
|
|
* @return true if the `more` bit is set in the block option
|
|
* @return false if the `more` bit is not set the block option
|
|
*/
|
|
bool coap_block_finish(coap_block_slicer_t *slicer, uint16_t option);
|
|
|
|
/**
|
|
* @brief Finish a block1 request
|
|
*
|
|
* This function finalizes the block1 response header
|
|
*
|
|
* Checks whether the `more` bit should be set in the block1 option and
|
|
* sets/clears it if required. Doesn't return the number of bytes, as this
|
|
* function overwrites bytes in the packet rather than adding new.
|
|
*
|
|
* @param[in] slicer Preallocated slicer struct to use
|
|
*
|
|
* @return true if the `more` bit is set in the block option
|
|
* @return false if the `more` bit is not set the block option
|
|
*/
|
|
static inline bool coap_block1_finish(coap_block_slicer_t *slicer)
|
|
{
|
|
return coap_block_finish(slicer, COAP_OPT_BLOCK1);
|
|
}
|
|
|
|
/**
|
|
* @brief Finish a block2 response
|
|
*
|
|
* This function finalizes the block2 response header
|
|
*
|
|
* Checks whether the `more` bit should be set in the block2 option and
|
|
* sets/clears it if required. Doesn't return the number of bytes, as this
|
|
* function overwrites bytes in the packet rather than adding new.
|
|
*
|
|
* @param[in] slicer Preallocated slicer struct to use
|
|
*
|
|
* @return true if the `more` bit is set in the block option
|
|
* @return false if the `more` bit is not set the block option
|
|
*/
|
|
static inline bool coap_block2_finish(coap_block_slicer_t *slicer)
|
|
{
|
|
return coap_block_finish(slicer, COAP_OPT_BLOCK2);
|
|
}
|
|
|
|
/**
|
|
* @brief Initialize a block2 slicer struct for writing the payload
|
|
*
|
|
* This function determines the size of the response payload based on the
|
|
* size requested by the client in @p pkt.
|
|
*
|
|
* @param[in] pkt packet to work on
|
|
* @param[out] slicer Preallocated slicer struct to fill
|
|
*/
|
|
void coap_block2_init(coap_pkt_t *pkt, coap_block_slicer_t *slicer);
|
|
|
|
/**
|
|
* @brief Initialize a block slicer struct from content information
|
|
*
|
|
* @param[out] slicer slicer struct to initialize
|
|
* @param[in] blknum offset from the beginning of content, in terms of
|
|
@p blksize byte blocks
|
|
* @param[in] blksize size of each block; must be a power of 2 between 16
|
|
* and 2 raised to #CONFIG_NANOCOAP_BLOCK_SIZE_EXP_MAX
|
|
*/
|
|
void coap_block_slicer_init(coap_block_slicer_t *slicer, size_t blknum,
|
|
size_t blksize);
|
|
|
|
/**
|
|
* @brief Add a byte array to a block2 reply.
|
|
*
|
|
* This function is used to add an array of bytes to a CoAP block2 reply. it
|
|
* checks which parts of the string should be added to the reply and ignores
|
|
* parts that are outside the current block2 request.
|
|
*
|
|
* @param[in] slicer slicer to use
|
|
* @param[in] bufpos pointer to the current payload buffer position
|
|
* @param[in] c byte array to copy
|
|
* @param[in] len length of the byte array
|
|
*
|
|
* @returns Number of bytes written to @p bufpos
|
|
*/
|
|
size_t coap_blockwise_put_bytes(coap_block_slicer_t *slicer, uint8_t *bufpos,
|
|
const void *c, size_t len);
|
|
|
|
/**
|
|
* @brief Add a single character to a block2 reply.
|
|
*
|
|
* This function is used to add single characters to a CoAP block2 reply. It
|
|
* checks whether the character should be added to the buffer and ignores it
|
|
* when the character is outside the current block2 request.
|
|
*
|
|
* @param[in] slicer slicer to use
|
|
* @param[in] bufpos pointer to the current payload buffer position
|
|
* @param[in] c character to write
|
|
*
|
|
* @returns Number of bytes written to @p bufpos
|
|
*/
|
|
size_t coap_blockwise_put_char(coap_block_slicer_t *slicer, uint8_t *bufpos, char c);
|
|
|
|
/**
|
|
* @brief Block option getter
|
|
*
|
|
* This function gets a CoAP packet's block option and parses it into a helper
|
|
* structure.
|
|
*
|
|
* If no block option is present in @p pkt, the values in @p block will be
|
|
* initialized with zero. That implies both block->offset and block->more are
|
|
* also valid in that case, as packet with offset==0 and more==0 means it contains
|
|
* all the payload for the corresponding request.
|
|
*
|
|
* @param[in] pkt pkt to work on
|
|
* @param[out] block ptr to preallocated coap_block1_t structure
|
|
* @param[in] option block1 or block2
|
|
*
|
|
* @returns 0 if block option not present
|
|
* @returns 1 if structure has been filled
|
|
*/
|
|
int coap_get_block(coap_pkt_t *pkt, coap_block1_t *block, uint16_t option);
|
|
|
|
/**
|
|
* @brief Block1 option getter
|
|
*
|
|
* This function gets a CoAP packet's block1 option and parses it into a helper
|
|
* structure.
|
|
*
|
|
* If no block1 option is present in @p pkt, the values in @p block1 will be
|
|
* initialized with zero. That implies both block1->offset and block1->more are
|
|
* also valid in that case, as packet with offset==0 and more==0 means it contains
|
|
* all the payload for the corresponding request.
|
|
*
|
|
* @param[in] pkt pkt to work on
|
|
* @param[out] block ptr to preallocated coap_block1_t structure
|
|
*
|
|
* @returns 0 if block1 option not present
|
|
* @returns 1 if structure has been filled
|
|
*/
|
|
static inline int coap_get_block1(coap_pkt_t *pkt, coap_block1_t *block)
|
|
{
|
|
return coap_get_block(pkt, block, COAP_OPT_BLOCK1);
|
|
}
|
|
|
|
/**
|
|
* @brief Block2 option getter
|
|
*
|
|
* @param[in] pkt pkt to work on
|
|
* @param[out] block ptr to preallocated coap_block1_t structure
|
|
*
|
|
* @returns 0 if block2 option not present
|
|
* @returns 1 if structure has been filled
|
|
*/
|
|
static inline int coap_get_block2(coap_pkt_t *pkt, coap_block1_t *block)
|
|
{
|
|
return coap_get_block(pkt, block, COAP_OPT_BLOCK2);
|
|
}
|
|
|
|
/**
|
|
* @brief Generic block option getter
|
|
*
|
|
* @param[in] pkt pkt to work on
|
|
* @param[in] option actual block option number to get
|
|
* @param[out] blknum block number
|
|
* @param[out] szx SZX value
|
|
*
|
|
* @returns -1 if option not found
|
|
* @returns 0 if more flag is not set
|
|
* @returns 1 if more flag is set
|
|
*/
|
|
int coap_get_blockopt(coap_pkt_t *pkt, uint16_t option, uint32_t *blknum, uint8_t *szx);
|
|
|
|
/**
|
|
* @brief Check whether any of the packet's options that are critical
|
|
*
|
|
* (i.e must be understood by the receiver, indicated by a 1 in the option number's least
|
|
* significant bit) were not accessed since the packet was parsed.
|
|
*
|
|
* Call this in a server on requests after all their option processing has happened,
|
|
* and stop processing the request if it returns true, returning a 4.02 Bad Option response.
|
|
*
|
|
* Call this in a client when receiving a response before acting on it;
|
|
* consider the response unprocessable if it returns true.
|
|
*
|
|
* @param[in] pkt pkt to work on
|
|
*
|
|
* @returns true if any of the options marked as critical at parse time have not been accessed.
|
|
* @returns false if there are no critical options, or all have been accessed.
|
|
*/
|
|
bool coap_has_unprocessed_critical_options(const coap_pkt_t *pkt);
|
|
|
|
/**
|
|
* @brief Helper to decode SZX value to size in bytes
|
|
*
|
|
* @param[in] szx SZX value to decode
|
|
*
|
|
* @returns SZX value decoded to bytes
|
|
*/
|
|
#define coap_szx2size(szx) (1U << ((szx) + 4))
|
|
|
|
/**
|
|
* @brief Helper to encode byte size into next equal or smaller SZX value
|
|
*
|
|
* @param[in] len Size in bytes
|
|
*
|
|
* @returns closest SZX value that fits into a buffer of @p len
|
|
*/
|
|
static inline unsigned coap_size2szx(unsigned len)
|
|
{
|
|
assert(len >= 16);
|
|
return bitarithm_msb(len >> 4);
|
|
}
|
|
/**@}*/
|
|
|
|
/**
|
|
* @name Functions -- Options Write Packet API
|
|
* @anchor net_nanocoap_opt_add
|
|
*
|
|
* Use a coap_pkt_t struct to manage writing Options to the PDU.
|
|
*
|
|
* The caller must monitor space remaining in the buffer; however, the API
|
|
* *will not* write past the end of the buffer, and returns -ENOSPC when it is
|
|
* full.
|
|
*/
|
|
/**@{*/
|
|
/**
|
|
* @brief Add block option in descriptive use from a slicer object
|
|
*
|
|
* When calling this function to initialize a packet with a block option, the
|
|
* more flag must be set to prevent the creation of an option with a length too
|
|
* small to contain the size bit.
|
|
|
|
* @post pkt.payload advanced to first byte after option
|
|
* @post pkt.payload_len reduced by option length
|
|
*
|
|
* @param[in,out] pkt pkt referencing target buffer
|
|
* @param[in] slicer coap blockwise slicer helper struct
|
|
* @param[in] more more flag (1 or 0)
|
|
* @param[in] option option number (block1 or block2)
|
|
*
|
|
* @return number of bytes written to buffer
|
|
* @return <0 on error
|
|
* @return -ENOSPC if no available options or insufficient buffer space
|
|
*/
|
|
ssize_t coap_opt_add_block(coap_pkt_t *pkt, coap_block_slicer_t *slicer,
|
|
bool more, uint16_t option);
|
|
|
|
/**
|
|
* @brief Add block1 option in descriptive use from a slicer object
|
|
*
|
|
* When calling this function to initialize a packet with a block option, the
|
|
* more flag must be set to prevent the creation of an option with a length too
|
|
* small to contain the size bit.
|
|
|
|
* @post pkt.payload advanced to first byte after option
|
|
* @post pkt.payload_len reduced by option length
|
|
*
|
|
* @param[in,out] pkt pkt referencing target buffer
|
|
* @param[in] slicer coap blockwise slicer helper struct
|
|
* @param[in] more more flag (1 or 0)
|
|
*
|
|
* @return number of bytes written to buffer
|
|
* @return <0 on error
|
|
* @return -ENOSPC if no available options or insufficient buffer space
|
|
*/
|
|
static inline ssize_t coap_opt_add_block1(coap_pkt_t *pkt,
|
|
coap_block_slicer_t *slicer, bool more)
|
|
{
|
|
return coap_opt_add_block(pkt, slicer, more, COAP_OPT_BLOCK1);
|
|
}
|
|
|
|
/**
|
|
* @brief Add block2 option in descriptive use from a slicer object
|
|
*
|
|
* When calling this function to initialize a packet with a block option, the
|
|
* more flag must be set to prevent the creation of an option with a length too
|
|
* small to contain the size bit.
|
|
|
|
* @post pkt.payload advanced to first byte after option
|
|
* @post pkt.payload_len reduced by option length
|
|
*
|
|
* @param[in,out] pkt pkt referencing target buffer
|
|
* @param[in] slicer coap blockwise slicer helper struct
|
|
* @param[in] more more flag (1 or 0)
|
|
*
|
|
* @return number of bytes written to buffer
|
|
* @return <0 on error
|
|
* @return -ENOSPC if no available options or insufficient buffer space
|
|
*/
|
|
static inline ssize_t coap_opt_add_block2(coap_pkt_t *pkt,
|
|
coap_block_slicer_t *slicer, bool more)
|
|
{
|
|
return coap_opt_add_block(pkt, slicer, more, COAP_OPT_BLOCK2);
|
|
}
|
|
/**
|
|
* @brief Encode the given uint option into pkt
|
|
*
|
|
* @post pkt.payload advanced to first byte after option
|
|
* @post pkt.payload_len reduced by option length
|
|
*
|
|
* @param[in,out] pkt pkt referencing target buffer
|
|
* @param[in] optnum option number to use
|
|
* @param[in] value uint to encode
|
|
*
|
|
* @return number of bytes written to buffer
|
|
* @return <0 on error
|
|
* @return -ENOSPC if no available options or insufficient buffer space
|
|
*/
|
|
ssize_t coap_opt_add_uint(coap_pkt_t *pkt, uint16_t optnum, uint32_t value);
|
|
|
|
/**
|
|
* @brief Encode the given block1 option in control use
|
|
*
|
|
* @post pkt.payload advanced to first byte after option
|
|
* @post pkt.payload_len reduced by option length
|
|
*
|
|
* @param[in,out] pkt pkt referencing target buffer
|
|
* @param[in] block block to encode
|
|
*
|
|
* @return number of bytes written to buffer
|
|
* @return <0 on error
|
|
* @return -ENOSPC if no available options or insufficient buffer space
|
|
*/
|
|
static inline ssize_t coap_opt_add_block1_control(coap_pkt_t *pkt, coap_block1_t *block) {
|
|
return coap_opt_add_uint(pkt, COAP_OPT_BLOCK1,
|
|
(block->blknum << 4) | block->szx | (block->more ? 0x8 : 0));
|
|
}
|
|
|
|
/**
|
|
* @brief Encode the given block2 option in control use
|
|
*
|
|
* @post pkt.payload advanced to first byte after option
|
|
* @post pkt.payload_len reduced by option length
|
|
*
|
|
* @param[in,out] pkt pkt referencing target buffer
|
|
* @param[in] block block to encode
|
|
*
|
|
* @return number of bytes written to buffer
|
|
* @return <0 on error
|
|
* @return -ENOSPC if no available options or insufficient buffer space
|
|
*/
|
|
static inline ssize_t coap_opt_add_block2_control(coap_pkt_t *pkt, coap_block1_t *block) {
|
|
/* block.more must be zero, so no need to 'or' it in */
|
|
return coap_opt_add_uint(pkt, COAP_OPT_BLOCK2,
|
|
(block->blknum << 4) | block->szx);
|
|
}
|
|
|
|
/**
|
|
* @brief Append an Accept option to the pkt buffer
|
|
*
|
|
* @post pkt.payload advanced to first byte after option
|
|
* @post pkt.payload_len reduced by option length
|
|
*
|
|
* @param[in,out] pkt pkt referencing target buffer
|
|
* @param[in] format COAP_FORMAT_xxx to accept
|
|
*
|
|
* @return number of bytes written to buffer
|
|
* @return <0 on error
|
|
* @return -ENOSPC if no available options or insufficient buffer space
|
|
*/
|
|
static inline ssize_t coap_opt_add_accept(coap_pkt_t *pkt, uint16_t format)
|
|
{
|
|
return coap_opt_add_uint(pkt, COAP_OPT_ACCEPT, format);
|
|
}
|
|
|
|
/**
|
|
* @brief Append a Content-Format option to the pkt buffer
|
|
*
|
|
* @post pkt.payload advanced to first byte after option
|
|
* @post pkt.payload_len reduced by option length
|
|
*
|
|
* @param[in,out] pkt pkt referencing target buffer
|
|
* @param[in] format COAP_FORMAT_xxx to use
|
|
*
|
|
* @return number of bytes written to buffer
|
|
* @return <0 on error
|
|
* @return -ENOSPC if no available options or insufficient buffer space
|
|
*/
|
|
static inline ssize_t coap_opt_add_format(coap_pkt_t *pkt, uint16_t format)
|
|
{
|
|
return coap_opt_add_uint(pkt, COAP_OPT_CONTENT_FORMAT, format);
|
|
}
|
|
|
|
/**
|
|
* @brief Encode the given buffer as an opaque data option into pkt
|
|
*
|
|
* @post pkt.payload advanced to first byte after option(s)
|
|
* @post pkt.payload_len reduced by option(s) length
|
|
*
|
|
* @param[in,out] pkt pkt referencing target buffer
|
|
* @param[in] optnum option number to use
|
|
* @param[in] val pointer to the value to be set
|
|
* @param[in] val_len length of val
|
|
*
|
|
* @return number of bytes written to buffer
|
|
* @return <0 on error
|
|
* @return -ENOSPC if no available options
|
|
*/
|
|
ssize_t coap_opt_add_opaque(coap_pkt_t *pkt, uint16_t optnum, const void *val, size_t val_len);
|
|
|
|
/**
|
|
* @brief Adds a single Uri-Query option in the form 'key=value' into pkt
|
|
*
|
|
*
|
|
* @param[in,out] pkt Packet being built
|
|
* @param[in] key Key to add to the query string
|
|
* @param[in] key_len Length of @p key
|
|
* @param[in] val Value to assign to @p key (may be NULL)
|
|
* @param[in] val_len Length of @p val. 0 if @p val is NULL
|
|
*
|
|
* @pre ((pkt != NULL) && (key != NULL) && (key_len > 0)
|
|
* && ((val_len == 0) || ((val != NULL) && (val_len > 0))))
|
|
*
|
|
* @return number of bytes written to pkt buffer
|
|
* @return <0 on error
|
|
* @return -ENOSPC if no available options or pkt full
|
|
*/
|
|
ssize_t coap_opt_add_uri_query2(coap_pkt_t *pkt, const char *key, size_t key_len,
|
|
const char *val, size_t val_len);
|
|
|
|
/**
|
|
* @brief Adds a single Uri-Query option in the form 'key=value' into pkt
|
|
*
|
|
* @note Use this only for null-terminated string. See @ref coap_opt_add_uri_query2()
|
|
* for non null-terminated string.
|
|
*
|
|
* @param[in,out] pkt Packet being built
|
|
* @param[in] key Key to add to the query string
|
|
* @param[in] val Value to assign to @p key (may be NULL)
|
|
*
|
|
* @pre ((pkt != NULL) && (key != NULL))
|
|
*
|
|
* @return number of bytes written to pkt buffer
|
|
* @return <0 on error
|
|
* @return -ENOSPC if no available options or pkt full
|
|
*/
|
|
static inline ssize_t coap_opt_add_uri_query(coap_pkt_t *pkt, const char *key,
|
|
const char *val)
|
|
{
|
|
return coap_opt_add_uri_query2(pkt, key, strlen(key), val, val ? strlen(val) : 0);
|
|
}
|
|
|
|
/**
|
|
* @brief Adds a single Proxy-URI option into @p pkt
|
|
*
|
|
* @note @p uri must be a NULL-terminated absolute URI
|
|
*
|
|
* @param[in,out] pkt Packet being built
|
|
* @param[in] uri absolute proxy URI
|
|
*
|
|
* @pre ((pkt != NULL) && (uri != NULL))
|
|
*
|
|
* @return number of bytes written to pkt buffer
|
|
* @return <0 on error
|
|
* @return -ENOSPC if no available options or pkt full
|
|
*/
|
|
ssize_t coap_opt_add_proxy_uri(coap_pkt_t *pkt, const char *uri);
|
|
|
|
/**
|
|
* @brief Encode the given array of characters as option(s) into pkt
|
|
*
|
|
* Use separator to split array of characters into multiple options.
|
|
*
|
|
* @post pkt.payload advanced to first byte after option(s)
|
|
* @post pkt.payload_len reduced by option(s) length
|
|
*
|
|
* @param[in,out] pkt pkt referencing target buffer
|
|
* @param[in] optnum option number to use
|
|
* @param[in] chars array of characters to encode as option
|
|
* @param[in] chars_len length of @p chars
|
|
* @param[in] separator character used in @p string to separate parts
|
|
*
|
|
* @return number of bytes written to buffer
|
|
* @return <0 on error
|
|
* @return -ENOSPC if no available options or insufficient buffer space
|
|
*/
|
|
ssize_t coap_opt_add_chars(coap_pkt_t *pkt, uint16_t optnum, const char *chars,
|
|
size_t chars_len, char separator);
|
|
|
|
/**
|
|
* @brief Encode the given string as option(s) into pkt
|
|
*
|
|
* Use separator to split string into multiple options.
|
|
*
|
|
* @post pkt.payload advanced to first byte after option(s)
|
|
* @post pkt.payload_len reduced by option(s) length
|
|
*
|
|
* @param[in,out] pkt pkt referencing target buffer
|
|
* @param[in] optnum option number to use
|
|
* @param[in] string string to encode as option
|
|
* @param[in] separator character used in @p string to separate parts
|
|
*
|
|
* @return number of bytes written to buffer
|
|
* @return <0 on error
|
|
* @return -ENOSPC if no available options or insufficient buffer space
|
|
*/
|
|
static inline ssize_t coap_opt_add_string(coap_pkt_t *pkt, uint16_t optnum,
|
|
const char *string, char separator)
|
|
{
|
|
return coap_opt_add_chars(pkt, optnum, string, strlen(string), separator);
|
|
}
|
|
|
|
/**
|
|
* @brief Adds one or multiple Uri-Path options in the form '/path' into pkt
|
|
*
|
|
* @note Use this only for null-terminated strings.
|
|
*
|
|
* @param[in,out] pkt Packet being built
|
|
* @param[in] path `\0`-terminated resource (sub)path
|
|
*
|
|
* @pre ((pkt != NULL) && (path != NULL))
|
|
*
|
|
* @return number of bytes written to pkt buffer
|
|
* @return <0 on error
|
|
* @return -ENOSPC if no available options or pkt full
|
|
*/
|
|
static inline ssize_t coap_opt_add_uri_path(coap_pkt_t *pkt, const char *path)
|
|
{
|
|
return coap_opt_add_string(pkt, COAP_OPT_URI_PATH, path, '/');
|
|
}
|
|
|
|
/**
|
|
* @brief Adds one or multiple Uri-Path options in the form '/path' into pkt
|
|
*
|
|
* @note Use this only for null-terminated strings.
|
|
*
|
|
* @param[in,out] pkt Packet being built
|
|
* @param[in] path Resource (sub)path
|
|
* @param[in] path_len Length of @p path
|
|
*
|
|
* @pre ((pkt != NULL) && (path != NULL))
|
|
*
|
|
* @return number of bytes written to pkt buffer
|
|
* @return <0 on error
|
|
* @return -ENOSPC if no available options or pkt full
|
|
*/
|
|
static inline ssize_t coap_opt_add_uri_path_buffer(coap_pkt_t *pkt,
|
|
const char *path,
|
|
size_t path_len)
|
|
{
|
|
return coap_opt_add_chars(pkt, COAP_OPT_URI_PATH, path, path_len, '/');
|
|
}
|
|
|
|
/**
|
|
* @brief Finalizes options as required and prepares for payload
|
|
*
|
|
* @post pkt.payload advanced to first available byte after options
|
|
* @post pkt.payload_len is maximum bytes available for payload
|
|
*
|
|
* @param[in,out] pkt pkt to update
|
|
* @param[in] flags see COAP_OPT_FINISH... macros
|
|
*
|
|
* @return total number of bytes written to buffer
|
|
* @return -ENOSPC if no buffer space for payload marker
|
|
*/
|
|
ssize_t coap_opt_finish(coap_pkt_t *pkt, uint16_t flags);
|
|
|
|
/**
|
|
* @brief Removes an option previously added with function in
|
|
* [the coap_opt_add_...() group](@ref net_nanocoap_opt_add)
|
|
*
|
|
* @param[in] pkt Packet to remove option from.
|
|
* @param[in] optnum Option number of the option to remove. If the option appears more than once,
|
|
* the first occurrence will be removed
|
|
*
|
|
* @pre pkt != NULL
|
|
* @pre The packet was finished using @ref coap_opt_finish() and any payload is in its final
|
|
* configuration.
|
|
*
|
|
* @return The new size of the packet with option of number @p optnum removed. In turn this means
|
|
* if there is no such option in the packet, the original size of the packet will be
|
|
* removed.
|
|
* @return -EINVAL if there was a parsing error for the existing options
|
|
*/
|
|
ssize_t coap_opt_remove(coap_pkt_t *pkt, uint16_t optnum);
|
|
/**@}*/
|
|
|
|
/**
|
|
* @name Functions -- Options Write Buffer API
|
|
*
|
|
* Write PDU Options directly to the array of bytes for a message.
|
|
*
|
|
* The caller must provide the last option number written as well as the buffer
|
|
* position. The caller is primarily responsible for tracking and managing the
|
|
* space remaining in the buffer.
|
|
*/
|
|
/**@{*/
|
|
/**
|
|
* @brief Insert block option into buffer
|
|
*
|
|
* When calling this function to initialize a packet with a block option, the
|
|
* more flag must be set to prevent the creation of an option with a length too
|
|
* small to contain the size bit.
|
|
*
|
|
* @param[out] buf buffer to write to
|
|
* @param[in] lastonum number of previous option, must be < @p option
|
|
* @param[in] slicer coap blockwise slicer helper struct
|
|
* @param[in] more more flag (1 or 0)
|
|
* @param[in] option option number (block1 or block2)
|
|
*
|
|
* @returns amount of bytes written to @p buf
|
|
*/
|
|
size_t coap_opt_put_block(uint8_t *buf, uint16_t lastonum, coap_block_slicer_t *slicer,
|
|
bool more, uint16_t option);
|
|
|
|
/**
|
|
* @brief Insert block1 option into buffer
|
|
*
|
|
* When calling this function to initialize a packet with a block1 option, the
|
|
* more flag must be set to prevent the creation of an option with a length too
|
|
* small to contain the size bit.
|
|
*
|
|
* @param[out] buf buffer to write to
|
|
* @param[in] lastonum number of previous option (for delta calculation),
|
|
* must be < 27
|
|
* @param[in] slicer coap blockwise slicer helper struct
|
|
* @param[in] more more flag (1 or 0)
|
|
*
|
|
* @returns amount of bytes written to @p buf
|
|
*/
|
|
static inline size_t coap_opt_put_block1(uint8_t *buf, uint16_t lastonum,
|
|
coap_block_slicer_t *slicer, bool more)
|
|
{
|
|
return coap_opt_put_block(buf, lastonum, slicer, more, COAP_OPT_BLOCK1);
|
|
}
|
|
|
|
/**
|
|
* @brief Insert block2 option into buffer
|
|
*
|
|
* When calling this function to initialize a packet with a block2 option, the
|
|
* more flag must be set to prevent the creation of an option with a length too
|
|
* small to contain the size bit.
|
|
*
|
|
* @param[out] buf buffer to write to
|
|
* @param[in] lastonum number of previous option (for delta calculation),
|
|
* must be < 23
|
|
* @param[in] slicer coap blockwise slicer helper struct
|
|
* @param[in] more more flag (1 or 0)
|
|
*
|
|
* @returns amount of bytes written to @p buf
|
|
*/
|
|
static inline size_t coap_opt_put_block2(uint8_t *buf, uint16_t lastonum,
|
|
coap_block_slicer_t *slicer, bool more)
|
|
{
|
|
return coap_opt_put_block(buf, lastonum, slicer, more, COAP_OPT_BLOCK2);
|
|
}
|
|
|
|
/**
|
|
* @brief Encode the given uint option into buffer
|
|
*
|
|
* @param[out] buf buffer to write to
|
|
* @param[in] lastonum number of previous option (for delta calculation),
|
|
* or 0 for first option
|
|
* @param[in] onum number of option
|
|
* @param[in] value value to encode
|
|
*
|
|
* @returns amount of bytes written to @p buf
|
|
*/
|
|
size_t coap_opt_put_uint(uint8_t *buf, uint16_t lastonum, uint16_t onum,
|
|
uint32_t value);
|
|
|
|
/**
|
|
* @brief Insert block1 option into buffer in control usage
|
|
*
|
|
* @param[in] buf buffer to write to
|
|
* @param[in] lastonum last option number (must be < 27)
|
|
* @param[in] block block option attribute struct
|
|
*
|
|
* @returns amount of bytes written to @p buf
|
|
*/
|
|
static inline size_t coap_opt_put_block1_control(uint8_t *buf, uint16_t lastonum,
|
|
coap_block1_t *block)
|
|
{
|
|
return coap_opt_put_uint(buf, lastonum, COAP_OPT_BLOCK1,
|
|
(block->blknum << 4) | block->szx | (block->more ? 0x8 : 0));
|
|
}
|
|
|
|
/**
|
|
* @brief Insert block2 option into buffer in control usage
|
|
*
|
|
* Forces value of block 'more' attribute to zero, per spec.
|
|
*
|
|
* @param[in] buf buffer to write to
|
|
* @param[in] lastonum last option number (must be < 27)
|
|
* @param[in] block block option attribute struct
|
|
*
|
|
* @returns amount of bytes written to @p buf
|
|
*/
|
|
static inline size_t coap_opt_put_block2_control(uint8_t *buf, uint16_t lastonum,
|
|
coap_block1_t *block)
|
|
{
|
|
/* block.more must be zero, so no need to 'or' it in */
|
|
return coap_opt_put_uint(buf, lastonum, COAP_OPT_BLOCK2,
|
|
(block->blknum << 4) | block->szx);
|
|
}
|
|
|
|
/**
|
|
* @brief Encode the given string as multi-part option into buffer
|
|
*
|
|
* @param[out] buf buffer to write to
|
|
* @param[in] lastonum number of previous option (for delta calculation),
|
|
* or 0 if first option
|
|
* @param[in] optnum option number to use
|
|
* @param[in] string string to encode as option
|
|
* @param[in] len length of the string
|
|
* @param[in] separator character used in @p string to separate parts
|
|
*
|
|
* @return number of bytes written to @p buf
|
|
*/
|
|
size_t coap_opt_put_string_with_len(uint8_t *buf, uint16_t lastonum, uint16_t optnum,
|
|
const char *string, size_t len, char separator);
|
|
/**
|
|
* @brief Encode the given string as multi-part option into buffer
|
|
*
|
|
* @param[out] buf buffer to write to
|
|
* @param[in] lastonum number of previous option (for delta calculation),
|
|
* or 0 if first option
|
|
* @param[in] optnum option number to use
|
|
* @param[in] string string to encode as option
|
|
* @param[in] separator character used in @p string to separate parts
|
|
*
|
|
* @return number of bytes written to @p buf
|
|
*/
|
|
static inline size_t coap_opt_put_string(uint8_t *buf, uint16_t lastonum,
|
|
uint16_t optnum,
|
|
const char *string, char separator)
|
|
{
|
|
return coap_opt_put_string_with_len(buf, lastonum, optnum,
|
|
string, strlen(string), separator);
|
|
}
|
|
|
|
/**
|
|
* @brief Convenience function for inserting LOCATION_PATH option into buffer
|
|
*
|
|
* @param[out] buf buffer to write to
|
|
* @param[in] lastonum number of previous option (for delta calculation),
|
|
* or 0 if first option
|
|
* @param[in] location ptr to string holding the location
|
|
*
|
|
* @returns amount of bytes written to @p buf
|
|
*/
|
|
static inline size_t coap_opt_put_location_path(uint8_t *buf,
|
|
uint16_t lastonum,
|
|
const char *location)
|
|
{
|
|
return coap_opt_put_string(buf, lastonum, COAP_OPT_LOCATION_PATH,
|
|
location, '/');
|
|
}
|
|
|
|
/**
|
|
* @brief Convenience function for inserting LOCATION_QUERY option into buffer
|
|
*
|
|
* @param[out] buf buffer to write to
|
|
* @param[in] lastonum number of previous option (for delta calculation),
|
|
* or 0 if first option
|
|
* @param[in] location ptr to string holding the location
|
|
*
|
|
* @returns amount of bytes written to @p buf
|
|
*/
|
|
static inline size_t coap_opt_put_location_query(uint8_t *buf,
|
|
uint16_t lastonum,
|
|
const char *location)
|
|
{
|
|
return coap_opt_put_string(buf, lastonum, COAP_OPT_LOCATION_QUERY,
|
|
location, '&');
|
|
}
|
|
|
|
/**
|
|
* @brief Convenience function for inserting URI_PATH option into buffer
|
|
*
|
|
* @param[out] buf buffer to write to
|
|
* @param[in] lastonum number of previous option (for delta calculation),
|
|
* or 0 if first option
|
|
* @param[in] uri ptr to source URI
|
|
*
|
|
* @returns amount of bytes written to @p buf
|
|
*/
|
|
static inline size_t coap_opt_put_uri_path(uint8_t *buf, uint16_t lastonum,
|
|
const char *uri)
|
|
{
|
|
return coap_opt_put_string(buf, lastonum, COAP_OPT_URI_PATH, uri, '/');
|
|
}
|
|
|
|
/**
|
|
* @brief Convenience function for inserting URI_QUERY option into buffer
|
|
*
|
|
* @param[out] buf buffer to write to
|
|
* @param[in] lastonum number of previous option (for delta calculation),
|
|
* or 0 if first option
|
|
* @param[in] uri ptr to source URI
|
|
*
|
|
* @returns amount of bytes written to @p buf
|
|
*/
|
|
static inline size_t coap_opt_put_uri_query(uint8_t *buf, uint16_t lastonum,
|
|
const char *uri)
|
|
{
|
|
return coap_opt_put_string(buf, lastonum, COAP_OPT_URI_QUERY, uri, '&');
|
|
}
|
|
|
|
/**
|
|
* @brief Convenience function for inserting URI_PATH and URI_QUERY into buffer
|
|
* This function will automatically split path and query parameters.
|
|
*
|
|
* @param[out] buf buffer to write to
|
|
* @param[in,out] lastonum number of previous option (for delta calculation),
|
|
* or 0 if first option
|
|
* @param[in] uri ptr into a source URI, to the first character after
|
|
* the authority component
|
|
*
|
|
* @returns amount of bytes written to @p buf
|
|
*
|
|
* This function may produce two different options (Uri-Path and Uri-Query).
|
|
* Users that need to insert Content-Format, Max-Age or the currently
|
|
* unassigned option 13 need to split their URI themselves and call the
|
|
* respective helper functions.
|
|
*/
|
|
size_t coap_opt_put_uri_pathquery(uint8_t *buf, uint16_t *lastonum, const char *uri);
|
|
|
|
/**
|
|
* @brief Convenience function for inserting PROXY_URI option into buffer
|
|
*
|
|
* @param[out] buf buffer to write to
|
|
* @param[in] lastonum number of previous option (for delta calculation),
|
|
* or 0 if first option
|
|
* @param[in] uri ptr to source URI
|
|
*
|
|
* @returns amount of bytes written to @p buf
|
|
*/
|
|
static inline size_t coap_opt_put_proxy_uri(uint8_t *buf, uint16_t lastonum,
|
|
const char *uri)
|
|
{
|
|
return coap_opt_put_string(buf, lastonum, COAP_OPT_PROXY_URI, uri, '\0');
|
|
}
|
|
|
|
/**
|
|
* @brief Insert block1 option into buffer (from coap_block1_t)
|
|
*
|
|
* This function is wrapper around @ref coap_put_option_block1(),
|
|
* taking its arguments from a coap_block1_t struct.
|
|
*
|
|
* It will write option Nr. 27 (COAP_OPT_BLOCK1).
|
|
*
|
|
* It is safe to be called when @p block1 was generated for a non-blockwise
|
|
* request.
|
|
*
|
|
* @param[in] pkt_pos buffer to write to
|
|
* @param[in] block1 ptr to block1 struct (created by coap_get_block1())
|
|
* @param[in] lastonum last option number (must be < 27)
|
|
*
|
|
* @returns amount of bytes written to @p pkt_pos
|
|
*/
|
|
size_t coap_put_block1_ok(uint8_t *pkt_pos, coap_block1_t *block1, uint16_t lastonum);
|
|
|
|
/**
|
|
* @brief Insert a CoAP option into buffer
|
|
*
|
|
* This function writes a CoAP option with nr. @p onum to @p buf.
|
|
* It handles calculating the option delta (from @p lastonum), encoding the
|
|
* length from @p olen and copying the option data from @p odata.
|
|
*
|
|
* @param[out] buf buffer to write to
|
|
* @param[in] lastonum number of previous option (for delta calculation),
|
|
* or 0 for first option
|
|
* @param[in] onum number of option
|
|
* @param[in] odata ptr to raw option data (or NULL)
|
|
* @param[in] olen length of @p odata (if any)
|
|
*
|
|
* @returns amount of bytes written to @p buf
|
|
*/
|
|
size_t coap_put_option(uint8_t *buf, uint16_t lastonum, uint16_t onum, const void *odata, size_t olen);
|
|
|
|
/**
|
|
* @brief Insert block1 option into buffer
|
|
*
|
|
* @param[out] buf buffer to write to
|
|
* @param[in] lastonum number of previous option (for delta calculation),
|
|
* must be < 27
|
|
* @param[in] blknum block number
|
|
* @param[in] szx SXZ value
|
|
* @param[in] more more flag (1 or 0)
|
|
*
|
|
* @returns amount of bytes written to @p buf
|
|
*/
|
|
static inline size_t coap_put_option_block1(uint8_t *buf, uint16_t lastonum,
|
|
unsigned blknum, unsigned szx, int more)
|
|
{
|
|
return coap_opt_put_uint(buf, lastonum, COAP_OPT_BLOCK1,
|
|
(blknum << 4) | szx | (more ? 0x8 : 0));
|
|
}
|
|
|
|
/**
|
|
* @brief Insert content type option into buffer
|
|
*
|
|
* @param[out] buf buffer to write to
|
|
* @param[in] lastonum number of previous option (for delta
|
|
* calculation), or 0 if first option
|
|
* @param[in] content_type content type to set
|
|
*
|
|
* @returns amount of bytes written to @p buf
|
|
*/
|
|
static inline size_t coap_put_option_ct(uint8_t *buf, uint16_t lastonum,
|
|
uint16_t content_type)
|
|
{
|
|
return coap_opt_put_uint(buf, lastonum, COAP_OPT_CONTENT_FORMAT, content_type);
|
|
}
|
|
/**@}*/
|
|
|
|
/**
|
|
* @name Functions -- Messaging
|
|
*
|
|
* Functions to support sending and receiving messages.
|
|
*/
|
|
/**@{*/
|
|
/**
|
|
* @brief Build reply to CoAP block2 request
|
|
*
|
|
* This function can be used to create a reply to a CoAP block2 request
|
|
* packet. In addition to @ref coap_build_reply, this function checks the
|
|
* block2 option and returns an error message to the client if necessary.
|
|
*
|
|
* @param[in] pkt packet to reply to
|
|
* @param[in] code reply code (e.g., COAP_CODE_204)
|
|
* @param[out] rbuf buffer to write reply to
|
|
* @param[in] rlen size of @p rbuf
|
|
* @param[in] payload_len length of payload
|
|
* @param[in] slicer slicer to use
|
|
*
|
|
* @returns size of reply packet on success
|
|
* @returns <0 on error
|
|
*/
|
|
ssize_t coap_block2_build_reply(coap_pkt_t *pkt, unsigned code,
|
|
uint8_t *rbuf, unsigned rlen, unsigned payload_len,
|
|
coap_block_slicer_t *slicer);
|
|
|
|
/**
|
|
* @brief Builds a CoAP header
|
|
*
|
|
* Caller *must* ensure @p hdr can hold the header and the full token!
|
|
*
|
|
* @param[out] hdr hdr to fill
|
|
* @param[in] type CoAP packet type (e.g., COAP_TYPE_CON, ...)
|
|
* @param[in] token token
|
|
* @param[in] token_len length of @p token
|
|
* @param[in] code CoAP code (e.g., COAP_CODE_204, ...)
|
|
* @param[in] id CoAP request id
|
|
*
|
|
* @returns length of resulting header
|
|
*/
|
|
ssize_t coap_build_hdr(coap_hdr_t *hdr, unsigned type, uint8_t *token,
|
|
size_t token_len, unsigned code, uint16_t id);
|
|
|
|
/**
|
|
* @brief Build reply to CoAP request
|
|
*
|
|
* This function can be used to create a reply to any CoAP request packet. It
|
|
* will create the reply packet header based on parameters from the request
|
|
* (e.g., id, token).
|
|
*
|
|
* Passing a non-zero @p payload_len will ensure the payload fits into the
|
|
* buffer along with the header. For this validation, payload_len must include
|
|
* any options, the payload marker, as well as the payload proper.
|
|
*
|
|
* @param[in] pkt packet to reply to
|
|
* @param[in] code reply code (e.g., COAP_CODE_204)
|
|
* @param[out] rbuf buffer to write reply to
|
|
* @param[in] rlen size of @p rbuf
|
|
* @param[in] payload_len length of payload
|
|
*
|
|
* @returns size of reply packet on success
|
|
*
|
|
* Note that this size can be severely shortened if due to a No-Response option there
|
|
* is only an empty ACK to be sent back. The caller may just continue populating the
|
|
* payload (the space was checked to suffice), but may also skip that needless step
|
|
* if the returned length is less than the requested payload length.
|
|
*
|
|
* @returns 0 if no response should be sent due to a No-Response option in the request
|
|
* @returns <0 on error
|
|
* @returns -ENOSPC if @p rbuf too small
|
|
*/
|
|
ssize_t coap_build_reply(coap_pkt_t *pkt, unsigned code,
|
|
uint8_t *rbuf, unsigned rlen, unsigned payload_len);
|
|
|
|
/**
|
|
* @brief Handle incoming CoAP request
|
|
*
|
|
* This function will find the correct handler, call it and write the reply
|
|
* into @p resp_buf.
|
|
*
|
|
* @param[in] pkt pointer to (parsed) CoAP packet
|
|
* @param[out] resp_buf buffer for response
|
|
* @param[in] resp_buf_len size of response buffer
|
|
* @param[in] ctx CoAP request context information
|
|
*
|
|
* @returns size of reply packet on success
|
|
* @returns <0 on error
|
|
*/
|
|
ssize_t coap_handle_req(coap_pkt_t *pkt, uint8_t *resp_buf, unsigned resp_buf_len,
|
|
coap_request_ctx_t *ctx);
|
|
|
|
/**
|
|
* @brief Pass a coap request to a matching handler
|
|
*
|
|
* This function will try to find a matching handler in @p resources and call
|
|
* the handler.
|
|
*
|
|
* @param[in] pkt pointer to (parsed) CoAP packet
|
|
* @param[out] resp_buf buffer for response
|
|
* @param[in] resp_buf_len size of response buffer
|
|
* @param[in] ctx CoAP request context information
|
|
* @param[in] resources Array of coap endpoint resources
|
|
* @param[in] resources_numof length of the coap endpoint resources
|
|
*
|
|
* @returns size of the reply packet on success
|
|
* @returns <0 on error
|
|
*/
|
|
ssize_t coap_tree_handler(coap_pkt_t *pkt, uint8_t *resp_buf,
|
|
unsigned resp_buf_len, coap_request_ctx_t *ctx,
|
|
const coap_resource_t *resources,
|
|
size_t resources_numof);
|
|
|
|
/**
|
|
* @brief Generic coap subtree handler
|
|
*
|
|
* This function can be used as a generic handler for resources with the
|
|
* @ref COAP_MATCH_SUBTREE where a new @ref coap_resource_t is to be parsed.
|
|
*
|
|
* @note The @p context must be of type @ref coap_resource_subtree_t.
|
|
*
|
|
* @param[in] pkt pointer to (parsed) CoAP packet
|
|
* @param[out] resp_buf buffer for response
|
|
* @param[in] resp_buf_len size of response buffer
|
|
* @param[in] context pointer to request context, must contain context
|
|
* to @ref coap_resource_subtree_t instance
|
|
*
|
|
* @returns size of the reply packet on success
|
|
* @returns <0 on error
|
|
*/
|
|
ssize_t coap_subtree_handler(coap_pkt_t *pkt, uint8_t *resp_buf,
|
|
size_t resp_buf_len, coap_request_ctx_t *context);
|
|
|
|
/**
|
|
* @brief Convert message code (request method) into a corresponding bit field
|
|
*
|
|
* @param[in] code request code denoting the request method
|
|
*
|
|
* @returns bit field corresponding to the given request method
|
|
*/
|
|
static inline coap_method_flags_t coap_method2flag(unsigned code)
|
|
{
|
|
return (1 << (code - 1));
|
|
}
|
|
|
|
/**
|
|
* @brief Parse a CoAP PDU
|
|
*
|
|
* This function parses a raw CoAP PDU from @p buf with size @p len and fills
|
|
* the structure pointed to by @p pkt.
|
|
* @p pkt must point to a preallocated coap_pkt_t structure.
|
|
*
|
|
* @param[out] pkt structure to parse into
|
|
* @param[in] buf pointer to raw packet data
|
|
* @param[in] len length of packet at @p buf
|
|
*
|
|
* @returns 0 on success
|
|
* @returns <0 on error
|
|
*/
|
|
int coap_parse(coap_pkt_t *pkt, uint8_t *buf, size_t len);
|
|
|
|
/**
|
|
* @brief Initialize a packet struct, to build a message buffer
|
|
*
|
|
* @pre buf CoAP header already initialized
|
|
* @post pkt.flags all zeroed
|
|
* @post pkt.payload points to first byte after header
|
|
* @post pkt.payload_len set to maximum space available for options + payload
|
|
*
|
|
* @param[out] pkt pkt to initialize
|
|
* @param[in] buf buffer to write for pkt, with CoAP header already
|
|
* initialized
|
|
* @param[in] len length of buf
|
|
* @param[in] header_len length of header in buf, including token
|
|
*/
|
|
void coap_pkt_init(coap_pkt_t *pkt, uint8_t *buf, size_t len, size_t header_len);
|
|
|
|
/**
|
|
* @brief Advance the payload pointer.
|
|
*
|
|
* @pre You added @p len bytes of data to `pkt->payload`.
|
|
*
|
|
* You can add payload to a CoAP request by writing data directly to
|
|
* `pkt->payload`.
|
|
* This convenience function takes care of advancing the payload pointer
|
|
* afterwards.
|
|
*
|
|
* @param[out] pkt pkt to which payload was added
|
|
* @param[in] len length of payload
|
|
*/
|
|
static inline void coap_payload_advance_bytes(coap_pkt_t *pkt, size_t len)
|
|
{
|
|
pkt->payload += len;
|
|
pkt->payload_len -= len;
|
|
}
|
|
|
|
/**
|
|
* @brief Add payload data to the CoAP request.
|
|
*
|
|
* @pre @ref coap_opt_finish must have been called before with
|
|
* the @ref COAP_OPT_FINISH_PAYLOAD option.
|
|
*
|
|
* The function copies @p data into the payload buffer of @p pkt and
|
|
* advances the payload pointer.
|
|
*
|
|
* This is just a convenience function, you can also directly write
|
|
* to `pkt->payload` if you have a function that outputs payload to
|
|
* a buffer.
|
|
* In this case you should instead call @ref coap_payload_advance_bytes.
|
|
*
|
|
* @param[out] pkt pkt to add payload to
|
|
* @param[in] data payload data
|
|
* @param[in] len length of payload
|
|
*
|
|
* @returns number of payload bytes added on success
|
|
* @returns < 0 on error
|
|
*/
|
|
ssize_t coap_payload_put_bytes(coap_pkt_t *pkt, const void *data, size_t len);
|
|
|
|
/**
|
|
* @brief Add a single character to the payload data of the CoAP request
|
|
*
|
|
* This function is used to add single characters to a CoAP payload data. It
|
|
* checks whether the character can be added to the buffer and ignores if the
|
|
* payload area is already exhausted.
|
|
*
|
|
* @param[out] pkt pkt to add payload to
|
|
* @param[in] c character to write
|
|
*
|
|
* @returns number of payload bytes added on success (always one)
|
|
* @returns < 0 on error
|
|
*/
|
|
ssize_t coap_payload_put_char(coap_pkt_t *pkt, char c);
|
|
|
|
/**
|
|
* @brief Create CoAP reply (convenience function)
|
|
*
|
|
* This is a simple wrapper that allows for building CoAP replies for simple
|
|
* use-cases.
|
|
*
|
|
* The reply will be written to @p buf. If @p payload and @p payload_len are
|
|
* non-zero, the payload will be copied into the resulting reply packet.
|
|
*
|
|
* @param[in] pkt packet to reply to
|
|
* @param[in] code reply code (e.g., COAP_CODE_204)
|
|
* @param[out] buf buffer to write reply to
|
|
* @param[in] len size of @p buf
|
|
* @param[in] ct content type of payload
|
|
* @param[in] payload ptr to payload
|
|
* @param[in] payload_len length of payload
|
|
*
|
|
* @returns size of reply packet on success
|
|
* @returns <0 on error
|
|
* @returns -ENOSPC if @p buf too small
|
|
*/
|
|
ssize_t coap_reply_simple(coap_pkt_t *pkt,
|
|
unsigned code,
|
|
uint8_t *buf, size_t len,
|
|
unsigned ct,
|
|
const void *payload, size_t payload_len);
|
|
|
|
/**
|
|
* @brief Reference to the default .well-known/core handler defined by the
|
|
* application
|
|
*/
|
|
extern ssize_t coap_well_known_core_default_handler(coap_pkt_t *pkt, \
|
|
uint8_t *buf, size_t len,
|
|
coap_request_ctx_t *context);
|
|
/**@}*/
|
|
|
|
/**
|
|
* @brief Respond to `/.well-known/core` to list all resources on the server
|
|
*/
|
|
#ifndef CONFIG_NANOCOAP_SERVER_WELL_KNOWN_CORE
|
|
#define CONFIG_NANOCOAP_SERVER_WELL_KNOWN_CORE !IS_USED(MODULE_GCOAP)
|
|
#endif
|
|
|
|
/**
|
|
* @brief Checks if a CoAP resource path matches a given URI
|
|
*
|
|
* Builds on strcmp() with rules specific to URI path matching
|
|
*
|
|
* @note This function is not intended for application use.
|
|
* @internal
|
|
*
|
|
* @param[in] resource CoAP resource to check
|
|
* @param[in] uri Null-terminated string URI to compare
|
|
*
|
|
* @return 0 if the resource path matches the URI
|
|
* @return <0 if the resource path sorts before the URI
|
|
* @return >0 if the resource path sorts after the URI
|
|
*/
|
|
int coap_match_path(const coap_resource_t *resource, uint8_t *uri);
|
|
|
|
#if defined(MODULE_GCOAP) || defined(DOXYGEN)
|
|
/**
|
|
* @name Functions -- gcoap specific
|
|
*/
|
|
/**@{*/
|
|
/**
|
|
* @brief Identifies a packet containing an observe option
|
|
*
|
|
* @param[in] pkt CoAP packet
|
|
*
|
|
* @returns true if observe value is set
|
|
* @returns false if not
|
|
*/
|
|
static inline bool coap_has_observe(coap_pkt_t *pkt)
|
|
{
|
|
return pkt->observe_value != UINT32_MAX;
|
|
}
|
|
|
|
/**
|
|
* @brief Clears the observe option value from a packet
|
|
*
|
|
* @param[in] pkt CoAP packet
|
|
*/
|
|
static inline void coap_clear_observe(coap_pkt_t *pkt)
|
|
{
|
|
pkt->observe_value = UINT32_MAX;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the value of the observe option from the given packet
|
|
*
|
|
* @param[in] pkt CoAP packet
|
|
*
|
|
* @returns value of the observe option
|
|
*/
|
|
static inline uint32_t coap_get_observe(coap_pkt_t *pkt)
|
|
{
|
|
return pkt->observe_value;
|
|
}
|
|
/**@}*/
|
|
#endif
|
|
|
|
/**
|
|
* @brief Resource definition for the default .well-known/core handler
|
|
*/
|
|
#define COAP_WELL_KNOWN_CORE_DEFAULT_HANDLER \
|
|
{ \
|
|
.path = "/.well-known/core", \
|
|
.methods = COAP_GET, \
|
|
.handler = coap_well_known_core_default_handler \
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
#endif /* NET_NANOCOAP_H */
|
|
/** @} */
|