Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net/nanocoap: Options sort module #9475

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion makefiles/pseudomodules.inc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ PSEUDOMODULES += lwip_tcp
PSEUDOMODULES += lwip_udp
PSEUDOMODULES += lwip_udplite
PSEUDOMODULES += mpu_stack_guard
PSEUDOMODULES += nanocoap_%
PSEUDOMODULES += nanocoap_sock
PSEUDOMODULES += nanocoap_opt2
PSEUDOMODULES += nanocoap_opt2_sort
PSEUDOMODULES += netdev_default
PSEUDOMODULES += netif
PSEUDOMODULES += netstats
Expand Down
49 changes: 48 additions & 1 deletion sys/include/net/nanocoap.h
Original file line number Diff line number Diff line change
@@ -1,16 +1,59 @@
/*
* Copyright (C) 2016-17 Kaspar Schleiser <kaspar@schleiser.de>
* Copyright (C) 2018 Ken Bannister <kb2ma@runbox.com>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @defgroup net_nanocoap nanocoap small CoAP library
* @defgroup net_nanocoap Nanocoap, small CoAP library
* @ingroup net
* @brief Provides CoAP functionality optimized for minimal resource usage
*
* nanocoap includes both server-side response generation and client-side
* request generation.
*
* ## Write Options and Payload ##
*
* For both server responses and client requests, CoAP uses an Option mechanism
* to encode message metadata that is not required for each message. For
* example, the resource URI path is required only for a request, and is encoded
* as the Uri-Path option.
*
* nanocoap provides two APIs for writing CoAP options:
*
* A **minimal** API that requires only a reference to the buffer. However, the
* caller must remember and provide the last option number written, as well
* as the buffer position. The minimal API always is available.
*
* A convenient **struct-based** API that uses a coap_pkt_t struct to track each
* option as it is written. Activate this API by use of the `nanocoap_opt2`
* submodule.
*
* For either API, by default the caller *must* write options in order by option
* number (see "CoAP option numbers", below). However, the struct-based API
* supports use of the `nanocoap_opt2_sort` module. This module allows the user
* to enter options in any order, and then sorts them in coap_opt_finish().
*
* ### Higher-level, struct-based API ###
*
* Before starting, ensure the buffer and CoAP header have been initialized.
* For a request, use `coap_build_hdr()`. For a response, update the header
* attributes from the request buffer as needed.
*
* Use `coap_pkt_init()` to initialize the coap_pkt_t struct, including the
* array of options.
*
* Next, use the `coap_opt_add_xxx()` functions to write each option, like
* `coap_opt_add_uint()`. When all options have been added, use
* `coap_opt_finish()`.
*
* Finally, write any message payload at the coap_pkt_t payload pointer
* attribute. The `payload_len` attribute provides the available length in the
* buffer.
*
* @{
*
* @file
Expand Down Expand Up @@ -403,6 +446,7 @@ ssize_t coap_handle_req(coap_pkt_t *pkt, uint8_t *resp_buf, unsigned resp_buf_le
ssize_t coap_build_hdr(coap_hdr_t *hdr, unsigned type, uint8_t *token,
size_t token_len, unsigned code, uint16_t id);

#ifdef MODULE_NANOCOAP_OPT2
/**
* @brief Initialize a packet struct, to build a message buffer
*
Expand All @@ -418,6 +462,7 @@ ssize_t coap_build_hdr(coap_hdr_t *hdr, unsigned type, uint8_t *token,
* @param[in] header_len length of header in buf, including token
*/
void coap_pkt_init(coap_pkt_t *pkt, uint8_t *buf, size_t len, size_t header_len);
#endif

/**
* @brief Insert a CoAP option into buffer
Expand Down Expand Up @@ -528,6 +573,7 @@ size_t coap_put_option_block1(uint8_t *buf, uint16_t lastonum, unsigned blknum,
*/
size_t coap_put_block1_ok(uint8_t *pkt_pos, coap_block1_t *block1, uint16_t lastonum);

#ifdef MODULE_NANOCOAP_OPT2
/**
* @brief Encode the given string as option(s) into pkt
*
Expand Down Expand Up @@ -573,6 +619,7 @@ ssize_t coap_opt_add_uint(coap_pkt_t *pkt, uint16_t optnum, uint32_t value);
* @return total number of bytes written to buffer
*/
ssize_t coap_opt_finish(coap_pkt_t *pkt, uint16_t flags);
#endif /* MODULE_NANOCOAP_OPT2 */

/**
* @brief Get content type from packet
Expand Down
10 changes: 9 additions & 1 deletion sys/net/application_layer/nanocoap/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
SRC := nanocoap.c
SUBMODULES := 1

ifneq (,$(filter nanocoap_sock,$(USEMODULE)))
SRC += sock.c
endif

ifneq (,$(filter nanocoap_opt2,$(USEMODULE)))
SRC += opt2_add.c
endif

include $(RIOTBASE)/Makefile.base
105 changes: 13 additions & 92 deletions sys/net/application_layer/nanocoap/nanocoap.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2016-18 Kaspar Schleiser <kaspar@schleiser.de>
* Copyright (C) 2018 Ken Bannister <kb2ma@runbox.com>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
Expand All @@ -14,6 +15,7 @@
* @brief Nanocoap implementation
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Ken Bannister <kb2ma@runbox.com>
*
* @}
*/
Expand All @@ -31,7 +33,11 @@
static int _decode_value(unsigned val, uint8_t **pkt_pos_ptr, uint8_t *pkt_end);
int coap_get_option_uint(coap_pkt_t *pkt, unsigned opt_num, uint32_t *target);
static uint32_t _decode_uint(uint8_t *pkt_pos, unsigned nbytes);
static size_t _encode_uint(uint32_t *val);
size_t _encode_uint(uint32_t *val);

