Skip to content
Snippets Groups Projects
Unverified Commit 635e72db authored by Koen Zandberg's avatar Koen Zandberg Committed by GitHub
Browse files

Merge pull request #8788 from kaspar030/nanocoap_add_serverside_block1

nanocoap: add serverside block1 support
parents fbea4f9b b42159df
No related branches found
No related tags found
No related merge requests found
...@@ -27,6 +27,9 @@ USEMODULE += nanocoap_sock ...@@ -27,6 +27,9 @@ USEMODULE += nanocoap_sock
# include this for nicely formatting the returned internal value # include this for nicely formatting the returned internal value
USEMODULE += fmt USEMODULE += fmt
# include sha256 (used by example blockwise handler)
USEMODULE += hashes
# include this for printing IP addresses # include this for printing IP addresses
USEMODULE += shell_commands USEMODULE += shell_commands
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "fmt.h" #include "fmt.h"
#include "net/nanocoap.h" #include "net/nanocoap.h"
#include "hashes/sha256.h"
/* internal value that can be read/written via CoAP */ /* internal value that can be read/written via CoAP */
static uint8_t internal_value = 0; static uint8_t internal_value = 0;
...@@ -55,9 +56,58 @@ static ssize_t _riot_value_handler(coap_pkt_t *pkt, uint8_t *buf, size_t len, vo ...@@ -55,9 +56,58 @@ static ssize_t _riot_value_handler(coap_pkt_t *pkt, uint8_t *buf, size_t len, vo
COAP_FORMAT_TEXT, (uint8_t*)rsp, p); COAP_FORMAT_TEXT, (uint8_t*)rsp, p);
} }
ssize_t _sha256_handler(coap_pkt_t* pkt, uint8_t *buf, size_t len, void *context)
{
(void)context;
/* using a shared sha256 context *will* break if two requests are handled
* at the same time. doing it anyways, as this is meant to showcase block1
* support, not proper synchronisation. */
static sha256_context_t sha256;
uint8_t digest[SHA256_DIGEST_LENGTH];
uint32_t result = COAP_CODE_204;
coap_block1_t block1;
int blockwise = coap_get_block1(pkt, &block1);
printf("_sha256_handler(): received data: offset=%u len=%u blockwise=%i more=%i\n", \
(unsigned)block1.offset, pkt->payload_len, blockwise, block1.more);
if (block1.offset == 0) {
puts("_sha256_handler(): init");
sha256_init(&sha256);
}
sha256_update(&sha256, pkt->payload, pkt->payload_len);
if (block1.more == 1) {
result = COAP_CODE_231;
}
size_t result_len = 0;
if (!blockwise || !block1.more) {
puts("_sha256_handler(): finish");
sha256_final(&sha256, digest);
result_len = SHA256_DIGEST_LENGTH * 2;
}
ssize_t reply_len = coap_build_reply(pkt, result, buf, len, 0);
uint8_t *pkt_pos = (uint8_t*)pkt->hdr + reply_len;
pkt_pos += coap_put_block1_ok(pkt_pos, &block1, 0);
if (result_len) {
*pkt_pos++ = 0xFF;
pkt_pos += fmt_bytes_hex((char *)pkt_pos, digest, sizeof(digest));
}
return pkt_pos - (uint8_t*)pkt->hdr;
}
/* must be sorted by path (alphabetically) */ /* must be sorted by path (alphabetically) */
const coap_resource_t coap_resources[] = { const coap_resource_t coap_resources[] = {
COAP_WELL_KNOWN_CORE_DEFAULT_HANDLER, COAP_WELL_KNOWN_CORE_DEFAULT_HANDLER,
{ "/sha256", COAP_POST, _sha256_handler, NULL },
{ "/riot/board", COAP_GET, _riot_board_handler, NULL }, { "/riot/board", COAP_GET, _riot_board_handler, NULL },
{ "/riot/value", COAP_GET | COAP_PUT | COAP_POST, _riot_value_handler, NULL }, { "/riot/value", COAP_GET | COAP_PUT | COAP_POST, _riot_value_handler, NULL },
}; };
......
...@@ -65,6 +65,8 @@ extern "C" { ...@@ -65,6 +65,8 @@ extern "C" {
#define COAP_OPT_URI_PATH (11) #define COAP_OPT_URI_PATH (11)
#define COAP_OPT_CONTENT_FORMAT (12) #define COAP_OPT_CONTENT_FORMAT (12)
#define COAP_OPT_URI_QUERY (15) #define COAP_OPT_URI_QUERY (15)
#define COAP_OPT_BLOCK2 (23)
#define COAP_OPT_BLOCK1 (27)
/** @} */ /** @} */
/** /**
...@@ -211,6 +213,16 @@ extern "C" { ...@@ -211,6 +213,16 @@ extern "C" {
#define COAP_DEFAULT_LEISURE (5) #define COAP_DEFAULT_LEISURE (5)
/** @} */ /** @} */
/**
* @name Blockwise transfer (RFC7959)
* @{
*/
#define COAP_BLOCKWISE_NUM_OFF (4)
#define COAP_BLOCKWISE_MORE_OFF (3)
#define COAP_BLOCKWISE_SZX_MASK (0x07)
#define COAP_BLOCKWISE_SZX_MAX (7)
/** @} */
/** /**
* @brief Raw CoAP PDU header structure * @brief Raw CoAP PDU header structure
*/ */
...@@ -262,6 +274,17 @@ typedef struct { ...@@ -262,6 +274,17 @@ typedef struct {
void *context; /**< ptr to user defined context data */ void *context; /**< ptr to user defined context data */
} coap_resource_t; } coap_resource_t;
/**
* @brief Block1 helper struct
*/
typedef struct {
size_t offset; /**< offset of received data */
uint32_t blknum; /**< block number */
unsigned szx; /**< szx value */
int more; /**< -1 for no option, 0 for last block,
1 for more blocks coming */
} coap_block1_t;
/** /**
* @brief Global CoAP resource list * @brief Global CoAP resource list
*/ */
...@@ -409,6 +432,71 @@ size_t coap_put_option_ct(uint8_t *buf, uint16_t lastonum, uint16_t content_type ...@@ -409,6 +432,71 @@ size_t coap_put_option_ct(uint8_t *buf, uint16_t lastonum, uint16_t content_type
*/ */
size_t coap_put_option_uri(uint8_t *buf, uint16_t lastonum, const char *uri, uint16_t optnum); size_t coap_put_option_uri(uint8_t *buf, uint16_t lastonum, const char *uri, uint16_t optnum);
/**
* @brief Generic block option getter
*
* @param[in] pkt pkt to work on
* @param[in] option actual block option number to get
* @param[out] blknum block number
* @param[out] szx SZX value
*
* @returns -1 if option not found
* @returns 0 if more flag is not set
* @returns 1 if more flag is set
*/
int coap_get_blockopt(coap_pkt_t *pkt, uint16_t option, uint32_t *blknum, unsigned *szx);
/**
* @brief Block1 option getter
*
* This function gets a CoAP packet's block1 option and parses it into a helper
* structure.
*
* If no block1 option is present in @p pkt, the values in @p block1 will be
* initialized with zero. That implies both block1->offset and block1->more are
* also valid in that case, as packet with offset==0 and more==0 means it contains
* all the payload for the corresponding request.
*
* @param[in] pkt pkt to work on
* @param[out] block1 ptr to preallocated coap_block1_t structure
*
* @returns 0 if block1 option not present
* @returns 1 if structure has been filled
*/
int coap_get_block1(coap_pkt_t *pkt, coap_block1_t *block1);
/**
* @brief Insert block1 option into buffer
*
* @param[out] buf buffer to write to
* @param[in] lastonum number of previous option (for delta calculation),
* must be < 27
* @param[in] blknum block number
* @param[in] szx SXZ value
* @param[in] more more flag (1 or 0)
*
* @returns amount of bytes written to @p buf
*/
size_t coap_put_option_block1(uint8_t *buf, uint16_t lastonum, unsigned blknum, unsigned szx, int more);
/**
* @brief Insert block1 option into buffer (from coap_block1_t)
*
* This function is wrapper around @ref coap_put_option_block1(),
* taking its arguments from a coap_block1_t struct.
*
* It will write option Nr. 27 (COAP_OPT_BLOCK1).
*
* It is safe to be called when @p block1 was generated for a non-blockwise
* request.
*
* @param[in] pkt_pos buffer to write to
* @param[in] block1 ptr to block1 struct (created by coap_get_block1())
* @param[in] lastonum last option number (must be < 27)
*
* @returns amount of bytes written to @p pkt_pos
*/
size_t coap_put_block1_ok(uint8_t *pkt_pos, coap_block1_t *block1, uint16_t lastonum);
/** /**
* @brief Get content type from packet * @brief Get content type from packet
...@@ -436,6 +524,18 @@ unsigned coap_get_content_type(coap_pkt_t *pkt); ...@@ -436,6 +524,18 @@ unsigned coap_get_content_type(coap_pkt_t *pkt);
*/ */
int coap_get_uri(coap_pkt_t *pkt, uint8_t *target); int coap_get_uri(coap_pkt_t *pkt, uint8_t *target);
/**
* @brief Helper to decode SZX value to size in bytes
*
* @param[in] szx SZX value to decode
*
* @returns SZX value decoded to bytes
*/
static inline unsigned coap_szx2size(unsigned szx)
{
return (1 << (szx + 4));
}
/** /**
* @brief Get the CoAP version number * @brief Get the CoAP version number
* *
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
static int _decode_value(unsigned val, uint8_t **pkt_pos_ptr, uint8_t *pkt_end); 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); 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);
/* http://tools.ietf.org/html/rfc7252#section-3 /* http://tools.ietf.org/html/rfc7252#section-3
* 0 1 2 3 * 0 1 2 3
...@@ -161,17 +163,6 @@ static uint8_t *_parse_option(coap_pkt_t *pkt, uint8_t *pkt_pos, uint16_t *delta ...@@ -161,17 +163,6 @@ static uint8_t *_parse_option(coap_pkt_t *pkt, uint8_t *pkt_pos, uint16_t *delta
return pkt_pos; return pkt_pos;
} }
static uint32_t _decode_uint(uint8_t *pkt_pos, unsigned nbytes)
{
assert(nbytes <= 4);
uint32_t res = 0;
if (nbytes) {
memcpy(((uint8_t *)&res) + (4 - nbytes), pkt_pos, nbytes);
}
return ntohl(res);
}
int coap_get_option_uint(coap_pkt_t *pkt, unsigned opt_num, uint32_t *target) int coap_get_option_uint(coap_pkt_t *pkt, unsigned opt_num, uint32_t *target)
{ {
assert(target); assert(target);
...@@ -265,6 +256,29 @@ int coap_get_uri(coap_pkt_t *pkt, uint8_t *target) ...@@ -265,6 +256,29 @@ int coap_get_uri(coap_pkt_t *pkt, uint8_t *target)
return NANOCOAP_URI_MAX - left; return NANOCOAP_URI_MAX - left;
} }
int coap_get_blockopt(coap_pkt_t *pkt, uint16_t option, uint32_t *blknum, unsigned *szx)
{
uint8_t *optpos = coap_find_option(pkt, option);
if (!optpos) {
*blknum = 0;
*szx = 0;
return -1;
}
int option_len;
uint16_t delta;
uint8_t *data_start = _parse_option(pkt, optpos, &delta, &option_len);
uint32_t blkopt = _decode_uint(data_start, option_len);
DEBUG("nanocoap: blkopt len: %i\n", option_len);
DEBUG("nanocoap: blkopt: 0x%08x\n", (unsigned)blkopt);
*blknum = blkopt >> COAP_BLOCKWISE_NUM_OFF;
*szx = blkopt & COAP_BLOCKWISE_SZX_MASK;
return (blkopt & 0x8) ? 1 : 0;
}
ssize_t coap_handle_req(coap_pkt_t *pkt, uint8_t *resp_buf, unsigned resp_buf_len) ssize_t coap_handle_req(coap_pkt_t *pkt, uint8_t *resp_buf, unsigned resp_buf_len)
{ {
if (coap_get_code_class(pkt) != COAP_REQ) { if (coap_get_code_class(pkt) != COAP_REQ) {
...@@ -416,6 +430,43 @@ static int _decode_value(unsigned val, uint8_t **pkt_pos_ptr, uint8_t *pkt_end) ...@@ -416,6 +430,43 @@ static int _decode_value(unsigned val, uint8_t **pkt_pos_ptr, uint8_t *pkt_end)
return res; return res;
} }
static uint32_t _decode_uint(uint8_t *pkt_pos, unsigned nbytes)
{
assert(nbytes <= 4);
uint32_t res = 0;
if (nbytes) {
memcpy(((uint8_t *)&res) + (4 - nbytes), pkt_pos, nbytes);
}
return ntohl(res);
}
static size_t _encode_uint(uint32_t *val)
{
uint8_t *tgt = (uint8_t *)val;
size_t size = 0;
/* count number of used bytes */
uint32_t tmp = *val;
while(tmp) {
size++;
tmp >>= 8;
}
/* convert to network byte order */
tmp = htonl(*val);
/* copy bytewise, starting with first actually used byte */
*val = 0;
uint8_t *tmp_u8 = (uint8_t *)&tmp;
tmp_u8 += (4 - size);
for (unsigned n = 0; n < size; n++) {
*tgt++ = *tmp_u8++;
}
return size;
}
static unsigned _put_delta_optlen(uint8_t *buf, unsigned offset, unsigned shift, unsigned val) static unsigned _put_delta_optlen(uint8_t *buf, unsigned offset, unsigned shift, unsigned val)
{ {
if (val < 13) { if (val < 13) {
...@@ -469,6 +520,46 @@ size_t coap_put_option_ct(uint8_t *buf, uint16_t lastonum, uint16_t content_type ...@@ -469,6 +520,46 @@ size_t coap_put_option_ct(uint8_t *buf, uint16_t lastonum, uint16_t content_type
} }
} }
static size_t coap_put_option_block(uint8_t *buf, uint16_t lastonum, unsigned blknum, unsigned szx, int more, uint16_t option)
{
uint32_t blkopt = (blknum << 4) | szx | (more ? 0x8 : 0);
size_t olen = _encode_uint(&blkopt);
return coap_put_option(buf, lastonum, option, (uint8_t*)&blkopt, olen);
}
size_t coap_put_option_block1(uint8_t *buf, uint16_t lastonum, unsigned blknum, unsigned szx, int more)
{
return coap_put_option_block(buf, lastonum, blknum, szx, more, COAP_OPT_BLOCK1);
}
int coap_get_block1(coap_pkt_t *pkt, coap_block1_t *block1)
{
uint32_t blknum;
unsigned szx;
block1->more = coap_get_blockopt(pkt, COAP_OPT_BLOCK1, &blknum, &szx);
if (block1->more >= 0) {
block1->offset = blknum << (szx + 4);
}
else {
block1->offset = 0;
}
block1->blknum = blknum;
block1->szx = szx;
return (block1->more >= 0);
}
size_t coap_put_block1_ok(uint8_t *pkt_pos, coap_block1_t *block1, uint16_t lastonum)
{
if (block1->more >= 1) {
return coap_put_option_block1(pkt_pos, lastonum, block1->blknum, block1->szx, block1->more);
}
else {
return 0;
}
}
size_t coap_put_option_uri(uint8_t *buf, uint16_t lastonum, const char *uri, uint16_t optnum) size_t coap_put_option_uri(uint8_t *buf, uint16_t lastonum, const char *uri, uint16_t optnum)
{ {
char separator = (optnum == COAP_OPT_URI_PATH) ? '/' : '&'; char separator = (optnum == COAP_OPT_URI_PATH) ? '/' : '&';
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment