Skip to content

CoAP API Options Update

Ken Bannister edited this page Apr 29, 2018 · 3 revisions

Below are proposed changes to the nanocoap and gcoap APIs, primarily to support specification of CoAP options. At the highest level these changes add a nanocoap API to use coap_pkt_t to build a packet/PDU. They also adapt the gcoap API to use this new nanocoap API. The gcoap API now can be seen basically as convenience/sugar on top of the nanocoap API.

Specifics:

  • Add coap_pkt_init()
  • Add coap_opt_add_[string|buf|uint]()
  • Allow storage of options in final form or in provisional form, identified by a new bitmask-style 'flags' attribute in coap_pkt_t.
  • Add coap_opt_finish() to convert provisional form to final form.
  • Adapt gcoap API to deprecate gcoap_finish() and add gcoap_opt_finish_format().

API Outline

coap_build_hdr(hdr, type, token, token_len, code, msgid)

Use as defined presently. Required for coap_pkt_init() below.

coap_pkt_init(pkt, buf, len, hdr)

  • Initializes coap_pkt_t. Copies hdr to pkt if pointers are not equal.
  • Sets the payload marker (0xFF), even though it may not be used.
  • Initializes payload pointer and payload_len. These will be maintained while adding options so the packet/buffer always are ready to accept the payload. User can query pkt.payload_len to know maximum length available for payload.
  • Defaults the packet to use 'final' mode for adding options (see below).

coap_pkt_set_flags(uint16_t)
coap_pkt_get_flags()

Add coap_pkt_t.flags, type uint16_t. Formatted with bitmasked values.

  • Bit 0: Provisional/Final mode flag
    • COAP_PKT_FLAGS_OPT_FINAL = 0
    • COAP_PKT_FLAGS_OPT_PROVISIONAL = 1
  • Bit 1: Move payload in coap_opt_finish() -- to support deprecated gcoap API
    • COAP_PKT_FLAGS_OPT_STATIC_PAYLOAD = 0
    • COAP_PKT_FLAGS_OPT_MOVE_PAYLOAD = 1
  • Bits 2-7: Reserved

coap_opt_add_[string|buf|uint](pkt, ...)

Two modes of operation -- final or provisional, depending on flag in coap_pkt_t. Final means the options are added in order, in their final positions in the packet. Provisional means the options are added in any order as a place to store them. The options will be sorted into final mode later.

  • Writes option data to buf at payload pointer (actually, pointer minus 1 for payload marker). If in provisional mode, option delta always set to zero.
  • Advances payload ptr and decrements payload_len.
  • Adds element to coap_optpos_t and increments options_len.
  • Sets the payload marker (OxFF).

coap_opt_finish(pkt)

Only called if options added in provisional mode.

  • Sorts and rewrites options as described in steps below.
  • Allocates a buffer on the stack to hold sorted options.
  • Reads each option, in option number order, and copies to stack buffer with coap_put_option().
  • Reads options in stack buffer, and updates packet options array. Maybe reuse/refactor coap_parse() for this purpose.
  • If pkt.flags:1 value is true, move bytes (memmove) in buffer from payload ptr to adjusted location based on bytes written to stack buffer. Truncate bytes to move if necessary.
  • Copies stack buffer to packet buffer.
  • Updates payload ptr and payload_len, and sets the payload marker.
  • Sets packet flag for final mode.

How gcoap uses the API

gcoap uses this basic API, and adds additional function calls to make simple messaging easy for the user. gcoap always adds options in provisional mode. For example, gcoap_req_init() includes the request path, as this will be defined with each request. Since CoAP saves the path as an option, gcoap_req_init() stores it by calling coap_opt_add_string().

1. gcoap_req_init(), gcoap_resp_init(), gcoap_obs_init()

gcoap_req_init() and gcoap_obs_init() use coap_build_hdr and coap_pkt_init() as these create a new coap_pkt_t. gcoap_resp_init() reuses the packet from the request.

Sets the packet to use provisional mode for options. As mentioned, gcoap_req_init() sets Uri-Path option. gcoap_obs_init() sets Observe option.

2. User adds other options as required

3. User calls gcoap_opt_finish_format(pkt, content_format)

This step is new. Without it, use of gcoap_finish() is troublesome because it specifies the content format option after the payload has been written. Currently use is optional, but after some time we can require it because it simplifies some of the gcoap/nanocoap implementation. It also allows the user to know exactly how many bytes are available for the payload.

This function sets the packet format and calls coap_opt_finish(). Use COAP_FORMAT_NONE if no format and COAP_FORMAT_NO_PAYLOAD if no payload. If no payload, adjusts payload length to remove payload marker.

4. User writes payload if necessary

5. gcoap_finish()

If option format still is provisional, first calls gcoap_opt_finish_format() to finalize. Then sets pkt.payload_len as it does currently. As with gcoap_opt_finish_format(), after some time we can reject a packet with options still in provisional mode.