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)
|
#define ENABLE_DEBUG (0)
|
||||||
#include "debug.h"
|
#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,
|
static void _resp_handler(unsigned req_state, coap_pkt_t* pdu,
|
||||||
sock_udp_ep_t *remote);
|
sock_udp_ep_t *remote);
|
||||||
static ssize_t _stats_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len, void *ctx);
|
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 },
|
{ "/riot/board", COAP_GET, _riot_board_handler, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char *_link_params[] = {
|
||||||
|
";ct=0;rt=\"count\"",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
static gcoap_listener_t _listener = {
|
static gcoap_listener_t _listener = {
|
||||||
&_resources[0],
|
&_resources[0],
|
||||||
sizeof(_resources) / sizeof(_resources[0]),
|
sizeof(_resources) / sizeof(_resources[0]),
|
||||||
|
_encode_link,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Counts requests sent by CLI. */
|
/* Counts requests sent by CLI. */
|
||||||
static uint16_t req_count = 0;
|
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.
|
* Response callback.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -50,7 +50,8 @@
|
|||||||
* [nanocoap](group__net__nanocoap.html) documentation.
|
* [nanocoap](group__net__nanocoap.html) documentation.
|
||||||
*
|
*
|
||||||
* gcoap itself defines a resource for `/.well-known/core` discovery, which
|
* 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 ###
|
* ### Creating a response ###
|
||||||
*
|
*
|
||||||
@ -82,6 +83,16 @@
|
|||||||
* If no payload, call only gcoap_response() to write the full response. If you
|
* 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.
|
* 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 ##
|
||||||
*
|
*
|
||||||
* Client operation includes two phases: creating and sending a request, and
|
* Client operation includes two phases: creating and sending a request, and
|
||||||
@ -449,6 +460,38 @@ extern "C" {
|
|||||||
#define GCOAP_RESEND_BUFS_MAX (1)
|
#define GCOAP_RESEND_BUFS_MAX (1)
|
||||||
#endif
|
#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
|
* @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
|
const coap_resource_t *resources; /**< First element in the array of
|
||||||
* resources; must order alphabetically */
|
* resources; must order alphabetically */
|
||||||
size_t resources_len; /**< Length of array */
|
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 */
|
struct gcoap_listener *next; /**< Next listener in list */
|
||||||
} gcoap_listener_t;
|
} 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);
|
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
|
* @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 = {
|
static gcoap_listener_t _default_listener = {
|
||||||
&_default_resources[0],
|
&_default_resources[0],
|
||||||
sizeof(_default_resources) / sizeof(_default_resources[0]),
|
sizeof(_default_resources) / sizeof(_default_resources[0]),
|
||||||
|
NULL,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -633,6 +634,9 @@ void gcoap_register_listener(gcoap_listener_t *listener)
|
|||||||
}
|
}
|
||||||
|
|
||||||
listener->next = NULL;
|
listener->next = NULL;
|
||||||
|
if (!listener->link_encoder) {
|
||||||
|
listener->link_encoder = gcoap_encode_link;
|
||||||
|
}
|
||||||
_last->next = listener;
|
_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)
|
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);
|
assert(cf == COAP_FORMAT_LINK);
|
||||||
|
|
||||||
/* skip the first listener, gcoap itself (we skip /.well-known/core) */
|
/* 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;
|
char *out = (char *)buf;
|
||||||
size_t pos = 0;
|
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 */
|
/* write payload */
|
||||||
while (listener) {
|
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++) {
|
for (; ctx.link_pos < listener->resources_len; ctx.link_pos++) {
|
||||||
size_t path_len = strlen(resource->path);
|
ssize_t res;
|
||||||
if (out) {
|
if (out) {
|
||||||
/* only add new resources if there is space in the buffer */
|
res = listener->link_encoder(&listener->resources[ctx.link_pos],
|
||||||
if ((pos + path_len + 3) > maxlen) {
|
&out[pos], maxlen - pos, &ctx);
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (pos) {
|
|
||||||
out[pos++] = ',';
|
|
||||||
}
|
|
||||||
out[pos++] = '<';
|
|
||||||
memcpy(&out[pos], resource->path, path_len);
|
|
||||||
pos += path_len;
|
|
||||||
out[pos++] = '>';
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pos += (pos) ? 3 : 2;
|
res = listener->link_encoder(&listener->resources[ctx.link_pos],
|
||||||
pos += path_len;
|
NULL, 0, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res > 0) {
|
||||||
|
pos += res;
|
||||||
|
ctx.flags &= ~COAP_LINK_FLAG_INIT_RESLIST;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
++resource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
listener = listener->next;
|
listener = listener->next;
|
||||||
@ -941,6 +950,31 @@ int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf)
|
|||||||
return (int)pos;
|
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)
|
int gcoap_add_qstring(coap_pkt_t *pdu, const char *key, const char *val)
|
||||||
{
|
{
|
||||||
char qs[NANOCOAP_QS_MAX];
|
char qs[NANOCOAP_QS_MAX];
|
||||||
|
|||||||
@ -38,12 +38,14 @@ static const coap_resource_t resources_second[] = {
|
|||||||
static gcoap_listener_t listener = {
|
static gcoap_listener_t listener = {
|
||||||
.resources = &resources[0],
|
.resources = &resources[0],
|
||||||
.resources_len = (sizeof(resources) / sizeof(resources[0])),
|
.resources_len = (sizeof(resources) / sizeof(resources[0])),
|
||||||
|
.link_encoder = NULL,
|
||||||
.next = NULL
|
.next = NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static gcoap_listener_t listener_second = {
|
static gcoap_listener_t listener_second = {
|
||||||
.resources = &resources_second[0],
|
.resources = &resources_second[0],
|
||||||
.resources_len = (sizeof(resources_second) / sizeof(resources_second[0])),
|
.resources_len = (sizeof(resources_second) / sizeof(resources_second[0])),
|
||||||
|
.link_encoder = NULL,
|
||||||
.next = NULL
|
.next = NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user