diff options
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.c')
-rw-r--r-- | thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.c | 854 |
1 files changed, 854 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.c new file mode 100644 index 0000000..4d58384 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap.c @@ -0,0 +1,854 @@ +/** + * Copyright (c) 2014 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include <stdbool.h> +#include <string.h> +#include "nordic_common.h" +#include "nrf.h" +#include "coap_api.h" +#include "coap.h" +#include "coap_queue.h" +#include "coap_transport.h" +#include "sdk_common.h" +#include "iot_common.h" +#include "mem_manager.h" +#include "coap_resource.h" +#include "coap_observe_api.h" +#include "coap_observe.h" + +#if IOT_COAP_CONFIG_LOG_ENABLED + +#define NRF_LOG_MODULE_NAME coap + +#define NRF_LOG_LEVEL IOT_COAP_CONFIG_LOG_LEVEL +#define NRF_LOG_INFO_COLOR IOT_COAP_CONFIG_INFO_COLOR +#define NRF_LOG_DEBUG_COLOR IOT_COAP_CONFIG_DEBUG_COLOR + +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + +#define COAP_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */ +#define COAP_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */ +#define COAP_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */ + +#define COAP_ENTRY() COAP_TRC(">> %s", __func__) +#define COAP_EXIT() COAP_TRC("<< %s", __func__) +#define COAP_EXIT_WITH_RESULT(result) COAP_TRC("<< %s, result: %d", __func__, result) + +#else // IOT_COAP_CONFIG_LOG_ENABLED + +#define COAP_TRC(...) /**< Disables traces. */ +#define COAP_DUMP(...) /**< Disables dumping of octet streams. */ +#define COAP_ERR(...) /**< Disables error logs. */ + +#define COAP_ENTRY(...) +#define COAP_EXIT(...) +#define COAP_EXIT_WITH_RESULT(...) + +#endif // IOT_COAP_CONFIG_LOG_ENABLED + +#define COAP_REQUEST_ENTITY_MAX_SIZE (BLE_IPSP_RX_BUFFER_SIZE - (IPV6_IP_HEADER_SIZE + \ + UDP_HEADER_SIZE)) /** Maximum request entity size. */ + +SDK_MUTEX_DEFINE(m_coap_mutex) /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */ + +static uint32_t m_token_seed; /**< Token seed provided by application to be used for generating token numbers. */ +static uint32_t m_message_id_counter; /**< Message ID counter, used to generate unique message IDs. */ +static coap_error_callback_t m_error_callback; /**< Function pointer to an application CoAP error handler. */ + +static coap_request_handler_t m_request_handler = NULL; /**< Request handler where to forward all incoming requests. */ + +#define COAP_MESSAGE_ACK_SET(REMOTE, LOCAL_PORT, MID) { \ + memcpy(&m_coap_empty_message.remote, (REMOTE), sizeof(coap_remote_t)); \ + m_coap_empty_message.port.port_number = (LOCAL_PORT); \ + m_coap_empty_message.header.id = (MID); \ + m_coap_empty_message.header.type = COAP_TYPE_ACK; \ +} + +#define COAP_MESSAGE_RST_SET(REMOTE, LOCAL_PORT, MID) { \ + memcpy(&m_coap_empty_message.remote, (REMOTE), sizeof(coap_remote_t)); \ + m_coap_empty_message.port.port_number = (LOCAL_PORT); \ + m_coap_empty_message.header.id = (MID); \ + m_coap_empty_message.header.type = COAP_TYPE_RST; \ +} + +static coap_message_t m_coap_empty_message = { + .header = { + .version = 1, + .type = COAP_TYPE_ACK, + .token_len = 0, + .code = COAP_CODE_EMPTY_MESSAGE, + .id = 0, + }, + .p_payload = NULL, + .payload_len = 0, + .options_count = 0, + .p_arg = NULL, + .response_callback = NULL, + .port = { + .port_number = 0 + }, + .options_len = 0, + .options_offset = 0, + .p_data = NULL, + .data_len = 0 +}; + +static inline bool is_ping(coap_message_t * p_message) +{ + return (p_message->header.code == COAP_CODE_EMPTY_MESSAGE) && + (p_message->header.type == COAP_TYPE_CON); +} + +static inline bool is_ack(coap_message_t * p_message) +{ + return (p_message->header.code == COAP_CODE_EMPTY_MESSAGE) && + (p_message->header.type == COAP_TYPE_ACK); +} + +static inline bool is_reset(coap_message_t * p_message) +{ + return (p_message->header.type == COAP_TYPE_RST); +} + +static inline bool is_con(coap_message_t * p_message) +{ + return (p_message->header.type == COAP_TYPE_CON); +} + +static inline bool is_non(coap_message_t * p_message) +{ + return (p_message->header.type == COAP_TYPE_NON); +} + +static inline bool is_request(uint8_t message_code) +{ + return (message_code >= 1) && (message_code < 32); +} + +static inline bool is_response(uint8_t message_code) +{ + return (message_code >= 64) && (message_code < 192); +} + +static inline void app_error_notify(uint32_t err_code, coap_message_t * p_message) +{ + if (m_error_callback != NULL) + { + COAP_MUTEX_UNLOCK(); + + m_error_callback(err_code, p_message); + + COAP_MUTEX_LOCK(); + } +} + +uint32_t coap_init(uint32_t token_rand_seed, coap_transport_init_t * p_transport_param) +{ + COAP_ENTRY(); + + uint32_t err_code; + + SDK_MUTEX_INIT(m_coap_mutex); + + COAP_MUTEX_LOCK(); + + internal_coap_observe_init(); + + m_error_callback = NULL; + + m_token_seed = token_rand_seed; + (void)m_token_seed; + + m_message_id_counter = 1; + + err_code = coap_transport_init(p_transport_param); + if (err_code != NRF_SUCCESS) + { + COAP_MUTEX_UNLOCK(); + return err_code; + } + + err_code = coap_queue_init(); + if (err_code != NRF_SUCCESS) + { + COAP_MUTEX_UNLOCK(); + return err_code; + } + + err_code = coap_resource_init(); + + COAP_MUTEX_UNLOCK(); + + COAP_EXIT(); + + return err_code; + +} + +uint32_t coap_error_handler_register(coap_error_callback_t error_callback) +{ + // TODO: error handling, null pointer, module initilized etc. + COAP_MUTEX_LOCK(); + + m_error_callback = error_callback; + + COAP_MUTEX_UNLOCK(); + + return NRF_SUCCESS; +} + +uint32_t internal_coap_message_send(uint32_t * p_handle, coap_message_t * p_message) +{ + if (p_message == NULL) + { + return (NRF_ERROR_NULL | IOT_COAP_ERR_BASE); + } + + // Compiled away if COAP_ENABLE_OBSERVE_CLIENT is not set to 1. + coap_observe_client_send_handle(p_message); + + COAP_ENTRY(); + + // Fetch the expected length of the packet serialized by passing length of 0. + uint16_t expected_length = 0; + uint32_t err_code = coap_message_encode(p_message, NULL, &expected_length); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + // Allocate a buffer to serialize the message into. + uint8_t * p_buffer; + uint32_t request_length = expected_length; + err_code = nrf_mem_reserve(&p_buffer, &request_length); + if (err_code != NRF_SUCCESS) + { + COAP_TRC("p_buffer alloc error = 0x%08lX!", err_code); + return err_code; + } + memset(p_buffer, 0, request_length); + COAP_TRC("Alloc mem, p_buffer = %p", (uint8_t *)p_buffer); + + // Serialize the message. + uint16_t buffer_length = (uint16_t)request_length; + err_code = coap_message_encode(p_message, p_buffer, &buffer_length); + if (err_code != NRF_SUCCESS) + { + COAP_TRC("Encode error!"); + COAP_TRC("Free mem, p_buffer = %p", p_buffer); + UNUSED_VARIABLE(nrf_free(p_buffer)); + + return err_code; + } + + err_code = coap_transport_write(&p_message->port, &p_message->remote, p_buffer, buffer_length); + + if (err_code == NRF_SUCCESS) + { + if (is_con(p_message) || (is_non(p_message) && + is_request(p_message->header.code) && + (p_message->response_callback != NULL))) + { + coap_queue_item_t item; + item.p_arg = p_message->p_arg; + item.mid = p_message->header.id; + item.callback = p_message->response_callback; + item.p_buffer = p_buffer; + item.buffer_len = buffer_length; + item.timeout_val = COAP_ACK_TIMEOUT * COAP_ACK_RANDOM_FACTOR; + + if (p_message->header.type == COAP_TYPE_CON) + { + item.timeout = item.timeout_val; + item.retrans_count = 0; + } + else + { + item.timeout = COAP_MAX_TRANSMISSION_SPAN; + item.retrans_count = COAP_MAX_RETRANSMIT_COUNT; + } + + item.port = p_message->port; + item.token_len = p_message->header.token_len; + + memcpy(&item.remote, &p_message->remote, sizeof(coap_remote_t)); + memcpy(item.token, p_message->token, p_message->header.token_len); + + err_code = coap_queue_add(&item); + if (err_code != NRF_SUCCESS) + { + COAP_TRC("Message queue error = 0x%08lX!", err_code); + + COAP_TRC("Free mem, p_buffer = %p", p_buffer); + UNUSED_VARIABLE(nrf_free(p_buffer)); + + return err_code; + } + + *p_handle = item.handle; + } + else + { + *p_handle = COAP_MESSAGE_QUEUE_SIZE; + + COAP_TRC("Free mem, p_buffer = %p", p_buffer); + UNUSED_VARIABLE(nrf_free(p_buffer)); + } + } + else + { + COAP_TRC("Free mem, p_buffer = %p", p_buffer); + UNUSED_VARIABLE(nrf_free(p_buffer)); + } + + COAP_EXIT(); + + return err_code; +} + + +static uint32_t create_response(coap_message_t ** pp_response, coap_message_t * p_request, uint16_t data_size) +{ + uint32_t err_code; + + // Allocate space for a new message. + uint32_t size = sizeof(coap_message_t); + err_code = nrf_mem_reserve((uint8_t **)pp_response, &size); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + coap_message_t * p_response = (*pp_response); + + memset(p_response, 0, sizeof(coap_message_t)); + COAP_TRC("Alloc mem, p_response = %p", (uint8_t *)p_response); + + if (data_size > 0) + { + // Allocate a scratch buffer for payload and options. + size = data_size; + err_code = nrf_mem_reserve(&(p_response->p_data), &size); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + memset(p_response->p_data, 0, size); + p_response->data_len = size; + COAP_TRC("Alloc mem, p_response->p_data = %p", p_response->p_data); + } + + coap_message_conf_t config; + memset (&config, 0, sizeof(coap_message_conf_t)); + + config.token_len = p_request->header.token_len; + config.id = p_request->header.id; + config.code = COAP_CODE_404_NOT_FOUND; + config.port.port_number = p_request->port.port_number; + + memcpy(config.token, p_request->token, p_request->header.token_len); + + if ((coap_msg_type_t)p_request->header.type == COAP_TYPE_CON) + { + config.type = COAP_TYPE_ACK; + } + else + { + config.type = (coap_msg_type_t)p_request->header.type; + } + + err_code = coap_message_create(p_response, &config); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + (void)coap_message_remote_addr_set(p_response, &p_request->remote); + + return NRF_SUCCESS; +} + + +/**@brief Common function for sending response error message + * + * @param[in] p_message Pointer to the original request message. + * @param[in] code CoAP message code to send in the reponse. + * + * @retval NRF_SUCCESS If the response was sent out successfully. + */ +static uint32_t send_error_response(coap_message_t * p_message, uint8_t code) +{ + coap_message_t * p_error_response = NULL; + + uint32_t err_code = create_response(&p_error_response, p_message, COAP_MESSAGE_DATA_MAX_SIZE); + if (err_code != NRF_SUCCESS) + { + // If message could not be created, notify the application. + app_error_notify(err_code, p_message); + return err_code; + } + + // Set the response code. + p_error_response->header.code = code; + + if (p_error_response != NULL) + { + uint32_t handle; + err_code = internal_coap_message_send(&handle, p_error_response); + + COAP_TRC("Free mem, p_response->p_data = %p", p_error_response->p_data); + UNUSED_VARIABLE(nrf_free(p_error_response->p_data)); + + COAP_TRC("Free mem, p_response = %p", (uint8_t *)p_error_response); + UNUSED_VARIABLE(nrf_free((uint8_t *)p_error_response)); + } + + return err_code; +} + +uint32_t coap_transport_read(const coap_port_t * p_port, + const coap_remote_t * p_remote, + const coap_remote_t * p_local, + uint32_t result, + const uint8_t * p_data, + uint16_t datalen) +{ + COAP_ENTRY(); + + // Discard all packets if not success or truncated. + if (!(result == NRF_SUCCESS || result == UDP_TRUNCATED_PACKET)) + { + return NRF_SUCCESS; + } + + uint32_t err_code; + coap_message_t * p_message; + + // Allocate space for a new message. + uint32_t size = sizeof(coap_message_t); + err_code = nrf_mem_reserve((uint8_t **)&p_message, &size); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + memset(p_message, 0, sizeof(coap_message_t)); + COAP_TRC("Alloc mem, p_message = %p", (uint8_t *)p_message); + + err_code = coap_message_decode(p_message, p_data, datalen); + if (err_code != NRF_SUCCESS) + { + app_error_notify(err_code, p_message); + + UNUSED_VARIABLE(nrf_free((uint8_t *)p_message)); + return err_code; + } + + // Copy the remote address information. + memcpy(&p_message->remote, p_remote, sizeof(coap_remote_t)); + + // Copy the destination address information. + if (p_local) + { + memcpy(&p_message->local, p_local, sizeof(coap_remote_t)); + } + + // Copy the local port information. + memcpy(&p_message->port, p_port, sizeof(coap_port_t)); + + if (result == UDP_TRUNCATED_PACKET) + { + app_error_notify(result, p_message); + } + else if (is_ping(p_message)) + { + COAP_MESSAGE_RST_SET(&p_message->remote, p_message->port.port_number, p_message->header.id); + + uint32_t handle; + err_code = internal_coap_message_send(&handle, &m_coap_empty_message); + } + else if (is_ack(p_message) || + is_reset(p_message)) + { + // Populate the token with the one used sending, before passing it to the application. + coap_queue_item_t * p_item = NULL; + err_code = coap_queue_item_by_mid_get(&p_item, p_message->header.id); + + if (err_code == NRF_SUCCESS) + { + if (p_item->callback != NULL) + { + // As the token is missing from peer, it will be added before giving it to the application. + memcpy(p_message->token, p_item->token, p_item->token_len); + p_message->header.token_len = p_item->token_len; + + // Compiled away if COAP_ENABLE_OBSERVE_CLIENT is not set to 1. + coap_observe_client_response_handle(p_message, p_item); + + COAP_TRC(">> application callback"); + + COAP_MUTEX_UNLOCK(); + + if (is_ack(p_message)) + { + p_item->callback(NRF_SUCCESS, p_item->p_arg, p_message); + } + else + { + p_item->callback(COAP_TRANSMISSION_RESET_BY_PEER, p_item->p_arg, p_message); + } + + COAP_MUTEX_LOCK(); + + COAP_TRC("<< application callback"); + } + + COAP_TRC("Free mem, p_item->p_buffer = %p", p_item->p_buffer); + UNUSED_VARIABLE(nrf_free(p_item->p_buffer)); + + // Remove the queue element, as a match occured. + err_code = coap_queue_remove(p_item); + } + } + else if (is_response(p_message->header.code)) + { + COAP_TRC("CoAP message type: RESPONSE"); + + coap_queue_item_t * p_item; + err_code = coap_queue_item_by_token_get(&p_item, p_message->token, p_message->header.token_len); + if (err_code != NRF_SUCCESS) + { + // Compiled away if COAP_ENABLE_OBSERVE_CLIENT is not set to 1. + coap_observe_client_response_handle(p_message, NULL); + + UNUSED_VARIABLE(nrf_free((uint8_t *)p_message)); + + COAP_MUTEX_UNLOCK(); + + return err_code; + } + + if (p_item->callback != NULL) + { + // Compiled away if COAP_ENABLE_OBSERVE_CLIENT is not set to 1. + coap_observe_client_response_handle(p_message, p_item); + + COAP_TRC(">> application callback"); + + COAP_MUTEX_UNLOCK(); + + p_item->callback(NRF_SUCCESS, p_item->p_arg, p_message); + + COAP_MUTEX_LOCK(); + + COAP_TRC("<< application callback"); + } + + COAP_TRC("Free mem, p_item->p_buffer = %p", p_item->p_buffer); + UNUSED_VARIABLE(nrf_free(p_item->p_buffer)); + + err_code = coap_queue_remove(p_item); + + } + else if (is_request(p_message->header.code)) + { + COAP_TRC("CoAP message type: REQUEST"); + + if (m_request_handler != NULL) + { + uint32_t return_code = m_request_handler(p_message); + + // If success, then all processing and any responses has been sent + // by the application callback. + + // If not success, then send an appropriate error message back to the + // origin with the return_code from the callback. + if (return_code != NRF_SUCCESS) + { + if (return_code == NRF_ERROR_NOT_FOUND) + { + // Send response with provided CoAP code. + (void)send_error_response(p_message, COAP_CODE_404_NOT_FOUND); + } + else if (return_code == NRF_ERROR_NULL) + { + (void)send_error_response(p_message, COAP_CODE_405_METHOD_NOT_ALLOWED); + } + else + { + (void)send_error_response(p_message, COAP_CODE_400_BAD_REQUEST); + } + } + } + else + { + uint8_t * uri_pointers[COAP_RESOURCE_MAX_DEPTH] = {0, }; + + uint8_t uri_path_count = 0; + uint16_t index; + + for (index = 0; index < p_message->options_count; index++) + { + if (p_message->options[index].number == COAP_OPT_URI_PATH) + { + uri_pointers[uri_path_count++] = p_message->options[index].p_data; + } + } + + coap_resource_t * found_resource; + err_code = coap_resource_get(&found_resource, uri_pointers, uri_path_count); + + if (found_resource != NULL) + { + if (found_resource->callback != NULL) + { + if (((found_resource->permission) & (1 << ((p_message->header.code) - 1))) > 0) // Has permission for the requested CoAP method. + { + COAP_MUTEX_UNLOCK(); + + found_resource->callback(found_resource, p_message); + + COAP_MUTEX_LOCK(); + } + else + { + // Reply with Method Not Allowed. + err_code = send_error_response(p_message, COAP_CODE_405_METHOD_NOT_ALLOWED); + } + } + else + { + // Reply with Method Not Allowed. + err_code = send_error_response(p_message, COAP_CODE_405_METHOD_NOT_ALLOWED); + } + } + else + { + // Reply with NOT FOUND. + err_code = send_error_response(p_message, COAP_CODE_404_NOT_FOUND); + } + } + } + + COAP_TRC("Free mem, p_message = %p", (uint8_t *)p_message); + UNUSED_VARIABLE(nrf_free((uint8_t *)p_message)); + + COAP_EXIT(); + return err_code; +} + +uint32_t coap_message_send(uint32_t * p_handle, coap_message_t * p_message) +{ + COAP_MUTEX_LOCK(); + + uint32_t err_code = internal_coap_message_send(p_handle, p_message); + + COAP_MUTEX_UNLOCK(); + + return err_code; +} + +uint32_t coap_message_abort(uint32_t handle) +{ + + return NRF_ERROR_NOT_SUPPORTED; +} + +uint32_t coap_message_new(coap_message_t ** p_request, coap_message_conf_t * p_config) +{ + COAP_ENTRY(); + + uint32_t err_code; + + // If port is not configured, return error and skip initialization of the message. + if (p_config->port.port_number == 0) + { + return (NRF_ERROR_INVALID_PARAM | IOT_COAP_ERR_BASE); + } + + COAP_MUTEX_LOCK(); + + // Allocate space for a new message. + uint32_t size = sizeof(coap_message_t); + err_code = nrf_mem_reserve((uint8_t **)p_request, &size); + if (err_code != NRF_SUCCESS) + { + COAP_MUTEX_UNLOCK(); + return err_code; + } + + memset(*p_request, 0, sizeof(coap_message_t)); + COAP_TRC("Alloc mem, *p_request = %p", (uint8_t *)(*p_request)); + + // Allocate a scratch buffer for payload and options. + size = COAP_MESSAGE_DATA_MAX_SIZE; + err_code = nrf_mem_reserve(&((*p_request)->p_data), &size); + if (err_code != NRF_SUCCESS) + { + COAP_TRC("Allocation of message data buffer failed!"); + + COAP_TRC("Free mem, *p_request = %p", (uint8_t *)(*p_request)); + UNUSED_VARIABLE(nrf_free((uint8_t *)(*p_request))); + + COAP_MUTEX_UNLOCK(); + return err_code; + } + + memset((*p_request)->p_data, 0, size); + (*p_request)->data_len = size; + + COAP_TRC("Alloc mem, (*p_request)->p_data = %p", (uint8_t *)((*p_request)->p_data)); + + if (p_config->id == 0) // Message id is not set, generate one. + { + p_config->id = m_message_id_counter++; + } + + err_code = coap_message_create(*p_request, p_config); + + COAP_MUTEX_UNLOCK(); + + COAP_EXIT_WITH_RESULT(err_code); + + return err_code; +} + +uint32_t coap_message_delete(coap_message_t * p_message) +{ + COAP_ENTRY(); + + COAP_MUTEX_LOCK(); + + //If this is a request free the coap_message_t and the data buffer. + + COAP_TRC("Free mem, p_message->p_data = %p", p_message->p_data); + UNUSED_VARIABLE(nrf_free(p_message->p_data)); + + COAP_TRC("Free mem, p_message = %p", (uint8_t *)p_message); + UNUSED_VARIABLE(nrf_free((uint8_t *)p_message)); + + + COAP_MUTEX_UNLOCK(); + + COAP_EXIT(); + + return NRF_SUCCESS; +} + + +uint32_t coap_time_tick(void) +{ + COAP_MUTEX_LOCK(); + + coap_transport_process(); + + // Loop through the message queue to see if any packets needs retransmission, or has timed out. + coap_queue_item_t * p_item = NULL; + while (coap_queue_item_next_get(&p_item, p_item) == NRF_SUCCESS) + { + if (p_item->timeout == 0) + { + // If there is still retransmission attempts left. + if (p_item->retrans_count < COAP_MAX_RETRANSMIT_COUNT) + { + p_item->timeout = p_item->timeout_val * 2; + p_item->timeout_val = p_item->timeout; + p_item->retrans_count++; + + // Retransmit the message. + uint32_t err_code = coap_transport_write(&p_item->port, &p_item->remote, p_item->p_buffer, p_item->buffer_len); + if (err_code != NRF_SUCCESS) + { + app_error_notify(err_code, NULL); + } + } + + // No more retransmission attempts left, or max transmit span reached. + if ((p_item->timeout > COAP_MAX_TRANSMISSION_SPAN) || + (p_item->retrans_count >= COAP_MAX_RETRANSMIT_COUNT)) + { + + COAP_MUTEX_UNLOCK(); + + p_item->callback(COAP_TRANSMISSION_TIMEOUT, p_item->p_arg, NULL); + + COAP_MUTEX_LOCK(); + + COAP_TRC("Free mem, p_item->p_buffer = %p", p_item->p_buffer); + UNUSED_VARIABLE(nrf_free(p_item->p_buffer)); + + (void)coap_queue_remove(p_item); + } + } + else + { + p_item->timeout--; + } + } + + COAP_MUTEX_UNLOCK(); + + return NRF_SUCCESS; +} + +uint32_t coap_request_handler_register(coap_request_handler_t p_request_handler) +{ + COAP_MUTEX_LOCK(); + + m_request_handler = p_request_handler; + + COAP_MUTEX_UNLOCK(); + + return NRF_SUCCESS; +} + +__WEAK void coap_transport_input(void) +{ + // By default not implemented. Transport specific. +} + +void coap_input(void) +{ + COAP_MUTEX_LOCK(); + + coap_transport_input(); + + COAP_MUTEX_UNLOCK(); +} |