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

Make CoAP block size configurable at build- and run-time #596

Merged
merged 3 commits into from
May 11, 2021
Merged
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
2 changes: 1 addition & 1 deletion .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# This file contains all commits which are purely cosmetics

# Cleaning up Eclipse headers
6a458fbc7a0e96a9fdd7d2b429c6924c5de7b35a
019c299b7183d49f975384651f2cf37ec60930d7
55 changes: 39 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Several compilation switches are used:
-DLWM2M_VERSION="1.0" to cmake.
- LWM2M_RAW_BLOCK1_REQUESTS For low memory client devices where it is not possible to keep a large post or put request in memory to be parsed (typically a firmware write).
This option enable each unprocessed block 1 payload to be passed to the application, typically to be stored to a flash memory.
- LWM2M_COAP_DEFAULT_BLOCK_SIZE CoAP block size used by CoAP layer when performing block-wise transfers. Possible values: 16, 32, 64, 128, 256, 512 and 1024. Defaults to 1024.

Depending on your platform, you need to define LWM2M_BIG_ENDIAN or LWM2M_LITTLE_ENDIAN.
LWM2M_CLIENT_MODE and LWM2M_SERVER_MODE can be defined at the same time.
Expand Down Expand Up @@ -110,7 +111,15 @@ The lwm2mserver listens on UDP port 5683. It features a basic command line
interface. Type 'help' for a list of supported commands.

Options are:
- -4 Use IPv4 connection. Default: IPv6 connection
```
Usage: lwm2mserver [OPTION]
Launch a LWM2M server on localhost.

Options:
-4 Use IPv4 connection. Default: IPv6 connection
-l PORT Set the local UDP port of the Server. Default: 5683
-S BYTES CoAP block size. Options: 16, 32, 64, 128, 256, 512, 1024. Default: 1024
```

### Test client example
* Create a build directory and change to that.
Expand Down Expand Up @@ -159,18 +168,27 @@ The lwm2mclient opens udp port 56830 and tries to register to a LWM2M Server at
list of supported commands.

Options are:
- -n NAME Set the endpoint name of the Client. Default: testlwm2mclient
- -l PORT Set the local UDP port of the Client. Default: 56830
- -h HOST Set the hostname of the LWM2M Server to connect to. Default: localhost
- -p HOST Set the port of the LWM2M Server to connect to. Default: 5683
- -4 Use IPv4 connection. Default: IPv6 connection
- -t TIME Set the lifetime of the Client. Default: 300
- -b Bootstrap requested.
- -c Change battery level over time.

```
Usage: lwm2mclient [OPTION]
Launch a LWM2M client.
Options:
-n NAME Set the endpoint name of the Client. Default: testlwm2mclient
-l PORT Set the local UDP port of the Client. Default: 56830
-h HOST Set the hostname of the LWM2M Server to connect to. Default: localhost
-p PORT Set the port of the LWM2M Server to connect to. Default: 5683
-4 Use IPv4 connection. Default: IPv6 connection
-t TIME Set the lifetime of the Client. Default: 300
-b Bootstrap requested.
-c Change battery level over time.
-S BYTES CoAP block size. Options: 16, 32, 64, 128, 256, 512, 1024. Default: 1024

```

If DTLS feature enable:
- -i Set the device management or bootstrap server PSK identity. If not set use none secure mode
- -s Set the device management or bootstrap server Pre-Shared-Key. If not set use none secure mode
```
-i Set the device management or bootstrap server PSK identity. If not set use none secure mode
-s Set the device management or bootstrap server Pre-Shared-Key. If not set use none secure mode
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CoAP block size and Pre-Shared-Key are both -s.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed that. I would go with -S then. Another option would be -a since other obvious options are already used.

```

To launch a bootstrap session:
``./lwm2mclient -b``
Expand All @@ -194,10 +212,15 @@ LWM2M objects:
The lightclient does not feature any command-line interface.

Options are:
- -n NAME Set the endpoint name of the Client. Default: testlightclient
- -l PORT Set the local UDP port of the Client. Default: 56830
- -4 Use IPv4 connection. Default: IPv6 connection

