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.
Dependents: mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510
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 #include "coap_message_handler.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 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 - mid: %d", transaction_ptr->service_id, common_read_16_bit(data_ptr + 2)); 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, transaction_ptr->local_address, 00145 data_ptr, data_len, (this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS) == COAP_SERVICE_OPTIONS_SECURE_BYPASS)) { 00146 transaction_ptr->data_ptr = ns_dyn_mem_alloc(data_len); 00147 if (!transaction_ptr->data_ptr) { 00148 tr_debug("coap tx out of memory"); 00149 return 0; 00150 00151 } 00152 memcpy(transaction_ptr->data_ptr, data_ptr, data_len); 00153 transaction_ptr->data_len = data_len; 00154 } else if (transaction_ptr->resp_cb == NULL ) { 00155 transaction_delete(transaction_ptr); 00156 } 00157 00158 return 0; 00159 } 00160 00161 static void service_event_handler(arm_event_s *event) 00162 { 00163 if (event->event_type == ARM_LIB_TASKLET_INIT_EVENT) { 00164 tr_debug("service tasklet initialised"); 00165 /*initialize coap service and listen socket*/ 00166 } 00167 if (event->event_type == ARM_LIB_SYSTEM_TIMER_EVENT && event->event_id == COAP_TICK_TIMER) { 00168 coap_message_handler_exec(coap_service_handle, coap_ticks++); 00169 if(coap_ticks && !coap_ticks % SECURE_SESSION_CLEAN_INTERVAL){ 00170 coap_connection_handler_exec(coap_ticks); 00171 } 00172 } 00173 eventOS_event_timer_request((uint8_t)COAP_TICK_TIMER, ARM_LIB_SYSTEM_TIMER_EVENT, tasklet_id, 1000); 00174 } 00175 00176 static int16_t coap_msg_process_callback(int8_t socket_id, sn_coap_hdr_s *coap_message, coap_transaction_t *transaction_ptr) 00177 { 00178 coap_service_t *this; 00179 if (!coap_message || !transaction_ptr) { 00180 return -1; 00181 } 00182 00183 // Message is request, find correct handle 00184 this = service_find_by_uri(socket_id, coap_message->uri_path_ptr, coap_message->uri_path_len); 00185 if (!this) { 00186 tr_debug("not registered uri %.*s", coap_message->uri_path_len, coap_message->uri_path_ptr); 00187 if (coap_message->msg_type == COAP_MSG_TYPE_CONFIRMABLE) { 00188 coap_message_handler_response_send(coap_service_handle, transaction_ptr->service_id, COAP_SERVICE_OPTIONS_NONE, coap_message, 00189 COAP_MSG_CODE_RESPONSE_NOT_FOUND, COAP_CT_NONE, NULL, 0); 00190 return 0; 00191 } 00192 return -1; 00193 } 00194 00195 uri_registration_t *uri_reg_ptr = uri_registration_find(this, coap_message->uri_path_ptr, coap_message->uri_path_len); 00196 if (uri_reg_ptr && uri_reg_ptr->request_recv_cb) { 00197 tr_debug("Service %d, call request recv cb uri %.*s", this->service_id, coap_message->uri_path_len, coap_message->uri_path_ptr); 00198 00199 if ((this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS) == COAP_SERVICE_OPTIONS_SECURE_BYPASS ) {//TODO Add secure bypass option 00200 // Service has secure bypass active TODO this is not defined in interface 00201 // this check can be removed I think 00202 transaction_ptr->options = COAP_REQUEST_OPTIONS_SECURE_BYPASS; 00203 } 00204 transaction_ptr->service_id = this->service_id; 00205 return uri_reg_ptr->request_recv_cb(this->service_id, transaction_ptr->remote_address, transaction_ptr->remote_port, coap_message); 00206 } 00207 return -1; 00208 } 00209 00210 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) 00211 { 00212 uint8_t *data_ptr = NULL; 00213 uint16_t data_len = 0; 00214 00215 if (!data || !len) { 00216 return -1; 00217 } 00218 00219 data_ptr = own_alloc(len); 00220 00221 if (!data_ptr) { 00222 return -1; 00223 } 00224 memcpy(data_ptr, data, len); 00225 data_len = len; 00226 tr_debug("service recv socket data len %d ", data_len); 00227 00228 //parse coap message what CoAP to use 00229 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); 00230 own_free(data_ptr); 00231 return ret; 00232 } 00233 00234 static int send_cb(int8_t socket_id, const uint8_t address[static 16], uint16_t port, const void *data_ptr, int data_len) 00235 { 00236 coap_service_t *this = service_find_by_socket(socket_id); 00237 if (this && this->virtual_socket_send_cb) { 00238 tr_debug("send to virtual socket"); 00239 return this->virtual_socket_send_cb(this->service_id, (uint8_t*)address, port, data_ptr, data_len); 00240 } 00241 return -1; 00242 } 00243 00244 static void sec_done_cb(int8_t socket_id, uint8_t address[static 16], uint16_t port, uint8_t keyblock[static 40]) 00245 { 00246 //TODO: this is not enough if shared socket. Inform all! 00247 coap_service_t *this = service_find_by_socket(socket_id); 00248 if (this && this->coap_security_done_cb) { // secure done callback 00249 this->coap_security_done_cb(this->service_id, address, keyblock); 00250 } 00251 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->local_address, 00262 transaction_ptr->data_ptr, transaction_ptr->data_len, (this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS) == COAP_SERVICE_OPTIONS_SECURE_BYPASS); 00263 ns_dyn_mem_free(transaction_ptr->data_ptr); 00264 transaction_ptr->data_ptr = NULL; 00265 transaction_ptr->data_len = 0; 00266 if (transaction_ptr->resp_cb == NULL) { 00267 transaction_delete(transaction_ptr); 00268 } 00269 } 00270 } 00271 00272 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) 00273 { 00274 coap_service_t *this = service_find_by_socket(socket_id); 00275 if (this && this->security_start_cb) { 00276 return this->security_start_cb(this->service_id, address, port, pw_ptr, pw_len); 00277 } 00278 return -1; 00279 } 00280 00281 int8_t coap_service_initialize(int8_t interface_id, uint16_t listen_port, uint8_t service_options, 00282 coap_service_security_start_cb *start_ptr, coap_service_security_done_cb *coap_security_done_cb) 00283 { 00284 (void) interface_id; 00285 00286 coap_service_t *this = ns_dyn_mem_alloc(sizeof(coap_service_t)); 00287 if (!this) { 00288 return -1; 00289 } 00290 memset(this, 0, sizeof(coap_service_t)); 00291 tr_debug("service init interface %d, port %d, options %d", interface_id, listen_port, service_options); 00292 00293 int8_t id = 1;// get unique id 00294 while (service_find(id) && id < 127) { 00295 id++; 00296 } 00297 this->service_id = id; 00298 this->service_options = service_options; 00299 00300 this->security_start_cb = start_ptr; 00301 this->coap_security_done_cb = coap_security_done_cb; 00302 00303 if (tasklet_id == -1) { 00304 tr_debug("service tasklet init"); 00305 tasklet_id = eventOS_event_handler_create(&service_event_handler, ARM_LIB_TASKLET_INIT_EVENT); 00306 } 00307 00308 this->conn_handler = connection_handler_create(recv_cb, send_cb, get_passwd_cb, sec_done_cb); 00309 if(!this->conn_handler){ 00310 ns_dyn_mem_free(this); 00311 return -1; 00312 } 00313 00314 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), 00315 ((this->service_options & COAP_SERVICE_OPTIONS_SECURE) == COAP_SERVICE_OPTIONS_SECURE), 00316 ((this->service_options & COAP_SERVICE_OPTIONS_VIRTUAL_SOCKET) != COAP_SERVICE_OPTIONS_VIRTUAL_SOCKET), 00317 ((this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS) == COAP_SERVICE_OPTIONS_SECURE_BYPASS))){ 00318 ns_dyn_mem_free(this->conn_handler); 00319 ns_dyn_mem_free(this); 00320 return -1; 00321 } 00322 00323 if (!coap_service_handle) { 00324 coap_service_handle = coap_message_handler_init(&own_alloc, &own_free, &coap_tx_function); 00325 } 00326 if (!coap_service_handle) { 00327 tr_error("coap service alloc failed"); 00328 //TODO proper handling 00329 } 00330 00331 ns_list_add_to_start(&instance_list, this); 00332 00333 return id; 00334 } 00335 00336 void coap_service_delete(int8_t service_id) 00337 { 00338 coap_service_t *this = service_find(service_id); 00339 if (!this) { 00340 return; 00341 } 00342 00343 if (this->conn_handler){ 00344 connection_handler_destroy(this->conn_handler); 00345 } 00346 00347 //TODO clear all transactions 00348 ns_list_foreach_safe(uri_registration_t, cur_ptr, &this->uri_list) { 00349 ns_dyn_mem_free(cur_ptr->uri_ptr); 00350 ns_list_remove(&this->uri_list, cur_ptr); 00351 ns_dyn_mem_free(cur_ptr); 00352 } 00353 00354 ns_list_remove(&instance_list, this); 00355 ns_dyn_mem_free(this); 00356 return; 00357 } 00358 00359 extern void coap_service_close_secure_connection(int8_t service_id, uint8_t destination_addr_ptr[static 16], uint16_t port) 00360 { 00361 coap_service_t *this = service_find(service_id); 00362 if (!this || !destination_addr_ptr) { 00363 return; 00364 } 00365 if (this->conn_handler){ 00366 connection_handler_close_secure_connection(this->conn_handler, destination_addr_ptr, port); 00367 } 00368 } 00369 00370 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) 00371 { 00372 coap_service_t *this = service_find(service_id); 00373 tr_debug("Service %d, virtual socket received", service_id); 00374 if (!this) { 00375 return -1; 00376 } 00377 return coap_connection_handler_virtual_recv(this->conn_handler, source_addr_ptr, port, data_ptr, data_len); 00378 } 00379 00380 int16_t coap_service_virtual_socket_set_cb(int8_t service_id, coap_service_virtual_socket_send_cb *send_method_ptr) 00381 { 00382 coap_service_t *this = service_find(service_id); 00383 tr_debug("register virtual socket cb"); 00384 if (!this) { 00385 return -1; 00386 } 00387 this->virtual_socket_send_cb = send_method_ptr; 00388 return 0; 00389 } 00390 00391 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) 00392 { 00393 coap_service_t *this = service_find(service_id); 00394 uri_registration_t *uri_reg_ptr; 00395 char *uri_ptr = NULL; 00396 uint16_t uri_len; 00397 tr_debug("Service %d, Uri registration uri: %s", service_id, uri); 00398 if (!this || !uri) { 00399 return -1; 00400 } 00401 uri_len = strlen(uri); 00402 00403 uri_reg_ptr = uri_registration_find(this, uri, uri_len); 00404 if (!uri_reg_ptr) { 00405 uri_reg_ptr = ns_dyn_mem_alloc(sizeof(uri_registration_t)); 00406 if( !uri_reg_ptr ){ 00407 tr_error("Uri registration failed, OOM"); 00408 return -2; 00409 } 00410 uri_reg_ptr->uri_ptr = NULL; 00411 } else { 00412 ns_dyn_mem_free(uri_reg_ptr->uri_ptr); 00413 ns_list_remove(&this->uri_list, uri_reg_ptr); 00414 } 00415 00416 uri_ptr = ns_dyn_mem_alloc(uri_len); 00417 if (!uri_ptr) { 00418 ns_dyn_mem_free(uri_reg_ptr); 00419 tr_error("Uri registration failed, OOM"); 00420 return -2; 00421 } 00422 00423 uri_reg_ptr->uri_ptr = memcpy(uri_ptr, uri, uri_len); 00424 uri_reg_ptr->uri_len = uri_len; 00425 uri_reg_ptr->request_recv_cb = request_recv_cb; 00426 uri_reg_ptr->allowed_method = allowed_method; 00427 ns_list_add_to_start(&this->uri_list, uri_reg_ptr); 00428 return 0; 00429 } 00430 00431 int8_t coap_service_unregister_uri(int8_t service_id, const char *uri) 00432 { 00433 coap_service_t *this = service_find(service_id); 00434 uri_registration_t *uri_reg_ptr; 00435 tr_debug("Service %d, Uri unregistration uri: %s", service_id, uri); 00436 if (!this || !uri) { 00437 return -1; 00438 } 00439 00440 uri_reg_ptr = uri_registration_find(this, uri, strlen(uri)); 00441 if (!uri_reg_ptr) { 00442 return -2; 00443 } 00444 00445 ns_dyn_mem_free(uri_reg_ptr->uri_ptr); 00446 ns_list_remove(&this->uri_list, uri_reg_ptr); 00447 ns_dyn_mem_free(uri_reg_ptr); 00448 00449 return 0; 00450 } 00451 00452 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, 00453 sn_coap_content_format_e cont_type, const uint8_t *payload_ptr, uint16_t payload_len, coap_service_response_recv *request_response_cb){ 00454 //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! 00455 //Callback would be still needed, but where to store callback? 00456 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); 00457 } 00458 00459 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){ 00460 return coap_message_handler_response_send(coap_service_handle, service_id, options, request_ptr, message_code, content_type, payload_ptr, payload_len); 00461 } 00462 00463 int8_t coap_service_set_handshake_timeout(int8_t service_id, uint32_t min, uint32_t max) 00464 { 00465 coap_service_t *this = service_find(service_id); 00466 if(!this){ 00467 return -1; 00468 } 00469 00470 return coap_connection_handler_set_timeout(this->conn_handler, min, max); 00471 } 00472 00473 uint32_t coap_service_get_internal_timer_ticks(void) 00474 { 00475 return coap_ticks; 00476 } 00477 00478 uint16_t coap_service_id_find_by_socket(int8_t socket_id) 00479 { 00480 coap_service_t *this = service_find_by_socket(socket_id); 00481 00482 return this ? this->service_id:0; 00483 }
Generated on Tue Jul 12 2022 11:02:35 by
