Skip to content
Snippets Groups Projects
Commit 4897222e authored by Kaspar Schleiser's avatar Kaspar Schleiser
Browse files

nanocoap: add server-side block1 support

parent 012c016b
No related branches found
No related tags found
No related merge requests found
......@@ -65,6 +65,8 @@ extern "C" {
#define COAP_OPT_URI_PATH (11)
#define COAP_OPT_CONTENT_FORMAT (12)
#define COAP_OPT_URI_QUERY (15)
#define COAP_OPT_BLOCK2 (23)
#define COAP_OPT_BLOCK1 (27)
/** @} */
/**
......@@ -211,6 +213,16 @@ extern "C" {
#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
*/
......@@ -262,6 +274,17 @@ typedef struct {
void *context; /**< ptr to user defined context data */
} 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
*/
......@@ -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);
/**
* @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
......@@ -436,6 +524,18 @@ unsigned coap_get_content_type(coap_pkt_t *pkt);
*/
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
*
......
......@@ -30,6 +30,8 @@
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);
/* http://tools.ietf.org/html/rfc7252#section-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
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)
{
assert(target);
......@@ -265,6 +256,29 @@ int coap_get_uri(coap_pkt_t *pkt, uint8_t *target)
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)
{
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)
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)
{
if (val < 13) {
......@@ -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)
{
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