Skip to content

Commit

Permalink
Merge pull request #7408 from haukepetersen/opt_gcoap_exportresourcel…
Browse files Browse the repository at this point in the history
…istcreation

net/gcoap: expose creation of resource list to API
  • Loading branch information
miri64 authored Aug 8, 2017
2 parents 2296d63 + 813c92e commit ea4a8e3
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 28 deletions.
20 changes: 20 additions & 0 deletions sys/include/net/gcoap.h
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,26 @@ size_t gcoap_obs_send(const uint8_t *buf, size_t len,
*/
uint8_t gcoap_op_state(void);

/**
* @brief Get the resource list, currently only `CoRE Link Format`
* (COAP_FORMAT_LINK) supported
*
* If @p buf := NULL, nothing will be written but the size of the resulting
* resource list is computed and returned.
*
* @param[out] buf output buffer to write resource list into, my be NULL
* @param[in] maxlen length of @p buf, ignored if @p buf is NULL
* @param[in] cf content format to use for the resource list, currently
* only COAP_FORMAT_LINK supported
*
* @todo add support for `JSON CoRE Link Format`
* @todo add support for 'CBOR CoRE Link Format`
*
* @return the number of bytes written to @p buf
* @return -1 on error
*/
int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf);

#ifdef __cplusplus
}
#endif
Expand Down
76 changes: 48 additions & 28 deletions sys/net/application_layer/coap/gcoap.c
Original file line number Diff line number Diff line change
Expand Up @@ -398,35 +398,10 @@ static ssize_t _well_known_core_handler(coap_pkt_t* pdu, uint8_t *buf, size_t le
{
/* write header */
gcoap_resp_init(pdu, buf, len, COAP_CODE_CONTENT);

/* skip the first listener, gcoap itself */
gcoap_listener_t *listener = _coap_state.listeners->next;

/* write payload */
uint8_t *bufpos = pdu->payload;

while (listener) {
coap_resource_t *resource = listener->resources;
for (size_t i = 0; i < listener->resources_len; i++) {
/* Don't overwrite buffer if paths are too long. */
if (bufpos + strlen(resource->path) + 3 > buf + len) {
break;
}
if (i) {
*bufpos++ = ',';
resource++;
}
*bufpos++ = '<';
unsigned url_len = strlen(resource->path);
memcpy(bufpos, resource->path, url_len);
bufpos += url_len;
*bufpos++ = '>';
}
listener = listener->next;
}

int plen = gcoap_get_resource_list(pdu->payload, (size_t)pdu->payload_len,
COAP_FORMAT_LINK);
/* response content */
return gcoap_finish(pdu, bufpos - pdu->payload, COAP_FORMAT_LINK);
return gcoap_finish(pdu, (size_t)plen, COAP_FORMAT_LINK);
}

/*
Expand Down Expand Up @@ -819,4 +794,49 @@ uint8_t gcoap_op_state(void)
return count;
}

int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf)
{
assert(cf == COAP_CT_LINK_FORMAT);
#ifndef DEVELHELP
(void)cf;
#endif

/* skip the first listener, gcoap itself (we skip /.well-known/core) */
gcoap_listener_t *listener = _coap_state.listeners->next;

char *out = (char *)buf;
size_t pos = 0;

/* write payload */
while (listener) {
coap_resource_t *resource = listener->resources;

for (unsigned i = 0; i < listener->resources_len; i++) {
size_t path_len = strlen(resource->path);
if (out) {
/* only add new resources if there is space in the buffer */
if ((pos + path_len + 3) > maxlen) {
break;
}
if (i) {
out[pos++] = ',';
}
out[pos++] = '<';
memcpy(&out[pos], resource->path, path_len);
pos += path_len;
out[pos++] = '>';
}
else {
pos += (i) ? 3 : 2;
pos += path_len;
}
++resource;
}

listener = listener->next;
}

return (int)pos;
}

/** @} */
42 changes: 42 additions & 0 deletions tests/unittests/tests-gcoap/tests-gcoap.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,23 @@
#include "unittests-constants.h"
#include "tests-gcoap.h"

/*
* A test set of dummy resources. The resource handlers are set to NULL.
*/
static const coap_resource_t ressources[] = {
{ "/test/info/all", (COAP_GET), NULL },
{ "/sensor/temp", (COAP_GET), NULL },
{ "/act/switch", (COAP_GET | COAP_POST), NULL }
};

static gcoap_listener_t listener = {
.resources = (coap_resource_t *)&ressources[0],
.resources_len = (sizeof(ressources) / sizeof(ressources[0])),
.next = NULL
};

static const char *resource_list_str = "</test/info/all>,</sensor/temp>,</act/switch>";

/*
* Client GET request success case. Test request generation.
* Request /time resource from libcoap example
Expand Down Expand Up @@ -226,6 +243,30 @@ static void test_gcoap__server_con_resp(void)
TEST_ASSERT_EQUAL_INT(sizeof(resp_data), res);
}

/*
* Test the export of configured resources as CoRE link format string
*/
static void test_gcoap__server_get_resource_list(void)
{
char res[128];
int size = 0;

gcoap_register_listener(&listener);

size = gcoap_get_resource_list(NULL, 0, COAP_CT_LINK_FORMAT);
TEST_ASSERT_EQUAL_INT(strlen(resource_list_str), size);

res[0] = 'A';
size = gcoap_get_resource_list(res, 0, COAP_CT_LINK_FORMAT);
TEST_ASSERT_EQUAL_INT(0, size);
TEST_ASSERT_EQUAL_INT((int)'A', (int)res[0]);

size = gcoap_get_resource_list(res, 127, COAP_CT_LINK_FORMAT);
res[size] = '\0';
TEST_ASSERT_EQUAL_INT(strlen(resource_list_str), size);
TEST_ASSERT_EQUAL_STRING(resource_list_str, (char *)res);
}

Test *tests_gcoap_tests(void)
{
EMB_UNIT_TESTFIXTURES(fixtures) {
Expand All @@ -235,6 +276,7 @@ Test *tests_gcoap_tests(void)
new_TestFixture(test_gcoap__server_get_resp),
new_TestFixture(test_gcoap__server_con_req),
new_TestFixture(test_gcoap__server_con_resp),
new_TestFixture(test_gcoap__server_get_resource_list)
};

EMB_UNIT_TESTCALLER(gcoap_tests, NULL, NULL, fixtures);
Expand Down

0 comments on commit ea4a8e3

Please sign in to comment.