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_connection_handler.c Source File

coap_connection_handler.c

00001 /*
00002  * Copyright (c) 2015-2016 ARM Limited. All Rights Reserved.
00003  */
00004 
00005 #include <string.h>
00006 #include "coap_connection_handler.h"
00007 #include "coap_security_handler.h"
00008 #include "ns_list.h"
00009 #include "ns_trace.h"
00010 #include "nsdynmemLIB.h"
00011 #include "socket_api.h"
00012 #include "net_interface.h"
00013 #include "eventOS_event_timer.h"
00014 #include "coap_service_api_internal.h"
00015 
00016 #define TRACE_GROUP "ThCH"
00017 
00018 typedef enum session_state_e {
00019     SECURE_SESSION_HANDSHAKE_ONGOING = 0,
00020     SECURE_SESSION_OK,
00021     SECURE_SESSION_CLOSED
00022 }session_state_t;
00023 
00024 typedef struct internal_socket_s {
00025     coap_conn_handler_t *parent;
00026 
00027     uint32_t timeout_min;
00028     uint32_t timeout_max;
00029 
00030     uint16_t listen_port;
00031     int8_t listen_socket;
00032 
00033     ns_address_t dest_addr;
00034     size_t data_len;
00035     uint8_t *data;
00036 
00037     bool real_socket;
00038     uint8_t usage_counter;
00039     bool is_secure;
00040 
00041     bool bypass_link_sec;
00042 
00043     ns_list_link_t link;
00044 } internal_socket_t;
00045 
00046 static NS_LIST_DEFINE(socket_list, internal_socket_t, link);
00047 
00048 static void timer_cb(void* param);
00049 
00050 #define TIMER_STATE_CANCELLED -1 /* cancelled */
00051 #define TIMER_STATE_NO_EXPIRY 0 /* none of the delays is expired */
00052 #define TIMER_STATE_INT_EXPIRY 1 /* the intermediate delay only is expired */
00053 #define TIMER_STATE_FIN_EXPIRY 2 /* the final delay is expired */
00054 
00055 typedef struct secure_timer_s {
00056     uint8_t id;
00057     timeout_t *timer;
00058     int8_t state;
00059     uint32_t fin_ms;
00060     uint32_t int_ms;
00061 } secure_timer_t;
00062 
00063 typedef struct secure_session {
00064     coap_security_t *sec_handler; //owned
00065     internal_socket_t *parent; //not owned
00066 
00067     secure_timer_t timer;
00068 
00069     session_state_t session_state;
00070     uint32_t last_contact_time;
00071     ns_list_link_t link;
00072 } secure_session_t;
00073 
00074 static NS_LIST_DEFINE(secure_session_list, secure_session_t, link);
00075 static int send_to_socket(int8_t socket_id, uint8_t *address_ptr, uint16_t port, const unsigned char *buf, size_t len);
00076 static int receive_from_socket(int8_t socket_id, unsigned char *buf, size_t len);
00077 static void start_timer(int8_t timer_id, uint32_t int_ms, uint32_t fin_ms);
00078 static int timer_status(int8_t timer_id);
00079 
00080 static secure_session_t *secure_session_find_by_timer_id(int8_t timer_id)
00081 {
00082     secure_session_t *this = NULL;
00083     ns_list_foreach(secure_session_t, cur_ptr, &secure_session_list) {
00084         if (cur_ptr->timer.id == timer_id) {
00085             this = cur_ptr;
00086             break;
00087         }
00088     }
00089     return this;
00090 }
00091 
00092 static void secure_session_delete(secure_session_t *this)
00093 {
00094     if (this) {
00095         ns_list_remove(&secure_session_list, this);
00096         if( this->sec_handler ){
00097             coap_security_destroy(this->sec_handler);
00098             this->sec_handler = NULL;
00099         }
00100         if(this->timer.timer){
00101             eventOS_timeout_cancel(this->timer.timer);
00102         }
00103         ns_dyn_mem_free(this);
00104         this = NULL;
00105     }
00106 
00107     return;
00108 }
00109 
00110 static secure_session_t *secure_session_create(internal_socket_t *parent, uint8_t *address_ptr, uint16_t port)
00111 {
00112     if(!address_ptr){
00113         return NULL;
00114     }
00115 
00116     if(MAX_SECURE_SESSION_COUNT <= ns_list_count(&secure_session_list)){
00117         // Seek & destroy oldest session where close notify have been sent
00118         secure_session_t *to_be_removed = NULL;
00119         ns_list_foreach(secure_session_t, cur_ptr, &secure_session_list) {
00120             if(cur_ptr->session_state == SECURE_SESSION_CLOSED){
00121                 if(!to_be_removed || cur_ptr->last_contact_time < to_be_removed->last_contact_time){
00122                     to_be_removed = cur_ptr;
00123                 }
00124             }
00125         }
00126         if(!to_be_removed){
00127             return NULL;
00128         }
00129 
00130         secure_session_delete(to_be_removed);
00131     }
00132 
00133     secure_session_t *this = ns_dyn_mem_alloc(sizeof(secure_session_t));
00134     if (!this) {
00135         return NULL;
00136     }
00137     memset(this, 0, sizeof(secure_session_t));
00138 
00139     uint8_t timer_id = 1;
00140 
00141     while(secure_session_find_by_timer_id(timer_id)){
00142         if(timer_id == 0xff){
00143             ns_dyn_mem_free(this);
00144             return NULL;
00145         }
00146         timer_id++;
00147     }
00148     this->timer.id = timer_id;
00149 
00150     this->sec_handler = coap_security_create(parent->listen_socket, this->timer.id, address_ptr, port, ECJPAKE,
00151                                                &send_to_socket, &receive_from_socket, &start_timer, &timer_status);
00152     if( !this->sec_handler ){
00153         ns_dyn_mem_free(this);
00154         return NULL;
00155     }
00156     this->parent = parent;
00157 
00158     this->session_state = SECURE_SESSION_HANDSHAKE_ONGOING;
00159     ns_list_add_to_start(&secure_session_list, this);
00160 
00161     return this;
00162 }
00163 
00164 
00165 static void clear_secure_sessions(internal_socket_t *this){
00166     if( this ){
00167         ns_list_foreach_safe(secure_session_t, cur_ptr, &secure_session_list) {
00168             if( cur_ptr->parent == this ){
00169                 coap_security_send_close_alert( cur_ptr->sec_handler );
00170                 secure_session_delete(cur_ptr);
00171             }
00172         }
00173     }
00174 }
00175 
00176 static secure_session_t *secure_session_find(internal_socket_t *parent, uint8_t *address_ptr, uint16_t port)
00177 {
00178     secure_session_t *this = NULL;
00179     ns_list_foreach(secure_session_t, cur_ptr, &secure_session_list) {
00180         if( cur_ptr->sec_handler ){
00181             if (cur_ptr->parent == parent && cur_ptr->sec_handler->_remote_port == port &&
00182                 memcmp(cur_ptr->sec_handler->_remote_address, address_ptr, 16) == 0) {
00183                 this = cur_ptr;
00184     //            hack_save_remote_address(address_ptr, port);
00185                 break;
00186             }
00187         }
00188     }
00189     return this;
00190 }
00191 
00192 
00193 
00194 static void recv_sckt_msg(void *cb_res);
00195 static void secure_recv_sckt_msg(void *cb_res);
00196 
00197 static internal_socket_t *int_socket_create(uint16_t listen_port, bool use_ephemeral_port, bool is_secure, bool real_socket, bool bypassSec)
00198 {
00199     internal_socket_t *this = ns_dyn_mem_alloc(sizeof(internal_socket_t));
00200     if (!this) {
00201         return NULL;
00202     }
00203     memset(this, 0, sizeof(internal_socket_t));
00204 
00205     this->data_len = 0;
00206     this->data = NULL;
00207 
00208     this->is_secure = is_secure;
00209     this->usage_counter = 1;
00210 
00211     this->listen_port = listen_port;
00212     this->real_socket = real_socket;
00213     this->bypass_link_sec = bypassSec;
00214     this->listen_socket = -1;
00215     if( real_socket ){
00216         if( use_ephemeral_port ){ //socket_api creates ephemeral port if the one provided is 0
00217             listen_port = 0;
00218         }
00219         if( !is_secure ){
00220             this->listen_socket = socket_open(SOCKET_UDP, listen_port, recv_sckt_msg);
00221         }else{
00222             this->listen_socket = socket_open(SOCKET_UDP, listen_port, secure_recv_sckt_msg);
00223         }
00224         // Socket create failed
00225         if(this->listen_socket < 0){
00226             ns_dyn_mem_free(this);
00227             return NULL;
00228         }
00229         // XXX API for this? May want to get clever to do recommended first query = 1 hop, retries = whole PAN
00230         socket_setsockopt(this->listen_socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_MULTICAST_HOPS, &(const int16_t) {
00231             16
00232         }, sizeof(int16_t));
00233     }else{
00234         this->listen_socket = -1;
00235     }
00236 
00237     ns_list_add_to_start(&socket_list, this);
00238     return this;
00239 }
00240 
00241 static void int_socket_delete(internal_socket_t *this)
00242 {
00243     if (this) {
00244         this->usage_counter--;
00245         if(this->usage_counter == 0){
00246             clear_secure_sessions(this);
00247             socket_free(this->listen_socket);
00248             ns_list_remove(&socket_list, this);
00249             if( this->data ){
00250                 ns_dyn_mem_free(this->data);
00251                 this->data = NULL;
00252             }
00253             if(this->parent){
00254                 ns_dyn_mem_free(this->parent);
00255             }
00256             ns_dyn_mem_free(this);
00257         }
00258     }
00259 }
00260 
00261 static internal_socket_t *int_socket_find_by_socket_id(int8_t id)
00262 {
00263     internal_socket_t *this = NULL;
00264     ns_list_foreach(internal_socket_t, cur_ptr, &socket_list) {
00265         if( cur_ptr->listen_socket == id ) {
00266             this = cur_ptr;
00267             break;
00268         }
00269     }
00270     return this;
00271 }
00272 
00273 static internal_socket_t *int_socket_find(uint16_t port, bool is_secure, bool is_real_socket, bool bypassSec)
00274 {
00275     (void) bypassSec;
00276 
00277     internal_socket_t *this = NULL;
00278     ns_list_foreach(internal_socket_t, cur_ptr, &socket_list) {
00279         if( cur_ptr->listen_port == port && cur_ptr->real_socket == is_real_socket &&
00280             is_secure == cur_ptr->is_secure /*&& bypass_link_sec == bypassSec*/) {
00281             this = cur_ptr;
00282             break;
00283         }
00284     }
00285     return this;
00286 }
00287 
00288 static int send_to_socket(int8_t socket_id, uint8_t *address_ptr, uint16_t port, const unsigned char *buf, size_t len)
00289 {
00290     internal_socket_t *sock = int_socket_find_by_socket_id(socket_id);
00291     if(!sock){
00292         return -1;
00293     }
00294     if(!sock->real_socket){
00295         //In this case all clients will have socket_id -1 and socket will not have a real address
00296         //so sock->dest_addr cannot be used here
00297         int ret = sock->parent->_send_cb(sock->listen_socket, address_ptr, port, buf, len);
00298         if( ret < 0 )
00299             return ret;
00300         return len;
00301     }
00302 
00303     int opt_name = SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT;
00304     int8_t securityLinkLayer = 1;
00305     if( sock->bypass_link_sec ){
00306         securityLinkLayer = 0;
00307     }
00308     socket_setsockopt(sock->listen_socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_ADDR_PREFERENCES, &opt_name, sizeof(int));
00309     socket_setsockopt(sock->listen_socket, SOCKET_IPPROTO_IPV6, SOCKET_LINK_LAYER_SECURITY, &securityLinkLayer, sizeof(int8_t));
00310     //For some reason socket_sendto returns 0 in success, while other socket impls return number of bytes sent!!!
00311     //TODO: check if address_ptr is valid and use that instead if it is
00312     int ret = socket_sendto(sock->listen_socket, &sock->dest_addr, (unsigned char*)buf, len);
00313     if( ret < 0 )
00314         return ret;
00315     return len;
00316 }
00317 
00318 static int receive_from_socket(int8_t socket_id, unsigned char *buf, size_t len)
00319 {
00320     (void)len;
00321     internal_socket_t *sock = int_socket_find_by_socket_id(socket_id);
00322     if( sock->data && sock->data_len > 0 ){
00323         memcpy( buf, sock->data, sock->data_len );
00324         int l = sock->data_len;
00325         ns_dyn_mem_free(sock->data);
00326         sock->data = NULL;
00327         sock->data_len = 0;
00328         return l;
00329     }
00330     return MBEDTLS_ERR_SSL_WANT_READ;
00331 }
00332 
00333 /**
00334  * Callback timer. Maybe called in interrupt context
00335  * so keep it simple.
00336  * TODO - might be better to use an event timer in conjunction with
00337  * CoAP tasklet
00338  */
00339 static void timer_cb(void *param)
00340 {
00341     secure_session_t *sec = param;
00342     if( sec ){
00343         if(sec->timer.fin_ms > sec->timer.int_ms){
00344             /* Intermediate expiry */
00345             sec->timer.fin_ms -= sec->timer.int_ms;
00346             sec->timer.state = TIMER_STATE_INT_EXPIRY;
00347             int error = coap_security_handler_continue_connecting(sec->sec_handler);
00348             if(MBEDTLS_ERR_SSL_TIMEOUT == error) {
00349                 //TODO: How do we handle timeouts?
00350                 secure_session_delete(sec);
00351             }
00352             else{
00353                 sec->timer.timer = eventOS_timeout_ms(timer_cb, sec->timer.int_ms, (void*)sec);
00354             }
00355         }
00356         else{
00357             /* We have counted the number of cycles - finish */
00358             eventOS_timeout_cancel(sec->timer.timer);
00359             sec->timer.fin_ms = 0;
00360             sec->timer.int_ms = 0;
00361             sec->timer.timer = NULL;
00362             sec->timer.state = TIMER_STATE_FIN_EXPIRY;
00363             int error = coap_security_handler_continue_connecting(sec->sec_handler);
00364             if(MBEDTLS_ERR_SSL_TIMEOUT == error) {
00365                 //TODO: How do we handle timeouts?
00366                 secure_session_delete(sec);
00367             }
00368         }
00369     }
00370 }
00371 
00372 static void start_timer(int8_t timer_id, uint32_t int_ms, uint32_t fin_ms)
00373 {
00374     secure_session_t *sec = secure_session_find_by_timer_id(timer_id);
00375     if( sec ){
00376         if ((int_ms > 0) && (fin_ms > 0)) {
00377             sec->timer.int_ms = int_ms;
00378             sec->timer.fin_ms = fin_ms;
00379             sec->timer.state = TIMER_STATE_NO_EXPIRY;
00380             if(sec->timer.timer){
00381                 eventOS_timeout_cancel(sec->timer.timer);
00382             }
00383             sec->timer.timer = eventOS_timeout_ms(timer_cb, int_ms, sec);
00384         } else if (fin_ms == 0) {
00385             /* fin_ms == 0 means cancel the timer */
00386             sec->timer.state = TIMER_STATE_CANCELLED;
00387             eventOS_timeout_cancel(sec->timer.timer);
00388             sec->timer.fin_ms = 0;
00389             sec->timer.int_ms = 0;
00390             sec->timer.timer = NULL;
00391         }
00392     }
00393 }
00394 
00395 static int timer_status(int8_t timer_id)
00396 {
00397     secure_session_t *sec = secure_session_find_by_timer_id(timer_id);
00398     if( sec ){
00399         return (int)sec->timer.state;
00400     }
00401     return TIMER_STATE_CANCELLED;
00402 }
00403 
00404 static int read_data(socket_callback_t *sckt_data, internal_socket_t *sock, ns_address_t *src_address)
00405 {
00406     sock->data_len = 0;
00407     if (sckt_data->event_type == SOCKET_DATA && sckt_data->d_len > 0) {
00408         if( sock->data ){
00409             ns_dyn_mem_free(sock->data);
00410             sock->data = NULL;
00411         }
00412         sock->data = ns_dyn_mem_temporary_alloc(sckt_data->d_len);
00413         if( !sock->data ){
00414             sock->data = NULL;
00415             return -1;
00416         }
00417         sock->data_len = socket_read(sckt_data->socket_id, src_address, sock->data, sckt_data->d_len);
00418     }
00419     if( sock->data_len < 1){
00420         ns_dyn_mem_free(sock->data);
00421         sock->data = NULL;
00422         sock->data_len = 0;
00423         return -1;
00424     }
00425     return 0;
00426 }
00427 
00428 static void secure_recv_sckt_msg(void *cb_res)
00429 {
00430     socket_callback_t *sckt_data = cb_res;
00431     internal_socket_t *sock = int_socket_find_by_socket_id(sckt_data->socket_id);
00432     ns_address_t src_address;
00433 
00434     if( sock && read_data(sckt_data, sock, &src_address) == 0 ){
00435         secure_session_t *session = secure_session_find(sock, src_address.address, src_address.identifier);
00436 
00437         // Create session
00438         if( !session ){
00439             memcpy( sock->dest_addr.address, src_address.address, 16 );
00440             sock->dest_addr.identifier = src_address.identifier;
00441             sock->dest_addr.type = src_address.type;
00442             session = secure_session_create(sock, src_address.address, src_address.identifier);
00443         }
00444         if( !session ){
00445             tr_err("secure_recv_sckt_msg session creation failed - OOM");
00446             return;
00447         }
00448         session->last_contact_time = coap_service_get_internal_timer_ticks();
00449         // Start handshake
00450         if( !session->sec_handler->_is_started ){
00451             uint8_t *pw = (uint8_t *)ns_dyn_mem_alloc(64);
00452             uint8_t pw_len;
00453             if( sock->parent->_get_password_cb && 0 == sock->parent->_get_password_cb(sock->listen_socket, src_address.address, src_address.identifier, pw, &pw_len)){
00454                 //TODO: get_password_cb should support certs and PSK also
00455                 coap_security_keys_t keys;
00456                 keys._priv = pw;
00457                 keys._priv_len = pw_len;
00458                 coap_security_handler_connect_non_blocking(session->sec_handler, true, DTLS, keys, sock->timeout_min, sock->timeout_max);
00459                 //TODO: error handling
00460             }
00461             ns_dyn_mem_free(pw);
00462         }else{
00463             //Continue handshake
00464             if(session->session_state == SECURE_SESSION_HANDSHAKE_ONGOING){
00465                 int ret = coap_security_handler_continue_connecting(session->sec_handler);
00466                 // Handshake done
00467                 if(ret == 0){
00468                     eventOS_timeout_cancel(session->timer.timer);
00469                     session->timer.timer = NULL;
00470                     session->session_state = SECURE_SESSION_OK;
00471                     if( sock->parent->_security_done_cb ){
00472                         sock->parent->_security_done_cb(sock->listen_socket, src_address.address,
00473                                                        src_address.identifier,
00474                                                        session->sec_handler->_keyblk.value);
00475                     }
00476                 }
00477                 else if (ret < 0){
00478                     // error handling
00479                     // TODO: here we also should clear CoAP retransmission buffer and inform that CoAP request sending is failed.
00480                     secure_session_delete(session);
00481                 }
00482             //Session valid
00483             }else{
00484                 unsigned char *data = ns_dyn_mem_temporary_alloc(sock->data_len);
00485                 int len = 0;
00486                 len = coap_security_handler_read(session->sec_handler, data, sock->data_len);
00487                 if( len < 0 ){
00488                     ns_dyn_mem_free(data);
00489                     secure_session_delete( session );
00490                 }else{
00491                     if( sock->parent->_recv_cb ){
00492                         sock->parent->_recv_cb(sock->listen_socket, src_address.address, src_address.identifier, data, len);
00493                     }
00494                     ns_dyn_mem_free(data);
00495                 }
00496             }
00497         }
00498     }
00499 }
00500 
00501 static void recv_sckt_msg(void *cb_res)
00502 {
00503     socket_callback_t *sckt_data = cb_res;
00504     internal_socket_t *sock = int_socket_find_by_socket_id(sckt_data->socket_id);
00505     ns_address_t src_address;
00506     if( sock && read_data(sckt_data, sock, &src_address) == 0 ){
00507         if(sock->parent && sock->parent->_recv_cb){
00508             sock->parent->_recv_cb(sock->listen_socket, src_address.address, src_address.identifier, sock->data, sock->data_len);
00509         }
00510         ns_dyn_mem_free(sock->data);
00511         sock->data = NULL;
00512     }
00513 }
00514 
00515 int coap_connection_handler_virtual_recv(coap_conn_handler_t *handler, uint8_t address[static 16], uint16_t port, uint8_t *data_ptr, uint16_t data_len)
00516 {
00517     if( !handler || !handler->socket ){
00518         return -1;
00519     }
00520     internal_socket_t *sock = handler->socket;
00521     sock->data_len = data_len;
00522     if( sock->data ){
00523         ns_dyn_mem_free(sock->data);
00524         sock->data = NULL;
00525     }
00526     sock->data = ns_dyn_mem_temporary_alloc(data_len);
00527     if( data_len > 0 && !sock->data ){
00528         return -1;
00529     }
00530     if( data_ptr ){
00531         memcpy(sock->data, data_ptr, data_len);
00532     }else{
00533         if( sock->data ){
00534             ns_dyn_mem_free(sock->data);
00535             sock->data = NULL;
00536         }
00537     }
00538 
00539     if( handler->socket->is_secure ){
00540         secure_session_t *session = secure_session_find(sock, address, port);
00541         if( !session ){
00542             session = secure_session_create(sock, address, port);
00543         }
00544         if( !session ){
00545             tr_err("coap_connection_handler_virtual_recv session creation failed - OOM");
00546             return -1;
00547         }
00548 
00549         session->last_contact_time = coap_service_get_internal_timer_ticks();
00550 
00551         if( !session->sec_handler->_is_started ){
00552             uint8_t *pw = (uint8_t *)ns_dyn_mem_alloc(64);
00553             uint8_t pw_len;
00554             if( sock->parent->_get_password_cb && 0 == sock->parent->_get_password_cb(sock->listen_socket, address, port, pw, &pw_len)){
00555                 //TODO: get_password_cb should support certs and PSK also
00556                 coap_security_keys_t keys;
00557                 keys._priv = pw;
00558                 keys._priv_len = pw_len;
00559                 coap_security_handler_connect_non_blocking(session->sec_handler, true, DTLS, keys, handler->socket->timeout_min, handler->socket->timeout_max);
00560                 //TODO: error handling
00561                 ns_dyn_mem_free(pw);
00562                 return 0;
00563             }else{
00564                 ns_dyn_mem_free(pw);
00565                 return -1;
00566             }
00567         }else{
00568             if(session->session_state == SECURE_SESSION_HANDSHAKE_ONGOING){
00569                 int ret = coap_security_handler_continue_connecting(session->sec_handler);
00570                 if(ret == 0){
00571                     session->session_state = SECURE_SESSION_OK;
00572                     if( handler->_security_done_cb ){
00573                         handler->_security_done_cb(sock->listen_socket,
00574                                                   address, port,
00575                                                   session->sec_handler->_keyblk.value);
00576                     }
00577                     return 0;
00578                 }
00579                 else if(ret < 0)
00580                 {
00581                     // error handling
00582                     // TODO: here we also should clear CoAP retransmission buffer and inform that CoAP request sending is failed.
00583                     secure_session_delete(session);
00584                 }
00585                 //TODO: error handling
00586             }else{
00587                 unsigned char *data = ns_dyn_mem_temporary_alloc(sock->data_len);
00588                 int len = 0;
00589                 len = coap_security_handler_read(session->sec_handler, data, sock->data_len);
00590                 if( len < 0 ){
00591                     ns_dyn_mem_free(data);
00592                     secure_session_delete( session );
00593                     return 0;
00594                 }else{
00595                     if( sock->parent->_recv_cb ){
00596                         sock->parent->_recv_cb(sock->listen_socket, address, port, data, len);
00597                     }
00598                     ns_dyn_mem_free(data);
00599                     data = NULL;
00600                 }
00601                 return 0;
00602             }
00603         }
00604     }else{
00605         if( sock->parent->_recv_cb ){
00606             sock->parent->_recv_cb(sock->listen_socket, address, port, sock->data, sock->data_len);
00607         }
00608         if( sock->data ){
00609             ns_dyn_mem_free(sock->data);
00610             sock->data = NULL;
00611         }
00612         return 0;
00613     }
00614     return -1;
00615 }
00616 
00617 coap_conn_handler_t *connection_handler_create(receive_from_socket_cb *recv_from_cb,
00618                                                  send_to_socket_cb *send_to_cb,
00619                                                  get_pw_cb *pw_cb,
00620                                                  security_done_cb *done_cb )
00621 {
00622     if( recv_from_cb == NULL ){
00623         return NULL;
00624     }
00625 
00626     coap_conn_handler_t *handler = ns_dyn_mem_alloc(sizeof(coap_conn_handler_t));
00627     if(!handler){
00628         return NULL;
00629     }
00630     memset(handler, 0, sizeof(coap_conn_handler_t));
00631     handler->socket = NULL;
00632     handler->_recv_cb = recv_from_cb;
00633     handler->_send_cb = send_to_cb;
00634 
00635     handler->_get_password_cb = pw_cb;
00636     handler->_security_done_cb = done_cb;
00637 
00638     return handler;
00639 }
00640 void connection_handler_destroy(coap_conn_handler_t *handler)
00641 {
00642     if(handler){
00643        int_socket_delete(handler->socket);
00644        ns_dyn_mem_free(handler);
00645     }
00646 }
00647 
00648 void connection_handler_close_secure_connection( coap_conn_handler_t *handler, uint8_t destination_addr_ptr[static 16], uint16_t port )
00649 {
00650     if(handler){
00651         if( handler->socket && handler->socket->is_secure){
00652             secure_session_t *session = secure_session_find( handler->socket, destination_addr_ptr, port);
00653             if( session ){
00654                 coap_security_send_close_alert( session->sec_handler );
00655                 session->session_state = SECURE_SESSION_CLOSED;
00656                 session->last_contact_time = coap_service_get_internal_timer_ticks();
00657             }
00658         }
00659     }
00660 }
00661 
00662 int coap_connection_handler_open_connection(coap_conn_handler_t *handler, uint16_t listen_port, bool use_ephemeral_port, bool is_secure, bool is_real_socket, bool bypassSec)
00663 {
00664     if( !handler ){
00665         return -1;
00666     }
00667     //virtual socket must have send callback
00668     if( !is_real_socket && !handler->_send_cb ){
00669         return -1;
00670     }
00671     if( handler->socket ){
00672         int_socket_delete(handler->socket);
00673     }
00674 
00675     internal_socket_t *current = !use_ephemeral_port?int_socket_find(listen_port, is_secure, is_real_socket, bypassSec):NULL;
00676     if(!current){
00677         handler->socket = int_socket_create(listen_port, use_ephemeral_port, is_secure, is_real_socket, bypassSec);
00678         if(!handler->socket){
00679             return -1;
00680         }
00681         handler->socket->parent = ns_dyn_mem_alloc(sizeof(coap_conn_handler_t));
00682         if(!handler->socket->parent){
00683             int_socket_delete(handler->socket);
00684             return -1;
00685         }
00686         *handler->socket->parent = *handler;
00687     }else{
00688         current->usage_counter++;
00689         handler->socket = current;
00690     }
00691     return 0;
00692 }
00693 
00694 int coap_connection_handler_send_data(coap_conn_handler_t *handler, ns_address_t *dest_addr, uint8_t *data_ptr, uint16_t data_len, bool bypass_link_sec)
00695 {
00696     if( !handler || !handler->socket || !dest_addr){
00697         return -1;
00698     }
00699     if(handler->socket->is_secure){
00700         handler->socket->bypass_link_sec = bypass_link_sec;
00701         memcpy(handler->socket->dest_addr.address, dest_addr->address, 16);
00702         handler->socket->dest_addr.identifier = dest_addr->identifier;
00703         handler->socket->dest_addr.type = dest_addr->type;
00704         secure_session_t *session = secure_session_find(handler->socket, dest_addr->address, dest_addr->identifier);
00705         if( !session ){
00706             session = secure_session_create(handler->socket, dest_addr->address, dest_addr->identifier);
00707             if( !session ){
00708                 return -1;
00709             }
00710             session->last_contact_time = coap_service_get_internal_timer_ticks();
00711             memcpy( handler->socket->dest_addr.address, dest_addr->address, 16 );
00712             handler->socket->dest_addr.identifier = dest_addr->identifier;
00713             handler->socket->dest_addr.type = dest_addr->type;
00714             uint8_t *pw = (uint8_t *)ns_dyn_mem_alloc(64);
00715             if(!pw){
00716                 //todo: free secure session?
00717                 return -1;
00718             }
00719             uint8_t pw_len;
00720             if( handler->_get_password_cb && 0 == handler->_get_password_cb(handler->socket->listen_socket, dest_addr->address, dest_addr->identifier, pw, &pw_len)){
00721                 //TODO: get_password_cb should support certs and PSK also
00722                 coap_security_keys_t keys;
00723                 keys._priv = pw;
00724                 keys._priv_len = pw_len;
00725                 coap_security_handler_connect_non_blocking(session->sec_handler, false, DTLS, keys, handler->socket->timeout_min, handler->socket->timeout_max);
00726                 ns_dyn_mem_free(pw);
00727                 return -2;
00728             }else{
00729                 //free secure session?
00730                 ns_dyn_mem_free(pw);
00731                 return -1;
00732             }
00733         }else if( session->session_state == SECURE_SESSION_OK ){
00734             if( coap_security_handler_send_message(session->sec_handler, data_ptr, data_len ) > 0 ){
00735                 session->last_contact_time = coap_service_get_internal_timer_ticks();
00736                 return 0;
00737             }
00738         }
00739         return -1;
00740     }else{
00741         if( !handler->socket->real_socket && handler->_send_cb){
00742             return handler->_send_cb((int8_t)handler->socket->listen_socket, dest_addr->address, dest_addr->identifier, data_ptr, data_len);
00743         }
00744         int opt_name = SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT;
00745         int8_t securityLinkLayer = 1;
00746         if( bypass_link_sec ){
00747             securityLinkLayer = 0;
00748         }
00749         socket_setsockopt(handler->socket->listen_socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_ADDR_PREFERENCES, &opt_name, sizeof(int));
00750         socket_setsockopt(handler->socket->listen_socket, SOCKET_IPPROTO_IPV6, SOCKET_LINK_LAYER_SECURITY, &securityLinkLayer, sizeof(int8_t));
00751         return socket_sendto(handler->socket->listen_socket, dest_addr, data_ptr, data_len);
00752     }
00753 }
00754 
00755 bool coap_connection_handler_socket_belongs_to(coap_conn_handler_t *handler, int8_t socket_id)
00756 {
00757     if( !handler || !handler->socket){
00758         return false;
00759     }
00760 
00761     if( handler->socket->listen_socket == socket_id){
00762         return true;
00763     }
00764     return false;
00765 }
00766 
00767 int8_t coap_connection_handler_set_timeout(coap_conn_handler_t *handler, uint32_t min, uint32_t max)
00768 {
00769     if(!handler || !handler->socket){
00770         return -1;
00771     }
00772     handler->socket->timeout_max = max;
00773     handler->socket->timeout_min = min;
00774 
00775     return 0;
00776 }
00777 
00778 /* No need to call every second - call rather like every minute (SECURE_SESSION_CLEAN_INTERVAL sets this) */
00779 void coap_connection_handler_exec(uint32_t time)
00780 {
00781     if(ns_list_count(&secure_session_list)){
00782         // Seek & destroy old sessions where close notify have been sent
00783         ns_list_foreach(secure_session_t, cur_ptr, &secure_session_list) {
00784             if(cur_ptr->session_state == SECURE_SESSION_CLOSED ||
00785                     cur_ptr->session_state == SECURE_SESSION_HANDSHAKE_ONGOING){
00786                 if((cur_ptr->last_contact_time +  CLOSED_SECURE_SESSION_TIMEOUT) <= time){
00787                     secure_session_delete(cur_ptr);
00788                 }
00789             }
00790             if(cur_ptr->session_state == SECURE_SESSION_OK){
00791                 if((cur_ptr->last_contact_time +  OPEN_SECURE_SESSION_TIMEOUT) <= time){
00792                     secure_session_delete(cur_ptr);
00793                 }
00794             }
00795         }
00796     }
00797 }