#ifdef MODULE_NANOCOAP_OPT2_SORT
extern ssize_t _sort_opts(coap_pkt_t *pkt);
#endif

/* http://tools.ietf.org/html/rfc7252#section-3
* 0 1 2 3
Expand Down Expand Up @@ -147,7 +153,7 @@ uint8_t *coap_find_option(coap_pkt_t *pkt, unsigned opt_num)
return NULL;
}

static uint8_t *_parse_option(coap_pkt_t *pkt, uint8_t *pkt_pos, uint16_t *delta, int *opt_len)
uint8_t *_parse_option(coap_pkt_t *pkt, uint8_t *pkt_pos, uint16_t *delta, int *opt_len)
{
uint8_t *hdr_end = pkt->payload;

Expand Down Expand Up @@ -383,15 +389,6 @@ ssize_t coap_build_hdr(coap_hdr_t *hdr, unsigned type, uint8_t *token, size_t to
return sizeof(coap_hdr_t) + token_len;
}

void coap_pkt_init(coap_pkt_t *pkt, uint8_t *buf, size_t len, size_t header_len)
{
memset(pkt, 0, sizeof(coap_pkt_t));
pkt->hdr = (coap_hdr_t *)buf;
pkt->token = buf + sizeof(coap_hdr_t);
pkt->payload = buf + header_len;
pkt->payload_len = len - header_len;
}

static int _decode_value(unsigned val, uint8_t **pkt_pos_ptr, uint8_t *pkt_end)
{
uint8_t *pkt_pos = *pkt_pos_ptr;
Expand Down Expand Up @@ -450,7 +447,7 @@ static uint32_t _decode_uint(uint8_t *pkt_pos, unsigned nbytes)
return ntohl(res);
}

static size_t _encode_uint(uint32_t *val)
size_t _encode_uint(uint32_t *val)
{
uint8_t *tgt = (uint8_t *)val;
size_t size = 0;
Expand Down Expand Up @@ -497,9 +494,12 @@ static unsigned _put_delta_optlen(uint8_t *buf, unsigned offset, unsigned shift,

size_t coap_put_option(uint8_t *buf, uint16_t lastonum, uint16_t onum, uint8_t *odata, size_t olen)
{
#ifdef MODULE_NANOCOAP_OPT2_SORT
unsigned delta = (lastonum <= onum) ? (onum - lastonum) : 0;
#else
assert(lastonum <= onum);

unsigned delta = (onum - lastonum);
#endif
*buf = 0;

/* write delta value to option header: 4 upper bits of header (shift 4) +
Expand Down Expand Up @@ -604,85 +604,6 @@ size_t coap_put_option_uri(uint8_t *buf, uint16_t lastonum, const char *uri, uin
return bufpos - buf;
}

/* Common functionality for addition of an option */
static ssize_t _add_opt_pkt(coap_pkt_t *pkt, uint16_t optnum, uint8_t *val,
size_t val_len)
{
assert(pkt->options_len < NANOCOAP_NOPTS_MAX);

uint16_t lastonum = (pkt->options_len)
? pkt->options[pkt->options_len - 1].opt_num : 0;
assert(optnum >= lastonum);

size_t optlen = coap_put_option(pkt->payload, lastonum, optnum, val, val_len);
assert(pkt->payload_len > optlen);

pkt->options[pkt->options_len].opt_num = optnum;
pkt->options[pkt->options_len].offset = pkt->payload - (uint8_t *)pkt->hdr;
pkt->options_len++;
pkt->payload += optlen;
pkt->payload_len -= optlen;

return optlen;
}

ssize_t coap_opt_add_string(coap_pkt_t *pkt, uint16_t optnum, const char *string,
char separator)
{
size_t unread_len = strlen(string);
if (!unread_len) {
return 0;
}
char *uripos = (char *)string;
size_t write_len = 0;

while (unread_len) {
size_t part_len;
uripos++;
uint8_t *part_start = (uint8_t *)uripos;

while (unread_len--) {
if ((*uripos == separator) || (*uripos == '\0')) {
break;
}
uripos++;
}

part_len = (uint8_t *)uripos - part_start;

if (part_len) {
if (pkt->options_len == NANOCOAP_NOPTS_MAX) {
return -ENOSPC;
}
write_len += _add_opt_pkt(pkt, optnum, part_start, part_len);
}
}

return write_len;
}

ssize_t coap_opt_add_uint(coap_pkt_t *pkt, uint16_t optnum, uint32_t value)
{
uint32_t tmp = value;
unsigned tmp_len = _encode_uint(&tmp);
return _add_opt_pkt(pkt, optnum, (uint8_t *)&tmp, tmp_len);
}

ssize_t coap_opt_finish(coap_pkt_t *pkt, uint16_t flags)
{
if (flags & COAP_OPT_FINISH_PAYLOAD) {
assert(pkt->payload_len > 1);

*pkt->payload++ = 0xFF;
pkt->payload_len--;
}
else {
pkt->payload_len = 0;
}

return pkt->payload - (uint8_t *)pkt->hdr;
}

ssize_t coap_well_known_core_default_handler(coap_pkt_t *pkt, uint8_t *buf, \
size_t len, void *context)
{
Expand Down
Loading