Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
coap_service_api.c
00001 /* 00002 * Copyright (c) 2015-2017 ARM Limited. All Rights Reserved. 00003 */ 00004 00005 00006 00007 #include <string.h> 00008 00009 #include "ns_types.h" 00010 #include "ns_list.h" 00011 #include "ns_trace.h" 00012 #include "nsdynmemLIB.h" 00013 #include "mbed-coap/sn_coap_header.h" 00014 #include "coap_service_api.h" 00015 #include "coap_message_handler.h" 00016 #include "eventOS_event.h" 00017 #include "eventOS_scheduler.h" 00018 #include "eventOS_event_timer.h" 00019 #include "common_functions.h" 00020 #include "coap_connection_handler.h" 00021 #include "net_interface.h" 00022 #include "coap_service_api_internal.h" 00023 #include "coap_message_handler.h" 00024 #include "mbed-coap/sn_coap_protocol.h" 00025 00026 static int16_t coap_msg_process_callback(int8_t socket_id, sn_coap_hdr_s *coap_message, coap_transaction_t *transaction_ptr); 00027 00028 typedef struct uri_registration { 00029 char *uri_ptr; 00030 uint16_t uri_len; 00031 uint8_t allowed_method; 00032 coap_service_request_recv_cb *request_recv_cb; 00033 ns_list_link_t link; 00034 } uri_registration_t; 00035 00036 typedef NS_LIST_HEAD(uri_registration_t, link) uri_registration_list_t; 00037 00038 typedef struct coap_service { 00039 coap_service_security_done_cb *coap_security_done_cb; 00040 coap_service_security_start_cb *security_start_cb; 00041 coap_service_virtual_socket_send_cb *virtual_socket_send_cb; 00042 uri_registration_list_t uri_list; 00043 coap_conn_handler_t *conn_handler; 00044 int8_t interface_id; 00045 int8_t service_id; 00046 int8_t listen_socket; 00047 uint8_t service_options; 00048 ns_list_link_t link; 00049 } coap_service_t; 00050 00051 #define TRACE_GROUP "ThSA" 00052 00053 static NS_LIST_DEFINE(instance_list, coap_service_t, link); 00054 static int8_t tasklet_id = -1; 00055 coap_msg_handler_t *coap_service_handle = NULL; 00056 static uint32_t coap_ticks = 1; 00057 00058 #define COAP_TICK_TIMER 0xf1 00059 00060 static uri_registration_t *uri_registration_find(coap_service_t *this, const void *uri_ptr, uint16_t uri_len) 00061 { 00062 ns_list_foreach(uri_registration_t, cur_ptr, &this->uri_list) { 00063 if (cur_ptr->uri_len == uri_len && memcmp(cur_ptr->uri_ptr, uri_ptr, uri_len) == 0) { 00064 return cur_ptr; 00065 } 00066 } 00067 return NULL; 00068 } 00069 static coap_service_t *service_find(int8_t service_id) 00070 { 00071 coap_service_t *this = NULL; 00072 ns_list_foreach(coap_service_t, cur_ptr, &instance_list) { 00073 if (cur_ptr->service_id == service_id) { 00074 this = cur_ptr; 00075 break; 00076 } 00077 } 00078 return this; 00079 } 00080 00081 static coap_service_t *service_find_by_socket(int8_t socket_id) 00082 { 00083 coap_service_t *this = NULL; 00084 ns_list_foreach(coap_service_t, cur_ptr, &instance_list) { 00085 if( coap_connection_handler_socket_belongs_to(cur_ptr->conn_handler, socket_id) ){ 00086 this = cur_ptr; 00087 break; 00088 } 00089 } 00090 return this; 00091 } 00092 00093 static coap_service_t *service_find_by_uri(uint8_t socket_id, uint8_t *uri_ptr, uint16_t uri_len) 00094 { 00095 ns_list_foreach(coap_service_t, cur_ptr, &instance_list) { 00096 if (coap_connection_handler_socket_belongs_to(cur_ptr->conn_handler, socket_id) && uri_registration_find(cur_ptr, uri_ptr, uri_len)) { 00097 return cur_ptr; 00098 } 00099 } 00100 return NULL; 00101 } 00102 00103 static bool coap_service_can_leave_multicast_group(coap_conn_handler_t *conn_handler) 00104 { 00105 int mc_count = 0; 00106 bool current_handler_joined_to_mc_group = false; 00107 00108 ns_list_foreach(coap_service_t, cur_ptr, &instance_list) { 00109 if (cur_ptr->conn_handler && cur_ptr->conn_handler->registered_to_multicast) { 00110 if (conn_handler == cur_ptr->conn_handler) { 00111 current_handler_joined_to_mc_group = true; 00112 } 00113 mc_count ++; 00114 } 00115 } 00116 00117 if (mc_count == 1 && current_handler_joined_to_mc_group) { 00118 // current handler is the only one joined to multicast group 00119 return true; 00120 } 00121 00122 return false; 00123 } 00124 00125 /** 00126 * Coap handling functions 00127 */ 00128 static void *own_alloc(uint16_t size) 00129 { 00130 if (size) { 00131 return ns_dyn_mem_temporary_alloc(size); 00132 } else { 00133 return 0; 00134 } 00135 } 00136 00137 static void own_free(void *ptr) 00138 { 00139 if (ptr) { 00140 ns_dyn_mem_free(ptr); 00141 } 00142 } 00143 00144 static uint8_t coap_tx_function(uint8_t *data_ptr, uint16_t data_len, sn_nsdl_addr_s *address_ptr, void *param) 00145 { 00146 coap_service_t *this; 00147 coap_transaction_t *transaction_ptr = coap_message_handler_transaction_valid(param); 00148 ns_address_t dest_addr; 00149 00150 if (!transaction_ptr || !data_ptr) { 00151 return 0; 00152 } 00153 00154 tr_debug("Service %d, CoAP TX Function - mid: %d", transaction_ptr->service_id, common_read_16_bit(data_ptr + 2)); 00155 00156 this = service_find(transaction_ptr->service_id); 00157 if (!this) { 00158 return 0; 00159 } 00160 00161 memcpy(&(dest_addr.address), address_ptr->addr_ptr, 16); 00162 dest_addr.identifier = address_ptr->port; 00163 dest_addr.type = ADDRESS_IPV6; 00164 00165 if (-2 == coap_connection_handler_send_data(this->conn_handler, &dest_addr, transaction_ptr->local_address, 00166 data_ptr, data_len, (this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS) == COAP_SERVICE_OPTIONS_SECURE_BYPASS)) { 00167 transaction_ptr->data_ptr = ns_dyn_mem_alloc(data_len); 00168 if (!transaction_ptr->data_ptr) { 00169 tr_debug("coap tx out of memory"); 00170 return 0; 00171 00172 } 00173 memcpy(transaction_ptr->data_ptr, data_ptr, data_len); 00174 transaction_ptr->data_len = data_len; 00175 } else if (transaction_ptr->resp_cb == NULL ) { 00176 transaction_delete(transaction_ptr); 00177 } 00178 00179 return 0; 00180 } 00181 00182 static void service_event_handler(arm_event_s *event) 00183 { 00184 if (event->event_type == ARM_LIB_TASKLET_INIT_EVENT) { 00185 tr_debug("service tasklet initialised"); 00186 /*initialize coap service and listen socket*/ 00187 } 00188 if (event->event_type == ARM_LIB_SYSTEM_TIMER_EVENT && event->event_id == COAP_TICK_TIMER) { 00189 coap_message_handler_exec(coap_service_handle, coap_ticks++); 00190 if(coap_ticks && !coap_ticks % SECURE_SESSION_CLEAN_INTERVAL){ 00191 coap_connection_handler_exec(coap_ticks); 00192 } 00193 } 00194 eventOS_event_timer_request((uint8_t)COAP_TICK_TIMER, ARM_LIB_SYSTEM_TIMER_EVENT, tasklet_id, 1000); 00195 } 00196 00197 static int16_t coap_msg_process_callback(int8_t socket_id, sn_coap_hdr_s *coap_message, coap_transaction_t *transaction_ptr) 00198 { 00199 coap_service_t *this; 00200 if (!coap_message || !transaction_ptr) { 00201 return -1; 00202 } 00203 00204 // Message is request, find correct handle 00205 this = service_find_by_uri(socket_id, coap_message->uri_path_ptr, coap_message->uri_path_len); 00206 if (!this) { 00207 tr_debug("not registered uri %.*s", coap_message->uri_path_len, coap_message->uri_path_ptr); 00208 if (coap_message->msg_type == COAP_MSG_TYPE_CONFIRMABLE) { 00209 coap_message_handler_response_send(coap_service_handle, transaction_ptr->service_id, COAP_SERVICE_OPTIONS_NONE, coap_message, 00210 COAP_MSG_CODE_RESPONSE_NOT_FOUND, COAP_CT_NONE, NULL, 0); 00211 return 0; 00212 } 00213 return -1; 00214 } 00215 00216 uri_registration_t *uri_reg_ptr = uri_registration_find(this, coap_message->uri_path_ptr, coap_message->uri_path_len); 00217 if (uri_reg_ptr && uri_reg_ptr->request_recv_cb) { 00218 tr_debug("Service %d, call request recv cb uri %.*s", this->service_id, coap_message->uri_path_len, coap_message->uri_path_ptr); 00219 00220 if ((this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS) == COAP_SERVICE_OPTIONS_SECURE_BYPASS ) {//TODO Add secure bypass option 00221 // Service has secure bypass active TODO this is not defined in interface 00222 // this check can be removed I think 00223 transaction_ptr->options = COAP_REQUEST_OPTIONS_SECURE_BYPASS; 00224 } 00225 transaction_ptr->service_id = this->service_id; 00226 return uri_reg_ptr->request_recv_cb(this->service_id, transaction_ptr->remote_address, transaction_ptr->remote_port, coap_message); 00227 } 00228 return -1; 00229 } 00230 00231 static int recv_cb(int8_t socket_id, uint8_t src_address[static 16], uint16_t port, const uint8_t dst_address[static 16], unsigned char *data, int len) 00232 { 00233 uint8_t *data_ptr = NULL; 00234 uint16_t data_len = 0; 00235 00236 if (!data || !len) { 00237 return -1; 00238 } 00239 00240 data_ptr = own_alloc(len); 00241 00242 if (!data_ptr) { 00243 return -1; 00244 } 00245 memcpy(data_ptr, data, len); 00246 data_len = len; 00247 tr_debug("service recv socket data len %d ", data_len); 00248 00249 //parse coap message what CoAP to use 00250 int ret = coap_message_handler_coap_msg_process(coap_service_handle, socket_id, src_address, port, dst_address, data_ptr, data_len, &coap_msg_process_callback); 00251 own_free(data_ptr); 00252 return ret; 00253 } 00254 00255 static int send_cb(int8_t socket_id, const uint8_t address[static 16], uint16_t port, const void *data_ptr, int data_len) 00256 { 00257 coap_service_t *this = service_find_by_socket(socket_id); 00258 if (this && this->virtual_socket_send_cb) { 00259 tr_debug("send to virtual socket, service: %d", this->service_id); 00260 return this->virtual_socket_send_cb(this->service_id, (uint8_t*)address, port, data_ptr, data_len); 00261 } 00262 return -1; 00263 } 00264 00265 static void sec_done_cb(int8_t socket_id, uint8_t address[static 16], uint16_t port, uint8_t keyblock[static 40]) 00266 { 00267 //TODO: this is not enough if shared socket. Inform all! 00268 coap_service_t *this = service_find_by_socket(socket_id); 00269 if (this && this->coap_security_done_cb) { // secure done callback 00270 this->coap_security_done_cb(this->service_id, address, keyblock); 00271 } 00272 00273 //TODO: send all unsend transactions if more than 1 00274 coap_transaction_t *transaction_ptr = coap_message_handler_find_transaction(address, port); 00275 if (transaction_ptr && transaction_ptr->data_ptr) { 00276 tr_debug("send delayed packet"); 00277 ns_address_t dest_addr; 00278 memcpy(dest_addr.address, address, 16); 00279 dest_addr.identifier = port; 00280 dest_addr.type = ADDRESS_IPV6; 00281 00282 coap_connection_handler_send_data(this->conn_handler, &dest_addr, transaction_ptr->local_address, 00283 transaction_ptr->data_ptr, transaction_ptr->data_len, (this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS) == COAP_SERVICE_OPTIONS_SECURE_BYPASS); 00284 ns_dyn_mem_free(transaction_ptr->data_ptr); 00285 transaction_ptr->data_ptr = NULL; 00286 transaction_ptr->data_len = 0; 00287 if (transaction_ptr->resp_cb == NULL) { 00288 transaction_delete(transaction_ptr); 00289 } 00290 } 00291 } 00292 00293 static int get_passwd_cb(int8_t socket_id, uint8_t address[static 16], uint16_t port, uint8_t *pw_ptr, uint8_t *pw_len) 00294 { 00295 coap_service_t *this = service_find_by_socket(socket_id); 00296 if (this && this->security_start_cb) { 00297 return this->security_start_cb(this->service_id, address, port, pw_ptr, pw_len); 00298 } 00299 return -1; 00300 } 00301 00302 int8_t coap_service_initialize(int8_t interface_id, uint16_t listen_port, uint8_t service_options, 00303 coap_service_security_start_cb *start_ptr, coap_service_security_done_cb *coap_security_done_cb) 00304 { 00305 coap_service_t *this = ns_dyn_mem_alloc(sizeof(coap_service_t)); 00306 00307 if (!this) { 00308 return -1; 00309 } 00310 memset(this, 0, sizeof(coap_service_t)); 00311 tr_debug("service init interface %d, port %d, options %d", interface_id, listen_port, service_options); 00312 00313 int8_t id = 1;// get unique id 00314 while (service_find(id) && id < 127) { 00315 id++; 00316 } 00317 this->interface_id = interface_id; 00318 this->service_id = id; 00319 this->service_options = service_options; 00320 00321 this->security_start_cb = start_ptr; 00322 this->coap_security_done_cb = coap_security_done_cb; 00323 00324 if (tasklet_id == -1) { 00325 tr_debug("service tasklet init"); 00326 tasklet_id = eventOS_event_handler_create(&service_event_handler, ARM_LIB_TASKLET_INIT_EVENT); 00327 } 00328 00329 this->conn_handler = connection_handler_create(recv_cb, send_cb, get_passwd_cb, sec_done_cb); 00330 if(!this->conn_handler){ 00331 ns_dyn_mem_free(this); 00332 return -1; 00333 } 00334 00335 this->conn_handler->socket_interface_selection = 0; // zero is illegal interface ID 00336 if (this->service_options & COAP_SERVICE_OPTIONS_SELECT_SOCKET_IF) { 00337 this->conn_handler->socket_interface_selection = this->interface_id; 00338 } 00339 00340 this->conn_handler->registered_to_multicast = this->service_options & COAP_SERVICE_OPTIONS_MULTICAST_JOIN; 00341 00342 if (0 > coap_connection_handler_open_connection(this->conn_handler, listen_port, 00343 (this->service_options & COAP_SERVICE_OPTIONS_EPHEMERAL_PORT), 00344 (this->service_options & COAP_SERVICE_OPTIONS_SECURE), 00345 !(this->service_options & COAP_SERVICE_OPTIONS_VIRTUAL_SOCKET), 00346 (this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS))) { 00347 ns_dyn_mem_free(this->conn_handler); 00348 ns_dyn_mem_free(this); 00349 return -1; 00350 } 00351 00352 if (!coap_service_handle) { 00353 coap_service_handle = coap_message_handler_init(&own_alloc, &own_free, &coap_tx_function); 00354 } 00355 if (!coap_service_handle) { 00356 tr_error("coap service alloc failed"); 00357 //TODO proper handling 00358 } 00359 00360 ns_list_add_to_start(&instance_list, this); 00361 00362 return id; 00363 } 00364 00365 void coap_service_delete(int8_t service_id) 00366 { 00367 coap_service_t *this = service_find(service_id); 00368 if (!this) { 00369 return; 00370 } 00371 00372 if (this->conn_handler){ 00373 bool leave_multicast_group = false; 00374 if (coap_service_can_leave_multicast_group(this->conn_handler)) { 00375 // This is the last handler joined to multicast group 00376 leave_multicast_group = true; 00377 } 00378 connection_handler_destroy(this->conn_handler, leave_multicast_group); 00379 } 00380 00381 //TODO clear all transactions 00382 ns_list_foreach_safe(uri_registration_t, cur_ptr, &this->uri_list) { 00383 ns_dyn_mem_free(cur_ptr->uri_ptr); 00384 ns_list_remove(&this->uri_list, cur_ptr); 00385 ns_dyn_mem_free(cur_ptr); 00386 } 00387 00388 ns_list_remove(&instance_list, this); 00389 ns_dyn_mem_free(this); 00390 return; 00391 } 00392 00393 extern void coap_service_close_secure_connection(int8_t service_id, uint8_t destination_addr_ptr[static 16], uint16_t port) 00394 { 00395 coap_service_t *this = service_find(service_id); 00396 if (!this || !destination_addr_ptr) { 00397 return; 00398 } 00399 if (this->conn_handler){ 00400 connection_handler_close_secure_connection(this->conn_handler, destination_addr_ptr, port); 00401 } 00402 } 00403 00404 int16_t coap_service_virtual_socket_recv(int8_t service_id, uint8_t source_addr_ptr[static 16], uint16_t port, uint8_t *data_ptr, uint16_t data_len) 00405 { 00406 coap_service_t *this = service_find(service_id); 00407 tr_debug("Service %d, virtual socket received", service_id); 00408 if (!this) { 00409 return -1; 00410 } 00411 return coap_connection_handler_virtual_recv(this->conn_handler, source_addr_ptr, port, data_ptr, data_len); 00412 } 00413 00414 int16_t coap_service_virtual_socket_set_cb(int8_t service_id, coap_service_virtual_socket_send_cb *send_method_ptr) 00415 { 00416 coap_service_t *this = service_find(service_id); 00417 tr_debug("register virtual socket cb to service %d", service_id); 00418 if (!this) { 00419 return -1; 00420 } 00421 this->virtual_socket_send_cb = send_method_ptr; 00422 return 0; 00423 } 00424 00425 int8_t coap_service_register_uri(int8_t service_id, const char *uri, uint8_t allowed_method, coap_service_request_recv_cb *request_recv_cb) 00426 { 00427 coap_service_t *this = service_find(service_id); 00428 uri_registration_t *uri_reg_ptr; 00429 char *uri_ptr = NULL; 00430 uint16_t uri_len; 00431 tr_debug("Service %d, Uri registration uri: %s", service_id, uri); 00432 if (!this || !uri) { 00433 return -1; 00434 } 00435 uri_len = strlen(uri); 00436 00437 uri_reg_ptr = uri_registration_find(this, uri, uri_len); 00438 if (!uri_reg_ptr) { 00439 uri_reg_ptr = ns_dyn_mem_alloc(sizeof(uri_registration_t)); 00440 if( !uri_reg_ptr ){ 00441 tr_error("Uri registration failed, OOM"); 00442 return -2; 00443 } 00444 uri_reg_ptr->uri_ptr = NULL; 00445 } else { 00446 ns_dyn_mem_free(uri_reg_ptr->uri_ptr); 00447 ns_list_remove(&this->uri_list, uri_reg_ptr); 00448 } 00449 00450 uri_ptr = ns_dyn_mem_alloc(uri_len); 00451 if (!uri_ptr) { 00452 ns_dyn_mem_free(uri_reg_ptr); 00453 tr_error("Uri registration failed, OOM"); 00454 return -2; 00455 } 00456 00457 uri_reg_ptr->uri_ptr = memcpy(uri_ptr, uri, uri_len); 00458 uri_reg_ptr->uri_len = uri_len; 00459 uri_reg_ptr->request_recv_cb = request_recv_cb; 00460 uri_reg_ptr->allowed_method = allowed_method; 00461 ns_list_add_to_start(&this->uri_list, uri_reg_ptr); 00462 return 0; 00463 } 00464 00465 int8_t coap_service_unregister_uri(int8_t service_id, const char *uri) 00466 { 00467 coap_service_t *this = service_find(service_id); 00468 uri_registration_t *uri_reg_ptr; 00469 tr_debug("Service %d, Uri unregistration uri: %s", service_id, uri); 00470 if (!this || !uri) { 00471 return -1; 00472 } 00473 00474 uri_reg_ptr = uri_registration_find(this, uri, strlen(uri)); 00475 if (!uri_reg_ptr) { 00476 return -2; 00477 } 00478 00479 ns_dyn_mem_free(uri_reg_ptr->uri_ptr); 00480 ns_list_remove(&this->uri_list, uri_reg_ptr); 00481 ns_dyn_mem_free(uri_reg_ptr); 00482 00483 return 0; 00484 } 00485 00486 uint16_t coap_service_request_send(int8_t service_id, uint8_t options, const uint8_t destination_addr[static 16], uint16_t destination_port, sn_coap_msg_type_e msg_type, sn_coap_msg_code_e msg_code, const char *uri, 00487 sn_coap_content_format_e cont_type, const uint8_t *payload_ptr, uint16_t payload_len, coap_service_response_recv *request_response_cb){ 00488 //TODO: coap_service_response_recv is an ugly cast, this should be refactored away + sn_coap_hdr_s MUST NOT be exposed to users of coap-service! 00489 //Callback would be still needed, but where to store callback? 00490 return coap_message_handler_request_send(coap_service_handle, service_id, options, destination_addr, destination_port, msg_type, msg_code, uri, cont_type, payload_ptr, payload_len, request_response_cb); 00491 } 00492 00493 int8_t coap_service_response_send(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){ 00494 return coap_message_handler_response_send(coap_service_handle, service_id, options, request_ptr, message_code, content_type, payload_ptr, payload_len); 00495 } 00496 00497 int8_t coap_service_request_delete(int8_t service_id, uint16_t msg_id) 00498 { 00499 return coap_message_handler_request_delete(coap_service_handle, service_id, msg_id); 00500 } 00501 00502 int8_t coap_service_set_handshake_timeout(int8_t service_id, uint32_t min, uint32_t max) 00503 { 00504 coap_service_t *this = service_find(service_id); 00505 if(!this){ 00506 return -1; 00507 } 00508 00509 return coap_connection_handler_set_timeout(this->conn_handler, min, max); 00510 } 00511 00512 int8_t coap_service_set_duplicate_message_buffer(int8_t service_id, uint8_t size) 00513 { 00514 (void) service_id; 00515 00516 if (!coap_service_handle) { 00517 return -1; 00518 } 00519 00520 return sn_coap_protocol_set_duplicate_buffer_size(coap_service_handle->coap, size); 00521 } 00522 00523 uint32_t coap_service_get_internal_timer_ticks(void) 00524 { 00525 return coap_ticks; 00526 } 00527 00528 uint16_t coap_service_id_find_by_socket(int8_t socket_id) 00529 { 00530 coap_service_t *this = service_find_by_socket(socket_id); 00531 00532 return this ? this->service_id:0; 00533 }
Generated on Sun Jul 17 2022 08:25:21 by 1.7.2