Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510
coap_message_handler.c
00001 /* 00002 * Copyright (c) 2015-2016 ARM Limited. All Rights Reserved. 00003 */ 00004 00005 #include <string.h> 00006 #include "nsdynmemLIB.h" 00007 #include "coap_service_api_internal.h" 00008 #include "coap_message_handler.h" 00009 #include "sn_coap_protocol.h" 00010 #include "socket_api.h" 00011 #include "ns_types.h" 00012 #include "ns_list.h" 00013 #include "ns_trace.h" 00014 #include "randLIB.h" 00015 00016 #define TRACE_GROUP "CoSA" 00017 00018 static void *own_alloc(uint16_t size) 00019 { 00020 if (size) { 00021 return ns_dyn_mem_temporary_alloc(size); 00022 } else { 00023 return 0; 00024 } 00025 } 00026 00027 static void own_free(void *ptr) 00028 { 00029 if (ptr) { 00030 ns_dyn_mem_free(ptr); 00031 } 00032 } 00033 00034 static NS_LIST_DEFINE(request_list, coap_transaction_t, link); 00035 00036 static coap_transaction_t *transaction_find_client_by_token(uint8_t token[4]) 00037 { 00038 coap_transaction_t *this = NULL; 00039 ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) { 00040 if (memcmp(cur_ptr->token,token,4) == 0 && cur_ptr->client_request) { 00041 this = cur_ptr; 00042 break; 00043 } 00044 } 00045 return this; 00046 } 00047 00048 static coap_transaction_t *transaction_find_server(uint16_t msg_id) 00049 { 00050 coap_transaction_t *this = NULL; 00051 ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) { 00052 if (cur_ptr->msg_id == msg_id && !cur_ptr->client_request) { 00053 this = cur_ptr; 00054 break; 00055 } 00056 } 00057 return this; 00058 } 00059 00060 static coap_transaction_t *transaction_find_by_address(uint8_t *address_ptr, uint16_t port) 00061 { 00062 coap_transaction_t *this = NULL; 00063 ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) { 00064 if (cur_ptr->remote_port == port && memcmp(cur_ptr->remote_address, address_ptr, 16) == 0) { 00065 this = cur_ptr; 00066 break; 00067 } 00068 } 00069 return this; 00070 } 00071 00072 static coap_transaction_t *transaction_create(void) 00073 { 00074 coap_transaction_t *this = ns_dyn_mem_alloc(sizeof(coap_transaction_t)); 00075 if (this) { 00076 memset(this, 0, sizeof(coap_transaction_t)); 00077 this->client_request = true;// default to client initiated method 00078 this->create_time = coap_service_get_internal_timer_ticks(); 00079 ns_list_add_to_start(&request_list, this); 00080 } 00081 00082 return this; 00083 } 00084 00085 static void transaction_free(coap_transaction_t *this) 00086 { 00087 if (!this) { 00088 return; 00089 } 00090 00091 if (this->data_ptr) { 00092 ns_dyn_mem_free(this->data_ptr); 00093 } 00094 ns_dyn_mem_free(this); 00095 } 00096 00097 void transaction_delete(coap_transaction_t *this) 00098 { 00099 if (this) { 00100 ns_list_remove(&request_list, this); 00101 transaction_free(this); 00102 } 00103 00104 return; 00105 } 00106 00107 void transactions_delete_all(uint8_t *address_ptr, uint16_t port) 00108 { 00109 coap_transaction_t *transaction = transaction_find_by_address(address_ptr, port); 00110 00111 while (transaction) { 00112 ns_list_remove(&request_list, transaction); 00113 if (transaction->resp_cb) { 00114 transaction->resp_cb(transaction->service_id, address_ptr, port, NULL); 00115 } 00116 sn_coap_protocol_delete_retransmission(coap_service_handle->coap, transaction->msg_id); 00117 transaction_free(transaction); 00118 transaction = transaction_find_by_address(address_ptr, port); 00119 } 00120 } 00121 00122 static int8_t coap_rx_function(sn_coap_hdr_s *resp_ptr, sn_nsdl_addr_s *address_ptr, void *param) 00123 { 00124 coap_transaction_t *this = NULL; 00125 (void)address_ptr; 00126 (void)param; 00127 tr_warn("transaction was not handled %d", resp_ptr->msg_id); 00128 if (!resp_ptr) { 00129 return -1; 00130 } 00131 if( resp_ptr->token_ptr ){ 00132 this = transaction_find_client_by_token(resp_ptr->token_ptr); 00133 } 00134 if (!this) { 00135 return 0; 00136 } 00137 00138 ns_list_remove(&request_list, this); 00139 if (this->resp_cb) { 00140 this->resp_cb(this->service_id, address_ptr->addr_ptr, address_ptr->port, NULL); 00141 } 00142 transaction_free(this); 00143 return 0; 00144 } 00145 00146 coap_msg_handler_t *coap_message_handler_init(void *(*used_malloc_func_ptr)(uint16_t), void (*used_free_func_ptr)(void *), 00147 uint8_t (*used_tx_callback_ptr)(uint8_t *, uint16_t, sn_nsdl_addr_s *, void *)){ 00148 00149 if ((used_malloc_func_ptr == NULL) || (used_free_func_ptr == NULL) || (used_tx_callback_ptr == NULL)) { 00150 return NULL; 00151 } 00152 00153 coap_msg_handler_t *handle; 00154 handle = used_malloc_func_ptr(sizeof(coap_msg_handler_t)); 00155 if (handle == NULL) { 00156 return NULL; 00157 } 00158 00159 memset(handle, 0, sizeof(coap_msg_handler_t)); 00160 00161 handle->sn_coap_tx_callback = used_tx_callback_ptr; 00162 00163 handle->sn_coap_service_free = used_free_func_ptr; 00164 handle->sn_coap_service_malloc = used_malloc_func_ptr; 00165 00166 handle->coap = sn_coap_protocol_init(used_malloc_func_ptr, used_free_func_ptr, used_tx_callback_ptr, &coap_rx_function); 00167 if( !handle->coap ){ 00168 used_free_func_ptr(handle); 00169 return NULL; 00170 } 00171 return handle; 00172 } 00173 00174 int8_t coap_message_handler_destroy(coap_msg_handler_t *handle){ 00175 if( !handle ){ 00176 return -1; 00177 } 00178 00179 if( handle->coap ){ 00180 sn_coap_protocol_destroy(handle->coap); 00181 } 00182 00183 //Destroy transactions 00184 ns_list_foreach_safe(coap_transaction_t, cur_ptr, &request_list) { 00185 ns_list_remove(&request_list, cur_ptr); 00186 ns_dyn_mem_free(cur_ptr); 00187 cur_ptr = NULL; 00188 } 00189 00190 handle->sn_coap_service_free(handle); 00191 return 0; 00192 } 00193 00194 coap_transaction_t *coap_message_handler_transaction_valid(coap_transaction_t *tr_ptr) 00195 { 00196 ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) { 00197 if (cur_ptr == tr_ptr) { 00198 return tr_ptr; 00199 } 00200 } 00201 return NULL; 00202 } 00203 00204 coap_transaction_t *coap_message_handler_find_transaction(uint8_t *address_ptr, uint16_t port) 00205 { 00206 if( !address_ptr ) 00207 return NULL; 00208 return transaction_find_by_address( address_ptr, port ); 00209 } 00210 00211 int16_t coap_message_handler_coap_msg_process(coap_msg_handler_t *handle, int8_t socket_id, const uint8_t source_addr_ptr[static 16], uint16_t port, const uint8_t dst_addr_ptr[static 16], 00212 uint8_t *data_ptr, uint16_t data_len, int16_t (cb)(int8_t, sn_coap_hdr_s *, coap_transaction_t *)) 00213 { 00214 if (!cb || !handle) { 00215 return -1; 00216 } 00217 sn_nsdl_addr_s src_addr; 00218 sn_coap_hdr_s *coap_message; 00219 src_addr.addr_ptr = (uint8_t *)source_addr_ptr; 00220 src_addr.addr_len = 16; 00221 src_addr.type = SN_NSDL_ADDRESS_TYPE_IPV6; 00222 src_addr.port = port; 00223 00224 coap_message = sn_coap_protocol_parse(handle->coap, &src_addr, data_len, data_ptr, NULL); 00225 if (coap_message == NULL) { 00226 tr_err("CoAP Parsing failed"); 00227 return -1; 00228 } 00229 tr_debug("CoAP status:%d, type:%d, code:%d, id:%d", coap_message->coap_status, coap_message->msg_type, coap_message->msg_code, coap_message->msg_id); 00230 /* Check, if coap itself sends response, or block receiving is ongoing... */ 00231 if (coap_message->coap_status != COAP_STATUS_OK && coap_message->coap_status != COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED) { 00232 tr_debug("CoAP library responds"); 00233 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message); 00234 return -1; 00235 } 00236 /* Request received */ 00237 if (coap_message->msg_code > 0 && coap_message->msg_code < 32) { 00238 coap_transaction_t *transaction_ptr = transaction_create(); 00239 if (transaction_ptr) { 00240 transaction_ptr->service_id = coap_service_id_find_by_socket(socket_id); 00241 transaction_ptr->msg_id = coap_message->msg_id; 00242 transaction_ptr->client_request = false;// this is server transaction 00243 memcpy(transaction_ptr->local_address, *(dst_addr_ptr) == 0xFF ? ns_in6addr_any : dst_addr_ptr, 16); 00244 memcpy(transaction_ptr->remote_address, source_addr_ptr, 16); 00245 transaction_ptr->remote_port = port; 00246 00247 int ret = cb(socket_id, coap_message, transaction_ptr); 00248 if (ret != 0) { 00249 tr_debug("Service %d, no response expected", transaction_ptr->service_id); 00250 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message); 00251 transaction_delete(transaction_ptr); 00252 return -1; 00253 } 00254 } else { 00255 //TODO: handle error case 00256 } 00257 /* Response received */ 00258 } else { 00259 coap_transaction_t *this = NULL; 00260 if (coap_message->token_ptr) { 00261 this = transaction_find_client_by_token(coap_message->token_ptr); 00262 } 00263 if (!this) { 00264 tr_error("client transaction not found"); 00265 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message); 00266 return -1; 00267 } 00268 tr_debug("Service %d, response received", this->service_id); 00269 ns_list_remove(&request_list, this); 00270 if (this->resp_cb) { 00271 this->resp_cb(this->service_id, (uint8_t *)source_addr_ptr, port, coap_message); 00272 } 00273 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message); 00274 transaction_free(this); 00275 } 00276 00277 return 0; 00278 00279 } 00280 00281 uint16_t coap_message_handler_request_send(coap_msg_handler_t *handle, int8_t service_id, uint8_t options, const uint8_t destination_addr[static 16], 00282 uint16_t destination_port, sn_coap_msg_type_e msg_type, sn_coap_msg_code_e msg_code, const char *uri, 00283 sn_coap_content_format_e cont_type, const uint8_t *payload_ptr, uint16_t payload_len, coap_message_handler_response_recv *request_response_cb) 00284 { 00285 coap_transaction_t *transaction_ptr; 00286 sn_coap_hdr_s request; 00287 sn_nsdl_addr_s dst_addr; 00288 uint8_t token[4]; 00289 uint16_t data_len; 00290 uint8_t *data_ptr; 00291 00292 tr_debug("Service %d, send CoAP request payload_len %d", service_id, payload_len); 00293 transaction_ptr = transaction_create(); 00294 00295 if (!uri || !transaction_ptr) { 00296 return 0; 00297 } 00298 00299 transaction_ptr->service_id = service_id; 00300 transaction_ptr->client_request = true; 00301 transaction_ptr->resp_cb = request_response_cb; 00302 transaction_ptr->options = options; 00303 memcpy(transaction_ptr->remote_address, destination_addr, 16); 00304 transaction_ptr->remote_port = destination_port; 00305 memset(&request, 0, sizeof(request)); 00306 dst_addr.addr_ptr = (uint8_t *) destination_addr; // Cast away const and trust that nsdl doesn't modify... 00307 dst_addr.addr_len = 16; 00308 dst_addr.type = SN_NSDL_ADDRESS_TYPE_IPV6; 00309 dst_addr.port = destination_port; 00310 00311 request.msg_type = msg_type; 00312 request.msg_code = msg_code; 00313 request.uri_path_ptr = (uint8_t *)uri; 00314 request.uri_path_len = strlen(uri); 00315 request.content_format = cont_type; 00316 00317 do{ 00318 randLIB_get_n_bytes_random(token,4); 00319 }while(transaction_find_client_by_token(token)); 00320 memcpy(transaction_ptr->token,token,4); 00321 request.token_ptr = transaction_ptr->token; 00322 request.token_len = 4; 00323 00324 request.payload_len = payload_len; 00325 request.payload_ptr = (uint8_t *) payload_ptr; // Cast away const and trust that nsdl doesn't modify... 00326 data_len = sn_coap_builder_calc_needed_packet_data_size(&request); 00327 data_ptr = own_alloc(data_len); 00328 if(data_len > 0 && !data_ptr){ 00329 transaction_delete(transaction_ptr); 00330 return 0; 00331 } 00332 sn_coap_protocol_build(handle->coap, &dst_addr, data_ptr, &request, transaction_ptr); 00333 transaction_ptr->msg_id = request.msg_id; 00334 handle->sn_coap_tx_callback(data_ptr, data_len, &dst_addr, transaction_ptr); 00335 00336 // Free allocated data 00337 own_free(data_ptr); 00338 if(request_response_cb == NULL){ 00339 //No response expected 00340 return 0; 00341 } 00342 return transaction_ptr->msg_id; 00343 } 00344 00345 int8_t coap_message_handler_response_send(coap_msg_handler_t *handle, int8_t service_id, uint8_t options, sn_coap_hdr_s *request_ptr, sn_coap_msg_code_e message_code, sn_coap_content_format_e content_type, const uint8_t *payload_ptr, uint16_t payload_len) 00346 { 00347 coap_transaction_t *transaction_ptr; 00348 sn_coap_hdr_s *response; 00349 sn_nsdl_addr_s dst_addr; 00350 uint16_t data_len; 00351 uint8_t *data_ptr; 00352 (void) options; 00353 (void)service_id; 00354 00355 tr_debug("Service %d, send CoAP response", service_id); 00356 if (!request_ptr || !handle) { 00357 tr_error("invalid params"); 00358 return -1; 00359 } 00360 00361 transaction_ptr = transaction_find_server(request_ptr->msg_id); 00362 00363 if (!transaction_ptr) { 00364 tr_error("response transaction not found"); 00365 return -2; 00366 } 00367 dst_addr.addr_ptr = transaction_ptr->remote_address; 00368 dst_addr.addr_len = 16; 00369 dst_addr.type = SN_NSDL_ADDRESS_TYPE_IPV6; 00370 dst_addr.port = transaction_ptr->remote_port; 00371 00372 response = sn_coap_build_response(handle->coap, request_ptr, message_code); 00373 if( !response ){ 00374 return -1; 00375 } 00376 response->payload_len = payload_len; 00377 response->payload_ptr = (uint8_t *) payload_ptr; // Cast away const and trust that nsdl doesn't modify... 00378 response->content_format = content_type; 00379 00380 data_len = sn_coap_builder_calc_needed_packet_data_size(response); 00381 data_ptr = own_alloc(data_len); 00382 if (data_len > 0 && !data_ptr) { 00383 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, response); 00384 return -1; 00385 } 00386 sn_coap_protocol_build(handle->coap, &dst_addr, data_ptr, response, transaction_ptr); 00387 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, response); 00388 handle->sn_coap_tx_callback(data_ptr, data_len, &dst_addr, transaction_ptr); 00389 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, request_ptr); 00390 own_free(data_ptr); 00391 return 0; 00392 } 00393 00394 int8_t coap_message_handler_exec(coap_msg_handler_t *handle, uint32_t current_time){ 00395 00396 if( !handle ){ 00397 return -1; 00398 } 00399 00400 // Remove outdated transactions from queue 00401 ns_list_foreach_safe(coap_transaction_t, transaction, &request_list) { 00402 if ((transaction->create_time + TRANSACTION_LIFETIME) < current_time) { 00403 transaction_delete(transaction); 00404 } 00405 } 00406 00407 return sn_coap_protocol_exec(handle->coap, current_time); 00408 }
Generated on Tue Jul 12 2022 11:02:34 by
