net/gcoap: Use nanocoap options API

Observe still uses coap_pkt_t attribute.
This commit is contained in:
Ken Bannister 2018-05-16 13:09:40 -04:00
parent fa5ab4eeb6
commit f0b966d65d
2 changed files with 76 additions and 140 deletions

View File

@ -253,26 +253,28 @@ extern "C" {
#endif
/**
* @brief Size of the buffer used to write options, other than Uri-Path, in a
* request
* @brief Reduce payload length by this value for a request created with
* gcoap_req_init()
*
* Accommodates Content-Format and Uri-Queries
* Accommodates writing Content-Format option in gcoap_finish()
*/
#define GCOAP_REQ_OPTIONS_BUF (40)
#define GCOAP_REQ_OPTIONS_BUF (4)
/**
* @brief Size of the buffer used to write options in a response
* @brief Reduce payload length by this value for a respons created with
* gcoap_resp_init()
*
* Accommodates Content-Format.
* Accommodates writing Content-Format option in gcoap_finish()
*/
#define GCOAP_RESP_OPTIONS_BUF (8)
#define GCOAP_RESP_OPTIONS_BUF (4)
/**
* @brief Size of the buffer used to write options in an Observe notification
* @brief Reduce payload length by this value for an observe notification
* created with gcoap_obs_init()
*
* Accommodates Content-Format and Observe.
* Accommodates writing Content-Format option in gcoap_finish()
*/
#define GCOAP_OBS_OPTIONS_BUF (8)
#define GCOAP_OBS_OPTIONS_BUF (4)
/**
* @brief Maximum number of requests awaiting a response
@ -506,6 +508,11 @@ void gcoap_register_listener(gcoap_listener_t *listener);
/**
* @brief Initializes a CoAP request PDU on a buffer.
* @warning After you use this function, you may not add Options with option
* number less than COAP_OPT_URI_PATH. Otherwise, use the struct-based API
* described with @link net_nanocoap nanocoap @endlink to initialize the
* message. See the implementation of gcoap_req_init() itself as an example.
*
* @param[out] pdu Request metadata
* @param[out] buf Buffer containing the PDU
@ -525,8 +532,14 @@ int gcoap_req_init(coap_pkt_t *pdu, uint8_t *buf, size_t len,
/**
* @brief Finishes formatting a CoAP PDU after the payload has been written
*
* Assumes the PDU has been initialized with gcoap_req_init() or
* gcoap_resp_init().
* Assumes the PDU has been initialized with a gcoap_xxx_init() function, like
* gcoap_req_init().
*
* @warning To use this function, you only may have added an Option with
* option number less than COAP_OPT_CONTENT_FORMAT. Otherwise, use the
* struct-based API described with @link net_nanocoap nanocoap. @endlink With
* this API, you specify the format with coap_opt_add_uint(), prepare for the
* payload with coap_opt_finish(), and then write the payload.
*
* @param[in,out] pdu Request metadata
* @param[in] payload_len Length of the payload, or 0 if none

View File

@ -38,20 +38,12 @@
#define GCOAP_RESOURCE_WRONG_METHOD -1
#define GCOAP_RESOURCE_NO_PATH -2
/*
* gcoap internal Content-Format option value. Not intended for use in a
* transmitted packet. Must be a 3-byte unsigned value.
*/
#define COAP_FORMAT_NO_PAYLOAD (UINT16_MAX + 1)
/* Internal functions */
static void *_event_loop(void *arg);
static void _listen(sock_udp_t *sock);
static ssize_t _well_known_core_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len, void *ctx);
static ssize_t _write_options(coap_pkt_t *pdu, uint8_t *buf, size_t len);
static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len,
sock_udp_ep_t *remote);
static ssize_t _finish_pdu(coap_pkt_t *pdu, uint8_t *buf, size_t len);
static void _expire_request(gcoap_request_memo_t *memo);
static void _find_req_memo(gcoap_request_memo_t **memo_ptr, coap_pkt_t *pdu,
const sock_udp_ep_t *remote);
@ -343,9 +335,6 @@ static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len,
memcpy(&memo->token[0], pdu->token, memo->token_len);
}
DEBUG("gcoap: Registered observer for: %s\n", memo->resource->path);
/* generate initial notification value */
uint32_t now = xtimer_now_usec();
pdu->observe_value = (now >> GCOAP_OBS_TICK_EXPONENT) & 0xFFFFFF;
}
} else if (coap_get_observe(pdu) == COAP_OBS_DEREGISTER) {
@ -429,29 +418,6 @@ static int _find_resource(coap_pkt_t *pdu, const coap_resource_t **resource_ptr,
return ret;
}
/*
* Finishes handling a PDU -- write options and reposition payload.
*
* Returns the size of the PDU within the buffer, or < 0 on error.
*/
static ssize_t _finish_pdu(coap_pkt_t *pdu, uint8_t *buf, size_t len)
{
ssize_t hdr_len = _write_options(pdu, buf, len);
DEBUG("gcoap: header length: %i\n", (int)hdr_len);
if (hdr_len > 0) {
/* move payload over unused space after options */
if (pdu->payload_len) {
memmove(buf + hdr_len, pdu->payload, pdu->payload_len);
}
return hdr_len + pdu->payload_len;
}
else {
return -1; /* generic failure code */
}
}
/*
* Finds the memo for an outstanding request within the _coap_state.open_reqs
* array. Matches on remote endpoint and token.
@ -535,69 +501,6 @@ static ssize_t _well_known_core_handler(coap_pkt_t* pdu, uint8_t *buf, size_t le
return gcoap_finish(pdu, (size_t)plen, COAP_FORMAT_LINK);
}
/*
* Creates CoAP options and sets payload marker, if any.
*
* Returns length of header + options, or -EINVAL on illegal path.
*/
static ssize_t _write_options(coap_pkt_t *pdu, uint8_t *buf, size_t len)
{
uint8_t last_optnum = 0;
(void)len;
uint8_t *bufpos = buf + coap_get_total_hdr_len(pdu); /* position for write */
/* Observe for notification or registration response */
if (coap_get_code_class(pdu) == COAP_CLASS_SUCCESS && coap_has_observe(pdu)) {
uint32_t nval = htonl(pdu->observe_value);
uint8_t *nbyte = (uint8_t *)&nval;
unsigned i;
/* find address of non-zero MSB; max 3 bytes */
for (i = 1; i < 4; i++) {
if (*(nbyte+i) > 0) {
break;
}
}
bufpos += coap_put_option(bufpos, last_optnum, COAP_OPT_OBSERVE,
nbyte+i, 4-i);
last_optnum = COAP_OPT_OBSERVE;
}
/* Uri-Path for request */
if (coap_get_code_class(pdu) == COAP_CLASS_REQ) {
size_t url_len = strlen((char *)pdu->url);
if (url_len) {
if (pdu->url[0] != '/') {
DEBUG("gcoap: _write_options: path does not start with '/'\n");
return -EINVAL;
}
bufpos += coap_opt_put_uri_path(bufpos, last_optnum,
(char *)pdu->url);
last_optnum = COAP_OPT_URI_PATH;
}
}
/* Content-Format */
if (pdu->content_type != COAP_FORMAT_NONE) {
bufpos += coap_put_option_ct(bufpos, last_optnum, pdu->content_type);
last_optnum = COAP_OPT_CONTENT_FORMAT;
}
/* Uri-query for requests */
if (coap_get_code_class(pdu) == COAP_CLASS_REQ) {
bufpos += coap_opt_put_uri_query(bufpos, last_optnum,
(char *)pdu->qs);
/* uncomment when further options are added below ... */
/* last_optnum = COAP_OPT_URI_QUERY; */
}
/* write payload marker */
if (pdu->payload_len) {
*bufpos++ = GCOAP_PAYLOAD_MARKER;
}
return bufpos - buf;
}
/*
* Find registered observer for a remote address and port.
*
@ -729,11 +632,7 @@ int gcoap_req_init(coap_pkt_t *pdu, uint8_t *buf, size_t len,
{
assert((path != NULL) && (path[0] == '/'));
(void)len;
pdu->hdr = (coap_hdr_t *)buf;
memset(pdu->url, 0, NANOCOAP_URL_MAX);
memset(pdu->qs, 0, NANOCOAP_QS_MAX);
/* generate token */
#if GCOAP_TOKENLEN
@ -754,15 +653,8 @@ int gcoap_req_init(coap_pkt_t *pdu, uint8_t *buf, size_t len,
#endif
if (hdrlen > 0) {
/* Reserve some space between the header and payload to write options later */
pdu->payload = buf + coap_get_total_hdr_len(pdu) + strlen(path)
+ GCOAP_REQ_OPTIONS_BUF;
/* Payload length really zero at this point, but we set this to the available
* length in the buffer. Allows us to reconstruct buffer length later. */
pdu->payload_len = len - (pdu->payload - buf);
pdu->content_type = COAP_FORMAT_NONE;
memcpy(&pdu->url[0], path, strlen(path));
coap_pkt_init(pdu, buf, len - GCOAP_REQ_OPTIONS_BUF, hdrlen);
coap_opt_add_string(pdu, COAP_OPT_URI_PATH, path, '/');
return 0;
}
else {
@ -771,14 +663,43 @@ int gcoap_req_init(coap_pkt_t *pdu, uint8_t *buf, size_t len,
}
}
/*
* Assumes pdu.payload_len attribute was reduced in gcoap_xxx_init() to
* ensure enough space in PDU buffer to write Content-Format option and
* payload marker here.
*/
ssize_t gcoap_finish(coap_pkt_t *pdu, size_t payload_len, unsigned format)
{
/* reconstruct full PDU buffer length */
size_t len = pdu->payload_len + (pdu->payload - (uint8_t *)pdu->hdr);
assert( !(pdu->options_len) ||
!(payload_len) ||
(format == COAP_FORMAT_NONE) ||
(pdu->options[pdu->options_len-1].opt_num < COAP_OPT_CONTENT_FORMAT));
pdu->content_type = format;
pdu->payload_len = payload_len;
return _finish_pdu(pdu, (uint8_t *)pdu->hdr, len);
if (payload_len) {
/* determine Content-Format option length */
unsigned format_optlen = 1;
if (format == COAP_FORMAT_NONE) {
format_optlen = 0;
}
else if (format > 255) {
format_optlen = 3;
}
else if (format > 0) {
format_optlen = 2;
}
/* move payload to accommodate option and payload marker */
memmove(pdu->payload+format_optlen+1, pdu->payload, payload_len);
if (format_optlen) {
coap_opt_add_uint(pdu, COAP_OPT_CONTENT_FORMAT, format);
}
*pdu->payload++ = 0xFF;
}
/* must write option before updating PDU with actual length */
pdu->payload_len = payload_len;
return pdu->payload_len + (pdu->payload - (uint8_t *)pdu->hdr);
}
size_t gcoap_req_send(const uint8_t *buf, size_t len, const ipv6_addr_t *addr,
@ -912,12 +833,18 @@ int gcoap_resp_init(coap_pkt_t *pdu, uint8_t *buf, size_t len, unsigned code)
}
coap_hdr_set_code(pdu->hdr, code);
/* Reserve some space between the header and payload to write options later */
pdu->payload = buf + coap_get_total_hdr_len(pdu) + GCOAP_RESP_OPTIONS_BUF;
/* Payload length really zero at this point, but we set this to the available
* length in the buffer. Allows us to reconstruct buffer length later. */
pdu->payload_len = len - (pdu->payload - buf);
pdu->content_type = COAP_FORMAT_NONE;
unsigned header_len = coap_get_total_hdr_len(pdu);
pdu->options_len = 0;
pdu->payload = buf + header_len;
pdu->payload_len = len - header_len - GCOAP_RESP_OPTIONS_BUF;
if (coap_get_observe(pdu) == COAP_OBS_REGISTER) {
/* generate initial notification value */
uint32_t now = xtimer_now_usec();
pdu->observe_value = (now >> GCOAP_OBS_TICK_EXPONENT) & 0xFFFFFF;
coap_opt_add_uint(pdu, COAP_OPT_OBSERVE, pdu->observe_value);
}
return 0;
}
@ -939,15 +866,11 @@ int gcoap_obs_init(coap_pkt_t *pdu, uint8_t *buf, size_t len,
memo->token_len, COAP_CODE_CONTENT, msgid);
if (hdrlen > 0) {
coap_pkt_init(pdu, buf, len - GCOAP_OBS_OPTIONS_BUF, hdrlen);
uint32_t now = xtimer_now_usec();
pdu->observe_value = (now >> GCOAP_OBS_TICK_EXPONENT) & 0xFFFFFF;
/* Reserve some space between the header and payload to write options later */
pdu->payload = buf + coap_get_total_hdr_len(pdu) + GCOAP_OBS_OPTIONS_BUF;
/* Payload length really zero at this point, but we set this to the available
* length in the buffer. Allows us to reconstruct buffer length later. */
pdu->payload_len = len - (pdu->payload - buf);
pdu->content_type = COAP_FORMAT_NONE;
coap_opt_add_uint(pdu, COAP_OPT_OBSERVE, pdu->observe_value);
return GCOAP_OBS_INIT_OK;
}