Simon Cooksey / mbed-os
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 
00230         socket_setsockopt(this->listen_socket, SOCKET_IPPROTO_IPV6, SOCKET_LINK_LAYER_SECURITY, &(const int8_t) {
00231             bypassSec ? 0 : 1
00232         }, sizeof(int8_t));
00233 
00234         // XXX API for this? May want to get clever to do recommended first query = 1 hop, retries = whole PAN
00235         socket_setsockopt(this->listen_socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_MULTICAST_HOPS, &(const int16_t) {
00236             16
00237         }, sizeof(int16_t));
00238     }else{
00239         this->listen_socket = -1;
00240     }
00241 
00242     ns_list_add_to_start(&socket_list, this);
00243     return this;
00244 }
00245 
00246 static void int_socket_delete(internal_socket_t *this)
00247 {
00248     if (this) {
00249         this->usage_counter--;
00250         if(this->usage_counter == 0){
00251             clear_secure_sessions(this);
00252             socket_free(this->listen_socket);
00253             ns_list_remove(&socket_list, this);
00254             if( this->data ){
00255                 ns_dyn_mem_free(this->data);
00256                 this->data = NULL;
00257             }
00258             if(this->parent){
00259                 ns_dyn_mem_free(this->parent);
00260             }
00261             ns_dyn_mem_free(this);
00262         }
00263     }
00264 }
00265 
00266 static internal_socket_t *int_socket_find_by_socket_id(int8_t id)
00267 {
00268     internal_socket_t *this = NULL;
00269     ns_list_foreach(internal_socket_t, cur_ptr, &socket_list) {
00270         if( cur_ptr->listen_socket == id ) {
00271             this = cur_ptr;
00272             break;
00273         }
00274     }
00275     return this;
00276 }
00277 
00278 static internal_socket_t *int_socket_find(uint16_t port, bool is_secure, bool is_real_socket, bool bypassSec)
00279 {
00280     (void) bypassSec;
00281 
00282     internal_socket_t *this = NULL;
00283     ns_list_foreach(internal_socket_t, cur_ptr, &socket_list) {
00284         if( cur_ptr->listen_port == port && cur_ptr->real_socket == is_real_socket &&
00285             is_secure == cur_ptr->is_secure /*&& bypass_link_sec == bypassSec*/) {
00286             this = cur_ptr;
00287             break;
00288         }
00289     }
00290     return this;
00291 }
00292 
00293 static int send_to_socket(int8_t socket_id, uint8_t *address_ptr, uint16_t port, const unsigned char *buf, size_t len)
00294 {
00295     internal_socket_t *sock = int_socket_find_by_socket_id(socket_id);
00296     if(!sock){
00297         return -1;
00298     }
00299     if(!sock->real_socket){
00300         //In this case all clients will have socket_id -1 and socket will not have a real address
00301         //so sock->dest_addr cannot be used here
00302         int ret = sock->parent->_send_cb(sock->listen_socket, address_ptr, port, buf, len);
00303         if( ret < 0 )
00304             return ret;
00305         return len;
00306     }
00307 
00308     int opt_name = SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT;
00309     int8_t securityLinkLayer = 1;
00310     if( sock->bypass_link_sec ){
00311         securityLinkLayer = 0;
00312     }
00313     socket_setsockopt(sock->listen_socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_ADDR_PREFERENCES, &opt_name, sizeof(int));
00314     socket_setsockopt(sock->listen_socket, SOCKET_IPPROTO_IPV6, SOCKET_LINK_LAYER_SECURITY, &securityLinkLayer, sizeof(int8_t));
00315     //For some reason socket_sendto returns 0 in success, while other socket impls return number of bytes sent!!!
00316     //TODO: check if address_ptr is valid and use that instead if it is
00317     int ret = socket_sendto(sock->listen_socket, &sock->dest_addr, (unsigned char*)buf, len);
00318     if( ret < 0 )
00319         return ret;
00320     return len;
00321 }
00322 
00323 static int receive_from_socket(int8_t socket_id, unsigned char *buf, size_t len)
00324 {
00325     (void)len;
00326     internal_socket_t *sock = int_socket_find_by_socket_id(socket_id);
00327     if( sock->data && sock->data_len > 0 ){
00328         memcpy( buf, sock->data, sock->data_len );
00329         int l = sock->data_len;
00330         ns_dyn_mem_free(sock->data);
00331         sock->data = NULL;
00332         sock->data_len = 0;
00333         return l;
00334     }
00335     return MBEDTLS_ERR_SSL_WANT_READ;
00336 }
00337 
00338 /**
00339  * Callback timer. Maybe called in interrupt context
00340  * so keep it simple.
00341  * TODO - might be better to use an event timer in conjunction with
00342  * CoAP tasklet
00343  */
00344 static void timer_cb(void *param)
00345 {
00346     secure_session_t *sec = param;
00347     if( sec ){
00348         if(sec->timer.fin_ms > sec->timer.int_ms){
00349             /* Intermediate expiry */
00350             sec->timer.fin_ms -= sec->timer.int_ms;
00351             sec->timer.state = TIMER_STATE_INT_EXPIRY;
00352             int error = coap_security_handler_continue_connecting(sec->sec_handler);
00353             if(MBEDTLS_ERR_SSL_TIMEOUT == error) {
00354                 //TODO: How do we handle timeouts?
00355                 secure_session_delete(sec);
00356             }
00357             else{
00358                 sec->timer.timer = eventOS_timeout_ms(timer_cb, sec->timer.int_ms, (void*)sec);
00359             }
00360         }
00361         else{
00362             /* We have counted the number of cycles - finish */
00363             eventOS_timeout_cancel(sec->timer.timer);
00364             sec->timer.fin_ms = 0;
00365             sec->timer.int_ms = 0;
00366             sec->timer.timer = NULL;
00367             sec->timer.state = TIMER_STATE_FIN_EXPIRY;
00368             int error = coap_security_handler_continue_connecting(sec->sec_handler);
00369             if(MBEDTLS_ERR_SSL_TIMEOUT == error) {
00370                 //TODO: How do we handle timeouts?
00371                 secure_session_delete(sec);
00372             }
00373         }
00374     }
00375 }
00376 
00377 static void start_timer(int8_t timer_id, uint32_t int_ms, uint32_t fin_ms)
00378 {
00379     secure_session_t *sec = secure_session_find_by_timer_id(timer_id);
00380     if( sec ){
00381         if ((int_ms > 0) && (fin_ms > 0)) {
00382             sec->timer.int_ms = int_ms;
00383             sec->timer.fin_ms = fin_ms;
00384             sec->timer.state = TIMER_STATE_NO_EXPIRY;
00385             if(sec->timer.timer){
00386                 eventOS_timeout_cancel(sec->timer.timer);
00387             }
00388             sec->timer.timer = eventOS_timeout_ms(timer_cb, int_ms, sec);
00389         } else if (fin_ms == 0) {
00390             /* fin_ms == 0 means cancel the timer */
00391             sec->timer.state = TIMER_STATE_CANCELLED;
00392             eventOS_timeout_cancel(sec->timer.timer);
00393             sec->timer.fin_ms = 0;
00394             sec->timer.int_ms = 0;
00395             sec->timer.timer = NULL;
00396         }
00397     }
00398 }
00399 
00400 static int timer_status(int8_t timer_id)
00401 {
00402     secure_session_t *sec = secure_session_find_by_timer_id(timer_id);
00403     if( sec ){
00404         return (int)sec->timer.state;
00405     }
00406     return TIMER_STATE_CANCELLED;
00407 }
00408 
00409 static int read_data(socket_callback_t *sckt_data, internal_socket_t *sock, ns_address_t *src_address)
00410 {
00411     sock->data_len = 0;
00412     if (sckt_data->event_type == SOCKET_DATA && sckt_data->d_len > 0) {
00413         if( sock->data ){
00414             ns_dyn_mem_free(sock->data);
00415             sock->data = NULL;
00416         }
00417         sock->data = ns_dyn_mem_temporary_alloc(sckt_data->d_len);
00418         if( !sock->data ){
00419             sock->data = NULL;
00420             return -1;
00421         }
00422         sock->data_len = socket_read(sckt_data->socket_id, src_address, sock->data, sckt_data->d_len);
00423     }
00424     if( sock->data_len < 1){
00425         ns_dyn_mem_free(sock->data);
00426         sock->data = NULL;
00427         sock->data_len = 0;
00428         return -1;
00429     }
00430     return 0;
00431 }
00432 
00433 static void secure_recv_sckt_msg(void *cb_res)
00434 {
00435     socket_callback_t *sckt_data = cb_res;
00436     internal_socket_t *sock = int_socket_find_by_socket_id(sckt_data->socket_id);
00437     ns_address_t src_address;
00438 
00439     if( sock && read_data(sckt_data, sock, &src_address) == 0 ){
00440         secure_session_t *session = secure_session_find(sock, src_address.address, src_address.identifier);
00441 
00442         // Create session
00443         if( !session ){
00444             memcpy( sock->dest_addr.address, src_address.address, 16 );
00445             sock->dest_addr.identifier = src_address.identifier;
00446             sock->dest_addr.type = src_address.type;
00447             session = secure_session_create(sock, src_address.address, src_address.identifier);
00448         }
00449         if( !session ){
00450             tr_err("secure_recv_sckt_msg session creation failed - OOM");
00451             return;
00452         }
00453         session->last_contact_time = coap_service_get_internal_timer_ticks();
00454         // Start handshake
00455         if( !session->sec_handler->_is_started ){
00456             uint8_t *pw = (uint8_t *)ns_dyn_mem_alloc(64);
00457             uint8_t pw_len;
00458             if( sock->parent->_get_password_cb && 0 == sock->parent->_get_password_cb(sock->listen_socket, src_address.address, src_address.identifier, pw, &pw_len)){
00459                 //TODO: get_password_cb should support certs and PSK also
00460                 coap_security_keys_t keys;
00461                 keys._priv = pw;
00462                 keys._priv_len = pw_len;
00463                 coap_security_handler_connect_non_blocking(session->sec_handler, true, DTLS, keys, sock->timeout_min, sock->timeout_max);
00464                 //TODO: error handling
00465             }
00466             ns_dyn_mem_free(pw);
00467         }else{
00468             //Continue handshake
00469             if(session->session_state == SECURE_SESSION_HANDSHAKE_ONGOING){
00470                 int ret = coap_security_handler_continue_connecting(session->sec_handler);
00471                 // Handshake done
00472                 if(ret == 0){
00473                     eventOS_timeout_cancel(session->timer.timer);
00474                     session->timer.timer = NULL;
00475                     session->session_state = SECURE_SESSION_OK;
00476                     if( sock->parent->_security_done_cb ){
00477                         sock->parent->_security_done_cb(sock->listen_socket, src_address.address,
00478                                                        src_address.identifier,
00479                                                        session->sec_handler->_keyblk.value);
00480                     }
00481                 }
00482                 else if (ret < 0){
00483                     // error handling
00484                     // TODO: here we also should clear CoAP retransmission buffer and inform that CoAP request sending is failed.
00485                     secure_session_delete(session);
00486                 }
00487             //Session valid
00488             }else{
00489                 unsigned char *data = ns_dyn_mem_temporary_alloc(sock->data_len);
00490                 int len = 0;
00491                 len = coap_security_handler_read(session->sec_handler, data, sock->data_len);
00492                 if( len < 0 ){
00493                     ns_dyn_mem_free(data);
00494                     secure_session_delete( session );
00495                 }else{
00496                     if( sock->parent->_recv_cb ){
00497                         sock->parent->_recv_cb(sock->listen_socket, src_address.address, src_address.identifier, data, len);
00498                     }
00499                     ns_dyn_mem_free(data);
00500                 }
00501             }
00502         }
00503     }
00504 }
00505 
00506 static void recv_sckt_msg(void *cb_res)
00507 {
00508     socket_callback_t *sckt_data = cb_res;
00509     internal_socket_t *sock = int_socket_find_by_socket_id(sckt_data->socket_id);
00510     ns_address_t src_address;
00511     if( sock && read_data(sckt_data, sock, &src_address) == 0 ){
00512         if(sock->parent && sock->parent->_recv_cb){
00513             sock->parent->_recv_cb(sock->listen_socket, src_address.address, src_address.identifier, sock->data, sock->data_len);
00514         }
00515         ns_dyn_mem_free(sock->data);
00516         sock->data = NULL;
00517     }
00518 }
00519 
00520 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)
00521 {
00522     if( !handler || !handler->socket ){
00523         return -1;
00524     }
00525     internal_socket_t *sock = handler->socket;
00526     sock->data_len = data_len;
00527     if( sock->data ){
00528         ns_dyn_mem_free(sock->data);
00529         sock->data = NULL;
00530     }
00531     sock->data = ns_dyn_mem_temporary_alloc(data_len);
00532     if( data_len > 0 && !sock->data ){
00533         return -1;
00534     }
00535     if( data_ptr ){
00536         memcpy(sock->data, data_ptr, data_len);
00537     }else{
00538         if( sock->data ){
00539             ns_dyn_mem_free(sock->data);
00540             sock->data = NULL;
00541         }
00542     }
00543 
00544     if( handler->socket->is_secure ){
00545         secure_session_t *session = secure_session_find(sock, address, port);
00546         if( !session ){
00547             session = secure_session_create(sock, address, port);
00548         }
00549         if( !session ){
00550             tr_err("coap_connection_handler_virtual_recv session creation failed - OOM");
00551             return -1;
00552         }
00553 
00554         session->last_contact_time = coap_service_get_internal_timer_ticks();
00555 
00556         if( !session->sec_handler->_is_started ){
00557             uint8_t *pw = (uint8_t *)ns_dyn_mem_alloc(64);
00558             uint8_t pw_len;
00559             if( sock->parent->_get_password_cb && 0 == sock->parent->_get_password_cb(sock->listen_socket, address, port, pw, &pw_len)){
00560                 //TODO: get_password_cb should support certs and PSK also
00561                 coap_security_keys_t keys;
00562                 keys._priv = pw;
00563                 keys._priv_len = pw_len;
00564                 coap_security_handler_connect_non_blocking(session->sec_handler, true, DTLS, keys, handler->socket->timeout_min, handler->socket->timeout_max);
00565                 //TODO: error handling
00566                 ns_dyn_mem_free(pw);
00567                 return 0;
00568             }else{
00569                 ns_dyn_mem_free(pw);
00570                 return -1;
00571             }
00572         }else{
00573             if(session->session_state == SECURE_SESSION_HANDSHAKE_ONGOING){
00574                 int ret = coap_security_handler_continue_connecting(session->sec_handler);
00575                 if(ret == 0){
00576                     session->session_state = SECURE_SESSION_OK;
00577                     if( handler->_security_done_cb ){
00578                         handler->_security_done_cb(sock->listen_socket,
00579                                                   address, port,
00580                                                   session->sec_handler->_keyblk.value);
00581                     }
00582                     return 0;
00583                 }
00584                 else if(ret < 0)
00585                 {
00586                     // error handling
00587                     // TODO: here we also should clear CoAP retransmission buffer and inform that CoAP request sending is failed.
00588                     secure_session_delete(session);
00589                 }
00590                 //TODO: error handling
00591             }else{
00592                 unsigned char *data = ns_dyn_mem_temporary_alloc(sock->data_len);
00593                 int len = 0;
00594                 len = coap_security_handler_read(session->sec_handler, data, sock->data_len);
00595                 if( len < 0 ){
00596                     ns_dyn_mem_free(data);
00597                     secure_session_delete( session );
00598                     return 0;
00599                 }else{
00600                     if( sock->parent->_recv_cb ){
00601                         sock->parent->_recv_cb(sock->listen_socket, address, port, data, len);
00602                     }
00603                     ns_dyn_mem_free(data);
00604                     data = NULL;
00605                 }
00606                 return 0;
00607             }
00608         }
00609     }else{
00610         if( sock->parent->_recv_cb ){
00611             sock->parent->_recv_cb(sock->listen_socket, address, port, sock->data, sock->data_len);
00612         }
00613         if( sock->data ){
00614             ns_dyn_mem_free(sock->data);
00615             sock->data = NULL;
00616         }
00617         return 0;
00618     }
00619     return -1;
00620 }
00621 
00622 coap_conn_handler_t *connection_handler_create(receive_from_socket_cb *recv_from_cb,
00623                                                  send_to_socket_cb *send_to_cb,
00624                                                  get_pw_cb *pw_cb,
00625                                                  security_done_cb *done_cb )
00626 {
00627     if( recv_from_cb == NULL ){
00628         return NULL;
00629     }
00630 
00631     coap_conn_handler_t *handler = ns_dyn_mem_alloc(sizeof(coap_conn_handler_t));
00632     if(!handler){
00633         return NULL;
00634     }
00635     memset(handler, 0, sizeof(coap_conn_handler_t));
00636     handler->socket = NULL;
00637     handler->_recv_cb = recv_from_cb;
00638     handler->_send_cb = send_to_cb;
00639 
00640     handler->_get_password_cb = pw_cb;
00641     handler->_security_done_cb = done_cb;
00642 
00643     return handler;
00644 }
00645 void connection_handler_destroy(coap_conn_handler_t *handler)
00646 {
00647     if(handler){
00648        int_socket_delete(handler->socket);
00649        ns_dyn_mem_free(handler);
00650     }
00651 }
00652 
00653 void connection_handler_close_secure_connection( coap_conn_handler_t *handler, uint8_t destination_addr_ptr[static 16], uint16_t port )
00654 {
00655     if(handler){
00656         if( handler->socket && handler->socket->is_secure){
00657             secure_session_t *session = secure_session_find( handler->socket, destination_addr_ptr, port);
00658             if( session ){
00659                 coap_security_send_close_alert( session->sec_handler );
00660                 session->session_state = SECURE_SESSION_CLOSED;
00661                 session->last_contact_time = coap_service_get_internal_timer_ticks();
00662             }
00663         }
00664     }
00665 }
00666 
00667 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)
00668 {
00669     if( !handler ){
00670         return -1;
00671     }
00672     //virtual socket must have send callback
00673     if( !is_real_socket && !handler->_send_cb ){
00674         return -1;
00675     }
00676     if( handler->socket ){
00677         int_socket_delete(handler->socket);
00678     }
00679 
00680     internal_socket_t *current = !use_ephemeral_port?int_socket_find(listen_port, is_secure, is_real_socket, bypassSec):NULL;
00681     if(!current){
00682         handler->socket = int_socket_create(listen_port, use_ephemeral_port, is_secure, is_real_socket, bypassSec);
00683         if(!handler->socket){
00684             return -1;
00685         }
00686         handler->socket->parent = ns_dyn_mem_alloc(sizeof(coap_conn_handler_t));
00687         if(!handler->socket->parent){
00688             int_socket_delete(handler->socket);
00689             return -1;
00690         }
00691         *handler->socket->parent = *handler;
00692     }else{
00693         current->usage_counter++;
00694         handler->socket = current;
00695     }
00696     return 0;
00697 }
00698 
00699 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)
00700 {
00701     if( !handler || !handler->socket || !dest_addr){
00702         return -1;
00703     }
00704     if(handler->socket->is_secure){
00705         handler->socket->bypass_link_sec = bypass_link_sec;
00706         memcpy(handler->socket->dest_addr.address, dest_addr->address, 16);
00707         handler->socket->dest_addr.identifier = dest_addr->identifier;
00708         handler->socket->dest_addr.type = dest_addr->type;
00709         secure_session_t *session = secure_session_find(handler->socket, dest_addr->address, dest_addr->identifier);
00710         if( !session ){
00711             session = secure_session_create(handler->socket, dest_addr->address, dest_addr->identifier);
00712             if( !session ){
00713                 return -1;
00714             }
00715             session->last_contact_time = coap_service_get_internal_timer_ticks();
00716             memcpy( handler->socket->dest_addr.address, dest_addr->address, 16 );
00717             handler->socket->dest_addr.identifier = dest_addr->identifier;
00718             handler->socket->dest_addr.type = dest_addr->type;
00719             uint8_t *pw = (uint8_t *)ns_dyn_mem_alloc(64);
00720             if(!pw){
00721                 //todo: free secure session?
00722                 return -1;
00723             }
00724             uint8_t pw_len;
00725             if( handler->_get_password_cb && 0 == handler->_get_password_cb(handler->socket->listen_socket, dest_addr->address, dest_addr->identifier, pw, &pw_len)){
00726                 //TODO: get_password_cb should support certs and PSK also
00727                 coap_security_keys_t keys;
00728                 keys._priv = pw;
00729                 keys._priv_len = pw_len;
00730                 coap_security_handler_connect_non_blocking(session->sec_handler, false, DTLS, keys, handler->socket->timeout_min, handler->socket->timeout_max);
00731                 ns_dyn_mem_free(pw);
00732                 return -2;
00733             }else{
00734                 //free secure session?
00735                 ns_dyn_mem_free(pw);
00736                 return -1;
00737             }
00738         }else if( session->session_state == SECURE_SESSION_OK ){
00739             if( coap_security_handler_send_message(session->sec_handler, data_ptr, data_len ) > 0 ){
00740                 session->last_contact_time = coap_service_get_internal_timer_ticks();
00741                 return 0;
00742             }
00743         }
00744         return -1;
00745     }else{
00746         if( !handler->socket->real_socket && handler->_send_cb){
00747             return handler->_send_cb((int8_t)handler->socket->listen_socket, dest_addr->address, dest_addr->identifier, data_ptr, data_len);
00748         }
00749         int opt_name = SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT;
00750         int8_t securityLinkLayer = 1;
00751         if( bypass_link_sec ){
00752             securityLinkLayer = 0;
00753         }
00754         socket_setsockopt(handler->socket->listen_socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_ADDR_PREFERENCES, &opt_name, sizeof(int));
00755         socket_setsockopt(handler->socket->listen_socket, SOCKET_IPPROTO_IPV6, SOCKET_LINK_LAYER_SECURITY, &securityLinkLayer, sizeof(int8_t));
00756         return socket_sendto(handler->socket->listen_socket, dest_addr, data_ptr, data_len);
00757     }
00758 }
00759 
00760 bool coap_connection_handler_socket_belongs_to(coap_conn_handler_t *handler, int8_t socket_id)
00761 {
00762     if( !handler || !handler->socket){
00763         return false;
00764     }
00765 
00766     if( handler->socket->listen_socket == socket_id){
00767         return true;
00768     }
00769     return false;
00770 }
00771 
00772 int8_t coap_connection_handler_set_timeout(coap_conn_handler_t *handler, uint32_t min, uint32_t max)
00773 {
00774     if(!handler || !handler->socket){
00775         return -1;
00776     }
00777     handler->socket->timeout_max = max;
00778     handler->socket->timeout_min = min;
00779 
00780     return 0;
00781 }
00782 
00783 /* No need to call every second - call rather like every minute (SECURE_SESSION_CLEAN_INTERVAL sets this) */
00784 void coap_connection_handler_exec(uint32_t time)
00785 {
00786     if(ns_list_count(&secure_session_list)){
00787         // Seek & destroy old sessions where close notify have been sent
00788         ns_list_foreach(secure_session_t, cur_ptr, &secure_session_list) {
00789             if(cur_ptr->session_state == SECURE_SESSION_CLOSED ||
00790                     cur_ptr->session_state == SECURE_SESSION_HANDSHAKE_ONGOING){
00791                 if((cur_ptr->last_contact_time +  CLOSED_SECURE_SESSION_TIMEOUT) <= time){
00792                     secure_session_delete(cur_ptr);
00793                 }
00794             }
00795             if(cur_ptr->session_state == SECURE_SESSION_OK){
00796                 if((cur_ptr->last_contact_time +  OPEN_SECURE_SESSION_TIMEOUT) <= time){
00797                     secure_session_delete(cur_ptr);
00798                 }
00799             }
00800         }
00801     }
00802 }