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: cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more
coap_message_handler.c
00001 /* 00002 * Copyright (c) 2015-2017, Arm Limited and affiliates. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #include <string.h> 00019 #include "nsdynmemLIB.h" 00020 #include "coap_service_api_internal.h" 00021 #include "coap_message_handler.h" 00022 #include "mbed-coap/sn_coap_protocol.h" 00023 #include "socket_api.h" 00024 #include "ns_types.h" 00025 #include "ns_list.h" 00026 #include "ns_trace.h" 00027 #include "randLIB.h" 00028 00029 #define TRACE_GROUP "CoSA" 00030 00031 static void *own_alloc(uint16_t size) 00032 { 00033 if (size) { 00034 return ns_dyn_mem_temporary_alloc(size); 00035 } else { 00036 return 0; 00037 } 00038 } 00039 00040 static void own_free(void *ptr) 00041 { 00042 if (ptr) { 00043 ns_dyn_mem_free(ptr); 00044 } 00045 } 00046 00047 static NS_LIST_DEFINE(request_list, coap_transaction_t, link); 00048 00049 static coap_transaction_t *transaction_find_client_by_token(uint8_t token[4]) 00050 { 00051 coap_transaction_t *this = NULL; 00052 ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) { 00053 if (memcmp(cur_ptr->token,token,4) == 0 && cur_ptr->client_request) { 00054 this = cur_ptr; 00055 break; 00056 } 00057 } 00058 return this; 00059 } 00060 00061 static coap_transaction_t *transaction_find_server(uint16_t msg_id) 00062 { 00063 coap_transaction_t *this = NULL; 00064 ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) { 00065 if (cur_ptr->msg_id == msg_id && !cur_ptr->client_request) { 00066 this = cur_ptr; 00067 break; 00068 } 00069 } 00070 return this; 00071 } 00072 00073 static coap_transaction_t *transaction_find_client(uint16_t msg_id) 00074 { 00075 coap_transaction_t *this = NULL; 00076 ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) { 00077 if (cur_ptr->msg_id == msg_id && cur_ptr->client_request) { 00078 this = cur_ptr; 00079 break; 00080 } 00081 } 00082 return this; 00083 } 00084 00085 static coap_transaction_t *transaction_find_by_address(uint8_t *address_ptr, uint16_t port) 00086 { 00087 coap_transaction_t *this = NULL; 00088 ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) { 00089 if (cur_ptr->remote_port == port && memcmp(cur_ptr->remote_address, address_ptr, 16) == 0) { 00090 this = cur_ptr; 00091 break; 00092 } 00093 } 00094 return this; 00095 } 00096 00097 static coap_transaction_t *transaction_create(void) 00098 { 00099 coap_transaction_t *this = ns_dyn_mem_alloc(sizeof(coap_transaction_t)); 00100 if (this) { 00101 memset(this, 0, sizeof(coap_transaction_t)); 00102 this->client_request = true;// default to client initiated method 00103 this->create_time = coap_service_get_internal_timer_ticks(); 00104 ns_list_add_to_start(&request_list, this); 00105 } 00106 00107 return this; 00108 } 00109 00110 static void transaction_free(coap_transaction_t *this) 00111 { 00112 if (this->data_ptr) { 00113 ns_dyn_mem_free(this->data_ptr); 00114 } 00115 ns_dyn_mem_free(this); 00116 } 00117 00118 void transaction_delete(coap_transaction_t *this) 00119 { 00120 if (!coap_message_handler_transaction_valid(this)) { 00121 return; 00122 } 00123 00124 ns_list_remove(&request_list, this); 00125 transaction_free(this); 00126 00127 return; 00128 } 00129 00130 void transactions_delete_all(uint8_t *address_ptr, uint16_t port) 00131 { 00132 coap_transaction_t *transaction = transaction_find_by_address(address_ptr, port); 00133 00134 while (transaction) { 00135 ns_list_remove(&request_list, transaction); 00136 if (transaction->resp_cb) { 00137 transaction->resp_cb(transaction->service_id, address_ptr, port, NULL); 00138 } 00139 sn_coap_protocol_delete_retransmission(coap_service_handle->coap, transaction->msg_id); 00140 transaction_free(transaction); 00141 transaction = transaction_find_by_address(address_ptr, port); 00142 } 00143 } 00144 00145 static int8_t coap_rx_function(sn_coap_hdr_s *resp_ptr, sn_nsdl_addr_s *address_ptr, void *param) 00146 { 00147 coap_transaction_t *this = NULL; 00148 (void)address_ptr; 00149 (void)param; 00150 tr_warn("transaction was not handled %d", resp_ptr->msg_id); 00151 if (!resp_ptr) { 00152 return -1; 00153 } 00154 if( resp_ptr->token_ptr ){ 00155 this = transaction_find_client_by_token(resp_ptr->token_ptr); 00156 } 00157 if (!this) { 00158 return 0; 00159 } 00160 00161 ns_list_remove(&request_list, this); 00162 if (this->resp_cb) { 00163 this->resp_cb(this->service_id, address_ptr->addr_ptr, address_ptr->port, NULL); 00164 } 00165 transaction_free(this); 00166 return 0; 00167 } 00168 00169 coap_msg_handler_t *coap_message_handler_init(void *(*used_malloc_func_ptr)(uint16_t), void (*used_free_func_ptr)(void *), 00170 uint8_t (*used_tx_callback_ptr)(uint8_t *, uint16_t, sn_nsdl_addr_s *, void *)){ 00171 00172 if ((used_malloc_func_ptr == NULL) || (used_free_func_ptr == NULL) || (used_tx_callback_ptr == NULL)) { 00173 return NULL; 00174 } 00175 00176 coap_msg_handler_t *handle; 00177 handle = used_malloc_func_ptr(sizeof(coap_msg_handler_t)); 00178 if (handle == NULL) { 00179 return NULL; 00180 } 00181 00182 memset(handle, 0, sizeof(coap_msg_handler_t)); 00183 00184 handle->sn_coap_tx_callback = used_tx_callback_ptr; 00185 00186 handle->sn_coap_service_free = used_free_func_ptr; 00187 handle->sn_coap_service_malloc = used_malloc_func_ptr; 00188 00189 handle->coap = sn_coap_protocol_init(used_malloc_func_ptr, used_free_func_ptr, used_tx_callback_ptr, &coap_rx_function); 00190 if( !handle->coap ){ 00191 used_free_func_ptr(handle); 00192 return NULL; 00193 } 00194 00195 /* Set default buffer size for CoAP duplicate message detection */ 00196 sn_coap_protocol_set_duplicate_buffer_size(handle->coap, DUPLICATE_MESSAGE_BUFFER_SIZE); 00197 00198 return handle; 00199 } 00200 00201 int8_t coap_message_handler_destroy(coap_msg_handler_t *handle){ 00202 if( !handle ){ 00203 return -1; 00204 } 00205 00206 if( handle->coap ){ 00207 sn_coap_protocol_destroy(handle->coap); 00208 } 00209 00210 //Destroy transactions 00211 ns_list_foreach_safe(coap_transaction_t, cur_ptr, &request_list) { 00212 ns_list_remove(&request_list, cur_ptr); 00213 ns_dyn_mem_free(cur_ptr); 00214 cur_ptr = NULL; 00215 } 00216 00217 handle->sn_coap_service_free(handle); 00218 return 0; 00219 } 00220 00221 coap_transaction_t *coap_message_handler_transaction_valid(coap_transaction_t *tr_ptr) 00222 { 00223 ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) { 00224 if (cur_ptr == tr_ptr) { 00225 return tr_ptr; 00226 } 00227 } 00228 return NULL; 00229 } 00230 00231 coap_transaction_t *coap_message_handler_find_transaction(uint8_t *address_ptr, uint16_t port) 00232 { 00233 if( !address_ptr ) 00234 return NULL; 00235 return transaction_find_by_address( address_ptr, port ); 00236 } 00237 00238 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], 00239 uint8_t *data_ptr, uint16_t data_len, int16_t (cb)(int8_t, sn_coap_hdr_s *, coap_transaction_t *)) 00240 { 00241 sn_nsdl_addr_s src_addr; 00242 sn_coap_hdr_s *coap_message; 00243 int16_t ret_val = 0; 00244 00245 if (!cb || !handle) { 00246 return -1; 00247 } 00248 00249 src_addr.addr_ptr = (uint8_t *)source_addr_ptr; 00250 src_addr.addr_len = 16; 00251 src_addr.type = SN_NSDL_ADDRESS_TYPE_IPV6; 00252 src_addr.port = port; 00253 00254 coap_message = sn_coap_protocol_parse(handle->coap, &src_addr, data_len, data_ptr, NULL); 00255 if (coap_message == NULL) { 00256 tr_err("CoAP Parsing failed"); 00257 return -1; 00258 } 00259 00260 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); 00261 00262 /* Check, if coap itself sends response, or block receiving is ongoing... */ 00263 if (coap_message->coap_status != COAP_STATUS_OK && coap_message->coap_status != COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED) { 00264 tr_debug("CoAP library responds"); 00265 ret_val = -1; 00266 goto exit; 00267 } 00268 00269 /* Request received */ 00270 if (coap_message->msg_code > 0 && coap_message->msg_code < 32) { 00271 coap_transaction_t *transaction_ptr = transaction_create(); 00272 if (transaction_ptr) { 00273 transaction_ptr->service_id = coap_service_id_find_by_socket(socket_id); 00274 transaction_ptr->msg_id = coap_message->msg_id; 00275 transaction_ptr->client_request = false;// this is server transaction 00276 transaction_ptr->req_msg_type = coap_message->msg_type; 00277 memcpy(transaction_ptr->local_address, *(dst_addr_ptr) == 0xFF ? ns_in6addr_any : dst_addr_ptr, 16); 00278 memcpy(transaction_ptr->remote_address, source_addr_ptr, 16); 00279 if (coap_message->token_len) { 00280 memcpy(transaction_ptr->token, coap_message->token_ptr, coap_message->token_len); 00281 } 00282 transaction_ptr->remote_port = port; 00283 if (cb(socket_id, coap_message, transaction_ptr) < 0) { 00284 // negative return value = message ignored -> delete transaction 00285 transaction_delete(transaction_ptr); 00286 } 00287 goto exit; 00288 } else { 00289 ret_val = -1; 00290 } 00291 /* Response received */ 00292 } else { 00293 coap_transaction_t *this = NULL; 00294 if (coap_message->token_ptr) { 00295 this = transaction_find_client_by_token(coap_message->token_ptr); 00296 } 00297 if (!this) { 00298 tr_error("client transaction not found"); 00299 ret_val = -1; 00300 goto exit; 00301 } 00302 tr_debug("Service %d, response received", this->service_id); 00303 ns_list_remove(&request_list, this); 00304 if (this->resp_cb) { 00305 this->resp_cb(this->service_id, (uint8_t *)source_addr_ptr, port, coap_message); 00306 } 00307 transaction_free(this); 00308 } 00309 00310 exit: 00311 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message); 00312 00313 return ret_val; 00314 } 00315 00316 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], 00317 uint16_t destination_port, sn_coap_msg_type_e msg_type, sn_coap_msg_code_e msg_code, const char *uri, 00318 sn_coap_content_format_e cont_type, const uint8_t *payload_ptr, uint16_t payload_len, coap_message_handler_response_recv *request_response_cb) 00319 { 00320 coap_transaction_t *transaction_ptr; 00321 sn_coap_hdr_s request; 00322 sn_nsdl_addr_s dst_addr; 00323 uint8_t token[4]; 00324 uint16_t data_len; 00325 uint8_t *data_ptr; 00326 00327 tr_debug("Service %d, send CoAP request payload_len %d", service_id, payload_len); 00328 transaction_ptr = transaction_create(); 00329 00330 if (!uri || !transaction_ptr) { 00331 return 0; 00332 } 00333 00334 transaction_ptr->service_id = service_id; 00335 transaction_ptr->client_request = true; 00336 transaction_ptr->resp_cb = request_response_cb; 00337 transaction_ptr->options = options; 00338 memcpy(transaction_ptr->remote_address, destination_addr, 16); 00339 transaction_ptr->remote_port = destination_port; 00340 memset(&request, 0, sizeof(request)); 00341 dst_addr.addr_ptr = (uint8_t *) destination_addr; // Cast away const and trust that nsdl doesn't modify... 00342 dst_addr.addr_len = 16; 00343 dst_addr.type = SN_NSDL_ADDRESS_TYPE_IPV6; 00344 dst_addr.port = destination_port; 00345 00346 request.msg_type = msg_type; 00347 request.msg_code = msg_code; 00348 request.uri_path_ptr = (uint8_t *)uri; 00349 request.uri_path_len = strlen(uri); 00350 request.content_format = cont_type; 00351 00352 do{ 00353 randLIB_get_n_bytes_random(token,4); 00354 }while(transaction_find_client_by_token(token)); 00355 memcpy(transaction_ptr->token,token,4); 00356 request.token_ptr = transaction_ptr->token; 00357 request.token_len = 4; 00358 00359 request.payload_len = payload_len; 00360 request.payload_ptr = (uint8_t *) payload_ptr; // Cast away const and trust that nsdl doesn't modify... 00361 data_len = sn_coap_builder_calc_needed_packet_data_size(&request); 00362 data_ptr = own_alloc(data_len); 00363 if(data_len > 0 && !data_ptr){ 00364 transaction_delete(transaction_ptr); 00365 return 0; 00366 } 00367 sn_coap_protocol_build(handle->coap, &dst_addr, data_ptr, &request, transaction_ptr); 00368 transaction_ptr->msg_id = request.msg_id; 00369 handle->sn_coap_tx_callback(data_ptr, data_len, &dst_addr, transaction_ptr); 00370 00371 // Free allocated data 00372 own_free(data_ptr); 00373 if(request_response_cb == NULL){ 00374 //No response expected 00375 return 0; 00376 } 00377 return transaction_ptr->msg_id; 00378 } 00379 00380 static int8_t coap_message_handler_resp_build_and_send(coap_msg_handler_t *handle, sn_coap_hdr_s *coap_msg_ptr, coap_transaction_t *transaction_ptr) 00381 { 00382 sn_nsdl_addr_s dst_addr; 00383 uint16_t data_len; 00384 uint8_t *data_ptr; 00385 00386 00387 dst_addr.addr_ptr = transaction_ptr->remote_address; 00388 dst_addr.addr_len = 16; 00389 dst_addr.type = SN_NSDL_ADDRESS_TYPE_IPV6; 00390 dst_addr.port = transaction_ptr->remote_port; 00391 00392 data_len = sn_coap_builder_calc_needed_packet_data_size(coap_msg_ptr); 00393 data_ptr = own_alloc(data_len); 00394 if (data_len > 0 && !data_ptr) { 00395 return -1; 00396 } 00397 sn_coap_protocol_build(handle->coap, &dst_addr, data_ptr, coap_msg_ptr, transaction_ptr); 00398 00399 handle->sn_coap_tx_callback(data_ptr, data_len, &dst_addr, transaction_ptr); 00400 own_free(data_ptr); 00401 00402 return 0; 00403 00404 } 00405 00406 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) 00407 { 00408 sn_coap_hdr_s *response; 00409 coap_transaction_t *transaction_ptr; 00410 int8_t ret_val = 0; 00411 (void) options; 00412 (void)service_id; 00413 00414 tr_debug("Service %d, send CoAP response", service_id); 00415 if (!request_ptr || !handle) { 00416 tr_error("invalid params"); 00417 return -1; 00418 } 00419 00420 transaction_ptr = transaction_find_server(request_ptr->msg_id); 00421 00422 if (!transaction_ptr) { 00423 tr_error("response transaction not found"); 00424 return -2; 00425 } 00426 00427 response = sn_coap_build_response(handle->coap, request_ptr, message_code); 00428 if( !response ){ 00429 return -1; 00430 } 00431 response->payload_len = payload_len; 00432 response->payload_ptr = (uint8_t *) payload_ptr; // Cast away const and trust that nsdl doesn't modify... 00433 response->content_format = content_type; 00434 00435 00436 ret_val = coap_message_handler_resp_build_and_send(handle, response, transaction_ptr); 00437 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, response); 00438 if(ret_val == 0) { 00439 transaction_delete(transaction_ptr); 00440 } 00441 00442 return ret_val; 00443 } 00444 00445 int8_t coap_message_handler_response_send_by_msg_id(coap_msg_handler_t *handle, int8_t service_id, uint8_t options, uint16_t msg_id, sn_coap_msg_code_e message_code, sn_coap_content_format_e content_type, const uint8_t *payload_ptr,uint16_t payload_len) 00446 { 00447 sn_coap_hdr_s response; 00448 coap_transaction_t *transaction_ptr; 00449 int8_t ret_val; 00450 00451 (void) options; 00452 (void)service_id; 00453 00454 transaction_ptr = transaction_find_server(msg_id); 00455 if (!transaction_ptr || !handle) { 00456 return -1; 00457 } 00458 00459 tr_debug("Service %d, send CoAP response", service_id); 00460 00461 memset(&response, 0, sizeof(sn_coap_hdr_s)); 00462 00463 response.payload_len = payload_len; 00464 response.payload_ptr = (uint8_t *) payload_ptr; // Cast away const and trust that nsdl doesn't modify... 00465 response.content_format = content_type; 00466 response.token_len = 4; 00467 response.token_ptr = transaction_ptr->token; 00468 response.msg_code = message_code; 00469 if (transaction_ptr->req_msg_type == COAP_MSG_TYPE_CONFIRMABLE) { 00470 response.msg_type = COAP_MSG_TYPE_ACKNOWLEDGEMENT; 00471 response.msg_id = msg_id; 00472 } else { 00473 response.msg_type = COAP_MSG_TYPE_NON_CONFIRMABLE; 00474 } 00475 00476 ret_val = coap_message_handler_resp_build_and_send(handle, &response, transaction_ptr); 00477 if(ret_val == 0) { 00478 transaction_delete(transaction_ptr); 00479 } 00480 00481 return ret_val; 00482 } 00483 00484 int8_t coap_message_handler_request_delete(coap_msg_handler_t *handle, int8_t service_id, uint16_t msg_id) 00485 { 00486 coap_transaction_t *transaction_ptr; 00487 (void)service_id; 00488 00489 00490 tr_debug("Service %d, delete CoAP request %d", service_id, msg_id); 00491 if (!handle) { 00492 tr_error("invalid params"); 00493 return -1; 00494 } 00495 sn_coap_protocol_delete_retransmission(handle->coap, msg_id); 00496 00497 transaction_ptr = transaction_find_client(msg_id); 00498 if (!transaction_ptr) { 00499 tr_error("response transaction not found"); 00500 return -2; 00501 } 00502 transaction_delete(transaction_ptr); 00503 return 0; 00504 } 00505 00506 int8_t coap_message_handler_exec(coap_msg_handler_t *handle, uint32_t current_time){ 00507 00508 if( !handle ){ 00509 return -1; 00510 } 00511 00512 // Remove outdated transactions from queue 00513 ns_list_foreach_safe(coap_transaction_t, transaction, &request_list) { 00514 if ((transaction->create_time + TRANSACTION_LIFETIME) < current_time) { 00515 transaction_delete(transaction); 00516 } 00517 } 00518 00519 return sn_coap_protocol_exec(handle->coap, current_time); 00520 }
Generated on Tue Jul 12 2022 13:02:49 by
