From 57fa92c8b75319afb707b23bac2a83aadcd5d9b6 Mon Sep 17 00:00:00 2001
From: "Dmitriy A. Gerasimov" <dmitriy.gerasimov@demlabs.net>
Date: Sat, 7 Dec 2019 00:21:55 +0700
Subject: [PATCH] [+] Added integration with chain net service

---
 dap_chain_net_srv_vpn.c        | 674 +++++++++++++++++++--------------
 dap_chain_net_srv_vpn.h        |  52 +--
 dap_chain_net_vpn_client_tun.c |   4 +-
 dap_chain_net_vpn_client_tun.h |   4 +-
 4 files changed, 431 insertions(+), 303 deletions(-)

diff --git a/dap_chain_net_srv_vpn.c b/dap_chain_net_srv_vpn.c
index f6daed8..1cc09a5 100755
--- a/dap_chain_net_srv_vpn.c
+++ b/dap_chain_net_srv_vpn.c
@@ -64,6 +64,7 @@
 #include "dap_chain_net.h"
 #include "dap_chain_net_srv.h"
 #include "dap_chain_net_srv_vpn.h"
+#include "dap_chain_net_srv_stream_session.h"
 #include "dap_chain_net_vpn_client.h"
 #include "dap_chain_ledger.h"
 
@@ -71,15 +72,26 @@
 
 #define SF_MAX_EVENTS 256
 
