joey shelton / LED_Demo

Dependencies:   MAX44000 PWM_Tone_Library nexpaq_mdk

Fork of LED_Demo by Maxim nexpaq

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-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 }