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.
Fork of OmniWheels by
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, uint8_t token_len, const uint8_t address[static 16], uint16_t port) 00050 { 00051 (void) address; 00052 (void) port; 00053 coap_transaction_t *this = NULL; 00054 00055 ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) { 00056 if ((cur_ptr->token_len == token_len) && (memcmp(cur_ptr->token, token, token_len) == 0) && cur_ptr->client_request) { 00057 this = cur_ptr; 00058 break; 00059 } 00060 } 00061 return this; 00062 } 00063 00064 static coap_transaction_t *transaction_find_server(uint16_t msg_id) 00065 { 00066 coap_transaction_t *this = NULL; 00067 ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) { 00068 if (cur_ptr->msg_id == msg_id && !cur_ptr->client_request) { 00069 this = cur_ptr; 00070 break; 00071 } 00072 } 00073 return this; 00074 } 00075 00076 static coap_transaction_t *transaction_find_client(uint16_t msg_id) 00077 { 00078 coap_transaction_t *this = NULL; 00079 ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) { 00080 if (cur_ptr->msg_id == msg_id && cur_ptr->client_request) { 00081 this = cur_ptr; 00082 break; 00083 } 00084 } 00085 return this; 00086 } 00087 00088 static coap_transaction_t *transaction_find_by_address(uint8_t *address_ptr, uint16_t port) 00089 { 00090 coap_transaction_t *this = NULL; 00091 ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) { 00092 if (cur_ptr->remote_port == port && memcmp(cur_ptr->remote_address, address_ptr, 16) == 0) { 00093 this = cur_ptr; 00094 break; 00095 } 00096 } 00097 return this; 00098 } 00099 00100 /* retransmission valid time is calculated to be max. time that CoAP message sending can take: */ 00101 /* Number of retransmisisons, each retransmission is 2 * previous retransmisison time */ 00102 /* + random factor (max. 1.5) */ 00103 static uint32_t transaction_valid_time_calculate(void) 00104 { 00105 int i; 00106 uint32_t time_valid = 0; 00107 00108 for (i = 0; i <= COAP_RESENDING_COUNT; i++) { 00109 time_valid += (COAP_RESENDING_INTERVAL << i) * 1.5; 00110 } 00111 00112 return time_valid + coap_service_get_internal_timer_ticks(); 00113 } 00114 00115 static coap_transaction_t *transaction_create(void) 00116 { 00117 coap_transaction_t *this = ns_dyn_mem_alloc(sizeof(coap_transaction_t)); 00118 if (this) { 00119 memset(this, 0, sizeof(coap_transaction_t)); 00120 this->client_request = true;// default to client initiated method 00121 this->valid_until = transaction_valid_time_calculate(); 00122 ns_list_add_to_start(&request_list, this); 00123 } 00124 00125 return this; 00126 } 00127 00128 static void transaction_free(coap_transaction_t *this) 00129 { 00130 if (this->data_ptr) { 00131 ns_dyn_mem_free(this->data_ptr); 00132 } 00133 ns_dyn_mem_free(this); 00134 } 00135 00136 void transaction_delete(coap_transaction_t *this) 00137 { 00138 if (!coap_message_handler_transaction_valid(this)) { 00139 return; 00140 } 00141 00142 ns_list_remove(&request_list, this); 00143 transaction_free(this); 00144 00145 return; 00146 } 00147 00148 void transactions_delete_all(uint8_t *address_ptr, uint16_t port) 00149 { 00150 coap_transaction_t *transaction = transaction_find_by_address(address_ptr, port); 00151 00152 while (transaction) { 00153 ns_list_remove(&request_list, transaction); 00154 if (transaction->resp_cb) { 00155 transaction->resp_cb(transaction->service_id, address_ptr, port, NULL); 00156 } 00157 sn_coap_protocol_delete_retransmission(coap_service_handle->coap, transaction->msg_id); 00158 transaction_free(transaction); 00159 transaction = transaction_find_by_address(address_ptr, port); 00160 } 00161 } 00162 00163 static int8_t coap_rx_function(sn_coap_hdr_s *resp_ptr, sn_nsdl_addr_s *address_ptr, void *param) 00164 { 00165 coap_transaction_t *this = NULL; 00166 (void)address_ptr; 00167 (void)param; 00168 00169 tr_warn("transaction was not handled %d", resp_ptr->msg_id); 00170 if (!resp_ptr) { 00171 return -1; 00172 } 00173 if(resp_ptr->token_ptr){ 00174 this = transaction_find_client_by_token(resp_ptr->token_ptr, resp_ptr->token_len, address_ptr->addr_ptr, address_ptr->port); 00175 } 00176 if (!this) { 00177 return 0; 00178 } 00179 00180 ns_list_remove(&request_list, this); 00181 if (this->resp_cb) { 00182 this->resp_cb(this->service_id, address_ptr->addr_ptr, address_ptr->port, NULL); 00183 } 00184 transaction_free(this); 00185 return 0; 00186 } 00187 00188 coap_msg_handler_t *coap_message_handler_init(void *(*used_malloc_func_ptr)(uint16_t), void (*used_free_func_ptr)(void *), 00189 uint8_t (*used_tx_callback_ptr)(uint8_t *, uint16_t, sn_nsdl_addr_s *, void *)){ 00190 00191 if ((used_malloc_func_ptr == NULL) || (used_free_func_ptr == NULL) || (used_tx_callback_ptr == NULL)) { 00192 return NULL; 00193 } 00194 00195 coap_msg_handler_t *handle; 00196 handle = used_malloc_func_ptr(sizeof(coap_msg_handler_t)); 00197 if (handle == NULL) { 00198 return NULL; 00199 } 00200 00201 memset(handle, 0, sizeof(coap_msg_handler_t)); 00202 00203 handle->sn_coap_tx_callback = used_tx_callback_ptr; 00204 00205 handle->sn_coap_service_free = used_free_func_ptr; 00206 handle->sn_coap_service_malloc = used_malloc_func_ptr; 00207 00208 handle->coap = sn_coap_protocol_init(used_malloc_func_ptr, used_free_func_ptr, used_tx_callback_ptr, &coap_rx_function); 00209 if( !handle->coap ){ 00210 used_free_func_ptr(handle); 00211 return NULL; 00212 } 00213 00214 /* Set default buffer size for CoAP duplicate message detection */ 00215 sn_coap_protocol_set_duplicate_buffer_size(handle->coap, DUPLICATE_MESSAGE_BUFFER_SIZE); 00216 00217 /* Set default CoAP retransmission paramters */ 00218 sn_coap_protocol_set_retransmission_parameters(handle->coap, COAP_RESENDING_COUNT, COAP_RESENDING_INTERVAL); 00219 00220 return handle; 00221 } 00222 00223 int8_t coap_message_handler_destroy(coap_msg_handler_t *handle){ 00224 if( !handle ){ 00225 return -1; 00226 } 00227 00228 if( handle->coap ){ 00229 sn_coap_protocol_destroy(handle->coap); 00230 } 00231 00232 //Destroy transactions 00233 ns_list_foreach_safe(coap_transaction_t, cur_ptr, &request_list) { 00234 ns_list_remove(&request_list, cur_ptr); 00235 ns_dyn_mem_free(cur_ptr); 00236 cur_ptr = NULL; 00237 } 00238 00239 handle->sn_coap_service_free(handle); 00240 return 0; 00241 } 00242 00243 coap_transaction_t *coap_message_handler_transaction_valid(coap_transaction_t *tr_ptr) 00244 { 00245 ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) { 00246 if (cur_ptr == tr_ptr) { 00247 return tr_ptr; 00248 } 00249 } 00250 return NULL; 00251 } 00252 00253 coap_transaction_t *coap_message_handler_find_transaction(uint8_t *address_ptr, uint16_t port) 00254 { 00255 if( !address_ptr ) 00256 return NULL; 00257 return transaction_find_by_address( address_ptr, port ); 00258 } 00259 00260 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], 00261 uint8_t *data_ptr, uint16_t data_len, int16_t (cb)(int8_t, sn_coap_hdr_s *, coap_transaction_t *)) 00262 { 00263 sn_nsdl_addr_s src_addr; 00264 sn_coap_hdr_s *coap_message; 00265 int16_t ret_val = 0; 00266 00267 if (!cb || !handle) { 00268 return -1; 00269 } 00270 00271 src_addr.addr_ptr = (uint8_t *)source_addr_ptr; 00272 src_addr.addr_len = 16; 00273 src_addr.type = SN_NSDL_ADDRESS_TYPE_IPV6; 00274 src_addr.port = port; 00275 00276 coap_message = sn_coap_protocol_parse(handle->coap, &src_addr, data_len, data_ptr, NULL); 00277 if (coap_message == NULL) { 00278 tr_err("CoAP Parsing failed"); 00279 return -1; 00280 } 00281 00282 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); 00283 00284 /* Check, if coap itself sends response, or block receiving is ongoing... */ 00285 if (coap_message->coap_status != COAP_STATUS_OK && coap_message->coap_status != COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED) { 00286 tr_debug("CoAP library responds"); 00287 ret_val = -1; 00288 goto exit; 00289 } 00290 00291 /* Request received */ 00292 if (coap_message->msg_code > 0 && coap_message->msg_code < 32) { 00293 coap_transaction_t *transaction_ptr = transaction_create(); 00294 if (transaction_ptr) { 00295 transaction_ptr->service_id = coap_service_id_find_by_socket(socket_id); 00296 transaction_ptr->msg_id = coap_message->msg_id; 00297 transaction_ptr->client_request = false;// this is server transaction 00298 transaction_ptr->req_msg_type = coap_message->msg_type; 00299 memcpy(transaction_ptr->local_address, *(dst_addr_ptr) == 0xFF ? ns_in6addr_any : dst_addr_ptr, 16); 00300 memcpy(transaction_ptr->remote_address, source_addr_ptr, 16); 00301 if (coap_message->token_len) { 00302 memcpy(transaction_ptr->token, coap_message->token_ptr, coap_message->token_len); 00303 transaction_ptr->token_len = coap_message->token_len; 00304 } 00305 transaction_ptr->remote_port = port; 00306 if (cb(socket_id, coap_message, transaction_ptr) < 0) { 00307 // negative return value = message ignored -> delete transaction 00308 transaction_delete(transaction_ptr); 00309 } 00310 goto exit; 00311 } else { 00312 ret_val = -1; 00313 } 00314 /* Response received */ 00315 } else { 00316 coap_transaction_t *this = NULL; 00317 if (coap_message->token_ptr) { 00318 this = transaction_find_client_by_token(coap_message->token_ptr, coap_message->token_len, source_addr_ptr, port); 00319 } 00320 if (!this) { 00321 tr_error("client transaction not found"); 00322 ret_val = -1; 00323 goto exit; 00324 } 00325 tr_debug("Service %d, response received", this->service_id); 00326 ns_list_remove(&request_list, this); 00327 if (this->resp_cb) { 00328 this->resp_cb(this->service_id, (uint8_t *)source_addr_ptr, port, coap_message); 00329 } 00330 transaction_free(this); 00331 } 00332 00333 exit: 00334 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message); 00335 00336 return ret_val; 00337 } 00338 00339 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], 00340 uint16_t destination_port, sn_coap_msg_type_e msg_type, sn_coap_msg_code_e msg_code, const char *uri, 00341 sn_coap_content_format_e cont_type, const uint8_t *payload_ptr, uint16_t payload_len, coap_message_handler_response_recv *request_response_cb) 00342 { 00343 coap_transaction_t *transaction_ptr; 00344 sn_coap_hdr_s request; 00345 sn_nsdl_addr_s dst_addr; 00346 uint8_t token[4]; 00347 uint16_t data_len; 00348 uint8_t *data_ptr; 00349 00350 tr_debug("Service %d, send CoAP request payload_len %d", service_id, payload_len); 00351 transaction_ptr = transaction_create(); 00352 00353 if (!uri || !transaction_ptr) { 00354 return 0; 00355 } 00356 00357 transaction_ptr->service_id = service_id; 00358 transaction_ptr->client_request = true; 00359 transaction_ptr->resp_cb = request_response_cb; 00360 transaction_ptr->options = options; 00361 memcpy(transaction_ptr->remote_address, destination_addr, 16); 00362 transaction_ptr->remote_port = destination_port; 00363 transaction_ptr->req_msg_type = msg_type; 00364 memset(&request, 0, sizeof(request)); 00365 dst_addr.addr_ptr = (uint8_t *) destination_addr; // Cast away const and trust that nsdl doesn't modify... 00366 dst_addr.addr_len = 16; 00367 dst_addr.type = SN_NSDL_ADDRESS_TYPE_IPV6; 00368 dst_addr.port = destination_port; 00369 00370 request.msg_type = msg_type; 00371 request.msg_code = msg_code; 00372 request.uri_path_ptr = (uint8_t *)uri; 00373 request.uri_path_len = strlen(uri); 00374 request.content_format = cont_type; 00375 00376 do{ 00377 randLIB_get_n_bytes_random(token,4); 00378 }while(transaction_find_client_by_token(token, 4, destination_addr, destination_port)); 00379 memcpy(transaction_ptr->token,token,4); 00380 transaction_ptr->token_len = 4; 00381 request.token_ptr = transaction_ptr->token; 00382 request.token_len = 4; 00383 00384 request.payload_len = payload_len; 00385 request.payload_ptr = (uint8_t *) payload_ptr; // Cast away const and trust that nsdl doesn't modify... 00386 data_len = sn_coap_builder_calc_needed_packet_data_size(&request); 00387 data_ptr = own_alloc(data_len); 00388 if(data_len > 0 && !data_ptr){ 00389 transaction_delete(transaction_ptr); 00390 return 0; 00391 } 00392 int16_t sn_coap_ret = sn_coap_protocol_build(handle->coap, &dst_addr, data_ptr, &request, transaction_ptr); 00393 if (sn_coap_ret == -4) { 00394 /* 00395 * Not able to add message to resend queue, adjust message lifetime to one resending 00396 */ 00397 transaction_ptr->valid_until = coap_service_get_internal_timer_ticks() + COAP_RESENDING_INTERVAL; 00398 } else if (sn_coap_ret < 0) { 00399 /* 00400 * Failed to build message, set transaction validity time to minimum to get this transaction cleared 00401 * immediately and callback called. 00402 */ 00403 transaction_ptr->valid_until = coap_service_get_internal_timer_ticks(); 00404 } 00405 00406 transaction_ptr->msg_id = request.msg_id; 00407 handle->sn_coap_tx_callback(data_ptr, data_len, &dst_addr, transaction_ptr); 00408 00409 // Free allocated data 00410 own_free(data_ptr); 00411 if(request_response_cb == NULL){ 00412 //No response expected 00413 return 0; 00414 } 00415 return request.msg_id; 00416 } 00417 00418 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) 00419 { 00420 sn_nsdl_addr_s dst_addr; 00421 uint16_t data_len; 00422 uint8_t *data_ptr; 00423 00424 00425 dst_addr.addr_ptr = transaction_ptr->remote_address; 00426 dst_addr.addr_len = 16; 00427 dst_addr.type = SN_NSDL_ADDRESS_TYPE_IPV6; 00428 dst_addr.port = transaction_ptr->remote_port; 00429 00430 data_len = sn_coap_builder_calc_needed_packet_data_size(coap_msg_ptr); 00431 data_ptr = own_alloc(data_len); 00432 if (data_len > 0 && !data_ptr) { 00433 return -1; 00434 } 00435 sn_coap_protocol_build(handle->coap, &dst_addr, data_ptr, coap_msg_ptr, transaction_ptr); 00436 00437 handle->sn_coap_tx_callback(data_ptr, data_len, &dst_addr, transaction_ptr); 00438 own_free(data_ptr); 00439 00440 return 0; 00441 00442 } 00443 00444 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) 00445 { 00446 sn_coap_hdr_s *response; 00447 coap_transaction_t *transaction_ptr; 00448 int8_t ret_val = 0; 00449 (void) options; 00450 (void)service_id; 00451 00452 tr_debug("Service %d, send CoAP response", service_id); 00453 if (!request_ptr || !handle) { 00454 tr_error("invalid params"); 00455 return -1; 00456 } 00457 00458 transaction_ptr = transaction_find_server(request_ptr->msg_id); 00459 00460 if (!transaction_ptr) { 00461 tr_error("response transaction not found"); 00462 return -2; 00463 } 00464 00465 response = sn_coap_build_response(handle->coap, request_ptr, message_code); 00466 if( !response ){ 00467 return -1; 00468 } 00469 response->payload_len = payload_len; 00470 response->payload_ptr = (uint8_t *) payload_ptr; // Cast away const and trust that nsdl doesn't modify... 00471 response->content_format = content_type; 00472 00473 00474 ret_val = coap_message_handler_resp_build_and_send(handle, response, transaction_ptr); 00475 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, response); 00476 if(ret_val == 0) { 00477 transaction_delete(transaction_ptr); 00478 } 00479 00480 return ret_val; 00481 } 00482 00483 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) 00484 { 00485 sn_coap_hdr_s response; 00486 coap_transaction_t *transaction_ptr; 00487 int8_t ret_val; 00488 00489 (void) options; 00490 (void)service_id; 00491 00492 transaction_ptr = transaction_find_server(msg_id); 00493 if (!transaction_ptr || !handle) { 00494 return -1; 00495 } 00496 00497 tr_debug("Service %d, send CoAP response", service_id); 00498 00499 memset(&response, 0, sizeof(sn_coap_hdr_s)); 00500 00501 response.payload_len = payload_len; 00502 response.payload_ptr = (uint8_t *) payload_ptr; // Cast away const and trust that nsdl doesn't modify... 00503 response.content_format = content_type; 00504 response.token_len = transaction_ptr->token_len; 00505 response.token_ptr = transaction_ptr->token; 00506 response.msg_code = message_code; 00507 if (transaction_ptr->req_msg_type == COAP_MSG_TYPE_CONFIRMABLE) { 00508 response.msg_type = COAP_MSG_TYPE_ACKNOWLEDGEMENT; 00509 response.msg_id = msg_id; 00510 } else { 00511 response.msg_type = COAP_MSG_TYPE_NON_CONFIRMABLE; 00512 } 00513 00514 ret_val = coap_message_handler_resp_build_and_send(handle, &response, transaction_ptr); 00515 if(ret_val == 0) { 00516 transaction_delete(transaction_ptr); 00517 } 00518 00519 return ret_val; 00520 } 00521 00522 int8_t coap_message_handler_request_delete(coap_msg_handler_t *handle, int8_t service_id, uint16_t msg_id) 00523 { 00524 coap_transaction_t *transaction_ptr; 00525 (void)service_id; 00526 00527 00528 tr_debug("Service %d, delete CoAP request %d", service_id, msg_id); 00529 if (!handle) { 00530 tr_error("invalid params"); 00531 return -1; 00532 } 00533 sn_coap_protocol_delete_retransmission(handle->coap, msg_id); 00534 00535 transaction_ptr = transaction_find_client(msg_id); 00536 if (!transaction_ptr) { 00537 tr_error("response transaction not found"); 00538 return -2; 00539 } 00540 transaction_delete(transaction_ptr); 00541 return 0; 00542 } 00543 00544 int8_t coap_message_handler_exec(coap_msg_handler_t *handle, uint32_t current_time){ 00545 00546 if( !handle ){ 00547 return -1; 00548 } 00549 00550 // Remove outdated transactions from queue 00551 ns_list_foreach_safe(coap_transaction_t, transaction, &request_list) { 00552 if (transaction->valid_until < current_time) { 00553 tr_debug("transaction %d timed out", transaction->msg_id); 00554 ns_list_remove(&request_list, transaction); 00555 if (transaction->resp_cb) { 00556 transaction->resp_cb(transaction->service_id, transaction->remote_address, transaction->remote_port, NULL); 00557 } 00558 transaction_free(transaction); 00559 } 00560 } 00561 00562 return sn_coap_protocol_exec(handle->coap, current_time); 00563 }
Generated on Fri Jul 22 2022 04:53:46 by
1.7.2
