1
0
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:
Leandro Lanzieri 2019-07-27 22:36:33 +02:00 committed by GitHub
commit a9ab9d37e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 141 additions and 19 deletions

View File

@ -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.
*/

View File

@ -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
*

View File

@ -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];

View File

@ -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
};