Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers coap_service_api.c Source File

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 }