diff --git a/features/frameworks/mbed-coap/CHANGELOG.md b/features/frameworks/mbed-coap/CHANGELOG.md index 1b01fc89fb..a7d2d68ddc 100644 --- a/features/frameworks/mbed-coap/CHANGELOG.md +++ b/features/frameworks/mbed-coap/CHANGELOG.md @@ -1,6 +1,23 @@ # Change Log -## [v4.8.1(https://github.com/ARMmbed/mbed-coap/releases/tag/v4.8.1) +## [v5.1.0](https://github.com/ARMmbed/mbed-coap/releases/tag/v5.1.0) + +- Introduce SN_COAP_REDUCE_BLOCKWISE_HEAP_FOOTPRINT configuration flag. + Flag is disabled by default to keep the backward compatibility in place. + If flag is enabled, application must NOT free the payload when it gets the COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED status. + And application must call sn_coap_protocol_block_remove() instead. + +-[Full Changelog](https://github.com/ARMmbed/mbed-coap/compare/v5.0.0...v5.1.0) + +## [v5.0.0](https://github.com/ARMmbed/mbed-coap/releases/tag/v5.0.0) + +- Reduce heap footprint by storing only single block when receiving a blockwise message. + * User is now responsible of freeing the data by calling sn_coap_protocol_block_remove() and must not free the payload separately. +- Bug fix: Request blockwise transfer if incoming payload length is too large and when it comes without block indication. + +-[Full Changelog](https://github.com/ARMmbed/mbed-coap/compare/v4.8.1...v5.0.0) + +## [v4.8.1](https://github.com/ARMmbed/mbed-coap/releases/tag/v4.8.1) - Store ACK's also into duplicate info list. - ROM size optimization. Flash size has gone down ~1100 bytes. diff --git a/features/frameworks/mbed-coap/mbed-coap/sn_coap_header.h b/features/frameworks/mbed-coap/mbed-coap/sn_coap_header.h index 4617bc789b..881770d849 100644 --- a/features/frameworks/mbed-coap/mbed-coap/sn_coap_header.h +++ b/features/frameworks/mbed-coap/mbed-coap/sn_coap_header.h @@ -157,7 +157,7 @@ typedef enum sn_coap_status_ { COAP_STATUS_PARSER_BLOCKWISE_ACK = 4, /**< Acknowledgement for sent Blockwise message received */ COAP_STATUS_PARSER_BLOCKWISE_MSG_REJECTED = 5, /**< Blockwise message received but not supported by compiling switch */ COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED = 6, /**< Blockwise message fully received and returned to app. - User must take care of releasing whole payload of the blockwise messages */ + User is responsible of freeing the data by calling sn_coap_protocol_block_remove() */ COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED = 7, /**< When re-transmissions have been done and ACK not received, CoAP library calls RX callback with this status */ diff --git a/features/frameworks/mbed-coap/mbed-coap/sn_config.h b/features/frameworks/mbed-coap/mbed-coap/sn_config.h index a71f854544..f04ffe80c7 100644 --- a/features/frameworks/mbed-coap/mbed-coap/sn_config.h +++ b/features/frameworks/mbed-coap/mbed-coap/sn_config.h @@ -260,4 +260,14 @@ #define SN_COAP_BLOCKWISE_INTERNAL_BLOCK_2_HANDLING_ENABLED 1 #endif +/** + * \def SN_COAP_REDUCE_BLOCKWISE_HEAP_FOOTPRINT + * \brief A heap optimization switch, which removes unnecessary copy of the blockwise data. + * If enabled, application must NOT free the payload when it gets the COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED status. + * Application must call sn_coap_protocol_block_remove() instead. + */ +#ifndef SN_COAP_REDUCE_BLOCKWISE_HEAP_FOOTPRINT +#define SN_COAP_REDUCE_BLOCKWISE_HEAP_FOOTPRINT 0 /**< Disabled by default */ +#endif + #endif // SN_CONFIG_H diff --git a/features/frameworks/mbed-coap/source/include/sn_coap_protocol_internal.h b/features/frameworks/mbed-coap/source/include/sn_coap_protocol_internal.h index 1592df55b4..f0cfffa5a8 100644 --- a/features/frameworks/mbed-coap/source/include/sn_coap_protocol_internal.h +++ b/features/frameworks/mbed-coap/source/include/sn_coap_protocol_internal.h @@ -97,6 +97,7 @@ typedef struct coap_blockwise_payload_ { uint16_t payload_len; uint8_t *payload_ptr; + unsigned int use_size1:1; ns_list_link_t link; } coap_blockwise_payload_s; diff --git a/features/frameworks/mbed-coap/source/sn_coap_protocol.c b/features/frameworks/mbed-coap/source/sn_coap_protocol.c index b4a1bafa79..aff7fff444 100644 --- a/features/frameworks/mbed-coap/source/sn_coap_protocol.c +++ b/features/frameworks/mbed-coap/source/sn_coap_protocol.c @@ -56,19 +56,20 @@ static bool sn_coap_protocol_update_duplicate_package_data(cons #endif #if SN_COAP_BLOCKWISE_ENABLED || SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwising is not enabled, this part of code will not be compiled */ -static void sn_coap_protocol_linked_list_blockwise_msg_remove(struct coap_s *handle, coap_blockwise_msg_s *removed_msg_ptr); -static void sn_coap_protocol_linked_list_blockwise_payload_store(struct coap_s *handle, sn_nsdl_addr_s *addr_ptr, uint16_t stored_payload_len, uint8_t *stored_payload_ptr, uint8_t *token_ptr, uint8_t token_len, uint32_t block_number); -static uint8_t *sn_coap_protocol_linked_list_blockwise_payload_search(struct coap_s *handle, const sn_nsdl_addr_s *src_addr_ptr, uint16_t *payload_length, const uint8_t *token_ptr, uint8_t token_len); -static bool sn_coap_protocol_linked_list_blockwise_payload_search_compare_block_number(struct coap_s *handle, const sn_nsdl_addr_s *src_addr_ptr, const uint8_t *token_ptr, uint8_t token_len, uint32_t block_number); -static void sn_coap_protocol_linked_list_blockwise_payload_remove(struct coap_s *handle, coap_blockwise_payload_s *removed_payload_ptr); -static void sn_coap_protocol_linked_list_blockwise_payload_remove_oldest(struct coap_s *handle, uint8_t *token_ptr, uint8_t token_len); -static uint32_t sn_coap_protocol_linked_list_blockwise_payloads_get_len(struct coap_s *handle, const sn_nsdl_addr_s *src_addr_ptr, const uint8_t *token_ptr, uint8_t token_len); -static void sn_coap_protocol_handle_blockwise_timout(struct coap_s *handle); -static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, sn_coap_hdr_s *received_coap_msg_ptr, void *param); -static bool sn_coap_handle_last_blockwise(struct coap_s *handle, const sn_nsdl_addr_s *src_addr_ptr, sn_coap_hdr_s *received_coap_msg_ptr); -static sn_coap_hdr_s *sn_coap_protocol_copy_header(struct coap_s *handle, const sn_coap_hdr_s *source_header_ptr); -static coap_blockwise_msg_s *search_sent_blockwise_message(struct coap_s *handle, uint16_t msg_id); -static int16_t store_blockwise_copy(struct coap_s *handle, const sn_coap_hdr_s *src_coap_msg_ptr, void *param, uint16_t original_payload_len, bool copy_payload); +static void sn_coap_protocol_linked_list_blockwise_msg_remove(struct coap_s *handle, coap_blockwise_msg_s *removed_msg_ptr); +static void sn_coap_protocol_linked_list_blockwise_payload_store(struct coap_s *handle, sn_nsdl_addr_s *addr_ptr, uint16_t payload_len, uint8_t *payload_ptr, uint8_t *token_ptr, uint8_t token_len, uint32_t block_number, uint32_t size1); +static uint8_t *sn_coap_protocol_linked_list_blockwise_payload_search(struct coap_s *handle, const sn_nsdl_addr_s *src_addr_ptr, uint16_t *payload_length, const uint8_t *token_ptr, uint8_t token_len); +static coap_blockwise_payload_s *sn_coap_protocol_linked_list_blockwise_search(struct coap_s *handle, const sn_nsdl_addr_s *src_addr_ptr, const uint8_t *token_ptr, uint8_t token_len); +static bool sn_coap_protocol_linked_list_blockwise_payload_search_compare_block_number(struct coap_s *handle, const sn_nsdl_addr_s *src_addr_ptr, const uint8_t *token_ptr, uint8_t token_len, uint32_t block_number); +static void sn_coap_protocol_linked_list_blockwise_payload_remove(struct coap_s *handle, coap_blockwise_payload_s *removed_payload_ptr); +static void sn_coap_protocol_linked_list_blockwise_payload_remove_oldest(struct coap_s *handle, uint8_t *token_ptr, uint8_t token_len); +static uint32_t sn_coap_protocol_linked_list_blockwise_payloads_get_len(struct coap_s *handle, const sn_nsdl_addr_s *src_addr_ptr, const uint8_t *token_ptr, uint8_t token_len); +static void sn_coap_protocol_handle_blockwise_timout(struct coap_s *handle); +static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, sn_coap_hdr_s *received_coap_msg_ptr, void *param); +static bool sn_coap_handle_last_blockwise(struct coap_s *handle, const sn_nsdl_addr_s *src_addr_ptr, sn_coap_hdr_s *received_coap_msg_ptr); +static sn_coap_hdr_s *sn_coap_protocol_copy_header(struct coap_s *handle, const sn_coap_hdr_s *source_header_ptr); +static coap_blockwise_msg_s *search_sent_blockwise_message(struct coap_s *handle, uint16_t msg_id); +static int16_t store_blockwise_copy(struct coap_s *handle, const sn_coap_hdr_s *src_coap_msg_ptr, void *param, uint16_t original_payload_len, bool copy_payload); #endif #if ENABLE_RESENDINGS @@ -561,6 +562,7 @@ static int16_t store_blockwise_copy(struct coap_s *handle, const sn_coap_hdr_s * stored_blockwise_msg_ptr->param = param; stored_blockwise_msg_ptr->msg_id = stored_blockwise_msg_ptr->coap_msg_ptr->msg_id; + ns_list_add_to_end(&handle->linked_list_blockwise_sent_msgs, stored_blockwise_msg_ptr); return 0; @@ -706,11 +708,12 @@ sn_coap_hdr_s *sn_coap_protocol_parse(struct coap_s *handle, sn_nsdl_addr_s *src /*** And here we check if message was block message ***/ /*** If so, we call own block handling function and ***/ /*** return to caller. ***/ + #if SN_COAP_BLOCKWISE_ENABLED || SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE if (returned_dst_coap_msg_ptr->options_list_ptr != NULL && - (returned_dst_coap_msg_ptr->options_list_ptr->block1 != COAP_OPTION_BLOCK_NONE || - returned_dst_coap_msg_ptr->options_list_ptr->block2 != COAP_OPTION_BLOCK_NONE)) { + (returned_dst_coap_msg_ptr->options_list_ptr->block1 != COAP_OPTION_BLOCK_NONE || + returned_dst_coap_msg_ptr->options_list_ptr->block2 != COAP_OPTION_BLOCK_NONE)) { // the sn_coap_handle_blockwise_message() will return the given message on success or NULL on error if (sn_coap_handle_blockwise_message(handle, src_addr_ptr, returned_dst_coap_msg_ptr, param) == NULL) { @@ -722,6 +725,63 @@ sn_coap_hdr_s *sn_coap_protocol_parse(struct coap_s *handle, sn_nsdl_addr_s *src returned_dst_coap_msg_ptr = NULL; } + } else if (returned_dst_coap_msg_ptr->payload_len > handle->sn_coap_block_data_size) { + + // If message comes without block1 information and payload length is too large to handle. + // Send hint response to the server to start a blockwise transfer. + + tr_info("sn_coap_protocol_parse - payload too large, request blockwise transfer"); + + uint8_t *packet_data_ptr = NULL; + uint16_t packet_data_size = 0; + sn_coap_hdr_s *resp = sn_coap_build_response(handle, + returned_dst_coap_msg_ptr, + COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE); + + if (resp == NULL) { + tr_error("sn_coap_protocol_parse - payload too large, failed to build response!"); + goto cleanup; + } + + if (sn_coap_parser_alloc_options(handle, resp) == NULL) { + tr_error("sn_coap_protocol_parse - payload too large, failed to allocate options!"); + goto cleanup; + } + + // set block1 size into response + resp->options_list_ptr->block1 &= 0x08; + resp->options_list_ptr->block1 |= sn_coap_convert_block_size(handle->sn_coap_block_data_size); + + packet_data_size = sn_coap_builder_calc_needed_packet_data_size_2(resp, handle->sn_coap_block_data_size); + + packet_data_ptr = handle->sn_coap_protocol_malloc(packet_data_size); + + if (packet_data_ptr == NULL) { + tr_error("sn_coap_protocol_parse - payload too large, failed to allocate buffer!"); + goto cleanup; + } + + if (sn_coap_builder_2(packet_data_ptr, resp, handle->sn_coap_block_data_size) < 0) { + tr_error("sn_coap_protocol_parse - payload too large, builder failed!"); + goto cleanup; + } + + sn_coap_parser_release_allocated_coap_msg_mem(handle, resp); + + handle->sn_coap_tx_callback(packet_data_ptr, packet_data_size, src_addr_ptr, param); + + handle->sn_coap_protocol_free(packet_data_ptr); + + returned_dst_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING; + + return returned_dst_coap_msg_ptr; + +cleanup: + sn_coap_parser_release_allocated_coap_msg_mem(handle, resp); + sn_coap_parser_release_allocated_coap_msg_mem(handle, returned_dst_coap_msg_ptr); + handle->sn_coap_protocol_free(packet_data_ptr); + return NULL; + } else if (returned_dst_coap_msg_ptr->msg_code != COAP_MSG_CODE_EMPTY) { // Do not clean stored blockwise message when empty ack is received. // Stored message is mandatory when building a next (GET) blockwise message. @@ -1155,7 +1215,6 @@ static void sn_coap_protocol_duplication_info_free(struct coap_s *handle, coap_d } } - #if SN_COAP_BLOCKWISE_ENABLED || SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /**************************************************************************//** * \fn static void sn_coap_protocol_linked_list_blockwise_msg_remove(struct coap_s *handle, coap_blockwise_msg_s *removed_msg_ptr) @@ -1179,28 +1238,32 @@ static void sn_coap_protocol_linked_list_blockwise_msg_remove(struct coap_s *han } /**************************************************************************//** - * \fn static void sn_coap_protocol_linked_list_blockwise_payload_store(sn_nsdl_addr_s *addr_ptr, uint16_t stored_payload_len, uint8_t *stored_payload_ptr) + * \fn static void sn_coap_protocol_linked_list_blockwise_payload_store(sn_nsdl_addr_s *addr_ptr, uint16_t payload_len, uint8_t *payload_ptr) * * \brief Stores blockwise payload to Linked list * * \param *addr_ptr is pointer to Address information to be stored - * \param stored_payload_len is length of stored Payload - * \param *stored_payload_ptr is pointer to stored Payload + * \param payload_len is length of incoming payload + * \param *payload_ptr is pointer to stored incoming payload + * \param *token_ptr is pointer to stored token + * \param token_len is length of the stored token + * \param block_number Block number to be stored + * \param size1 Size of the whole incoming message *****************************************************************************/ static void sn_coap_protocol_linked_list_blockwise_payload_store(struct coap_s *handle, sn_nsdl_addr_s *addr_ptr, - uint16_t stored_payload_len, - uint8_t *stored_payload_ptr, + uint16_t payload_len, + uint8_t *payload_ptr, uint8_t *token_ptr, uint8_t token_len, - uint32_t block_number) + uint32_t block_number, + uint32_t size1) { - if (!addr_ptr || !stored_payload_len || !stored_payload_ptr) { + if (!addr_ptr || !payload_len || !payload_ptr) { return; } // Do not add duplicates to list, this could happen if server needs to retransmit block message again - if (sn_coap_protocol_linked_list_blockwise_payload_search_compare_block_number(handle, addr_ptr, token_ptr, @@ -1209,67 +1272,105 @@ static void sn_coap_protocol_linked_list_blockwise_payload_store(struct coap_s * return; } - coap_blockwise_payload_s *stored_blockwise_payload_ptr = NULL; + coap_blockwise_payload_s *stored_blockwise_payload_ptr = sn_coap_protocol_linked_list_blockwise_search(handle, addr_ptr, token_ptr, token_len); - /* * * * Allocating memory for stored Payload * * * */ + if (stored_blockwise_payload_ptr && stored_blockwise_payload_ptr->use_size1) { + memcpy(stored_blockwise_payload_ptr->payload_ptr + (block_number * handle->sn_coap_block_data_size), payload_ptr, payload_len); + } else if (stored_blockwise_payload_ptr) { + uint16_t new_len = stored_blockwise_payload_ptr->payload_len + payload_len; + tr_debug("sn_coap_protocol_linked_list_blockwise_payload_store - reallocate from %d to %d", stored_blockwise_payload_ptr->payload_len, new_len); - /* Allocate memory for stored Payload's structure */ - stored_blockwise_payload_ptr = handle->sn_coap_protocol_malloc(sizeof(coap_blockwise_payload_s)); + uint8_t *temp_ptr = handle->sn_coap_protocol_malloc(stored_blockwise_payload_ptr->payload_len); + if (temp_ptr == NULL) { + tr_error("sn_coap_protocol_linked_list_blockwise_payload_store - failed to allocate temp buffer!"); + sn_coap_protocol_linked_list_blockwise_payload_remove(handle, stored_blockwise_payload_ptr); + return; + } - if (stored_blockwise_payload_ptr == NULL) { - tr_error("sn_coap_protocol_linked_list_blockwise_payload_store - failed to allocate blockwise!"); - return; - } + memcpy(temp_ptr, stored_blockwise_payload_ptr->payload_ptr, stored_blockwise_payload_ptr->payload_len); - - /* Allocate memory for stored Payload's data */ - stored_blockwise_payload_ptr->payload_ptr = sn_coap_protocol_malloc_copy(handle, stored_payload_ptr, stored_payload_len); - - if (stored_blockwise_payload_ptr->payload_ptr == NULL) { - tr_error("sn_coap_protocol_linked_list_blockwise_payload_store - failed to allocate payload!"); - handle->sn_coap_protocol_free(stored_blockwise_payload_ptr); - return; - } - - /* Allocate memory for stored Payload's address */ - stored_blockwise_payload_ptr->addr_ptr = sn_coap_protocol_malloc_copy(handle, addr_ptr->addr_ptr, addr_ptr->addr_len); - - if (stored_blockwise_payload_ptr->addr_ptr == NULL) { - tr_error("sn_coap_protocol_linked_list_blockwise_payload_store - failed to allocate address pointer!"); handle->sn_coap_protocol_free(stored_blockwise_payload_ptr->payload_ptr); - handle->sn_coap_protocol_free(stored_blockwise_payload_ptr); - return; - } + stored_blockwise_payload_ptr->payload_ptr = handle->sn_coap_protocol_malloc(new_len); - /* Allocate & copy token number */ - if (token_ptr && token_len) { - stored_blockwise_payload_ptr->token_ptr = sn_coap_protocol_malloc_copy(handle, token_ptr, token_len); + if (stored_blockwise_payload_ptr->payload_ptr == NULL) { + tr_error("sn_coap_protocol_linked_list_blockwise_payload_store - failed to reallocate payload!"); + handle->sn_coap_protocol_free(temp_ptr); + sn_coap_protocol_linked_list_blockwise_payload_remove(handle, stored_blockwise_payload_ptr); + return; + } - if (!stored_blockwise_payload_ptr->token_ptr) { - tr_error("sn_coap_protocol_linked_list_blockwise_payload_store - failed to allocate token pointer!"); - handle->sn_coap_protocol_free(stored_blockwise_payload_ptr->addr_ptr); + memcpy(stored_blockwise_payload_ptr->payload_ptr, temp_ptr, stored_blockwise_payload_ptr->payload_len); + memcpy(stored_blockwise_payload_ptr->payload_ptr + stored_blockwise_payload_ptr->payload_len, payload_ptr, payload_len); + stored_blockwise_payload_ptr->payload_len = new_len; + handle->sn_coap_protocol_free(temp_ptr); + + } else { + stored_blockwise_payload_ptr = NULL; + stored_blockwise_payload_ptr = handle->sn_coap_protocol_malloc(sizeof(coap_blockwise_payload_s)); + + if (stored_blockwise_payload_ptr == NULL) { + tr_error("sn_coap_protocol_linked_list_blockwise_payload_store - failed to allocate blockwise!"); + return; + } + + // If size1 option present then we can allocate the whole payload before hand. + stored_blockwise_payload_ptr->use_size1 = size1 ? 1 : 0; + + /* Allocate memory for stored Payload's data */ + if (stored_blockwise_payload_ptr->use_size1) { + stored_blockwise_payload_ptr->payload_ptr = handle->sn_coap_protocol_malloc(size1); + if (stored_blockwise_payload_ptr->payload_ptr) { + memcpy(stored_blockwise_payload_ptr->payload_ptr, payload_ptr, payload_len); + stored_blockwise_payload_ptr->payload_len = size1; + } + } else { + stored_blockwise_payload_ptr->payload_ptr = sn_coap_protocol_malloc_copy(handle, payload_ptr, payload_len); + stored_blockwise_payload_ptr->payload_len = payload_len; + } + + if (stored_blockwise_payload_ptr->payload_ptr == NULL) { + tr_error("sn_coap_protocol_linked_list_blockwise_payload_store - failed to allocate payload!"); + handle->sn_coap_protocol_free(stored_blockwise_payload_ptr); + return; + } + + /* Allocate memory for stored Payload's address */ + stored_blockwise_payload_ptr->addr_ptr = sn_coap_protocol_malloc_copy(handle, addr_ptr->addr_ptr, addr_ptr->addr_len); + + if (stored_blockwise_payload_ptr->addr_ptr == NULL) { + tr_error("sn_coap_protocol_linked_list_blockwise_payload_store - failed to allocate address pointer!"); handle->sn_coap_protocol_free(stored_blockwise_payload_ptr->payload_ptr); handle->sn_coap_protocol_free(stored_blockwise_payload_ptr); return; } - stored_blockwise_payload_ptr->token_len = token_len; - } else { - stored_blockwise_payload_ptr->token_ptr = NULL; - stored_blockwise_payload_ptr->token_len = 0; + /* Allocate & copy token number */ + if (token_ptr && token_len) { + stored_blockwise_payload_ptr->token_ptr = sn_coap_protocol_malloc_copy(handle, token_ptr, token_len); + + if (!stored_blockwise_payload_ptr->token_ptr) { + tr_error("sn_coap_protocol_linked_list_blockwise_payload_store - failed to allocate token pointer!"); + handle->sn_coap_protocol_free(stored_blockwise_payload_ptr->addr_ptr); + handle->sn_coap_protocol_free(stored_blockwise_payload_ptr->payload_ptr); + handle->sn_coap_protocol_free(stored_blockwise_payload_ptr); + return; + } + + stored_blockwise_payload_ptr->token_len = token_len; + } else { + stored_blockwise_payload_ptr->token_ptr = NULL; + stored_blockwise_payload_ptr->token_len = 0; + } + + /* * * * Filling fields of stored Payload * * * */ + stored_blockwise_payload_ptr->port = addr_ptr->port; + + /* * * * Storing Payload to Linked list * * * */ + ns_list_add_to_end(&handle->linked_list_blockwise_received_payloads, stored_blockwise_payload_ptr); } - /* * * * Filling fields of stored Payload * * * */ - - stored_blockwise_payload_ptr->timestamp = handle->system_time; - - stored_blockwise_payload_ptr->port = addr_ptr->port; - stored_blockwise_payload_ptr->payload_len = stored_payload_len; - stored_blockwise_payload_ptr->block_number = block_number; - - /* * * * Storing Payload to Linked list * * * */ - ns_list_add_to_end(&handle->linked_list_blockwise_received_payloads, stored_blockwise_payload_ptr); + stored_blockwise_payload_ptr->timestamp = handle->system_time; } /**************************************************************************//** @@ -1307,6 +1408,38 @@ static uint8_t *sn_coap_protocol_linked_list_blockwise_payload_search(struct coa return NULL; } +/**************************************************************************//** + * \fn static uint8_t *sn_coap_protocol_linked_list_blockwise_search(sn_nsdl_addr_s *src_addr_ptr, uint16_t *payload_length) + * + * \brief Searches stored blockwise message from Linked list (Address as key) + * + * \param *addr_ptr is pointer to Address key to be searched + * \param *payload_length is pointer to returned Payload length + * + * \return Return value is pointer to found stored blockwise message in Linked + * list or NULL if message not found + *****************************************************************************/ +static coap_blockwise_payload_s *sn_coap_protocol_linked_list_blockwise_search(struct coap_s *handle, const sn_nsdl_addr_s *src_addr_ptr, const uint8_t *token_ptr, uint8_t token_len) +{ + /* Loop all stored blockwise payloads in Linked list */ + ns_list_foreach(coap_blockwise_payload_s, stored_payload_info_ptr, &handle->linked_list_blockwise_received_payloads) { + /* If payload's Source address and port is same than is searched */ + if ((0 == memcmp(src_addr_ptr->addr_ptr, stored_payload_info_ptr->addr_ptr, src_addr_ptr->addr_len)) && (stored_payload_info_ptr->port == src_addr_ptr->port)) { + /* Check token */ + if (token_ptr) { + if (!stored_payload_info_ptr->token_ptr || (token_len != stored_payload_info_ptr->token_len) || (memcmp(stored_payload_info_ptr->token_ptr, token_ptr, token_len))) { + continue; + } + } else if (stored_payload_info_ptr->token_ptr) { + continue; + } + return stored_payload_info_ptr; + } + } + + return NULL; +} + static bool sn_coap_protocol_linked_list_blockwise_payload_search_compare_block_number(struct coap_s *handle, const sn_nsdl_addr_s *src_addr_ptr, const uint8_t *token_ptr, @@ -1770,14 +1903,6 @@ static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn blocks_in_order = false; } - sn_coap_protocol_linked_list_blockwise_payload_store(handle, - src_addr_ptr, - received_coap_msg_ptr->payload_len, - received_coap_msg_ptr->payload_ptr, - received_coap_msg_ptr->token_ptr, - received_coap_msg_ptr->token_len, - block_number); - /* If not last block (more value is set) */ /* Block option length can be 1-3 bytes. First 4-20 bits are for block number. Last 4 bits are ALWAYS more bit + block size. */ if (received_coap_msg_ptr->options_list_ptr->block1 & 0x08) { @@ -1814,12 +1939,12 @@ static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn /* Check block size */ block_temp = (src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 & 0x07); uint16_t block_size = 1u << (block_temp + 4); + if (block_size > handle->sn_coap_block_data_size) { // Include maximum size that stack can handle into response tr_error("sn_coap_handle_blockwise_message - (recv block1) COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE!"); src_coap_blockwise_ack_msg_ptr->msg_code = COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE; src_coap_blockwise_ack_msg_ptr->options_list_ptr->size1 = handle->sn_coap_block_data_size; - sn_coap_protocol_linked_list_blockwise_payload_remove_oldest(handle, received_coap_msg_ptr->token_ptr, received_coap_msg_ptr->token_len); } if (block_temp > sn_coap_convert_block_size(handle->sn_coap_block_data_size)) { @@ -1851,15 +1976,28 @@ static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn #if SN_COAP_DUPLICATION_MAX_MSGS_COUNT // copy coap data buffer to duplicate list for resending purposes if (!sn_coap_protocol_update_duplicate_package_data(handle, - src_addr_ptr, - src_coap_blockwise_ack_msg_ptr, - dst_packed_data_needed_mem, - dst_ack_packet_data_ptr)) { + src_addr_ptr, + src_coap_blockwise_ack_msg_ptr, + dst_packed_data_needed_mem, + dst_ack_packet_data_ptr)) { sn_coap_parser_release_allocated_coap_msg_mem(handle, src_coap_blockwise_ack_msg_ptr); handle->sn_coap_protocol_free(dst_ack_packet_data_ptr); return NULL; } #endif + // Store only in success case + if (src_coap_blockwise_ack_msg_ptr->msg_code != COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_INCOMPLETE && + src_coap_blockwise_ack_msg_ptr->msg_code != COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE) { + sn_coap_protocol_linked_list_blockwise_payload_store(handle, + src_addr_ptr, + received_coap_msg_ptr->payload_len, + received_coap_msg_ptr->payload_ptr, + received_coap_msg_ptr->token_ptr, + received_coap_msg_ptr->token_len, + block_number, + received_coap_msg_ptr->options_list_ptr->size1); + } + handle->sn_coap_tx_callback(dst_ack_packet_data_ptr, dst_packed_data_needed_mem, src_addr_ptr, param); sn_coap_parser_release_allocated_coap_msg_mem(handle, src_coap_blockwise_ack_msg_ptr); @@ -1869,9 +2007,19 @@ static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn received_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING; } else { + /* * * This is the last block when whole Blockwise payload from received * * */ /* * * blockwise messages is gathered and returned to User * * */ + sn_coap_protocol_linked_list_blockwise_payload_store(handle, + src_addr_ptr, + received_coap_msg_ptr->payload_len, + received_coap_msg_ptr->payload_ptr, + received_coap_msg_ptr->token_ptr, + received_coap_msg_ptr->token_len, + block_number, + received_coap_msg_ptr->options_list_ptr->size1); + if (!sn_coap_handle_last_blockwise(handle, src_addr_ptr, received_coap_msg_ptr)) { return NULL; @@ -1897,7 +2045,8 @@ static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn received_coap_msg_ptr->payload_ptr, received_coap_msg_ptr->token_ptr, received_coap_msg_ptr->token_len, - received_coap_msg_ptr->options_list_ptr->block2 >> 4); + received_coap_msg_ptr->options_list_ptr->block2 >> 4, + received_coap_msg_ptr->options_list_ptr->size1); /* If not last block (more value is set) */ if (received_coap_msg_ptr->options_list_ptr->block2 & 0x08) { coap_blockwise_msg_s *previous_blockwise_msg_ptr; @@ -2136,30 +2285,26 @@ static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn static bool sn_coap_handle_last_blockwise(struct coap_s *handle, const sn_nsdl_addr_s *src_addr_ptr, sn_coap_hdr_s *received_coap_msg_ptr) { - /* Store last Blockwise payload to Linked list */ uint16_t payload_len = 0; - uint8_t *payload_ptr = sn_coap_protocol_linked_list_blockwise_payload_search(handle, src_addr_ptr, &payload_len, received_coap_msg_ptr->token_ptr, received_coap_msg_ptr->token_len); uint32_t whole_payload_len = sn_coap_protocol_linked_list_blockwise_payloads_get_len(handle, src_addr_ptr, received_coap_msg_ptr->token_ptr, received_coap_msg_ptr->token_len); - uint8_t *temp_whole_payload_ptr = NULL; + uint8_t *payload_ptr = sn_coap_protocol_linked_list_blockwise_payload_search(handle, src_addr_ptr, &payload_len, received_coap_msg_ptr->token_ptr, received_coap_msg_ptr->token_len); - temp_whole_payload_ptr = handle->sn_coap_protocol_malloc(whole_payload_len); - if (temp_whole_payload_ptr == NULL || whole_payload_len > UINT16_MAX) { - tr_error("sn_coap_handle_blockwise_message - (recv block) failed to allocate all blocks, len: %" PRIu32, whole_payload_len); - handle->sn_coap_protocol_free(temp_whole_payload_ptr); + tr_debug("sn_coap_handle_last_blockwise - whole len %d", whole_payload_len); + if (!whole_payload_len) { return false; } - // In block message case, payload_ptr freeing must be done in application level - received_coap_msg_ptr->payload_ptr = temp_whole_payload_ptr; +#if SN_COAP_REDUCE_BLOCKWISE_HEAP_FOOTPRINT + received_coap_msg_ptr->payload_ptr = payload_ptr; received_coap_msg_ptr->payload_len = whole_payload_len; - - /* Copy stored Blockwise payloads to returned whole Blockwise payload pointer */ - while (payload_ptr != NULL) { - memcpy(temp_whole_payload_ptr, payload_ptr, payload_len); - temp_whole_payload_ptr += payload_len; - sn_coap_protocol_linked_list_blockwise_payload_remove_oldest(handle, received_coap_msg_ptr->token_ptr, received_coap_msg_ptr->token_len); - payload_ptr = sn_coap_protocol_linked_list_blockwise_payload_search(handle, src_addr_ptr, &payload_len, received_coap_msg_ptr->token_ptr, received_coap_msg_ptr->token_len); +#else + received_coap_msg_ptr->payload_ptr = sn_coap_protocol_malloc_copy(handle, payload_ptr, whole_payload_len); + if (received_coap_msg_ptr->payload_ptr == NULL) { + tr_error("sn_coap_handle_last_blockwise - failed to allocate whole package!"); + return false; } + received_coap_msg_ptr->payload_len = whole_payload_len; +#endif received_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED; return true;