```
Usage: lwm2mclient [OPTION]
Launch a LWM2M client.
Options:
-n NAME Set the endpoint name of the Client. Default: testlightclient
-l PORT Set the local UDP port of the Client. Default: 56830
-4 Use IPv4 connection. Default: IPv6 connection
-S BYTES CoAP block size. Options: 16, 32, 64, 128, 256, 512, 1024. Default: 1024
```
### Bootstrap Server example
* Create a build directory and change to that.
* ``cmake [wakaama directory]/examples/bootstrap_server``
Expand Down
23 changes: 0 additions & 23 deletions coap/er-coap-13/er-coap-13.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,6 @@
#include <stdint.h>
#include <stddef.h> /* for size_t */

/*
* The maximum buffer size that is provided for resource responses and must be respected due to the limited IP buffer.
* Larger data must be handled by the resource and will be sent chunk-wise through a TCP stream or CoAP blocks.
*/
#ifndef REST_MAX_CHUNK_SIZE
#define REST_MAX_CHUNK_SIZE 128
rettichschnidi marked this conversation as resolved.
Show resolved Hide resolved
#endif

#define COAP_DEFAULT_MAX_AGE 60
#define COAP_RESPONSE_TIMEOUT 2
#define COAP_MAX_RETRANSMIT 4
Expand Down Expand Up @@ -82,21 +74,6 @@
#define COAP_HEADER_OPTION_DELTA_MASK 0xF0
#define COAP_HEADER_OPTION_SHORT_LENGTH_MASK 0x0F

/*
* Conservative size limit, as not all options have to be set at the same time.
*/
#ifndef COAP_MAX_HEADER_SIZE
/* Hdr CoT Age Tag Obs Tok Blo strings */
#define COAP_MAX_HEADER_SIZE (4 + 3 + 5 + 1+COAP_ETAG_LEN + 3 + 1+COAP_TOKEN_LEN + 4 + 30) /* 70 */
#endif /* COAP_MAX_HEADER_SIZE */

#define COAP_MAX_PACKET_SIZE (COAP_MAX_HEADER_SIZE + REST_MAX_CHUNK_SIZE)
/* 0/14 48 for IPv6 (28 for IPv4) */
#if COAP_MAX_PACKET_SIZE > (UIP_BUFSIZE - UIP_LLH_LEN - UIP_IPUDPH_LEN)
//#error "UIP_CONF_BUFFER_SIZE too small for REST_MAX_CHUNK_SIZE"
#endif