+typedef struct usage_client {
+    pthread_rwlock_t rwlock;
+    dap_chain_net_srv_ch_vpn_t * ch_vpn;
+    dap_chain_net_srv_client_t *net_srv_client;
+    dap_chain_datum_tx_receipt_t * receipt;
+    size_t receipt_size;
+    uint32_t usage_id;
+    dap_chain_net_srv_t * srv;
+    UT_hash_handle hh;
+} usage_client_t;
+
+
 typedef struct vpn_local_network {
-    struct in_addr client_addr_last;
-    struct in_addr client_addr_mask;
-    struct in_addr client_addr_host;
-    struct in_addr client_addr;
+    struct in_addr ipv4_lease_last;
+    struct in_addr ipv4_network_mask;
+    struct in_addr ipv4_host;
+    struct in_addr ipv4_network_addr;
     int tun_ctl_fd;
     int tun_fd;
     struct ifreq ifr;
-    dap_stream_ch_vpn_remote_single_t * clients; // Remote clients identified by destination address
 
     ch_vpn_pkt_t * pkt_out[400];
     size_t pkt_out_size;
@@ -87,15 +99,11 @@ typedef struct vpn_local_network {
     size_t pkt_out_windex;
     pthread_mutex_t pkt_out_mutex;
 
-    pthread_mutex_t clients_mutex;
 } vpn_local_network_t;
 
-typedef struct list_addr_element {
-    struct in_addr addr;
-    struct list_addr_element *next;
-} list_addr_element;
-
-static list_addr_element *list_addr_head = NULL;
+static usage_client_t * s_clients;
+static dap_chain_net_srv_ch_vpn_t * s_ch_vpn_addrs ;
+static pthread_rwlock_t s_clients_rwlock = PTHREAD_RWLOCK_INITIALIZER;
 
 static ch_vpn_socket_proxy_t * sf_socks = NULL;
 static ch_vpn_socket_proxy_t * sf_socks_client = NULL;
@@ -105,11 +113,16 @@ static int sf_socks_epoll_fd;
 static pthread_t srv_sf_socks_pid;
 static pthread_t srv_sf_socks_raw_pid;
 static vpn_local_network_t *s_raw_server;
+static pthread_rwlock_t s_raw_server_rwlock = PTHREAD_RWLOCK_INITIALIZER;
 
 static const char *s_addr;
 
 // Service callbacks
-static int s_callback_request_after(dap_chain_net_srv_t * a_srv, dap_chain_net_srv_client_t * a_srv_client
+static int s_callback_requested(dap_chain_net_srv_t * a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_t * a_srv_client
+                                    , const void * a_custom_data, size_t a_custom_data_size );
+static int s_callback_response_success(dap_chain_net_srv_t * a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_t * a_srv_client
+                                    , const void * a_custom_data, size_t a_custom_data_size );
+static int s_callback_response_error(dap_chain_net_srv_t * a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_t * a_srv_client
                                     , const void * a_custom_data, size_t a_custom_data_size );
 
 
@@ -124,13 +137,13 @@ static void s_tun_destroy(void);
 // Stream callbacks
 static void s_new(dap_stream_ch_t* ch, void* arg);
 static void srv_ch_sf_delete(dap_stream_ch_t* ch, void* arg);
-static void srv_ch_sf_packet_in(dap_stream_ch_t* ch, void* arg);
-static void srv_ch_sf_packet_out(dap_stream_ch_t* ch, void* arg);
+static void s_ch_packet_in(dap_stream_ch_t* ch, void* arg);
+static void s_ch_packet_out(dap_stream_ch_t* ch, void* arg);
 
 //static int srv_ch_sf_raw_write(uint8_t op_code, const void * data, size_t data_size);
 //static void srv_stream_sf_disconnect(ch_vpn_socket_proxy_t * sf_sock);
 
-static char *s_srv_vpn_addr, *s_srv_vpn_mask;
+static char *s_srv_vpn_addr = NULL, *s_srv_vpn_mask = NULL;
 
 
 /**
@@ -148,17 +161,20 @@ int dap_chain_net_srv_vpn_init(dap_config_t * g_config)
         s_srv_vpn_mask = strdup(c_mask);
 
         s_raw_server = DAP_NEW_Z(vpn_local_network_t);
-        pthread_mutex_init(&s_raw_server->clients_mutex, NULL);
         pthread_mutex_init(&s_raw_server->pkt_out_mutex, NULL);
         pthread_mutex_init(&s_sf_socks_mutex, NULL);
         pthread_cond_init(&s_sf_socks_cond, NULL);
         pthread_create(&srv_sf_socks_raw_pid, NULL, srv_ch_sf_thread_raw, NULL);
         pthread_create(&srv_sf_socks_pid, NULL, srv_ch_sf_thread, NULL);
-        dap_stream_ch_proc_add(DAP_STREAM_CH_ID_NET_SRV_VPN, s_new, srv_ch_sf_delete, srv_ch_sf_packet_in,
-                srv_ch_sf_packet_out);
+        dap_stream_ch_proc_add(DAP_STREAM_CH_ID_NET_SRV_VPN, s_new, srv_ch_sf_delete, s_ch_packet_in,
+                s_ch_packet_out);
 
         dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_VPN_ID };
-        dap_chain_net_srv_t* l_srv = dap_chain_net_srv_add( l_uid, s_callback_request_after);
+        dap_chain_net_srv_t* l_srv = dap_chain_net_srv_add( l_uid, s_callback_requested,
+                                                            s_callback_response_success, s_callback_response_error);
+        dap_chain_net_srv_vpn_t* l_srv_vpn  = DAP_NEW_Z( dap_chain_net_srv_vpn_t);
+        l_srv->_inhertor = l_srv_vpn;
+        l_srv_vpn->parent = l_srv;
 
         uint16_t l_pricelist_count = 0;
         char ** l_pricelist = dap_config_get_array_str(g_config,"srv_vpn","pricelist", &l_pricelist_count );
@@ -275,19 +291,61 @@ void dap_chain_net_srv_vpn_deinit(void)
 }
 
 /**
- * @brief s_callback_request_after
- * @param a_srv
- * @param a_srv_client
- * @param a_custom_data
- * @param a_custom_data_size
- * @return
+ * Callback calls after successful request for service
  */
-static int s_callback_request_after(dap_chain_net_srv_t * a_srv, dap_chain_net_srv_client_t * a_srv_client
+static int s_callback_requested(dap_chain_net_srv_t * a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_t * a_srv_client
                                     , const void * a_custom_data, size_t a_custom_data_size )
 {
+
+    // TODO parse custom data like JSON or smth like this
+    (void) a_custom_data;
+    (void) a_custom_data_size;
+    (void) a_srv;
+    return 0; // aways allow to use it for now
+}
+
+/**
+ * Called if responses success with all signature checks
+ */
+static int s_callback_response_success(dap_chain_net_srv_t * a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_t * a_srv_client
+                                    , const void * a_request, size_t a_request_size )
+{
+    const dap_chain_datum_tx_receipt_t * l_receipt = (const dap_chain_datum_tx_receipt_t *) a_request;
+    size_t l_receipt_size = a_request_size;
+//    dap_stream_ch_chain_net_srv_pkt_request_t * l_request =  (dap_stream_ch_chain_net_srv_pkt_request_t *) a_request;
+//    dap_chain_net_srv_stream_session_t * l_srv_session = (dap_chain_net_srv_stream_session_t *) a_srv_client->ch->stream->session->_inheritor;
+    dap_chain_net_srv_stream_session_t * l_srv_session = (dap_chain_net_srv_stream_session_t *) a_srv_client->ch->stream->session->_inheritor;
+
+    usage_client_t * l_usage_client = DAP_NEW_Z(usage_client_t);
+    l_usage_client->usage_id = a_usage_id;
+    l_usage_client->net_srv_client = a_srv_client;
+    l_usage_client->receipt = DAP_NEW_SIZE(dap_chain_datum_tx_receipt_t,l_receipt_size);
+
+    l_srv_session->usage_active = dap_chain_net_srv_usage_find(l_srv_session->usages,a_usage_id);
+    pthread_rwlock_init(&l_usage_client->rwlock,NULL);
+    memcpy(l_usage_client->receipt, l_receipt, l_receipt_size);
+
+    pthread_rwlock_wrlock(&s_clients_rwlock);
+    HASH_ADD(hh, s_clients,usage_id,sizeof(a_usage_id),l_usage_client);
+    pthread_rwlock_unlock(&s_clients_rwlock);
+    log_it(L_NOTICE,"Enable VPN service");
     return 0;
 }
 
+/**
+ * If error
+ */
+static int s_callback_response_error(dap_chain_net_srv_t * a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_t * a_srv_client
+                                    , const void * a_custom_data, size_t a_custom_data_size )
+{
+    if (a_custom_data_size != sizeof (dap_stream_ch_chain_net_srv_pkt_error_t)){
+        log_it(L_ERROR, "Wrong custom data size, must be %zd", sizeof(dap_stream_ch_chain_net_srv_pkt_error_t) );
+        return -1;
+    }
+    dap_stream_ch_chain_net_srv_pkt_error_t * l_err = (dap_stream_ch_chain_net_srv_pkt_error_t *)a_custom_data;
+    log_it(L_WARNING,"Response error code 0x%08X", l_err->code);
+    return 0;
+}
 
 
 /**
@@ -295,10 +353,11 @@ static int s_callback_request_after(dap_chain_net_srv_t * a_srv, dap_chain_net_s
  */
 static void s_tun_create(void)
 {
-    inet_aton(s_srv_vpn_addr, &s_raw_server->client_addr);
-    inet_aton(s_srv_vpn_mask, &s_raw_server->client_addr_mask);
-    s_raw_server->client_addr_host.s_addr = (s_raw_server->client_addr.s_addr | 0x01000000); // grow up some shit here!
-    s_raw_server->client_addr_last.s_addr = s_raw_server->client_addr_host.s_addr;
+    pthread_rwlock_wrlock(& s_raw_server_rwlock);
+    inet_aton(s_srv_vpn_addr, &s_raw_server->ipv4_network_addr);
+    inet_aton(s_srv_vpn_mask, &s_raw_server->ipv4_network_mask);
+    s_raw_server->ipv4_host.s_addr = (s_raw_server->ipv4_network_addr.s_addr | 0x01000000); // grow up some shit here!
+    s_raw_server->ipv4_lease_last.s_addr = s_raw_server->ipv4_host.s_addr;
 
     if((s_raw_server->tun_ctl_fd = open("/dev/net/tun", O_RDWR)) < 0) {
         log_it(L_ERROR, "Opening /dev/net/tun error: '%s'", strerror(errno));
@@ -313,17 +372,18 @@ static void s_tun_create(void)
         } else {
             char buf[256];
             log_it(L_NOTICE, "Bringed up %s virtual network interface (%s/%s)", s_raw_server->ifr.ifr_name,
-                    inet_ntoa(s_raw_server->client_addr_host), s_srv_vpn_mask);
+                    inet_ntoa(s_raw_server->ipv4_host), s_srv_vpn_mask);
             s_raw_server->tun_fd = s_raw_server->tun_ctl_fd; // Looks yes, its so
             snprintf(buf, sizeof(buf), "ip link set %s up", s_raw_server->ifr.ifr_name);
             int res = system(buf);
-            snprintf(buf, sizeof(buf), "ip addr add %s/%s dev %s ", inet_ntoa(s_raw_server->client_addr_host),
+            snprintf(buf, sizeof(buf), "ip addr add %s/%s dev %s ", inet_ntoa(s_raw_server->ipv4_host),
                     s_srv_vpn_mask,
                     s_raw_server->ifr.ifr_name);
             res = system(buf);
             res = 0;
         }
     }
+    pthread_rwlock_unlock(& s_raw_server_rwlock);
 
 }
 
@@ -332,8 +392,10 @@ static void s_tun_create(void)
  */
 static void s_tun_destroy(void)
 {
+    pthread_rwlock_wrlock(& s_raw_server_rwlock);
     close(s_raw_server->tun_fd);
     s_raw_server->tun_fd = -1;
+    pthread_rwlock_unlock(& s_raw_server_rwlock);
 }
 
 /**
@@ -343,18 +405,18 @@ static void s_tun_destroy(void)
  */
 static void s_callback_trafic(dap_client_remote_t *a_client, dap_stream_ch_t* a_ch)
 {
-    dap_chain_net_srv_vpn_t *l_ch_vpn = CH_VPN(a_ch);
+    dap_chain_net_srv_ch_vpn_t *l_ch_vpn = CH_VPN(a_ch);
     //dap_stream_ch_vpn_t *l_ch_vpn = (dap_stream_ch_vpn_t*)(a_ch->internal);
     if(!a_client || !l_ch_vpn)
         return;
-    dap_chain_net_srv_abstract_t *srv_common = &l_ch_vpn->net_srv.srv_common;
+    dap_chain_net_srv_abstract_t *srv_common = &l_ch_vpn->net_srv->srv_common;
     size_t bytes_max = srv_common->proposal_params.vpn.limit_bytes;
     static size_t bytes_cur_prev = 0;
     size_t bytes_cur = a_client->download_stat.buf_size_total;
     size_t delta_bytes = (bytes_cur > bytes_cur_prev) ? bytes_cur - bytes_cur_prev : 0;
     // make receipt transaction
     if(delta_bytes) {
-        const dap_chain_net_srv_abstract_t *l_cond = &(l_ch_vpn->net_srv.srv_common);
+        const dap_chain_net_srv_abstract_t *l_cond = &(l_ch_vpn->net_srv->srv_common);
         //l_cond->
         //if()
         //if(!dap_chain_mempool_tx_create_receipt(delta_bytes))
@@ -391,38 +453,24 @@ void s_new(dap_stream_ch_t* a_stream_ch, void* a_arg)
 {
     (void) a_arg;
 
-    a_stream_ch->internal = DAP_NEW_Z(dap_chain_net_srv_vpn_t);
-    dap_chain_net_srv_vpn_t * sf = CH_VPN(a_stream_ch);
-    pthread_mutex_init(&sf->mutex, NULL);
-    sf->raw_l3_sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
-    //
-    if(a_stream_ch->stream->session->service_key) {
-
-        char *l_addr_base58;
-        char *l_sign_hash_str;
-        a_stream_ch->stream->session->service_key =
-                "RpiDC8c1SxrT7TUExyGWNErgV6HtwkKhSd1yLEkTA9qHcSiYA4GXjE67KJQay2TzHdG2ouk42d8GgLyABu6rP55JeFYzBkqZ7CqijDEw;12345";
-
-        const dap_chain_net_srv_abstract_t *l_cond = NULL;
-        // debug
-        const char *l_net_name = "kelvin-testnet";
-        dap_ledger_t *l_ledger = dap_chain_ledger_by_net_name(l_net_name);
-        // get value for service and fill l_cond struct
-        uint64_t l_value = dap_chain_net_srv_client_auth(l_ledger, a_stream_ch->stream->session->service_key, &l_cond);
-
-        // add service
-        if(l_cond && l_value > 0) {
-            dap_chain_net_srv_t l_srv;
-            memset(&l_srv, 0, sizeof(dap_chain_net_srv_t));
-            l_srv.callback_trafic = s_callback_trafic;
-            // debug
-            l_srv.srv_common.proposal_params.vpn.limit_bytes = 2000;
-            if(l_cond)
-                memcpy(&l_srv.srv_common, l_cond, sizeof(dap_chain_net_srv_abstract_t));
-            memcpy(&sf->net_srv, &l_srv, sizeof(dap_chain_net_srv_t)); // Unique ID for service.
-        }
-
+    a_stream_ch->internal = DAP_NEW_Z(dap_chain_net_srv_ch_vpn_t);
+    dap_chain_net_srv_ch_vpn_t * l_srv_vpn = CH_VPN(a_stream_ch);
+    dap_chain_net_srv_stream_session_t * l_srv_session = (dap_chain_net_srv_stream_session_t *) a_stream_ch->stream->session->_inheritor;
+    pthread_mutex_init(&l_srv_vpn->mutex, NULL);
+    l_srv_vpn->raw_l3_sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
+
+    l_srv_vpn->usage_id = l_srv_session->usage_active?  l_srv_session->usage_active->id : 0;
+    // So complicated to update usage client to be sure that nothing breaks it
+    usage_client_t * l_usage_client = NULL;
+    pthread_rwlock_rdlock(&s_clients_rwlock);
+    HASH_FIND(hh,s_clients, &l_srv_vpn->usage_id,sizeof(l_srv_vpn->usage_id),l_usage_client );
+    if (l_usage_client){
+        pthread_rwlock_wrlock(&l_usage_client->rwlock);
+        l_usage_client->ch_vpn = l_srv_vpn;
+        pthread_rwlock_unlock(&l_usage_client->rwlock);
     }
+    pthread_rwlock_unlock(&s_clients_rwlock);
+
 }
 
 /**
@@ -433,47 +481,62 @@ void s_new(dap_stream_ch_t* a_stream_ch, void* a_arg)
 void srv_ch_sf_delete(dap_stream_ch_t* ch, void* arg)
 {
     log_it(L_DEBUG, "ch_sf_delete() for %s", ch->stream->conn->hostaddr);
-    ch_vpn_socket_proxy_t * cur, *tmp;
-    dap_stream_ch_vpn_remote_single_t * raw_client = 0;
-    // in_addr_t raw_client_addr = CH_SF(ch)->tun_client_addr.s_addr;
-    in_addr_t raw_client_addr = ch->stream->session->tun_client_addr.s_addr;
-
-    if(raw_client_addr) {
-        log_it(L_DEBUG, "ch_sf_delete() %s searching in hash table",
-                inet_ntoa(ch->stream->session->tun_client_addr));
-        list_addr_element *el = (list_addr_element*) malloc(sizeof(list_addr_element));
-        //el->addr = CH_SF(ch)->tun_client_addr;
-        el->addr = ch->stream->session->tun_client_addr;
-        LL_APPEND(list_addr_head, el);
-        //   LL_FOREACH(list_addr_head,el) log_it(L_INFO,"addr = %s", inet_ntoa(el->addr));
-
-        pthread_mutex_lock(&s_raw_server->clients_mutex);
-
-        HASH_FIND_INT(s_raw_server->clients, &raw_client_addr, raw_client);
-        if(raw_client) {
-            HASH_DEL(s_raw_server->clients, raw_client);
-            log_it(L_DEBUG, "ch_sf_delete() %s removed from hash table",
-                    inet_ntoa(ch->stream->session->tun_client_addr));
-            free(raw_client);
-        } else
-            log_it(L_DEBUG, "ch_sf_delete() %s is not present in raw sockets hash table",
-                    inet_ntoa(ch->stream->session->tun_client_addr));
+    dap_chain_net_srv_ch_vpn_t * l_ch_vpn = CH_VPN(ch);
+    dap_chain_net_srv_vpn_t * l_srv_vpn =(dap_chain_net_srv_vpn_t *) l_ch_vpn->net_srv->_inhertor;
+    pthread_mutex_lock(&(l_ch_vpn->mutex));
+    // So complicated to update usage client to be sure that nothing breaks it
+    usage_client_t * l_usage_client = NULL;
+
+    bool l_is_unleased = true;
+    if ( l_ch_vpn->addr_ipv4.s_addr ){ // if leased address
+        pthread_rwlock_wrlock(& s_raw_server_rwlock);
+        if ( s_raw_server->ipv4_lease_last.s_addr == l_ch_vpn->addr_ipv4.s_addr ){
+            s_raw_server->ipv4_lease_last.s_addr = ntohl( ntohl(s_raw_server->ipv4_lease_last.s_addr)-1 );
+            l_is_unleased = false;
+        }
+        pthread_rwlock_unlock(& s_raw_server_rwlock);
+    }
+
+    pthread_rwlock_wrlock(&s_clients_rwlock);
+    HASH_DEL(s_ch_vpn_addrs,l_ch_vpn);
 
-        pthread_mutex_unlock(&s_raw_server->clients_mutex);
+    if ( l_is_unleased ){ // If unleased
+        dap_chain_net_srv_vpn_item_ipv4_t * l_item_unleased = DAP_NEW_Z(dap_chain_net_srv_vpn_item_ipv4_t);
+        l_item_unleased->addr.s_addr = l_ch_vpn->addr_ipv4.s_addr;
+        l_item_unleased->next = l_srv_vpn->ipv4_unleased;
+        l_srv_vpn->ipv4_unleased = l_item_unleased;
     }
-    HASH_ITER(hh, CH_VPN(ch)->socks , cur, tmp)
+
+    HASH_FIND(hh,s_clients, &l_ch_vpn->usage_id,sizeof(l_ch_vpn->usage_id),l_usage_client );
+    if (l_usage_client){
+        pthread_rwlock_wrlock(&l_usage_client->rwlock);
+
+        l_usage_client->ch_vpn = NULL; // NULL the channel, nobody uses that indicates
+        pthread_rwlock_unlock(&l_usage_client->rwlock);
+    }
+
+    pthread_rwlock_unlock(&s_clients_rwlock);
+
+    ch_vpn_socket_proxy_t * cur, *tmp;
+    // in_addr_t raw_client_addr = CH_SF(ch)->tun_client_addr.s_addr;
+    HASH_ITER(hh, l_ch_vpn->socks , cur, tmp)
     {
         log_it(L_DEBUG, "delete socket: %i", cur->sock);
-        HASH_DEL(CH_VPN(ch)->socks, cur);
+        HASH_DEL(l_ch_vpn->socks, cur);
         if(cur)
             free(cur);
     }
-    pthread_mutex_unlock(&( CH_VPN(ch)->mutex));
-    if(CH_VPN(ch)->raw_l3_sock)
-        close(CH_VPN(ch)->raw_l3_sock);
+
+    if(l_ch_vpn->raw_l3_sock)
+        close(l_ch_vpn->raw_l3_sock);
+    l_ch_vpn->ch = NULL;
+    l_ch_vpn->net_srv = NULL;
+    l_ch_vpn->is_allowed =false;
+    pthread_mutex_unlock(&(l_ch_vpn->mutex));
+    pthread_mutex_destroy(& l_ch_vpn->mutex);
 }
 
-static void stream_sf_socket_delete(ch_vpn_socket_proxy_t * sf)
+static void s_ch_proxy_delete(ch_vpn_socket_proxy_t * sf)
 {
     dap_return_if_fail(sf);
     if(sf->sock > 0)
@@ -486,15 +549,14 @@ static void stream_sf_socket_delete(ch_vpn_socket_proxy_t * sf)
     free(sf);
 }
 
-static void stream_sf_socket_ready_to_write(dap_stream_ch_t * ch, bool is_ready)
+static void s_ch_ready_to_write(dap_stream_ch_t * ch, bool is_ready)
 {
     pthread_mutex_lock(&ch->mutex);
     ch->ready_to_write = is_ready;
     if(is_ready)
         ch->stream->conn_http->state_write = DAP_HTTP_CLIENT_STATE_DATA;
     //!!!
-    //dap_stream_ch_set_ready_to_write(ch, is_ready);
-    dap_client_remote_ready_to_write(ch->stream->conn, is_ready);
+    dap_stream_ch_set_ready_to_write(ch, is_ready);
     pthread_mutex_unlock(&ch->mutex);
 
 }
@@ -517,95 +579,216 @@ static ch_vpn_pkt_t* srv_ch_sf_raw_read()
 }
 
 /**
- * @brief stream_sf_packet_in
+ * @brief stream_sf_packet_out Packet Out Ch callback
  * @param ch
  * @param arg
  */
-void srv_ch_sf_packet_in(dap_stream_ch_t* ch, void* arg)
+static void s_ch_packet_out(dap_stream_ch_t* a_ch, void* a_arg)
 {
-    dap_stream_ch_pkt_t * pkt = (dap_stream_ch_pkt_t *) arg;
+    (void) a_arg;
+    ch_vpn_socket_proxy_t * cur, *tmp;
+    dap_chain_net_srv_stream_session_t * l_srv_session = DAP_CHAIN_NET_SRV_STREAM_SESSION( a_ch->stream->session );
+    dap_chain_net_srv_ch_vpn_t *l_ch_vpn = CH_VPN(a_ch);
 
-    if ( pkt->hdr.type == DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_CLIENT )
-        dap_chain_net_vpn_client_pkt_in( ch, pkt);
-    else {
-        static bool client_connected = false;
-        ch_vpn_pkt_t * sf_pkt = (ch_vpn_pkt_t *) pkt->data;
+    dap_chain_net_srv_usage_t * l_usage = dap_chain_net_srv_usage_find(l_srv_session,  l_ch_vpn->usage_id);
+    if ( ! l_usage){
+        log_it(L_NOTICE, "No active usage in list, possible disconnected. Send nothin on this channel");
+        dap_stream_ch_set_ready_to_write(a_ch,false);
+        return;
+    }
 
-        int remote_sock_id = sf_pkt->header.sock_id;
+    if ( ! l_usage->is_active ){
+        log_it(L_INFO, "Usage inactivation: switch off packet output channel");
+        dap_stream_ch_set_ready_to_write(a_ch,false);
+        return;
+    }
 
-        //log_it(L_DEBUG, "Got SF packet with id %d op_code 0x%02x", remote_sock_id, sf_pkt->header.op_code);
-        if(sf_pkt->header.op_code >= 0xb0) { // Raw packets
-            switch (sf_pkt->header.op_code) {
-            case VPN_PACKET_OP_CODE_VPN_ADDR_REQUEST: { // Client request after L3 connection the new IP address
-                log_it(L_DEBUG, "Got SF packet with id %d op_code 0x%02x", remote_sock_id, sf_pkt->header.op_code);
-                struct in_addr n_addr = { 0 };
+    bool l_is_smth_out = false;
+//    log_it(L_DEBUG,"Socket forwarding packet out callback: %u sockets in hashtable", HASH_COUNT(CH_SF(ch)->socks) );
+    HASH_ITER(hh, l_ch_vpn->socks , cur, tmp)
+    {
+        bool l_signal_to_break = false;
+        pthread_mutex_lock(&(cur->mutex));
+        size_t i;
+        //log_it(L_DEBUG, "Socket with id %d has %u packets in output buffer", cur->id, cur->pkt_out_size);
+        if(cur->pkt_out_size) {
+            for(i = 0; i < cur->pkt_out_size; i++) {
+                ch_vpn_pkt_t * pout = cur->pkt_out[i];
+                if(pout) {
+                    if(dap_stream_ch_pkt_write(a_ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pout,
+                            pout->header.op_data.data_size + sizeof(pout->header))) {
+                        l_is_smth_out = true;
+                        DAP_DELETE(pout);
+                        cur->pkt_out[i] = NULL;
+                    } else {
+                        //log_it(L_WARNING,
+                        //        "Buffer is overflowed, breaking cycle to let the upper level cycle drop data to the output socket");
+                        l_is_smth_out = true;
+                        l_signal_to_break = true;
+                        break;
+                    }
+                }
+            }
+        }
 
-                if(n_addr.s_addr == 0) { // If the addres still in the network
+        if(l_signal_to_break) {
+            pthread_mutex_unlock(&(cur->mutex));
+            break;
+        }
+        cur->pkt_out_size = 0;
+        if(cur->signal_to_delete) {
+            log_it(L_NOTICE, "Socket id %d got signal to be deleted", cur->id);
+            pthread_mutex_lock(&( CH_VPN(a_ch)->mutex));
+            HASH_DEL(l_ch_vpn->socks, cur);
+            pthread_mutex_unlock(&( CH_VPN(a_ch)->mutex));
 
-                    pthread_mutex_lock(&s_raw_server->clients_mutex);
+            pthread_mutex_lock(&(s_sf_socks_mutex));
+            HASH_DELETE(hh2, sf_socks, cur);
+            HASH_DELETE(hh_sock, sf_socks_client, cur);
+            pthread_mutex_unlock(&(s_sf_socks_mutex));
 
-                    int count_free_addr = -1;
-                    list_addr_element *el;
-                    LL_COUNT(list_addr_head, el, count_free_addr);
+            pthread_mutex_unlock(&(cur->mutex));
+            s_ch_proxy_delete(cur);
+        } else
+            pthread_mutex_unlock(&(cur->mutex));
+    }
+    if(l_is_smth_out) {
+        a_ch->stream->conn_http->state_write = DAP_HTTP_CLIENT_STATE_DATA;
+    }
 
-                    dap_stream_ch_vpn_remote_single_t * n_client = (dap_stream_ch_vpn_remote_single_t*) calloc(1,
-                            sizeof(dap_stream_ch_vpn_remote_single_t));
-                    n_client->ch = ch;
+    dap_stream_ch_set_ready_to_write(a_ch, l_is_smth_out);
+}
 
-                    if(count_free_addr > 0) {
-                        n_addr.s_addr = list_addr_head->addr.s_addr;
-                        LL_DELETE(list_addr_head, list_addr_head);
-                    }
-                    else
-                    {
-                        n_addr.s_addr = ntohl(s_raw_server->client_addr_last.s_addr);
-                        n_addr.s_addr++;
-                        n_addr.s_addr = ntohl(n_addr.s_addr);
-                    }
+/**
+ * @brief stream_sf_packet_in
+ * @param ch
+ * @param arg
+ */
+void s_ch_packet_in(dap_stream_ch_t* a_ch, void* arg)
+{
+    dap_stream_ch_pkt_t * pkt = (dap_stream_ch_pkt_t *) arg;
+    dap_chain_net_srv_stream_session_t * l_srv_session = DAP_CHAIN_NET_SRV_STREAM_SESSION (a_ch->stream->session );
+    dap_chain_net_srv_ch_vpn_t *l_ch_vpn = CH_VPN(a_ch);
+    dap_chain_net_srv_usage_t * l_usage = dap_chain_net_srv_usage_find(l_srv_session,  l_ch_vpn->usage_id);
 
-                    n_client->addr_ipv4 = n_addr.s_addr;
-                    s_raw_server->client_addr_last.s_addr = n_addr.s_addr;
-                    ch->stream->session->tun_client_addr.s_addr = n_addr.s_addr;
-                    HASH_ADD_INT(s_raw_server->clients, addr_ipv4, n_client);
+    if ( ! l_usage){
+        log_it(L_NOTICE, "No active usage in list, possible disconnected. Send nothin on this channel");
+        dap_stream_ch_set_ready_to_write(a_ch,false);
+        return;
+    }
 
-                    pthread_mutex_unlock(&s_raw_server->clients_mutex);
+    if ( ! l_usage->is_active ){
+        log_it(L_INFO, "Usage inactivation: switch off packet input channel");
+        dap_stream_ch_set_ready_to_write(a_ch,false);
+        return;
+    }
 
-                    log_it(L_NOTICE, "VPN client address %s leased", inet_ntoa(n_addr));
-                    log_it(L_INFO, "\tgateway %s", inet_ntoa(s_raw_server->client_addr_host));
-                    log_it(L_INFO, "\tmask %s", inet_ntoa(s_raw_server->client_addr_mask));
-                    log_it(L_INFO, "\taddr %s", inet_ntoa(s_raw_server->client_addr));
-                    log_it(L_INFO, "\tlast_addr %s", inet_ntoa(s_raw_server->client_addr_last));
+    // TODO move address leasing to this structure
+    dap_chain_net_srv_vpn_t * l_srv_vpn =(dap_chain_net_srv_vpn_t *) l_usage->service->_inhertor;
 
-                    ch_vpn_pkt_t *pkt_out = (ch_vpn_pkt_t*) calloc(1,
-                            sizeof(pkt_out->header) + sizeof(n_addr) + sizeof(s_raw_server->client_addr_host));
-                    pkt_out->header.sock_id = s_raw_server->tun_fd;
-                    pkt_out->header.op_code = VPN_PACKET_OP_CODE_VPN_ADDR_REPLY;
-                    pkt_out->header.op_data.data_size = sizeof(n_addr) + sizeof(s_raw_server->client_addr_host);
+    if ( pkt->hdr.type == DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_CLIENT )
+        dap_chain_net_vpn_client_pkt_in( a_ch, pkt);
+    else {
+        static bool client_connected = false;
+        ch_vpn_pkt_t * l_vpn_pkt = (ch_vpn_pkt_t *) pkt->data;
+        size_t l_vpn_pkt_size = pkt->hdr.size - sizeof (l_vpn_pkt->header);
 
-                    memcpy(pkt_out->data, &n_addr, sizeof(n_addr));
-                    memcpy(pkt_out->data + sizeof(n_addr), &s_raw_server->client_addr_host,
-                            sizeof(s_raw_server->client_addr_host));
-                    dap_stream_ch_pkt_write(ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pkt_out,
-                            pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
-                    stream_sf_socket_ready_to_write(ch, true);
+        int remote_sock_id = l_vpn_pkt->header.sock_id;
 
-                    //ch_sf_raw_write(n_addr.s_addr,STREAM_SF_PACKET_OP_CODE_RAW_L3_ADDR_REPLY,&n_addr,sizeof(n_addr));
-                } else { // All the network is filled with clients, can't lease a new address
-                    log_it(L_WARNING, "All the network is filled with clients, can't lease a new address");
+        //log_it(L_DEBUG, "Got SF packet with id %d op_code 0x%02x", remote_sock_id, sf_pkt->header.op_code);
+        if(l_vpn_pkt->header.op_code >= 0xb0) { // Raw packets
+            switch (l_vpn_pkt->header.op_code) {
+            case VPN_PACKET_OP_CODE_VPN_ADDR_REQUEST: { // Client request after L3 connection the new IP address
+                log_it(L_INFO, "Received address request  ");
+                if ( l_ch_vpn->addr_ipv4.s_addr ){
+                    log_it(L_WARNING,"We already have ip address leased to us");
                     ch_vpn_pkt_t *pkt_out = (ch_vpn_pkt_t*) calloc(1, sizeof(pkt_out->header));
-                    pkt_out->header.sock_id = s_raw_server->tun_fd;
                     pkt_out->header.op_code = VPN_PACKET_OP_CODE_PROBLEM;
-                    pkt_out->header.op_problem.code = VPN_PROBLEM_CODE_NO_FREE_ADDR;
-                    dap_stream_ch_pkt_write(ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pkt_out,
+                    pkt_out->header.op_problem.code = VPN_PROBLEM_CODE_ALREADY_ASSIGNED_ADDR;
+                    pkt_out->header.sock_id = s_raw_server->tun_fd;
+                    pkt_out->header.usage_id = l_usage->id;
+                    dap_stream_ch_pkt_write(a_ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pkt_out,
                             pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
-                    stream_sf_socket_ready_to_write(ch, true);
+                    s_ch_ready_to_write(a_ch, true);
+                    break;
+                }
+                dap_chain_net_srv_vpn_item_ipv4_t * l_item_ipv4 = l_srv_vpn->ipv4_unleased;
+                if ( l_item_ipv4){
+                    l_ch_vpn->addr_ipv4.s_addr = l_item_ipv4->addr.s_addr;
+
+                    pthread_rwlock_wrlock( &s_clients_rwlock );
+                    HASH_ADD(hh, s_ch_vpn_addrs, addr_ipv4, sizeof (l_ch_vpn->addr_ipv4), l_ch_vpn);
+                    pthread_rwlock_unlock( &s_clients_rwlock );
+
+                    ch_vpn_pkt_t *l_pkt_out = DAP_NEW_Z_SIZE(ch_vpn_pkt_t,
+                            sizeof(l_pkt_out->header) + sizeof(l_ch_vpn->addr_ipv4) + sizeof(s_raw_server->ipv4_host));
+                    l_pkt_out->header.sock_id = s_raw_server->tun_fd;
+                    l_pkt_out->header.op_code = VPN_PACKET_OP_CODE_VPN_ADDR_REPLY;
+                    l_pkt_out->header.op_data.data_size = sizeof(l_ch_vpn->addr_ipv4) + sizeof(s_raw_server->ipv4_host);
+                    l_pkt_out->header.usage_id = l_usage->id;
+
+                    memcpy(l_pkt_out->data, &l_ch_vpn->addr_ipv4, sizeof(l_ch_vpn->addr_ipv4));
+                    memcpy(l_pkt_out->data + sizeof(l_ch_vpn->addr_ipv4), &s_raw_server->ipv4_host,
+                            sizeof(s_raw_server->ipv4_host));
+                    dap_stream_ch_pkt_write(a_ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, l_pkt_out,
+                            l_pkt_out->header.op_data.data_size + sizeof(l_pkt_out->header));
+                    s_ch_ready_to_write(a_ch, true);
+                    l_srv_vpn->ipv4_unleased = l_item_ipv4->next;
+                    DAP_DELETE(l_item_ipv4);
+                }else{
+                    struct in_addr n_addr={0};
+                    n_addr.s_addr = ntohl(s_raw_server->ipv4_lease_last.s_addr);
+                    n_addr.s_addr++;
+
+                    if( (uint32_t)n_addr.s_addr >= (uint32_t)(ntohl(s_raw_server->ipv4_network_addr.s_addr)|
+                                                              ~(ntohl(s_raw_server->ipv4_network_mask.s_addr)))  ) { // If the addres still in the network
+                        n_addr.s_addr = ntohl(n_addr.s_addr);
+                        l_ch_vpn->addr_ipv4.s_addr = n_addr.s_addr;
+                        s_raw_server->ipv4_lease_last.s_addr = n_addr.s_addr;
+                        a_ch->stream->session->tun_client_addr.s_addr = n_addr.s_addr;
+
+                        log_it(L_NOTICE, "VPN client address %s leased", inet_ntoa(n_addr));
+                        log_it(L_INFO, "\tgateway %s", inet_ntoa(s_raw_server->ipv4_host));
+                        log_it(L_INFO, "\tmask %s", inet_ntoa(s_raw_server->ipv4_network_mask));
+                        log_it(L_INFO, "\taddr %s", inet_ntoa(s_raw_server->ipv4_network_addr));
+                        log_it(L_INFO, "\tlast_addr %s", inet_ntoa(s_raw_server->ipv4_lease_last));
+                        pthread_rwlock_wrlock( &s_clients_rwlock );
+                        HASH_ADD(hh, s_ch_vpn_addrs, addr_ipv4, sizeof (l_ch_vpn->addr_ipv4), l_ch_vpn);
+                        pthread_rwlock_unlock( &s_clients_rwlock );
+
+                        ch_vpn_pkt_t *pkt_out = (ch_vpn_pkt_t*) calloc(1,
+                                sizeof(pkt_out->header) + sizeof(l_ch_vpn->addr_ipv4) + sizeof(s_raw_server->ipv4_host));
+                        pkt_out->header.sock_id = s_raw_server->tun_fd;
+                        pkt_out->header.op_code = VPN_PACKET_OP_CODE_VPN_ADDR_REPLY;
+                        pkt_out->header.op_data.data_size = sizeof(l_ch_vpn->addr_ipv4) + sizeof(s_raw_server->ipv4_host);
+                        pkt_out->header.usage_id = l_usage->id;
+
+                        memcpy(pkt_out->data, &l_ch_vpn->addr_ipv4, sizeof(l_ch_vpn->addr_ipv4));
+                        memcpy(pkt_out->data + sizeof(l_ch_vpn->addr_ipv4), &s_raw_server->ipv4_host,
+                                sizeof(s_raw_server->ipv4_host));
+                        dap_stream_ch_pkt_write(a_ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pkt_out,
+                                pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
+                        s_ch_ready_to_write(a_ch, true);
+
+                        //ch_sf_raw_write(n_addr.s_addr,STREAM_SF_PACKET_OP_CODE_RAW_L3_ADDR_REPLY,&n_addr,sizeof(n_addr));
+                    } else { // All the network is filled with clients, can't lease a new address
+                        log_it(L_WARNING, "All the network is filled with clients, can't lease a new address");
+                        ch_vpn_pkt_t *pkt_out = (ch_vpn_pkt_t*) calloc(1, sizeof(pkt_out->header));
+                        pkt_out->header.sock_id = s_raw_server->tun_fd;
+                        pkt_out->header.op_code = VPN_PACKET_OP_CODE_PROBLEM;
+                        pkt_out->header.usage_id = l_usage->id;
+                        pkt_out->header.op_problem.code = VPN_PROBLEM_CODE_NO_FREE_ADDR;
+                        dap_stream_ch_pkt_write(a_ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pkt_out,
+                                pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
+                        s_ch_ready_to_write(a_ch, true);
+                    }
                 }
             }
                 break;
             case VPN_PACKET_OP_CODE_VPN_SEND: {
                 struct in_addr in_saddr, in_daddr;
-                in_saddr.s_addr = ((struct iphdr*) sf_pkt->data)->saddr;
-                in_daddr.s_addr = ((struct iphdr*) sf_pkt->data)->daddr;
+                in_saddr.s_addr = ((struct iphdr*) l_vpn_pkt->data)->saddr;
+                in_daddr.s_addr = ((struct iphdr*) l_vpn_pkt->data)->daddr;
 
                 char str_daddr[42], str_saddr[42];
                 strncpy(str_saddr, inet_ntoa(in_saddr), sizeof(str_saddr));
@@ -618,17 +801,18 @@ void srv_ch_sf_packet_in(dap_stream_ch_t* ch, void* arg)
                 sin.sin_addr.s_addr = in_daddr.s_addr;
 
                 //if((ret=sendto(CH_SF(ch)->raw_l3_sock , sf_pkt->data,sf_pkt->header.op_data.data_size,0,(struct sockaddr *) &sin, sizeof (sin)))<0){
-                if((ret = write(s_raw_server->tun_fd, sf_pkt->data, sf_pkt->header.op_data.data_size)) < 0) {
+                if((ret = write(s_raw_server->tun_fd, l_vpn_pkt->data, l_vpn_pkt->header.op_data.data_size)) < 0) {
                     log_it(L_ERROR, "write() returned error %d : '%s'", ret, strerror(errno));
                     //log_it(L_ERROR,"raw socket ring buffer overflowed");
                     ch_vpn_pkt_t *pkt_out = (ch_vpn_pkt_t*) calloc(1, sizeof(pkt_out->header));
                     pkt_out->header.op_code = VPN_PACKET_OP_CODE_PROBLEM;
                     pkt_out->header.op_problem.code = VPN_PROBLEM_CODE_PACKET_LOST;
                     pkt_out->header.sock_id = s_raw_server->tun_fd;
-                    dap_stream_ch_pkt_write(ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pkt_out,
+                    dap_stream_ch_pkt_write(a_ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pkt_out,
                             pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
-                    stream_sf_socket_ready_to_write(ch, true);
+                    s_ch_ready_to_write(a_ch, true);
                 } else {
+
                     //log_it(L_DEBUG, "Raw IP packet daddr:%s saddr:%s  %u from %d bytes sent to tun/tap interface",
                     //        str_saddr, str_daddr, sf_pkt->header.op_data.data_size, ret);
                     //log_it(L_DEBUG, "Raw IP sent %u bytes ", ret);
@@ -637,21 +821,21 @@ void srv_ch_sf_packet_in(dap_stream_ch_t* ch, void* arg)
             }
                 break;
             default:
-                log_it(L_WARNING, "Can't process SF type 0x%02x", sf_pkt->header.op_code);
+                log_it(L_WARNING, "Can't process SF type 0x%02x", l_vpn_pkt->header.op_code);
             }
         } else { // All except CONNECT
             ch_vpn_socket_proxy_t * sf_sock = NULL;
-            if(sf_pkt->header.op_code != VPN_PACKET_OP_CODE_CONNECT) {
+            if(l_vpn_pkt->header.op_code != VPN_PACKET_OP_CODE_CONNECT) {
 
-                pthread_mutex_lock(&( CH_VPN(ch)->mutex));
+                pthread_mutex_lock(&( CH_VPN(a_ch)->mutex));
                 //      log_it(L_DEBUG,"Looking in hash table with %d",remote_sock_id);
-                HASH_FIND_INT((CH_VPN(ch)->socks), &remote_sock_id, sf_sock);
-                pthread_mutex_unlock(&( CH_VPN(ch)->mutex));
+                HASH_FIND_INT((CH_VPN(a_ch)->socks), &remote_sock_id, sf_sock);
+                pthread_mutex_unlock(&( CH_VPN(a_ch)->mutex));
 
                 if(sf_sock != NULL) {
                     pthread_mutex_lock(&sf_sock->mutex); // Unlock it in your case as soon as possible to reduce lock time
                     sf_sock->time_lastused = time(NULL);
-                    switch (sf_pkt->header.op_code) {
+                    switch (l_vpn_pkt->header.op_code) {
                     case VPN_PACKET_OP_CODE_SEND: {
                         if(client_connected == false)
                         {
@@ -660,12 +844,12 @@ void srv_ch_sf_packet_in(dap_stream_ch_t* ch, void* arg)
                             break;
                         }
                         int ret;
-                        if((ret = send(sf_sock->sock, sf_pkt->data, sf_pkt->header.op_data.data_size, 0)) < 0) {
+                        if((ret = send(sf_sock->sock, l_vpn_pkt->data, l_vpn_pkt->header.op_data.data_size, 0)) < 0) {
                             log_it(L_INFO, "Disconnected from the remote host");
                             pthread_mutex_unlock(&sf_sock->mutex);
-                            pthread_mutex_lock(&( CH_VPN(ch)->mutex));
-                            HASH_DEL(CH_VPN(ch)->socks, sf_sock);
-                            pthread_mutex_unlock(&( CH_VPN(ch)->mutex));
+                            pthread_mutex_lock(&( CH_VPN(a_ch)->mutex));
+                            HASH_DEL(CH_VPN(a_ch)->socks, sf_sock);
+                            pthread_mutex_unlock(&( CH_VPN(a_ch)->mutex));
 
                             pthread_mutex_lock(&s_sf_socks_mutex);
                             HASH_DELETE(hh2, sf_socks, sf_sock);
@@ -683,7 +867,7 @@ void srv_ch_sf_packet_in(dap_stream_ch_t* ch, void* arg)
                             }
                             pthread_mutex_unlock(&s_sf_socks_mutex);
 
-                            stream_sf_socket_delete(sf_sock);
+                            s_ch_proxy_delete(sf_sock);
                         } else {
                             sf_sock->bytes_sent += ret;
                             pthread_mutex_unlock(&sf_sock->mutex);
@@ -695,9 +879,9 @@ void srv_ch_sf_packet_in(dap_stream_ch_t* ch, void* arg)
                     case VPN_PACKET_OP_CODE_DISCONNECT: {
                         log_it(L_INFO, "Disconnect action from %d sock_id", sf_sock->id);
 
-                        pthread_mutex_lock(&( CH_VPN(ch)->mutex));
-                        HASH_DEL(CH_VPN(ch)->socks, sf_sock);
-                        pthread_mutex_unlock(&( CH_VPN(ch)->mutex));
+                        pthread_mutex_lock(&( CH_VPN(a_ch)->mutex));
+                        HASH_DEL(CH_VPN(a_ch)->socks, sf_sock);
+                        pthread_mutex_unlock(&( CH_VPN(a_ch)->mutex));
 
                         pthread_mutex_lock(&s_sf_socks_mutex);
                         HASH_DELETE(hh2, sf_socks, sf_sock);
@@ -715,11 +899,11 @@ void srv_ch_sf_packet_in(dap_stream_ch_t* ch, void* arg)
                         pthread_mutex_unlock(&s_sf_socks_mutex);
 
                         pthread_mutex_unlock(&sf_sock->mutex);
-                        stream_sf_socket_delete(sf_sock);
+                        s_ch_proxy_delete(sf_sock);
                     }
                         break;
                     default: {
-                        log_it(L_WARNING, "Unprocessed op code 0x%02x", sf_pkt->header.op_code);
+                        log_it(L_WARNING, "Unprocessed op code 0x%02x", l_vpn_pkt->header.op_code);
                         pthread_mutex_unlock(&sf_sock->mutex);
                     }
                     }
@@ -727,27 +911,27 @@ void srv_ch_sf_packet_in(dap_stream_ch_t* ch, void* arg)
                   //  log_it(L_WARNING, "Packet input: packet with sock_id %d thats not present in current stream channel",
                   //          remote_sock_id);
             } else {
-                HASH_FIND_INT(CH_VPN(ch)->socks, &remote_sock_id, sf_sock);
+                HASH_FIND_INT(CH_VPN(a_ch)->socks, &remote_sock_id, sf_sock);
                 if(sf_sock) {
                     log_it(L_WARNING, "Socket id %d is already used, take another number for socket id", remote_sock_id);
                 } else { // Connect action
                     struct sockaddr_in remote_addr;
                     char addr_str[1024];
                     size_t addr_str_size =
-                            (sf_pkt->header.op_connect.addr_size > (sizeof(addr_str) - 1)) ?
+                            (l_vpn_pkt->header.op_connect.addr_size > (sizeof(addr_str) - 1)) ?
                                     (sizeof(addr_str) - 1) :
-                                    sf_pkt->header.op_connect.addr_size;
+                                    l_vpn_pkt->header.op_connect.addr_size;
                     memset(&remote_addr, 0, sizeof(remote_addr));
                     remote_addr.sin_family = AF_INET;
-                    remote_addr.sin_port = htons(sf_pkt->header.op_connect.port);
+                    remote_addr.sin_port = htons(l_vpn_pkt->header.op_connect.port);
 
-                    memcpy(addr_str, sf_pkt->data, addr_str_size);
+                    memcpy(addr_str, l_vpn_pkt->data, addr_str_size);
                     addr_str[addr_str_size] = 0;
 
-                    log_it(L_DEBUG, "Connect action to %s:%u (addr_size %lu)", addr_str, sf_pkt->header.op_connect.port,
-                            sf_pkt->header.op_connect.addr_size);
+                    log_it(L_DEBUG, "Connect action to %s:%u (addr_size %lu)", addr_str, l_vpn_pkt->header.op_connect.port,
+                            l_vpn_pkt->header.op_connect.addr_size);
                     if(inet_pton(AF_INET, addr_str, &(remote_addr.sin_addr)) < 0) {
-                        log_it(L_ERROR, "Wrong remote address '%s:%u'", addr_str, sf_pkt->header.op_connect.port);
+                        log_it(L_ERROR, "Wrong remote address '%s:%u'", addr_str, l_vpn_pkt->header.op_connect.port);
                     } else {
                         int s;
                         if((s = socket(AF_INET, SOCK_STREAM, 0)) >= 0) {
@@ -755,17 +939,17 @@ void srv_ch_sf_packet_in(dap_stream_ch_t* ch, void* arg)
                             if(connect(s, (struct sockaddr *) &remote_addr, sizeof(remote_addr)) >= 0) {
                                 fcntl(s, F_SETFL, O_NONBLOCK);
                                 log_it(L_INFO, "Remote address connected (%s:%u) with sock_id %d", addr_str,
-                                        sf_pkt->header.op_connect.port, remote_sock_id);
+                                        l_vpn_pkt->header.op_connect.port, remote_sock_id);
                                 ch_vpn_socket_proxy_t * sf_sock = NULL;
                                 sf_sock = DAP_NEW_Z(ch_vpn_socket_proxy_t);
                                 sf_sock->id = remote_sock_id;
                                 sf_sock->sock = s;
-                                sf_sock->ch = ch;
+                                sf_sock->ch = a_ch;
                                 pthread_mutex_init(&sf_sock->mutex, NULL);
 
                                 pthread_mutex_lock(&s_sf_socks_mutex);
-                                pthread_mutex_lock(&( CH_VPN(ch)->mutex));
-                                HASH_ADD_INT(CH_VPN(ch)->socks, id, sf_sock);
+                                pthread_mutex_lock(&( CH_VPN(a_ch)->mutex));
+                                HASH_ADD_INT(CH_VPN(a_ch)->socks, id, sf_sock);
                                 log_it(L_DEBUG, "Added %d sock_id with sock %d to the hash table", sf_sock->id,
                                         sf_sock->sock);
                                 HASH_ADD(hh2, sf_socks, id, sizeof(sf_sock->id), sf_sock);
@@ -774,7 +958,7 @@ void srv_ch_sf_packet_in(dap_stream_ch_t* ch, void* arg)
                                 HASH_ADD(hh_sock, sf_socks_client, sock, sizeof(int), sf_sock);
                                 //log_it(L_DEBUG,"Added %d sock_id with sock %d to the socks hash table",sf->id,sf->sock);
                                 pthread_mutex_unlock(&s_sf_socks_mutex);
-                                pthread_mutex_unlock(&( CH_VPN(ch)->mutex));
+                                pthread_mutex_unlock(&( CH_VPN(a_ch)->mutex));
 
                                 struct epoll_event ev;
                                 ev.data.fd = s;
@@ -789,17 +973,17 @@ void srv_ch_sf_packet_in(dap_stream_ch_t* ch, void* arg)
                                     ch_vpn_pkt_t *pkt_out = (ch_vpn_pkt_t*) calloc(1, sizeof(pkt_out->header));
                                     pkt_out->header.sock_id = remote_sock_id;
                                     pkt_out->header.op_code = VPN_PACKET_OP_CODE_CONNECTED;
-                                    dap_stream_ch_pkt_write(ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_CLIENT, pkt_out,
+                                    dap_stream_ch_pkt_write(a_ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_CLIENT, pkt_out,
                                             pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
                                     free(pkt_out);
                                     client_connected = true;
                                 }
-                                stream_sf_socket_ready_to_write(ch, true);
+                                s_ch_ready_to_write(a_ch, true);
                             } else {
                                 log_it(L_INFO, "Can't connect to the remote server %s", addr_str);
-                                dap_stream_ch_pkt_write_f(ch, 'i', "sock_id=%d op_code=%c result=-1",
-                                        sf_pkt->header.sock_id, sf_pkt->header.op_code);
-                                stream_sf_socket_ready_to_write(ch, true);
+                                dap_stream_ch_pkt_write_f(a_ch, 'i', "sock_id=%d op_code=%c result=-1",
+                                        l_vpn_pkt->header.sock_id, l_vpn_pkt->header.op_code);
+                                s_ch_ready_to_write(a_ch, true);
                             }
                         } else {
                             log_it(L_ERROR, "Can't create the socket");
@@ -895,12 +1079,12 @@ void * srv_ch_sf_thread(void * arg)
                             memcpy(pout->data, buf, buf_size);
                             sf->pkt_out_size++;
                             pthread_mutex_unlock(&(sf->mutex));
-                            stream_sf_socket_ready_to_write(sf->ch, true);
+                            s_ch_ready_to_write(sf->ch, true);
                         } else {
                             log_it(L_NOTICE,
                                     "Socket id %d returned error on recv() function - may be host has disconnected", s);
                             pthread_mutex_unlock(&(sf->mutex));
-                            stream_sf_socket_ready_to_write(sf->ch, true);
+                            s_ch_ready_to_write(sf->ch, true);
                             srv_stream_sf_disconnect(sf);
                         }
                     } else {
@@ -974,6 +1158,7 @@ void* srv_ch_sf_thread_raw(void *arg)
                     }
                 }
             }
+
             if(FD_ISSET(s_raw_server->tun_fd, &fds_read_active)) {
                 int read_ret = read(s_raw_server->tun_fd, tmp_buf, tun_MTU);
                 if(read_ret < 0) {
@@ -990,22 +1175,24 @@ void* srv_ch_sf_thread_raw(void *arg)
 
                     //log_it(L_DEBUG, "Read IP packet from tun/tap interface daddr=%s saddr=%s total_size = %d "
                     //        , str_daddr, str_saddr, read_ret);
-                    dap_stream_ch_vpn_remote_single_t * raw_client = NULL;
-                    pthread_mutex_lock(&s_raw_server->clients_mutex);
-                    HASH_FIND_INT(s_raw_server->clients, &in_daddr.s_addr, raw_client);
+                    dap_chain_net_srv_ch_vpn_t * l_ch_vpn = NULL;
+                    pthread_rwlock_rdlock(&s_clients_rwlock);
+                    HASH_FIND(hh,s_ch_vpn_addrs, &in_daddr, sizeof (in_daddr), l_ch_vpn);
 //                  HASH_ADD_INT(CH_SF(ch)->socks, id, sf_sock );
 //                  HASH_DEL(CH_SF(ch)->socks,sf_sock);
-                    if(raw_client) { // Is present in hash table such destination address
+
+                    ///
+                    if(l_ch_vpn) { // Is present in hash table such destination address
                         ch_vpn_pkt_t *pkt_out = (ch_vpn_pkt_t*) calloc(1, sizeof(pkt_out->header) + read_ret);
                         pkt_out->header.op_code = VPN_PACKET_OP_CODE_VPN_RECV;
                         pkt_out->header.sock_id = s_raw_server->tun_fd;
                         pkt_out->header.op_data.data_size = read_ret;
                         memcpy(pkt_out->data, tmp_buf, read_ret);
-                        dap_stream_ch_pkt_write(raw_client->ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pkt_out,
+                        dap_stream_ch_pkt_write(l_ch_vpn->ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pkt_out,
                                 pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
-                        stream_sf_socket_ready_to_write(raw_client->ch, true);
+                        s_ch_ready_to_write(l_ch_vpn->ch, true);
                     }
-                    pthread_mutex_unlock(&s_raw_server->clients_mutex);
+                    pthread_rwlock_unlock(&s_clients_rwlock);
                 }
             }/*else {
              log_it(L_CRITICAL,"select() has no tun handler in the returned set");
@@ -1022,69 +1209,4 @@ void* srv_ch_sf_thread_raw(void *arg)
     return NULL;
 }
 
-/**
- * @brief stream_sf_packet_out Packet Out Ch callback
- * @param ch
- * @param arg
- */
-void srv_ch_sf_packet_out(dap_stream_ch_t* ch, void* arg)
-{
-    ch_vpn_socket_proxy_t * cur, *tmp;
-    bool isSmthOut = false;
-//    log_it(L_DEBUG,"Socket forwarding packet out callback: %u sockets in hashtable", HASH_COUNT(CH_SF(ch)->socks) );
-    HASH_ITER(hh, CH_VPN(ch)->socks , cur, tmp)
-    {
-        bool signalToBreak = false;
-        pthread_mutex_lock(&(cur->mutex));
-        int i;
-        //log_it(L_DEBUG, "Socket with id %d has %u packets in output buffer", cur->id, cur->pkt_out_size);
-        if(cur->pkt_out_size) {
-            for(i = 0; i < cur->pkt_out_size; i++) {
-                ch_vpn_pkt_t * pout = cur->pkt_out[i];
-                if(pout) {
-                    if(dap_stream_ch_pkt_write(ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pout,
-                            pout->header.op_data.data_size + sizeof(pout->header))) {
-                        isSmthOut = true;
-                        free(pout);
-                        cur->pkt_out[i] = NULL;
-                    } else {
-                        //log_it(L_WARNING,
-                        //        "Buffer is overflowed, breaking cycle to let the upper level cycle drop data to the output socket");
-                        isSmthOut = true;
-                        signalToBreak = true;
-                        break;
-                    }
-                }
-            }
-        }
-
-        if(signalToBreak) {
-            pthread_mutex_unlock(&(cur->mutex));
-            break;
-        }
-        cur->pkt_out_size = 0;
-        if(cur->signal_to_delete) {
-            log_it(L_NOTICE, "Socket id %d got signal to be deleted", cur->id);
-            pthread_mutex_lock(&( CH_VPN(ch)->mutex));
-            HASH_DEL(CH_VPN(ch)->socks, cur);
-            pthread_mutex_unlock(&( CH_VPN(ch)->mutex));
-
-            pthread_mutex_lock(&(s_sf_socks_mutex));
-            HASH_DELETE(hh2, sf_socks, cur);
-            HASH_DELETE(hh_sock, sf_socks_client, cur);
-            pthread_mutex_unlock(&(s_sf_socks_mutex));
-
-            pthread_mutex_unlock(&(cur->mutex));
-            stream_sf_socket_delete(cur);
-        } else
-            pthread_mutex_unlock(&(cur->mutex));
-    }
-    ch->ready_to_write = isSmthOut;
-    if(isSmthOut) {
-        ch->stream->conn_http->state_write = DAP_HTTP_CLIENT_STATE_DATA;
-    }
-    dap_client_remote_ready_to_write(ch->stream->conn, isSmthOut);
-    //dap_stream_ch_set_ready_to_write(ch, isSmthOut);
-
-}
 
diff --git a/dap_chain_net_srv_vpn.h b/dap_chain_net_srv_vpn.h
index c479a71..3e617ed 100755
--- a/dap_chain_net_srv_vpn.h
+++ b/dap_chain_net_srv_vpn.h
@@ -46,9 +46,10 @@
 #define VPN_PACKET_OP_CODE_RECV             0x000000ad
 #define VPN_PACKET_OP_CODE_PROBLEM          0x000000ae
 
-#define VPN_PROBLEM_CODE_NO_FREE_ADDR       0x00000001
-#define VPN_PROBLEM_CODE_TUNNEL_DOWN        0x00000002
-#define VPN_PROBLEM_CODE_PACKET_LOST        0x00000003
+#define VPN_PROBLEM_CODE_NO_FREE_ADDR                0x00000001
+#define VPN_PROBLEM_CODE_TUNNEL_DOWN                 0x00000002
+#define VPN_PROBLEM_CODE_PACKET_LOST                 0x00000003
+#define VPN_PROBLEM_CODE_ALREADY_ASSIGNED_ADDR       0x00000004
 
 #define VPN_PACKET_OP_CODE_VPN_METADATA     0x000000b0
 #define VPN_PACKET_OP_CODE_VPN_RESERVED     0x000000b1
@@ -61,25 +62,11 @@
 #define VPN_PACKET_OP_CODE_PING             0xc0
 #define VPN_PACKET_OP_CODE_PONG             0xc1
 
-typedef struct dap_stream_ch_vpn_remote_single { //
-#ifdef DAP_OS_UNIX
-    in_addr_t addr_ipv4;
-#else
-    uint32_t addr_ipv4;
-#endif
-//    pthread_mutex_t mutex;
-    dap_stream_ch_t * ch;
-
-    uint64_t bytes_sent;
-    uint64_t bytes_recieved;
-
-    UT_hash_handle hh;
-} dap_stream_ch_vpn_remote_single_t;
-
 typedef struct ch_vpn_pkt {
     struct {
         int sock_id; // Client's socket id
         uint32_t op_code; // Operation code
+        uint32_t usage_id; // Usage id (for multinetworking)
         union {
             struct { // L4 connect operation
                 uint32_t addr_size;
@@ -99,9 +86,9 @@ typedef struct ch_vpn_pkt {
                 uint32_t padding2;
             } raw; // Raw access to OP bytes
         };
-    }__attribute__((packed)) header;
+    } DAP_ALIGN_PACKED header;
     uint8_t data[]; // Binary data nested by packet
-}__attribute__((packed)) ch_vpn_pkt_t;
+}DAP_ALIGN_PACKED ch_vpn_pkt_t;
 
 /**
  * @struct ch_vpn_socket_proxy
@@ -138,19 +125,36 @@ typedef struct ch_vpn_socket_proxy {
  *
  *
  **/
-typedef struct dap_chain_net_srv_vpn
+typedef struct dap_chain_net_srv_ch_vpn
 {
-    dap_chain_net_srv_t net_srv;
+    uint32_t usage_id;
+    dap_chain_net_srv_t* net_srv;
     //dap_chain_net_srv_uid_t srv_uid; // Unique ID for service.
     pthread_mutex_t mutex;
     ch_vpn_socket_proxy_t * socks;
     int raw_l3_sock;
+    bool is_allowed;
+
 
+    struct in_addr addr_ipv4;
     dap_stream_ch_t * ch;
-    dap_ledger_t *ledger;
+    UT_hash_handle hh;
+} dap_chain_net_srv_ch_vpn_t;
+
+
+typedef struct dap_chain_net_srv_vpn_item_ipv4{
+    struct in_addr addr;
+    struct dap_chain_net_srv_vpn_item_ipv4 * next;
+} dap_chain_net_srv_vpn_item_ipv4_t;
+
+typedef struct dap_chain_net_srv_vpn
+{
+    dap_chain_net_srv_vpn_item_ipv4_t * ipv4_unleased;
+    dap_chain_net_srv_ch_vpn_t * ch_vpn_ipv4;
+    dap_chain_net_srv_t * parent;
 } dap_chain_net_srv_vpn_t;
 
-#define CH_VPN(a) ((dap_chain_net_srv_vpn_t *) ((a)->internal) )
+#define CH_VPN(a) ((dap_chain_net_srv_ch_vpn_t *) ((a)->internal) )
 
 int dap_chain_net_srv_vpn_init(dap_config_t * g_config);
 void dap_chain_net_srv_vpn_deinit(void);
diff --git a/dap_chain_net_vpn_client_tun.c b/dap_chain_net_vpn_client_tun.c
index d77b8c3..ef786d3 100644
--- a/dap_chain_net_vpn_client_tun.c
+++ b/dap_chain_net_vpn_client_tun.c
@@ -563,7 +563,7 @@ static void ch_sf_pkt_send(dap_stream_ch_t * a_ch, void * a_data, size_t a_data_
     dap_stream_ch_set_ready_to_write(a_ch, true);
 }
 
-void ch_sf_tun_send(dap_chain_net_srv_vpn_t * ch_sf, void * pkt_data, size_t pkt_data_size) {
+void ch_sf_tun_send(dap_chain_net_srv_ch_vpn_t * ch_sf, void * pkt_data, size_t pkt_data_size) {
     bool passPacket = true;
     /*switch(ch_sf_snort_pkt(pkt_data,pkt_data_size)){
      case SNORT_ALERT: passPacket=false; break;
@@ -627,7 +627,7 @@ void ch_sf_tun_send(dap_chain_net_srv_vpn_t * ch_sf, void * pkt_data, size_t pkt
  * @param a_pkt
  * @param a_pkt_data_size
  */
-int ch_sf_tun_addr_leased(dap_chain_net_srv_vpn_t * a_sf, ch_vpn_pkt_t * a_pkt, size_t a_pkt_data_size)
+int ch_sf_tun_addr_leased(dap_chain_net_srv_ch_vpn_t * a_sf, ch_vpn_pkt_t * a_pkt, size_t a_pkt_data_size)
 {
     // we'd receive address assigment from server
     struct in_addr l_addr = { 0 };
diff --git a/dap_chain_net_vpn_client_tun.h b/dap_chain_net_vpn_client_tun.h
index d495604..250b638 100644
--- a/dap_chain_net_vpn_client_tun.h
+++ b/dap_chain_net_vpn_client_tun.h
@@ -22,10 +22,12 @@
  along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#pragma once
+#include "dap_chain_net_srv_vpn.h"
 
 int dap_chain_net_vpn_client_tun_init(const char *a_ipv4_gw_str);
 int dap_chain_net_vpn_client_tun_create(const char *a_ipv4_addr_str, const char *a_ipv4_gw_str);
 int dap_chain_net_vpn_client_tun_delete(void);
 int dap_chain_net_vpn_client_tun_status(void);
 
-int ch_sf_tun_addr_leased(dap_chain_net_srv_vpn_t * a_sf, ch_vpn_pkt_t * a_pkt, size_t a_pkt_data_size);
+int ch_sf_tun_addr_leased(dap_chain_net_srv_ch_vpn_t * a_sf, ch_vpn_pkt_t * a_pkt, size_t a_pkt_data_size);
-- 
GitLab