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.
Dependencies: MAX44000 PWM_Tone_Library nexpaq_mdk
Fork of LED_Demo 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 12:28:28 by
