nanocoap: add server-side block1 support
This commit is contained in:
parent
012c016b74
commit
4897222e7e
@ -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" {
|
|||||||
#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 {
|
|||||||
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
|
|||||||
*/
|
*/
|
||||||
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);
|
|||||||
*/
|
*/
|
||||||
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 @@
|
|||||||
|
|
||||||
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
|
|||||||
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)
|
|||||||
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)
|
|||||||
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
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) ? '/' : '&';
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user