diff --git a/sys/include/net/gcoap.h b/sys/include/net/gcoap.h index 375a57c498..0c4c4c2070 100644 --- a/sys/include/net/gcoap.h +++ b/sys/include/net/gcoap.h @@ -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 diff --git a/sys/net/application_layer/coap/gcoap.c b/sys/net/application_layer/coap/gcoap.c index 1284b02c4e..a7fbcdc8dd 100644 --- a/sys/net/application_layer/coap/gcoap.c +++ b/sys/net/application_layer/coap/gcoap.c @@ -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); } /* @@ -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; +} + /** @} */