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.
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 Tue Jul 12 2022 12:21:47 by
