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 mbed-os by
coap_service_api.c
00001 /* 00002 * Copyright (c) 2015-2016 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 "sn_nsdl.h" 00014 #include "sn_coap_header.h" 00015 #include "coap_service_api.h" 00016 #include "coap_message_handler.h" 00017 #include "eventOS_event.h" 00018 #include "eventOS_scheduler.h" 00019 #include "eventOS_event_timer.h" 00020 #include "common_functions.h" 00021 #include "coap_connection_handler.h" 00022 #include "net_interface.h" 00023 #include "coap_service_api_internal.h" 00024 00025 static int16_t coap_service_coap_msg_process(int8_t socket_id, uint8_t source_addr_ptr[static 16], uint16_t port, uint8_t *data_ptr, uint16_t data_len); 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 00104 /** 00105 * Coap handling functions 00106 */ 00107 static void *own_alloc(uint16_t size) 00108 { 00109 if (size) { 00110 return ns_dyn_mem_temporary_alloc(size); 00111 } else { 00112 return 0; 00113 } 00114 } 00115 00116 static void own_free(void *ptr) 00117 { 00118 if (ptr) { 00119 ns_dyn_mem_free(ptr); 00120 } 00121 } 00122 00123 static uint8_t coap_tx_function(uint8_t *data_ptr, uint16_t data_len, sn_nsdl_addr_s *address_ptr, void *param) 00124 { 00125 coap_service_t *this; 00126 coap_transaction_t *transaction_ptr = coap_message_handler_transaction_valid(param); 00127 ns_address_t dest_addr; 00128 00129 if (!transaction_ptr || !data_ptr) { 00130 return -1; 00131 } 00132 00133 tr_debug("Service %d, CoAP TX Function", transaction_ptr->service_id); 00134 00135 this = service_find(transaction_ptr->service_id); 00136 if (!this) { 00137 return -1; 00138 } 00139 00140 memcpy(&(dest_addr.address), address_ptr->addr_ptr, 16); 00141 dest_addr.identifier = address_ptr->port; 00142 dest_addr.type = ADDRESS_IPV6; 00143 00144 if( -2 == coap_connection_handler_send_data(this->conn_handler, &dest_addr, data_ptr, data_len, (this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS) == COAP_SERVICE_OPTIONS_SECURE_BYPASS) ){ 00145 transaction_ptr->data_ptr = ns_dyn_mem_alloc(data_len); 00146 if (!transaction_ptr->data_ptr) { 00147 tr_debug("coap tx out of memory"); 00148 return 0; 00149 00150 } 00151 memcpy(transaction_ptr->data_ptr, data_ptr, data_len); 00152 transaction_ptr->data_len = data_len; 00153 } 00154 00155 return 0; 00156 } 00157 00158 static void service_event_handler(arm_event_s *event) 00159 { 00160 if (event->event_type == ARM_LIB_TASKLET_INIT_EVENT) { 00161 tr_debug("service tasklet initialised"); 00162 /*initialize coap service and listen socket*/ 00163 } 00164 if (event->event_type == ARM_LIB_SYSTEM_TIMER_EVENT && event->event_id == COAP_TICK_TIMER) { 00165 coap_message_handler_exec(coap_service_handle, coap_ticks++); 00166 if(coap_ticks && !coap_ticks % SECURE_SESSION_CLEAN_INTERVAL){ 00167 coap_connection_handler_exec(coap_ticks); 00168 } 00169 } 00170 eventOS_event_timer_request((uint8_t)COAP_TICK_TIMER, ARM_LIB_SYSTEM_TIMER_EVENT, tasklet_id, 1000); 00171 } 00172 00173 static int16_t coap_msg_process_callback(int8_t socket_id, sn_coap_hdr_s *coap_message, coap_transaction_t *transaction_ptr) 00174 { 00175 coap_service_t *this; 00176 if( !coap_message ){ 00177 return -1; 00178 } 00179 // Message is request find correct handle 00180 this = service_find_by_uri(socket_id, coap_message->uri_path_ptr, coap_message->uri_path_len); 00181 if (!this) { 00182 tr_warn("not registered uri %.*s", coap_message->uri_path_len, coap_message->uri_path_ptr); 00183 return -1; 00184 } 00185 00186 uri_registration_t *uri_reg_ptr = uri_registration_find(this, coap_message->uri_path_ptr, coap_message->uri_path_len); 00187 if (transaction_ptr && uri_reg_ptr && uri_reg_ptr->request_recv_cb) { 00188 tr_debug("Service %d, call request recv cb uri %.*s", this->service_id, coap_message->uri_path_len, coap_message->uri_path_ptr); 00189 00190 if ((this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS) == COAP_SERVICE_OPTIONS_SECURE_BYPASS ) {//TODO Add secure bypass option 00191 // Service has secure bypass active TODO this is not defined in interface 00192 // this check can be removed I think 00193 transaction_ptr->options = COAP_REQUEST_OPTIONS_SECURE_BYPASS; 00194 } 00195 transaction_ptr->service_id = this->service_id; 00196 return uri_reg_ptr->request_recv_cb(this->service_id, transaction_ptr->remote_address, transaction_ptr->remote_port, coap_message); 00197 } 00198 return -1; 00199 } 00200 00201 static int16_t coap_service_coap_msg_process(int8_t socket_id, uint8_t source_addr_ptr[static 16], uint16_t port, uint8_t *data_ptr, uint16_t data_len) 00202 { 00203 return coap_message_handler_coap_msg_process( coap_service_handle, socket_id, source_addr_ptr, port, data_ptr, data_len, &coap_msg_process_callback); 00204 } 00205 00206 static int recv_cb(int8_t socket_id, uint8_t address[static 16], uint16_t port, unsigned char *data, int len) 00207 { 00208 uint8_t *data_ptr = NULL; 00209 uint16_t data_len = 0; 00210 00211 data_ptr = own_alloc(len); 00212 00213 if (!data_ptr || len < 1) { 00214 return -1; 00215 } 00216 memcpy(data_ptr, data, len); 00217 data_len = len; 00218 tr_debug("service recv socket data len %d ", data_len); 00219 00220 //parse coap message what CoAP to use 00221 int ret = coap_service_coap_msg_process(socket_id, address, port, data_ptr, data_len); 00222 own_free(data_ptr); 00223 return ret; 00224 } 00225 00226 static int send_cb(int8_t socket_id, uint8_t address[static 16], uint16_t port, const unsigned char *data_ptr, int data_len) 00227 { 00228 coap_service_t *this = service_find_by_socket(socket_id); 00229 if (this && this->virtual_socket_send_cb) { 00230 tr_debug("send to virtual socket"); 00231 return this->virtual_socket_send_cb(this->service_id, address, port, data_ptr, data_len); 00232 } 00233 return -1; 00234 } 00235 00236 //static void sec_conn_closed_cb(int8_t socket_id) 00237 //{ 00238 // coap_service_t *this = service_find_by_socket(socket_id); 00239 00240 // tr_debug("Secure socket was closed by end device"); 00241 //} 00242 00243 static void sec_done_cb(int8_t socket_id, uint8_t address[static 16], uint16_t port, uint8_t keyblock[static 40]) 00244 { 00245 //TODO: this is not enough if shared socket. Inform all! 00246 coap_service_t *this = service_find_by_socket(socket_id); 00247 if (this && this->coap_security_done_cb) { // secure done callback 00248 this->coap_security_done_cb(this->service_id, address, keyblock); 00249 } 00250 00251 //TODO refactor this away. There should be no transaction_ptr(s) before done_cb has been called 00252 //TODO: send all unsend transactions if more than 1 00253 coap_transaction_t *transaction_ptr = coap_message_handler_find_transaction(address, port); 00254 if (transaction_ptr && transaction_ptr->data_ptr) { 00255 tr_debug("send delayed packet"); 00256 ns_address_t dest_addr; 00257 memcpy(dest_addr.address, address, 16); 00258 dest_addr.identifier = port; 00259 dest_addr.type = ADDRESS_IPV6; 00260 00261 coap_connection_handler_send_data(this->conn_handler, &dest_addr, transaction_ptr->data_ptr, transaction_ptr->data_len, (this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS) == COAP_SERVICE_OPTIONS_SECURE_BYPASS); 00262 ns_dyn_mem_free(transaction_ptr->data_ptr); 00263 transaction_ptr->data_ptr = NULL; 00264 transaction_ptr->data_len = 0; 00265 //TODO: who deletes transaction incase no response is required 00266 } 00267 } 00268 00269 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) 00270 { 00271 coap_service_t *this = service_find_by_socket(socket_id); 00272 if (this && this->security_start_cb) { 00273 return this->security_start_cb(this->service_id, address, port, pw_ptr, pw_len); 00274 } 00275 return -1; 00276 } 00277 00278 int8_t coap_service_initialize(int8_t interface_id, uint16_t listen_port, uint8_t service_options, 00279 coap_service_security_start_cb *start_ptr, coap_service_security_done_cb *coap_security_done_cb) 00280 { 00281 (void) interface_id; 00282 00283 coap_service_t *this = ns_dyn_mem_alloc(sizeof(coap_service_t)); 00284 if (!this) { 00285 return -1; 00286 } 00287 memset(this, 0, sizeof(coap_service_t)); 00288 tr_debug("service init interface %d, port %d, options %d", interface_id, listen_port, service_options); 00289 00290 int8_t id = 1;// get unique id 00291 while (service_find(id) && id < 127) { 00292 id++; 00293 } 00294 this->service_id = id; 00295 this->service_options = service_options; 00296 00297 this->security_start_cb = start_ptr; 00298 this->coap_security_done_cb = coap_security_done_cb; 00299 00300 if (tasklet_id == -1) { 00301 tr_debug("service tasklet init"); 00302 tasklet_id = eventOS_event_handler_create(&service_event_handler, ARM_LIB_TASKLET_INIT_EVENT); 00303 } 00304 00305 this->conn_handler = connection_handler_create(recv_cb, send_cb, get_passwd_cb, sec_done_cb); 00306 if(!this->conn_handler){ 00307 ns_dyn_mem_free(this); 00308 return -1; 00309 } 00310 00311 if (0 > coap_connection_handler_open_connection(this->conn_handler, listen_port, ((this->service_options & COAP_SERVICE_OPTIONS_EPHEMERAL_PORT) == COAP_SERVICE_OPTIONS_EPHEMERAL_PORT), 00312 ((this->service_options & COAP_SERVICE_OPTIONS_SECURE) == COAP_SERVICE_OPTIONS_SECURE), 00313 ((this->service_options & COAP_SERVICE_OPTIONS_VIRTUAL_SOCKET) != COAP_SERVICE_OPTIONS_VIRTUAL_SOCKET), 00314 ((this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS) == COAP_SERVICE_OPTIONS_SECURE_BYPASS))){ 00315 ns_dyn_mem_free(this->conn_handler); 00316 ns_dyn_mem_free(this); 00317 return -1; 00318 } 00319 00320 if (!coap_service_handle) { 00321 coap_service_handle = coap_message_handler_init(&own_alloc, &own_free, &coap_tx_function); 00322 } 00323 if (!coap_service_handle) { 00324 tr_error("coap service alloc failed"); 00325 //TODO proper handling 00326 } 00327 00328 ns_list_add_to_start(&instance_list, this); 00329 00330 return id; 00331 } 00332 00333 void coap_service_delete(int8_t service_id) 00334 { 00335 coap_service_t *this = service_find(service_id); 00336 if (!this) { 00337 return; 00338 } 00339 00340 if (this->conn_handler){ 00341 connection_handler_destroy(this->conn_handler); 00342 } 00343 00344 //TODO clear all transactions 00345 ns_list_foreach_safe(uri_registration_t, cur_ptr, &this->uri_list) { 00346 ns_dyn_mem_free(cur_ptr->uri_ptr); 00347 ns_list_remove(&this->uri_list, cur_ptr); 00348 ns_dyn_mem_free(cur_ptr); 00349 } 00350 00351 ns_list_remove(&instance_list, this); 00352 ns_dyn_mem_free(this); 00353 return; 00354 } 00355 00356 extern void coap_service_close_secure_connection(int8_t service_id, uint8_t destination_addr_ptr[static 16], uint16_t port) 00357 { 00358 coap_service_t *this = service_find(service_id); 00359 if (!this || !destination_addr_ptr) { 00360 return; 00361 } 00362 if (this->conn_handler){ 00363 connection_handler_close_secure_connection(this->conn_handler, destination_addr_ptr, port); 00364 } 00365 } 00366 00367 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) 00368 { 00369 coap_service_t *this = service_find(service_id); 00370 tr_debug("Service %d, virtual socket received", service_id); 00371 if (!this) { 00372 return -1; 00373 } 00374 return coap_connection_handler_virtual_recv(this->conn_handler, source_addr_ptr, port, data_ptr, data_len); 00375 } 00376 00377 int16_t coap_service_virtual_socket_set_cb(int8_t service_id, coap_service_virtual_socket_send_cb *send_method_ptr) 00378 { 00379 coap_service_t *this = service_find(service_id); 00380 tr_debug("register virtual socket cb"); 00381 if (!this) { 00382 return -1; 00383 } 00384 this->virtual_socket_send_cb = send_method_ptr; 00385 return 0; 00386 } 00387 00388 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) 00389 { 00390 coap_service_t *this = service_find(service_id); 00391 uri_registration_t *uri_reg_ptr; 00392 char *uri_ptr = NULL; 00393 uint16_t uri_len; 00394 tr_debug("Service %d, Uri registration uri: %s", service_id, uri); 00395 if (!this || !uri) { 00396 return -1; 00397 } 00398 uri_len = strlen(uri); 00399 00400 uri_reg_ptr = uri_registration_find(this, uri, uri_len); 00401 if (!uri_reg_ptr) { 00402 uri_reg_ptr = ns_dyn_mem_alloc(sizeof(uri_registration_t)); 00403 if( !uri_reg_ptr ){ 00404 tr_error("Uri registration failed, OOM"); 00405 return -2; 00406 } 00407 uri_reg_ptr->uri_ptr = NULL; 00408 } else { 00409 ns_dyn_mem_free(uri_reg_ptr->uri_ptr); 00410 ns_list_remove(&this->uri_list, uri_reg_ptr); 00411 } 00412 00413 uri_ptr = ns_dyn_mem_alloc(uri_len); 00414 if (!uri_ptr) { 00415 ns_dyn_mem_free(uri_reg_ptr); 00416 tr_error("Uri registration failed, OOM"); 00417 return -2; 00418 } 00419 00420 uri_reg_ptr->uri_ptr = memcpy(uri_ptr, uri, uri_len); 00421 uri_reg_ptr->uri_len = uri_len; 00422 uri_reg_ptr->request_recv_cb = request_recv_cb; 00423 uri_reg_ptr->allowed_method = allowed_method; 00424 ns_list_add_to_start(&this->uri_list, uri_reg_ptr); 00425 return 0; 00426 } 00427 00428 int8_t coap_service_unregister_uri(int8_t service_id, const char *uri) 00429 { 00430 coap_service_t *this = service_find(service_id); 00431 uri_registration_t *uri_reg_ptr; 00432 tr_debug("Service %d, Uri unregistration uri: %s", service_id, uri); 00433 if (!this || !uri) { 00434 return -1; 00435 } 00436 00437 uri_reg_ptr = uri_registration_find(this, uri, strlen(uri)); 00438 if (!uri_reg_ptr) { 00439 return -2; 00440 } 00441 00442 ns_dyn_mem_free(uri_reg_ptr->uri_ptr); 00443 ns_list_remove(&this->uri_list, uri_reg_ptr); 00444 ns_dyn_mem_free(uri_reg_ptr); 00445 00446 return 0; 00447 } 00448 00449 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, 00450 sn_coap_content_format_e cont_type, const uint8_t *payload_ptr, uint16_t payload_len, coap_service_response_recv *request_response_cb){ 00451 //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! 00452 //Callback would be still needed, but where to store callback? 00453 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); 00454 } 00455 00456 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){ 00457 return coap_message_handler_response_send(coap_service_handle, service_id, options, request_ptr, message_code, content_type, payload_ptr, payload_len); 00458 } 00459 00460 int8_t coap_service_set_handshake_timeout(int8_t service_id, uint32_t min, uint32_t max) 00461 { 00462 coap_service_t *this = service_find(service_id); 00463 if(!this){ 00464 return -1; 00465 } 00466 00467 return coap_connection_handler_set_timeout(this->conn_handler, min, max); 00468 } 00469 00470 uint32_t coap_service_get_internal_timer_ticks(void) 00471 { 00472 return coap_ticks; 00473 }
Generated on Tue Jul 12 2022 13:15:38 by
