mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 05:32:45 +01:00
Merge pull request #11765 from kb2ma/coap/encode_resources
net/gcoap: add/publish link format attributes for a resource
This commit is contained in:
commit
a9ab9d37e2
@ -29,6 +29,8 @@
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
static ssize_t _encode_link(const coap_resource_t *resource, char *buf,
|
||||
size_t maxlen, coap_link_encoder_ctx_t *context);
|
||||
static void _resp_handler(unsigned req_state, coap_pkt_t* pdu,
|
||||
sock_udp_ep_t *remote);
|
||||
static ssize_t _stats_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len, void *ctx);
|
||||
@ -40,15 +42,39 @@ static const coap_resource_t _resources[] = {
|
||||
{ "/riot/board", COAP_GET, _riot_board_handler, NULL },
|
||||
};
|
||||
|
||||
static const char *_link_params[] = {
|
||||
";ct=0;rt=\"count\"",
|
||||
NULL
|
||||
};
|
||||
|
||||
static gcoap_listener_t _listener = {
|
||||
&_resources[0],
|
||||
sizeof(_resources) / sizeof(_resources[0]),
|
||||
_encode_link,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Counts requests sent by CLI. */
|
||||
static uint16_t req_count = 0;
|
||||
|
||||
/* Adds link format params to resource list */
|
||||
static ssize_t _encode_link(const coap_resource_t *resource, char *buf,
|
||||
size_t maxlen, coap_link_encoder_ctx_t *context) {
|
||||
ssize_t res = gcoap_encode_link(resource, buf, maxlen, context);
|
||||
if (res > 0) {
|
||||
if (_link_params[context->link_pos]
|
||||
&& (strlen(_link_params[context->link_pos]) < (maxlen - res))) {
|
||||
if (buf) {
|
||||
memcpy(buf+res, _link_params[context->link_pos],
|
||||
strlen(_link_params[context->link_pos]));
|
||||
}
|
||||
return res + strlen(_link_params[context->link_pos]);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Response callback.
|
||||
*/
|
||||
|
@ -50,7 +50,8 @@
|
||||
* [nanocoap](group__net__nanocoap.html) documentation.
|
||||
*
|
||||
* gcoap itself defines a resource for `/.well-known/core` discovery, which
|
||||
* lists all of the registered paths.
|
||||
* lists all of the registered paths. See the _Resource list creation_ section
|
||||
* below for more.
|
||||
*
|
||||
* ### Creating a response ###
|
||||
*
|
||||
@ -82,6 +83,16 @@
|
||||
* If no payload, call only gcoap_response() to write the full response. If you
|
||||
* need to add Options, follow the first three steps in the list above instead.
|
||||
*
|
||||
* ### Resource list creation ###
|
||||
*
|
||||
* gcoap allows customization of the function that provides the list of registered
|
||||
* resources for `/.well-known/core` and CoRE Resource Directory registration.
|
||||
* By default gcoap provides gcoap_encode_link(), which lists only the target
|
||||
* path for each link. However, an application may specify a custom function in
|
||||
* the gcoap_listener_t it registers with gcoap. For example, this function may
|
||||
* add parameters to provide more information about the resource, as described
|
||||
* in RFC 6690. See the gcoap example for use of a custom encoder function.
|
||||
*
|
||||
* ## Client Operation ##
|
||||
*
|
||||
* Client operation includes two phases: creating and sending a request, and
|
||||
@ -449,6 +460,38 @@ extern "C" {
|
||||
#define GCOAP_RESEND_BUFS_MAX (1)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name Bitwise positional flags for encoding resource links
|
||||
* @{
|
||||
*/
|
||||
#define COAP_LINK_FLAG_INIT_RESLIST (1) /**< initialize as for first resource
|
||||
* in a list */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Context information required to write a resource link
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned content_format; /**< link format */
|
||||
size_t link_pos; /**< position of link within listener */
|
||||
uint16_t flags; /**< encoder switches; see GCOAP_LINK_FLAG_*
|
||||
constants */
|
||||
} coap_link_encoder_ctx_t;
|
||||
|
||||
/**
|
||||
* @brief Handler function to write a resource link
|
||||
*
|
||||
* @param[in] resource Resource for link
|
||||
* @param[out] buf Buffer on which to write; may be null
|
||||
* @param[in] maxlen Remaining length for @p buf
|
||||
* @param[in] context Contextual information on what/how to write
|
||||
*
|
||||
* @return count of bytes written to @p buf (or writable if @p buf is null)
|
||||
* @return -1 on error
|
||||
*/
|
||||
typedef ssize_t (*gcoap_link_encoder_t)(const coap_resource_t *resource, char *buf,
|
||||
size_t maxlen, coap_link_encoder_ctx_t *context);
|
||||
|
||||
/**
|
||||
* @brief A modular collection of resources for a server
|
||||
*/
|
||||
@ -456,6 +499,7 @@ typedef struct gcoap_listener {
|
||||
const coap_resource_t *resources; /**< First element in the array of
|
||||
* resources; must order alphabetically */
|
||||
size_t resources_len; /**< Length of array */
|
||||
gcoap_link_encoder_t link_encoder; /**< Writes a link for a resource */
|
||||
struct gcoap_listener *next; /**< Next listener in list */
|
||||
} gcoap_listener_t;
|
||||
|
||||
@ -715,6 +759,22 @@ uint8_t gcoap_op_state(void);
|
||||
*/
|
||||
int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf);
|
||||
|
||||
/**
|
||||
* @brief Writes a resource in CoRE Link Format to a provided buffer.
|
||||
*
|
||||
* This default implementation only writes the resource path.
|
||||
*
|
||||
* @param[in] resource resource to write
|
||||
* @param[out] buf output buffer to write link into, may be null
|
||||
* @param[in] maxlen length of @p buf, ignored if @p buf is NULL
|
||||
* @param[in] context other parameters that affect how link is written
|
||||
*
|
||||
* @return count of bytes written to @p buf (or writable if @p buf is null)
|
||||
* @return -1 on error
|
||||
*/
|
||||
ssize_t gcoap_encode_link(const coap_resource_t *resource, char *buf,
|
||||
size_t maxlen, coap_link_encoder_ctx_t *context);
|
||||
|
||||
/**
|
||||
* @brief Adds a single Uri-Query option to a CoAP request
|
||||
*
|
||||
|
@ -63,6 +63,7 @@ const coap_resource_t _default_resources[] = {
|
||||
static gcoap_listener_t _default_listener = {
|
||||
&_default_resources[0],
|
||||
sizeof(_default_resources) / sizeof(_default_resources[0]),
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -633,6 +634,9 @@ void gcoap_register_listener(gcoap_listener_t *listener)
|
||||
}
|
||||
|
||||
listener->next = NULL;
|
||||
if (!listener->link_encoder) {
|
||||
listener->link_encoder = gcoap_encode_link;
|
||||
}
|
||||
_last->next = listener;
|
||||
}
|
||||
|
||||
@ -900,7 +904,6 @@ uint8_t gcoap_op_state(void)
|
||||
|
||||
int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf)
|
||||
{
|
||||
(void)cf; /* only used in the assert below. */
|
||||
assert(cf == COAP_FORMAT_LINK);
|
||||
|
||||
/* skip the first listener, gcoap itself (we skip /.well-known/core) */
|
||||
@ -909,30 +912,36 @@ int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf)
|
||||
char *out = (char *)buf;
|
||||
size_t pos = 0;
|
||||
|
||||
coap_link_encoder_ctx_t ctx;
|
||||
ctx.content_format = cf;
|
||||
/* indicate initial link for the list */
|
||||
ctx.flags = COAP_LINK_FLAG_INIT_RESLIST;
|
||||
|
||||
/* write payload */
|
||||
while (listener) {
|
||||
const coap_resource_t *resource = listener->resources;
|
||||
if (!listener->link_encoder) {
|
||||
continue;
|
||||
}
|
||||
ctx.link_pos = 0;
|
||||
|
||||
for (unsigned i = 0; i < listener->resources_len; i++) {
|
||||
size_t path_len = strlen(resource->path);
|
||||
for (; ctx.link_pos < listener->resources_len; ctx.link_pos++) {
|
||||
ssize_t res;
|
||||
if (out) {
|
||||
/* only add new resources if there is space in the buffer */
|
||||
if ((pos + path_len + 3) > maxlen) {
|
||||
break;
|
||||
}
|
||||
if (pos) {
|
||||
out[pos++] = ',';
|
||||
}
|
||||
out[pos++] = '<';
|
||||
memcpy(&out[pos], resource->path, path_len);
|
||||
pos += path_len;
|
||||
out[pos++] = '>';
|
||||
res = listener->link_encoder(&listener->resources[ctx.link_pos],
|
||||
&out[pos], maxlen - pos, &ctx);
|
||||
}
|
||||
else {
|
||||
pos += (pos) ? 3 : 2;
|
||||
pos += path_len;
|
||||
res = listener->link_encoder(&listener->resources[ctx.link_pos],
|
||||
NULL, 0, &ctx);
|
||||
}
|
||||
|
||||
if (res > 0) {
|
||||
pos += res;
|
||||
ctx.flags &= ~COAP_LINK_FLAG_INIT_RESLIST;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
++resource;
|
||||
}
|
||||
|
||||
listener = listener->next;
|
||||
@ -941,6 +950,31 @@ int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf)
|
||||
return (int)pos;
|
||||
}
|
||||
|
||||
ssize_t gcoap_encode_link(const coap_resource_t *resource, char *buf,
|
||||
size_t maxlen, coap_link_encoder_ctx_t *context)
|
||||
{
|
||||
size_t path_len = strlen(resource->path);
|
||||
/* count target separators and any link separator */
|
||||
size_t exp_size = path_len + 2
|
||||
+ ((context->flags & COAP_LINK_FLAG_INIT_RESLIST) ? 0 : 1);
|
||||
|
||||
if (buf) {
|
||||
unsigned pos = 0;
|
||||
if (exp_size > maxlen) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(context->flags & COAP_LINK_FLAG_INIT_RESLIST)) {
|
||||
buf[pos++] = ',';
|
||||
}
|
||||
buf[pos++] = '<';
|
||||
memcpy(&buf[pos], resource->path, path_len);
|
||||
buf[pos+path_len] = '>';
|
||||
}
|
||||
|
||||
return exp_size;
|
||||
}
|
||||
|
||||
int gcoap_add_qstring(coap_pkt_t *pdu, const char *key, const char *val)
|
||||
{
|
||||
char qs[NANOCOAP_QS_MAX];
|
||||
|
@ -38,12 +38,14 @@ static const coap_resource_t resources_second[] = {
|
||||
static gcoap_listener_t listener = {
|
||||
.resources = &resources[0],
|
||||
.resources_len = (sizeof(resources) / sizeof(resources[0])),
|
||||
.link_encoder = NULL,
|
||||
.next = NULL
|
||||
};
|
||||
|
||||
static gcoap_listener_t listener_second = {
|
||||
.resources = &resources_second[0],
|
||||
.resources_len = (sizeof(resources_second) / sizeof(resources_second[0])),
|
||||
.link_encoder = NULL,
|
||||
.next = NULL
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user