Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
coap_message_handler.c
00001 /* 00002 * Copyright (c) 2015-2017 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 "mbed-coap/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_client(uint16_t msg_id) 00061 { 00062 coap_transaction_t *this = NULL; 00063 ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) { 00064 if (cur_ptr->msg_id == msg_id && cur_ptr->client_request) { 00065 this = cur_ptr; 00066 break; 00067 } 00068 } 00069 return this; 00070 } 00071 00072 static coap_transaction_t *transaction_find_by_address(uint8_t *address_ptr, uint16_t port) 00073 { 00074 coap_transaction_t *this = NULL; 00075 ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) { 00076 if (cur_ptr->remote_port == port && memcmp(cur_ptr->remote_address, address_ptr, 16) == 0) { 00077 this = cur_ptr; 00078 break; 00079 } 00080 } 00081 return this; 00082 } 00083 00084 static coap_transaction_t *transaction_create(void) 00085 { 00086 coap_transaction_t *this = ns_dyn_mem_alloc(sizeof(coap_transaction_t)); 00087 if (this) { 00088 memset(this, 0, sizeof(coap_transaction_t)); 00089 this->client_request = true;// default to client initiated method 00090 this->create_time = coap_service_get_internal_timer_ticks(); 00091 ns_list_add_to_start(&request_list, this); 00092 } 00093 00094 return this; 00095 } 00096 00097 static void transaction_free(coap_transaction_t *this) 00098 { 00099 if (!this) { 00100 return; 00101 } 00102 00103 if (this->data_ptr) { 00104 ns_dyn_mem_free(this->data_ptr); 00105 } 00106 ns_dyn_mem_free(this); 00107 } 00108 00109 void transaction_delete(coap_transaction_t *this) 00110 { 00111 if (this) { 00112 ns_list_remove(&request_list, this); 00113 transaction_free(this); 00114 } 00115 00116 return; 00117 } 00118 00119 void transactions_delete_all(uint8_t *address_ptr, uint16_t port) 00120 { 00121 coap_transaction_t *transaction = transaction_find_by_address(address_ptr, port); 00122 00123 while (transaction) { 00124 ns_list_remove(&request_list, transaction); 00125 if (transaction->resp_cb) { 00126 transaction->resp_cb(transaction->service_id, address_ptr, port, NULL); 00127 } 00128 sn_coap_protocol_delete_retransmission(coap_service_handle->coap, transaction->msg_id); 00129 transaction_free(transaction); 00130 transaction = transaction_find_by_address(address_ptr, port); 00131 } 00132 } 00133 00134 static int8_t coap_rx_function(sn_coap_hdr_s *resp_ptr, sn_nsdl_addr_s *address_ptr, void *param) 00135 { 00136 coap_transaction_t *this = NULL; 00137 (void)address_ptr; 00138 (void)param; 00139 tr_warn("transaction was not handled %d", resp_ptr->msg_id); 00140 if (!resp_ptr) { 00141 return -1; 00142 } 00143 if( resp_ptr->token_ptr ){ 00144 this = transaction_find_client_by_token(resp_ptr->token_ptr); 00145 } 00146 if (!this) { 00147 return 0; 00148 } 00149 00150 ns_list_remove(&request_list, this); 00151 if (this->resp_cb) { 00152 this->resp_cb(this->service_id, address_ptr->addr_ptr, address_ptr->port, NULL); 00153 } 00154 transaction_free(this); 00155 return 0; 00156 } 00157 00158 coap_msg_handler_t *coap_message_handler_init(void *(*used_malloc_func_ptr)(uint16_t), void (*used_free_func_ptr)(void *), 00159 uint8_t (*used_tx_callback_ptr)(uint8_t *, uint16_t, sn_nsdl_addr_s *, void *)){ 00160 00161 if ((used_malloc_func_ptr == NULL) || (used_free_func_ptr == NULL) || (used_tx_callback_ptr == NULL)) { 00162 return NULL; 00163 } 00164 00165 coap_msg_handler_t *handle; 00166 handle = used_malloc_func_ptr(sizeof(coap_msg_handler_t)); 00167 if (handle == NULL) { 00168 return NULL; 00169 } 00170 00171 memset(handle, 0, sizeof(coap_msg_handler_t)); 00172 00173 handle->sn_coap_tx_callback = used_tx_callback_ptr; 00174 00175 handle->sn_coap_service_free = used_free_func_ptr; 00176 handle->sn_coap_service_malloc = used_malloc_func_ptr; 00177 00178 handle->coap = sn_coap_protocol_init(used_malloc_func_ptr, used_free_func_ptr, used_tx_callback_ptr, &coap_rx_function); 00179 if( !handle->coap ){ 00180 used_free_func_ptr(handle); 00181 return NULL; 00182 } 00183 00184 /* Set default buffer size for CoAP duplicate message detection */ 00185 sn_coap_protocol_set_duplicate_buffer_size(handle->coap, DUPLICATE_MESSAGE_BUFFER_SIZE); 00186 00187 return handle; 00188 } 00189 00190 int8_t coap_message_handler_destroy(coap_msg_handler_t *handle){ 00191 if( !handle ){ 00192 return -1; 00193 } 00194 00195 if( handle->coap ){ 00196 sn_coap_protocol_destroy(handle->coap); 00197 } 00198 00199 //Destroy transactions 00200 ns_list_foreach_safe(coap_transaction_t, cur_ptr, &request_list) { 00201 ns_list_remove(&request_list, cur_ptr); 00202 ns_dyn_mem_free(cur_ptr); 00203 cur_ptr = NULL; 00204 } 00205 00206 handle->sn_coap_service_free(handle); 00207 return 0; 00208 } 00209 00210 coap_transaction_t *coap_message_handler_transaction_valid(coap_transaction_t *tr_ptr) 00211 { 00212 ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) { 00213 if (cur_ptr == tr_ptr) { 00214 return tr_ptr; 00215 } 00216 } 00217 return NULL; 00218 } 00219 00220 coap_transaction_t *coap_message_handler_find_transaction(uint8_t *address_ptr, uint16_t port) 00221 { 00222 if( !address_ptr ) 00223 return NULL; 00224 return transaction_find_by_address( address_ptr, port ); 00225 } 00226 00227 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], 00228 uint8_t *data_ptr, uint16_t data_len, int16_t (cb)(int8_t, sn_coap_hdr_s *, coap_transaction_t *)) 00229 { 00230 if (!cb || !handle) { 00231 return -1; 00232 } 00233 sn_nsdl_addr_s src_addr; 00234 sn_coap_hdr_s *coap_message; 00235 src_addr.addr_ptr = (uint8_t *)source_addr_ptr; 00236 src_addr.addr_len = 16; 00237 src_addr.type = SN_NSDL_ADDRESS_TYPE_IPV6; 00238 src_addr.port = port; 00239 00240 coap_message = sn_coap_protocol_parse(handle->coap, &src_addr, data_len, data_ptr, NULL); 00241 if (coap_message == NULL) { 00242 tr_err("CoAP Parsing failed"); 00243 return -1; 00244 } 00245 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); 00246 /* Check, if coap itself sends response, or block receiving is ongoing... */ 00247 if (coap_message->coap_status != COAP_STATUS_OK && coap_message->coap_status != COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED) { 00248 tr_debug("CoAP library responds"); 00249 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message); 00250 return -1; 00251 } 00252 /* Request received */ 00253 if (coap_message->msg_code > 0 && coap_message->msg_code < 32) { 00254 coap_transaction_t *transaction_ptr = transaction_create(); 00255 if (transaction_ptr) { 00256 transaction_ptr->service_id = coap_service_id_find_by_socket(socket_id); 00257 transaction_ptr->msg_id = coap_message->msg_id; 00258 transaction_ptr->client_request = false;// this is server transaction 00259 memcpy(transaction_ptr->local_address, *(dst_addr_ptr) == 0xFF ? ns_in6addr_any : dst_addr_ptr, 16); 00260 memcpy(transaction_ptr->remote_address, source_addr_ptr, 16); 00261 transaction_ptr->remote_port = port; 00262 00263 int ret = cb(socket_id, coap_message, transaction_ptr); 00264 if (ret != 0) { 00265 tr_debug("Service %d, no response expected", transaction_ptr->service_id); 00266 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message); 00267 transaction_delete(transaction_ptr); 00268 return -1; 00269 } 00270 } else { 00271 //TODO: handle error case 00272 } 00273 /* Response received */ 00274 } else { 00275 coap_transaction_t *this = NULL; 00276 if (coap_message->token_ptr) { 00277 this = transaction_find_client_by_token(coap_message->token_ptr); 00278 } 00279 if (!this) { 00280 tr_error("client transaction not found"); 00281 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message); 00282 return -1; 00283 } 00284 tr_debug("Service %d, response received", this->service_id); 00285 ns_list_remove(&request_list, this); 00286 if (this->resp_cb) { 00287 this->resp_cb(this->service_id, (uint8_t *)source_addr_ptr, port, coap_message); 00288 } 00289 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message); 00290 transaction_free(this); 00291 } 00292 00293 return 0; 00294 00295 } 00296 00297 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], 00298 uint16_t destination_port, sn_coap_msg_type_e msg_type, sn_coap_msg_code_e msg_code, const char *uri, 00299 sn_coap_content_format_e cont_type, const uint8_t *payload_ptr, uint16_t payload_len, coap_message_handler_response_recv *request_response_cb) 00300 { 00301 coap_transaction_t *transaction_ptr; 00302 sn_coap_hdr_s request; 00303 sn_nsdl_addr_s dst_addr; 00304 uint8_t token[4]; 00305 uint16_t data_len; 00306 uint8_t *data_ptr; 00307 00308 tr_debug("Service %d, send CoAP request payload_len %d", service_id, payload_len); 00309 transaction_ptr = transaction_create(); 00310 00311 if (!uri || !transaction_ptr) { 00312 return 0; 00313 } 00314 00315 transaction_ptr->service_id = service_id; 00316 transaction_ptr->client_request = true; 00317 transaction_ptr->resp_cb = request_response_cb; 00318 transaction_ptr->options = options; 00319 memcpy(transaction_ptr->remote_address, destination_addr, 16); 00320 transaction_ptr->remote_port = destination_port; 00321 memset(&request, 0, sizeof(request)); 00322 dst_addr.addr_ptr = (uint8_t *) destination_addr; // Cast away const and trust that nsdl doesn't modify... 00323 dst_addr.addr_len = 16; 00324 dst_addr.type = SN_NSDL_ADDRESS_TYPE_IPV6; 00325 dst_addr.port = destination_port; 00326 00327 request.msg_type = msg_type; 00328 request.msg_code = msg_code; 00329 request.uri_path_ptr = (uint8_t *)uri; 00330 request.uri_path_len = strlen(uri); 00331 request.content_format = cont_type; 00332 00333 do{ 00334 randLIB_get_n_bytes_random(token,4); 00335 }while(transaction_find_client_by_token(token)); 00336 memcpy(transaction_ptr->token,token,4); 00337 request.token_ptr = transaction_ptr->token; 00338 request.token_len = 4; 00339 00340 request.payload_len = payload_len; 00341 request.payload_ptr = (uint8_t *) payload_ptr; // Cast away const and trust that nsdl doesn't modify... 00342 data_len = sn_coap_builder_calc_needed_packet_data_size(&request); 00343 data_ptr = own_alloc(data_len); 00344 if(data_len > 0 && !data_ptr){ 00345 transaction_delete(transaction_ptr); 00346 return 0; 00347 } 00348 sn_coap_protocol_build(handle->coap, &dst_addr, data_ptr, &request, transaction_ptr); 00349 transaction_ptr->msg_id = request.msg_id; 00350 handle->sn_coap_tx_callback(data_ptr, data_len, &dst_addr, transaction_ptr); 00351 00352 // Free allocated data 00353 own_free(data_ptr); 00354 if(request_response_cb == NULL){ 00355 //No response expected 00356 return 0; 00357 } 00358 return transaction_ptr->msg_id; 00359 } 00360 00361 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) 00362 { 00363 coap_transaction_t *transaction_ptr; 00364 sn_coap_hdr_s *response; 00365 sn_nsdl_addr_s dst_addr; 00366 uint16_t data_len; 00367 uint8_t *data_ptr; 00368 (void) options; 00369 (void)service_id; 00370 00371 tr_debug("Service %d, send CoAP response", service_id); 00372 if (!request_ptr || !handle) { 00373 tr_error("invalid params"); 00374 return -1; 00375 } 00376 00377 transaction_ptr = transaction_find_server(request_ptr->msg_id); 00378 00379 if (!transaction_ptr) { 00380 tr_error("response transaction not found"); 00381 return -2; 00382 } 00383 dst_addr.addr_ptr = transaction_ptr->remote_address; 00384 dst_addr.addr_len = 16; 00385 dst_addr.type = SN_NSDL_ADDRESS_TYPE_IPV6; 00386 dst_addr.port = transaction_ptr->remote_port; 00387 00388 response = sn_coap_build_response(handle->coap, request_ptr, message_code); 00389 if( !response ){ 00390 return -1; 00391 } 00392 response->payload_len = payload_len; 00393 response->payload_ptr = (uint8_t *) payload_ptr; // Cast away const and trust that nsdl doesn't modify... 00394 response->content_format = content_type; 00395 00396 data_len = sn_coap_builder_calc_needed_packet_data_size(response); 00397 data_ptr = own_alloc(data_len); 00398 if (data_len > 0 && !data_ptr) { 00399 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, response); 00400 return -1; 00401 } 00402 sn_coap_protocol_build(handle->coap, &dst_addr, data_ptr, response, transaction_ptr); 00403 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, response); 00404 handle->sn_coap_tx_callback(data_ptr, data_len, &dst_addr, transaction_ptr); 00405 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, request_ptr); 00406 own_free(data_ptr); 00407 return 0; 00408 } 00409 00410 int8_t coap_message_handler_request_delete(coap_msg_handler_t *handle, int8_t service_id, uint16_t msg_id) 00411 { 00412 coap_transaction_t *transaction_ptr; 00413 (void)service_id; 00414 00415 00416 tr_debug("Service %d, delete CoAP request %d", service_id, msg_id); 00417 if (!handle) { 00418 tr_error("invalid params"); 00419 return -1; 00420 } 00421 sn_coap_protocol_delete_retransmission(handle->coap, msg_id); 00422 00423 transaction_ptr = transaction_find_client(msg_id); 00424 if (!transaction_ptr) { 00425 tr_error("response transaction not found"); 00426 return -2; 00427 } 00428 transaction_delete(transaction_ptr); 00429 return 0; 00430 } 00431 00432 int8_t coap_message_handler_exec(coap_msg_handler_t *handle, uint32_t current_time){ 00433 00434 if( !handle ){ 00435 return -1; 00436 } 00437 00438 // Remove outdated transactions from queue 00439 ns_list_foreach_safe(coap_transaction_t, transaction, &request_list) { 00440 if ((transaction->create_time + TRANSACTION_LIFETIME) < current_time) { 00441 transaction_delete(transaction); 00442 } 00443 } 00444 00445 return sn_coap_protocol_exec(handle->coap, current_time); 00446 }
Generated on Sun Jul 17 2022 08:25:21 by 1.7.2