/* Bitmap for set options */
enum { OPTION_MAP_SIZE = sizeof(uint8_t) * 8 };
#define SET_OPTION(packet, opt) {if (opt <= sizeof((packet)->options) * OPTION_MAP_SIZE) {(packet)->options[opt / OPTION_MAP_SIZE] |= 1 << (opt % OPTION_MAP_SIZE);}}
Expand Down
8 changes: 4 additions & 4 deletions coap/transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -487,12 +487,12 @@ void transaction_set_payload(lwm2m_transaction_t * transaction, uint8_t * buffer
{
transaction->payload = buffer;
transaction->payload_len = length;

if ( length > REST_MAX_CHUNK_SIZE ){
coap_set_header_block1(transaction->message, 0, true, REST_MAX_CHUNK_SIZE);
const uint16_t lwm2m_coap_block_size = lwm2m_get_coap_block_size();
if (length > lwm2m_coap_block_size) {
coap_set_header_block1(transaction->message, 0, true, lwm2m_coap_block_size);
}

coap_set_payload(transaction->message, buffer, MIN(length, REST_MAX_CHUNK_SIZE));
coap_set_payload(transaction->message, buffer, MIN(length, lwm2m_coap_block_size));
}

bool transaction_free_userData(lwm2m_context_t * context, lwm2m_transaction_t * transaction)
Expand Down
102 changes: 62 additions & 40 deletions core/packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,37 @@ Contains code snippets which are:

#include <stdio.h>

#if __STDC_VERSION__ >= 201112L
#include <assert.h>
static_assert(LWM2M_COAP_DEFAULT_BLOCK_SIZE == 16 || LWM2M_COAP_DEFAULT_BLOCK_SIZE == 32 ||
LWM2M_COAP_DEFAULT_BLOCK_SIZE == 64 || LWM2M_COAP_DEFAULT_BLOCK_SIZE == 128 ||
LWM2M_COAP_DEFAULT_BLOCK_SIZE == 256 || LWM2M_COAP_DEFAULT_BLOCK_SIZE == 512 ||
LWM2M_COAP_DEFAULT_BLOCK_SIZE == 1024,
"Block transfer options support only power-of-two block sizes, from 2**4 (16) to 2**10 (1024) bytes.");
#endif

uint16_t coap_block_size = LWM2M_COAP_DEFAULT_BLOCK_SIZE;
rettichschnidi marked this conversation as resolved.
Show resolved Hide resolved

static bool validate_block_size(const uint16_t coap_block_size_arg) {
const uint16_t valid_block_sizes[7] = {16, 32, 64, 128, 256, 512, 1024};
rettichschnidi marked this conversation as resolved.
Show resolved Hide resolved
int i;
for (i = 0; i < 7; i++) {
if (coap_block_size_arg == valid_block_sizes[i]) {
return true;
}
}
return false;
}

bool lwm2m_set_coap_block_size(const uint16_t coap_block_size_arg) {
if (validate_block_size(coap_block_size_arg)) {
coap_block_size = coap_block_size_arg;
return true;
}
return false;
}

uint16_t lwm2m_get_coap_block_size() { return coap_block_size; }

static void handle_reset(lwm2m_context_t * contextP,
void * fromSessionH,
Expand Down Expand Up @@ -349,8 +380,8 @@ static int prv_change_to_block1(lwm2m_context_t * contextP, void * sessionH, uin
block_size = 16 << n;
}

block_size = MIN(block_size, REST_MAX_CHUNK_SIZE);
block_size = MIN(block_size, lwm2m_get_coap_block_size());

return prv_send_new_block1(contextP, transaction, 0, block_size);
}

Expand Down Expand Up @@ -407,7 +438,7 @@ static int prv_send_get_block2(lwm2m_context_t * contextP,
if (next == NULL) return COAP_500_INTERNAL_SERVER_ERROR;

// set block2 header
coap_set_header_block2(next->message, block2_num, 0, MIN(block2_size, REST_MAX_CHUNK_SIZE));
coap_set_header_block2(next->message, block2_num, 0, MIN(block2_size, lwm2m_get_coap_block_size()));

// update block2data to nect expected mid
coap_block2_set_expected_mid(blockDataHead, currentMID, nextMID);
Expand Down Expand Up @@ -451,7 +482,7 @@ void lwm2m_handle_packet(lwm2m_context_t * contextP,
if (message->code >= COAP_GET && message->code <= COAP_DELETE)
{
uint32_t block_num = 0;
uint16_t block_size = REST_MAX_CHUNK_SIZE;
uint16_t block_size = lwm2m_get_coap_block_size();
uint32_t block_offset = 0;

/* prepare response */
Expand All @@ -472,21 +503,18 @@ void lwm2m_handle_packet(lwm2m_context_t * contextP,
coap_set_header_token(response, message->token, message->token_len);
}

if (message->payload_len > REST_MAX_CHUNK_SIZE)
{
if (message->payload_len > lwm2m_get_coap_block_size()) {
coap_error_code = COAP_413_ENTITY_TOO_LARGE;

if (IS_OPTION(message, COAP_OPTION_BLOCK1)){
uint32_t block1_num;
uint8_t block1_more;
coap_get_header_block1(message, &block1_num, &block1_more, NULL, NULL);
coap_set_header_block1(response, block1_num, block1_more, REST_MAX_CHUNK_SIZE);
coap_set_header_block1(response, block1_num, block1_more, lwm2m_get_coap_block_size());
} else {
coap_set_header_block1(response, 0, 1, REST_MAX_CHUNK_SIZE);
coap_set_header_block1(response, 0, 1, lwm2m_get_coap_block_size());
}
}
else if (IS_OPTION(message, COAP_OPTION_BLOCK1))
{
} else if (IS_OPTION(message, COAP_OPTION_BLOCK1)) {
#ifdef LWM2M_CLIENT_MODE
// get server
lwm2m_server_t * peerP;
Expand Down Expand Up @@ -531,7 +559,8 @@ void lwm2m_handle_packet(lwm2m_context_t * contextP,

// parse block1 header
coap_get_header_block1(message, &block1_num, &block1_more, &block1_size, NULL);
LOG_ARG("Blockwise: block1 request NUM %u (SZX %u/ SZX Max%u) MORE %u", block1_num, block1_size, REST_MAX_CHUNK_SIZE, block1_more);
LOG_ARG("Blockwise: block1 request NUM %u (SZX %u/ SZX Max%u) MORE %u", block1_num, block1_size,
lwm2m_get_coap_block_size(), block1_more);

char * uri = coap_get_packet_uri_as_string(message);
if (uri == NULL){
Expand All @@ -553,7 +582,7 @@ void lwm2m_handle_packet(lwm2m_context_t * contextP,
message->payload_len = complete_buffer_size;
}
#endif
block1_size = MIN(block1_size, REST_MAX_CHUNK_SIZE);
block1_size = MIN(block1_size, lwm2m_get_coap_block_size());
coap_set_header_block1(response, block1_num, block1_more, block1_size);
}
}
Expand All @@ -574,8 +603,9 @@ void lwm2m_handle_packet(lwm2m_context_t * contextP,
/* get offset for blockwise transfers */
if (coap_get_header_block2(message, &block_num, NULL, &block_size, &block_offset))
{
LOG_ARG("Blockwise: block request %u (%u/%u) @ %u bytes", block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset);
block_size = MIN(block_size, REST_MAX_CHUNK_SIZE);
LOG_ARG("Blockwise: block request %u (%u/%u) @ %u bytes", block_num, block_size,
lwm2m_get_coap_block_size(), block_offset);
block_size = MIN(block_size, lwm2m_get_coap_block_size());
}

if (block_offset >= response->payload_len)
Expand All @@ -590,10 +620,10 @@ void lwm2m_handle_packet(lwm2m_context_t * contextP,
coap_set_header_block2(response, block_num, response->payload_len - block_offset > block_size, block_size);
coap_set_payload(response, response->payload+block_offset, MIN(response->payload_len - block_offset, block_size));
} /* if (valid offset) */
}
else if (response->payload_len > REST_MAX_CHUNK_SIZE){
coap_set_header_block2(response, 0, response->payload_len > REST_MAX_CHUNK_SIZE, REST_MAX_CHUNK_SIZE);
coap_set_payload(response, response->payload, REST_MAX_CHUNK_SIZE);
} else if (response->payload_len > lwm2m_get_coap_block_size()) {
coap_set_header_block2(response, 0, response->payload_len > lwm2m_get_coap_block_size(),
lwm2m_get_coap_block_size());
coap_set_payload(response, response->payload, lwm2m_get_coap_block_size());
}

coap_error_code = message_send(contextP, response, fromSessionH);
Expand Down Expand Up @@ -631,8 +661,7 @@ void lwm2m_handle_packet(lwm2m_context_t * contextP,
{
case COAP_TYPE_NON:
case COAP_TYPE_CON:
if (message->payload_len > REST_MAX_CHUNK_SIZE)
{
if (message->payload_len > lwm2m_get_coap_block_size()) {
#ifdef LWM2M_CLIENT_MODE
// get server
lwm2m_server_t * peerP;
Expand All @@ -650,7 +679,8 @@ void lwm2m_handle_packet(lwm2m_context_t * contextP,
if (peerP != NULL)
{
// retry as a block2 request
prv_send_get_block2(contextP, fromSessionH, peerP->blockData, message->mid, 0, REST_MAX_CHUNK_SIZE);
prv_send_get_block2(contextP, fromSessionH, peerP->blockData, message->mid, 0,
lwm2m_get_coap_block_size());
}
transaction_handleResponse(contextP, fromSessionH, message, NULL);
} else {
Expand All @@ -667,8 +697,7 @@ void lwm2m_handle_packet(lwm2m_context_t * contextP,
if (!done && message->type == COAP_TYPE_CON )
{
coap_init_message(response, COAP_TYPE_ACK, 0, message->mid);
if (message->payload_len > REST_MAX_CHUNK_SIZE)
{
if (message->payload_len > lwm2m_get_coap_block_size()) {
coap_set_status_code(response, COAP_413_ENTITY_TOO_LARGE);
}
coap_error_code = message_send(contextP, response, fromSessionH);
Expand All @@ -683,8 +712,7 @@ void lwm2m_handle_packet(lwm2m_context_t * contextP,
break;

case COAP_TYPE_ACK:
if (message->payload_len > REST_MAX_CHUNK_SIZE)
{
if (message->payload_len > lwm2m_get_coap_block_size()) {
#ifdef LWM2M_CLIENT_MODE
// get server
lwm2m_server_t * peerP;
Expand All @@ -702,12 +730,11 @@ void lwm2m_handle_packet(lwm2m_context_t * contextP,
if (peerP != NULL)
{
// retry as a block2 request
prv_send_get_block2(contextP, fromSessionH, peerP->blockData, message->mid, 0, REST_MAX_CHUNK_SIZE);
prv_send_get_block2(contextP, fromSessionH, peerP->blockData, message->mid, 0,
lwm2m_get_coap_block_size());
}
transaction_handleResponse(contextP, fromSessionH, message, NULL);
}
else if (IS_OPTION(message, COAP_OPTION_BLOCK1))
{
} else if (IS_OPTION(message, COAP_OPTION_BLOCK1)) {
uint32_t block_num;
uint16_t block_size;

Expand All @@ -728,9 +755,7 @@ void lwm2m_handle_packet(lwm2m_context_t * contextP,
}

transaction_handleResponse(contextP, fromSessionH, message, NULL);
}
else if (IS_OPTION(message, COAP_OPTION_BLOCK2))
{
} else if (IS_OPTION(message, COAP_OPTION_BLOCK2)) {
#ifdef LWM2M_CLIENT_MODE
// get server
lwm2m_server_t * peerP;
Expand Down Expand Up @@ -760,7 +785,8 @@ void lwm2m_handle_packet(lwm2m_context_t * contextP,

// parse block2 header
coap_get_header_block2(message, &block2_num, &block2_more, &block2_size, NULL);
LOG_ARG("Blockwise: block2 response NUM %u (SZX %u/ SZX Max%u) MORE %u", block2_num, block2_size, REST_MAX_CHUNK_SIZE, block2_more);
LOG_ARG("Blockwise: block2 response NUM %u (SZX %u/ SZX Max%u) MORE %u", block2_num,
block2_size, lwm2m_get_coap_block_size(), block2_more);

// handle block 2
coap_error_code = coap_block2_handler(&peerP->blockData, message->mid, message->payload, message->payload_len, block2_size, block2_num, block2_more, &complete_buffer, &complete_buffer_size);
Expand All @@ -780,18 +806,14 @@ void lwm2m_handle_packet(lwm2m_context_t * contextP,
coap_error_code = NO_ERROR;
}
}
}
else if (message->code == COAP_413_ENTITY_TOO_LARGE)
{
} else if (message->code == COAP_413_ENTITY_TOO_LARGE) {
rettichschnidi marked this conversation as resolved.
Show resolved Hide resolved
/*
All our responses are piggyback so this must be the result of request being too large (not a separate CON)
switch to a block1 request.
*/
prv_change_to_block1(contextP, fromSessionH, message->mid, message->size);
transaction_handleResponse(contextP, fromSessionH, message, NULL);
}
else
{
} else {
rettichschnidi marked this conversation as resolved.
Show resolved Hide resolved
transaction_handleResponse(contextP, fromSessionH, message, NULL);
}
break;
Expand Down
6 changes: 6 additions & 0 deletions core/wakaama.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
set(WAKAAMA_SOURCES_DIR ${CMAKE_CURRENT_LIST_DIR})
set(WAKAAMA_HEADERS_DIR ${CMAKE_CURRENT_LIST_DIR}/../include)

# The maximum buffer size that is provided for resource responses and must be respected due to the limited IP buffer.
# Larger data must be handled by the resource and will be sent chunk-wise through a TCP stream or CoAP blocks.
# Block size is set to 1024 bytes if not specified otherwise to avoid block transfers in common use cases.
set(LWM2M_COAP_DEFAULT_BLOCK_SIZE 1024 CACHE STRING "Set default coap block size")
add_compile_definitions(LWM2M_COAP_DEFAULT_BLOCK_SIZE=${LWM2M_COAP_DEFAULT_BLOCK_SIZE})

set(WAKAAMA_SOURCES
${WAKAAMA_SOURCES_DIR}/liblwm2m.c
${WAKAAMA_SOURCES_DIR}/uri.c
Expand Down
Loading