From 1599c6b8fe345ad489edc8ca0596810466ed73c6 Mon Sep 17 00:00:00 2001 From: Tero Heinonen Date: Wed, 1 Aug 2018 12:01:05 +0300 Subject: [PATCH] CoAP blockwise transfer support (#94) - sn_coap_protocol_parse() might call tx-callback. Create transaction before calling that. - Call prepare_blockwise_message() before sending CoAP message. This adds dependency to internal coap header file, and anyhow needs to be done inside the coap protocol library. - API to set blockwise message size --- coap-service/coap_service_api.h | 13 +++ source/coap_message_handler.c | 81 ++++++++++++------- source/coap_service_api.c | 9 +++ source/include/coap_message_handler.h | 4 + .../test_coap_message_handler.c | 37 ++++++--- .../unittest/stub/sn_coap_builder_stub.c | 5 ++ .../unittest/stub/sn_coap_protocol_stub.c | 10 +++ 7 files changed, 116 insertions(+), 43 deletions(-) diff --git a/coap-service/coap_service_api.h b/coap-service/coap_service_api.h index a21ff1d5914b..623c381744a0 100644 --- a/coap-service/coap_service_api.h +++ b/coap-service/coap_service_api.h @@ -353,6 +353,19 @@ extern int8_t coap_service_set_duplicate_message_buffer(int8_t service_id, uint8 */ extern int8_t coap_service_certificate_set(int8_t service_id, const unsigned char *cert, uint16_t cert_len, const unsigned char *priv_key, uint8_t priv_key_len); + +/** + * \brief Set CoAP blockwise payload size + * + * Set CoAP blockwise payload limit. If payload is bigger than configured limit, CoAP message will use blockwise option when sending. + * + * \param service_id Id number of the current service. + * \param size Blockwise size. Valid sizes are 16, 32, 64, 128, 256, 512 and 1024 bytes + * + * \return -1 For failure + *- 0 For success + */ +extern int8_t coap_service_blockwise_size_set(int8_t service_id, uint16_t size); #ifdef __cplusplus } #endif diff --git a/source/coap_message_handler.c b/source/coap_message_handler.c index 57b4a96022ff..db2cc14ef667 100644 --- a/source/coap_message_handler.c +++ b/source/coap_message_handler.c @@ -20,6 +20,7 @@ #include "coap_service_api_internal.h" #include "coap_message_handler.h" #include "mbed-coap/sn_coap_protocol.h" +#include "source/include/sn_coap_protocol_internal.h" #include "socket_api.h" #include "ns_types.h" #include "ns_list.h" @@ -138,7 +139,6 @@ void transaction_delete(coap_transaction_t *this) if (!coap_message_handler_transaction_valid(this)) { return; } - ns_list_remove(&request_list, this); transaction_free(this); @@ -163,11 +163,14 @@ void transactions_delete_all(uint8_t *address_ptr, uint16_t port) static int8_t coap_rx_function(sn_coap_hdr_s *resp_ptr, sn_nsdl_addr_s *address_ptr, void *param) { coap_transaction_t *this = NULL; - (void)address_ptr; (void)param; - tr_warn("transaction not handled %d", resp_ptr->msg_id); - if (!resp_ptr) { + if (resp_ptr->coap_status == COAP_STATUS_BUILDER_BLOCK_SENDING_DONE) { + return 0; + } + + tr_warn("transaction was not handled %d", resp_ptr->msg_id); + if (!resp_ptr || !address_ptr) { return -1; } if(resp_ptr->token_ptr){ @@ -214,6 +217,9 @@ coap_msg_handler_t *coap_message_handler_init(void *(*used_malloc_func_ptr)(uint /* Set default buffer size for CoAP duplicate message detection */ sn_coap_protocol_set_duplicate_buffer_size(handle->coap, DUPLICATE_MESSAGE_BUFFER_SIZE); + /* Set default blockwise message size. */ + sn_coap_protocol_set_block_size(handle->coap, DEFAULT_BLOCKWISE_DATA_SIZE); + /* Set default CoAP retransmission paramters */ sn_coap_protocol_set_retransmission_parameters(handle->coap, COAP_RESENDING_COUNT, COAP_RESENDING_INTERVAL); @@ -263,6 +269,7 @@ int16_t coap_message_handler_coap_msg_process(coap_msg_handler_t *handle, int8_t sn_nsdl_addr_s src_addr; sn_coap_hdr_s *coap_message; int16_t ret_val = 0; + coap_transaction_t *this = NULL; if (!cb || !handle) { return -1; @@ -273,8 +280,19 @@ int16_t coap_message_handler_coap_msg_process(coap_msg_handler_t *handle, int8_t src_addr.type = SN_NSDL_ADDRESS_TYPE_IPV6; src_addr.port = port; - coap_message = sn_coap_protocol_parse(handle->coap, &src_addr, data_len, data_ptr, NULL); + coap_transaction_t *transaction_ptr = transaction_create(); + if (!transaction_ptr) { + return -1; + } + transaction_ptr->service_id = coap_service_id_find_by_socket(socket_id); + transaction_ptr->client_request = false;// this is server transaction + memcpy(transaction_ptr->local_address, *(dst_addr_ptr) == 0xFF ? ns_in6addr_any : dst_addr_ptr, 16); + memcpy(transaction_ptr->remote_address, source_addr_ptr, 16); + transaction_ptr->remote_port = port; + + coap_message = sn_coap_protocol_parse(handle->coap, &src_addr, data_len, data_ptr, transaction_ptr); if (coap_message == NULL) { + transaction_delete(transaction_ptr); tr_err("CoAP Parsing failed"); return -1; } @@ -284,36 +302,26 @@ int16_t coap_message_handler_coap_msg_process(coap_msg_handler_t *handle, int8_t /* Check, if coap itself sends response, or block receiving is ongoing... */ if (coap_message->coap_status != COAP_STATUS_OK && coap_message->coap_status != COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED) { tr_debug("CoAP library responds"); + transaction_delete(transaction_ptr); ret_val = -1; goto exit; } /* Request received */ if (coap_message->msg_code > 0 && coap_message->msg_code < 32) { - coap_transaction_t *transaction_ptr = transaction_create(); - if (transaction_ptr) { - transaction_ptr->service_id = coap_service_id_find_by_socket(socket_id); - transaction_ptr->msg_id = coap_message->msg_id; - transaction_ptr->client_request = false;// this is server transaction - transaction_ptr->req_msg_type = coap_message->msg_type; - memcpy(transaction_ptr->local_address, *(dst_addr_ptr) == 0xFF ? ns_in6addr_any : dst_addr_ptr, 16); - memcpy(transaction_ptr->remote_address, source_addr_ptr, 16); - if (coap_message->token_len) { - memcpy(transaction_ptr->token, coap_message->token_ptr, coap_message->token_len); - transaction_ptr->token_len = coap_message->token_len; - } - transaction_ptr->remote_port = port; - if (cb(socket_id, coap_message, transaction_ptr) < 0) { - // negative return value = message ignored -> delete transaction - transaction_delete(transaction_ptr); - } - goto exit; - } else { - ret_val = -1; + transaction_ptr->msg_id = coap_message->msg_id; + transaction_ptr->req_msg_type = coap_message->msg_type; + if (coap_message->token_len) { + memcpy(transaction_ptr->token, coap_message->token_ptr, coap_message->token_len); + transaction_ptr->token_len = coap_message->token_len; } + if (cb(socket_id, coap_message, transaction_ptr) < 0) { + // negative return value = message ignored -> delete transaction + transaction_delete(transaction_ptr); + } + goto exit; /* Response received */ } else { - coap_transaction_t *this = NULL; if (coap_message->token_ptr) { this = transaction_find_client_by_token(coap_message->token_ptr, coap_message->token_len, source_addr_ptr, port); } @@ -331,6 +339,10 @@ int16_t coap_message_handler_coap_msg_process(coap_msg_handler_t *handle, int8_t } exit: + if (coap_message->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED) { + handle->sn_coap_service_free(coap_message->payload_ptr); + } + sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message); return ret_val; @@ -350,7 +362,7 @@ uint16_t coap_message_handler_request_send(coap_msg_handler_t *handle, int8_t se tr_debug("Service %d, send CoAP request payload_len %d", service_id, payload_len); transaction_ptr = transaction_create(); - if (!uri || !transaction_ptr) { + if (!uri || !transaction_ptr || !handle) { return 0; } @@ -383,7 +395,10 @@ uint16_t coap_message_handler_request_send(coap_msg_handler_t *handle, int8_t se request.payload_len = payload_len; request.payload_ptr = (uint8_t *) payload_ptr; // Cast away const and trust that nsdl doesn't modify... - data_len = sn_coap_builder_calc_needed_packet_data_size(&request); + + prepare_blockwise_message(handle->coap, &request); + + data_len = sn_coap_builder_calc_needed_packet_data_size_2(&request, sn_coap_protocol_get_configured_blockwise_size(handle->coap)); data_ptr = own_alloc(data_len); if(data_len > 0 && !data_ptr){ transaction_delete(transaction_ptr); @@ -408,6 +423,10 @@ uint16_t coap_message_handler_request_send(coap_msg_handler_t *handle, int8_t se // Free allocated data own_free(data_ptr); + if(request.options_list_ptr) { + own_free(request.options_list_ptr); + } + if(request_response_cb == NULL){ //No response expected return 0; @@ -426,8 +445,10 @@ static int8_t coap_message_handler_resp_build_and_send(coap_msg_handler_t *handl dst_addr.addr_len = 16; dst_addr.type = SN_NSDL_ADDRESS_TYPE_IPV6; dst_addr.port = transaction_ptr->remote_port; - - data_len = sn_coap_builder_calc_needed_packet_data_size(coap_msg_ptr); +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE + prepare_blockwise_message(handle->coap, coap_msg_ptr); +#endif + data_len = sn_coap_builder_calc_needed_packet_data_size_2(coap_msg_ptr, sn_coap_protocol_get_configured_blockwise_size(handle->coap)); data_ptr = own_alloc(data_len); if (data_len > 0 && !data_ptr) { return -1; diff --git a/source/coap_service_api.c b/source/coap_service_api.c index 9adcee212a4e..a2966c28a42c 100644 --- a/source/coap_service_api.c +++ b/source/coap_service_api.c @@ -606,3 +606,12 @@ int8_t coap_service_certificate_set(int8_t service_id, const unsigned char *cert return 0; } + +int8_t coap_service_blockwise_size_set(int8_t service_id, uint16_t size) +{ + if (!coap_service_handle) { + return -1; + } + + return sn_coap_protocol_set_block_size(coap_service_handle->coap, size); +} diff --git a/source/include/coap_message_handler.h b/source/include/coap_message_handler.h index b4e51c54ba6a..9b54619ca792 100644 --- a/source/include/coap_message_handler.h +++ b/source/include/coap_message_handler.h @@ -23,9 +23,13 @@ #include "ns_list.h" #define TRANSACTION_LIFETIME 180 + /* Default value for CoAP duplicate message buffer (0 = disabled) */ #define DUPLICATE_MESSAGE_BUFFER_SIZE 0 +/* Default value for CoAP blockwise data size (0 = disabled) */ +#define DEFAULT_BLOCKWISE_DATA_SIZE 0 + /* Default values for CoAP resendings */ #define COAP_RESENDING_COUNT 3 #define COAP_RESENDING_INTERVAL 10 diff --git a/test/coap-service/unittest/coap_message_handler/test_coap_message_handler.c b/test/coap-service/unittest/coap_message_handler/test_coap_message_handler.c index 91af9de1e406..c00067fa49d8 100644 --- a/test/coap-service/unittest/coap_message_handler/test_coap_message_handler.c +++ b/test/coap-service/unittest/coap_message_handler/test_coap_message_handler.c @@ -81,6 +81,7 @@ bool test_coap_message_handler_init() retCounter = 1; sn_coap_protocol_stub.expectedCoap = (struct coap_s*)malloc(sizeof(struct coap_s)); memset(sn_coap_protocol_stub.expectedCoap, 0, sizeof(struct coap_s)); + nsdynmemlib_stub.returnCounter = 1; coap_msg_handler_t *handle = coap_message_handler_init(&test_own_alloc, &test_own_free, &coap_tx_function); if( NULL == handle ) return false; @@ -97,6 +98,7 @@ bool test_coap_message_handler_destroy() retCounter = 1; sn_coap_protocol_stub.expectedCoap = (struct coap_s*)malloc(sizeof(struct coap_s)); memset(sn_coap_protocol_stub.expectedCoap, 0, sizeof(struct coap_s)); + nsdynmemlib_stub.returnCounter = 1; coap_msg_handler_t *handle = coap_message_handler_init(&test_own_alloc, &test_own_free, &coap_tx_function); if( 0 != coap_message_handler_destroy(handle) ) @@ -113,6 +115,7 @@ bool test_coap_message_handler_find_transaction() retCounter = 1; sn_coap_protocol_stub.expectedCoap = (struct coap_s*)malloc(sizeof(struct coap_s)); memset(sn_coap_protocol_stub.expectedCoap, 0, sizeof(struct coap_s)); + nsdynmemlib_stub.returnCounter = 1; coap_msg_handler_t *handle = coap_message_handler_init(&test_own_alloc, &test_own_free, &coap_tx_function); uint8_t buf[16]; @@ -140,26 +143,29 @@ bool test_coap_message_handler_coap_msg_process() { uint8_t buf[16]; memset(&buf, 1, 16); + bool ret_val = false; /*Handler is null*/ if( -1 != coap_message_handler_coap_msg_process(NULL, 0, buf, 22, ns_in6addr_any, NULL, 0, NULL)) - return false; + goto exit; retCounter = 1; sn_coap_protocol_stub.expectedCoap = (struct coap_s*)malloc(sizeof(struct coap_s)); memset(sn_coap_protocol_stub.expectedCoap, 0, sizeof(struct coap_s)); + nsdynmemlib_stub.returnCounter = 1; coap_msg_handler_t *handle = coap_message_handler_init(&test_own_alloc, &test_own_free, &coap_tx_function); sn_coap_protocol_stub.expectedHeader = NULL; /* Coap parse returns null */ if( -1 != coap_message_handler_coap_msg_process(handle, 0, buf, 22, ns_in6addr_any, NULL, 0, process_cb)) - return false; + goto exit; sn_coap_protocol_stub.expectedHeader = (sn_coap_hdr_s *)malloc(sizeof(sn_coap_hdr_s)); memset(sn_coap_protocol_stub.expectedHeader, 0, sizeof(sn_coap_hdr_s)); sn_coap_protocol_stub.expectedHeader->coap_status = 66; + nsdynmemlib_stub.returnCounter = 1; /* Coap library responds */ if( -1 != coap_message_handler_coap_msg_process(handle, 0, buf, 22, ns_in6addr_any, NULL, 0, process_cb)) - return false; + goto exit; sn_coap_protocol_stub.expectedHeader = (sn_coap_hdr_s *)malloc(sizeof(sn_coap_hdr_s)); memset(sn_coap_protocol_stub.expectedHeader, 0, sizeof(sn_coap_hdr_s)); @@ -167,8 +173,9 @@ bool test_coap_message_handler_coap_msg_process() sn_coap_protocol_stub.expectedHeader->msg_code = 1; retValue = 0; /* request received */ + nsdynmemlib_stub.returnCounter = 1; if( 0 != coap_message_handler_coap_msg_process(handle, 0, buf, 22, ns_in6addr_any, NULL, 0, process_cb)) - return false; + goto exit; sn_coap_protocol_stub.expectedHeader = (sn_coap_hdr_s *)malloc(sizeof(sn_coap_hdr_s)); memset(sn_coap_protocol_stub.expectedHeader, 0, sizeof(sn_coap_hdr_s)); @@ -177,15 +184,16 @@ bool test_coap_message_handler_coap_msg_process() nsdynmemlib_stub.returnCounter = 1; retValue = -1; if( 0 != coap_message_handler_coap_msg_process(handle, 0, buf, 22, ns_in6addr_any, NULL, 0, process_cb)) - return false; + goto exit; sn_coap_protocol_stub.expectedHeader = (sn_coap_hdr_s *)malloc(sizeof(sn_coap_hdr_s)); memset(sn_coap_protocol_stub.expectedHeader, 0, sizeof(sn_coap_hdr_s)); sn_coap_protocol_stub.expectedHeader->coap_status = COAP_STATUS_OK; sn_coap_protocol_stub.expectedHeader->msg_code = 333; + nsdynmemlib_stub.returnCounter = 1; if( -1 != coap_message_handler_coap_msg_process(handle, 0, buf, 22, ns_in6addr_any, NULL, 0, process_cb)) - return false; + goto exit; sn_coap_protocol_stub.expectedHeader = (sn_coap_hdr_s *)malloc(sizeof(sn_coap_hdr_s)); memset(sn_coap_protocol_stub.expectedHeader, 0, sizeof(sn_coap_hdr_s)); @@ -200,20 +208,19 @@ bool test_coap_message_handler_coap_msg_process() sn_coap_builder_stub.expectedUint16 = 1; nsdynmemlib_stub.returnCounter = 3; if( 2 != coap_message_handler_request_send(handle, 3, 0, buf, 24, 1, 2, &uri, 4, NULL, 0, &resp_recv)) - return false; + goto exit; sn_coap_protocol_stub.expectedHeader->msg_id = 2; -// sn_coap_protocol_stub.expectedHeader->token_ptr = (uint8_t*)malloc(4); -// memset(sn_coap_protocol_stub.expectedHeader->token_ptr, 1, 4); - if( -1 != coap_message_handler_coap_msg_process(handle, 0, buf, 22, ns_in6addr_any, NULL, 0, process_cb)) - return false; -// free(sn_coap_protocol_stub.expectedHeader->token_ptr); + if( -1 != coap_message_handler_coap_msg_process(handle, 0, buf, 22, ns_in6addr_any, NULL, 0, process_cb)) + goto exit; + ret_val = true; +exit: free(sn_coap_protocol_stub.expectedCoap); sn_coap_protocol_stub.expectedCoap = NULL; coap_message_handler_destroy(handle); - return true; + return ret_val; } bool test_coap_message_handler_request_send() @@ -221,6 +228,7 @@ bool test_coap_message_handler_request_send() retCounter = 1; sn_coap_protocol_stub.expectedCoap = (struct coap_s*)malloc(sizeof(struct coap_s)); memset(sn_coap_protocol_stub.expectedCoap, 0, sizeof(struct coap_s)); + nsdynmemlib_stub.returnCounter = 1; coap_msg_handler_t *handle = coap_message_handler_init(&test_own_alloc, &test_own_free, &coap_tx_function); uint8_t buf[16]; @@ -293,6 +301,7 @@ bool test_coap_message_handler_request_delete() retCounter = 1; sn_coap_protocol_stub.expectedCoap = (struct coap_s*)malloc(sizeof(struct coap_s)); memset(sn_coap_protocol_stub.expectedCoap, 0, sizeof(struct coap_s)); + nsdynmemlib_stub.returnCounter = 1; coap_msg_handler_t *handle = coap_message_handler_init(&test_own_alloc, &test_own_free, &coap_tx_function); uint8_t buf[16]; @@ -329,6 +338,7 @@ bool test_coap_message_handler_response_send() retCounter = 1; sn_coap_protocol_stub.expectedCoap = (struct coap_s*)malloc(sizeof(struct coap_s)); memset(sn_coap_protocol_stub.expectedCoap, 0, sizeof(struct coap_s)); + nsdynmemlib_stub.returnCounter = 1; coap_msg_handler_t *handle = coap_message_handler_init(&test_own_alloc, &test_own_free, &coap_tx_function); sn_coap_hdr_s *header = (sn_coap_hdr_s *)malloc(sizeof(sn_coap_hdr_s)); memset(header, 0, sizeof(sn_coap_hdr_s)); @@ -385,6 +395,7 @@ bool test_coap_message_handler_exec() retCounter = 1; sn_coap_protocol_stub.expectedCoap = (struct coap_s*)malloc(sizeof(struct coap_s)); memset(sn_coap_protocol_stub.expectedCoap, 0, sizeof(struct coap_s)); + nsdynmemlib_stub.returnCounter = 1; coap_msg_handler_t *handle = coap_message_handler_init(&test_own_alloc, &test_own_free, &coap_tx_function); if( 0 != coap_message_handler_exec(handle, 0)) diff --git a/test/coap-service/unittest/stub/sn_coap_builder_stub.c b/test/coap-service/unittest/stub/sn_coap_builder_stub.c index 99c010d5bd13..0aa5f2199d17 100644 --- a/test/coap-service/unittest/stub/sn_coap_builder_stub.c +++ b/test/coap-service/unittest/stub/sn_coap_builder_stub.c @@ -49,6 +49,11 @@ uint16_t sn_coap_builder_calc_needed_packet_data_size(sn_coap_hdr_s *src_coap_ms return sn_coap_builder_stub.expectedUint16; } +uint16_t sn_coap_builder_calc_needed_packet_data_size_2(sn_coap_hdr_s *src_coap_msg_ptr, uint16_t blockwise_payload_size) +{ + return sn_coap_builder_stub.expectedUint16; +} + int16_t sn_coap_builder_options_build_add_zero_length_option(uint8_t **dst_packet_data_pptr, uint8_t option_length, uint8_t option_exist, sn_coap_option_numbers_e option_number) { return sn_coap_builder_stub.expectedInt16; diff --git a/test/coap-service/unittest/stub/sn_coap_protocol_stub.c b/test/coap-service/unittest/stub/sn_coap_protocol_stub.c index e12c2cbf92d6..fcab0aa2d850 100644 --- a/test/coap-service/unittest/stub/sn_coap_protocol_stub.c +++ b/test/coap-service/unittest/stub/sn_coap_protocol_stub.c @@ -110,3 +110,13 @@ int8_t sn_coap_protocol_delete_retransmission(struct coap_s *handle, uint16_t ms { return 0; } + +uint16_t sn_coap_protocol_get_configured_blockwise_size(struct coap_s *handle) +{ + return 0; +} + +int8_t prepare_blockwise_message(struct coap_s *handle, sn_coap_hdr_s *src_coap_msg_ptr) +{ + return 0; +}