diff --git a/3rdparty/uthash/src/utarray.h b/3rdparty/uthash/src/utarray.h
index 6ed0dcebcb170136209d3e35d6882694b0e5ec1f..6b6201820e0a0b78a289cf555d793c3626549ae6 100644
--- a/3rdparty/uthash/src/utarray.h
+++ b/3rdparty/uthash/src/utarray.h
@@ -38,8 +38,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define UTARRAY_UNUSED
 #endif
 
-#ifndef oom
-#define oom() exit(-1)
+#ifdef oom
+#error "The name of macro 'oom' has been changed to 'utarray_oom'. Please update your code."
+#define utarray_oom() oom()
+#endif
+
+#ifndef utarray_oom
+#define utarray_oom() exit(-1)
 #endif
 
 typedef void (ctor_f)(void *dst, const void *src);
@@ -78,7 +83,9 @@ typedef struct {
 
 #define utarray_new(a,_icd) do {                                              \
   (a) = (UT_array*)malloc(sizeof(UT_array));                                  \
-  if ((a) == NULL) oom();                                                     \
+  if ((a) == NULL) {                                                          \
+    utarray_oom();                                                            \
+  }                                                                           \
   utarray_init(a,_icd);                                                       \
 } while(0)
 
@@ -92,7 +99,9 @@ typedef struct {
     char *utarray_tmp;                                                        \
     while (((a)->i+(by)) > (a)->n) { (a)->n = ((a)->n ? (2*(a)->n) : 8); }    \
     utarray_tmp=(char*)realloc((a)->d, (a)->n*(a)->icd.sz);                   \
-    if (utarray_tmp == NULL) oom();                                           \
+    if (utarray_tmp == NULL) {                                                \
+      utarray_oom();                                                          \
+    }                                                                         \
     (a)->d=utarray_tmp;                                                       \
   }                                                                           \
 } while(0)
@@ -118,7 +127,7 @@ typedef struct {
 #define utarray_len(a) ((a)->i)
 
 #define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL)
-#define _utarray_eltptr(a,j) ((a)->d + ((a)->icd.sz * (j)))
+#define _utarray_eltptr(a,j) ((void*)((a)->d + ((a)->icd.sz * (j))))
 
 #define utarray_insert(a,p,j) do {                                            \
   if ((j) > (a)->i) utarray_resize(a,j);                                      \
@@ -216,10 +225,10 @@ typedef struct {
 #define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp)
 
 #define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL)
-#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL))
-#define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) > 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL))
+#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : (((a)->i != utarray_eltidx(a,e)+1) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL))
+#define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) != 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL))
 #define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL)
-#define utarray_eltidx(a,e) (((char*)(e) >= (a)->d) ? (((char*)(e) - (a)->d)/(a)->icd.sz) : -1)
+#define utarray_eltidx(a,e) (((char*)(e) - (a)->d) / (a)->icd.sz)
 
 /* last we pre-define a few icd for common utarrays of ints and strings */
 static void utarray_str_cpy(void *dst, const void *src) {
diff --git a/3rdparty/uthash/src/uthash.h b/3rdparty/uthash/src/uthash.h
index 76bdca64199f11dbb6387633e2a651dcaee1bb4f..5e5866a353869bc8328f5d9a6fd0a41003a431a5 100644
--- a/3rdparty/uthash/src/uthash.h
+++ b/3rdparty/uthash/src/uthash.h
@@ -144,7 +144,7 @@ typedef unsigned char uint8_t;
 /* calculate the element whose hash handle address is hhp */
 #define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
 /* calculate the hash handle from element address elp */
-#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle *)(((char*)(elp)) + ((tbl)->hho)))
+#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle*)(void*)(((char*)(elp)) + ((tbl)->hho)))
 
 #define HASH_ROLLBACK_BKT(hh, head, itemptrhh)                                   \
 do {                                                                             \
@@ -175,9 +175,12 @@ do {
 
 #define HASH_FIND(hh,head,keyptr,keylen,out)                                     \
 do {                                                                             \
-  unsigned _hf_hashv;                                                            \
-  HASH_VALUE(keyptr, keylen, _hf_hashv);                                         \
-  HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out);               \
+  (out) = NULL;                                                                  \
+  if (head) {                                                                    \
+    unsigned _hf_hashv;                                                          \
+    HASH_VALUE(keyptr, keylen, _hf_hashv);                                       \
+    HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out);             \
+  }                                                                              \
 } while (0)
 
 #ifdef HASH_BLOOM
@@ -519,7 +522,8 @@ do {
  * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
  */
 #ifdef HASH_DEBUG
-#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)
+#include <stdio.h>   /* fprintf, stderr */
+#define HASH_OOPS(...) do { fprintf(stderr, __VA_ARGS__); exit(-1); } while (0)
 #define HASH_FSCK(hh,head,where)                                                 \
 do {                                                                             \
   struct UT_hash_handle *_thh;                                                   \
@@ -750,87 +754,6 @@ do {
   hashv += hashv >> 6;                                                           \
 } while (0)
 
-#ifdef HASH_USING_NO_STRICT_ALIASING
-/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads.
- * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
- * MurmurHash uses the faster approach only on CPU's where we know it's safe.
- *
- * Note the preprocessor built-in defines can be emitted using:
- *
- *   gcc -m64 -dM -E - < /dev/null                  (on gcc)
- *   cc -## a.c (where a.c is a simple test file)   (Sun Studio)
- */
-#if (defined(__i386__) || defined(__x86_64__)  || defined(_M_IX86))
-#define MUR_GETBLOCK(p,i) p[i]
-#else /* non intel */
-#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 3UL) == 0UL)
-#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 3UL) == 1UL)
-#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 3UL) == 2UL)
-#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 3UL) == 3UL)
-#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL))
-#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__))
-#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24))
-#define MUR_TWO_TWO(p)   ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16))
-#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >>  8))
-#else /* assume little endian non-intel */
-#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24))
-#define MUR_TWO_TWO(p)   ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16))
-#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) <<  8))
-#endif
-#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) :           \
-                            (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \
-                             (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) :  \
-                                                      MUR_ONE_THREE(p))))
-#endif
-#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r))))
-#define MUR_FMIX(_h) \
-do {                 \
-  _h ^= _h >> 16;    \
-  _h *= 0x85ebca6bu; \
-  _h ^= _h >> 13;    \
-  _h *= 0xc2b2ae35u; \
-  _h ^= _h >> 16;    \
-} while (0)
-
-#define HASH_MUR(key,keylen,hashv)                                     \
-do {                                                                   \
-  const uint8_t *_mur_data = (const uint8_t*)(key);                    \
-  const int _mur_nblocks = (int)(keylen) / 4;                          \
-  uint32_t _mur_h1 = 0xf88D5353u;                                      \
-  uint32_t _mur_c1 = 0xcc9e2d51u;                                      \
-  uint32_t _mur_c2 = 0x1b873593u;                                      \
-  uint32_t _mur_k1 = 0;                                                \
-  const uint8_t *_mur_tail;                                            \
-  const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+(_mur_nblocks*4)); \
-  int _mur_i;                                                          \
-  for (_mur_i = -_mur_nblocks; _mur_i != 0; _mur_i++) {                \
-    _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i);                        \
-    _mur_k1 *= _mur_c1;                                                \
-    _mur_k1 = MUR_ROTL32(_mur_k1,15);                                  \
-    _mur_k1 *= _mur_c2;                                                \
-                                                                       \
-    _mur_h1 ^= _mur_k1;                                                \
-    _mur_h1 = MUR_ROTL32(_mur_h1,13);                                  \
-    _mur_h1 = (_mur_h1*5U) + 0xe6546b64u;                              \
-  }                                                                    \
-  _mur_tail = (const uint8_t*)(_mur_data + (_mur_nblocks*4));          \
-  _mur_k1=0;                                                           \
-  switch ((keylen) & 3U) {                                             \
-    case 0: break;                                                     \
-    case 3: _mur_k1 ^= (uint32_t)_mur_tail[2] << 16; /* FALLTHROUGH */ \
-    case 2: _mur_k1 ^= (uint32_t)_mur_tail[1] << 8;  /* FALLTHROUGH */ \
-    case 1: _mur_k1 ^= (uint32_t)_mur_tail[0];                         \
-    _mur_k1 *= _mur_c1;                                                \
-    _mur_k1 = MUR_ROTL32(_mur_k1,15);                                  \
-    _mur_k1 *= _mur_c2;                                                \
-    _mur_h1 ^= _mur_k1;                                                \
-  }                                                                    \
-  _mur_h1 ^= (uint32_t)(keylen);                                       \
-  MUR_FMIX(_mur_h1);                                                   \
-  hashv = _mur_h1;                                                     \
-} while (0)
-#endif  /* HASH_USING_NO_STRICT_ALIASING */
-
 /* iterate over items in a known bucket to find desired item */
 #define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out)               \
 do {                                                                             \
@@ -1080,7 +1003,7 @@ do {
         _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh);                         \
         if (cond(_elt)) {                                                        \
           IF_HASH_NONFATAL_OOM( int _hs_oomed = 0; )                             \
-          _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho);                 \
+          _dst_hh = (UT_hash_handle*)(void*)(((char*)_elt) + _dst_hho);          \
           _dst_hh->key = _src_hh->key;                                           \
           _dst_hh->keylen = _src_hh->keylen;                                     \
           _dst_hh->hashv = _src_hh->hashv;                                       \
diff --git a/3rdparty/uthash/src/utstring.h b/3rdparty/uthash/src/utstring.h
index ca25c902ca585720fe6427037ac5eac74f677ea5..4cf5ffd3dd42128ee8f46c56153ad572930f6ba2 100644
--- a/3rdparty/uthash/src/utstring.h
+++ b/3rdparty/uthash/src/utstring.h
@@ -39,8 +39,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define UTSTRING_UNUSED
 #endif
 
-#ifndef oom
-#define oom() exit(-1)
+#ifdef oom
+#error "The name of macro 'oom' has been changed to 'utstring_oom'. Please update your code."
+#define utstring_oom() oom()
+#endif
+
+#ifndef utstring_oom
+#define utstring_oom() exit(-1)
 #endif
 
 typedef struct {
@@ -54,7 +59,9 @@ do {                                                       \
   if (((s)->n - (s)->i) < (size_t)(amt)) {                 \
     char *utstring_tmp = (char*)realloc(                   \
       (s)->d, (s)->n + (amt));                             \
-    if (utstring_tmp == NULL) oom();                       \
+    if (!utstring_tmp) {                                   \
+      utstring_oom();                                      \
+    }                                                      \
     (s)->d = utstring_tmp;                                 \
     (s)->n += (amt);                                       \
   }                                                        \
@@ -81,9 +88,11 @@ do {                                                       \
 
 #define utstring_new(s)                                    \
 do {                                                       \
-   (s) = (UT_string*)malloc(sizeof(UT_string));            \
-   if (!(s)) oom();                                        \
-   utstring_init(s);                                       \
+  (s) = (UT_string*)malloc(sizeof(UT_string));             \
+  if (!(s)) {                                              \
+    utstring_oom();                                        \
+  }                                                        \
+  utstring_init(s);                                        \
 } while(0)
 
 #define utstring_renew(s)                                  \
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ffdd0d382392a60f3576763f64459b0fd9449488..78a20014107b6486344743aa1f369881256b07d9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,7 @@ project(cellframe-sdk C)
 cmake_minimum_required(VERSION 2.8)
 
 set(CMAKE_C_STANDARD 11)
-set(CELLFRAME_SDK_NATIVE_VERSION "2.3-4")
+set(CELLFRAME_SDK_NATIVE_VERSION "2.5-14")
 add_definitions ("-DCELLFRAME_SDK_VERSION=\"${CELLFRAME_SDK_NATIVE_VERSION}\"")
 
 set(DAPSDK_MODULES "")
diff --git a/cmake/OS_Detection.cmake b/cmake/OS_Detection.cmake
index f0be4d78b5fd2ccf926b81f99305cb8ec25dac70..e2801cf8ddc932e28369f4f312750cffc7af1539 100644
--- a/cmake/OS_Detection.cmake
+++ b/cmake/OS_Detection.cmake
@@ -54,11 +54,11 @@ if(UNIX)
     add_definitions ("-DDAP_OS_LINUX -DDAP_OS_UNIX")
     # add_definitions ("-DDAP_LOG_MT")
     if(DAP_DEBUG)
-      set(_CCOPT "-DDAP_DEBUG -Wall -Wno-deprecated-declarations -Wno-unused-local-typedefs -Wno-unused-function -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable -pg -g3 -ggdb -fno-eliminate-unused-debug-symbols")
+      set(_CCOPT "-DDAP_DEBUG -Wall -Wno-deprecated-declarations -Wno-unused-local-typedefs -Wno-unused-function -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable -pg -g3 -ggdb -fno-eliminate-unused-debug-symbols -fno-strict-aliasing")
       set(_LOPT "-pg")
       SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pg")
     else()
-        set(_CCOPT "-Wno-deprecated-declarations -Wno-unused-local-typedefs -Wno-unused-function -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable -O3 -fPIC -fno-ident -ffast-math -ftree-vectorize -fno-asynchronous-unwind-tables -ffunction-sections -Wl,--gc-sections -Wl,--strip-all -std=gnu11")
+        set(_CCOPT "-Wno-deprecated-declarations -Wno-unused-local-typedefs -Wno-unused-function -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable -O3 -fPIC -fno-strict-aliasing -fno-ident -ffast-math -ftree-vectorize -fno-asynchronous-unwind-tables -ffunction-sections -Wl,--gc-sections -Wl,--strip-all -std=gnu11")
     endif()
 
     if (ANDROID)
@@ -99,10 +99,10 @@ if(WIN32)
     add_definitions ("-DDAP_OS_WINDOWS")
 
      if(DAP_DEBUG)
-      set(_CCOPT "-mconsole -static -Wall -std=gnu11 -Wextra -Wno-deprecated-declarations -Wno-unused-local-typedefs -Wno-unused-function -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable -g3 -ggdb -fno-eliminate-unused-debug-symbols -pg")
+      set(_CCOPT "-mconsole -static -Wall -std=gnu11 -Wextra -Wno-deprecated-declarations -Wno-unused-local-typedefs -Wno-unused-function -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable -g3 -ggdb -fno-strict-aliasing -fno-eliminate-unused-debug-symbols -pg")
       set(_LOPT "-mconsole -static -pg")
     else()
-      set(_CCOPT "-static -std=gnu11 -Wall -Wextra -Wno-deprecated-declarations -Wno-unused-local-typedefs -Wno-unused-function -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable -O3 -fno-ident -ffast-math -ftree-vectorize -mfpmath=sse -mmmx -msse2 -fno-asynchronous-unwind-tables -ffunction-sections -Wl,--gc-sections -Wl,--strip-all")
+      set(_CCOPT "-static -std=gnu11 -Wall -Wextra -Wno-deprecated-declarations -Wno-unused-local-typedefs -Wno-unused-function -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable -O3 -fno-ident -ffast-math -fno-strict-aliasing -ftree-vectorize -mfpmath=sse -mmmx -msse2 -fno-asynchronous-unwind-tables -ffunction-sections -Wl,--gc-sections -Wl,--strip-all")
     endif()
 
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_CCOPT} ")
diff --git a/dap-sdk/CMakeLists.txt b/dap-sdk/CMakeLists.txt
index 89f2652ec8d5e66e2fb9f976a739d8db2dda8831..cc44d581e1355d8536edad52b489ecc24a46f550 100644
--- a/dap-sdk/CMakeLists.txt
+++ b/dap-sdk/CMakeLists.txt
@@ -1,3 +1,4 @@
+set(DAP_SDK_NATIVE_VERSION "2.0-11")
 # Core 
 if (DAPSDK_MODULES MATCHES "core")
     # Core
diff --git a/dap-sdk/core/CMakeLists.txt b/dap-sdk/core/CMakeLists.txt
index b9c659ff124ce96e65668f0cc490d15f2a1bcbcb..cd185b4c47bce90ad7758654b64ad5204709c722 100755
--- a/dap-sdk/core/CMakeLists.txt
+++ b/dap-sdk/core/CMakeLists.txt
@@ -1,9 +1,8 @@
 cmake_minimum_required(VERSION 3.0)
 project (dap_core)
 
-# fix implicit declaration warnings
-add_definitions ("-D_GNU_SOURCE")
-
+add_definitions("-D_GNU_SOURCE") 
+add_definitions("-DDHASH_USING_NO_STRICT_ALIASING -DHASH_FUNCTION=HASH_MUR")
 if(UNIX)
   file(GLOB CORE_SRCS 
       src/*.c 
diff --git a/dap-sdk/core/include/dap_common.h b/dap-sdk/core/include/dap_common.h
index 1fb9ca8e86abc5ef747ab17ca38a953b81cb93fb..ea2a41ab94901868dd8158c9735d2825258a9821 100755
--- a/dap-sdk/core/include/dap_common.h
+++ b/dap-sdk/core/include/dap_common.h
@@ -162,6 +162,20 @@ DAP_STATIC_INLINE void _dap_aligned_free( void *ptr )
 
 #define DAP_PROTOCOL_VERSION  22
 
+#if __SIZEOF_LONG__==8
+#define DAP_UINT64_FORMAT_X  "lX"
+#define     DAP_UINT64_FORMAT_x  "lx"
+#define DAP_UINT64_FORMAT_u  "lu"
+#define DAP_UINT64_FORMAT_U  "lU"
+#elif __SIZEOF_LONG__==4
+#define DAP_UINT64_FORMAT_X  "llX"
+#define DAP_UINT64_FORMAT_x  "llx"
+#define DAP_UINT64_FORMAT_u  "llu"
+#define DAP_UINT64_FORMAT_U  "llU"
+#else
+#error "DAP_UINT64_FORMAT_* are undefined for your platform"
+#endif
+
 #ifndef LOWORD
   #define LOWORD( l ) ((uint16_t) (((uintptr_t) (l)) & 0xFFFF))
   #define HIWORD( l ) ((uint16_t) ((((uintptr_t) (l)) >> 16) & 0xFFFF))
@@ -412,6 +426,12 @@ void dap_lendian_put32(uint8_t *a_buf, uint32_t a_val);
 uint64_t dap_lendian_get64(const uint8_t *a_buf);
 void dap_lendian_put64(uint8_t *a_buf, uint64_t a_val);
 
+// crossplatform usleep
+#define DAP_USEC_PER_SEC 1000000
+void dap_usleep(time_t a_microseconds);
+
+
+
 #ifdef __MINGW32__
 int exec_silent(const char *a_cmd);
 #endif
diff --git a/dap-sdk/core/include/dap_strfuncs.h b/dap-sdk/core/include/dap_strfuncs.h
index 79f00942eaeb5050de51017e3d9ab36b2cd165e6..b929c3a891bf169fc475dfbc52f9a1f5a604f0db 100755
--- a/dap-sdk/core/include/dap_strfuncs.h
+++ b/dap-sdk/core/include/dap_strfuncs.h
@@ -112,6 +112,3 @@ char *dap_itoa128(char *a_str, int128_t a_value, int a_base);
 char *_strndup(const char *str, unsigned long len);
 #endif
 
-#define DAP_USEC_PER_SEC 1000000
-void dap_usleep(time_t a_microseconds);
-
diff --git a/dap-sdk/core/src/dap_common.c b/dap-sdk/core/src/dap_common.c
index 7d7f37c4738c5a4ab9111d302a62d3e03097fe0e..800425970092a112cf1d408ccb5a8b2d3a2c36e9 100755
--- a/dap-sdk/core/src/dap_common.c
+++ b/dap-sdk/core/src/dap_common.c
@@ -1041,3 +1041,23 @@ void dap_lendian_put64(uint8_t *a_buf, uint64_t a_val)
     dap_lendian_put32(a_buf, a_val);
     dap_lendian_put32(a_buf + 4, a_val >> 32);
 }
+
+/**
+ * dap_usleep:
+ * @a_microseconds: number of microseconds to pause
+ *
+ * Pauses the current thread for the given number of microseconds.
+ */
+void dap_usleep(time_t a_microseconds)
+{
+#ifdef DAP_OS_WINDOWS
+    Sleep (a_microseconds / 1000);
+#else
+    struct timespec l_request, l_remaining;
+    l_request.tv_sec = a_microseconds / DAP_USEC_PER_SEC;
+    l_request.tv_nsec = 1000 * (a_microseconds % DAP_USEC_PER_SEC);
+    while(nanosleep(&l_request, &l_remaining) == -1 && errno == EINTR)
+        l_request = l_remaining;
+#endif
+}
+
diff --git a/dap-sdk/core/src/dap_strfuncs.c b/dap-sdk/core/src/dap_strfuncs.c
index 2685947f96e330bdc41bb865cfac7434e6e2d326..a766b125633417400291f7f06c78a35b2ed9a02f 100755
--- a/dap-sdk/core/src/dap_strfuncs.c
+++ b/dap-sdk/core/src/dap_strfuncs.c
@@ -866,22 +866,3 @@ char *_strndup(const char *str, unsigned long len) {
 }
 #endif
 
-/**
- * dap_usleep:
- * @a_microseconds: number of microseconds to pause
- *
- * Pauses the current thread for the given number of microseconds.
- */
-void dap_usleep(time_t a_microseconds)
-{
-#ifdef _WIN32
-    Sleep (a_microseconds / 1000);
-#else
-    struct timespec l_request, l_remaining;
-    l_request.tv_sec = a_microseconds / DAP_USEC_PER_SEC;
-    l_request.tv_nsec = 1000 * (a_microseconds % DAP_USEC_PER_SEC);
-    while(nanosleep(&l_request, &l_remaining) == -1 && errno == EINTR)
-        l_request = l_remaining;
-#endif
-}
-
diff --git a/dap-sdk/crypto/include/dap_enc_key.h b/dap-sdk/crypto/include/dap_enc_key.h
index 7e2c7c6901aba7f627e26bbfc30c31098e877631..7ef187742ec71e45813da67a55d286cddee647b0 100755
--- a/dap-sdk/crypto/include/dap_enc_key.h
+++ b/dap-sdk/crypto/include/dap_enc_key.h
@@ -256,6 +256,7 @@ int dap_enc_key_deserealize_pub_key(dap_enc_key_t *a_key, const uint8_t *a_buf,
 
 dap_enc_key_serealize_t* dap_enc_key_serealize(dap_enc_key_t * key);
 dap_enc_key_t* dap_enc_key_deserealize(const void *buf, size_t buf_size);
+dap_enc_key_t* dap_enc_key_dup(dap_enc_key_t * a_key);
 
 // allocate memory for key struct
 dap_enc_key_t *dap_enc_key_new(dap_enc_key_type_t a_key_type);
diff --git a/dap-sdk/crypto/src/dap_cert.c b/dap-sdk/crypto/src/dap_cert.c
index 2916d19b6707d73da4597d8231f928bc3d99400e..b9bc42688635fe060bd631c36eb9c7d60f9a03d0 100755
--- a/dap-sdk/crypto/src/dap_cert.c
+++ b/dap-sdk/crypto/src/dap_cert.c
@@ -207,11 +207,11 @@ dap_cert_t * dap_cert_generate_mem_with_seed(const char * a_cert_name, dap_enc_k
     if ( l_enc_key ){
         dap_cert_t * l_cert = dap_cert_new(a_cert_name);
         l_cert->enc_key = l_enc_key;
-        log_it(L_DEBUG,"Certificate generated");
+        //log_it(L_DEBUG,"Certificate generated");
         //dap_cert_item_t * l_cert_item = DAP_NEW_Z(dap_cert_item_t);
         //snprintf(l_cert_item->name,sizeof(l_cert_item->name),"%s",a_cert_name);
         //HASH_ADD_STR(s_certs,name,l_cert_item);
-        log_it(L_DEBUG,"Certificate name %s recorded", a_cert_name);
+        //log_it(L_DEBUG,"Certificate name %s recorded", a_cert_name);
         return l_cert;
     } else {
         log_it(L_ERROR,"Can't generate key in memory!");
diff --git a/dap-sdk/crypto/src/dap_cert_file.c b/dap-sdk/crypto/src/dap_cert_file.c
index cad1955c2d228d65d6a7e3399cfe6f212950b8d5..7a733e50b6550763a24c1940f5c96fdba8b97c7e 100755
--- a/dap-sdk/crypto/src/dap_cert_file.c
+++ b/dap-sdk/crypto/src/dap_cert_file.c
@@ -238,15 +238,15 @@ uint8_t* dap_cert_mem_save(dap_cert_t * a_cert, uint32_t *a_cert_size_out)
     l_hdr.type = dap_cert_FILE_TYPE_PUBLIC;
     if ( l_priv_key_data ){
         l_hdr.type =  dap_cert_FILE_TYPE_PRIVATE;
-        log_it(L_DEBUG,"Private key size %u",l_priv_key_data_size);
+        //log_it(L_DEBUG,"Private key size %u",l_priv_key_data_size);
     }
     if (l_pub_key_data){
-        log_it(L_DEBUG,"Public key size %u",l_pub_key_data_size);
+        //log_it(L_DEBUG,"Public key size %u",l_pub_key_data_size);
     }else{
         log_it(L_ERROR,"No public or private key in certificate, nothing to save");
         goto lb_exit;
     }
-    log_it(L_DEBUG,"Key private data size %u",l_key->_inheritor_size);
+    //log_it(L_DEBUG,"Key private data size %u",l_key->_inheritor_size);
 
     l_hdr.version = dap_cert_FILE_VERSION;
     l_hdr.data_size = l_pub_key_data_size;
@@ -290,7 +290,7 @@ lb_exit:
         DAP_DELETE(l_metadata);
     }
 
-    log_it(L_NOTICE,"Certificate \"%s\" successfully serialized",a_cert->name);
+    //log_it(L_NOTICE,"Certificate \"%s\" successfully serialized",a_cert->name);
 
     if(a_cert_size_out)
         *a_cert_size_out = l_data_offset;
@@ -378,7 +378,7 @@ dap_cert_t* dap_cert_mem_load(const void * a_data, size_t a_data_size)
             l_data_offset += l_hdr.metadata_size;
         }
         dap_enc_key_update(l_ret->enc_key);
-        log_it(L_NOTICE,"Successfully loaded certificate %s", l_ret->name);
+        //log_it(L_NOTICE,"Successfully loaded certificate %s", l_ret->name);
     }else
         log_it(L_ERROR,"Unrecognizable certificate version, corrupted file or you have too old software");
 
diff --git a/dap-sdk/crypto/src/dap_enc_base58.c b/dap-sdk/crypto/src/dap_enc_base58.c
index a8538a9b97132b8758bf6d5819c6d7d8872e01d4..acbfe8fcc550e359a81542ea00ab35564fe77636 100755
--- a/dap-sdk/crypto/src/dap_enc_base58.c
+++ b/dap-sdk/crypto/src/dap_enc_base58.c
@@ -27,6 +27,8 @@
 #include <stdint.h>
 #include <string.h>
 #include "dap_common.h"
+#include "dap_strfuncs.h"
+#include "dap_string.h"
 #include "dap_enc_base58.h"
 
 #define LOG_TAG "dap_enc_base58"
@@ -225,7 +227,7 @@ char* dap_enc_base58_from_hex_str_to_str(const char *a_in_str)
         return NULL;
     // from "0x..." to binary
     char *l_out_str = DAP_NEW_Z_SIZE(char, a_in_hash_len / 2 + 1);
-    size_t len = dap_hex2bin(l_out_str, a_in_str+2, a_in_hash_len-2);
+    size_t len = dap_hex2bin((uint8_t*)l_out_str, a_in_str+2, a_in_hash_len-2);
     // from binary to base58
     char *l_base58_out = dap_enc_base58_encode_to_str(l_out_str, len/2);
     DAP_DELETE(l_out_str);
diff --git a/dap-sdk/crypto/src/dap_enc_base64.c b/dap-sdk/crypto/src/dap_enc_base64.c
index b0f1351cead5ee1bb8329ec6fd6b50dbddbfa74d..b8d0c05783fca79606da4e7d5ecc6d3f86a26626 100755
--- a/dap-sdk/crypto/src/dap_enc_base64.c
+++ b/dap-sdk/crypto/src/dap_enc_base64.c
@@ -288,7 +288,7 @@ char * dap_enc_strdup_from_base64(const char * a_string_base64){
     if(!l_string_base64_len)
         return NULL;
 
-    char * l_string = DAP_NEW_Z_SIZE(byte_t, l_string_base64_len * 2);
+    char * l_string = DAP_NEW_Z_SIZE(char, l_string_base64_len * 2);
     size_t l_string_len = dap_enc_base64_decode(a_string_base64, l_string_base64_len, l_string, DAP_ENC_DATA_TYPE_B64_URLSAFE);
 
     if(!l_string_len){
diff --git a/dap-sdk/crypto/src/dap_enc_iaes.c b/dap-sdk/crypto/src/dap_enc_iaes.c
index 0e4df9e74a1add551155ec2a531c2b0d27f5e567..29ef751860de7e58f12962727451d8b7b8d6981f 100755
--- a/dap-sdk/crypto/src/dap_enc_iaes.c
+++ b/dap-sdk/crypto/src/dap_enc_iaes.c
@@ -105,8 +105,8 @@ size_t dap_enc_iaes256_cbc_decrypt_fast(struct dap_enc_key * a_key, const void *
     memcpy(&feedback[0], DAP_ENC_AES_KEY(a_key)->ivec, IAES_BLOCK_SIZE);
     memcpy(priv_key_swapped_endian, a_key->priv_key_data, sizeof(priv_key_swapped_endian));
 
-    swap_endian(priv_key_swapped_endian, sizeof(priv_key_swapped_endian)/sizeof(uint32_t));
-    Key_Shedule_for_decrypT(priv_key_swapped_endian, round_decrypt_key);
+    swap_endian((uint32_t*)priv_key_swapped_endian, sizeof(priv_key_swapped_endian)/sizeof(uint32_t));
+    Key_Shedule_for_decrypT((uint32_t*)priv_key_swapped_endian, round_decrypt_key);
 
     void *data = buf_out;
     const void *cdata = a_in;
diff --git a/dap-sdk/crypto/src/dap_enc_key.c b/dap-sdk/crypto/src/dap_enc_key.c
index 24e38aedf9968d1da58de509f444d66532d337f0..95b9c89200f6f94124a1657e9cc882b54fd6bebf 100755
--- a/dap-sdk/crypto/src/dap_enc_key.c
+++ b/dap-sdk/crypto/src/dap_enc_key.c
@@ -632,6 +632,28 @@ dap_enc_key_serealize_t* dap_enc_key_serealize(dap_enc_key_t * key)
     return result;
 }
 
+/**
+ * @brief dap_enc_key_dup
+ * @param a_key
+ * @return
+ */
+dap_enc_key_t* dap_enc_key_dup(dap_enc_key_t * a_key)
+{
+    dap_enc_key_t * l_ret = DAP_NEW_S_SIZE(dap_enc_key_t,sizeof(*l_ret) );
+    memcpy(l_ret,a_key,sizeof (*a_key));
+
+    l_ret->priv_key_data = DAP_NEW_Z_SIZE(byte_t, l_ret->priv_key_data_size);
+    memcpy(l_ret->priv_key_data, a_key->priv_key_data, a_key->priv_key_data_size);
+    l_ret->pub_key_data = DAP_NEW_Z_SIZE(byte_t, a_key->pub_key_data_size);
+    memcpy(l_ret->pub_key_data, a_key->pub_key_data, a_key->pub_key_data_size);
+    if(a_key->_inheritor_size) {
+        l_ret->_inheritor = DAP_NEW_Z_SIZE(byte_t, a_key->_inheritor_size );
+        memcpy(l_ret->_inheritor, a_key->_inheritor, a_key->_inheritor_size);
+    }
+
+    return l_ret;
+}
+
 /**
  * @brief dap_enc_key_deserealize
  * @param buf
@@ -652,13 +674,13 @@ dap_enc_key_t* dap_enc_key_deserealize(const void *buf, size_t buf_size)
     result->_inheritor_size = in_key->inheritor_size;
     DAP_DEL_Z(result->priv_key_data)
     DAP_DEL_Z(result->pub_key_data)
-    result->priv_key_data = DAP_NEW_Z_SIZE(uint8_t, result->priv_key_data_size);
+    result->priv_key_data = DAP_NEW_Z_SIZE(byte_t, result->priv_key_data_size);
     memcpy(result->priv_key_data, in_key->priv_key_data, result->priv_key_data_size);
-    result->pub_key_data = DAP_NEW_Z_SIZE(uint8_t, result->pub_key_data_size);
+    result->pub_key_data = DAP_NEW_Z_SIZE(byte_t, result->pub_key_data_size);
     memcpy(result->pub_key_data, in_key->pub_key_data, result->pub_key_data_size);
     if(in_key->inheritor_size) {
         DAP_DEL_Z(result->_inheritor)
-        result->_inheritor = DAP_NEW_Z(dap_enc_key_t);
+        result->_inheritor = DAP_NEW_Z_SIZE(byte_t, in_key->inheritor_size );
         memcpy(result->_inheritor, in_key->inheritor, in_key->inheritor_size);
     } else {
         result->_inheritor = NULL;
diff --git a/dap-sdk/crypto/src/iaes/iaes256_cbc_cernal.c b/dap-sdk/crypto/src/iaes/iaes256_cbc_cernal.c
index 9052a2c996371a2fa153aab5139ad5e8e61a932a..2a1b55cf02f3cb56f38a524ff7b046db38e59d4c 100755
--- a/dap-sdk/crypto/src/iaes/iaes256_cbc_cernal.c
+++ b/dap-sdk/crypto/src/iaes/iaes256_cbc_cernal.c
@@ -23,6 +23,12 @@ void swap_endian(uint32_t *buff, unsigned long len)
 
 void AES256_enc_cernelT(uint32_t * in, uint32_t * out, uint32_t * masterkey)
 {           //first round includes replacement of byte order
+    uint32_t t0, t1, t2, t3;
+    uint32_t s0, s1, s2, s3;
+    uint32_t k0, k1, k2, k3;
+    uint32_t k4, k5, k6, k7;
+    uint32_t temp;
+
     /*r1*/	s0 = ((in[0] & 0xff) << 24) ^ ((in[0] >> 8) & 0xff) << 16 ^ ((in[0] >> 16) & 0xff) << 8 ^ (in[0] >> 24) ^ masterkey[0];
             s1 = ((in[1] & 0xff) << 24) ^ ((in[1] >> 8) & 0xff) << 16 ^ ((in[1] >> 16) & 0xff) << 8 ^ (in[1] >> 24) ^ masterkey[1];
             s2 = ((in[2] & 0xff) << 24) ^ ((in[2] >> 8) & 0xff) << 16 ^ ((in[2] >> 16) & 0xff) << 8 ^ (in[2] >> 24) ^ masterkey[2];
@@ -372,6 +378,8 @@ void Key_Shedule_for_decrypT(uint32_t * key, uint32_t * rounds_keys)
 
 void AES256_dec_cernelT(uint32_t * in, uint32_t * out, uint32_t * decr_key)
 {/*r1-xor*/
+    uint32_t t0, t1, t2, t3;
+    uint32_t s0, s1, s2, s3;
     //first round includes replacement of byte order
     s0 = ((in[0] & 0xff) << 24) ^ ((in[0] >> 8) & 0xff) << 16 ^ ((in[0] >> 16) & 0xff) << 8 ^ (in[0] >> 24) ^ decr_key[0];
     s1 = ((in[1] & 0xff) << 24) ^ ((in[1] >> 8) & 0xff) << 16 ^ ((in[1] >> 16) & 0xff) << 8 ^ (in[1] >> 24) ^ decr_key[1];
diff --git a/dap-sdk/crypto/src/iaes/iaes_tables.h b/dap-sdk/crypto/src/iaes/iaes_tables.h
index c13c59b42d8fa534df18eabc0330fced076d7a55..3fa43b052281c7b06fc84f67cfecafb9868cd5e5 100755
--- a/dap-sdk/crypto/src/iaes/iaes_tables.h
+++ b/dap-sdk/crypto/src/iaes/iaes_tables.h
@@ -690,12 +690,5 @@ uint32_t rcon[] =
     0xab000000, 0x4d000000, 0x9a000000, 0x2f000000
 };
 
-//define AES_VAR
-uint32_t k0, k1, k2, k3;
-uint32_t k4, k5, k6, k7;
-uint32_t temp;
-uint32_t t0, t1, t2, t3;
-uint32_t s0, s1, s2, s3;
-
 
 #endif // TABLES_H
diff --git a/dap-sdk/net/client/CMakeLists.txt b/dap-sdk/net/client/CMakeLists.txt
index 82df978c4995d6b69d1640134cbebe8d2383c941..00f855bceb52d93e73d327260e24cf0b43ee6ac6 100644
--- a/dap-sdk/net/client/CMakeLists.txt
+++ b/dap-sdk/net/client/CMakeLists.txt
@@ -15,7 +15,7 @@ add_library(${PROJECT_NAME} STATIC ${DAP_CLIENT_HEADERS} ${DAP_CLIENT_SOURCES})
 target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_server_core dap_udp_server dap_http_server dap_enc_server dap_stream dap_session dap_stream_ch json-c)
 
 if(UNIX AND NOT ANDROID)
-    target_link_libraries(${PROJECT_NAME} ev)
+    target_link_libraries(${PROJECT_NAME} rt)
 endif()
 
 
diff --git a/dap-sdk/net/client/dap_client.c b/dap-sdk/net/client/dap_client.c
index b799fe8080941db2ce65225fc546f9a3312f6650..d977b219ddadbed22628cee1e67eeeb78bdbe1bb 100644
--- a/dap-sdk/net/client/dap_client.c
+++ b/dap-sdk/net/client/dap_client.c
@@ -443,6 +443,18 @@ dap_stream_t * dap_client_get_stream(dap_client_t * a_client)
     return (l_client_internal) ? l_client_internal->stream : NULL;
 }
 
+/**
+ * @brief dap_client_get_stream_worker
+ * @param a_client
+ * @return
+ */
+dap_stream_worker_t * dap_client_get_stream_worker(dap_client_t * a_client)
+{
+    dap_client_pvt_t * l_client_internal = DAP_CLIENT_PVT(a_client);
+    return (l_client_internal) ? l_client_internal->stream_worker : NULL;
+
+}
+
 dap_stream_ch_t * dap_client_get_stream_ch(dap_client_t * a_client, uint8_t a_ch_id)
 {
     dap_stream_ch_t * l_ch = NULL;
diff --git a/dap-sdk/net/client/dap_client_http.c b/dap-sdk/net/client/dap_client_http.c
index baeef39724cd923730739a3ff4fdf08422206be1..79ca6f4484c0ac269259a660ef45e9956eb04f3d 100644
--- a/dap-sdk/net/client/dap_client_http.c
+++ b/dap-sdk/net/client/dap_client_http.c
@@ -128,7 +128,7 @@ static void s_http_read(dap_events_socket_t * a_es, void * arg)
         return;
     }
     // read data
-    l_client_http_internal->response_size += dap_events_socket_read(a_es,
+    l_client_http_internal->response_size += dap_events_socket_pop_from_buf_in(a_es,
             l_client_http_internal->response + l_client_http_internal->response_size,
             l_client_http_internal->response_size_max - l_client_http_internal->response_size);
 
@@ -208,7 +208,7 @@ static void s_http_read(dap_events_socket_t * a_es, void * arg)
         }
         else {
             // close connection
-            dap_events_socket_kill_socket(a_es);
+            a_es->kill_signal=true;
             //dap_events_socket_remove_and_delete(a_es, true); //dap_events_socket_delete(a_es, true);
         }
     }
@@ -219,7 +219,7 @@ static void s_http_read(dap_events_socket_t * a_es, void * arg)
  * @param a_es
  * @param arg
  */
-static void s_http_error(dap_events_socket_t * a_es, void * arg)
+static void s_http_error(dap_events_socket_t * a_es, int arg)
 {
     log_it(L_INFO, "http client error");
     dap_client_http_internal_t * l_client_http_internal = DAP_CLIENT_HTTP(a_es);
@@ -228,10 +228,10 @@ static void s_http_error(dap_events_socket_t * a_es, void * arg)
         return;
     }
     if(l_client_http_internal->error_callback)
-        l_client_http_internal->error_callback((int)arg, l_client_http_internal->obj);
+        l_client_http_internal->error_callback(arg, l_client_http_internal->obj);
 
     // close connection
-    dap_events_socket_kill_socket(a_es);
+    a_es->kill_signal = true;
     //dap_events_socket_remove_and_delete(a_es, true);
     //dap_events_thread_wake_up( &a_es->events->proc_thread);
     //dap_events_socket_delete(a_es, false);
@@ -354,7 +354,7 @@ void* dap_client_http_request_custom(const char *a_uplink_addr, uint16_t a_uplin
     setsockopt(l_socket, SOL_SOCKET, SO_SNDBUF, (void*) &buffsize, sizeof(buffsize));
     setsockopt(l_socket, SOL_SOCKET, SO_RCVBUF, (void*) &buffsize, sizeof(buffsize));
 #endif
-    dap_events_socket_t *l_ev_socket = dap_events_socket_wrap_no_add(NULL, l_socket, &l_s_callbacks);
+    dap_events_socket_t *l_ev_socket = dap_events_socket_wrap_no_add(dap_events_get_default(), l_socket, &l_s_callbacks);
 
     // create private struct
     dap_client_http_internal_t *l_client_http_internal = DAP_NEW_Z(dap_client_http_internal_t);
@@ -372,7 +372,8 @@ void* dap_client_http_request_custom(const char *a_uplink_addr, uint16_t a_uplin
     if(!l_remote_addr.sin_addr.s_addr) {
         if(resolve_host(a_uplink_addr, AF_INET, (struct sockaddr*) &l_remote_addr.sin_addr) < 0) {
             log_it(L_ERROR, "Wrong remote address '%s:%u'", a_uplink_addr, a_uplink_port);
-            dap_events_socket_kill_socket(l_ev_socket);
+            DAP_DELETE(l_ev_socket);
+            close(l_socket);
             return NULL;
         }
     }
@@ -380,20 +381,18 @@ void* dap_client_http_request_custom(const char *a_uplink_addr, uint16_t a_uplin
     l_remote_addr.sin_family = AF_INET;
     l_remote_addr.sin_port = htons(a_uplink_port);
     int l_err = 0;
+    dap_worker_t *l_worker = NULL;
     if((l_err = connect(l_socket, (struct sockaddr *) &l_remote_addr, sizeof(struct sockaddr_in))) != -1) {
         //s_set_sock_nonblock(a_client_pvt->stream_socket, false);
         log_it(L_INFO, "Remote address connected (%s:%u) with sock_id %d", a_uplink_addr, a_uplink_port, l_socket);
         // add to dap_worker
-        dap_events_socket_create_after(l_ev_socket);
+        l_worker = dap_worker_add_events_socket_auto(l_ev_socket);
     }
     else {
         log_it(L_ERROR, "Remote address can't connected (%s:%u) with sock_id %d err: %s", a_uplink_addr, a_uplink_port,
                 l_socket, strerror(errno));
-        //l_ev_socket->no_close = false;
-        dap_events_socket_kill_socket(l_ev_socket);
-        //shutdown(l_ev_socket->socket, SHUT_RDWR);
-        //dap_events_socket_remove_and_delete(l_ev_socket, true);
-        //l_ev_socket->socket = 0;
+        DAP_DELETE(l_ev_socket);
+        close(l_socket);
         return NULL ;
     }
 
@@ -441,16 +440,14 @@ void* dap_client_http_request_custom(const char *a_uplink_addr, uint16_t a_uplin
     }
 
     // send header
-    dap_events_socket_write_f(l_ev_socket, "%s /%s%s HTTP/1.1\r\n"
+    dap_events_socket_write_f_mt(l_worker, l_ev_socket, "%s /%s%s HTTP/1.1\r\n"
             "Host: %s\r\n"
             "%s"
             "\r\n",
             a_method, a_path, l_get_str ? l_get_str : "", a_uplink_addr, l_request_headers->str);
     // send data for POST request
     if(!l_get_str)
-        dap_events_socket_write(l_ev_socket, a_request, a_request_size);
-    dap_events_socket_set_writable(l_ev_socket, true);
-
+        dap_events_socket_write_mt(l_worker, l_ev_socket, a_request, a_request_size);
     DAP_DELETE(l_get_str);
     dap_string_free(l_request_headers, true);
     return l_client_http_internal;
diff --git a/dap-sdk/net/client/dap_client_pvt.c b/dap-sdk/net/client/dap_client_pvt.c
index 56e006a5118cf9c7cfd572aac1fcc2affff89f3b..59a52c01f98d95256170fcc41b950340ddafb383 100644
--- a/dap-sdk/net/client/dap_client_pvt.c
+++ b/dap-sdk/net/client/dap_client_pvt.c
@@ -64,6 +64,7 @@
 #include "dap_client_pvt.h"
 #include "dap_server.h"
 #include "dap_stream.h"
+#include "dap_stream_worker.h"
 #include "dap_stream_ch.h"
 #include "dap_stream_ch_proc.h"
 #include "dap_stream_ch_pkt.h"
@@ -98,7 +99,7 @@ void m_request_error(int, void *);
 void m_es_stream_delete(dap_events_socket_t * a_es, void * arg);
 void m_es_stream_read(dap_events_socket_t * a_es, void * arg);
 void m_es_stream_write(dap_events_socket_t * a_es, void * arg);
-void m_es_stream_error(dap_events_socket_t * a_es, void * arg);
+void m_es_stream_error(dap_events_socket_t * a_es, int a_arg);
 
 /**
  * @brief dap_client_internal_init
@@ -125,6 +126,7 @@ void dap_client_pvt_new(dap_client_pvt_t * a_client_internal)
     a_client_internal->stage = STAGE_BEGIN; // start point of state machine
     a_client_internal->stage_status = STAGE_STATUS_DONE;
     a_client_internal->uplink_protocol_version = DAP_PROTOCOL_VERSION;
+    a_client_internal->events = dap_events_get_default();
     // add to list
     dap_client_pvt_hh_add(a_client_internal);
 }
@@ -277,16 +279,14 @@ int dap_client_pvt_disconnect(dap_client_pvt_t *a_client_pvt)
 
 //        l_client_internal->stream_es->signal_close = true;
         // start stopping connection
-        if(a_client_pvt->stream_es && !dap_events_socket_kill_socket(a_client_pvt->stream_es)) {
+        if(a_client_pvt->stream_es ) {
+            dap_events_socket_remove_and_delete_mt(a_client_pvt->stream_es->worker, a_client_pvt->stream_es);
             int l_counter = 0;
             // wait for stop of connection (max 0.7 sec.)
             while(a_client_pvt->stream_es && l_counter < 70) {
                 dap_usleep(DAP_USEC_PER_SEC / 100);
                 l_counter++;
             }
-            if(l_counter >= 70) {
-                dap_events_socket_remove_and_delete(a_client_pvt->stream_es, true);
-            }
         }
 //        if (l_client_internal->stream_socket ) {
 //            close (l_client_internal->stream_socket);
@@ -338,7 +338,7 @@ static void dap_client_pvt_delete_in(dap_client_pvt_t * a_client_pvt)
         dap_enc_key_delete(a_client_pvt->stream_key);
 
     //a_client_pvt->client = NULL;
-    DAP_DELETE(a_client_pvt);
+   // DAP_DELETE(a_client_pvt);
 }
 
 /*
@@ -479,16 +479,22 @@ static void s_stage_status_after(dap_client_pvt_t * a_client_pvt)
             };
             a_client_pvt->stream_es = dap_events_socket_wrap_no_add(a_client_pvt->events,
                     a_client_pvt->stream_socket, &l_s_callbacks);
+            dap_worker_t * l_worker = dap_events_worker_get_auto();
+            assert(l_worker);
+            assert(l_worker->_inheritor);
+            a_client_pvt->stream_worker = DAP_STREAM_WORKER(l_worker);
             // add to dap_worker
-            dap_events_socket_create_after(a_client_pvt->stream_es);
+            dap_events_socket_assign_on_worker_mt(a_client_pvt->stream_es, l_worker);
 
             a_client_pvt->stream_es->_inheritor = a_client_pvt;//->client;
-            a_client_pvt->stream = dap_stream_new_es(a_client_pvt->stream_es);
+            a_client_pvt->stream = dap_stream_new_es_client(a_client_pvt->stream_es);
             a_client_pvt->stream->is_client_to_uplink = true;
             a_client_pvt->stream->session = dap_stream_session_pure_new(); // may be from in packet?
 
             // new added, whether it is necessary?
             a_client_pvt->stream->session->key = a_client_pvt->stream_key;
+            a_client_pvt->stream->stream_worker = a_client_pvt->stream_worker;
+
 
             // connect
             struct sockaddr_in l_remote_addr;
@@ -498,7 +504,7 @@ static void s_stage_status_after(dap_client_pvt_t * a_client_pvt)
             if(inet_pton(AF_INET, a_client_pvt->uplink_addr, &(l_remote_addr.sin_addr)) < 0) {
                 log_it(L_ERROR, "Wrong remote address '%s:%u'", a_client_pvt->uplink_addr, a_client_pvt->uplink_port);
                 //close(a_client_pvt->stream_socket);
-                dap_events_socket_kill_socket(a_client_pvt->stream_es);
+                dap_events_socket_remove_and_delete_mt(a_client_pvt->stream_es->worker, a_client_pvt->stream_es);
                 //a_client_pvt->stream_socket = 0;
                 a_client_pvt->stage_status = STAGE_STATUS_ERROR;
             }
@@ -508,14 +514,14 @@ static void s_stage_status_after(dap_client_pvt_t * a_client_pvt)
                         sizeof(struct sockaddr_in))) != -1) {
                     a_client_pvt->stream_es->flags &= ~DAP_SOCK_SIGNAL_CLOSE;
                     //s_set_sock_nonblock(a_client_pvt->stream_socket, false);
-                    log_it(L_INFO, "Remote address connected (%s:%u) with sock_id %d", a_client_pvt->uplink_addr,
-                            a_client_pvt->uplink_port, a_client_pvt->stream_socket);
+                    log_it(L_INFO, "Remote address connected (%s:%u) with sock_id %d (assign on worker #%u)", a_client_pvt->uplink_addr,
+                            a_client_pvt->uplink_port, a_client_pvt->stream_socket, l_worker->id);
                     a_client_pvt->stage_status = STAGE_STATUS_DONE;
                 }
                 else {
                     log_it(L_ERROR, "Remote address can't connected (%s:%u) with sock_id %d", a_client_pvt->uplink_addr,
                             a_client_pvt->uplink_port);
-                    dap_events_socket_kill_socket(a_client_pvt->stream_es);
+                    dap_events_socket_remove_and_delete_mt(a_client_pvt->stream_es->worker, a_client_pvt->stream_es);
                     //close(a_client_pvt->stream_socket);
                     a_client_pvt->stream_socket = 0;
                     a_client_pvt->stage_status = STAGE_STATUS_ERROR;
@@ -546,7 +552,7 @@ static void s_stage_status_after(dap_client_pvt_t * a_client_pvt)
 
             const char *l_add_str = "";
 
-            dap_events_socket_write_f( a_client_pvt->stream_es, "GET /%s HTTP/1.1\r\n"
+            dap_events_socket_write_f_mt(a_client_pvt->stream_worker->worker, a_client_pvt->stream_es, "GET /%s HTTP/1.1\r\n"
                                                                 "Host: %s:%d%s\r\n"
                                                                 "\r\n",
                                        l_full_path, a_client_pvt->uplink_addr, a_client_pvt->uplink_port, l_add_str);
@@ -1289,30 +1295,30 @@ void m_es_stream_write(dap_events_socket_t * a_es, void * arg)
         return;
     }
     switch (l_client_pvt->stage) {
-    case STAGE_STREAM_STREAMING: {
-        size_t i;
-        bool ready_to_write = false;
-        //  log_it(DEBUG,"Process channels data output (%u channels)",STREAM(sh)->channel_count);
-
-        for(i = 0; i < l_client_pvt->stream->channel_count; i++) {
-            dap_stream_ch_t * ch = l_client_pvt->stream->channel[i];
-            if(ch->ready_to_write) {
-                ch->proc->packet_out_callback(ch, NULL);
-                ready_to_write |= ch->ready_to_write;
+        case STAGE_STREAM_STREAMING: {
+            size_t i;
+            bool ready_to_write = false;
+            //  log_it(DEBUG,"Process channels data output (%u channels)",STREAM(sh)->channel_count);
+
+            for(i = 0; i < l_client_pvt->stream->channel_count; i++) {
+                dap_stream_ch_t * ch = l_client_pvt->stream->channel[i];
+                if(ch->ready_to_write) {
+                    ch->proc->packet_out_callback(ch, NULL);
+                    ready_to_write |= ch->ready_to_write;
+                }
             }
-        }
-        //log_it(L_DEBUG,"stream_data_out (ready_to_write=%s)", ready_to_write?"true":"false");
+            //log_it(L_DEBUG,"stream_data_out (ready_to_write=%s)", ready_to_write?"true":"false");
 
-        dap_events_socket_set_writable(l_client_pvt->stream_es, ready_to_write);
-        //log_it(ERROR,"No stream_data_write_callback is defined");
-    }
-        break;
-    default: {
-    }
+            dap_events_socket_set_writable_unsafe(l_client_pvt->stream_es, ready_to_write);
+            //log_it(ERROR,"No stream_data_write_callback is defined");
+        }
+            break;
+        default: {
+        }
     }
 }
 
-void m_es_stream_error(dap_events_socket_t * a_es, void * arg)
+void m_es_stream_error(dap_events_socket_t * a_es, int a_arg)
 {
     //dap_client_t * l_client = DAP_CLIENT(a_es);
     //dap_client_pvt_t * l_client_pvt = (l_client) ? DAP_CLIENT_PVT(l_client) : NULL;
@@ -1321,6 +1327,6 @@ void m_es_stream_error(dap_events_socket_t * a_es, void * arg)
         log_it(L_ERROR, "m_es_stream_error: l_client_pvt is NULL!");
         return;
     }
-    log_it(L_INFO, "m_es_stream_error");
+    log_it(L_INFO, "m_es_stream_error: code %d", a_arg);
 }
 
diff --git a/dap-sdk/net/client/include/dap_client.h b/dap-sdk/net/client/include/dap_client.h
index dc49c63796fc313f5084043988a51f75231ba117..ff2ec55fda9f9da9f5c6bb2226d49bf4b915af18 100644
--- a/dap-sdk/net/client/include/dap_client.h
+++ b/dap-sdk/net/client/include/dap_client.h
@@ -131,6 +131,7 @@ const char * dap_client_get_error_str(dap_client_t * a_client);
 
 const char * dap_client_get_auth_cookie(dap_client_t * a_client);
 dap_stream_t * dap_client_get_stream(dap_client_t * a_client);
+dap_stream_worker_t * dap_client_get_stream_worker(dap_client_t * a_client);
 dap_stream_ch_t * dap_client_get_stream_ch(dap_client_t * a_client, uint8_t a_ch_id);
 const char * dap_client_get_stream_id(dap_client_t * a_client);
 void dap_client_set_active_channels (dap_client_t * a_client, const char * a_active_channels);
diff --git a/dap-sdk/net/client/include/dap_client_http.h b/dap-sdk/net/client/include/dap_client_http.h
index ebf0df092b03f074debaa5d35b05249998485cb8..ec17cdbae2c758b2f40896b1ab2b0ac2517ea314 100644
--- a/dap-sdk/net/client/include/dap_client_http.h
+++ b/dap-sdk/net/client/include/dap_client_http.h
@@ -22,7 +22,7 @@
 #pragma once
 
 #include <stdint.h>
-
+#include <stddef.h>
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/dap-sdk/net/client/include/dap_client_pvt.h b/dap-sdk/net/client/include/dap_client_pvt.h
index 5bb82ed0c274ed7b93bea1ce0caefbbce40e47e5..6966a2cf5f3bef2125ef8189d035df71dccbf556 100644
--- a/dap-sdk/net/client/include/dap_client_pvt.h
+++ b/dap-sdk/net/client/include/dap_client_pvt.h
@@ -42,6 +42,7 @@ typedef struct dap_client_internal
     dap_events_socket_t * stream_es;
     int stream_socket;
     dap_stream_t* stream;
+    dap_stream_worker_t* stream_worker;
     dap_events_t * events;
 
     dap_enc_key_t * session_key_open; // Open assymetric keys exchange
diff --git a/dap-sdk/net/core/dap_client_remote.c b/dap-sdk/net/core/dap_client_remote.c
deleted file mode 100644
index 567ef6954111c59af407bca8e043c158dddbd74d..0000000000000000000000000000000000000000
--- a/dap-sdk/net/core/dap_client_remote.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Authors:
- * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * Kelvin Project https://github.com/kelvinblockchain
- * Copyright  (c) 2017-2018
- * All rights reserved.
-
- This file is part of DAP (Deus Applications Prototypes) the open source project
-
-    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    DAP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-#ifndef _WIN32
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <sys/epoll.h>
-#include <sys/timerfd.h>
-#else
-#include <winsock2.h>
-#include <windows.h>
-#include <mswsock.h>
-#include <ws2tcpip.h>
-#include <io.h>
-#include <pthread.h>
-#endif
-
-#include "dap_common.h"
-#include "dap_server.h"
-#include "dap_client_remote.h"
-
-#define LOG_TAG "dap_client_remote"
-
-/**
- * @brief dap_client_init Init clients module
- * @return Zero if ok others if no
- */
-int dap_client_remote_init( )
-{
-  log_it( L_NOTICE, "Initialized socket client module" );
-
-  return 0;
-}
-
-/**
- * @brief dap_client_deinit Deinit clients module
- */
-void dap_client_remote_deinit( )
-{
-
-  return;
-}
-
-/**
- * @brief _save_ip_and_port
- * @param cl
- */
-void _save_ip_and_port( dap_client_remote_t * cl )
-{
-  struct sockaddr_in ip_adr_get;
-  socklen_t ip_adr_len = sizeof(ip_adr_get);
-
-  int l_res = getpeername( cl->socket, (struct sockaddr * restrict)&ip_adr_get, &ip_adr_len );
-  if(l_res == -1)
-    log_it(L_ERROR, "%s error: %s", __PRETTY_FUNCTION__, strerror(errno));
-
-  cl->port = ntohs( ip_adr_get.sin_port );
-  strcpy( cl->s_ip, inet_ntoa(ip_adr_get.sin_addr) );
-}
-
-/**
- * @brief dap_client_remote_create Create new client and add it to the list
- * @param sh Server instance
- * @param s Client's socket
- * @return Pointer to the new list's node
- */
-dap_client_remote_t *dap_client_remote_create( dap_server_t *sh, int s, dap_server_thread_t *t )
-{
-  dap_client_remote_t *dsc = DAP_NEW_Z( dap_client_remote_t );
-
-  dap_random_string_fill( dsc->id, CLIENT_ID_SIZE );
-
-  dsc->socket = s;
-  dsc->server = sh;
-  dsc->tn = t->thread_num;
-  dsc->thread = t;
-  dsc->efd = t->epoll_fd;
-  dsc->time_connection = dsc->last_time_active = time( NULL) ;
-
-  dsc->pevent.events = EPOLLIN | EPOLLOUT | EPOLLERR;
-  dsc->pevent.data.ptr = dsc;
-
-  dsc->flags = DAP_SOCK_READY_TO_READ;
-  dsc->buf_out_offset = 0;
-
-  _save_ip_and_port( dsc );
-
-  pthread_mutex_lock( &t->mutex_on_hash );
-  HASH_ADD_INT( t->hclients, socket, dsc );
-  pthread_mutex_unlock( &t->mutex_on_hash );
-
-  if ( sh->client_new_callback )
-    sh->client_new_callback( dsc, NULL ); // Init internal structure
-
-  log_it(L_DEBUG, "Create remote client: ip: %s port %d", dsc->s_ip, dsc->port );
-
-    //log_it(L_DEBUG, "Create new client. ID: %s", dsc->id);
-  return dsc;
-}
-
-/**
- * @brief safe_client_remove Removes the client from the list
- * @param sc Client instance
- */
-void dap_client_remote_remove( dap_client_remote_t *sc )
-{
-  log_it(L_DEBUG, "dap_client_remote_remove [THREAD %u] efd %u", sc->tn , sc->efd );
-
-  dap_server_thread_t *t = sc->thread;
-
-  pthread_mutex_lock( &t->mutex_on_hash );
-  HASH_DEL( t->hclients, sc );
-  pthread_mutex_unlock( &t->mutex_on_hash );
-
-  if( sc->server->client_delete_callback ) {
-    sc->server->client_delete_callback( sc, NULL ); // Init internal structure
-  }
-
-  if( sc->_inheritor ) {
-    free( sc->_inheritor );
-  }
-
-  if( sc->socket ) {
-    log_it( L_INFO, "dap_client_remote_remove close( %d );", sc->socket );
-#ifdef _WIN32
-    closesocket( sc->socket );
-#else
-    close( sc->socket );
-#endif
-  }
-
-  free( sc );
-}
-
-/**
- * @brief dap_server_client_find
- * @param sock
- * @param sh
- * @return
- */
-dap_client_remote_t *dap_client_remote_find( int sock, dap_server_thread_t *t )
-{
-  dap_client_remote_t *ret = NULL;
-
-  pthread_mutex_lock( &t->mutex_on_hash );
-  HASH_FIND_INT( t->hclients, &sock, ret );
-  pthread_mutex_unlock( &t->mutex_on_hash );
-
-  return ret;
-}
-
-/**
- * @brief dap_client_remote_ready_to_read
- * @param sc
- * @param isReady
- */
-void  dap_client_remote_ready_to_read( dap_client_remote_t *sc, bool is_ready )
-{
-  if( is_ready == (bool)(sc->flags & DAP_SOCK_READY_TO_READ) )
-    return;
-
-//  log_it( L_ERROR, "remote_ready_to_read() %u efd %X", sc->socket, sc->efd );
-
-  if ( is_ready )
-    sc->flags |= DAP_SOCK_READY_TO_READ;
-  else
-    sc->flags ^= DAP_SOCK_READY_TO_READ;
-
-  int events = EPOLLERR;
-
-  if( sc->flags & DAP_SOCK_READY_TO_READ )
-    events |= EPOLLIN;
-
-  if( sc->flags & DAP_SOCK_READY_TO_WRITE )
-    events |= EPOLLOUT;
-
-  sc->pevent.events = events;
-
-  if( epoll_ctl(sc->efd, EPOLL_CTL_MOD, sc->socket, &sc->pevent) != 0 )
-    log_it( L_ERROR, "epoll_ctl failed 000" );
-}
-
-/**
- * @brief dap_client_remote_ready_to_write
- * @param sc
- * @param isReady
- */
-void  dap_client_remote_ready_to_write( dap_client_remote_t *sc, bool is_ready )
-{
-  if ( is_ready == (bool)(sc->flags & DAP_SOCK_READY_TO_WRITE) )
-    return;
-
-//    log_it( L_ERROR, "remote_ready_to_write() %u efd %X", sc->socket, sc->efd );
-
-  if ( is_ready )
-    sc->flags |= DAP_SOCK_READY_TO_WRITE;
-  else
-    sc->flags ^= DAP_SOCK_READY_TO_WRITE;
-
-  int events = EPOLLERR;
-
-  if( sc->flags & DAP_SOCK_READY_TO_READ )
-    events |= EPOLLIN;
-
-  if( sc->flags & DAP_SOCK_READY_TO_WRITE )
-    events |= EPOLLOUT;
-
-  sc->pevent.events = events;
-
-  if( epoll_ctl(sc->efd, EPOLL_CTL_MOD, sc->socket, &sc->pevent) != 0 )
-    log_it( L_ERROR, "epoll_ctl failed 001" );
-}
-
-/**
- * @brief dap_client_write Write data to the client
- * @param sc Client instance
- * @param data Pointer to data
- * @param data_size Size of data to write
- * @return Number of bytes that were placed into the buffer
- */
-size_t dap_client_remote_write( dap_client_remote_t *sc, const void * data, size_t data_size )
-{     
-  if ( sc->buf_out_size + data_size > sizeof(sc->buf_out) ) {
-    log_it( L_WARNING, "Client buffer overflow. Packet loosed" );
-    return 0;
-  }
-
-  memcpy( sc->buf_out + sc->buf_out_size, data, data_size );
-  sc->buf_out_size += data_size;
-  return data_size;
-}
-
-/**
- * @brief dap_client_write_f Write formatted text to the client
- * @param a_client Client instance
- * @param a_format Format
- * @return Number of bytes that were placed into the buffer
- */
-size_t dap_client_remote_write_f( dap_client_remote_t *a_client, const char * a_format, ... )
-{
-  size_t max_data_size = sizeof( a_client->buf_out ) - a_client->buf_out_size;
-
-  va_list ap;
-  va_start( ap, a_format );
-
-  int ret = dap_vsnprintf( a_client->buf_out + a_client->buf_out_size, max_data_size, a_format, ap );
-
-  va_end( ap );
-
-  if( ret > 0 ) {
-    a_client->buf_out_size += (unsigned long)ret;
-    return (size_t)ret;
-  } 
-  else {
-    log_it( L_ERROR, "Can't write out formatted data '%s'", a_format );
-    return 0;
-  }
-}
-
-/**
- * @brief dap_client_read Read data from input buffer
- * @param a_client Client instasnce
- * @param a_data Pointer to memory where to store the data
- * @param a_data_size Size of data to read
- * @return Actual bytes number that were read
- */
-size_t dap_client_remote_read( dap_client_remote_t *a_client, void *a_data, size_t a_data_size )
-{
-  if ( a_data_size < a_client->buf_in_size ) {
-
-    memcpy( a_data, a_client->buf_in, a_data_size );
-    memmove( a_client->buf_in, a_client->buf_in + a_data_size, a_client->buf_in_size - a_data_size );
-  } 
-  else {
-    if ( a_data_size > a_client->buf_in_size ) {
-      a_data_size = a_client->buf_in_size;
-    }
-    memcpy( a_data, a_client->buf_in, a_data_size );
-  }
-
-  a_client->buf_in_size -= a_data_size;
-
-  return a_data_size;
-}
-
-
-/**
- * @brief dap_client_remote_shrink_client_buf_in Shrink input buffer (shift it left)
- * @param a_client Client instance
- * @param a_shrink_size Size on wich we shrink the buffer with shifting it left
- */
-void dap_client_remote_shrink_buf_in( dap_client_remote_t *a_client, size_t a_shrink_size )
-{
-#if 0
-    if((a_shrink_size==0)||(a_client->buf_in_size==0) ){
-        return;
-    }else if(a_client->buf_in_size>a_shrink_size){
-        size_t buf_size=a_client->buf_in_size-a_shrink_size;
-        void * buf = malloc(buf_size);
-        memcpy(buf,a_client->buf_in+ a_shrink_size,buf_size );
-        memcpy(a_client->buf_in,buf,buf_size);
-        a_client->buf_in_size=buf_size;
-        free(buf);
-    }else {
-        a_client->buf_in_size=0;
-    }
-#endif
-
-  if ( a_shrink_size == 0 || a_client->buf_in_size == 0 )
-    return;
-
-  if ( a_client->buf_in_size > a_shrink_size ) {
-
-    size_t buf_size = a_client->buf_in_size - a_shrink_size;
-    memmove( a_client->buf_in, a_client->buf_in + a_shrink_size, buf_size );
-/**
-    void *buf = malloc( buf_size );
-    memcpy( buf, a_client->buf_in + a_shrink_size, buf_size );
-    memcpy( a_client->buf_in, buf, buf_size );
-    // holy shit
-    a_client->buf_in_size = buf_size;
-    free( buf );
-**/
-    a_client->buf_in_size = buf_size;
-  }
-  else {
-    a_client->buf_in_size = 0;
-  }
-}
diff --git a/dap-sdk/net/core/dap_events.c b/dap-sdk/net/core/dap_events.c
index 0228f5b783da4bde285bc17092b98a73ea78e856..fd786c671c1b1831f49cb734c6239ffa6f35185e 100644
--- a/dap-sdk/net/core/dap_events.c
+++ b/dap-sdk/net/core/dap_events.c
@@ -31,29 +31,32 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#ifndef _WIN32
+#ifdef DAP_OS_UNIX
 #include <arpa/inet.h>
 #include <netinet/in.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-
-#include <sys/epoll.h>
+#endif
 
 #include <netdb.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <signal.h>
+#include <sched.h>
 
-#if 1
+#ifdef DAP_OS_LINUX
 #include <sys/timerfd.h>
-#elif defined(DAP_OS_ANDROID)
+#endif
+
+#if defined(DAP_OS_ANDROID)
 #define NO_POSIX_SHED
 #define NO_TIMER
+#else
 #endif
 
-#else
+#ifdef DAP_OS_WINDOWS
 #include <winsock2.h>
 #include <windows.h>
 #include <mswsock.h>
@@ -63,35 +66,23 @@
 #endif
 
 #include <utlist.h>
-#include <sched.h>
 
 #include "dap_common.h"
 #include "dap_strfuncs.h"
 #include "dap_server.h"
 #include "dap_events.h"
+#include "dap_events_socket.h"
+#include "dap_proc_thread.h"
 
-#define DAP_MAX_EPOLL_EVENTS    8192
-
-//typedef struct open_connection_info_s {
-//    dap_events_socket_t *es;
-//    struct open_connection_info *prev;
-//    struct open_connection_info *next;
-//} dap_events_socket_info_t;
-
-//dap_events_socket_info_t **s_dap_events_sockets;
+#define LOG_TAG "dap_events"
 
+static bool s_workers_init = false;
 static uint32_t s_threads_count = 1;
-static size_t   s_connection_timeout = 6000;
-static struct epoll_event *g_epoll_events = NULL;
-static volatile bool bEventsAreActive = true;
+static dap_worker_t **s_workers = NULL;
+static dap_thread_t *s_threads = NULL;
+static dap_events_t * s_events_default = NULL;
 
-bool s_workers_init = false;
-dap_worker_t *s_workers = NULL;
-dap_thread_t *s_threads = NULL;
-
-#define LOG_TAG "dap_events"
-
-uint32_t s_get_cpu_count( )
+uint32_t dap_get_cpu_count( )
 {
 #ifdef _WIN32
   SYSTEM_INFO si;
@@ -116,44 +107,78 @@ uint32_t s_get_cpu_count( )
 #endif
 }
 
+void dap_cpu_assign_thread_on(uint32_t a_cpu_id)
+{
+#ifndef _WIN32
+#ifndef NO_POSIX_SHED
+    cpu_set_t mask;
+    CPU_ZERO(&mask);
+    CPU_SET(a_cpu_id, &mask);
+
+    int l_retcode;
+#ifndef __ANDROID__
+    l_retcode = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &mask);
+#else
+  err = sched_setaffinity(pthread_self(), sizeof(cpu_set_t), &mask);
+#endif
+    if(l_retcode != 0)
+    {
+        char l_errbuf[128]={0};
+        switch (l_retcode) {
+            case EFAULT: strncpy(l_errbuf,"A supplied memory address was invalid.",sizeof (l_errbuf)-1); break;
+            case EINVAL: strncpy(l_errbuf,"The affinity bit mask mask contains no processors that are currently physically on the system and permitted to the thread",sizeof (l_errbuf)-1); break;
+            case ESRCH:  strncpy(l_errbuf,"No thread with the ID thread could be found",sizeof (l_errbuf)-1); break;
+            default:     strncpy(l_errbuf,"Unknown error",sizeof (l_errbuf)-1);
+        }
+        log_it(L_CRITICAL, "Worker #%u: error pthread_setaffinity_np(): %s (%d)", l_errbuf , l_retcode);
+        abort();
+    }
+#endif
+#else
+
+  if ( !SetThreadAffinityMask( GetCurrentThread(), (DWORD_PTR)(1 << a_cpu_id) ) ) {
+    log_it( L_CRITICAL, "Error pthread_setaffinity_np() You really have %d or more core in CPU?", a_cpu_id );
+    abort();
+  }
+#endif
+
+}
+
 /**
  * @brief sa_server_init Init server module
  * @arg a_threads_count  number of events processor workers in parallel threads
  * @return Zero if ok others if no
  */
-int32_t dap_events_init( uint32_t a_threads_count, size_t conn_timeout )
+int dap_events_init( uint32_t a_threads_count, size_t a_conn_timeout )
 {
-  s_threads_count = a_threads_count ? a_threads_count : s_get_cpu_count( );
-
-  if ( conn_timeout )
-    s_connection_timeout = conn_timeout;
-
-  s_workers = (dap_worker_t *) calloc( 1, sizeof(dap_worker_t) * s_threads_count );
-  s_threads = (dap_thread_t *) calloc( 1, sizeof(dap_thread_t) * s_threads_count );
-  if ( !s_workers || !s_threads )
-    goto err;
+    s_threads_count = a_threads_count ? a_threads_count : dap_get_cpu_count( );
 
-  g_epoll_events = (struct epoll_event *)malloc( sizeof(struct epoll_event) * DAP_MAX_EPOLL_EVENTS * s_threads_count );
-  if ( !g_epoll_events )
-    goto err;
+    s_workers =  DAP_NEW_Z_SIZE(dap_worker_t*,s_threads_count*sizeof (dap_worker_t*) );
+    s_threads = DAP_NEW_Z_SIZE(dap_thread_t, sizeof(dap_thread_t) * s_threads_count );
+    if ( !s_workers || !s_threads )
+        return -1;
 
-  if ( dap_events_socket_init() != 0 ) {
+    s_workers_init = true;
 
-    log_it( L_CRITICAL, "Can't init client submodule dap_events_socket_init( )" );
-    goto err;
-  }
-  s_workers_init = true;
+    dap_worker_init(a_conn_timeout);
+    if ( dap_events_socket_init() != 0 ) {
+        log_it( L_CRITICAL, "Can't init client submodule dap_events_socket_init( )" );
+        goto err;
+    }
+    if (dap_proc_thread_init(s_threads_count) != 0 ){
+        log_it( L_CRITICAL, "Can't init proc threads" );
+        goto err;
 
-  log_it( L_NOTICE, "Initialized socket server module" );
+    }
+    log_it( L_NOTICE, "Initialized event socket reactor for %u threads", s_threads_count );
 
-  #ifndef _WIN32
-    signal( SIGPIPE, SIG_IGN );
-  #endif
-  return 0;
+    return 0;
 
 err:
-  dap_events_deinit( );
-  return -1;
+    log_it(L_ERROR,"Deinit events subsystem");
+    dap_events_deinit();
+    dap_worker_deinit();
+    return -1;
 }
 
 /**
@@ -161,16 +186,13 @@ err:
  */
 void dap_events_deinit( )
 {
-  dap_events_socket_deinit( );
-
-  if ( g_epoll_events )
-    free( g_epoll_events );
+    dap_events_socket_deinit();
+    dap_worker_deinit();
+    if ( s_threads )
+        DAP_DELETE( s_threads );
 
-  if ( s_threads )
-    free( s_threads );
-
-  if ( s_workers )
-    free( s_workers );
+    if ( s_workers )
+        DAP_DELETE( s_workers );
 }
 
 /**
@@ -179,12 +201,17 @@ void dap_events_deinit( )
  */
 dap_events_t * dap_events_new( )
 {
-  dap_events_t *ret = (dap_events_t *)calloc( 1, sizeof(dap_events_t) );
+    dap_events_t *ret = DAP_NEW_Z(dap_events_t);
 
-  pthread_rwlock_init( &ret->sockets_rwlock, NULL );
-  pthread_rwlock_init( &ret->servers_rwlock, NULL );
+    pthread_rwlock_init( &ret->sockets_rwlock, NULL );
+    if ( s_events_default == NULL)
+        s_events_default = ret;
+    return ret;
+}
 
-  return ret;
+dap_events_t* dap_events_get_default( )
+{
+    return s_events_default;
 }
 
 /**
@@ -193,417 +220,147 @@ dap_events_t * dap_events_new( )
  */
 void dap_events_delete( dap_events_t *a_events )
 {
-  dap_events_socket_t *cur, *tmp;
-
-  if ( a_events ) {
-
-    HASH_ITER( hh, a_events->sockets,cur, tmp ) {
-      dap_events_socket_delete( cur, true );
-    }
+    if (a_events) {
+        dap_events_socket_t *l_cur, *l_tmp;
+        HASH_ITER( hh, a_events->sockets,l_cur, l_tmp ) {
+            dap_events_socket_remove_and_delete_unsafe( l_cur, true );
+        }
 
-    if ( a_events->_inheritor )
-      free( a_events->_inheritor );
+        if ( a_events->_inheritor )
+            DAP_DELETE( a_events->_inheritor );
 
-    pthread_rwlock_destroy( &a_events->servers_rwlock );
-    pthread_rwlock_destroy( &a_events->sockets_rwlock );
+        pthread_rwlock_destroy( &a_events->sockets_rwlock );
 
-    free( a_events );
-  }
+        DAP_DELETE( a_events );
+    }
 }
 
 /**
- * @brief s_socket_info_all_check_activity
- * @param n_thread
- * @param sh
+ * @brief sa_server_loop Main server loop
+ * @param sh Server instance
+ * @return Zero if ok others if not
  */
-static void s_socket_all_check_activity( dap_worker_t *dap_worker, dap_events_t *d_ev, time_t cur_time )
+int dap_events_start( dap_events_t *a_events )
 {
-  dap_events_socket_t *a_es, *tmp;
-
-  pthread_mutex_lock( &dap_worker->locker_on_count );
-  DL_FOREACH_SAFE( d_ev->dlsockets, a_es, tmp ) {
-
-    if ( a_es->type == DESCRIPTOR_TYPE_FILE)
-      continue;
-
-    if ( !a_es->kill_signal && cur_time >= a_es->last_time_active + s_connection_timeout && !a_es->no_close ) {
 
-      log_it( L_INFO, "Socket %u timeout, closing...", a_es->socket );
-      if (a_es->callbacks->error_callback) {
-          a_es->callbacks->error_callback(a_es, (void *)ETIMEDOUT);
-      }
-
-      if ( epoll_ctl( dap_worker->epoll_fd, EPOLL_CTL_DEL, a_es->socket, &a_es->ev) == -1 )
-        log_it( L_ERROR,"Can't remove event socket's handler from the epoll_fd" );
-      else
-        log_it( L_DEBUG,"Removed epoll's event from dap_worker #%u", dap_worker->number_thread );
-
-      dap_worker->event_sockets_count --;
-      DL_DELETE( d_ev->dlsockets, a_es );
-      dap_events_socket_delete( a_es, true );
+    for( uint32_t i = 0; i < s_threads_count; i++) {
+        dap_worker_t * l_worker = DAP_NEW_Z(dap_worker_t);
+
+        l_worker->id = i;
+        l_worker->events = a_events;
+        l_worker->proc_queue = dap_proc_thread_get(i)->proc_queue;
+#ifdef DAP_EVENTS_CAPS_EPOLL
+        l_worker->epoll_fd = epoll_create( DAP_MAX_EPOLL_EVENTS );
+        pthread_mutex_init(& l_worker->started_mutex, NULL);
+        pthread_cond_init( & l_worker->started_cond, NULL);
+        //log_it(L_DEBUG, "Created event_fd %d for worker %u", l_worker->epoll_fd,i);
+        if ( l_worker->epoll_fd == -1 ) {
+            int l_errno = errno;
+            char l_errbuf[128];
+            strerror_r(l_errno, l_errbuf, sizeof ( l_errbuf) );
+            log_it(L_CRITICAL, "Error create epoll fd: %s (%d)", l_errbuf, l_errno);
+            DAP_DELETE(l_worker);
+            return -1;
+        }
+#endif
+        s_workers[i] = l_worker;
+        pthread_mutex_lock(&l_worker->started_mutex);
+        struct timespec l_timeout;
+        clock_gettime(CLOCK_REALTIME, &l_timeout);
+        l_timeout.tv_sec+=5;
+        pthread_create( &s_threads[i].tid, NULL, dap_worker_thread, l_worker );
+
+        int l_ret;
+        l_ret=pthread_cond_timedwait(&l_worker->started_cond, &l_worker->started_mutex, &l_timeout);
+        if ( l_ret== ETIMEDOUT ){
+            log_it(L_CRITICAL, "Timeout 5 seconds is out: worker #%u thread don't respond", i);
+            return -2;
+        } else if (l_ret != 0){
+            log_it(L_CRITICAL, "Can't wait on condition: %d error code", l_ret);
+            return -3;
+        }
     }
-  }
-  pthread_mutex_unlock( &dap_worker->locker_on_count );
-
+    return 0;
 }
 
 /**
- * @brief thread_worker_function
- * @param arg
+ * @brief dap_events_wait
+ * @param sh
  * @return
  */
-static void *thread_worker_function(void *arg)
+int dap_events_wait( dap_events_t *a_events )
 {
-    dap_events_socket_t *cur;
-    dap_worker_t *w = (dap_worker_t *) arg;
-    time_t next_time_timeout_check = time( NULL) + s_connection_timeout / 2;
-    uint32_t tn = w->number_thread;
-
-#ifndef _WIN32
-#ifndef NO_POSIX_SHED
-    cpu_set_t mask;
-    CPU_ZERO(&mask);
-    CPU_SET(tn, &mask);
-
-    int err;
-#ifndef __ANDROID__
-    err = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &mask);
-#else
-  err = sched_setaffinity(pthread_self(), sizeof(cpu_set_t), &mask);
-#endif
-    if(err)
-    {
-        log_it(L_CRITICAL, "Error pthread_setaffinity_np() You really have %d or more core in CPU?", *(int* )arg);
-        abort();
+    (void) a_events;
+    for( uint32_t i = 0; i < s_threads_count; i ++ ) {
+        void *ret;
+        pthread_join( s_threads[i].tid, &ret );
     }
-#endif
-#else
-
-  if ( !SetThreadAffinityMask( GetCurrentThread(), (DWORD_PTR)(1 << tn) ) ) {
-    log_it( L_CRITICAL, "Error pthread_setaffinity_np() You really have %d or more core in CPU?", tn );
-    abort();
-  }
-  #endif
-
-    log_it(L_INFO, "Worker %d started, epoll fd %d", w->number_thread, w->epoll_fd);
-
-    struct epoll_event *events = &g_epoll_events[ DAP_MAX_EPOLL_EVENTS * tn];
-
-//  memset( &ev, 0, sizeof(ev) );
-//  memset( &events, 0, sizeof(events) );
-
-    size_t total_sent;
-    int bytes_sent = 0;
-
-    while(bEventsAreActive) {
-
-        int selected_sockets = epoll_wait(w->epoll_fd, events, DAP_MAX_EPOLL_EVENTS, 1000);
-
-        if(selected_sockets == -1) {
-            if( errno == EINTR)
-                continue;
-            log_it(L_ERROR, "Worker thread %d got errno: %d", w->number_thread, errno);
-            break;
-        }
-
-        time_t cur_time = time( NULL);
-        for(int32_t n = 0; n < selected_sockets; n++) {
-
-            cur = (dap_events_socket_t *) events[n].data.ptr;
-
-            if(!cur) {
-
-                log_it(L_ERROR, "dap_events_socket NULL");
-                continue;
-            }
-            //log_it(L_DEBUG, "Worker=%d fd=%d socket=%d event=0x%x(%d)", w->number_thread, w->epoll_fd,cur->socket, events[n].events,events[n].events);
-            int l_sock_err = 0, l_sock_err_size = sizeof(l_sock_err);
-            //connection already closed (EPOLLHUP - shutdown has been made in both directions)
-            if(events[n].events & EPOLLHUP) { // && events[n].events & EPOLLERR) {
-                getsockopt(cur->socket, SOL_SOCKET, SO_ERROR, (void *)&l_sock_err, (socklen_t *)&l_sock_err_size);
-                //if(!(events[n].events & EPOLLIN))
-                //cur->no_close = false;
-                if (l_sock_err) {
-                    cur->flags |= DAP_SOCK_SIGNAL_CLOSE;
-                    log_it(L_DEBUG, "Socket shutdown (EPOLLHUP): %s", strerror(l_sock_err));
-                    if(!(events[n].events & EPOLLERR))
-                        cur->callbacks->error_callback(cur, NULL); // Call callback to process error event
-                }
-            }
-
-            if(events[n].events & EPOLLERR) {
-                getsockopt(cur->socket, SOL_SOCKET, SO_ERROR, (void *)&l_sock_err, (socklen_t *)&l_sock_err_size);
-                log_it(L_ERROR, "Socket error: %s", strerror(l_sock_err));
-                cur->flags |= DAP_SOCK_SIGNAL_CLOSE;
-                cur->callbacks->error_callback(cur, NULL); // Call callback to process error event
-            }
-
-            cur->last_time_active = cur_time;
-
-            if(events[n].events & EPOLLIN) {
-
-                //log_it(DEBUG,"Comes connection in active read set");
-                if(cur->buf_in_size == sizeof(cur->buf_in)) {
-                    log_it(L_WARNING, "Buffer is full when there is smth to read. Its dropped!");
-                    cur->buf_in_size = 0;
-                }
-
-                int32_t bytes_read = 0;
-                if(cur->type == DESCRIPTOR_TYPE_SOCKET) {
-                    bytes_read = recv(cur->socket, (char *) (cur->buf_in + cur->buf_in_size),
-                            sizeof(cur->buf_in) - cur->buf_in_size, 0);
-                }else if(cur->type == DESCRIPTOR_TYPE_FILE) {
-                    bytes_read = read(cur->socket, (char *) (cur->buf_in + cur->buf_in_size),
-                            sizeof(cur->buf_in) - cur->buf_in_size);
-                }
-
-                if(bytes_read > 0) {
-                    cur->buf_in_size += bytes_read;
-                    //log_it(DEBUG, "Received %d bytes", bytes_read);
-                    cur->callbacks->read_callback(cur, NULL); // Call callback to process read event. At the end of callback buf_in_size should be zero if everything was read well
-                }
-                else if(bytes_read < 0) {
-                    log_it(L_ERROR, "Some error occured in recv() function: %s", strerror(errno));
-                    dap_events_socket_set_readable(cur, false);
-                    cur->flags |= DAP_SOCK_SIGNAL_CLOSE;
-                }
-                else if(bytes_read == 0) {
-                    log_it(L_INFO, "Client socket disconnected");
-                    dap_events_socket_set_readable(cur, false);
-                    cur->flags |= DAP_SOCK_SIGNAL_CLOSE;
-                }
-            }
-
-            // Socket is ready to write
-            if(((events[n].events & EPOLLOUT) || (cur->flags & DAP_SOCK_READY_TO_WRITE))
-                    && !(cur->flags & DAP_SOCK_SIGNAL_CLOSE)) {
-                ///log_it(DEBUG, "Main loop output: %u bytes to send",sa_cur->buf_out_size);
-                if(cur->callbacks->write_callback)
-                    cur->callbacks->write_callback(cur, NULL); // Call callback to process write event
-
-                if(cur->flags & DAP_SOCK_READY_TO_WRITE) {
-
-                    static const uint32_t buf_out_zero_count_max = 20;
-                    cur->buf_out[cur->buf_out_size] = 0;
-
-                    if(!cur->buf_out_size) {
-
-                        //log_it(L_WARNING, "Output: nothing to send. Why we are in write socket set?");
-                        cur->buf_out_zero_count++;
-
-                        if(cur->buf_out_zero_count > buf_out_zero_count_max) { // How many time buf_out on write event could be empty
-                            log_it(L_ERROR, "Output: nothing to send %u times, remove socket from the write set",
-                                    buf_out_zero_count_max);
-                            dap_events_socket_set_writable(cur, false);
-                        }
-                    }
-                    else
-                        cur->buf_out_zero_count = 0;
-                }
-                for(total_sent = 0; total_sent < cur->buf_out_size;) { // If after callback there is smth to send - we do it
-                    if(cur->type == DESCRIPTOR_TYPE_SOCKET) {
-                        bytes_sent = send(cur->socket, (char *) (cur->buf_out + total_sent),
-                                cur->buf_out_size - total_sent, MSG_DONTWAIT | MSG_NOSIGNAL);
-                    }else if(cur->type == DESCRIPTOR_TYPE_FILE) {
-                        bytes_sent = write(cur->socket, (char *) (cur->buf_out + total_sent),
-                                cur->buf_out_size - total_sent);
-                    }
-
-                    if(bytes_sent < 0) {
-                        log_it(L_ERROR, "Some error occured in send(): %s", strerror(errno));
-                        cur->flags |= DAP_SOCK_SIGNAL_CLOSE;
-                        break;
-                    }
-                    total_sent += bytes_sent;
-                    //log_it(L_DEBUG, "Output: %u from %u bytes are sent ", total_sent,sa_cur->buf_out_size);
-                }
-                //log_it(L_DEBUG,"Output: sent %u bytes",total_sent);
-                if (total_sent) {
-                    pthread_mutex_lock(&cur->write_hold);
-                    cur->buf_out_size -= total_sent;
-                    if (cur->buf_out_size) {
-                        memmove(cur->buf_out, &cur->buf_out[total_sent], cur->buf_out_size);
-                    } else {
-                        cur->flags &= ~DAP_SOCK_READY_TO_WRITE;
-                    }
-                    pthread_mutex_unlock(&cur->write_hold);
-                }
-            }
-
-            if((cur->flags & DAP_SOCK_SIGNAL_CLOSE) && !cur->no_close) {
-                // protect against double deletion
-                cur->kill_signal = true;
-                //dap_events_socket_remove_and_delete(cur, true);
-                log_it(L_INFO, "Got signal to close %s, sock %u [thread %u]", cur->hostaddr, cur->socket, tn);
-            }
-
-            if(cur->kill_signal) {
-                log_it(L_INFO, "Kill %u socket (processed).... [ thread %u ]", cur->socket, tn);
-                dap_events_socket_remove(cur);
-                dap_events_socket_delete( cur, true);
-            }
-
-            /*
-            if(!w->event_to_kill_count) {
-
-             pthread_mutex_unlock(&w->locker_on_count);
-             continue;
-
-             do {
-
-//      if ( cur->no_close ) {
-//        cur = cur->knext;
-//        continue;
-//      }
-                tmp = cur_del->knext;
-
-                // delete only current events_socket because others may be active in the other workers
-                //if(cur_del == cur)
-                if(cur->kill_signal) {
-                    log_it(L_INFO, "Kill %u socket (processed).... [ thread %u ]", cur_del->socket, tn);
-                    DL_LIST_REMOVE_NODE(w->events->to_kill_sockets, cur, kprev, knext, w->event_to_kill_count);
-                    dap_events_socket_remove_and_delete(cur_del, true);
-                }
-                cur_del = tmp;
-
-            } while(cur_del);
-
-            log_it(L_INFO, "[ Thread %u ] coneections: %u, to kill: %u", tn, w->event_sockets_count,
-                    w->event_to_kill_count);
-
-            pthread_mutex_unlock(&w->locker_on_count);
-            */
-        } // for
-
-#ifndef  NO_TIMER
-        if(cur_time >= next_time_timeout_check) {
-            s_socket_all_check_activity(w, w->events, cur_time);
-            next_time_timeout_check = cur_time + s_connection_timeout / 2;
-        }
-#endif
-
-    } // while
-
-    return NULL;
+    return 0;
 }
 
 /**
- * @brief dap_worker_get_min
- * @return
+ * @brief dap_events_stop
+ * @param a_events
  */
-dap_worker_t *dap_worker_get_min( )
+void dap_events_stop_all( )
 {
-    // wait for s_workers init
-    while(!s_workers_init)
-        dap_usleep(DAP_USEC_PER_SEC / 1000);
-    dap_worker_t *l_workers = &s_workers[dap_worker_get_index_min()];
-    // wait for worker start
-    while(!l_workers->events)
-        dap_usleep(DAP_USEC_PER_SEC / 1000);
-    return l_workers;
+    // TODO implement signal to stop the workers
 }
 
+
 /**
  * @brief dap_worker_get_index_min
  * @return
  */
-uint32_t dap_worker_get_index_min( )
+uint32_t dap_events_worker_get_index_min( )
 {
-  uint32_t min = 0;
-  uint32_t i;
+    uint32_t min = 0;
+    uint32_t i;
 
-  for( i = 1; i < s_threads_count; i++ ) {
+    for( i = 1; i < s_threads_count; i++ ) {
 
-    if ( s_workers[min].event_sockets_count > s_workers[i].event_sockets_count )
-      min = i;
-  }
-
-  return min;
-}
-
-/**
- * @brief dap_worker_print_all
- */
-void dap_worker_print_all( )
-{
-  uint32_t i;
-
-  for( i = 0; i < s_threads_count; i ++ ) {
-
-    log_it( L_INFO, "Worker: %d, count open connections: %d",
-            s_workers[i].number_thread, s_workers[i].event_sockets_count );
-  }
-}
-
-/**
- * @brief sa_server_loop Main server loop
- * @param sh Server instance
- * @return Zero if ok others if not
- */
-int dap_events_start( dap_events_t *a_events )
-{
-  for( uint32_t i = 0; i < s_threads_count; i++) {
-
-    s_workers[i].epoll_fd = epoll_create( DAP_MAX_EPOLL_EVENTS );
-    if ( (intptr_t)s_workers[i].epoll_fd == -1 ) {
-      log_it(L_CRITICAL, "Error create epoll fd");
-      return -1;
+    if ( s_workers[min]->event_sockets_count > s_workers[i]->event_sockets_count )
+        min = i;
     }
 
-    //s_workers[i].event_to_kill_count = 0;
-    s_workers[i].event_sockets_count = 0;
-    s_workers[i].number_thread = i;
-    s_workers[i].events = a_events;
-
-    pthread_mutex_init( &s_workers[i].locker_on_count, NULL );
-    pthread_create( &s_threads[i].tid, NULL, thread_worker_function, &s_workers[i] );
-  }
-
-  return 0;
+    return min;
 }
 
-void dap_events_stop()
+uint32_t dap_events_worker_get_count()
 {
-  bEventsAreActive = false;
+    return  s_threads_count;
 }
 
 /**
- * @brief dap_events_wait
- * @param sh
+ * @brief dap_worker_get_min
  * @return
  */
-int dap_events_wait( dap_events_t *sh )
+dap_worker_t *dap_events_worker_get_auto( )
 {
-  (void) sh;
-
-  for( uint32_t i = 0; i < s_threads_count; i ++ ) {
-    void *ret;
-    pthread_join( s_threads[i].tid, &ret );
-  }
-
-  return 0;
+    return s_workers[dap_events_worker_get_index_min()];
 }
 
 /**
- * @brief dap_worker_add_events_socket
- * @param a_worker
- * @param a_events_socket
+ * @brief dap_worker_get_index
+ * @param a_index
+ * @return
  */
-void dap_worker_add_events_socket( dap_events_socket_t *a_es)
+dap_worker_t * dap_events_worker_get(uint8_t a_index)
 {
-//  struct epoll_event ev = {0};
-  dap_worker_t *l_worker = dap_worker_get_min( );
-
-  a_es->dap_worker = l_worker;
-  a_es->events = a_es->dap_worker->events;
+    if (a_index < s_threads_count){
+        return   s_workers[a_index];
+    }else
+        return NULL;
 }
 
 /**
- * @brief dap_events__thread_wake_up
- * @param th
+ * @brief dap_worker_print_all
  */
-void dap_events_thread_wake_up( dap_thread_t *th )
+void dap_events_worker_print_all( )
 {
-  (void) th;
- //pthread_kill(th->tid,SIGUSR1);
+    uint32_t i;
+    for( i = 0; i < s_threads_count; i ++ ) {
+        log_it( L_INFO, "Worker: %d, count open connections: %d",
+                s_workers[i]->id, s_workers[i]->event_sockets_count );
+    }
 }
diff --git a/dap-sdk/net/core/dap_events_socket.c b/dap-sdk/net/core/dap_events_socket.c
index c73c4d00390b4104b93806d33074a6e162415820..542be22e8779cae1cdafda25d0a92702b4b987ca 100644
--- a/dap-sdk/net/core/dap_events_socket.c
+++ b/dap-sdk/net/core/dap_events_socket.c
@@ -1,33 +1,33 @@
 /*
  * Authors:
  * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * Kelvin Project https://github.com/kelvinblockchain
- * Copyright  (c) 2017-2019
+ * DeM Labs Ltd.   https://demlabs.net
+ * Copyright  (c) 2017
  * All rights reserved.
 
- This file is part of DAP (Deus Applications Prototypes) the open source project
+ This file is part of DAP SDK the open source project
 
-    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
+    DAP SDK is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation, either version 3 of the License, or
     (at your option) any later version.
 
-    DAP is distributed in the hope that it will be useful,
+    DAP SDK is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
 
     You should have received a copy of the GNU General Public License
-    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
 #include <assert.h>
-
+#include <errno.h>
 #ifndef _WIN32
 #include <sys/epoll.h>
 #include <unistd.h>
@@ -43,6 +43,7 @@
 #endif
 
 #include "dap_common.h"
+#include "dap_worker.h"
 #include "dap_events.h"
 
 #include "dap_events_socket.h"
@@ -55,7 +56,19 @@
  */
 int dap_events_socket_init( )
 {
-    log_it(L_NOTICE,"Initialized socket client module");
+    log_it(L_NOTICE,"Initialized events socket module");
+#if defined (DAP_EVENTS_CAPS_QUEUE_POSIX)
+#ifdef DAP_OS_LINUX
+#include <sys/time.h>
+#include <sys/resource.h>
+
+    struct rlimit l_mqueue_limit;
+    l_mqueue_limit.rlim_cur = 1024;
+    l_mqueue_limit.rlim_max = 1024;
+//    setrlimit(RLIMIT_MSGQUEUE,&l_mqueue_limit);
+#endif
+#endif
+    dap_timerfd_init();
     return 0;
 }
 
@@ -79,52 +92,449 @@ void dap_events_socket_deinit( )
 dap_events_socket_t *dap_events_socket_wrap_no_add( dap_events_t *a_events,
                                             int a_sock, dap_events_socket_callbacks_t *a_callbacks )
 {
-//  assert(a_events);
-  assert(a_callbacks);
+    assert(a_events);
+    assert(a_callbacks);
 
-  dap_events_socket_t *ret = DAP_NEW_Z( dap_events_socket_t );
+    dap_events_socket_t *ret = DAP_NEW_Z( dap_events_socket_t );
 
-  ret->socket = a_sock;
-  ret->events = a_events;
-  ret->callbacks = a_callbacks;
-  ret->flags = DAP_SOCK_READY_TO_READ;
-  ret->no_close = false;
-  pthread_mutex_init(&ret->write_hold, NULL);
+    ret->socket = a_sock;
+    ret->events = a_events;
+    memcpy(&ret->callbacks, a_callbacks, sizeof(ret->callbacks) );
+    ret->flags = DAP_SOCK_READY_TO_READ;
 
-  log_it( L_DEBUG,"Dap event socket wrapped around %d sock a_events = %X", a_sock, a_events );
+    #if defined(DAP_EVENTS_CAPS_EPOLL)
+    ret->ev_base_flags = EPOLLERR | EPOLLRDHUP | EPOLLHUP;
+    #endif
 
-  return ret;
+    if ( a_sock!= 0 && a_sock != -1){
+        pthread_rwlock_wrlock(&a_events->sockets_rwlock);
+        HASH_ADD(hh,a_events->sockets, socket, sizeof (int), ret);
+        pthread_rwlock_unlock(&a_events->sockets_rwlock);
+    }else
+        log_it(L_WARNING, "Be carefull, you've wrapped socket 0 or -1 so it wasn't added to global list. Do it yourself when possible");
+
+    //log_it( L_DEBUG,"Dap event socket wrapped around %d sock a_events = %X", a_sock, a_events );
+
+    return ret;
 }
 
 /**
- * @brief dap_events_socket_create_after
+ * @brief dap_events_socket_assign_on_worker
  * @param a_es
+ * @param a_worker
  */
-void dap_events_socket_create_after( dap_events_socket_t *a_es )
+void dap_events_socket_assign_on_worker_mt(dap_events_socket_t * a_es, struct dap_worker * a_worker)
 {
-  if ( a_es->callbacks->new_callback )
-    a_es->callbacks->new_callback( a_es, NULL ); // Init internal structure
+    a_es->last_ping_request = time(NULL);
+   // log_it(L_DEBUG, "Assigned %p on worker %u", a_es, a_worker->id);
+    dap_worker_add_events_socket(a_es,a_worker);
+}
 
-  a_es->last_time_active = a_es->last_ping_request = time( NULL );
 
-  dap_worker_add_events_socket( a_es );
+void dap_events_socket_reassign_between_workers_unsafe(dap_events_socket_t * a_es, dap_worker_t * a_worker_new)
+{
+    log_it(L_DEBUG, "reassign between workers");
+    dap_events_socket_remove_from_worker_unsafe( a_es, a_es->worker );
+    a_es->was_reassigned = true;
+    if (a_es->callbacks.worker_unassign_callback)
+        a_es->callbacks.worker_unassign_callback(a_es, a_es->worker);
 
-  pthread_mutex_lock( &a_es->dap_worker->locker_on_count );
+    dap_events_socket_assign_on_worker_mt( a_es, a_worker_new );
+}
 
-  a_es->dap_worker->event_sockets_count ++;
-  DL_APPEND( a_es->events->dlsockets, a_es );
+void dap_events_socket_reassign_between_workers_mt(dap_worker_t * a_worker_old, dap_events_socket_t * a_es, dap_worker_t * a_worker_new)
+{
+    dap_worker_msg_reassign_t * l_msg = DAP_NEW_Z(dap_worker_msg_reassign_t);
+    l_msg->esocket = a_es;
+    l_msg->worker_new = a_worker_new;
+    dap_events_socket_queue_ptr_send(a_worker_old->queue_es_reassign, l_msg);
+}
 
-  pthread_rwlock_wrlock( &a_es->events->sockets_rwlock );
-  HASH_ADD_INT( a_es->events->sockets, socket, a_es );
-  pthread_rwlock_unlock( &a_es->events->sockets_rwlock );
+/**
+ * @brief dap_events_socket_assign_on_worker_unsafe
+ * @param a_es
+ * @param a_worker
+ */
+void dap_events_socket_assign_on_worker_unsafe(dap_events_socket_t * a_es, struct dap_worker * a_worker)
+{
+#if defined(DAP_EVENTS_CAPS_EPOLL)
+    int l_event_fd = a_es->fd;
+    //log_it( L_INFO, "Create event descriptor with queue %d (%p) and add it on epoll fd %d", l_event_fd, l_es, a_w->epoll_fd);
+    a_es->ev.events = a_es->ev_base_flags;
+    a_es->ev.data.ptr = a_es;
+    epoll_ctl(a_worker->epoll_fd, EPOLL_CTL_ADD, l_event_fd, &a_es->ev);
+#endif
+}
 
-  a_es->ev.events = EPOLLIN | EPOLLERR;
-  a_es->ev.data.ptr = a_es;
+/**
+ * @brief s_create_type_pipe
+ * @param a_w
+ * @param a_callback
+ * @param a_flags
+ * @return
+ */
+dap_events_socket_t * s_create_type_pipe(dap_worker_t * a_w, dap_events_socket_callback_t a_callback, uint32_t a_flags)
+{
+    UNUSED(a_flags);
+    dap_events_socket_t * l_es = DAP_NEW_Z(dap_events_socket_t);
+    l_es->type = DESCRIPTOR_TYPE_PIPE;
+    l_es->worker = a_w;
+    l_es->events = a_w->events;
+    l_es->callbacks.read_callback = a_callback; // Arm event callback
+    l_es->ev_base_flags = EPOLLIN | EPOLLERR | EPOLLRDHUP | EPOLLHUP;
+
+#if defined(DAP_EVENTS_CAPS_PIPE_POSIX)
+    int l_pipe[2];
+    int l_errno;
+    char l_errbuf[128];
+    if( pipe(l_pipe) < 0 ){
+        l_errno = errno;
+        strerror_r(l_errno, l_errbuf, sizeof (l_errbuf));
+        log_it( L_ERROR, "Error detected, can't create pipe(): '%s' (%d)", l_errbuf, l_errno);
+        DAP_DELETE(l_es);
+        return NULL;
+    }//else
+     //   log_it(L_DEBUG, "Created one-way unnamed bytestream pipe %d->%d", l_pipe[0], l_pipe[1]);
+    l_es->fd = l_pipe[0];
+    l_es->fd2 = l_pipe[1];
+#else
+#error "No defined s_create_type_pipe() for your platform"
+#endif
+    return l_es;
+}
 
-  if ( epoll_ctl( a_es->dap_worker->epoll_fd, EPOLL_CTL_ADD, a_es->socket, &a_es->ev ) == 1 )
-    log_it( L_CRITICAL, "Can't add event socket's handler to epoll_fd" );
+/**
+ * @brief dap_events_socket_create_type_pipe_mt
+ * @param a_w
+ * @param a_callback
+ * @param a_flags
+ * @return
+ */
+dap_events_socket_t * dap_events_socket_create_type_pipe_mt(dap_worker_t * a_w, dap_events_socket_callback_t a_callback, uint32_t a_flags)
+{
+    dap_events_socket_t * l_es = s_create_type_pipe(a_w, a_callback, a_flags);
+    dap_events_socket_assign_on_worker_unsafe(l_es,a_w);
+    return  l_es;
+}
 
-  pthread_mutex_unlock( &a_es->dap_worker->locker_on_count );
+/**
+ * @brief dap_events_socket_create_type_pipe_unsafe
+ * @param a_w
+ * @param a_callback
+ * @param a_flags
+ * @return
+ */
+dap_events_socket_t * dap_events_socket_create_type_pipe_unsafe(dap_worker_t * a_w, dap_events_socket_callback_t a_callback, uint32_t a_flags)
+{
+    dap_events_socket_t * l_es = s_create_type_pipe(a_w, a_callback, a_flags);
+    dap_events_socket_assign_on_worker_unsafe(l_es,a_w);
+    return  l_es;
+}
+
+/**
+ * @brief s_create_type_queue
+ * @param a_w
+ * @param a_flags
+ * @return
+ */
+dap_events_socket_t * s_create_type_queue_ptr(dap_worker_t * a_w, dap_events_socket_callback_queue_ptr_t a_callback)
+{
+    dap_events_socket_t * l_es = DAP_NEW_Z(dap_events_socket_t);
+    l_es->type = DESCRIPTOR_TYPE_QUEUE;
+    l_es->flags =  DAP_SOCK_QUEUE_PTR;
+    if (a_w){
+        l_es->events = a_w->events;
+        l_es->worker = a_w;
+    }
+    l_es->callbacks.queue_ptr_callback = a_callback; // Arm event callback
+    l_es->ev_base_flags = EPOLLIN | EPOLLERR | EPOLLRDHUP | EPOLLHUP;
+
+#ifdef DAP_EVENTS_CAPS_QUEUE_PIPE2
+    int l_pipe[2];
+    int l_errno;
+    char l_errbuf[128];
+    if( pipe2(l_pipe,O_DIRECT | O_NONBLOCK ) < 0 ){
+        l_errno = errno;
+        strerror_r(l_errno, l_errbuf, sizeof (l_errbuf));
+        switch (l_errno) {
+            case EINVAL: log_it(L_CRITICAL, "Too old linux version thats doesn't support O_DIRECT flag for pipes (%s)", l_errbuf); break;
+            default: log_it( L_ERROR, "Error detected, can't create pipe(): '%s' (%d)", l_errbuf, l_errno);
+        }
+        DAP_DELETE(l_es);
+        return NULL;
+    }//else
+     //   log_it(L_DEBUG, "Created one-way unnamed packet pipe %d->%d", l_pipe[0], l_pipe[1]);
+    l_es->fd = l_pipe[0];
+    l_es->fd2 = l_pipe[1];
+    const int l_file_buf_size = 64;
+    FILE* l_sys_max_pipe_size_fd = fopen("/proc/sys/fs/pipe-max-size", "r");
+    if (l_sys_max_pipe_size_fd == NULL) {
+        log_it(L_WARNING, "Сan't resize pipe buffer");
+    }
+    char l_file_buf[l_file_buf_size];
+    memset(l_file_buf, 0, l_file_buf_size);
+    fread(l_file_buf, l_file_buf_size, 1, l_sys_max_pipe_size_fd);
+    uint64_t l_sys_max_pipe_size = strtoull(l_file_buf, 0, 10);
+    if (l_sys_max_pipe_size && fcntl(l_pipe[0], F_SETPIPE_SZ, l_sys_max_pipe_size) == l_sys_max_pipe_size) {
+        log_it(L_DEBUG, "Successfully resized pipe buffer to %lld", l_sys_max_pipe_size);
+    }
+#elif defined (DAP_EVENTS_CAPS_QUEUE_POSIX)
+    char l_mq_name[64];
+    struct mq_attr l_mq_attr ={0};
+    l_mq_attr.mq_curmsgs = 9;
+    l_mq_attr.mq_maxmsg = 9; // Don't think we need to hold more than 1024 messages
+    l_mq_attr.mq_msgsize = sizeof (void *); // We send only pointer on memory,
+                                            // so use it with shared memory if you do access from another process
+    snprintf(l_mq_name,sizeof (l_mq_name),"/dap-%d-esocket-0x%p",getpid(),l_es);
+
+    l_es->mqd = mq_open(l_mq_name,O_CREAT|O_RDWR,S_IRWXU, &l_mq_attr);
+    if (l_es->mqd == -1 ){
+        int l_errno = errno;
+        char l_errbuf[128]={0};
+        strerror_r(l_errno,l_errbuf,sizeof (l_errbuf) );
+        DAP_DELETE(l_es);
+        l_es = NULL;
+        log_it(L_CRITICAL,"Can't create mqueue descriptor %s: \"%s\" code %d",l_mq_name, l_errbuf, l_errno);
+    }
+#else
+#error "Not implemented s_create_type_queue_ptr() on your platform"
+#endif
+    return l_es;
+}
+
+/**
+ * @brief dap_events_socket_create_type_queue_mt
+ * @param a_w
+ * @param a_callback
+ * @param a_flags
+ * @return
+ */
+dap_events_socket_t * dap_events_socket_create_type_queue_ptr_mt(dap_worker_t * a_w, dap_events_socket_callback_queue_ptr_t a_callback)
+{
+    dap_events_socket_t * l_es = s_create_type_queue_ptr(a_w, a_callback);
+    assert(l_es);
+    // If no worker - don't assign
+    if ( a_w)
+        dap_events_socket_assign_on_worker_mt(l_es,a_w);
+    return  l_es;
+}
+
+
+/**
+ * @brief dap_events_socket_create_type_queue
+ * @param a_w
+ * @param a_callback
+ * @return
+ */
+dap_events_socket_t * dap_events_socket_create_type_queue_ptr_unsafe(dap_worker_t * a_w, dap_events_socket_callback_queue_ptr_t a_callback)
+{
+    dap_events_socket_t * l_es = s_create_type_queue_ptr(a_w, a_callback);
+    assert(l_es);
+    // If no worker - don't assign
+    if ( a_w)
+        dap_events_socket_assign_on_worker_unsafe(l_es,a_w);
+    return  l_es;
+}
+
+/**
+ * @brief dap_events_socket_queue_proc_input
+ * @param a_esocket
+ */
+int dap_events_socket_queue_proc_input_unsafe(dap_events_socket_t * a_esocket)
+{
+    if (a_esocket->callbacks.queue_callback){
+        if (a_esocket->flags & DAP_SOCK_QUEUE_PTR){
+            void * l_queue_ptr = NULL;
+#if defined(DAP_EVENTS_CAPS_QUEUE_PIPE2)
+            if(read( a_esocket->fd, &l_queue_ptr,sizeof (void *)) == sizeof (void *))
+                a_esocket->callbacks.queue_ptr_callback(a_esocket, l_queue_ptr);
+            else if ( (errno != EAGAIN) && (errno != EWOULDBLOCK) )  // we use blocked socket for now but who knows...
+                log_it(L_WARNING, "Can't read packet from pipe");
+#elif defined (DAP_EVENTS_CAPS_QUEUE_POSIX)
+            struct timespec s_timeout;
+            clock_gettime(CLOCK_REALTIME, &s_timeout);
+            s_timeout.tv_sec+=1;
+            ssize_t l_ret = mq_timedreceive(a_esocket->mqd,(char*) &l_queue_ptr, sizeof (l_queue_ptr),NULL,&s_timeout );
+            if (l_ret == -1){
+                int l_errno = errno;
+                char l_errbuf[128]={0};
+                strerror_r(l_errno, l_errbuf, sizeof (l_errbuf));
+                log_it(L_ERROR, "Error in esocket queue_ptr:\"%s\" code %d", l_errbuf, l_errno);
+                return -1;
+            }
+            a_esocket->callbacks.queue_ptr_callback (a_esocket, l_queue_ptr);
+#else
+#error "No Queue fetch mechanism implemented on your platform"
+#endif
+        }else{
+            size_t l_read = read(a_esocket->socket, a_esocket->buf_in,sizeof(a_esocket->buf_in));
+            a_esocket->callbacks.queue_callback(a_esocket,a_esocket->buf_in,l_read );
+        }
+    }else{
+        log_it(L_ERROR, "Queue socket %d accepted data but callback is NULL ", a_esocket->socket);
+        return -1;
+    }
+    return 0;
+}
+
+/**
+ * @brief s_create_type_event
+ * @param a_w
+ * @param a_callback
+ * @return
+ */
+dap_events_socket_t * s_create_type_event(dap_worker_t * a_w, dap_events_socket_callback_event_t a_callback)
+{
+    dap_events_socket_t * l_es = DAP_NEW_Z(dap_events_socket_t);
+    l_es->type = DESCRIPTOR_TYPE_EVENT;
+    if (a_w){
+        l_es->events = a_w->events;
+        l_es->worker = a_w;
+    }
+    l_es->callbacks.event_callback = a_callback; // Arm event callback
+    l_es->ev_base_flags = EPOLLIN | EPOLLERR | EPOLLRDHUP | EPOLLHUP;
+
+#ifdef DAP_EVENTS_CAPS_EVENT_EVENTFD
+    if((l_es->fd = eventfd(0,0) ) < 0 ){
+        int l_errno = errno;
+        char l_errbuf[128];
+        strerror_r(l_errno, l_errbuf, sizeof (l_errbuf));
+        switch (l_errno) {
+            case EINVAL: log_it(L_CRITICAL, "An unsupported value was specified in flags: \"%s\" (%d)", l_errbuf, l_errno); break;
+            case EMFILE: log_it(L_CRITICAL, "The per-process limit on the number of open file descriptors has been reached: \"%s\" (%d)", l_errbuf, l_errno); break;
+            case ENFILE: log_it(L_CRITICAL, "The system-wide limit on the total number of open files has been reached: \"%s\" (%d)", l_errbuf, l_errno); break;
+            case ENODEV: log_it(L_CRITICAL, "Could not mount (internal) anonymous inode device: \"%s\" (%d)", l_errbuf, l_errno); break;
+            case ENOMEM: log_it(L_CRITICAL, "There was insufficient memory to create a new eventfd file descriptor: \"%s\" (%d)", l_errbuf, l_errno); break;
+            default: log_it( L_ERROR, "Error detected, can't create eventfd: '%s' (%d)", l_errbuf, l_errno);
+        }
+        DAP_DELETE(l_es);
+        return NULL;
+    }else
+        log_it(L_DEBUG, "Created eventfd descriptor %d", l_es->fd );
+#endif
+    return l_es;
+}
+
+/**
+ * @brief dap_events_socket_create_type_event_mt
+ * @param a_w
+ * @param a_callback
+ * @return
+ */
+dap_events_socket_t * dap_events_socket_create_type_event_mt(dap_worker_t * a_w, dap_events_socket_callback_event_t a_callback)
+{
+    dap_events_socket_t * l_es = s_create_type_event(a_w, a_callback);
+    // If no worker - don't assign
+    if ( a_w)
+        dap_events_socket_assign_on_worker_mt(l_es,a_w);
+    return  l_es;
+}
+
+/**
+ * @brief dap_events_socket_create_type_event_unsafe
+ * @param a_w
+ * @param a_callback
+ * @return
+ */
+dap_events_socket_t * dap_events_socket_create_type_event_unsafe(dap_worker_t * a_w, dap_events_socket_callback_event_t a_callback)
+{
+    dap_events_socket_t * l_es = s_create_type_event(a_w, a_callback);
+    // If no worker - don't assign
+    if ( a_w)
+        dap_events_socket_assign_on_worker_unsafe(l_es,a_w);
+    return  l_es;
+}
+
+/**
+ * @brief dap_events_socket_event_proc_input_unsafe
+ * @param a_esocket
+ */
+void dap_events_socket_event_proc_input_unsafe(dap_events_socket_t *a_esocket)
+{
+    if (a_esocket->callbacks.event_callback ){
+#if defined(DAP_EVENTS_CAPS_EVENT_EVENTFD )
+        eventfd_t l_value;
+        if(eventfd_read( a_esocket->fd, &l_value)==0 ){ // would block if not ready
+            a_esocket->callbacks.event_callback(a_esocket, l_value);
+        }else if ( (errno != EAGAIN) && (errno != EWOULDBLOCK) ){  // we use blocked socket for now but who knows...
+            int l_errno = errno;
+            char l_errbuf[128];
+            strerror_r(l_errno, l_errbuf, sizeof (l_errbuf));
+            log_it(L_WARNING, "Can't read packet from event fd: \"%s\"(%d)", l_errbuf, l_errno);
+        }else
+            return; // do nothing
+#else
+#error "No Queue fetch mechanism implemented on your platform"
+#endif
+    }else
+        log_it(L_ERROR, "Queue socket %d accepted data but callback is NULL ", a_esocket->socket);
+}
+
+/**
+ * @brief dap_events_socket_send_event
+ * @param a_es
+ * @param a_arg
+ */
+int dap_events_socket_queue_ptr_send( dap_events_socket_t * a_es, void* a_arg)
+{
+#if defined(DAP_EVENTS_CAPS_QUEUE_PIPE2)
+    int ret = write(a_es->fd2, &a_arg, sizeof(a_arg));
+    int l_errno = errno;
+    if (ret == sizeof(a_arg) )
+        return  0;
+    else{
+        char l_errbuf[128];
+        strerror_r(l_errno, l_errbuf, sizeof (l_errbuf));
+        log_it(L_ERROR, "Can't send ptr to queue:\"%s\" code %d", l_errbuf, l_errno);
+        return l_errno;
+    }
+#elif defined (DAP_EVENTS_CAPS_QUEUE_POSIX)
+    struct timespec l_timeout;
+    clock_gettime(CLOCK_REALTIME, &l_timeout);
+    l_timeout.tv_sec+=2; // Not wait more than 1 second to get and 2 to send
+    int ret = mq_timedsend(a_es->mqd, (const char *)&a_arg,sizeof (a_arg),0, &l_timeout );
+    int l_errno = errno;
+    if (ret == sizeof(a_arg) )
+        return  0;
+    else
+        return l_errno;
+#else
+#error "Not implemented dap_events_socket_queue_ptr_send() for this platform"
+#endif
+}
+
+/**
+ * @brief dap_events_socket_event_signal
+ * @param a_es
+ * @param a_value
+ * @return
+ */
+int dap_events_socket_event_signal( dap_events_socket_t * a_es, uint64_t a_value)
+{
+#if defined(DAP_EVENTS_CAPS_EVENT_EVENTFD)
+    int ret = eventfd_write( a_es->fd2,a_value);
+    int l_errno = errno;
+    if (ret == 0 )
+        return  0;
+    else if ( ret < 0)
+        return l_errno;
+    else
+        return 1;
+#else
+#error "Not implemented dap_events_socket_event_signal() for this platform"
+#endif
+}
+
+/**
+ * @brief dap_events_socket_queue_on_remove_and_delete
+ * @param a_es
+ */
+void dap_events_socket_queue_on_remove_and_delete(dap_events_socket_t* a_es)
+{
+    int l_ret= dap_events_socket_queue_ptr_send( a_es->worker->queue_es_delete, a_es );
+    if( l_ret != 0 ){
+        log_it(L_ERROR, "Queue send returned %d", l_ret);
+    }
 }
 
 /**
@@ -142,12 +552,15 @@ dap_events_socket_t * dap_events_socket_wrap2( dap_server_t *a_server, struct da
   assert( a_callbacks );
   assert( a_server );
 
-  log_it( L_DEBUG,"Sap event socket wrapped around %d sock", a_sock );
+  //log_it( L_DEBUG,"Dap event socket wrapped around %d sock", a_sock );
   dap_events_socket_t * ret = DAP_NEW_Z( dap_events_socket_t );
 
   ret->socket = a_sock;
   ret->events = a_events;
-  ret->callbacks = a_callbacks;
+  ret->server = a_server;
+  ret->is_dont_reset_write_flag = true;
+
+  memcpy(&ret->callbacks,a_callbacks, sizeof ( ret->callbacks) );
 
   ret->flags = DAP_SOCK_READY_TO_READ;
   ret->is_pingable = true;
@@ -157,9 +570,6 @@ dap_events_socket_t * dap_events_socket_wrap2( dap_server_t *a_server, struct da
   HASH_ADD_INT( a_events->sockets, socket, ret );
   pthread_rwlock_unlock( &a_events->sockets_rwlock );
 
-  if( a_callbacks->new_callback )
-    a_callbacks->new_callback( ret, NULL ); // Init internal structure
-
   return ret;
 }
 
@@ -169,17 +579,17 @@ dap_events_socket_t * dap_events_socket_wrap2( dap_server_t *a_server, struct da
  * @param sh
  * @return
  */
-dap_events_socket_t *dap_events_socket_find( int sock, struct dap_events *a_events )
+dap_events_socket_t *dap_events_socket_find_unsafe( int sock, struct dap_events *a_events )
 {
-  dap_events_socket_t *ret = NULL;
-  if(!a_events)
-      return NULL;
-  pthread_rwlock_wrlock( &a_events->sockets_rwlock );
-  if(a_events->sockets)
-      HASH_FIND_INT( a_events->sockets, &sock, ret );
-  pthread_rwlock_unlock( &a_events->sockets_rwlock );
-
-  return ret;
+    // Why we have only unsafe socket? Because you need to lock sockets_rwlock when do any operations with
+    // socket that you've find in global list
+    dap_events_socket_t *ret = NULL;
+    if(!a_events)
+        return NULL;
+    if(a_events->sockets)
+        HASH_FIND_INT( a_events->sockets, &sock, ret );
+
+    return ret;
 }
 
 /**
@@ -187,12 +597,13 @@ dap_events_socket_t *dap_events_socket_find( int sock, struct dap_events *a_even
  * @param sc
  * @param isReady
  */
-void dap_events_socket_set_readable( dap_events_socket_t *sc, bool is_ready )
+void dap_events_socket_set_readable_unsafe( dap_events_socket_t *sc, bool is_ready )
 {
   if( is_ready == (bool)(sc->flags & DAP_SOCK_READY_TO_READ) )
     return;
 
-  sc->ev.events = EPOLLERR;
+  sc->ev.events = sc->ev_base_flags;
+  sc->ev.events |= EPOLLERR;
 
   if ( is_ready )
     sc->flags |= DAP_SOCK_READY_TO_READ;
@@ -208,11 +619,13 @@ void dap_events_socket_set_readable( dap_events_socket_t *sc, bool is_ready )
     events |= EPOLLOUT;
 
   sc->ev.events = events;
-
-  if ( epoll_ctl(sc->dap_worker->epoll_fd, EPOLL_CTL_MOD, sc->socket, &sc->ev) == -1 )
-    log_it( L_ERROR,"Can't update read client socket state in the epoll_fd" );
-  else
-    dap_events_thread_wake_up( &sc->events->proc_thread );
+  if (sc->worker)
+    if ( epoll_ctl(sc->worker->epoll_fd, EPOLL_CTL_MOD, sc->socket, &sc->ev) == -1 ){
+        int l_errno = errno;
+        char l_errbuf[128];
+        strerror_r( l_errno, l_errbuf, sizeof (l_errbuf));
+        log_it( L_ERROR,"Can't update read client socket state in the epoll_fd: \"%s\" (%d)", l_errbuf, l_errno );
+    }
 }
 
 /**
@@ -220,140 +633,247 @@ void dap_events_socket_set_readable( dap_events_socket_t *sc, bool is_ready )
  * @param sc
  * @param isReady
  */
-void dap_events_socket_set_writable( dap_events_socket_t *sc, bool is_ready )
+void dap_events_socket_set_writable_unsafe( dap_events_socket_t *sc, bool a_is_ready )
 {
-  pthread_mutex_lock(&sc->write_hold);
-
-  if ( is_ready == (bool)(sc->flags & DAP_SOCK_READY_TO_WRITE) ) {
-    pthread_mutex_unlock(&sc->write_hold);
-    return;
-  }
-
-  if ( is_ready )
-    sc->flags |= DAP_SOCK_READY_TO_WRITE;
-  else
-    sc->flags ^= DAP_SOCK_READY_TO_WRITE;
+    if ( a_is_ready == (bool)(sc->flags & DAP_SOCK_READY_TO_WRITE) ) {
+        return;
+    }
 
-  int events = EPOLLERR;
+    if ( a_is_ready )
+        sc->flags |= DAP_SOCK_READY_TO_WRITE;
+    else
+        sc->flags ^= DAP_SOCK_READY_TO_WRITE;
 
-  if( sc->flags & DAP_SOCK_READY_TO_READ )
-    events |= EPOLLIN;
+    int events = sc->ev_base_flags | EPOLLERR;
 
-  if( sc->flags & DAP_SOCK_READY_TO_WRITE )
-    events |= EPOLLOUT;
+    // Check & add
+    if( sc->flags & DAP_SOCK_READY_TO_READ )
+        events |= EPOLLIN;
 
-  pthread_mutex_unlock(&sc->write_hold);
+    if( sc->flags & DAP_SOCK_READY_TO_WRITE )
+        events |= EPOLLOUT;
 
-  sc->ev.events = events;
+    sc->ev.events = events;
 
-  if ( epoll_ctl(sc->dap_worker->epoll_fd, EPOLL_CTL_MOD, sc->socket, &sc->ev) == -1 )
-    log_it(L_ERROR,"Can't update write client socket state in the epoll_fd");
-  else
-    dap_events_thread_wake_up( &sc->events->proc_thread );
+    if (sc->worker)
+        if ( epoll_ctl(sc->worker->epoll_fd, EPOLL_CTL_MOD, sc->socket, &sc->ev) ){
+            int l_errno = errno;
+            char l_errbuf[128];
+            strerror_r(l_errno, l_errbuf, sizeof (l_errbuf));
+            log_it(L_ERROR,"Can't update write client socket state in the epoll_fd %d: \"%s\" (%d)",
+                   sc->worker->epoll_fd, l_errbuf, l_errno);
+        }
 }
 
-
 /**
- * @brief dap_events_socket_kill_socket
+ * @brief dap_events_socket_remove Removes the client from the list
  * @param sc Connection instance
  */
-int dap_events_socket_kill_socket( dap_events_socket_t *a_es )
+void dap_events_socket_remove_and_delete_unsafe( dap_events_socket_t *a_es, bool preserve_inheritor )
 {
-  if ( !a_es ) {
-    log_it( L_ERROR, "dap_events_socket_kill_socket( NULL )" );
-    return -1;
-  }
+    if ( !a_es )
+        return;
 
-  if( !a_es->dap_worker ) {
-      log_it( L_WARNING, "%s: socket %u has no worker thread", __PRETTY_FUNCTION__, a_es->socket );
-      a_es->kill_signal = true;
-      return 0;
-  }
+    //log_it( L_DEBUG, "es is going to be removed from the lists and free the memory (0x%016X)", a_es );
+    dap_events_socket_remove_from_worker_unsafe(a_es, a_es->worker);
 
-  uint32_t tn = a_es->dap_worker->number_thread;
+    if (a_es->events){ // It could be socket NOT from events
+        pthread_rwlock_wrlock( &a_es->events->sockets_rwlock );
+        if(!dap_events_socket_find_unsafe(a_es->socket, a_es->events)){
+            log_it( L_ERROR, "dap_events_socket 0x%x already deleted", a_es);
+            pthread_rwlock_unlock( &a_es->events->sockets_rwlock );
+            return ;
+        }
 
-  //dap_events_t *d_ev = w->events;
+        if(a_es->events->sockets)
+            HASH_DEL( a_es->events->sockets, a_es );
+        pthread_rwlock_unlock( &a_es->events->sockets_rwlock );
+    }
+    //log_it( L_DEBUG, "dap_events_socket wrapped around %d socket is removed", a_es->socket );
 
-  if ( a_es->kill_signal ) {
-    return 0;
-  }
+    if( a_es->callbacks.delete_callback )
+        a_es->callbacks.delete_callback( a_es, NULL ); // Init internal structure
 
-  log_it( L_DEBUG, "KILL %u socket! (in queue) [ thread %u ]", a_es->socket, tn );
+    if ( a_es->_inheritor && !preserve_inheritor )
+        DAP_DELETE( a_es->_inheritor );
 
-  a_es->kill_signal = true;
-  //DL_LIST_ADD_NODE_HEAD( d_ev->to_kill_sockets, a_es, kprev, knext, w->event_to_kill_count );
+    if ( a_es->socket && a_es->socket != -1) {
+#ifdef _WIN32
+        closesocket( a_es->socket );
+#else
+        close( a_es->socket );
+#ifdef DAP_EVENTS_CAPS_QUEUE_PIPE2
+        if( a_es->type == DESCRIPTOR_TYPE_QUEUE){
+            close( a_es->fd2);
+        }
+#endif
 
-  return 0;
+#endif
+    }
+    DAP_DELETE( a_es );
 }
 
 /**
- * @brief dap_events_socket_remove Removes the client from the list
- * @param sc Connection instance
+ * @brief dap_events_socket_delete
+ * @param a_es
  */
-void dap_events_socket_delete( dap_events_socket_t *a_es, bool preserve_inheritor )
+void dap_events_socket_remove_from_worker_unsafe( dap_events_socket_t *a_es, dap_worker_t * a_worker)
 {
-  if ( !a_es ) return;
-
-  log_it( L_DEBUG, "es is going to be removed from the lists and free the memory (0x%016X)", a_es );
-
-  if(!dap_events_socket_find(a_es->socket, a_es->events)){
-      log_it( L_ERROR, "dap_events_socket 0x%x already deleted", a_es);
-      return ;
-  }
-  pthread_rwlock_wrlock( &a_es->events->sockets_rwlock );
-  if(a_es->events->sockets)
-    HASH_DEL( a_es->events->sockets, a_es );
-  pthread_rwlock_unlock( &a_es->events->sockets_rwlock );
-
-  log_it( L_DEBUG, "dap_events_socket wrapped around %d socket is removed", a_es->socket );
-
-  if( a_es->callbacks->delete_callback )
-    a_es->callbacks->delete_callback( a_es, NULL ); // Init internal structure
-
-  if ( a_es->_inheritor && !preserve_inheritor )
-    DAP_DELETE( a_es->_inheritor );
+    if (!a_es->worker) {
+        // Socket already removed from worker
+        return;
+    }
+    if ( epoll_ctl( a_worker->epoll_fd, EPOLL_CTL_DEL, a_es->socket, &a_es->ev) == -1 ) {
+        int l_errno = errno;
+        char l_errbuf[128];
+        strerror_r(l_errno, l_errbuf, sizeof (l_errbuf));
+        log_it( L_ERROR,"Can't remove event socket's handler from the epoll_fd %d  \"%s\" (%d)",
+                a_worker->epoll_fd, l_errbuf, l_errno);
+    } //else
+      //  log_it( L_DEBUG,"Removed epoll's event from dap_worker #%u", a_worker->id );
+    a_worker->event_sockets_count--;
+    if(a_worker->esockets)
+        HASH_DELETE(hh_worker,a_worker->esockets, a_es);
+    a_es->worker = NULL;
+}
 
-  if ( a_es->socket ) {
-#ifdef _WIN32
-    closesocket( a_es->socket );
-#else
-    close( a_es->socket );
-#endif
-  }
-  pthread_mutex_destroy(&a_es->write_hold);
-  DAP_DELETE( a_es );
+/**
+ * @brief dap_events_socket_check_unsafe
+ * @param a_worker
+ * @param a_es
+ * @return
+ */
+bool dap_events_socket_check_unsafe(dap_worker_t * a_worker,dap_events_socket_t * a_es)
+{
+    if (a_es){
+        if ( a_worker->esockets){
+            dap_events_socket_t * l_es = NULL;
+            HASH_FIND(hh_worker,a_worker->esockets,&a_es, sizeof(a_es), l_es );
+            return l_es == a_es;
+        }else
+            return false;
+    }else
+        return false;
 }
 
 /**
- * @brief dap_events_socket_delete
+ * @brief dap_events_socket_remove_and_delete
  * @param a_es
+ * @param preserve_inheritor
  */
-void dap_events_socket_remove( dap_events_socket_t *a_es)
+void dap_events_socket_remove_and_delete_mt(dap_worker_t * a_w,  dap_events_socket_t *a_es )
 {
-  pthread_mutex_lock(&a_es->dap_worker->locker_on_count);
-  if ( epoll_ctl( a_es->dap_worker->epoll_fd, EPOLL_CTL_DEL, a_es->socket, &a_es->ev) == -1 )
-     log_it( L_ERROR,"Can't remove event socket's handler from the epoll_fd" );
-  else
-     log_it( L_DEBUG,"Removed epoll's event from dap_worker #%u", a_es->dap_worker->number_thread );
+    if(a_w)
+        dap_events_socket_queue_ptr_send( a_w->queue_es_delete, a_es );
+}
 
-  DL_DELETE( a_es->events->dlsockets, a_es );
-  a_es->dap_worker->event_sockets_count --;
-  pthread_mutex_unlock(&a_es->dap_worker->locker_on_count);
+/**
+ * @brief dap_events_socket_set_readable_mt
+ * @param a_w
+ * @param a_es
+ * @param a_is_ready
+ */
+void dap_events_socket_set_readable_mt(dap_worker_t * a_w, dap_events_socket_t * a_es,bool a_is_ready)
+{
+    dap_worker_msg_io_t * l_msg = DAP_NEW_Z(dap_worker_msg_io_t);
+    l_msg->esocket = a_es;
+    if (a_is_ready)
+        l_msg->flags_set = DAP_SOCK_READY_TO_READ;
+    else
+        l_msg->flags_unset = DAP_SOCK_READY_TO_READ;
+
+    int l_ret= dap_events_socket_queue_ptr_send(a_w->queue_es_io, l_msg );
+    if (l_ret!=0){
+        log_it(L_ERROR, "Wasn't send pointer to queue: code %d", l_ret);
+        DAP_DELETE(l_msg);
+    }
 }
 
-void dap_events_socket_remove_and_delete( dap_events_socket_t *a_es,  bool preserve_inheritor )
+/**
+ * @brief dap_events_socket_set_writable_mt
+ * @param sc
+ * @param is_ready
+ */
+void dap_events_socket_set_writable_mt(dap_worker_t * a_w, dap_events_socket_t * a_es,bool a_is_ready)
 {
-  pthread_mutex_lock(&a_es->dap_worker->locker_on_count);
-  if ( epoll_ctl( a_es->dap_worker->epoll_fd, EPOLL_CTL_DEL, a_es->socket, &a_es->ev) == -1 )
-     log_it( L_ERROR,"Can't remove event socket's handler from the epoll_fd" );
-  else
-     log_it( L_DEBUG,"Removed epoll's event from dap_worker #%u", a_es->dap_worker->number_thread );
+    dap_worker_msg_io_t * l_msg = DAP_NEW_Z(dap_worker_msg_io_t);
+    l_msg->esocket = a_es;
+    if (a_is_ready)
+        l_msg->flags_set = DAP_SOCK_READY_TO_WRITE;
+    else
+        l_msg->flags_unset = DAP_SOCK_READY_TO_WRITE;
+
+    int l_ret= dap_events_socket_queue_ptr_send(a_w->queue_es_io, l_msg );
+    if (l_ret!=0){
+        log_it(L_ERROR, "Wasn't send pointer to queue: code %d", l_ret);
+        DAP_DELETE(l_msg);
+    }
+}
 
-  DL_DELETE( a_es->events->dlsockets, a_es );
-  a_es->dap_worker->event_sockets_count --;
-  pthread_mutex_unlock(&a_es->dap_worker->locker_on_count);
+/**
+ * @brief dap_events_socket_write_mt
+ * @param sc
+ * @param data
+ * @param data_size
+ * @return
+ */
+size_t dap_events_socket_write_mt(dap_worker_t * a_w,dap_events_socket_t *a_es, const void * data, size_t l_data_size)
+{
+    dap_worker_msg_io_t * l_msg = DAP_NEW_Z(dap_worker_msg_io_t);
+    l_msg->esocket = a_es;
+    l_msg->data = DAP_NEW_SIZE(void,l_data_size);
+    l_msg->data_size = l_data_size;
+    l_msg->flags_set = DAP_SOCK_READY_TO_WRITE;
+    memcpy( l_msg->data, data, l_data_size);
+
+    int l_ret= dap_events_socket_queue_ptr_send(a_w->queue_es_io, l_msg );
+    if (l_ret!=0){
+        log_it(L_ERROR, "Wasn't send pointer to queue: code %d", l_ret);
+        DAP_DELETE(l_msg);
+        return 0;
+    }
+    return  l_data_size;
+}
 
-  dap_events_socket_delete( a_es, preserve_inheritor );
+/**
+ * @brief dap_events_socket_write_f_mt
+ * @param a_es
+ * @param format
+ * @return
+ */
+size_t dap_events_socket_write_f_mt(dap_worker_t * a_w,dap_events_socket_t *a_es, const char * format,...)
+{
+    va_list ap, ap_copy;
+    va_start(ap,format);
+    va_copy(ap_copy, ap);
+    int l_data_size = dap_vsnprintf(NULL,0,format,ap);
+    va_end(ap);
+    if (l_data_size <0 ){
+        log_it(L_ERROR,"Can't write out formatted data '%s' with values",format);
+        va_end(ap_copy);
+        return 0;
+    }
+    dap_worker_msg_io_t * l_msg = DAP_NEW_Z(dap_worker_msg_io_t);
+    l_msg->esocket = a_es;
+    l_msg->data = DAP_NEW_SIZE(void,l_data_size + 1);
+    l_msg->flags_set = DAP_SOCK_READY_TO_WRITE;
+    l_data_size = dap_vsprintf(l_msg->data,format,ap_copy);
+    va_end(ap_copy);
+    if (l_data_size <0 ){
+        log_it(L_ERROR,"Can't write out formatted data '%s' with values",format);
+        DAP_DELETE(l_msg->data);
+        DAP_DELETE(l_msg);
+        return 0;
+    }
+    l_msg->data_size = l_data_size;
+    int l_ret= dap_events_socket_queue_ptr_send(a_w->queue_es_io, l_msg );
+    if (l_ret!=0){
+        log_it(L_ERROR, "Wasn't send pointer to queue: code %d", l_ret);
+        DAP_DELETE(l_msg->data);
+        DAP_DELETE(l_msg);
+        return 0;
+    }
+    return l_data_size;
 }
 
 /**
@@ -363,14 +883,17 @@ void dap_events_socket_remove_and_delete( dap_events_socket_t *a_es,  bool prese
  * @param data_size Size of data to write
  * @return Number of bytes that were placed into the buffer
  */
-size_t dap_events_socket_write(dap_events_socket_t *sc, const void * data, size_t data_size)
+size_t dap_events_socket_write_unsafe(dap_events_socket_t *sc, const void * data, size_t data_size)
 {
+    if(sc->buf_out_size>sizeof(sc->buf_out)){
+        log_it(L_DEBUG,"write buffer already overflow size=%u/max=%u", sc->buf_out_size, sizeof(sc->buf_out));
+        return 0;
+    }
     //log_it(L_DEBUG,"dap_events_socket_write %u sock data %X size %u", sc->socket, data, data_size );
-     pthread_mutex_lock(&sc->write_hold);
      data_size = ((sc->buf_out_size+data_size)<(sizeof(sc->buf_out)))?data_size:(sizeof(sc->buf_out)-sc->buf_out_size );
      memcpy(sc->buf_out+sc->buf_out_size,data,data_size);
      sc->buf_out_size+=data_size;
-     pthread_mutex_unlock(&sc->write_hold);
+     dap_events_socket_set_writable_unsafe(sc, true);
      return data_size;
 }
 
@@ -380,11 +903,10 @@ size_t dap_events_socket_write(dap_events_socket_t *sc, const void * data, size_
  * @param format Format
  * @return Number of bytes that were placed into the buffer
  */
-size_t dap_events_socket_write_f(dap_events_socket_t *sc, const char * format,...)
+size_t dap_events_socket_write_f_unsafe(dap_events_socket_t *sc, const char * format,...)
 {
-    log_it(L_DEBUG,"dap_events_socket_write_f %u sock", sc->socket );
+    //log_it(L_DEBUG,"dap_events_socket_write_f %u sock", sc->socket );
 
-    pthread_mutex_lock(&sc->write_hold);
     size_t max_data_size = sizeof(sc->buf_out)-sc->buf_out_size;
     va_list ap;
     va_start(ap,format);
@@ -395,18 +917,18 @@ size_t dap_events_socket_write_f(dap_events_socket_t *sc, const char * format,..
     }else{
         log_it(L_ERROR,"Can't write out formatted data '%s'",format);
     }
-    pthread_mutex_unlock(&sc->write_hold);
+    dap_events_socket_set_writable_unsafe(sc, true);
     return (ret > 0) ? ret : 0;
 }
 
 /**
- * @brief dap_events_socket_read Read data from input buffer
+ * @brief dap_events_socket_pop_from_buf_in Read data from input buffer
  * @param sc Conn instasnce
  * @param data Pointer to memory where to store the data
  * @param data_size Size of data to read
  * @return Actual bytes number that were read
  */
-size_t dap_events_socket_read(dap_events_socket_t *sc, void *data, size_t data_size)
+size_t dap_events_socket_pop_from_buf_in(dap_events_socket_t *sc, void *data, size_t data_size)
 {
 //    log_it(L_DEBUG,"dap_events_socket_read %u sock data %X size %u", sc->socket, data, data_size );
 
diff --git a/dap-sdk/net/core/dap_proc_queue.c b/dap-sdk/net/core/dap_proc_queue.c
new file mode 100644
index 0000000000000000000000000000000000000000..d41f6604ca75a55e570d21031dbe733bd8ec1a00
--- /dev/null
+++ b/dap-sdk/net/core/dap_proc_queue.c
@@ -0,0 +1,101 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Ltd.   https://demlabs.net
+ * Copyright  (c) 2020
+ * All rights reserved.
+
+ This file is part of DAP SDK the open source project
+
+    DAP SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DAP SDK is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "dap_proc_queue.h"
+#include "dap_proc_thread.h"
+#define LOG_TAG "dap_proc_queue"
+
+
+typedef struct dap_proc_queue_msg{
+    dap_proc_queue_callback_t callback;
+    void * callback_arg;
+    bool signal_kill;
+} dap_proc_queue_msg_t;
+
+static void s_queue_esocket_callback( dap_events_socket_t * a_es, void * a_msg);
+
+/**
+ * @brief dap_proc_queue_create
+ * @param a_thread
+ * @return
+ */
+dap_proc_queue_t * dap_proc_queue_create(dap_proc_thread_t * a_thread)
+{
+    dap_proc_queue_t * l_queue = DAP_NEW_Z(dap_proc_queue_t);
+    l_queue->proc_thread = a_thread;
+    l_queue->esocket = dap_events_socket_create_type_queue_ptr_unsafe(NULL,s_queue_esocket_callback);
+    l_queue->esocket->_inheritor = l_queue;
+    return l_queue;
+}
+
+/**
+ * @brief dap_proc_queue_delete
+ * @param a_queue
+ */
+void dap_proc_queue_delete(dap_proc_queue_t * a_queue)
+{
+    dap_proc_queue_msg_t * l_msg = DAP_NEW_Z(dap_proc_queue_msg_t);
+    l_msg->signal_kill = true;
+    dap_events_socket_queue_ptr_send( a_queue->esocket, l_msg );
+}
+
+/**
+ * @brief s_queue_esocket_callback
+ * @param a_es
+ * @param a_msg
+ */
+static void s_queue_esocket_callback( dap_events_socket_t * a_es, void * a_msg)
+{
+    //log_it(L_DEBUG, "New callback in list accepted");
+    dap_proc_queue_t * l_queue = (dap_proc_queue_t*) a_es->_inheritor;
+    dap_proc_queue_msg_t * l_msg = (dap_proc_queue_msg_t*) a_msg;
+
+    // We have callback to add in list
+    if (l_msg->callback){
+        dap_proc_queue_item_t * l_item = DAP_NEW_Z(dap_proc_queue_item_t);
+        l_item->callback = l_msg->callback;
+        l_item->callback_arg = l_msg->callback_arg;
+        l_item->next=l_queue->items;
+        l_queue->items = l_item;
+        // Add on top so after call this callback will be executed first
+        dap_events_socket_queue_ptr_send(l_queue->proc_thread->proc_event,NULL);
+        //log_it( L_DEBUG, "Sent signal to proc thread that we have callbacks on board");
+    }
+    if (l_msg->signal_kill){ // Say to kill this object and delete its inherior dap_proc_queue_t
+        a_es->kill_signal = true;
+    }
+    DAP_DELETE(l_msg);
+}
+
+
+void dap_proc_queue_add_callback(dap_proc_queue_t * a_queue,dap_proc_queue_callback_t a_callback, void * a_callback_arg)
+{
+    dap_proc_queue_msg_t * l_msg = DAP_NEW_Z(dap_proc_queue_msg_t);
+    l_msg->callback = a_callback;
+    l_msg->callback_arg = a_callback_arg;
+    dap_events_socket_queue_ptr_send( a_queue->esocket, l_msg );
+}
+
+void dap_proc_queue_add_callback_auto(dap_proc_queue_callback_t a_callback, void * a_callback_arg)
+{
+    dap_proc_queue_add_callback(  dap_proc_thread_get_auto()->proc_queue ,a_callback,a_callback_arg);
+}
diff --git a/dap-sdk/net/core/dap_proc_thread.c b/dap-sdk/net/core/dap_proc_thread.c
new file mode 100644
index 0000000000000000000000000000000000000000..133bf810016f99f8b82807837e288d53b99586aa
--- /dev/null
+++ b/dap-sdk/net/core/dap_proc_thread.c
@@ -0,0 +1,269 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Ltd.   https://demlabs.net
+ * Copyright  (c) 2020
+ * All rights reserved.
+
+ This file is part of DAP SDK the open source project
+
+    DAP SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DAP SDK is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include "dap_server.h"
+
+#if defined(DAP_EVENTS_CAPS_WEPOLL)
+#elif defined(DAP_EVENTS_CAPS_EPOLL)
+#include <sys/epoll.h>
+#else
+#error "Unimplemented poll for this platform"
+#endif
+
+#include "dap_events.h"
+#include "dap_events_socket.h"
+#include "dap_proc_thread.h"
+
+#define LOG_TAG "dap_proc_thread"
+
+static size_t s_threads_count = 0;
+static dap_proc_thread_t * s_threads = NULL;
+static void * s_proc_thread_function(void * a_arg);
+
+/**
+ * @brief dap_proc_thread_init
+ * @param a_cpu_count 0 means autodetect
+ * @return
+ */
+int dap_proc_thread_init(uint32_t a_threads_count){
+    s_threads_count = a_threads_count ? a_threads_count : dap_get_cpu_count( );
+    s_threads = DAP_NEW_Z_SIZE(dap_proc_thread_t, sizeof (dap_proc_thread_t)* s_threads_count);
+
+    for (size_t i = 0; i < s_threads_count; i++ ){
+        s_threads[i].cpu_id = i;
+        pthread_cond_init( &s_threads[i].started_cond, NULL );
+        pthread_mutex_init( &s_threads[i].started_mutex, NULL );
+        pthread_mutex_lock( &s_threads[i].started_mutex );
+        int res = pthread_create( &s_threads[i].thread_id,NULL, s_proc_thread_function, &s_threads[i] );
+        if (res) {
+            log_it(L_CRITICAL, "Create thread failed with code %d", res);
+            pthread_mutex_unlock( &s_threads[i].started_mutex );
+            return -1;
+        }
+        pthread_cond_wait( &s_threads[i].started_cond, &s_threads[i].started_mutex );
+        pthread_mutex_unlock( &s_threads[i].started_mutex );
+    }
+    return 0;
+}
+
+/**
+ * @brief dap_proc_thread_deinit
+ */
+void dap_proc_thread_deinit()
+{
+    // Signal to cancel working threads and wait for finish
+    for (size_t i = 0; i < s_threads_count; i++ ){
+        pthread_cancel(s_threads[i].thread_id);
+        pthread_join(s_threads[i].thread_id, NULL);
+    }
+}
+
+/**
+ * @brief dap_proc_thread_get
+ * @param a_cpu_id
+ * @return
+ */
+dap_proc_thread_t * dap_proc_thread_get(uint32_t a_cpu_id)
+{
+    return a_cpu_id<s_threads_count? &s_threads[a_cpu_id] : NULL;
+}
+
+/**
+ * @brief dap_proc_thread_get_auto
+ * @return
+ */
+dap_proc_thread_t * dap_proc_thread_get_auto()
+{
+    size_t l_id_min=0;
+    size_t l_size_min=UINT32_MAX;
+    for (size_t i = 0; i < s_threads_count; i++ ){
+        size_t l_queue_size = s_threads[i].proc_queue_size;
+        if( l_queue_size < l_size_min ){
+            l_size_min = l_queue_size;
+            l_id_min = i;
+        }
+    }
+    return &s_threads[l_id_min];
+
+}
+
+/**
+ * @brief s_proc_event_callback
+ * @param a_esocket
+ * @param a_value
+ */
+static void s_proc_event_callback(dap_events_socket_t * a_esocket, void * a_value)
+{
+    (void) a_value;
+    //log_it(L_DEBUG, "Proc event callback");
+    dap_proc_thread_t * l_thread = (dap_proc_thread_t *) a_esocket->_inheritor;
+    dap_proc_queue_item_t * l_item = l_thread->proc_queue->items;
+    dap_proc_queue_item_t * l_item_old = NULL;
+    bool l_is_anybody_for_repeat=false;
+    while(l_item){
+        bool l_is_finished = l_item->callback(l_thread, l_item->callback_arg);
+        if (l_is_finished){
+            if(l_item_old){
+                l_item_old->next = l_item->next;
+                DAP_DELETE(l_item);
+                l_item = l_item_old->next;
+            }else{
+                l_thread->proc_queue->items = l_item->next;
+                DAP_DELETE(l_item);
+                l_item = l_thread->proc_queue->items;
+            }
+
+        }else{
+            l_item_old = l_item;
+            l_item=l_item->next;
+        }
+        l_is_anybody_for_repeat &= (!l_is_finished);
+    }
+    if(l_is_anybody_for_repeat) // Arm event if we have smth to proc again
+        dap_events_socket_event_signal(a_esocket,1);
+}
+
+static void * s_proc_thread_function(void * a_arg)
+{
+
+    dap_proc_thread_t * l_thread = (dap_proc_thread_t*) a_arg;
+    assert(l_thread);
+    dap_cpu_assign_thread_on(l_thread->cpu_id);
+    struct sched_param l_shed_params;
+    l_shed_params.sched_priority = 0;
+    pthread_setschedparam(pthread_self(),SCHED_BATCH ,&l_shed_params);
+    l_thread->proc_queue = dap_proc_queue_create(l_thread);
+
+
+    l_thread->proc_event = dap_events_socket_create_type_queue_ptr_unsafe(NULL, s_proc_event_callback);
+    l_thread->proc_event->_inheritor = l_thread; // we pass thread through it
+
+#ifdef DAP_EVENTS_CAPS_EPOLL
+    struct epoll_event l_epoll_events[DAP_MAX_EPOLL_EVENTS], l_ev;
+    memset(l_epoll_events, 0,sizeof (l_epoll_events));
+
+    // Create epoll ctl
+    l_thread->epoll_ctl = epoll_create( DAP_MAX_EPOLL_EVENTS );
+
+    // add proc queue
+    l_ev.events = l_thread->proc_queue->esocket->ev_base_flags;
+    l_ev.data.ptr = l_thread->proc_queue->esocket;
+    if( epoll_ctl(l_thread->epoll_ctl, EPOLL_CTL_ADD, l_thread->proc_queue->esocket->socket , &l_ev) != 0 ){
+        log_it(L_CRITICAL, "Can't add proc queue on epoll ctl");
+        return NULL;
+    }
+
+    // Add proc event
+    l_ev.events = l_thread->proc_event->ev_base_flags ;
+    l_ev.data.ptr = l_thread->proc_event;
+    if( epoll_ctl(l_thread->epoll_ctl, EPOLL_CTL_ADD, l_thread->proc_event->fd , &l_ev) != 0 ){
+        log_it(L_CRITICAL, "Can't add proc queue on epoll ctl");
+        return NULL;
+    }
+
+#else
+#error "Unimplemented poll events analog for this platform"
+#endif
+
+    //We've started!
+    pthread_mutex_lock(&l_thread->started_mutex);
+    pthread_mutex_unlock(&l_thread->started_mutex);
+    pthread_cond_broadcast(&l_thread->started_cond);
+    // Main loop
+    while (! l_thread->signal_kill){
+
+#ifdef DAP_EVENTS_CAPS_EPOLL
+        //log_it(L_DEBUG, "Epoll_wait call");
+        int l_selected_sockets = epoll_wait(l_thread->epoll_ctl, l_epoll_events, DAP_MAX_EPOLL_EVENTS, -1);
+#else
+#error "Unimplemented poll wait analog for this platform"
+#endif
+        //log_it(L_DEBUG,"Proc thread waked up");
+        if(l_selected_sockets == -1) {
+            if( errno == EINTR)
+                continue;
+            int l_errno = errno;
+            char l_errbuf[128];
+            strerror_r(l_errno, l_errbuf, sizeof (l_errbuf));
+            log_it(L_ERROR, "Proc thread #%d got errno:\"%s\" (%d)", l_thread->cpu_id , l_errbuf, l_errno);
+            break;
+        }
+        time_t l_cur_time = time( NULL);
+        for(int32_t n = 0; n < l_selected_sockets; n++) {
+            dap_events_socket_t * l_cur;
+            l_cur = (dap_events_socket_t *) l_epoll_events[n].data.ptr;
+            uint32_t l_cur_events = l_epoll_events[n].events;
+            if(!l_cur) {
+                log_it(L_ERROR, "dap_events_socket NULL");
+                continue;
+            }
+            l_cur->last_time_active = l_cur_time;
+            if (l_cur_events & EPOLLERR ){
+                char l_buferr[128];
+                strerror_r(errno,l_buferr, sizeof (l_buferr));
+                log_it(L_ERROR,"Some error happend in proc thread #%u: %s", l_thread->cpu_id, l_buferr);
+            }
+            if (l_cur_events & EPOLLERR ){
+                int l_errno = errno;
+                char l_errbuf[128];
+                strerror_r(l_errno, l_errbuf,sizeof (l_errbuf));
+                log_it(L_ERROR,"Some error with %d socket: %s(%d)", l_cur->socket, l_errbuf, l_errno);
+                if(l_cur->callbacks.error_callback)
+                    l_cur->callbacks.error_callback(l_cur,errno);
+            }
+            if (l_cur_events & EPOLLIN ){
+                switch (l_cur->type) {
+                    case DESCRIPTOR_TYPE_QUEUE:
+                            dap_events_socket_queue_proc_input_unsafe(l_cur);
+                    break;
+                    case DESCRIPTOR_TYPE_EVENT:
+                            dap_events_socket_event_proc_input_unsafe (l_cur);
+                    break;
+
+                    default:{ log_it(L_ERROR, "Unprocessed descriptor type accepted in proc thread loop"); }
+                }
+            }
+            if(l_cur->kill_signal){
+#ifdef DAP_EVENTS_CAPS_EPOLL
+                if ( epoll_ctl( l_thread->epoll_ctl, EPOLL_CTL_DEL, l_cur->fd, &l_cur->ev ) == -1 )
+                    log_it( L_ERROR,"Can't remove event socket's handler from the epoll ctl" );
+                //else
+                //    log_it( L_DEBUG,"Removed epoll's event from proc thread #%u", l_thread->cpu_id );
+                if (l_cur->callbacks.delete_callback)
+                    l_cur->callbacks.delete_callback(l_cur, l_thread);
+                if(l_cur->_inheritor)
+                    DAP_DELETE(l_cur->_inheritor);
+                DAP_DELETE(l_cur);
+#else
+#error "Unimplemented poll ctl analog for this platform"
+#endif
+            }
+
+        }
+    }
+    log_it(L_NOTICE, "Stop processing thread #%u", l_thread->cpu_id);
+    return NULL;
+}
+
+
diff --git a/dap-sdk/net/core/dap_server.c b/dap-sdk/net/core/dap_server.c
index bbc3bbd5e526c50636b85f3bec4531814a7a8e32..6f49c8298997a1de133f432a7c9449a25fd95500 100644
--- a/dap-sdk/net/core/dap_server.c
+++ b/dap-sdk/net/core/dap_server.c
@@ -1,847 +1,270 @@
-/*
- Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc
-  All rights reserved.
-
- This file is part of DAP (Deus Applications Prototypes) the open source project
-
-    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
-    it under the terms of the GNU Lesser General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    DAP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU Lesser General Public License for more details.
-
-    You should have received a copy of the GNU Lesser General Public License
-    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#define __USE_GNU
-
-#include <string.h>
-#include <time.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdint.h>
-
-//#include <errno.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdatomic.h>
-
-#ifndef _WIN32
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/select.h>
-#include <errno.h>
-#include <netdb.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/epoll.h>
-#include <sys/timerfd.h>
-#else
-#include <winsock2.h>
-#include <windows.h>
-#include <mswsock.h>
-#include <ws2tcpip.h>
-#include <io.h>
-#include <pthread.h>
-#endif
-
-#include <sched.h>
-
-#if 0
-#define NI_NUMERICHOST  1 /* Don't try to look up hostname.  */
-#define NI_NUMERICSERV  2 /* Don't convert port number to name.  */
-#define NI_NOFQDN       4 /* Only return nodename portion.  */
-#define NI_NAMEREQD     8 /* Don't return numeric addresses.  */
-#define NI_DGRAM       16 /* Look up UDP service rather than TCP.  */
-#endif
-
-#include "dap_common.h"
-#include "dap_server.h"
-#include "dap_strfuncs.h"
-
-#define LOG_TAG "server"
-
-#define DAP_MAX_THREAD_EVENTS           8192
-#define DAP_MAX_THREADS                 16
-
-#define SOCKET_TIMEOUT_TIME             300
-#define SOCKETS_TIMEOUT_CHECK_PERIOD    15
-
-static uint32_t _count_threads = 0;
-static uint32_t epoll_max_events = 0;
-static bool bQuitSignal = false;
-static bool moduleInit = false;
-
-static struct epoll_event  *threads_epoll_events = NULL;
-static dap_server_t *_current_run_server = NULL;
-
-static void read_write_cb( dap_client_remote_t *dap_cur, int32_t revents );
-void  *thread_loop( void *arg );
-
-dap_server_thread_t dap_server_threads[ DAP_MAX_THREADS ];
-
-/*
-===============================================
-  get_epoll_max_user_watches( )
-
-  return max epoll() event watches
-===============================================
-*/
-static uint32_t  get_epoll_max_user_watches( void )
-{
-  static const char *maxepollpath = "/proc/sys/fs/epoll/max_user_watches";
-  uint32_t  v = 0, len;
-  char  str[32];
-
-  FILE *fp = fopen( maxepollpath, "r" );
-  if ( !fp ) {
-//    printf("can't open %s\n", maxepollpath );
-    return v;
-  }
-
-  len = fread( &str[0], 1, 31, fp );
-  if ( !len ) {
-    return v;
-  }
-
-  str[ len ] = 0;
-  v = atoi( str );
-
-  return v;
-}
-
-/*
-===============================================
-  dap_server_init( )
-
-  Init server module
-  return Zero if ok others if no
-===============================================
-*/
-int32_t dap_server_init( uint32_t count_threads )
-{
-  dap_server_thread_t *dap_thread;
-  moduleInit = true;
-
-  #ifndef _WIN32
-    signal( SIGPIPE, SIG_IGN );
-  #endif
-
-  if ( count_threads > DAP_MAX_THREADS )
-    count_threads = DAP_MAX_THREADS;
-
-  _count_threads = count_threads;
-  log_it( L_NOTICE, "dap_server_init() threads %u", count_threads );
-
-  epoll_max_events = get_epoll_max_user_watches( );
-  if ( epoll_max_events > DAP_MAX_THREAD_EVENTS )
-    epoll_max_events = DAP_MAX_THREAD_EVENTS;
-
-  threads_epoll_events = (struct epoll_event *)malloc( sizeof(struct epoll_event) * _count_threads * epoll_max_events );
-  if ( !threads_epoll_events )
-    goto err;
-
-  memset( threads_epoll_events, 0, sizeof(struct epoll_event) * _count_threads * epoll_max_events );
-
-  dap_thread = &dap_server_threads[0];
-  memset( dap_thread, 0, sizeof(dap_server_thread_t) * DAP_MAX_THREADS );
-
-  for ( uint32_t i = 0; i < _count_threads; ++i, ++dap_thread ) {
-    #ifndef _WIN32
-      dap_thread->epoll_fd = -1;
-    #else
-      dap_thread->epoll_fd = (void*)-1;
-    #endif
-    dap_thread->thread_num = i;
-    dap_thread->epoll_events = &threads_epoll_events[ i * epoll_max_events ];
-
-    pthread_mutex_init( &dap_thread->mutex_dlist_add_remove, NULL );
-    pthread_mutex_init( &dap_thread->mutex_on_hash, NULL );
-  }
-
-  log_it( L_NOTICE, "Initialized socket server module" );
-
-  dap_client_remote_init( );
-
-
-  pthread_t thread_listener[ DAP_MAX_THREADS ];
-
-  for( uint32_t i = 0; i < _count_threads; ++i ) {
-
-    EPOLL_HANDLE efd = epoll_create1( 0 );
-    if ( (intptr_t)efd == -1 ) {
-      log_it( L_ERROR, "Can't create epoll instance" );
-      goto err;
-    }
-    dap_server_threads[ i ].epoll_fd = efd;
-    dap_server_threads[ i ].thread_num = i;
-  }
-
-  for( uint32_t i = 0; i < _count_threads; ++i ) {
-    pthread_create( &thread_listener[i], NULL, thread_loop, &dap_server_threads[i] );
-  }
-
-
-  return 0;
-
-err:;
-
-  dap_server_deinit( );
-  return 1;
-}
-
-void dap_server_loop_stop( void ){
-    bQuitSignal = true;
-}
-
-/*
-=========================================================
-  dap_server_deinit( )
-
-  Deinit server module
-=========================================================
-*/
-void  dap_server_deinit( void )
-{
-    if (moduleInit) {
-      dap_client_remote_t *dap_cur, *tmp;
-      dap_server_thread_t *t = &dap_server_threads[0];
-
-      dap_client_remote_deinit( );
-
-      if ( threads_epoll_events ) {
-        free( threads_epoll_events );
-
-        for ( uint32_t i = 0; i < _count_threads; ++i, ++t ) {
-
-          HASH_ITER( hh, t->hclients, dap_cur, tmp )
-            dap_client_remote_remove( dap_cur );
-
-          pthread_mutex_destroy( &dap_server_threads[i].mutex_on_hash );
-          pthread_mutex_destroy( &dap_server_threads[i].mutex_dlist_add_remove );
-
-          if ( (intptr_t)dap_server_threads[ i ].epoll_fd != -1 ) {
-            #ifndef _WIN32
-              close( dap_server_threads[ i ].epoll_fd );
-            #else
-              epoll_close( dap_server_threads[ i ].epoll_fd );
-            #endif
-          }
-        }
-      }
-      moduleInit = false;
-    }
-}
-
-/*
-=========================================================
-  dap_server_new( )
-
-  Creates new empty instance of dap_server_t
-=========================================================
-*/
-dap_server_t  *dap_server_new( void )
-{
-  return (dap_server_t *)calloc( 1, sizeof(dap_server_t) );
-}
-
-/*
-=========================================================
-  dap_server_new( )
-
-  Delete server instance
-=========================================================
-*/
-void dap_server_delete( dap_server_t *sh )
-{
-  if ( !sh ) return;
-
-  if( sh->address )
-    free( sh->address );
-
-  if( sh->server_delete_callback )
-    sh->server_delete_callback( sh, NULL );
-
-  if ( sh->_inheritor )
-    free( sh->_inheritor );
-
-  free( sh );
-}
-
-/*
-=========================================================
-  set_nonblock_socket( )
-=========================================================
-*/
-int32_t set_nonblock_socket( int32_t fd )
-{
-#ifdef _WIN32
-  unsigned long arg = 1;
-  return ioctlsocket( fd, FIONBIO, &arg );
-#else
-  int32_t flags;
-
-  flags = fcntl( fd, F_GETFL );
-  flags |= O_NONBLOCK;
-
-  return fcntl( fd, F_SETFL, flags );
-#endif
-}
-
-
-/*
-=========================================================
-  get_thread_min_connections( )
-
-  return number thread which has minimum open connections
-=========================================================
-*/
-static inline uint32_t get_thread_index_min_connections( )
-{
-  uint32_t min = 0;
-
-  for( uint32_t i = 1; i < _count_threads; i ++ ) {
-    if ( dap_server_threads[min].connections_count > dap_server_threads[i].connections_count ) {
-      min = i;
-    }
-  }
-
-  return min;
-}
-
-/*
-=========================================================
-  print_online( )
-
-=========================================================
-*/
-static inline void print_online()
-{
-  for( uint32_t i = 0; i < _count_threads; i ++ )  {
-    log_it( L_INFO, "Thread number: %u, count: %u", i, dap_server_threads[i].connections_count );
-  }
-}
-
-void  dap_server_kill_socket( dap_client_remote_t *dcr )
-{
-  if ( !dcr ) {
-    log_it( L_ERROR, "dap_server_kill_socket( NULL )" );
-    return;
-  }
-
-  dap_server_thread_t *dsth = &dap_server_threads[ dcr->tn ];
-
-  pthread_mutex_lock( &dsth->mutex_dlist_add_remove );
-
-  if ( dcr->kill_signal ) {
-    pthread_mutex_unlock( &dsth->mutex_dlist_add_remove );
-    return;
-  }
-
-  log_it( L_DEBUG, "KILL %u socket! [ thread %u ]", dcr->socket, dcr->tn );
-
-  dcr->kill_signal = true;
-
-  DL_LIST_ADD_NODE_HEAD( dsth->dap_clients_to_kill, dcr, kprev, knext, dsth->to_kill_count );
-  pthread_mutex_unlock( &dsth->mutex_dlist_add_remove );
-
-  return;
-}
-
-/*
-=========================================================
-  dap_server_add_socket( )
-
-=========================================================
-*/
-dap_client_remote_t  *dap_server_add_socket( int32_t fd, int32_t forced_thread_n )
-{
-  uint32_t tn = (forced_thread_n == -1) ? get_thread_index_min_connections( ) : forced_thread_n;
-  dap_server_thread_t *dsth = &dap_server_threads[ tn ];
-  dap_client_remote_t *dcr = dap_client_remote_create( _current_run_server, fd, dsth );
-
-  if ( !dcr ) {
-    log_it( L_ERROR, "accept %d dap_client_remote_create() == NULL", fd );
-//    pthread_mutex_unlock( &dsth->mutex_dlist_add_remove );
-    return dcr;
-  }
-
-  log_it( L_DEBUG, "accept %d Client, thread %d", fd, tn );
-
-  pthread_mutex_lock( &dsth->mutex_dlist_add_remove );
-
-
-  DL_APPEND( dsth->dap_remote_clients, dcr );
-  dsth->connections_count ++;
-  if ( epoll_ctl( dsth->epoll_fd, EPOLL_CTL_ADD, fd, &dcr->pevent) != 0 ) {
-    log_it( L_ERROR, "epoll_ctl failed 005" );
-  }
-  pthread_mutex_unlock( &dsth->mutex_dlist_add_remove );
-
-  return dcr;
-}
-
-/*
-=========================================================
-  dap_server_remove_socket( )
-
-=========================================================
-*/
-void  dap_server_remove_socket( dap_client_remote_t *dcr )
-{
-  if ( !dcr ) {
-    log_it( L_ERROR, "dap_server_remove_socket( NULL )" );
-    return;
-  }
-
-  uint32_t tn = dcr->tn;
-  log_it( L_DEBUG, "dap_server_remove_socket %u thread %u", dcr->socket, tn );
-
-  dap_server_thread_t *dsth = &dap_server_threads[ tn ];
-
-  if ( epoll_ctl( dcr->efd, EPOLL_CTL_DEL, dcr->socket, &dcr->pevent ) == -1 )
-    log_it( L_ERROR,"Can't remove event socket's handler from the epoll_fd" );
-
-//  pthread_mutex_lock( &dsth->mutex_dlist_add_remove );
-  DL_DELETE( dsth->dap_remote_clients, dcr );
-  dsth->connections_count --;
-
-//  pthread_mutex_unlock( &dsth->mutex_dlist_add_remove );
-
-//  log_it( L_DEBUG, "dcr = %X", dcr );
-}
-
-static void s_socket_all_check_activity( uint32_t tn, time_t cur_time )
-{
-  dap_client_remote_t *dcr, *tmp;
-  dap_server_thread_t *dsth = &dap_server_threads[ tn ];
-
-//  log_it( L_INFO,"s_socket_info_all_check_activity() on thread %u", tn );
-
-  pthread_mutex_lock( &dsth->mutex_dlist_add_remove );
-
-  DL_FOREACH_SAFE( dsth->dap_remote_clients, dcr, tmp ) {
-
-    if ( !dcr->kill_signal && cur_time >= dcr->last_time_active + SOCKET_TIMEOUT_TIME && !dcr->no_close ) {
-
-      log_it( L_INFO, "Socket %u timeout, closing...", dcr->socket );
-
-      if ( epoll_ctl( dcr->efd, EPOLL_CTL_DEL, dcr->socket, &dcr->pevent ) == -1 )
-        log_it( L_ERROR,"Can't remove event socket's handler from the epoll_fd" );
-
-      DL_DELETE( dsth->dap_remote_clients, dcr );
-      dsth->connections_count --;
-
-      dap_client_remote_remove( dcr );
-    }
-  }
-  pthread_mutex_unlock( &dsth->mutex_dlist_add_remove );
-}
-
-/*
-=========================================================
-  read_write_cb( )
-
-=========================================================
-*/
-static void read_write_cb( dap_client_remote_t *dap_cur, int32_t revents )
-{
-//  log_it( L_NOTICE, "[THREAD %u] read_write_cb fd %u revents %u", dap_cur->tn, dap_cur->socket, revents );
-//  sleep( 5 ); // ?????????
-
-  if( !dap_cur ) {
-
-    log_it( L_ERROR, "read_write_cb: dap_client_remote NULL" );
-    return;
-  }
-
-  if ( revents & EPOLLIN ) {
-
-//    log_it( L_DEBUG, "[THREAD %u] socket read %d ", dap_cur->tn, dap_cur->socket );
-
-    int32_t bytes_read = recv( dap_cur->socket,
-                                  dap_cur->buf_in + dap_cur->buf_in_size,
-                                  sizeof(dap_cur->buf_in) - dap_cur->buf_in_size,
-                                  0 );
-    if ( bytes_read > 0 ) {
-//      log_it( L_DEBUG, "[THREAD %u] read %u socket client said: %s", dap_cur->tn, bytes_read, dap_cur->buf_in + dap_cur->buf_in_size );
-
-      dap_cur->buf_in_size += (size_t)bytes_read;
-      dap_cur->upload_stat.buf_size_total += (size_t)bytes_read;
-
-//      log_it( L_DEBUG, "[THREAD %u] read %u socket read callback()", dap_cur->tn, bytes_read );
-      _current_run_server->client_read_callback( dap_cur ,NULL );
-    }
-    else if ( bytes_read < 0 ) {
-      log_it( L_ERROR,"Bytes read Error %s",strerror(errno) );
-      if ( strcmp(strerror(errno),"Resource temporarily unavailable") != 0 )
-      dap_cur->flags |= DAP_SOCK_SIGNAL_CLOSE;
-    }
-    else { // bytes_read == 0
-      dap_cur->flags |= DAP_SOCK_SIGNAL_CLOSE;
-      log_it( L_DEBUG, "0 bytes read" );
-    }
-  }
-
-  if( ( (revents & EPOLLOUT) || (dap_cur->flags & DAP_SOCK_READY_TO_WRITE) ) && !(dap_cur->flags & DAP_SOCK_SIGNAL_CLOSE) ) {
-
-//    log_it(L_DEBUG, "[THREAD %u] socket write %d ", dap_cur->tn, dap_cur->socket );
-    _current_run_server->client_write_callback( dap_cur, NULL ); // Call callback to process write event
-
-    if( dap_cur->buf_out_size == 0 ) {
-     //log_it(L_DEBUG, "dap_cur->buf_out_size = 0, set ev_read watcher " );
-
-      dap_cur->pevent.events = EPOLLIN | EPOLLERR;
-      if( epoll_ctl(dap_cur->efd, EPOLL_CTL_MOD, dap_cur->socket, &dap_cur->pevent) != 0 ) {
-        log_it( L_ERROR, "epoll_ctl failed 003" );
-      }
-    }
-    else {
-//      log_it(L_DEBUG, "[THREAD %u] send dap_cur->buf_out_size = %u , %s", dap_cur->tn, dap_cur->buf_out_size, dap_cur->buf_out );
-
-      size_t total_sent = dap_cur->buf_out_offset;
-
-      while ( total_sent < dap_cur->buf_out_size ) {
-        //log_it(DEBUG, "Output: %u from %u bytes are sent ", total_sent, dap_cur->buf_out_size);
-        ssize_t bytes_sent = send( dap_cur->socket,
-                                   dap_cur->buf_out + total_sent,
-                                   dap_cur->buf_out_size - total_sent,
-                                   MSG_DONTWAIT | MSG_NOSIGNAL );
-        if( bytes_sent < 0 ) {
-            if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
-                dap_cur->pevent.events = EPOLLOUT | EPOLLERR;
-                if( epoll_ctl(dap_cur->efd, EPOLL_CTL_MOD, dap_cur->socket, &dap_cur->pevent) != 0 ) {
-                    log_it( L_ERROR, "epoll_ctl failed..." );
-                    dap_cur->flags |= DAP_SOCK_SIGNAL_CLOSE;
-                    break;
-                }
-            } else {
-                log_it(L_ERROR,"[THREAD %u] Error occured in send() function %s", dap_cur->tn, strerror(errno) );
-                dap_cur->flags |= DAP_SOCK_SIGNAL_CLOSE;
-                break;
-            }
-        }
-
-        total_sent += (size_t)bytes_sent;
-        dap_cur->download_stat.buf_size_total += (size_t)bytes_sent;
-      }
-
-//      log_it( L_ERROR, "check !" );
-
-      if( total_sent == dap_cur->buf_out_size ) {
-        dap_cur->buf_out_offset = dap_cur->buf_out_size  = 0;
-      }
-      else {
-        dap_cur->buf_out_offset = total_sent;
-      }
-    } // else
-  } // write
-
-
-//  log_it(L_ERROR,"OPA !") ;
-//  Sleep(200);
-
-//  if ( (dap_cur->flags & DAP_SOCK_SIGNAL_CLOSE) && !dap_cur->no_close ) {
-//    log_it(L_ERROR,"Close signal" );
-
-//    dap_server_remove_socket( dap_cur );
-//    dap_client_remote_remove( dap_cur, _current_run_server );
-//  }
-
-}
-
-
-/*
-=========================================================
-  dap_server_listen( )
-
-  Create server_t instance and start to listen tcp port with selected address
-
-=========================================================
-*/
-dap_server_t *dap_server_listen( const char *addr, uint16_t port, dap_server_type_t type )
-{
-  dap_server_t* sh = dap_server_new( );
-
-  sh->socket_listener = -111;
-
-  if( type == DAP_SERVER_TCP )
-    sh->socket_listener = socket( AF_INET, SOCK_STREAM, 0 );
-  else {
-    dap_server_delete( sh );
-    return NULL;
-  }
-  
-  if ( set_nonblock_socket(sh->socket_listener) == -1 ) {
-    log_it( L_WARNING, "error server socket nonblock" );
-    dap_server_delete( sh );
-    return NULL;
-  }
-
-  if ( sh->socket_listener < 0 ) {
-    log_it ( L_ERROR,"Socket error %s", strerror(errno) );
-    dap_server_delete( sh );
-    return NULL;
-  }
-
-  log_it( L_NOTICE," Socket created..." );
-
-  int32_t reuse = 1;
-
-  if ( reuse ) 
-    if ( setsockopt( sh->socket_listener, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0 )
-      log_it( L_WARNING, "Can't set up REUSEADDR flag to the socket" );
-
-  sh->listener_addr.sin_family = AF_INET;
-  sh->listener_addr.sin_port = htons( port );
-  inet_pton( AF_INET, addr, &(sh->listener_addr.sin_addr) );
-
-  if( bind(sh->socket_listener, (struct sockaddr *)&(sh->listener_addr), sizeof(sh->listener_addr)) < 0 ) {
-    log_it( L_ERROR,"Bind error: %s",strerror(errno) );
-    dap_server_delete( sh );
-    return NULL;
-  }
-
-  log_it( L_INFO,"Binded %s:%u", addr, port );
-  listen( sh->socket_listener, DAP_MAX_THREAD_EVENTS * _count_threads );
-
-  return sh;
-}
-
-
-/*
-=========================================================
-  thread_loop( )
-
-  Server listener thread loop
-=========================================================
-*/
-void  *thread_loop( void *arg )
-{
-  dap_client_remote_t *dap_cur, *tmp;
-  dap_server_thread_t *dsth = (dap_server_thread_t *)arg;
-  uint32_t tn  = dsth->thread_num;
-  EPOLL_HANDLE efd = dsth->epoll_fd;
-  struct epoll_event  *events = dsth->epoll_events;
-  time_t next_time_timeout_check = time( NULL ) + SOCKETS_TIMEOUT_CHECK_PERIOD;
-
-  log_it(L_NOTICE, "Start loop listener socket thread %u efd %u", tn, efd );
-
-  #ifndef _WIN32
-  cpu_set_t mask;
-  CPU_ZERO( &mask );
-  CPU_SET( tn, &mask );
-
-  int err;
-  int l_sock_err = 0, l_sock_err_size = sizeof(l_sock_err);
-#ifndef ANDROID
-  err = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &mask);
-#else
-  err = sched_setaffinity(pthread_self(), sizeof(cpu_set_t), &mask);
-#endif
-  if (err) {
-    log_it( L_CRITICAL, "Error pthread_setaffinity_np() You really have %d or more core in CPU?", tn );
-    abort();
-  }
-  #else
-
-  if ( !SetThreadAffinityMask( GetCurrentThread(), (DWORD_PTR)(1 << tn) ) ) {
-    log_it( L_CRITICAL, "Error pthread_setaffinity_np() You really have %d or more core in CPU?", tn );
-    abort();
-  }
-
-  #endif
-
-  do {
-
-    int32_t n = epoll_wait( efd, events, DAP_MAX_THREAD_EVENTS, 1000 );
-
-//    log_it(L_WARNING,"[THREAD %u] epoll events %u", tn, n  );
-//    Sleep(300);
-
-    if ( bQuitSignal )
-      break;
-
-    if ( n < 0 ) {
-      if ( errno == EINTR )
-        continue;
-      break;
-    }
-
-    time_t cur_time = time( NULL );
-
-    for ( int32_t i = 0; i < n; ++ i ) {
-
-//      log_it(L_ERROR,"[THREAD %u] process epoll event %u", tn, i  );
-      dap_cur = (dap_client_remote_t *)events[i].data.ptr;
-
-      if ( !dap_cur ) {
-        log_it( L_ERROR,"dap_client_remote_t NULL" );
-        continue;
-      }
-
-      dap_cur->last_time_active = cur_time;
-      if( events[i].events & EPOLLERR ) {
-          getsockopt(dap_cur->socket, SOL_SOCKET, SO_ERROR, (void *)&l_sock_err, (socklen_t *)&l_sock_err_size);
-          log_it( L_ERROR,"Socket %u error: %s, remove it" , dap_cur->socket, strerror(l_sock_err));
-          dap_cur->flags |= DAP_SOCK_SIGNAL_CLOSE;
-      }
-      set_nonblock_socket(dap_cur->socket);
-      if ( !(dap_cur->flags & DAP_SOCK_SIGNAL_CLOSE) || dap_cur->no_close )
-        read_write_cb( dap_cur, events[i].events );
-
-      if ( (dap_cur->flags & DAP_SOCK_SIGNAL_CLOSE) && !dap_cur->no_close ) {
-
-        pthread_mutex_lock( &dsth->mutex_dlist_add_remove );
-
-        if ( dap_cur->kill_signal ) {
-          pthread_mutex_unlock( &dsth->mutex_dlist_add_remove );
-          continue;
-        }
-
-//        pthread_mutex_unlock( &dsth->mutex_dlist_add_remove );
-//        dap_server_kill_socket( dap_cur );
-//        continue;
-
-        log_it( L_INFO, "Got signal to close %u socket, closing...[ %u ]", dap_cur->socket, tn );
-
-        dap_server_remove_socket( dap_cur );
-        dap_client_remote_remove( dap_cur );
-
-        pthread_mutex_unlock( &dsth->mutex_dlist_add_remove );
-      }
-
-    } // for
-
-    if ( cur_time >= next_time_timeout_check ) {
-
-      s_socket_all_check_activity( tn, cur_time );
-      next_time_timeout_check = cur_time + SOCKETS_TIMEOUT_CHECK_PERIOD;
-    }
-
-    pthread_mutex_lock( &dsth->mutex_dlist_add_remove );
-    if ( !dsth->to_kill_count ) {
-
-      pthread_mutex_unlock( &dsth->mutex_dlist_add_remove );
-      continue;
-    }
-
-    dap_cur = dsth->dap_clients_to_kill;
-
-    do {
-
-      if ( dap_cur->no_close ) {
-        dap_cur = dap_cur->knext;
-        continue;
-      }
-
-      log_it( L_INFO, "Kill %u socket ...............[ thread %u ]", dap_cur->socket, tn );
-
-      tmp = dap_cur->knext;
-      DL_LIST_REMOVE_NODE( dsth->dap_clients_to_kill, dap_cur, kprev, knext, dsth->to_kill_count );
-
-      dap_server_remove_socket( dap_cur );
-      dap_client_remote_remove( dap_cur );
-      dap_cur = tmp;
-
-    } while ( dap_cur );
-
-    log_it( L_INFO, "[ Thread %u ] coneections: %u, to kill: %u", tn, dsth->connections_count, dsth->to_kill_count  );
-    pthread_mutex_unlock( &dsth->mutex_dlist_add_remove );
-
-  } while( !bQuitSignal ); 
-
-  return NULL;
-}
-
-/*
-=========================================================
-  dap_server_loop( )
-
-  Main server loop
-
-  @param a_server Server instance
-  @return Zero if ok others if not
-=========================================================
-*/
-int32_t dap_server_loop( dap_server_t *d_server )
-{
-  int errCode = 0;
-
-  if(d_server == NULL){
-    log_it(L_ERROR, "Server is NULL");
-    return -1;
-  }
-
-  _current_run_server = d_server;
-
-  EPOLL_HANDLE efd = epoll_create1( 0 );
-  if ( (intptr_t)efd == -1 ) {
-    return -10;
-  }
-
-  struct epoll_event  pev;
-  struct epoll_event  events[ 16 ];
-
-  memset(&pev, 0, sizeof(pev));
-  pev.events = EPOLLIN | EPOLLERR;
-  pev.data.fd = d_server->socket_listener;
-
-  if( epoll_ctl( efd, EPOLL_CTL_ADD, d_server->socket_listener, &pev) != 0 ) {
-      log_it( L_ERROR, "epoll_ctl failed 004" );
-      return -20;
-  }
-
-  while( !bQuitSignal && errCode == 0 ) {
-    int32_t n = epoll_wait( efd, &events[0], 16, 1000 );
-
-    if ( bQuitSignal )
-      break;
-
-    if ( n < 0 ) {
-      if ( errno == EINTR )
-        continue;
-      log_it( L_ERROR, "Server wakeup on error: %i", errno );
-      errCode = -30;
-    }
-
-    for( int32_t i = 0; i < n && errCode == 0; ++i ) {
-
-      if ( events[i].events & EPOLLIN ) {
-        int client_fd = accept( events[i].data.fd, 0, 0 );
-
-        if ( client_fd < 0 ) {
-          log_it( L_ERROR, "accept_cb: error accept socket");
-          continue;
-        }
-
-        set_nonblock_socket( client_fd );
-        dap_server_add_socket( client_fd, -1 );
-      }
-      else if( events[i].events & EPOLLERR ) {
-        log_it( L_ERROR, "Server socket error event" );
-        errCode = -40;
-      }
-
-    } // for
-  } // while
-
-  if (efd != -1) {
-    #ifndef _WIN32
-      close( efd );
-    #else
-      epoll_close( efd );
-    #endif
-  }
-
-  return errCode;
-}
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Ltd.   https://demlabs.net
+ * Copyright  (c) 2017
+ * All rights reserved.
+
+ This file is part of DAP SDK the open source project
+
+    DAP SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DAP SDK is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <sys/epoll.h>
+
+#include <netdb.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+
+#include <stdio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/timerfd.h>
+#include <utlist.h>
+#if ! defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+#if ! defined (__USE_GNU)
+#define __USE_GNU
+#endif
+#include <sched.h>
+#include "dap_common.h"
+#include "dap_config.h"
+#include "dap_server.h"
+#include "dap_worker.h"
+#include "dap_events.h"
+
+#define LOG_TAG "dap_server"
+
+static dap_events_socket_t * s_es_server_create(dap_events_t * a_events, int a_sock,
+                                             dap_events_socket_callbacks_t * a_callbacks, dap_server_t * a_server);
+
+static void s_es_server_accept(dap_events_socket_t *a_es, int a_remote_socket, struct sockaddr* a_remote_addr);
+static void s_es_server_error(dap_events_socket_t *a_es, int a_arg);
+static void s_es_server_new(dap_events_socket_t *a_es, void * a_arg);
+static void s_server_delete(dap_server_t * a_server);
+/**
+ * @brief dap_server_init
+ * @return
+ */
+int dap_server_init()
+{
+    log_it(L_NOTICE,"Server module init");
+    return 0;
+}
+
+/**
+ * @brief dap_server_deinit
+ */
+void dap_server_deinit()
+{
+}
+
+/**
+ * @brief dap_server_delete
+ * @param a_server
+ */
+void s_server_delete(dap_server_t * a_server)
+{
+    if(a_server->delete_callback)
+        a_server->delete_callback(a_server,NULL);
+   if( a_server->address )
+       DAP_DELETE(a_server->address );
+   if( a_server->_inheritor )
+       DAP_DELETE( a_server->_inheritor );
+   DAP_DELETE(a_server);
+}
+
+/**
+ * @brief dap_server_new
+ * @param a_events
+ * @param a_addr
+ * @param a_port
+ * @param a_type
+ * @return
+ */
+dap_server_t* dap_server_new(dap_events_t *a_events, const char * a_addr, uint16_t a_port, dap_server_type_t a_type)
+{
+    assert(a_events);
+    dap_server_t *l_server =  DAP_NEW_Z(dap_server_t);
+
+    l_server->socket_listener=-1; // To diff it from 0 fd
+    l_server->address = a_addr? strdup( a_addr) : strdup("0.0.0.0"); // If NULL we listen everything
+    l_server->port = a_port;
+    l_server->type = a_type;
+
+    if(l_server->type == DAP_SERVER_TCP)
+        l_server->socket_listener = socket(AF_INET, SOCK_STREAM, 0);
+
+    if (l_server->socket_listener < 0) {
+        int l_errno = errno;
+        log_it (L_ERROR,"Socket error %s (%d)",strerror(l_errno), l_errno);
+        DAP_DELETE(l_server);
+        return NULL;
+    }
+
+    log_it(L_NOTICE,"Listen socket %d created...", l_server->socket_listener);
+    int reuse=1;
+
+    if (setsockopt(l_server->socket_listener, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0)
+        log_it(L_WARNING, "Can't set up REUSEADDR flag to the socket");
+#ifdef SO_REUSEPORT
+    if (setsockopt(l_server->socket_listener, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0)
+        log_it(L_WARNING, "Can't set up REUSEPORT flag to the socket");
+#endif
+
+//create socket
+    l_server->listener_addr.sin_family = AF_INET;
+    l_server->listener_addr.sin_port = htons(l_server->port);
+    inet_pton(AF_INET, l_server->address, &(l_server->listener_addr.sin_addr));
+
+    if(bind (l_server->socket_listener, (struct sockaddr *) &(l_server->listener_addr), sizeof(l_server->listener_addr)) < 0){
+        log_it(L_ERROR,"Bind error: %s",strerror(errno));
+        close(l_server->socket_listener);
+        DAP_DELETE(l_server);
+        return NULL;
+    }else{
+        log_it(L_INFO,"Binded %s:%u",l_server->address,l_server->port);
+        listen(l_server->socket_listener, SOMAXCONN);
+    }
+
+    fcntl( l_server->socket_listener, F_SETFL, O_NONBLOCK);
+    pthread_mutex_init(&l_server->started_mutex,NULL);
+    pthread_cond_init(&l_server->started_cond,NULL);
+
+
+
+    dap_events_socket_callbacks_t l_callbacks;
+    memset(&l_callbacks,0,sizeof (l_callbacks));
+    l_callbacks.new_callback = s_es_server_new;
+    l_callbacks.accept_callback = s_es_server_accept;
+    l_callbacks.error_callback = s_es_server_error;
+
+    for(size_t l_worker_id = 0; l_worker_id < dap_events_worker_get_count() ; l_worker_id++){
+        dap_worker_t *l_w = dap_events_worker_get(l_worker_id);
+        assert(l_w);
+        dap_events_socket_t * l_es = dap_events_socket_wrap2( l_server, a_events, l_server->socket_listener, &l_callbacks);
+
+        if ( l_es){
+            l_es->type = DESCRIPTOR_TYPE_SOCKET_LISTENING;
+#ifdef DAP_EVENTS_CAPS_EPOLL
+            // Prepare for multi thread listening
+            l_es->ev_base_flags  = EPOLLET| EPOLLIN | EPOLLEXCLUSIVE;
+#endif
+            l_es->_inheritor = l_server;
+            pthread_mutex_lock(&l_server->started_mutex);
+            dap_worker_add_events_socket( l_es, l_w );
+            pthread_cond_wait(&l_server->started_cond, &l_server->started_mutex);
+            pthread_mutex_unlock(&l_server->started_mutex);
+        } else{
+            log_it(L_WARNING, "Can't wrap event socket for %s:%u server", a_addr, a_port);
+            return NULL;
+        }
+    }
+    return  l_server;
+}
+
+/**
+ * @brief s_es_server_new
+ * @param a_es
+ * @param a_arg
+ */
+static void s_es_server_new(dap_events_socket_t *a_es, void * a_arg)
+{
+    log_it(L_DEBUG, "Created server socket %p on worker %u", a_es, a_es->worker->id);
+    dap_server_t *l_server = (dap_server_t*) a_es->_inheritor;
+    pthread_mutex_lock( &l_server->started_mutex);
+    pthread_mutex_unlock( &l_server->started_mutex);
+    pthread_cond_broadcast( &l_server->started_cond);
+}
+
+/**
+ * @brief s_es_server_error
+ * @param a_es
+ * @param a_arg
+ */
+static void s_es_server_error(dap_events_socket_t *a_es, int a_arg)
+{
+    (void) a_arg;
+    (void) a_es;
+    char l_buf[128];
+    strerror_r(errno, l_buf, sizeof (l_buf));
+    log_it(L_WARNING, "Listening socket error: %s, ", l_buf);
+}
+
+/**
+ * @brief s_es_server_accept
+ * @param a_events
+ * @param a_remote_socket
+ * @param a_remote_addr
+ */
+static void s_es_server_accept(dap_events_socket_t *a_es, int a_remote_socket, struct sockaddr *a_remote_addr)
+{
+    socklen_t a_remote_addr_size = sizeof(*a_remote_addr);
+    a_es->buf_in_size = 0; // It should be 1 so we reset it to 0
+    //log_it(L_DEBUG, "Server socket %d is active",i);
+    dap_server_t * l_server = (dap_server_t*) a_es->_inheritor;
+    assert(l_server);
+
+    dap_events_socket_t * l_es_new = NULL;
+    log_it(L_DEBUG, "Listening socket (binded on %s:%u) got new incomming connection",l_server->address,l_server->port);
+    log_it(L_DEBUG, "Accepted new connection (sock %d from %d)", a_remote_socket, a_es->socket);
+    l_es_new = s_es_server_create(a_es->events,a_remote_socket,&l_server->client_callbacks,l_server);
+    //l_es_new->is_dont_reset_write_flag = true; // By default all income connection has this flag
+    getnameinfo(a_remote_addr,a_remote_addr_size, l_es_new->hostaddr
+                , sizeof(l_es_new->hostaddr),l_es_new->service,sizeof(l_es_new->service),
+                NI_NUMERICHOST | NI_NUMERICSERV);
+
+    log_it(L_INFO,"Connection accepted from %s (%s)", l_es_new->hostaddr, l_es_new->service );
+    dap_worker_add_events_socket_auto(l_es_new);
+}
+
+
+/**
+ * @brief s_esocket_new
+ * @param a_events
+ * @param a_sock
+ * @param a_callbacks
+ * @param a_server
+ * @return
+ */
+static dap_events_socket_t * s_es_server_create(dap_events_t * a_events, int a_sock,
+                                             dap_events_socket_callbacks_t * a_callbacks, dap_server_t * a_server)
+{
+    dap_events_socket_t * ret = NULL;
+    if (a_sock > 0)  {
+        // set it nonblock
+        //fcntl(a_sock, F_SETFL, O_NONBLOCK);
+
+        ret = dap_events_socket_wrap_no_add(a_events, a_sock, a_callbacks);
+        ret->is_dont_reset_write_flag = true;
+        ret->type = DESCRIPTOR_TYPE_SOCKET;
+        ret->server = a_server;
+
+    } else {
+        log_it(L_CRITICAL,"Accept error: %s",strerror(errno));
+    }
+    return ret;
+}
diff --git a/dap-sdk/net/core/dap_timerfd.c b/dap-sdk/net/core/dap_timerfd.c
index 89bf5f116b86707e539d67918356742a984d88c4..f2cc746622a5bf2c312f710b4327de38d48b586c 100644
--- a/dap-sdk/net/core/dap_timerfd.c
+++ b/dap-sdk/net/core/dap_timerfd.c
@@ -1,27 +1,26 @@
 /*
  * Authors:
  * Alexander Lysikov <alexander.lysikov@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * Kelvin Project https://github.com/kelvinblockchain
+ * DeM Labs Ltd.   https://demlabs.net
  * Copyright  (c) 2020
  * All rights reserved.
 
- This file is part of DAP (Deus Applications Prototypes) the open source project
+ This file is part of DAP SDK the open source project
 
- DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
+    DAP SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
 
- DAP is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
+    DAP SDK is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
 
- You should have received a copy of the GNU General Public License
- along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef WIN32
+    You should have received a copy of the GNU General Public License
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifdef DAP_OS_UNIX
 #include <stdint.h>
 #include <stdbool.h>
 #include <errno.h>
@@ -33,38 +32,14 @@
 #include <inttypes.h>
 
 #include "dap_common.h"
+#include "dap_events.h"
+#include "dap_worker.h"
 #include "dap_events_socket.h"
 #include "dap_timerfd.h"
 
 #define LOG_TAG "dap_timerfd"
+static void s_es_callback_timer(struct dap_events_socket *a_event_sock);
 
-void callback_timerfd_read(struct dap_events_socket *a_event_sock, void * arg)
-{
-    uint64_t l_ptiu64;
-    size_t l_read_ret;
-    do {
-        l_read_ret = dap_events_socket_read(a_event_sock, &l_ptiu64, sizeof(l_ptiu64));
-
-        if(l_read_ret > 0) {
-            dap_timerfd_t *l_timerfd = a_event_sock->_inheritor;
-            //printf("\nread() returned %d, %d\n", l_ptiu64, l_read_ret);
-            struct itimerspec l_ts;
-            // first expiration in 0 seconds after times start
-            l_ts.it_interval.tv_sec = 0;
-            l_ts.it_interval.tv_nsec = 0;
-            // timeout for timer
-            l_ts.it_value.tv_sec = l_timerfd->timeout_ms / 1000;
-            l_ts.it_value.tv_nsec = (l_timerfd->timeout_ms % 1000) * 1000000;
-            if(timerfd_settime(l_timerfd->tfd, 0, &l_ts, NULL) < 0) {
-                log_it(L_WARNING, "callback_timerfd_read() failed: timerfd_settime() errno=%d\n", errno);
-            }
-            // run user's callback
-            if(l_timerfd->callback)
-                l_timerfd->callback(l_timerfd->callback_arg);
-        }
-    } while(l_read_ret > 0);
-    dap_events_socket_set_readable(a_event_sock, true);
-}
 
 /**
  * @brief dap_events_socket_init Init clients module
@@ -82,7 +57,21 @@ int dap_timerfd_init()
  * @param a_callback
  * @return new allocated dap_timerfd_t structure or NULL if error
  */
-dap_timerfd_t* dap_timerfd_start(uint64_t a_timeout_ms, dap_timerfd_callback_t *a_callback, void *a_callback_arg)
+dap_timerfd_t* dap_timerfd_start(uint64_t a_timeout_ms, dap_timerfd_callback_t a_callback, void *a_callback_arg)
+{
+     return dap_timerfd_start_on_worker(dap_events_worker_get_auto(), a_timeout_ms, a_callback, a_callback_arg );
+}
+
+/**
+ * @brief dap_timerfd_start_on_worker
+ * @param a_worker
+ * @param a_timeout_ms
+ * @param a_callback
+ * @param a_callback_arg
+ * @return
+ */
+dap_timerfd_t* dap_timerfd_start_on_worker(dap_worker_t * a_worker, uint64_t a_timeout_ms, dap_timerfd_callback_t a_callback, void *a_callback_arg)
+
 {
     struct itimerspec l_ts;
     int l_tfd = timerfd_create(CLOCK_MONOTONIC, 0);
@@ -106,15 +95,12 @@ dap_timerfd_t* dap_timerfd_start(uint64_t a_timeout_ms, dap_timerfd_callback_t *
     dap_timerfd_t *l_timerfd = DAP_NEW(dap_timerfd_t);
 
     // create events_socket for timer file descriptor
-    static dap_events_socket_callbacks_t l_s_callbacks = {
-        .read_callback = callback_timerfd_read,
-        .write_callback = NULL,
-        .error_callback = NULL,
-        .delete_callback = NULL
-    };
-    dap_events_socket_t * l_events_socket = dap_events_socket_wrap_no_add(NULL, l_tfd, &l_s_callbacks);
-    l_events_socket->type = DESCRIPTOR_TYPE_FILE;
-    dap_events_socket_create_after(l_events_socket);
+    dap_events_socket_callbacks_t l_s_callbacks;
+    memset(&l_s_callbacks,0,sizeof (l_s_callbacks));
+    l_s_callbacks.timer_callback = s_es_callback_timer;
+
+    dap_events_socket_t * l_events_socket = dap_events_socket_wrap_no_add(a_worker->events, l_tfd, &l_s_callbacks);
+    l_events_socket->type = DESCRIPTOR_TYPE_TIMER;
     // pass l_timerfd to events_socket
     l_events_socket->_inheritor = l_timerfd;
 
@@ -124,29 +110,45 @@ dap_timerfd_t* dap_timerfd_start(uint64_t a_timeout_ms, dap_timerfd_callback_t *
     l_timerfd->events_socket = l_events_socket;
     l_timerfd->callback = a_callback;
     l_timerfd->callback_arg = a_callback_arg;
+    dap_worker_add_events_socket(l_events_socket, a_worker);
+
     return l_timerfd;
 }
 
+/**
+ * @brief s_es_callback_timer
+ * @param a_event_sock
+ */
+static void s_es_callback_timer(struct dap_events_socket *a_event_sock)
+{
+    uint64_t l_ptiu64;
+    dap_timerfd_t *l_timerfd = a_event_sock->_inheritor;
+    //printf("\nread() returned %d, %d\n", l_ptiu64, l_read_ret);
+    struct itimerspec l_ts;
+    // first expiration in 0 seconds after times start
+    l_ts.it_interval.tv_sec = 0;
+    l_ts.it_interval.tv_nsec = 0;
+    // timeout for timer
+    l_ts.it_value.tv_sec = l_timerfd->timeout_ms / 1000;
+    l_ts.it_value.tv_nsec = (l_timerfd->timeout_ms % 1000) * 1000000;
+    if(timerfd_settime(l_timerfd->tfd, 0, &l_ts, NULL) < 0) {
+        log_it(L_WARNING, "callback_timerfd_read() failed: timerfd_settime() errno=%d\n", errno);
+    }
+    // run user's callback
+    if(l_timerfd->callback)
+        l_timerfd->callback(l_timerfd->callback_arg);
+    dap_events_socket_set_readable_unsafe(a_event_sock, true);
+}
+
 /**
  * @brief dap_timerfd_stop
  * @param a_tfd
  * @param a_callback
- * @return 0 or <0 if error
  */
-int dap_timerfd_delete(dap_timerfd_t *l_timerfd)
+void dap_timerfd_delete(dap_timerfd_t *l_timerfd)
 {
-    if(!l_timerfd || l_timerfd->tfd < 1 || !l_timerfd->events_socket) {
-        return -1;
-    }
-
-    if(close(l_timerfd->tfd) == -1) {
-        log_it(L_WARNING, "dap_timerfd_stop() failed to close timerfd: errno=%d\n", errno);
-        return -2;
-    }
-
-    dap_events_socket_kill_socket(l_timerfd->events_socket);
-    l_timerfd->events_socket = NULL;
-    DAP_DELETE(l_timerfd);
-    return 0;
+    dap_events_socket_remove_and_delete_mt(l_timerfd->events_socket->worker, l_timerfd->events_socket);
 }
+#else
+#error "No dap_timerfd realization for your platform"
 #endif
diff --git a/dap-sdk/net/core/dap_traffic_track.c b/dap-sdk/net/core/dap_traffic_track.c
deleted file mode 100644
index 44c7506a6c426d84dcdfd0ce7aec280e8f766b46..0000000000000000000000000000000000000000
--- a/dap-sdk/net/core/dap_traffic_track.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Authors:
- * Anatoliy Kurotich <anatoliy.kurotich@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * Kelvin Project https://github.com/kelvinblockchain
- * Copyright  (c) 2017-2018
- * All rights reserved.
-
- This file is part of DAP (Deus Applications Prototypes) the open source project
-
-    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    DAP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <string.h>
-#include <time.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-
-#ifndef _WIN32
-#include <pthread.h>
-#include <ev.h>
-#else
-#include <winsock2.h>
-#include <windows.h>
-#include <mswsock.h>
-#include <ws2tcpip.h>
-#include <io.h>
-#include <pthread.h>
-#endif
-
-#include "dap_traffic_track.h"
-#include "dap_common.h"
-#include "dap_cpu_monitor.h"
-
-#define LOG_TAG "dap_traffic_track"
-
-#define BITS_IN_BYTE    8
-#define ALLOC_STEP      100
-
-static dap_traffic_callback_t _callback = NULL;
-static dap_server_t *_dap_server;
-
-#ifndef _WIN32
-static ev_timer _timeout_watcher;
-static struct ev_loop *loop;
-#else
-static HANDLE _timeout_watcher;
-#endif
-static size_t timertimeout = 1;
-
-static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t _cond = PTHREAD_COND_INITIALIZER;
-static pthread_t worker_thread;
-static bool _stop_worker_signal = false;
-
-
-/**
- * @brief calculate_mbits_speed
- * @param count_bytes
- * @details timeout we gots from _timeout_watcher.repeat
- * @return mbit/second speed
- */
-static double _calculate_mbits_speed( size_t count_bytes )
-{
-  size_t bits_per_second = (count_bytes / timertimeout) * BITS_IN_BYTE;
-  //    log_it(L_DEBUG, "TIMEOUT: %d, bits_per_second: %d mbits: %f",
-  //           (size_t)_timeout_watcher.repeat, bits_per_second, bits_per_second / 1000000.0);
-  return (double)bits_per_second / 1000000.0; // convert to mbits
-}
-
-void *_worker_run( void *a )
-{
-  (void)a;
-
-  pthread_mutex_lock( &_mutex );
-
-  while( true ) {
-    pthread_cond_wait( &_cond, &_mutex );
-    if ( _stop_worker_signal ) {
-      log_it(L_INFO, "Dap traffic track worker stopped");
-      _stop_worker_signal = false;
-      break;
-    }
-    _callback( _dap_server );
-  }
-
-  pthread_mutex_unlock( &_mutex );
-  return NULL;
-}
-
-void _worker_start( )
-{
-  pthread_mutex_init( &_mutex, NULL );
-  pthread_cond_init( &_cond, NULL );
-  pthread_create( &worker_thread, NULL, _worker_run, NULL );
-}
-
-void _worker_stop()
-{
-  pthread_mutex_lock( &_mutex );
-  _stop_worker_signal = true;
-  pthread_cond_signal( &_cond );
-  pthread_mutex_unlock( &_mutex );
-
-  // wait for exit worker_thread
-  pthread_join( worker_thread, NULL );
-
-  pthread_mutex_destroy( &_mutex );
-  pthread_cond_destroy( &_cond );
-  _callback = NULL;
-}
-
-#ifndef _WIN32
-static void _timeout_cb( )
-#else
-VOID CALLBACK _timeout_cb( void *lpParameter, BOOL TimerOrWaitFired )
-#endif
-{
-#if 0
-  pthread_mutex_lock( &_dap_server->mutex_on_hash );
-
-  size_t count_users = HASH_COUNT(_dap_server->clients );
-
-  if ( count_users ) {
-//    size_t idx = 0;
-    dap_client_remote_t *dap_cur, *tmp;
-    HASH_ITER( hh, _dap_server->clients, dap_cur, tmp ) {
-
-      dap_cur->upload_stat.speed_mbs = _calculate_mbits_speed( dap_cur->upload_stat.buf_size_total -
-                                       dap_cur->upload_stat.buf_size_total_old );
-
-      dap_cur->upload_stat.buf_size_total_old = dap_cur->upload_stat.buf_size_total;
-
-      dap_cur->download_stat.speed_mbs = _calculate_mbits_speed( dap_cur->download_stat.buf_size_total -
-                                           dap_cur->download_stat.buf_size_total_old );
-
-      dap_cur->download_stat.buf_size_total_old = dap_cur->download_stat.buf_size_total;
-
-//      idx ++;
-    }
-  }
-
-  /* TODO find some better solution and place for this line */
-  _dap_server->cpu_stats = dap_cpu_get_stats( );
-
-  pthread_mutex_unlock( &_dap_server->mutex_on_hash );
-#endif
-
-  if ( _callback != NULL ) {
-    pthread_mutex_lock( &_mutex );
-    pthread_cond_signal( &_cond );
-    pthread_mutex_unlock( &_mutex );
-  }
-}
-
-void dap_traffic_track_init( dap_server_t * server,
-                            time_t timeout )
-{
-  dap_cpu_monitor_init( );
-
-  _dap_server = server;
-#ifndef _WIN32
-  _timeout_watcher.repeat = timeout;
-
-  loop = EV_DEFAULT;
-
-  ev_init( &_timeout_watcher, _timeout_cb );
-  ev_timer_again( loop, &_timeout_watcher );
-#else
-
-  timertimeout = timeout;
-
-  CreateTimerQueueTimer( &_timeout_watcher, NULL, (WAITORTIMERCALLBACK)_timeout_cb, NULL, timertimeout, timertimeout, 0 );
-
-#endif
-
-  log_it(L_NOTICE, "Initialized traffic track module");
-}
-
-void dap_traffic_track_deinit()
-{
-  if ( _callback != NULL )
-    _worker_stop();
-
-#ifndef _WIN32
-  ev_timer_stop( loop, &_timeout_watcher );
-  ev_loop_destroy( loop );
-#else
-  DeleteTimerQueueTimer( NULL, _timeout_watcher, NULL );
-#endif
-
-  log_it( L_NOTICE, "Deinitialized traffic track module" );
-  dap_cpu_monitor_deinit( );
-}
-
-void dap_traffic_callback_stop() {
-
-  if ( _callback == NULL ) {
-    log_it( L_WARNING, "worker not running" );
-    return;
-  }
-  _worker_stop();
-}
-
-void dap_traffic_callback_set(dap_traffic_callback_t cb)
-{
-  if( _callback == NULL ) {
-    _callback = cb;
-    _worker_start();
-    return;
-  }
-
-  log_it( L_WARNING, "Callback already setted" );
-}
diff --git a/dap-sdk/net/core/dap_worker.c b/dap-sdk/net/core/dap_worker.c
new file mode 100644
index 0000000000000000000000000000000000000000..ea14d3a1feb2c0e2df2dcf48797a764972f2d5b4
--- /dev/null
+++ b/dap-sdk/net/core/dap_worker.c
@@ -0,0 +1,579 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Ltd.   https://demlabs.net
+ * Copyright  (c) 2017
+ * All rights reserved.
+
+ This file is part of DAP SDK the open source project
+
+    DAP SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DAP SDK is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <time.h>
+#include <errno.h>
+#include <unistd.h>
+#if ! defined (_GNU_SOURCE)
+#define _GNU_SOURCE         /* See feature_test_macros(7) */
+#endif
+#include <fcntl.h>
+
+#include "dap_common.h"
+#include "dap_math_ops.h"
+#include "dap_worker.h"
+#include "dap_events.h"
+
+#define LOG_TAG "dap_worker"
+
+
+static time_t s_connection_timeout = 20000;
+
+
+static void s_socket_all_check_activity( void * a_arg);
+static void s_queue_new_es_callback( dap_events_socket_t * a_es, void * a_arg);
+static void s_queue_delete_es_callback( dap_events_socket_t * a_es, void * a_arg);
+static void s_queue_es_reassign_callback( dap_events_socket_t * a_es, void * a_arg);
+static void s_queue_callback_callback( dap_events_socket_t * a_es, void * a_arg);
+static void s_queue_es_io_callback( dap_events_socket_t * a_es, void * a_arg);
+
+/**
+ * @brief dap_worker_init
+ * @param a_threads_count
+ * @param conn_timeout
+ * @return
+ */
+int dap_worker_init( size_t a_conn_timeout )
+{
+    if ( a_conn_timeout )
+      s_connection_timeout = a_conn_timeout;
+    return 0;
+}
+
+void dap_worker_deinit( )
+{
+}
+
+/**
+ * @brief dap_worker_thread
+ * @param arg
+ * @return
+ */
+void *dap_worker_thread(void *arg)
+{
+    dap_events_socket_t *l_cur;
+    dap_worker_t *l_worker = (dap_worker_t *) arg;
+    time_t l_next_time_timeout_check = time( NULL) + s_connection_timeout / 2;
+    uint32_t l_tn = l_worker->id;
+
+    dap_cpu_assign_thread_on(l_worker->id);
+    struct sched_param l_shed_params;
+    l_shed_params.sched_priority = 0;
+    pthread_setschedparam(pthread_self(),SCHED_FIFO ,&l_shed_params);
+
+    l_worker->queue_es_new = dap_events_socket_create_type_queue_ptr_unsafe( l_worker, s_queue_new_es_callback);
+    l_worker->queue_es_delete = dap_events_socket_create_type_queue_ptr_unsafe( l_worker, s_queue_delete_es_callback);
+    l_worker->queue_es_io = dap_events_socket_create_type_queue_ptr_unsafe( l_worker, s_queue_es_io_callback);
+    l_worker->queue_es_reassign = dap_events_socket_create_type_queue_ptr_unsafe( l_worker, s_queue_es_reassign_callback );
+    l_worker->queue_callback= dap_events_socket_create_type_queue_ptr_unsafe( l_worker, s_queue_callback_callback);
+    l_worker->timer_check_activity = dap_timerfd_start_on_worker( l_worker,s_connection_timeout / 2,s_socket_all_check_activity,l_worker);
+
+#ifdef DAP_EVENTS_CAPS_EPOLL
+    struct epoll_event l_epoll_events[ DAP_MAX_EPOLL_EVENTS]= {{0}};
+    log_it(L_INFO, "Worker #%d started with epoll fd %d and assigned to dedicated CPU unit", l_worker->id, l_worker->epoll_fd);
+#else
+#error "Unimplemented socket array for this platform"
+#endif
+
+    pthread_cond_broadcast(&l_worker->started_cond);
+    bool s_loop_is_active = true;
+    while(s_loop_is_active) {
+#ifdef DAP_EVENTS_CAPS_EPOLL
+        int l_selected_sockets = epoll_wait(l_worker->epoll_fd, l_epoll_events, DAP_MAX_EPOLL_EVENTS, -1);
+#else
+#error "Unimplemented poll wait analog for this platform"
+#endif
+        if(l_selected_sockets == -1) {
+            if( errno == EINTR)
+                continue;
+            int l_errno = errno;
+            char l_errbuf[128];
+            strerror_r(l_errno, l_errbuf, sizeof (l_errbuf));
+            log_it(L_ERROR, "Worker thread %d got errno:\"%s\" (%d)", l_worker->id, l_errbuf, l_errno);
+            break;
+        }
+
+        time_t l_cur_time = time( NULL);
+        for(int32_t n = 0; n < l_selected_sockets; n++) {
+
+            l_cur = (dap_events_socket_t *) l_epoll_events[n].data.ptr;
+            if(!l_cur) {
+                log_it(L_ERROR, "dap_events_socket NULL");
+                continue;
+            }
+            l_cur->last_time_active = l_cur_time;
+
+            //log_it(L_DEBUG, "Worker=%d fd=%d socket=%d event=0x%x(%d)", l_worker->id,
+            //       l_worker->epoll_fd,l_cur->socket, l_epoll_events[n].events,l_epoll_events[n].events);
+            int l_sock_err = 0, l_sock_err_size = sizeof(l_sock_err);
+            //connection already closed (EPOLLHUP - shutdown has been made in both directions)
+            if(l_epoll_events[n].events & EPOLLHUP) { // && events[n].events & EPOLLERR) {
+                switch (l_cur->type ){
+                    case DESCRIPTOR_TYPE_SOCKET_LISTENING:
+                    case DESCRIPTOR_TYPE_SOCKET:
+                        getsockopt(l_cur->socket, SOL_SOCKET, SO_ERROR, (void *)&l_sock_err, (socklen_t *)&l_sock_err_size);
+                        //if(!(events[n].events & EPOLLIN))
+                        //cur->no_close = false;
+                        if (l_sock_err) {
+                            l_cur->flags |= DAP_SOCK_SIGNAL_CLOSE;
+                            log_it(L_INFO, "Socket shutdown (EPOLLHUP): %s", strerror(l_sock_err));
+                        }
+                    break;
+                    default: log_it(L_WARNING, "Unimplemented EPOLLHUP for socket type %d", l_cur->type);
+                }
+            }
+
+            if(l_epoll_events[n].events & EPOLLERR) {
+                switch (l_cur->type ){
+                    case DESCRIPTOR_TYPE_SOCKET_LISTENING:
+                    case DESCRIPTOR_TYPE_SOCKET:
+                        getsockopt(l_cur->socket, SOL_SOCKET, SO_ERROR, (void *)&l_sock_err, (socklen_t *)&l_sock_err_size);
+                        log_it(L_ERROR, "Socket error: %s", strerror(l_sock_err));
+                    default: ;
+                }
+                l_cur->flags |= DAP_SOCK_SIGNAL_CLOSE;
+                l_cur->callbacks.error_callback(l_cur, 0); // Call callback to process error event
+            }
+
+            if (l_epoll_events[n].events & EPOLLRDHUP) {
+                log_it(L_INFO, "Client socket disconnected");
+                dap_events_socket_set_readable_unsafe(l_cur, false);
+                l_cur->flags |= DAP_SOCK_SIGNAL_CLOSE;
+            }
+
+            if(l_epoll_events[n].events & EPOLLIN) {
+
+                //log_it(L_DEBUG, "Comes connection with type %d", l_cur->type);
+                if(l_cur->buf_in_size == sizeof(l_cur->buf_in)) {
+                    log_it(L_WARNING, "Buffer is full when there is smth to read. Its dropped!");
+                    l_cur->buf_in_size = 0;
+                }
+
+                int32_t l_bytes_read = 0;
+                int l_errno=0;
+                bool l_must_read_smth = false;
+                switch (l_cur->type) {
+                    case DESCRIPTOR_TYPE_PIPE:
+                    case DESCRIPTOR_TYPE_FILE:
+                        l_must_read_smth = true;
+                        l_bytes_read = read(l_cur->socket, (char *) (l_cur->buf_in + l_cur->buf_in_size),
+                                sizeof(l_cur->buf_in) - l_cur->buf_in_size);
+                        l_errno = errno;
+                    break;
+                    case DESCRIPTOR_TYPE_SOCKET:
+                        l_must_read_smth = true;
+                        l_bytes_read = recv(l_cur->fd, (char *) (l_cur->buf_in + l_cur->buf_in_size),
+                                sizeof(l_cur->buf_in) - l_cur->buf_in_size, 0);
+                        l_errno = errno;
+                    break;
+                    case DESCRIPTOR_TYPE_SOCKET_LISTENING:
+                        // Accept connection
+                        if ( l_cur->callbacks.accept_callback){
+                            struct sockaddr l_remote_addr;
+                            socklen_t l_remote_addr_size= sizeof (l_remote_addr);
+                            int l_remote_socket= accept(l_cur->socket ,&l_remote_addr,&l_remote_addr_size);
+                            int l_errno = errno;
+                            if ( l_remote_socket == -1 ){
+                                if( l_errno == EAGAIN || l_errno == EWOULDBLOCK){// Everything is good, we'll receive ACCEPT on next poll
+                                    continue;
+                                }else{
+                                    char l_errbuf[128];
+                                    strerror_r(l_errno, l_errbuf, sizeof (l_errbuf));
+                                    log_it(L_WARNING,"accept() on socket %d error:\"%s\"(%d)",l_cur->socket, l_errbuf,l_errno);
+                                }
+                            }
+
+                            l_cur->callbacks.accept_callback(l_cur,l_remote_socket,&l_remote_addr);
+                        }else
+                            log_it(L_ERROR,"No accept_callback on listening socket");
+                    break;
+                    case DESCRIPTOR_TYPE_TIMER:{
+                        uint64_t val;
+                        /* if we not reading data from socket, he triggered again */
+                        read( l_cur->fd, &val, 8);
+                        if (l_cur->callbacks.timer_callback)
+                            l_cur->callbacks.timer_callback(l_cur);
+                        else
+                            log_it(L_ERROR, "Socket %d with timer callback fired, but callback is NULL ", l_cur->socket);
+
+                    } break;
+                    case DESCRIPTOR_TYPE_QUEUE:
+                        dap_events_socket_queue_proc_input_unsafe(l_cur);
+                    break;
+                    case DESCRIPTOR_TYPE_EVENT:
+                        dap_events_socket_event_proc_input_unsafe(l_cur);
+                    break;
+                }
+
+                if (l_must_read_smth){ // Socket/Descriptor read
+                    if(l_bytes_read > 0) {
+                        l_cur->buf_in_size += l_bytes_read;
+                        //log_it(L_DEBUG, "Received %d bytes", l_bytes_read);
+                        if(l_cur->callbacks.read_callback){
+                            l_cur->callbacks.read_callback(l_cur, NULL); // Call callback to process read event. At the end of callback buf_in_size should be zero if everything was read well
+                            if (l_cur->worker == NULL ){ // esocket was unassigned in callback, we don't need any ops with it now,
+                                                         // continue to poll another esockets
+                                continue;
+                            }
+                        }else{
+                            log_it(L_WARNING, "We have incomming %u data but no read callback on socket %d, removing from read set", l_cur->socket);
+                            dap_events_socket_set_readable_unsafe(l_cur,false);
+                        }
+                    }
+                    else if(l_bytes_read < 0) {
+                        if (l_errno != EAGAIN && l_errno != EWOULDBLOCK){ // Socket is blocked
+                            log_it(L_ERROR, "Some error occured in recv() function: %s", strerror(errno));
+                            dap_events_socket_set_readable_unsafe(l_cur, false);
+                            l_cur->flags |= DAP_SOCK_SIGNAL_CLOSE;
+                        }
+                    }
+                    else if (!(l_epoll_events[n].events & EPOLLRDHUP) || !(l_epoll_events[n].events & EPOLLERR)) {
+                        log_it(L_WARNING, "EPOLLIN triggered but nothing to read");
+                        dap_events_socket_set_readable_unsafe(l_cur,false);
+                    }
+                }
+            }
+
+            // Socket is ready to write
+            if(((l_epoll_events[n].events & EPOLLOUT) || (l_cur->flags & DAP_SOCK_READY_TO_WRITE))
+                    && !(l_cur->flags & DAP_SOCK_SIGNAL_CLOSE)) {
+
+                //log_it(L_DEBUG, "Main loop output: %u bytes to send", l_cur->buf_out_size);
+                if(l_cur->callbacks.write_callback)
+                    l_cur->callbacks.write_callback(l_cur, NULL); // Call callback to process write event
+
+                if (l_cur->worker == NULL ){ // esocket was unassigned in callback, we don't need any ops with it now,
+                                             // continue to poll another esockets
+                    continue;
+                }
+                if(l_cur->flags & DAP_SOCK_READY_TO_WRITE) {
+
+                    static const uint32_t buf_out_zero_count_max = 2;
+                    //l_cur->buf_out[l_cur->buf_out_size] = 0;
+
+                    if(!l_cur->buf_out_size) {
+
+                        //log_it(L_WARNING, "Output: nothing to send. Why we are in write socket set?");
+                        l_cur->buf_out_zero_count++;
+
+                        if(l_cur->buf_out_zero_count > buf_out_zero_count_max) { // How many time buf_out on write event could be empty
+                            //log_it(L_WARNING, "Output: nothing to send %u times, remove socket from the write set",
+                            //        buf_out_zero_count_max);
+                            dap_events_socket_set_writable_unsafe(l_cur, false);
+                        }
+                    }
+                    else
+                        l_cur->buf_out_zero_count = 0;
+                }
+                //for(total_sent = 0; total_sent < cur->buf_out_size;) { // If after callback there is smth to send - we do it
+                ssize_t l_bytes_sent =0;
+                int l_errno;
+                switch (l_cur->type){
+                    case DESCRIPTOR_TYPE_SOCKET:
+                        l_bytes_sent = send(l_cur->socket, l_cur->buf_out,
+                                l_cur->buf_out_size, MSG_DONTWAIT | MSG_NOSIGNAL);
+                        l_errno = errno;
+                    break;
+                    case DESCRIPTOR_TYPE_PIPE:
+                    case DESCRIPTOR_TYPE_FILE:
+                        l_bytes_sent = write(l_cur->socket, (char *) (l_cur->buf_out + l_bytes_sent),
+                                l_cur->buf_out_size );
+                        l_errno = errno;
+                    break;
+                    default:
+                        log_it(L_WARNING, "Socket %d is not SOCKET, PIPE or FILE but has WRITE state on. Switching it off");
+                        dap_events_socket_set_writable_unsafe(l_cur,false);
+                }
+
+                if(l_bytes_sent < 0) {
+                    if (l_errno != EAGAIN && l_errno != EWOULDBLOCK ){ // If we have non-blocking socket
+                        log_it(L_ERROR, "Some error occured in send(): %s", strerror(errno));
+                        l_cur->flags |= DAP_SOCK_SIGNAL_CLOSE;
+                    }
+                }else{
+
+                    //log_it(L_DEBUG, "Output: %u from %u bytes are sent ", l_bytes_sent,l_cur->buf_out_size);
+                    if (l_bytes_sent) {
+                        if ( l_bytes_sent <= l_cur->buf_out_size ){
+                            l_cur->buf_out_size -= l_bytes_sent;
+                            if (l_cur->buf_out_size ) {
+                                memmove(l_cur->buf_out, &l_cur->buf_out[l_bytes_sent], l_cur->buf_out_size);
+                            }
+                        }else{
+                            log_it(L_ERROR, "Wrong bytes sent, %zd more then was in buffer %zd",l_bytes_sent, l_cur->buf_out_size);
+                            l_cur->buf_out_size = 0;
+                        }
+                    }
+                }
+            }
+            if (l_cur->buf_out_size) {
+                dap_events_socket_set_writable_unsafe(l_cur,true);
+            }
+            if((l_cur->flags & DAP_SOCK_SIGNAL_CLOSE) && !l_cur->no_close  && l_cur->buf_out_size == 0) {
+                // protect against double deletion
+                l_cur->kill_signal = true;
+                //dap_events_socket_remove_and_delete(cur, true);
+                log_it(L_INFO, "Got signal to close %s, sock %u [thread %u]", l_cur->hostaddr, l_cur->socket, l_tn);
+            } else if (l_cur->buf_out_size ){
+                log_it(L_INFO, "Got signal to close %s, sock %u [thread %u] but buffer is not empty(%zd)", l_cur->hostaddr, l_cur->socket, l_tn,
+                       l_cur->buf_out_size);
+            }
+
+            if(l_cur->kill_signal && l_cur->buf_out_size == 0) {
+                log_it(L_INFO, "Kill %u socket (processed).... [ thread %u ]", l_cur->socket, l_tn);
+                dap_events_socket_remove_and_delete_unsafe( l_cur, false);
+            }else if (l_cur->buf_out_size ){
+                log_it(L_INFO, "Kill %u socket (processed).... [ thread %u ] but buffer is not empty(%zd)", l_cur->socket, l_tn,
+                       l_cur->buf_out_size);
+            }
+
+        }
+
+    } // while
+
+    return NULL;
+}
+
+/**
+ * @brief s_new_es_callback
+ * @param a_es
+ * @param a_arg
+ */
+static void s_queue_new_es_callback( dap_events_socket_t * a_es, void * a_arg)
+{
+    dap_events_socket_t * l_es_new =(dap_events_socket_t *) a_arg;
+    dap_worker_t * w = a_es->worker;
+    //log_it(L_DEBUG, "Received event socket %p to add on worker", l_es_new);
+    if(dap_events_socket_check_unsafe( w, a_es)){
+        log_it(L_ERROR, "Already assigned %d (%p), you're doing smth wrong", a_es->socket, a_es);
+        return;
+    }
+
+    if (  l_es_new->type == DESCRIPTOR_TYPE_SOCKET  ||  l_es_new->type == DESCRIPTOR_TYPE_SOCKET_LISTENING ){
+        int l_cpu = w->id;
+        setsockopt(l_es_new->socket , SOL_SOCKET, SO_INCOMING_CPU, &l_cpu, sizeof(l_cpu));
+    }
+    bool l_socket_present = (l_es_new->worker && l_es_new->is_initalized) ? true : false;
+    l_es_new->worker = w;
+    // We need to differ new and reassigned esockets. If its new - is_initialized is false
+    if ( ! l_es_new->is_initalized ){
+        if (l_es_new->callbacks.new_callback)
+            l_es_new->callbacks.new_callback(l_es_new, NULL);
+        l_es_new->is_initalized = true;
+    }
+
+    if (l_es_new->socket>0){
+        int l_ret = -1;
+#ifdef DAP_EVENTS_CAPS_EPOLL
+        // Init events for EPOLL
+        l_es_new->ev.events = l_es_new->ev_base_flags ;
+        if(l_es_new->flags & DAP_SOCK_READY_TO_READ )
+            l_es_new->ev.events |= EPOLLIN;
+        if(l_es_new->flags & DAP_SOCK_READY_TO_WRITE )
+            l_es_new->ev.events |= EPOLLOUT;
+        l_es_new->ev.data.ptr = l_es_new;
+        if (l_socket_present) {
+            // Update only flags, socket already present in worker
+            return;
+        }
+        l_ret = epoll_ctl(w->epoll_fd, EPOLL_CTL_ADD, l_es_new->socket, &l_es_new->ev);
+#else
+#error "Unimplemented new esocket on worker callback for current platform"
+#endif
+        if (  l_ret != 0 ){
+            log_it(L_CRITICAL,"Can't add event socket's handler to worker i/o poll mechanism with error %d", errno);
+        }else{
+            // Add in global list
+            // Add in worker
+            l_es_new->me = l_es_new;
+            HASH_ADD(hh_worker, w->esockets, me, sizeof(void *), l_es_new );
+            w->event_sockets_count++;
+            //log_it(L_DEBUG, "Added socket %d on worker %u", l_es_new->socket, w->id);
+            if (l_es_new->callbacks.worker_assign_callback)
+                l_es_new->callbacks.worker_assign_callback(l_es_new, w);
+
+        }
+    }else{
+        log_it(L_ERROR, "Incorrect socket %d after new callback. Dropping this handler out", l_es_new->socket);
+        dap_events_socket_remove_and_delete_unsafe( l_es_new, false );
+    }
+}
+
+/**
+ * @brief s_delete_es_callback
+ * @param a_es
+ * @param a_arg
+ */
+static void s_queue_delete_es_callback( dap_events_socket_t * a_es, void * a_arg)
+{
+    dap_events_socket_t * l_esocket = (dap_events_socket_t*) a_arg;
+    if (dap_events_socket_check_unsafe(a_es->worker,l_esocket)){
+        ((dap_events_socket_t*)a_arg)->kill_signal = true; // Send signal to socket to kill
+    }else
+        log_it(L_INFO, "While we were sending the delete() message, esocket %p has been disconnected", l_esocket);
+}
+
+/**
+ * @brief s_reassign_es_callback
+ * @param a_es
+ * @param a_arg
+ */
+static void s_queue_es_reassign_callback( dap_events_socket_t * a_es, void * a_arg)
+{
+    dap_worker_msg_reassign_t * l_msg = (dap_worker_msg_reassign_t*) a_arg;
+    dap_events_socket_t * l_es_reassign = l_msg->esocket;
+    if (dap_events_socket_check_unsafe(a_es->worker,l_es_reassign)){
+        if( l_es_reassign->was_reassigned && l_es_reassign->flags & DAP_SOCK_REASSIGN_ONCE) {
+            log_it(L_INFO, "Reassgment request with DAP_SOCK_REASSIGN_ONCE allowed only once, declined reassigment from %u to %u",
+                   l_es_reassign->worker->id, l_msg->worker_new->id);
+
+        }else{
+            dap_events_socket_reassign_between_workers_unsafe(l_es_reassign,l_msg->worker_new);
+        }
+    }else{
+        log_it(L_INFO, "While we were sending the reassign message, esocket %p has been disconnected", l_msg->esocket);
+    }
+    DAP_DELETE(l_msg);
+}
+
+/**
+ * @brief s_queue_callback
+ * @param a_es
+ * @param a_arg
+ */
+static void s_queue_callback_callback( dap_events_socket_t * a_es, void * a_arg)
+{
+    dap_worker_msg_callback_t * l_msg = (dap_worker_msg_callback_t *) a_arg;
+    assert(l_msg);
+    assert(l_msg->callback);
+    l_msg->callback(a_es->worker, l_msg->arg);
+    DAP_DELETE(l_msg);
+}
+
+/**
+ * @brief s_pipe_data_out_read_callback
+ * @param a_es
+ * @param a_arg
+ */
+static void s_queue_es_io_callback( dap_events_socket_t * a_es, void * a_arg)
+{
+    dap_worker_msg_io_t * l_msg = a_arg;
+
+    // Check if it was removed from the list
+    dap_events_socket_t *l_msg_es = NULL;
+    HASH_FIND(hh_worker, a_es->worker->esockets, &l_msg->esocket , sizeof (void*), l_msg_es );
+    if ( l_msg_es == NULL){
+        log_it(L_INFO, "We got i/o message for client thats now not in list. Lost %u data", l_msg->data_size);
+        DAP_DELETE(l_msg);
+        return;
+    }
+
+    if (l_msg->flags_set & DAP_SOCK_READY_TO_READ)
+        dap_events_socket_set_readable_unsafe(l_msg_es, true);
+    if (l_msg->flags_unset & DAP_SOCK_READY_TO_READ)
+        dap_events_socket_set_readable_unsafe(l_msg_es, false);
+    if (l_msg->flags_set & DAP_SOCK_READY_TO_WRITE)
+        dap_events_socket_set_writable_unsafe(l_msg_es, true);
+    if (l_msg->flags_unset & DAP_SOCK_READY_TO_WRITE)
+        dap_events_socket_set_writable_unsafe(l_msg_es, false);
+    if (l_msg->data_size && l_msg->data)
+        dap_events_socket_write_unsafe(l_msg_es, l_msg->data,l_msg->data_size);
+    DAP_DELETE(l_msg);
+}
+
+/**
+ * @brief s_socket_all_check_activity
+ * @param a_arg
+ */
+static void s_socket_all_check_activity( void * a_arg)
+{
+    dap_worker_t *l_worker = (dap_worker_t*) a_arg;
+    assert(l_worker);
+    dap_events_socket_t *l_es, *tmp;
+    char l_curtimebuf[64];
+    time_t l_curtime= time(NULL);
+    ctime_r(&l_curtime, l_curtimebuf);
+    //log_it(L_DEBUG,"Check sockets activity on worker #%u at %s", l_worker->id, l_curtimebuf);
+
+    HASH_ITER(hh_worker, l_worker->esockets, l_es, tmp ) {
+        if ( l_es->type == DESCRIPTOR_TYPE_SOCKET  ){
+            if ( !l_es->kill_signal && l_curtime >=  (time_t)l_es->last_time_active + s_connection_timeout && !l_es->no_close ) {
+                log_it( L_INFO, "Socket %u timeout, closing...", l_es->socket );
+                if (l_es->callbacks.error_callback) {
+                    l_es->callbacks.error_callback(l_es, ETIMEDOUT);
+                }
+                dap_events_socket_remove_and_delete_mt( l_worker, l_es);
+            }
+        }
+    }
+}
+
+/**
+ * @brief sap_worker_add_events_socket
+ * @param a_events_socket
+ * @param a_worker
+ */
+void dap_worker_add_events_socket(dap_events_socket_t * a_events_socket, dap_worker_t * a_worker)
+{
+    int l_ret = dap_events_socket_queue_ptr_send( a_worker->queue_es_new, a_events_socket );
+    if(l_ret != 0 ){
+        char l_errbuf[128];
+        strerror_r(l_ret,l_errbuf,sizeof (l_errbuf));
+        log_it(L_ERROR, "Cant send pointer in queue: \"%s\"(code %d)", l_errbuf, l_ret);
+    }
+}
+
+/**
+ * @brief dap_worker_exec_callback_on
+ */
+void dap_worker_exec_callback_on(dap_worker_t * a_worker, dap_worker_callback_t a_callback, void * a_arg)
+{
+    dap_worker_msg_callback_t * l_msg = DAP_NEW_Z(dap_worker_msg_callback_t);
+    l_msg->callback = a_callback;
+    l_msg->arg = a_arg;
+    int l_ret=dap_events_socket_queue_ptr_send( a_worker->queue_callback,l_msg );
+    if(l_ret != 0 ){
+        char l_errbuf[128];
+        strerror_r(l_ret,l_errbuf,sizeof (l_errbuf));
+        log_it(L_ERROR, "Cant send pointer in queue: \"%s\"(code %d)", l_errbuf, l_ret);
+    }
+
+}
+
+
+/**
+ * @brief dap_worker_add_events_socket
+ * @param a_worker
+ * @param a_events_socket
+ */
+dap_worker_t *dap_worker_add_events_socket_auto( dap_events_socket_t *a_es)
+{
+//  struct epoll_event ev = {0};
+  dap_worker_t *l_worker = dap_events_worker_get_auto( );
+
+  a_es->events = l_worker->events;
+  dap_worker_add_events_socket( a_es, l_worker);
+  return l_worker;
+}
+
+
+
diff --git a/dap-sdk/net/core/include/dap_client_remote.h b/dap-sdk/net/core/include/dap_client_remote.h
deleted file mode 100644
index 00a70653d7f63c2d836c17f9586b6b6f6a61eab6..0000000000000000000000000000000000000000
--- a/dap-sdk/net/core/include/dap_client_remote.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Authors:
- * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * Kelvin Project https://github.com/kelvinblockchain
- * Copyright  (c) 2017-2018
- * All rights reserved.
-
- This file is part of DAP (Deus Applications Prototypes) the open source project
-
-    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    DAP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
-#pragma once
-
-#include <stdint.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include "uthash.h"
-
-#ifndef WIN32
-#include <sys/epoll.h>
-#include <sys/timerfd.h>
-#endif
-
-#ifndef EPOLL_HANDLE
-  #ifndef WIN32
-    #define EPOLL_HANDLE  int
-  #else
-    #define EPOLL_HANDLE  HANDLE
-    #include "wepoll.h"
-  #endif
-#endif
-
-typedef char str_ip[16];
-
-typedef struct dap_server dap_server_t;
-typedef struct dap_server_thread_s dap_server_thread_t;
-
-struct dap_client_remote;
-
-typedef void (*dap_server_client_callback_t) (struct dap_client_remote *,void * arg); // Callback for specific client operations
-
-#define DAP_CLIENT_REMOTE_BUF 500000
-#define CLIENT_ID_SIZE 12
-
-typedef char dap_server_client_id[CLIENT_ID_SIZE];
-
-typedef struct traffic_stats {
-
-  size_t buf_size_total;
-  size_t buf_size_total_old; // for calculate speed
-  double speed_mbs; // MegaBits per second
-} traffic_stats_t;
-
-typedef struct dap_client_remote {
-
-  int socket;
-  dap_server_client_id id;
-
-  uint32_t  flags;
-  bool no_close;
-  bool kill_signal;
-
-  uint16_t port;
-  str_ip s_ip;
-
-  uint32_t buf_out_zero_count;
-  char buf_in[DAP_CLIENT_REMOTE_BUF]; // Internal buffer for input data
-
-  size_t buf_in_size; // size of data that is in the input buffer
-
-  traffic_stats_t upload_stat;
-  traffic_stats_t download_stat;
-
-  char buf_out[DAP_CLIENT_REMOTE_BUF]; // Internal buffer for output data
-  size_t buf_out_offset;
-
-  char hostaddr[1024]; // Address
-  char service[128];
-
-  size_t buf_out_size; // size of data that is in the output buffer
-  struct epoll_event  pevent;
-
-  EPOLL_HANDLE efd;            // Epoll fd
-  int tn;             // working thread index
-
-  time_t time_connection;
-  time_t last_time_active;
-
-  struct dap_server *server;
-  dap_server_thread_t *thread;
-
-  UT_hash_handle hh;
-  struct dap_client_remote *next, *prev;
-  struct dap_client_remote *knext, *kprev;
-
-  void *_internal;
-  void *_inheritor; // Internal data to specific client type, usualy states for state machine
-
-} dap_client_remote_t; // Node of bidirectional list of clients
-
-int   dap_client_remote_init( void ); //  Init clients module
-void  dap_client_remote_deinit( void ); // Deinit clients module
-
-dap_client_remote_t *dap_client_remote_create( dap_server_t *sh, int s, dap_server_thread_t *dsth );
-dap_client_remote_t *dap_client_remote_find( int sock, dap_server_thread_t *t );
-
-bool dap_client_remote_is_ready_to_read( dap_client_remote_t * sc );
-bool dap_client_remote_is_ready_to_write( dap_client_remote_t * sc );
-void dap_client_remote_ready_to_read( dap_client_remote_t * sc,bool is_ready );
-void dap_client_remote_ready_to_write( dap_client_remote_t * sc,bool is_ready );
-
-size_t dap_client_remote_write( dap_client_remote_t *sc, const void * data, size_t data_size );
-size_t dap_client_remote_write_f( dap_client_remote_t *a_client, const char * a_format,... );
-size_t dap_client_remote_read( dap_client_remote_t *sc, void * data, size_t data_size );
-
-//void dap_client_remote_remove( dap_client_remote_t *sc, struct dap_server * sh ); // Removes the client from the list
-void dap_client_remote_remove( dap_client_remote_t *sc );
-
-void dap_client_remote_shrink_buf_in( dap_client_remote_t * cl, size_t shrink_size );
-
diff --git a/dap-sdk/net/core/include/dap_events.h b/dap-sdk/net/core/include/dap_events.h
index e7b7777b1087b98c104d33bc0c91860f0d8b4d4d..c8e5471fb9e525c88370d01b1fa8c2661269f680 100644
--- a/dap-sdk/net/core/include/dap_events.h
+++ b/dap-sdk/net/core/include/dap_events.h
@@ -3,7 +3,7 @@
  * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
  * DeM Labs Inc.   https://demlabs.net
  * Kelvin Project https://github.com/kelvinblockchain
- * Copyright  (c) 2017-2019
+ * Copyright  (c) 2017-2020
  * All rights reserved.
 
  This file is part of DAP (Deus Applications Prototypes) the open source project
@@ -22,23 +22,13 @@
     along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
 */
 #pragma once
-
-#ifndef WIN32
-#include <netinet/in.h>
-
-#include <stdint.h>
 #include <pthread.h>
-#include <stdatomic.h>
-#define EPOLL_HANDLE  int
-#else
-#define EPOLL_HANDLE  HANDLE
-#endif
-
 #include "uthash.h"
 #include "dap_events_socket.h"
 #include "dap_server.h"
-
+#include "dap_worker.h"
 struct dap_events;
+#define DAP_MAX_EPOLL_EVENTS    8192
 
 typedef void (*dap_events_callback_t) (struct dap_events *, void *arg); // Callback for specific server's operations
 
@@ -46,47 +36,29 @@ typedef struct dap_thread {
   pthread_t tid;
 } dap_thread_t;
 
-struct dap_worker;
-
 typedef struct dap_events {
-
-  dap_events_socket_t *sockets; // Hashmap of event sockets
-  dap_events_socket_t *dlsockets; // Dlist of event sockets
-  dap_events_socket_t *to_kill_sockets; // Dlist of event sockets
-
-  pthread_rwlock_t sockets_rwlock;
-  void *_inheritor;  // Pointer to the internal data, HTTP for example
-  dap_thread_t proc_thread;
-  pthread_rwlock_t servers_rwlock;
-
+    dap_events_socket_t *sockets; // Hashmap of event sockets
+    pthread_rwlock_t sockets_rwlock;
+    void *_inheritor;  // Pointer to the internal data, HTTP for example
+    dap_thread_t proc_thread;
 } dap_events_t;
 
-typedef struct dap_worker
-{
-  atomic_uint event_sockets_count;
-  //uint32_t event_to_kill_count;
-
-  EPOLL_HANDLE epoll_fd;
-  uint32_t number_thread;
-  pthread_mutex_t locker_on_count;
-  dap_events_t *events;
-
-} dap_worker_t;
-
-int32_t  dap_events_init( uint32_t a_threads_count, size_t conn_t ); // Init server module
+int dap_events_init( uint32_t a_threads_count, size_t a_conn_timeout ); // Init server module
 void dap_events_deinit( ); // Deinit server module
 
-void dap_events_thread_wake_up( dap_thread_t *th );
 dap_events_t* dap_events_new( );
-void dap_events_delete( dap_events_t * sh );
-
-int32_t dap_events_start( dap_events_t *sh );
-void dap_events_stop();
-int32_t dap_events_wait( dap_events_t *sh );
+dap_events_t* dap_events_get_default( );
+void dap_events_delete( dap_events_t * a_events );
 
-uint32_t dap_worker_get_index_min( );
-dap_worker_t *dap_worker_get_min( );
+int32_t dap_events_start( dap_events_t *a_events );
+void dap_events_stop_all();
+int32_t dap_events_wait( dap_events_t *a_events );
 
-void dap_worker_add_events_socket( dap_events_socket_t * a_events_socket );
-void dap_worker_print_all( );
+void dap_events_worker_print_all( );
+uint32_t dap_events_worker_get_index_min( );
+uint32_t dap_events_worker_get_count();
+dap_worker_t *dap_events_worker_get_auto( );
 
+dap_worker_t * dap_events_worker_get(uint8_t a_index);
+uint32_t dap_get_cpu_count();
+void dap_cpu_assign_thread_on(uint32_t a_cpu_id);
diff --git a/dap-sdk/net/core/include/dap_events_socket.h b/dap-sdk/net/core/include/dap_events_socket.h
index 99ebe57b2bc355c41ecf4545b16a6547867bae23..81bf6a0098557b55c6d8db40b8fda629ea7aadb4 100644
--- a/dap-sdk/net/core/include/dap_events_socket.h
+++ b/dap-sdk/net/core/include/dap_events_socket.h
@@ -1,173 +1,243 @@
 /*
  * Authors:
  * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * Kelvin Project https://github.com/kelvinblockchain
- * Copyright  (c) 2017-2019
+ * DeM Labs Ltd.   https://demlabs.net
+ * Copyright  (c) 2017
  * All rights reserved.
 
- This file is part of DAP (Deus Applications Prototypes) the open source project
+ This file is part of DAP SDK the open source project
 
-    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
+    DAP SDK is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation, either version 3 of the License, or
     (at your option) any later version.
 
-    DAP is distributed in the hope that it will be useful,
+    DAP SDK is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
 
     You should have received a copy of the GNU General Public License
-    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
 */
 #pragma once
-
 #include <stdint.h>
 #include <stddef.h>
 #include <stdbool.h>
 #include <stdatomic.h>
+#include <pthread.h>
 #include "uthash.h"
-#ifndef _WIN32
+
+#include "dap_common.h"
+
+// Caps for different platforms
+#if defined(DAP_OS_LINUX)
+    #define DAP_EVENTS_CAPS_EPOLL
+    #define DAP_EVENTS_CAPS_PIPE_POSIX
+    #define DAP_EVENTS_CAPS_QUEUE_PIPE2
+    //#define DAP_EVENTS_CAPS_QUEUE_POSIX
+    #define DAP_EVENTS_CAPS_EVENT_EVENTFD
+    #include <netinet/in.h>
+    #include <sys/eventfd.h>
+    #include <mqueue.h>
+#elif defined (DAP_OS_UNIX)
+    #define DAP_EVENTS_CAPS_KQUEUE
+    #define DAP_EVENTS_CAPS_PIPE_POSIX
+    #define DAP_EVENTS_CAPS_EVENT_KEVENT
+    #define DAP_EVENTS_CAPS_QUEUE_SOCKETPAIR
+    #include <netinet/in.h>
+#elif defined (DAP_OS_WINDOWS)
+    #define DAP_EVENTS_CAPS_WEPOLL
+    #define DAP_EVENTS_CAPS_EPOLL
+    #define DAP_EVENTS_CAPS_QUEUE_WEVENT
+    #define DAP_EVENTS_CAPS_EVENT_WEVENT
+    #define DAP_EVENTS_CAPS_PIPE_POSIX
+#endif
+
+#if defined(DAP_EVENTS_CAPS_EPOLL)
 #include <sys/epoll.h>
-#else
+#define EPOLL_HANDLE  int
+#elif defined (DAP_EVENTS_CAPS_WEPOLL)
 #include "wepoll.h"
+#define EPOLL_HANDLE  HANDLE
 #endif
-#include <pthread.h>
-struct dap_events;
-struct dap_events_socket;
-struct dap_worker;
+
+#define BIT( x ) ( 1 << x )
+#define DAP_SOCK_READY_TO_READ     BIT( 0 )
+#define DAP_SOCK_READY_TO_WRITE    BIT( 1 )
+#define DAP_SOCK_SIGNAL_CLOSE      BIT( 2 )
+#define DAP_SOCK_ACTIVE            BIT( 3 )
+#define DAP_SOCK_REASSIGN_ONCE     BIT( 4 )   // This usable for FlowControl to prevent multiple reassigment
+
+// If set - queue limited to sizeof(void*) size of data transmitted
+#define DAP_SOCK_QUEUE_PTR         BIT( 8 )
+
+typedef struct dap_events dap_events_t;
+typedef struct dap_events_socket dap_events_socket_t;
+typedef struct dap_worker dap_worker_t;
 
 typedef struct dap_server dap_server_t;
-typedef void (*dap_events_socket_callback_t) (struct dap_events_socket *,void * arg); // Callback for specific client operations
+typedef void (*dap_events_socket_callback_t) (dap_events_socket_t *,void * ); // Callback for specific client operations
+typedef void (*dap_events_socket_callback_error_t) (dap_events_socket_t *, int ); // Callback for specific client operations
+typedef void (*dap_events_socket_callback_queue_t) (dap_events_socket_t *,const void * , size_t); // Callback for specific client operations
+typedef void (*dap_events_socket_callback_event_t) (dap_events_socket_t *, uint64_t); // Callback for specific client operations
+typedef void (*dap_events_socket_callback_pipe_t) (dap_events_socket_t *,const void * , size_t); // Callback for specific client operations
+typedef void (*dap_events_socket_callback_queue_ptr_t) (dap_events_socket_t *, void *); // Callback for specific client operations
+typedef void (*dap_events_socket_callback_timer_t) (dap_events_socket_t * ); // Callback for specific client operations
+typedef void (*dap_events_socket_callback_accept_t) (dap_events_socket_t * , int, struct sockaddr* ); // Callback for accept of new connection
+typedef void (*dap_events_socket_worker_callback_t) (dap_events_socket_t *,dap_worker_t * ); // Callback for specific client operations
 
 typedef struct dap_events_socket_callbacks {
-
+    union{
+        dap_events_socket_callback_accept_t accept_callback; // Accept callback for listening socket
+        dap_events_socket_callback_timer_t timer_callback; // Timer callback for listening socket
+        dap_events_socket_callback_event_t event_callback; // Event callback for listening socket
+        dap_events_socket_callback_queue_t queue_callback; // Queue callback for listening socket
+        dap_events_socket_callback_queue_ptr_t queue_ptr_callback; // queue_ptr callback for listening socket
+    };
     dap_events_socket_callback_t new_callback; // Create new client callback
     dap_events_socket_callback_t delete_callback; // Delete client callback
     dap_events_socket_callback_t read_callback; // Read function
     dap_events_socket_callback_t write_callback; // Write function
-    dap_events_socket_callback_t error_callback; // Error processing function
+    dap_events_socket_callback_error_t error_callback; // Error processing function
+
+    dap_events_socket_worker_callback_t worker_assign_callback; // After successful worker assign
+    dap_events_socket_worker_callback_t worker_unassign_callback; // After successful worker unassign
 
 } dap_events_socket_callbacks_t;
 
 #define DAP_EVENTS_SOCKET_BUF 100000
 
-#if 0
+typedef enum {
+    DESCRIPTOR_TYPE_SOCKET = 0,
+    DESCRIPTOR_TYPE_SOCKET_LISTENING,
+    DESCRIPTOR_TYPE_QUEUE,
+    DESCRIPTOR_TYPE_PIPE,
+    DESCRIPTOR_TYPE_TIMER,
+    DESCRIPTOR_TYPE_EVENT,
+    DESCRIPTOR_TYPE_FILE
+} dap_events_desc_type_t;
+
 typedef struct dap_events_socket {
+    union{
+        int socket;
+        int fd;
+#if defined(DAP_EVENTS_CAPS_QUEUE_POSIX)
+        mqd_t mqd;
+#endif
+    };
+#ifdef DAP_EVENTS_CAPS_PIPE_POSIX
+    int fd2;
+#endif
+    dap_events_desc_type_t type;
+    // Related sockets (be careful - possible problems, delete them before )
+    dap_events_socket_t ** workers_es; // If not NULL - on every worker must be present
+    size_t workers_es_size;           //  events socket with same socket
+
+    // Flags. TODO  - rework in bool fields
+    uint32_t  flags;
+    bool no_close;
+    atomic_bool kill_signal;
+    atomic_bool is_initalized;
+    bool was_reassigned; // Was reassigment at least once
 
-    int socket;
-    bool signal_close;
+    uint32_t buf_out_zero_count;
 
-    bool _ready_to_write;
-    bool _ready_to_read;
+    // Flags
+    bool is_pingable;
+    bool is_read_direct; // If set - don't call read() in worker, let operate with handler to callback
+    bool is_dont_reset_write_flag; // If set - don't reset write flag ever data is over
 
-    uint32_t buf_out_zero_count;
+    // Input section
     union{
         uint8_t buf_in[DAP_EVENTS_SOCKET_BUF+1]; // Internal buffer for input data
         char buf_in_str[DAP_EVENTS_SOCKET_BUF+1];
     };
     size_t buf_in_size; // size of data that is in the input buffer
 
+    // Output section
+
     uint8_t buf_out[DAP_EVENTS_SOCKET_BUF+1]; // Internal buffer for output data
+    size_t buf_out_size; // size of data that is in the output buffer
+    dap_events_socket_t * pipe_out; // Pipe socket with data for output
 
+    // Stored string representation
     char hostaddr[1024]; // Address
     char service[128];
+    struct sockaddr remote_addr;
 
-    size_t buf_out_size; // size of data that is in the output buffer
+    // Links to related objects
+    dap_events_t *events;
+    dap_worker_t *worker;
+    dap_server_t *server; // If this socket assigned with server
 
-    struct dap_events *events;
+    // Platform specific things
+#ifdef DAP_EVENTS_CAPS_EPOLL
+    uint32_t ev_base_flags;
+    struct epoll_event ev;
+#endif
 
-    struct dap_worker *dap_worker;
-    dap_events_socket_callbacks_t *callbacks;
+    dap_events_socket_callbacks_t callbacks;
 
     time_t time_connection;
+    time_t last_time_active;
     time_t last_ping_request;
-    bool is_pingable;
-
-    UT_hash_handle hh;
-
-    void * _inheritor; // Inheritor data to specific client type, usualy states for state machine
-} dap_events_socket_t; // Node of bidirectional list of clients
-#endif
-
-typedef enum {
-    DESCRIPTOR_TYPE_SOCKET = 0,
-    DESCRIPTOR_TYPE_FILE
-} dap_events_desc_type_t;
-
-typedef struct dap_events_socket {
 
-  int32_t socket;
-  dap_events_desc_type_t type;
+    void *_inheritor; // Inheritor data to specific client type, usualy states for state machine
+    struct dap_events_socket * me; // pointer on itself
 
-  uint32_t  flags;
-//  bool signal_close;
-  bool no_close;
-  atomic_bool kill_signal;
-//  bool _ready_to_write;
-//  bool _ready_to_read;
-
-  uint32_t buf_out_zero_count;
-  union{
-    uint8_t buf_in[DAP_EVENTS_SOCKET_BUF+1]; // Internal buffer for input data
-    char buf_in_str[DAP_EVENTS_SOCKET_BUF+1];
-  };
-  size_t buf_in_size; // size of data that is in the input buffer
-
-  uint8_t buf_out[DAP_EVENTS_SOCKET_BUF+1]; // Internal buffer for output data
-
-  char hostaddr[1024]; // Address
-  char service[128];
-
-  size_t buf_out_size; // size of data that is in the output buffer
-
-  struct dap_events *events;
-  struct dap_worker *dap_worker;
-  struct epoll_event ev;
-
-  dap_events_socket_callbacks_t *callbacks;
-
-  time_t time_connection;
-  time_t last_time_active;
-  time_t last_ping_request;
-  bool is_pingable;
-
-  UT_hash_handle hh;
-  struct dap_events_socket *next, *prev;
-  struct dap_events_socket *knext, *kprev;
-
-  void *_inheritor; // Inheritor data to specific client type, usualy states for state machine
-
-  pthread_mutex_t write_hold;
+    UT_hash_handle hh;
+    UT_hash_handle hh_worker; // Handle for local CPU storage on worker
 } dap_events_socket_t; // Node of bidirectional list of clients
 
 int dap_events_socket_init(); //  Init clients module
 void dap_events_socket_deinit(); // Deinit clients module
 
-void dap_events_socket_create_after(dap_events_socket_t * a_es);
+dap_events_socket_t * dap_events_socket_create_type_queue_ptr_unsafe(dap_worker_t * a_w, dap_events_socket_callback_queue_ptr_t a_callback);
+dap_events_socket_t * dap_events_socket_create_type_queue_ptr_mt(dap_worker_t * a_w, dap_events_socket_callback_queue_ptr_t a_callback);
+int dap_events_socket_queue_proc_input_unsafe(dap_events_socket_t * a_esocket);
 
-dap_events_socket_t * dap_events_socket_wrap_no_add(struct dap_events * a_events,
-                                            int s, dap_events_socket_callbacks_t * a_callbacks); // Create new client and add it to the list
+dap_events_socket_t * dap_events_socket_create_type_event_unsafe(dap_worker_t * a_w, dap_events_socket_callback_event_t a_callback);
+dap_events_socket_t * dap_events_socket_create_type_event_mt(dap_worker_t * a_w, dap_events_socket_callback_event_t a_callback);
+void dap_events_socket_event_proc_input_unsafe(dap_events_socket_t *a_esocket);
 
+dap_events_socket_t * dap_events_socket_create_type_pipe_unsafe(dap_worker_t * a_w, dap_events_socket_callback_t a_callback, uint32_t a_flags);
+dap_events_socket_t * dap_events_socket_create_type_pipe_mt(dap_worker_t * a_w, dap_events_socket_callback_t a_callback, uint32_t a_flags);
+int dap_events_socket_queue_ptr_send( dap_events_socket_t * a_es, void* a_arg);
+int dap_events_socket_event_signal( dap_events_socket_t * a_es, uint64_t a_value);
 
-dap_events_socket_t * dap_events_socket_find(int sock, struct dap_events * sh); // Find client by socket
+dap_events_socket_t *dap_events_socket_wrap_no_add( dap_events_t *a_events,
+                                            int a_sock, dap_events_socket_callbacks_t *a_callbacks );
+dap_events_socket_t * dap_events_socket_wrap2( dap_server_t *a_server, struct dap_events *a_events,
+                                            int a_sock, dap_events_socket_callbacks_t *a_callbacks );
 
-bool dap_events_socket_is_ready_to_read(dap_events_socket_t * sc);
-bool dap_events_socket_is_ready_to_write(dap_events_socket_t * sc);
-void dap_events_socket_set_readable(dap_events_socket_t * sc,bool is_ready);
-void dap_events_socket_set_writable(dap_events_socket_t * sc,bool is_ready);
+void dap_events_socket_assign_on_worker_unsafe(dap_events_socket_t * a_es, struct dap_worker * a_worker);
+void dap_events_socket_assign_on_worker_mt(dap_events_socket_t * a_es, struct dap_worker * a_worker);
 
-size_t dap_events_socket_write(dap_events_socket_t *sc, const void * data, size_t data_size);
-size_t dap_events_socket_write_f(dap_events_socket_t *sc, const char * format,...);
-size_t dap_events_socket_read(dap_events_socket_t *sc, void * data, size_t data_size);
+void dap_events_socket_reassign_between_workers_mt(dap_worker_t * a_worker_old, dap_events_socket_t * a_es, dap_worker_t * a_worker_new);
+void dap_events_socket_reassign_between_workers_unsafe(dap_events_socket_t * a_es, dap_worker_t * a_worker_new);
 
-void dap_events_socket_remove( dap_events_socket_t *a_es);
-void dap_events_socket_delete(dap_events_socket_t *sc,bool preserve_inheritor); // Removes the client from the list
-void dap_events_socket_remove_and_delete(dap_events_socket_t* a_es, bool preserve_inheritor );
-int dap_events_socket_kill_socket( dap_events_socket_t *a_es );
+dap_events_socket_t * dap_events_socket_find_unsafe(int sock, struct dap_events * sh); // Find client by socket
 
+size_t dap_events_socket_pop_from_buf_in(dap_events_socket_t *sc, void * data, size_t data_size);
 
+// Non-MT functions
+bool dap_events_socket_check_unsafe(dap_worker_t * a_worker,dap_events_socket_t * a_es);
+void dap_events_socket_set_readable_unsafe(dap_events_socket_t * sc,bool is_ready);
+void dap_events_socket_set_writable_unsafe(dap_events_socket_t * sc,bool is_ready);
 
+size_t dap_events_socket_write_unsafe(dap_events_socket_t *sc, const void * data, size_t data_size);
+size_t dap_events_socket_write_f_unsafe(dap_events_socket_t *sc, const char * format,...);
+
+// MT variants less
+void dap_events_socket_set_readable_mt(dap_worker_t * a_w, dap_events_socket_t * a_es,bool a_is_ready);
+void dap_events_socket_set_writable_mt(dap_worker_t * a_w, dap_events_socket_t * a_es,bool a_is_ready);
+size_t dap_events_socket_write_mt(dap_worker_t * a_w, dap_events_socket_t *sc, const void * data, size_t data_size);
+size_t dap_events_socket_write_f_mt(dap_worker_t * a_w, dap_events_socket_t *sc, const char * format,...);
+void dap_events_socket_remove_and_delete_mt( dap_worker_t * a_w, dap_events_socket_t* a_es);
+void dap_events_socket_remove_and_delete_unsafe( dap_events_socket_t *a_es, bool preserve_inheritor );
+
+void dap_events_socket_remove_from_worker_unsafe( dap_events_socket_t *a_es, dap_worker_t * a_worker);
 void dap_events_socket_shrink_buf_in(dap_events_socket_t * cl, size_t shrink_size);
 
+
diff --git a/dap-sdk/net/core/include/dap_proc_queue.h b/dap-sdk/net/core/include/dap_proc_queue.h
new file mode 100644
index 0000000000000000000000000000000000000000..e38c2d82c3c99bd37da2f338105f1ace57c52d23
--- /dev/null
+++ b/dap-sdk/net/core/include/dap_proc_queue.h
@@ -0,0 +1,48 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Ltd.   https://demlabs.net
+ * Copyright  (c) 2020
+ * All rights reserved.
+
+ This file is part of DAP SDK the open source project
+
+    DAP SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DAP SDK is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+#include "dap_events_socket.h"
+
+typedef struct dap_proc_thread dap_proc_thread_t;
+
+typedef bool (*dap_proc_queue_callback_t)(dap_proc_thread_t*,void* ); // Callback for processor. Returns true if we want to continue running
+
+typedef struct dap_proc_queue_item{
+    dap_proc_queue_callback_t callback;
+    void *callback_arg;
+    struct dap_proc_queue_item * next;
+} dap_proc_queue_item_t;
+
+typedef struct dap_proc_queue{
+    dap_proc_thread_t * proc_thread;
+    dap_events_socket_t *esocket;
+    dap_proc_queue_item_t * items;
+} dap_proc_queue_t;
+
+dap_proc_queue_t * dap_proc_queue_create(dap_proc_thread_t * a_thread);
+
+void dap_proc_queue_delete(dap_proc_queue_t * a_queue);
+void dap_proc_queue_add_callback(dap_proc_queue_t * a_queue,dap_proc_queue_callback_t a_callback, void * a_callback_arg);
+
+void dap_proc_queue_add_callback_auto(dap_proc_queue_callback_t a_callback, void * a_callback_arg);
+
diff --git a/dap-sdk/net/core/include/dap_proc_thread.h b/dap-sdk/net/core/include/dap_proc_thread.h
new file mode 100644
index 0000000000000000000000000000000000000000..0682f285b22a6d568846986cdf3e32c628cf5b1b
--- /dev/null
+++ b/dap-sdk/net/core/include/dap_proc_thread.h
@@ -0,0 +1,52 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Ltd.   https://demlabs.net
+ * Copyright  (c) 2020
+ * All rights reserved.
+
+ This file is part of DAP SDK the open source project
+
+    DAP SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DAP SDK is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <pthread.h>
+#include <stdatomic.h>
+#include "dap_common.h"
+#include "dap_proc_queue.h"
+
+typedef struct dap_proc_thread{
+    uint32_t cpu_id;
+    pthread_t thread_id;
+    dap_proc_queue_t * proc_queue;
+    dap_events_socket_t * proc_event; // Should be armed if we have to deal with it
+    atomic_uint proc_queue_size;
+
+    pthread_cond_t started_cond;
+    pthread_mutex_t started_mutex;
+
+    bool signal_kill;
+
+#ifdef DAP_EVENTS_CAPS_EPOLL
+    EPOLL_HANDLE epoll_ctl;
+#else
+#error "No poll for proc thread for your platform"
+#endif
+} dap_proc_thread_t;
+
+int dap_proc_thread_init(uint32_t a_threads_count);
+dap_proc_thread_t * dap_proc_thread_get(uint32_t a_thread_number);
+dap_proc_thread_t * dap_proc_thread_get_auto();
diff --git a/dap-sdk/net/core/include/dap_server.h b/dap-sdk/net/core/include/dap_server.h
index 77f0004e0d1ee306a409e37969f55df2a37c6397..44bf62135e5756e0d1c05fb1f62937e4d0b1ccc8 100644
--- a/dap-sdk/net/core/include/dap_server.h
+++ b/dap-sdk/net/core/include/dap_server.h
@@ -1,36 +1,47 @@
 /*
- Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc
-  All rights reserved.
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Ltd.   https://demlabs.net
+ * Copyright  (c) 2017
+ * All rights reserved.
 
- This file is part of DAP (Deus Applications Prototypes) the open source project
+ This file is part of DAP SDK the open source project
 
-    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
-    it under the terms of the GNU Lesser General Public License as published by
+    DAP SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
     the Free Software Foundation, either version 3 of the License, or
     (at your option) any later version.
 
-    DAP is distributed in the hope that it will be useful,
+    DAP SDK is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU Lesser General Public License for more details.
+    GNU General Public License for more details.
 
-    You should have received a copy of the GNU Lesser General Public License
-    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
+    You should have received a copy of the GNU General Public License
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
 */
+
+
 #pragma once
 
-#ifndef _WIN32
+#include "dap_common.h"
+#if defined( DAP_OS_LINUX)
+
 #include <netinet/in.h>
 #include <stdint.h>
 #include <sys/epoll.h>
 #include <sys/timerfd.h>
 #define EPOLL_HANDLE  int
-#else
+
+#elif defined(DAP_OS_WINDOWS)
+
 #define EPOLL_HANDLE  HANDLE
 #define MSG_DONTWAIT 0
 #define MSG_NOSIGNAL 0
 #include "winsock.h"
 #include "wepoll.h"
+#else
+#error "No poll headers for your platform"
 #endif
 
 #include <pthread.h>
@@ -38,34 +49,11 @@
 #include "utlist.h"
 
 #include "dap_cpu_monitor.h"
-#include "dap_client_remote.h"
+#include "dap_events_socket.h"
 
 typedef enum dap_server_type {DAP_SERVER_TCP} dap_server_type_t;
 
-#define BIT( x ) ( 1 << x )
 
-#define DAP_SOCK_READY_TO_READ     BIT( 0 )
-#define DAP_SOCK_READY_TO_WRITE    BIT( 1 )
-#define DAP_SOCK_SIGNAL_CLOSE      BIT( 2 )
-#define DAP_SOCK_ACTIVE            BIT( 3 )
-
-typedef struct dap_server_thread_s {
-
-  EPOLL_HANDLE epoll_fd;
-
-  uint32_t thread_num;
-  uint32_t connections_count;
-  uint32_t to_kill_count;
-
-  struct epoll_event  *epoll_events;
-  dap_client_remote_t *dap_remote_clients;
-  dap_client_remote_t *hclients; // Hashmap of clients
-  dap_client_remote_t *dap_clients_to_kill;
-
-  pthread_mutex_t mutex_dlist_add_remove;
-  pthread_mutex_t mutex_on_hash;
-
-} dap_server_thread_t;
 
 struct dap_server;
 
@@ -78,7 +66,7 @@ typedef struct dap_server {
   char *address; // Listen address
 
   int32_t socket_listener; // Socket for listener
-  EPOLL_HANDLE epoll_fd; // Epoll fd
+  dap_events_socket_t * es_listener;
 
   struct sockaddr_in listener_addr; // Kernel structure for listener's binded address
 
@@ -86,64 +74,15 @@ typedef struct dap_server {
 
   dap_cpu_stats_t cpu_stats;
 
-  dap_server_callback_t server_delete_callback;
+  dap_server_callback_t delete_callback;
 
-  dap_server_client_callback_t client_new_callback; // Create new client callback
-  dap_server_client_callback_t client_delete_callback; // Delete client callback
-  dap_server_client_callback_t client_read_callback; // Read function
-  dap_server_client_callback_t client_write_callback; // Write function
-  dap_server_client_callback_t client_error_callback; // Error processing function
+  dap_events_socket_callbacks_t client_callbacks; // Callbacks for the new clients
 
+  pthread_cond_t started_cond; // Condition for initialized socket
+  pthread_mutex_t started_mutex; // Mutex for shared operation between mirrored sockets
 } dap_server_t;
 
-int32_t dap_server_init( uint32_t count_threads ); // Init server module
-void    dap_server_deinit( void ); // Deinit server module
-
-dap_server_t *dap_server_listen( const char *addr, uint16_t port, dap_server_type_t type );
-
-int32_t dap_server_loop( dap_server_t *d_server );
-void dap_server_loop_stop( void );
-
-#define DL_LIST_REMOVE_NODE( head, obj, _prev_, _next_, total )  \
-                                                                 \
-  if ( obj->_next_ ) {                                           \
-                                                                 \
-    if ( obj->_prev_ )                                           \
-      obj->_next_->_prev_ = obj->_prev_;                         \
-    else {                                                       \
-                                                                 \
-      obj->_next_->_prev_ = NULL;                                \
-      head = obj->_next_;                                        \
-    }                                                            \
-  }                                                              \
-                                                                 \
-  if ( obj->_prev_ ) {                                           \
-                                                                 \
-    if ( obj->_next_ )                                           \
-      obj->_prev_->_next_ = obj->_next_;                         \
-    else {                                                       \
-                                                                 \
-      obj->_prev_->_next_ = NULL;                                \
-    }                                                            \
-  }                                                              \
-  -- total;
-
-#define DL_LIST_ADD_NODE_HEAD( head, obj, _prev_, _next_, total )\
-                                                                 \
-  if ( !total ) {                                                \
-                                                                 \
-    obj->_prev_    = NULL;                                       \
-    obj->_next_    = NULL;                                       \
-                                                                 \
-    head = obj;                                                  \
-  }                                                              \
-  else {                                                         \
-                                                                 \
-    head->_prev_ = obj;                                          \
-                                                                 \
-    obj->_prev_ = NULL;                                          \
-    obj->_next_ = head;                                          \
-                                                                 \
-    head = obj;                                                  \
-  }                                                              \
-  ++ total;
+int dap_server_init( ); // Init server module
+void  dap_server_deinit( void ); // Deinit server module
+
+dap_server_t* dap_server_new(dap_events_t *a_events, const char * a_addr, uint16_t a_port, dap_server_type_t a_type);
diff --git a/dap-sdk/net/core/include/dap_timerfd.h b/dap-sdk/net/core/include/dap_timerfd.h
index a658606e8395a69668ae11d1fa430c35e5e011dd..716e721871db6501e60daced826294e6ff4bc2b8 100644
--- a/dap-sdk/net/core/include/dap_timerfd.h
+++ b/dap-sdk/net/core/include/dap_timerfd.h
@@ -1,27 +1,26 @@
 /*
  * Authors:
  * Alexander Lysikov <alexander.lysikov@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * Kelvin Project https://github.com/kelvinblockchain
+ * DeM Labs Ltd.   https://demlabs.net
  * Copyright  (c) 2020
  * All rights reserved.
 
- This file is part of DAP (Deus Applications Prototypes) the open source project
+ This file is part of DAP SDK the open source project
 
- DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
+    DAP SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
 
- DAP is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
- */
+    DAP SDK is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
 
+    You should have received a copy of the GNU General Public License
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
 #include <stdint.h>
 #include <stdbool.h>
 #include <errno.h>
@@ -35,7 +34,7 @@
 #include "dap_common.h"
 #include "dap_events_socket.h"
 
-typedef void (*dap_timerfd_callback_t)(void * arg); // Callback for timer
+typedef void (*dap_timerfd_callback_t)(void* ); // Callback for timer
 
 typedef struct dap_timerfd {
     uint64_t timeout_ms;
@@ -46,6 +45,7 @@ typedef struct dap_timerfd {
 } dap_timerfd_t;
 
 int dap_timerfd_init();
-dap_timerfd_t* dap_timerfd_start(uint64_t a_timeout_ms, dap_timerfd_callback_t *a_callback, void *callback_arg);
-int dap_timerfd_delete(dap_timerfd_t *l_timerfd);
+dap_timerfd_t* dap_timerfd_start(uint64_t a_timeout_ms, dap_timerfd_callback_t a_callback, void *callback_arg);
+dap_timerfd_t* dap_timerfd_start_on_worker(dap_worker_t * a_worker, uint64_t a_timeout_ms, dap_timerfd_callback_t a_callback, void *a_callback_arg);
+void dap_timerfd_delete(dap_timerfd_t *l_timerfd);
 
diff --git a/dap-sdk/net/core/include/dap_traffic_track.h b/dap-sdk/net/core/include/dap_traffic_track.h
deleted file mode 100644
index 1cfae9d22689621d0c99a746f96d07a9321543a3..0000000000000000000000000000000000000000
--- a/dap-sdk/net/core/include/dap_traffic_track.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Authors:
- * Anatoliy Jurotich  <anatoliy.kurotich@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * Kelvin Project https://github.com/kelvinblockchain
- * Copyright  (c) 2017-2018
- * All rights reserved.
-
- This file is part of DAP (Deus Applications Prototypes) the open source project
-
-    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    DAP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#pragma once
-
-#include "dap_client_remote.h"
-#include "dap_server.h"
-
-typedef void (*dap_traffic_callback_t) (dap_server_t *);
-
-/**
- * @brief dap_traffic_track_init
- * @param clients
- * @param timeout callback
- */
-void dap_traffic_track_init( dap_server_t *server, time_t timeout );
-
-/**
- * @brief dap_traffic_track_deinit
- */
-void dap_traffic_track_deinit( void );
-
-/**
- * @brief dap_traffic_add_callback
- */
-void dap_traffic_callback_set( dap_traffic_callback_t );
-
-void dap_traffic_callback_stop( void );
-
diff --git a/dap-sdk/net/core/include/dap_worker.h b/dap-sdk/net/core/include/dap_worker.h
new file mode 100644
index 0000000000000000000000000000000000000000..eb02022f633a4162e63536a2349091a553857e28
--- /dev/null
+++ b/dap-sdk/net/core/include/dap_worker.h
@@ -0,0 +1,86 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Ltd.   https://demlabs.net
+ * Copyright  (c) 2020
+ * All rights reserved.
+
+ This file is part of DAP SDK the open source project
+
+    DAP SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DAP SDK is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+#include <stdint.h>
+#include <stdatomic.h>
+#include <pthread.h>
+#include "dap_events_socket.h"
+#include "dap_timerfd.h"
+
+#include "dap_proc_queue.h"
+typedef struct dap_worker
+{
+    uint32_t id;
+    dap_events_t* events;
+    dap_proc_queue_t* proc_queue;
+    atomic_uint event_sockets_count;
+    dap_events_socket_t *esockets; // Hashmap of event sockets
+
+    // worker control queues
+    dap_events_socket_t * queue_es_new; // Events socket for new socket
+    dap_events_socket_t * queue_es_delete; // Events socke
+    dap_events_socket_t * queue_es_reassign; // Reassign between workers
+    dap_events_socket_t * queue_es_io; // Events socket for new socket
+
+    dap_events_socket_t * queue_callback; // Queue for pure callback on worker
+
+    dap_timerfd_t * timer_check_activity;
+#ifdef DAP_EVENTS_CAPS_EPOLL
+    EPOLL_HANDLE epoll_fd;
+#endif
+    pthread_cond_t started_cond;
+    pthread_mutex_t started_mutex;
+    void * _inheritor;
+} dap_worker_t;
+
+// Message for reassigment
+typedef struct dap_worker_msg_reassign{
+    dap_events_socket_t * esocket;
+    dap_worker_t * worker_new;
+} dap_worker_msg_reassign_t;
+
+// Message for input/output queue
+typedef struct dap_worker_msg_io{
+    dap_events_socket_t * esocket;
+    size_t data_size;
+    void *data;
+    uint32_t flags_set;
+    uint32_t flags_unset;
+} dap_worker_msg_io_t;
+
+// Message for callback execution
+typedef void (*dap_worker_callback_t)(dap_worker_t *,void *);
+typedef struct dap_worker_msg_callback{
+    dap_worker_callback_t callback; // Callback for specific client operations
+    void * arg;
+} dap_worker_msg_callback_t;
+
+int dap_worker_init( size_t a_conn_timeout );
+void dap_worker_deinit();
+
+void dap_worker_add_events_socket(dap_events_socket_t * a_events_socket, dap_worker_t * a_worker);
+dap_worker_t *dap_worker_add_events_socket_auto( dap_events_socket_t * a_events_socket );
+void dap_worker_exec_callback_on(dap_worker_t * a_worker, dap_worker_callback_t a_callback, void * a_arg);
+
+// Thread function
+void *dap_worker_thread(void *arg);
diff --git a/dap-sdk/net/server-udp/dap_udp_client.c b/dap-sdk/net/server-udp/dap_udp_client.c
index ab13f7de654ba89a6184c4c38eb71a4e7a3c9d28..fd4e86e809fa192a12a492537eeeb2f7cd7e51d8 100644
--- a/dap-sdk/net/server-udp/dap_udp_client.c
+++ b/dap-sdk/net/server-udp/dap_udp_client.c
@@ -70,7 +70,7 @@ extern bool sb_payload_ready;
  * @param port Client port
  * @return Pointer to the new list's node
  */
-dap_client_remote_t *dap_udp_client_create( dap_server_t *dap_srv, EPOLL_HANDLE efd, unsigned long host, unsigned short port )
+dap_events_socket_t *dap_udp_client_create( dap_server_t *dap_srv, EPOLL_HANDLE efd, unsigned long host, unsigned short port )
 {
   dap_udp_server_t *udp_server = DAP_UDP_SERVER( dap_srv );
   log_it( L_DEBUG, "Client structure create with host = %x, port = %d", host, port );
@@ -78,14 +78,10 @@ dap_client_remote_t *dap_udp_client_create( dap_server_t *dap_srv, EPOLL_HANDLE
   dap_udp_client_t *inh = DAP_NEW_Z( dap_udp_client_t );
   inh->host_key = get_key( host, port );
 
-  dap_client_remote_t *ret = DAP_NEW_Z( dap_client_remote_t );
-  inh->client = ret;
-
-  ret->pevent.events = EPOLLIN | EPOLLERR;
-  ret->pevent.data.fd = dap_srv->socket_listener;
+  dap_events_socket_t *ret = dap_events_socket_wrap_no_add( dap_srv->es_listener->events, dap_srv->socket_listener, &dap_srv->client_callbacks);
+  inh->esocket = ret;
 
   ret->server = dap_srv;
-  ret->efd = efd;
 
   ret->flags = DAP_SOCK_READY_TO_READ;
 
@@ -101,8 +97,8 @@ dap_client_remote_t *dap_udp_client_create( dap_server_t *dap_srv, EPOLL_HANDLE
   HASH_ADD_INT( udp_server->hclients, host_key, inh );
   pthread_mutex_unlock( &udp_server->mutex_on_list );
 
-  if( dap_srv->client_new_callback )
-    dap_srv->client_new_callback( ret, NULL ); // Init internal structure
+  if( dap_srv->client_callbacks.new_callback )
+    dap_srv->client_callbacks.new_callback( ret, NULL ); // Init internal structure
 
   return ret;
 }
@@ -113,7 +109,7 @@ dap_client_remote_t *dap_udp_client_create( dap_server_t *dap_srv, EPOLL_HANDLE
  * @param host Variable for host address
  * @param host Variable for port
  */
-void dap_udp_client_get_address( dap_client_remote_t *client, unsigned int* host, unsigned short* port )
+void dap_udp_client_get_address( dap_events_socket_t *client, unsigned int* host, unsigned short* port )
 {
   dap_udp_client_t* udp_client = DAP_UDP_CLIENT( client );
   *host = udp_client->host_key >> 32;
@@ -127,7 +123,7 @@ void dap_udp_client_get_address( dap_client_remote_t *client, unsigned int* host
  * @param port Source port
  * @return Pointer to client or NULL if not found
  */
-dap_client_remote_t *dap_udp_client_find( dap_server_t *dap_srv, unsigned long host, unsigned short port )
+dap_events_socket_t *dap_udp_client_find( dap_server_t *dap_srv, unsigned long host, unsigned short port )
 {
   dap_udp_client_t *inh = NULL;
   dap_udp_server_t *udp_server = DAP_UDP_SERVER( dap_srv );
@@ -141,78 +137,14 @@ dap_client_remote_t *dap_udp_client_find( dap_server_t *dap_srv, unsigned long h
   if( inh == NULL )
     return NULL;
   else
-    return inh->client;
-}
-
-/**
- * @brief udp_client_ready_to_read Set ready_to_read flag
- * @param dap_rclient Client structure
- * @param is_ready Flag value
- */
-void dap_udp_client_ready_to_read( dap_client_remote_t *sc, bool is_ready )
-{
-  if( is_ready == (bool)(sc->flags & DAP_SOCK_READY_TO_READ) )
-    return;
-
-  if ( is_ready )
-    sc->flags |= DAP_SOCK_READY_TO_READ;
-  else
-    sc->flags ^= DAP_SOCK_READY_TO_READ;
-
-  int events = EPOLLERR;
-
-  if( sc->flags & DAP_SOCK_READY_TO_READ )
-    events |= EPOLLIN;
-
-  if( sc->flags & DAP_SOCK_READY_TO_WRITE )
-    events |= EPOLLOUT;
-
-  sc->pevent.events = events;
-
-  if( epoll_ctl(sc->efd, EPOLL_CTL_MOD, sc->server->socket_listener, &sc->pevent) != 0 ) {
-    log_it( L_ERROR, "epoll_ctl failed 002" );
-  }
-}
-
-/**
- * @brief udp_client_ready_to_write Set ready_to_write flag
- * @param dap_rclient Client structure
- * @param is_ready Flag value
- */
-void dap_udp_client_ready_to_write( dap_client_remote_t *sc, bool is_ready )
-{
-  if ( is_ready == (bool)(sc->flags & DAP_SOCK_READY_TO_WRITE) )
-    return;
-
-  if ( is_ready )
-    sc->flags |= DAP_SOCK_READY_TO_WRITE;
-  else
-    sc->flags ^= DAP_SOCK_READY_TO_WRITE;
-  int events = EPOLLERR;
-
-  if( sc->flags & DAP_SOCK_READY_TO_READ )
-    events |= EPOLLIN;
-
-  if( sc->flags & DAP_SOCK_READY_TO_WRITE )
-  {
-    dap_udp_server_t *udp_server = DAP_UDP_SERVER(sc->server);
-    pthread_mutex_lock(&udp_server->mutex_on_list);
-    sb_payload_ready = true;
-    pthread_mutex_unlock(&udp_server->mutex_on_list );
-  }
-
-  sc->pevent.events = events;
-
-  if ( epoll_ctl(sc->efd, EPOLL_CTL_MOD, sc->pevent.data.fd, &sc->pevent) != 0 ) {
-    log_it( L_ERROR, "epoll_ctl failed 003" );
-  }
+    return inh->esocket;
 }
 
 /**
  * @brief add_waiting_client Add Client to write queue
  * @param client Client instance
  */
-void add_waiting_client( dap_client_remote_t *dap_rclient )
+void add_waiting_client( dap_events_socket_t *dap_rclient )
 {
     dap_udp_client_t* udp_cl, *tmp;
 
@@ -231,20 +163,20 @@ void add_waiting_client( dap_client_remote_t *dap_rclient )
     pthread_mutex_unlock( &udp_server->mutex_on_list );
 }
 
-size_t dap_udp_client_write( dap_client_remote_t *dap_rclient, const void *data, size_t data_size )
+size_t dap_udp_client_write_unsafe( dap_events_socket_t *dap_rclient, const void *data, size_t data_size )
 {
-    size_t size = dap_client_remote_write( dap_rclient, data, data_size );
+    size_t size = dap_events_socket_write_unsafe( dap_rclient, data, data_size );
     add_waiting_client( dap_rclient );
     return size;
 }
 
-size_t dap_udp_client_write_f( dap_client_remote_t *dap_rclient, const char * a_format, ... )
+size_t dap_udp_client_write_f( dap_events_socket_t *dap_rclient, const char * a_format, ... )
 {
     size_t size = 0;
     va_list va;
 
     va_start( va, a_format );
-    size = dap_client_remote_write_f( dap_rclient, a_format, va );
+    size = dap_events_socket_write_f_unsafe( dap_rclient, a_format, va );
     va_end( va );
 
     add_waiting_client( dap_rclient );
diff --git a/dap-sdk/net/server-udp/dap_udp_server.c b/dap-sdk/net/server-udp/dap_udp_server.c
index 12c1c82120c35e0cb5981dc38c1eca371a45f555..26a0fc39bb2bd9378a6b91011415cfe163468a62 100644
--- a/dap-sdk/net/server-udp/dap_udp_server.c
+++ b/dap-sdk/net/server-udp/dap_udp_server.c
@@ -67,7 +67,7 @@ EPOLL_HANDLE efd_read  = (EPOLL_HANDLE)-1;
 
 //static void write_cb( EPOLL_HANDLE efd, int revents );
 
-int check_close( dap_client_remote_t *client );
+int check_close( dap_events_socket_t *client );
 
 /**
  */
@@ -113,8 +113,8 @@ void dap_udp_server_delete( dap_server_t *sh )
 //  HASH_ITER( hh, udps->hclients, client, tmp )
 //    dap_client_remote_remove( client );
 
-  if ( sh->server_delete_callback )
-    sh->server_delete_callback( sh, NULL );
+  if ( sh->delete_callback )
+    sh->delete_callback( sh, NULL );
 
   if ( sh->_inheritor )
     free( sh->_inheritor );
@@ -179,17 +179,10 @@ static void write_cb( EPOLL_HANDLE efd, int revents, dap_server_t *sh )
         //log_it(L_INFO,"write_cb");
         //pthread_mutex_lock(&udp_client->mutex_on_client);
 
-    dap_client_remote_t *client = udp_client->client;
+    dap_events_socket_t *client = udp_client->esocket;
 
     if( client != NULL && !check_close(client) && (client->flags & DAP_SOCK_READY_TO_WRITE) ) {
-
-      if ( sh->client_write_callback )
-        sh->client_write_callback( client, NULL );
-
       if ( client->buf_out_size > 0 ) {
-
-
-
         struct sockaddr_in addr;
         addr.sin_family = AF_INET;
         dap_udp_client_get_address( client, (unsigned int *)&addr.sin_addr.s_addr, &addr.sin_port );
@@ -211,6 +204,8 @@ static void write_cb( EPOLL_HANDLE efd, int revents, dap_server_t *sh )
         sb_payload_ready = false;
       }
       LL_DELETE( udp->waiting_clients, udp_client );
+      if ( sh->client_callbacks.write_callback )
+        sh->client_callbacks.write_callback( client, NULL );
     }
     else if( client == NULL ) {
       LL_DELETE( udp->waiting_clients, udp_client );
@@ -226,25 +221,26 @@ static void write_cb( EPOLL_HANDLE efd, int revents, dap_server_t *sh )
  * @param client Client structure
  * @return 1 if client deleted, 0 if client is no need to delete
  */
-int check_close( dap_client_remote_t *client )
+int check_close( dap_events_socket_t *client )
 {
-  dap_udp_client_t *client_check, *tmp;
+    dap_udp_client_t *client_check, *tmp;
 
-  if( !(client->flags & DAP_SOCK_SIGNAL_CLOSE) ) return 0;
+    if( !(client->flags & DAP_SOCK_SIGNAL_CLOSE) )
+        return 0;
 
-  dap_udp_client_t *udp_client = DAP_UDP_CLIENT( client );
-  dap_server_t *sh = client->server;
-  dap_udp_server_t *udp_server = DAP_UDP_SERVER( sh );
+    dap_udp_client_t *udp_client = DAP_UDP_CLIENT( client );
+    dap_server_t *sh = client->server;
+    dap_udp_server_t *udp_server = DAP_UDP_SERVER( sh );
 
-  LL_FOREACH_SAFE( udp_server->waiting_clients, client_check, tmp ) {
+    LL_FOREACH_SAFE( udp_server->waiting_clients, client_check, tmp ) {
 
     if ( client_check->host_key == udp_client->host_key )
-      LL_DELETE( udp_server->waiting_clients, client_check );
-  }
+        LL_DELETE( udp_server->waiting_clients, client_check );
+    }
 
-  dap_client_remote_remove( client );
+    dap_events_socket_remove_and_delete_mt(client->worker, client );
 
-  return 1;
+    return 1;
 }
 
 /**
@@ -263,7 +259,7 @@ static void read_cb( EPOLL_HANDLE efd, int revents, dap_server_t *sh )
 
     int32_t bytes = (int32_t) recvfrom( sh->socket_listener, buf, BUFSIZE, 0,(struct sockaddr *) &clientaddr, &clientlen );
 
-    dap_client_remote_t *client = dap_udp_client_find( sh, clientaddr.sin_addr.s_addr, clientaddr.sin_port );
+    dap_events_socket_t *client = dap_udp_client_find( sh, clientaddr.sin_addr.s_addr, clientaddr.sin_port );
 
     if( client != NULL && check_close(client) != 0 )
             return;
@@ -304,8 +300,8 @@ static void read_cb( EPOLL_HANDLE efd, int revents, dap_server_t *sh )
             memcpy( client->buf_in + client->buf_in_size,buf + bytes_processed, bytes_to_transfer );
             client->buf_in_size += bytes_to_transfer;
 
-            if ( sh->client_read_callback )
-                sh->client_read_callback( client, NULL );
+            if ( sh->client_callbacks.read_callback )
+                sh->client_callbacks.read_callback( client, NULL );
 
             bytes_processed += bytes_to_transfer;
             bytes_recieved -= bytes_to_transfer;
diff --git a/dap-sdk/net/server-udp/include/dap_udp_client.h b/dap-sdk/net/server-udp/include/dap_udp_client.h
index 7fc66f14585e359c482b97c201a7fb6bb5beb1ad..f1b3844f5123cae65beb051171dc62c9211e7a1a 100644
--- a/dap-sdk/net/server-udp/include/dap_udp_client.h
+++ b/dap-sdk/net/server-udp/include/dap_udp_client.h
@@ -27,10 +27,10 @@
 #include <sys/queue.h>
 #endif
 
+#include "dap_events_socket.h"
+#include "dap_server.h"
 #include "uthash.h"
 
-#include "dap_client_remote.h"
-
 typedef struct dap_udp_server dap_udp_server_t;
 struct dap_udp_client;
 
@@ -38,7 +38,7 @@ struct dap_udp_client;
 
 typedef struct dap_udp_client {
 
-    dap_client_remote_t *client;
+    dap_events_socket_t *esocket;
     uint64_t host_key; //key contains host address in first 4 bytes and port in last 4 bytes
 
     UT_hash_handle hh;
@@ -52,15 +52,15 @@ typedef struct dap_udp_client {
 
 #define DAP_UDP_CLIENT(a) ((dap_udp_client_t *) (a)->_inheritor)
 
-dap_client_remote_t *dap_udp_client_create( dap_server_t *sh, EPOLL_HANDLE efd, unsigned long host, unsigned short port ); // Create new client and add it to the list
-dap_client_remote_t *dap_udp_client_find( dap_server_t *sh, unsigned long host, unsigned short port ); // Find client by host and port
+dap_events_socket_t *dap_udp_client_create( dap_server_t *sh, EPOLL_HANDLE efd, unsigned long host, unsigned short port ); // Create new client and add it to the list
+dap_events_socket_t *dap_udp_client_find( dap_server_t *sh, unsigned long host, unsigned short port ); // Find client by host and port
 
-void dap_udp_client_ready_to_read( dap_client_remote_t *sc, bool is_ready );
-void dap_udp_client_ready_to_write( dap_client_remote_t *sc, bool is_ready );
+void dap_udp_client_ready_to_read( dap_events_socket_t *sc, bool is_ready );
+void dap_udp_client_ready_to_write( dap_events_socket_t *sc, bool is_ready );
 
-size_t dap_udp_client_write( dap_client_remote_t *sc, const void * data, size_t data_size );
-size_t dap_udp_client_write_f( dap_client_remote_t *a_client, const char * a_format, ... );
+size_t dap_udp_client_write_unsafe( dap_events_socket_t *sc, const void * data, size_t data_size );
+size_t dap_udp_client_write_f( dap_events_socket_t *a_client, const char * a_format, ... );
 
-void add_waiting_client( dap_client_remote_t *client ); // Add client to writing queue
+void add_waiting_client( dap_events_socket_t *client ); // Add client to writing queue
 
-void dap_udp_client_get_address( dap_client_remote_t *client, unsigned int *host, unsigned short *port );
+void dap_udp_client_get_address( dap_events_socket_t *client, unsigned int *host, unsigned short *port );
diff --git a/dap-sdk/net/server-udp/include/dap_udp_server.h b/dap-sdk/net/server-udp/include/dap_udp_server.h
index 2ed9465c012118bf5f4edd3761ae1b92f58fa39a..f1725b4d141d6c6704d00d9f3eab397913a48593 100644
--- a/dap-sdk/net/server-udp/include/dap_udp_server.h
+++ b/dap-sdk/net/server-udp/include/dap_udp_server.h
@@ -36,7 +36,6 @@
 
 #include "dap_udp_client.h"
 #include "dap_server.h"
-#include "dap_client_remote.h"
 
 struct dap_udp_server;
 
diff --git a/dap-sdk/net/server/enc_server/dap_enc_http.c b/dap-sdk/net/server/enc_server/dap_enc_http.c
index c04ddf05f18018e72f717db26160bf6e7580b79a..eabc22b6f6c1fa57f3781f051c181a719824cc5f 100644
--- a/dap-sdk/net/server/enc_server/dap_enc_http.c
+++ b/dap-sdk/net/server/enc_server/dap_enc_http.c
@@ -98,7 +98,7 @@ void enc_http_proc(struct dap_http_simple *cl_st, void * arg)
     log_it(L_DEBUG,"Proc enc http request");
     http_status_code_t * return_code = (http_status_code_t*)arg;
 
-    if(strcmp(cl_st->http->url_path,"gd4y5yh78w42aaagh") == 0 ) {
+    if(strcmp(cl_st->http_client->url_path,"gd4y5yh78w42aaagh") == 0 ) {
 
         uint8_t alice_msg[cl_st->request_size];
         size_t decode_len = dap_enc_base64_decode(cl_st->request, cl_st->request_size, alice_msg, DAP_ENC_DATA_TYPE_B64);
@@ -148,7 +148,7 @@ void enc_http_proc(struct dap_http_simple *cl_st, void * arg)
         *return_code = Http_Status_OK;
 
     } else{
-        log_it(L_ERROR,"Wrong path '%s' in the request to enc_http module",cl_st->http->url_path);
+        log_it(L_ERROR,"Wrong path '%s' in the request to enc_http module",cl_st->http_client->url_path);
         *return_code = Http_Status_NotFound;
     }
 }
@@ -171,16 +171,16 @@ void enc_http_add_proc(struct dap_http * sh, const char * url)
 enc_http_delegate_t *enc_http_request_decode(struct dap_http_simple *a_http_simple)
 {
 
-    dap_enc_key_t * l_key= dap_enc_ks_find_http(a_http_simple->http);
+    dap_enc_key_t * l_key= dap_enc_ks_find_http(a_http_simple->http_client);
     if(l_key){
         enc_http_delegate_t * dg = DAP_NEW_Z(enc_http_delegate_t);
         dg->key=l_key;
-        dg->http=a_http_simple->http;
+        dg->http=a_http_simple->http_client;
        // dg->isOk=true;
 
-        strncpy(dg->action,a_http_simple->http->action,sizeof(dg->action)-1);
-        if(a_http_simple->http->in_cookie[0])
-            dg->cookie=strdup(a_http_simple->http->in_cookie);
+        strncpy(dg->action,a_http_simple->http_client->action,sizeof(dg->action)-1);
+        if(a_http_simple->http_client->in_cookie[0])
+            dg->cookie=strdup(a_http_simple->http_client->in_cookie);
 
         if(a_http_simple->request_size){
             size_t l_dg_request_size_max = a_http_simple->request_size;
@@ -199,20 +199,20 @@ enc_http_delegate_t *enc_http_request_decode(struct dap_http_simple *a_http_simp
         else
             l_enc_type = DAP_ENC_DATA_TYPE_B64;
 
-        size_t l_url_path_size_max = strlen(a_http_simple->http->url_path);
+        size_t l_url_path_size_max = strlen(a_http_simple->http_client->url_path);
         if(l_url_path_size_max){
             dg->url_path= DAP_NEW_SIZE(char,l_url_path_size_max+1);
-            dg->url_path_size=dap_enc_decode(l_key, a_http_simple->http->url_path,l_url_path_size_max,dg->url_path, l_url_path_size_max, l_enc_type);
+            dg->url_path_size=dap_enc_decode(l_key, a_http_simple->http_client->url_path,l_url_path_size_max,dg->url_path, l_url_path_size_max, l_enc_type);
             dg->url_path[dg->url_path_size] = 0;
             log_it(L_DEBUG,"URL path after decode '%s'",dg->url_path );
             // log_it(L_DEBUG,"URL path before decode: '%s' after decode '%s'",cl_st->http->url_path,dg->url_path );
         }
 
-        size_t l_in_query_size=strlen(a_http_simple->http->in_query_string);
+        size_t l_in_query_size=strlen(a_http_simple->http_client->in_query_string);
 
         if(l_in_query_size){
             dg->in_query= DAP_NEW_SIZE(char, l_in_query_size+1);
-            dg->in_query_size=dap_enc_decode(l_key, a_http_simple->http->in_query_string,l_in_query_size,dg->in_query,l_in_query_size,  l_enc_type);
+            dg->in_query_size=dap_enc_decode(l_key, a_http_simple->http_client->in_query_string,l_in_query_size,dg->in_query,l_in_query_size,  l_enc_type);
             dg->in_query[dg->in_query_size] = 0;
             log_it(L_DEBUG,"Query string after decode '%s'",dg->in_query);
         }
@@ -233,7 +233,7 @@ enc_http_delegate_t *enc_http_request_decode(struct dap_http_simple *a_http_simp
  */
 void enc_http_reply_encode(struct dap_http_simple *a_http_simple,enc_http_delegate_t * a_http_delegate)
 {
-    dap_enc_key_t * key = dap_enc_ks_find_http(a_http_simple->http);
+    dap_enc_key_t * key = dap_enc_ks_find_http(a_http_simple->http_client);
     if( key == NULL ) {
         log_it(L_ERROR, "Can't find http key.");
         return;
diff --git a/dap-sdk/net/server/http_server/dap_http.c b/dap-sdk/net/server/http_server/dap_http.c
index 51fe57a57e4b8fbc14e776666dd1ffe1012d2d10..d28c653537df9cd4a78b4d8b1d61fe121fa7eaa6 100644
--- a/dap-sdk/net/server/http_server/dap_http.c
+++ b/dap-sdk/net/server/http_server/dap_http.c
@@ -47,7 +47,7 @@
 
 #include "dap_common.h"
 #include "dap_server.h"
-#include "dap_client_remote.h"
+#include "dap_events_socket.h"
 #include "dap_http.h"
 #include "dap_http_header.h"
 #include "dap_http_client.h"
@@ -99,11 +99,11 @@ int dap_http_new( dap_server_t *sh, const char * server_name )
   shttp->server = sh;
   strncpy( shttp->server_name, server_name, sizeof(shttp->server_name)-1 );
 
-  sh->client_new_callback    = dap_http_client_new;
-  sh->client_delete_callback = dap_http_client_delete;
-  sh->client_read_callback   = dap_http_client_read;
-  sh->client_write_callback  = dap_http_client_write;
-  sh->client_error_callback  = dap_http_client_error;
+  sh->client_callbacks.new_callback    = dap_http_client_new;
+  sh->client_callbacks.delete_callback = dap_http_client_delete;
+  sh->client_callbacks.read_callback   = dap_http_client_read;
+  sh->client_callbacks.write_callback  = dap_http_client_write;
+  sh->client_callbacks.error_callback  = dap_http_client_error;
 
   return 0;
 }
@@ -144,7 +144,7 @@ void dap_http_add_proc(dap_http_t *sh, const char *url_path, void *internal
                       ,dap_http_client_callback_t headers_write_callback
                       ,dap_http_client_callback_t data_read_callback
                       ,dap_http_client_callback_t data_write_callback
-                      ,dap_http_client_callback_t error_callback
+                      ,dap_http_client_callback_error_t error_callback
 
                       )
 {
diff --git a/dap-sdk/net/server/http_server/dap_http_folder.c b/dap-sdk/net/server/http_server/dap_http_folder.c
index e3a34342983862540e54aca62b83964213ed4933..857f39775268a9c2affa017e80cd2bfa22e5c52e 100644
--- a/dap-sdk/net/server/http_server/dap_http_folder.c
+++ b/dap-sdk/net/server/http_server/dap_http_folder.c
@@ -1,310 +1,314 @@
-/*
- Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc
-  All rights reserved.
-
- This file is part of DAP (Deus Applications Prototypes) the open source project
-
-    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
-    it under the terms of the GNU Lesser General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    DAP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU Lesser General Public License for more details.
-
-    You should have received a copy of the GNU Lesser General Public License
-    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <stdio.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <errno.h>
-
-#ifndef _WIN32
-#include <sys/types.h>
-#include <sys/stat.h>
-#else
-#include <winsock2.h>
-#include <windows.h>
-#include <mswsock.h>
-#include <ws2tcpip.h>
-#include <io.h>
-#endif
-
-#include <pthread.h>
-#include <magic.h>
-
-#include "dap_common.h"
-#include "dap_client_remote.h"
-#include "dap_http.h"
-#include "dap_http_client.h"
-#include "dap_http_folder.h"
-#include "http_status_code.h"
-
-typedef struct dap_http_url_proc_folder {
-    char local_path[4096];
-    magic_t mime_detector;
-} dap_http_url_proc_folder_t;
-
-#define URL_PROC_FOLDER(a) ((dap_http_url_proc_folder_t*) (a)->_inhertior )
-
-typedef struct dap_http_file{
-    FILE * fd;
-    size_t position;
-    char local_path[4096+2048+1];
-    dap_http_client_t *client;
-} dap_http_file_t;
-
-#define DAP_HTTP_FILE(a) ((dap_http_file_t*) (a)->_inheritor )
-
-void dap_http_folder_headers_read( dap_http_client_t *cl_ht, void *arg );
-void dap_http_folder_headers_write( dap_http_client_t *cl_ht, void *arg );
-void dap_http_folder_data_read( dap_http_client_t *cl_ht, void *arg );
-void dap_http_folder_data_write( dap_http_client_t *cl_ht, void *arg );
-
-#define LOG_TAG "dap_http_folder"
-
-int dap_http_folder_init( )
-{
-    return 0;
-}
-
-void dap_http_folder_deinit( )
-{
-
-}
-
-
-/**
- * @brief dap_http_folder_add Add folder for reading to the HTTP server
- * @param sh Server instance
- * @param url_path Beginning part of the URL
- * @param local_path Local path that will be read for
- */
-int dap_http_folder_add( dap_http_t *sh, const char *url_path, const char *local_path )
-{
-  if ( !local_path ) {
-    log_it( L_ERROR, "Directory Path parameter is empty!" );
-    return -11;
-  }
-
-  log_it( L_DEBUG, "Checking url path %s", local_path );
-
-#ifndef _WIN32
-  DIR *dirptr = opendir( local_path );
-  if ( dirptr == NULL ) {
-    log_it( L_ERROR, "Directory Not Found!" );
-    return -11;
-  }
-  else {
-    closedir( dirptr );
-  }
-#else // WIN32
-
-  DWORD attr = GetFileAttributesA( local_path );
-  if ( attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY) ) {
-    log_it( L_ERROR, "Directory Not Found!" );
-    return -11;
-  }
-
-#endif
-
-  log_it( L_NOTICE, "File service for %s => %s ", url_path, local_path );
-
-  dap_http_url_proc_folder_t *up_folder = (dap_http_url_proc_folder_t *)calloc( 1, sizeof(dap_http_url_proc_folder_t) );
-  strncpy( up_folder->local_path, local_path, sizeof(up_folder->local_path)-1 );
-
-  up_folder->mime_detector = magic_open( MAGIC_SYMLINK | MAGIC_MIME | MAGIC_PRESERVE_ATIME );
-
-  if ( up_folder->mime_detector == NULL) {
-    log_it( L_CRITICAL,"Can't init MIME detection library" );
-    free( up_folder );
-    return -1;
-  }
-
-#ifndef _WIN32
-  if( 0 != magic_load( up_folder->mime_detector, NULL) ) {
-#else
-  if( 0 != magic_load( up_folder->mime_detector, "data.mag" )  ) {
-#endif
-
-    log_it( L_CRITICAL, "Can't load MIME magic detection database" );
-    magic_close( up_folder->mime_detector );
-    free( up_folder );
-    return -2;
-  }
-
-  dap_http_add_proc(  sh, 
-                      url_path, 
-                      up_folder, 
-                      NULL,
-                      NULL,
-                      dap_http_folder_headers_read,
-                      dap_http_folder_headers_write,
-                      dap_http_folder_data_read,
-                      dap_http_folder_data_write,
-                      NULL );
-    return 0;
-}
-
-/**
- * @brief dap_http_folder_headers_read Signal thats HTTP client is now going to output the data
- * @param cl_ht HTTP client instance
- * @param arg Not used
- */
-void dap_http_folder_headers_read(dap_http_client_t * cl_ht, void * arg)
-{
-    (void) arg;
-    cl_ht->state_write=DAP_HTTP_CLIENT_STATE_START;
-    cl_ht->state_read=cl_ht->keep_alive?DAP_HTTP_CLIENT_STATE_START:DAP_HTTP_CLIENT_STATE_NONE;
-    dap_client_remote_ready_to_write(cl_ht->client,true);
-    dap_client_remote_ready_to_read(cl_ht->client, cl_ht->keep_alive);
-}
-
-#ifdef _WIN32
-time_t FileTimeToUnixTime( FILETIME ft )
-{
-  ULARGE_INTEGER ull;
- 
-  ull.LowPart = ft.dwLowDateTime;
-  ull.HighPart = ft.dwHighDateTime;
- 
-  return ull.QuadPart / 10000000ULL - 11644473600ULL;
-}
-#endif
-
-/**
- * @brief dap_http_folder_headers Prepare response HTTP headers for file folder request
- * @param cl_ht HTTP client instane
- * @param arg Not used
- */
-void dap_http_folder_headers_write( dap_http_client_t *cl_ht, void * arg)
-{
-  (void) arg;
-  // Get specific data for folder URL processor
-  dap_http_url_proc_folder_t * up_folder=(dap_http_url_proc_folder_t*) cl_ht->proc->_inheritor;
-
-  // Init specific file response data for HTTP client instance
-  cl_ht->_inheritor=DAP_NEW_Z(dap_http_file_t);
-
-  dap_http_file_t* cl_ht_file=DAP_HTTP_FILE(cl_ht);
-  cl_ht_file->client=cl_ht;
-
-  // Produce local path for file to open
-  dap_snprintf(cl_ht_file->local_path,sizeof(cl_ht_file->local_path),"%s/%s", up_folder->local_path, cl_ht->url_path );
-  log_it(L_DEBUG, "Check %s file", cl_ht_file->local_path);
-
-#ifndef _WIN32
-
-  struct stat file_stat;
-
-  if ( stat(cl_ht_file->local_path, &file_stat) != 0 ) 
-    goto err;
-
-  cl_ht->out_last_modified  = file_stat.st_mtime;
-  cl_ht->out_content_length = file_stat.st_size;
-
-#else
-
-  FILETIME CreationTime;
-  FILETIME LastAccessTime;
-  FILETIME LastWriteTime;
-
-  HANDLE fileh = CreateFileA( cl_ht_file->local_path, 
-                              GENERIC_READ, 
-                              FILE_SHARE_READ, 
-                              NULL, 
-                              OPEN_EXISTING, 
-                              FILE_ATTRIBUTE_ARCHIVE, 
-                              NULL 
-                 );
-
-  if ( fileh == INVALID_HANDLE_VALUE ) 
-    goto err;
-
-  GetFileTime( fileh,
-               &CreationTime,
-               &LastAccessTime,
-               &LastWriteTime );
-
-  cl_ht->out_last_modified  = FileTimeToUnixTime( LastWriteTime );
-  cl_ht->out_content_length = GetFileSize( fileh, NULL );
-
-  CloseHandle( fileh );
-
-#endif
-
-  cl_ht_file->fd = fopen( cl_ht_file->local_path, "rb" );
-
-  if ( cl_ht_file->fd == NULL ) {
-    log_it(L_ERROR, "Can't open %s: %s",cl_ht_file->local_path,strerror(errno));
-    cl_ht->reply_status_code = Http_Status_NotFound;
-    strncpy( cl_ht->reply_reason_phrase, "Not Found", sizeof(cl_ht->reply_reason_phrase)-1 );
-  }
-  else {
-    cl_ht->reply_status_code = Http_Status_OK;
-    strncpy( cl_ht->reply_reason_phrase,"OK",sizeof(cl_ht->reply_reason_phrase)-1 );
-
-    const char *mime_type = magic_file( up_folder->mime_detector, cl_ht_file->local_path );
-    if( mime_type ) {
-      strncpy(cl_ht->out_content_type,mime_type,sizeof(cl_ht->out_content_type)-1);
-      log_it( L_DEBUG, "MIME type detected: '%s'", mime_type );
-    }
-    else {
-      cl_ht->reply_status_code=Http_Status_NotFound;
-      cl_ht->client->flags |= DAP_SOCK_SIGNAL_CLOSE;
-      log_it(L_WARNING,"Can't detect MIME type of %s file: %s",cl_ht_file->local_path,magic_error(up_folder->mime_detector));
-    }
-  }
-
-  return;
-
-err:
-
-  log_it( L_WARNING, "Can't get file info: %s", strerror(errno) );
-  cl_ht->reply_status_code = 404;
-  strncpy( cl_ht->reply_reason_phrase, "Not Found", sizeof(cl_ht->reply_reason_phrase)-1 );
-
-  return;
-}
-
-/**
- * @brief dap_http_folder_read HTTP client callback for reading function for the folder processing
- * @param cl_ht HTTP client instance
- * @param arg Pointer to int with return bytes number
- */
-void dap_http_folder_data_read(dap_http_client_t * cl_ht, void * arg)
-{
-    int * bytes_return = (int*) arg; // Return number of read bytes
-    //Do nothing
-    *bytes_return=cl_ht->client->buf_in_size;
-}
-
-/**
- * @brief dap_http_folder_write HTTP client callback for writting function for the folder processing
- * @param cl_ht HTTP client instance
- * @param arg
- */
-void dap_http_folder_data_write(dap_http_client_t * cl_ht, void * arg)
-{
-    (void) arg;
-    dap_http_file_t * cl_ht_file= DAP_HTTP_FILE(cl_ht);
-    cl_ht->client->buf_out_size=fread(cl_ht->client->buf_out,1,sizeof(cl_ht->client->buf_out),cl_ht_file->fd);
-    cl_ht_file->position+=cl_ht->client->buf_out_size;
-
-    if(feof(cl_ht_file->fd)!=0){
-        log_it(L_INFO, "All the file %s is sent out",cl_ht_file->local_path);
-        //strncat(cl_ht->client->buf_out+cl_ht->client->buf_out_size,"\r\n",sizeof(cl_ht->client->buf_out));
-        fclose(cl_ht_file->fd);
-        dap_client_remote_ready_to_write(cl_ht->client,false);
-
-        if ( !cl_ht->keep_alive )
-            cl_ht->client->flags |= DAP_SOCK_SIGNAL_CLOSE;
-
-        cl_ht->state_write=DAP_HTTP_CLIENT_STATE_NONE;
-    }
-}
-
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Ltd.   https://demlabs.net
+ * Copyright  (c) 2017
+ * All rights reserved.
+
+ This file is part of DAP SDK the open source project
+
+    DAP SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DAP SDK is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <stdio.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+
+#ifndef _WIN32
+#include <sys/types.h>
+#include <sys/stat.h>
+#else
+#include <winsock2.h>
+#include <windows.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <io.h>
+#endif
+
+#include <pthread.h>
+#include <magic.h>
+
+#include "dap_common.h"
+#include "dap_events_socket.h"
+#include "dap_http.h"
+#include "dap_http_client.h"
+#include "dap_http_folder.h"
+#include "http_status_code.h"
+
+typedef struct dap_http_url_proc_folder {
+    char local_path[4096];
+    magic_t mime_detector;
+} dap_http_url_proc_folder_t;
+
+#define URL_PROC_FOLDER(a) ((dap_http_url_proc_folder_t*) (a)->_inhertior )
+
+typedef struct dap_http_file{
+    FILE * fd;
+    size_t position;
+    char local_path[4096+2048+1];
+    dap_http_client_t *client;
+} dap_http_file_t;
+
+#define DAP_HTTP_FILE(a) ((dap_http_file_t*) (a)->_inheritor )
+
+void dap_http_folder_headers_read( dap_http_client_t *cl_ht, void *arg );
+void dap_http_folder_headers_write( dap_http_client_t *cl_ht, void *arg );
+void dap_http_folder_data_read( dap_http_client_t *cl_ht, void *arg );
+void dap_http_folder_data_write( dap_http_client_t *cl_ht, void *arg );
+
+#define LOG_TAG "dap_http_folder"
+
+int dap_http_folder_init( )
+{
+    return 0;
+}
+
+void dap_http_folder_deinit( )
+{
+
+}
+
+
+/**
+ * @brief dap_http_folder_add Add folder for reading to the HTTP server
+ * @param sh Server instance
+ * @param url_path Beginning part of the URL
+ * @param local_path Local path that will be read for
+ */
+int dap_http_folder_add( dap_http_t *sh, const char *url_path, const char *local_path )
+{
+  if ( !local_path ) {
+    log_it( L_ERROR, "Directory Path parameter is empty!" );
+    return -11;
+  }
+
+  log_it( L_DEBUG, "Checking url path %s", local_path );
+
+#ifndef _WIN32
+  DIR *dirptr = opendir( local_path );
+  if ( dirptr == NULL ) {
+    log_it( L_ERROR, "Directory Not Found!" );
+    return -11;
+  }
+  else {
+    closedir( dirptr );
+  }
+#else // WIN32
+
+  DWORD attr = GetFileAttributesA( local_path );
+  if ( attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY) ) {
+    log_it( L_ERROR, "Directory Not Found!" );
+    return -11;
+  }
+
+#endif
+
+  log_it( L_NOTICE, "File service for %s => %s ", url_path, local_path );
+
+  dap_http_url_proc_folder_t *up_folder = (dap_http_url_proc_folder_t *)calloc( 1, sizeof(dap_http_url_proc_folder_t) );
+  strncpy( up_folder->local_path, local_path, sizeof(up_folder->local_path)-1 );
+
+  up_folder->mime_detector = magic_open( MAGIC_SYMLINK | MAGIC_MIME | MAGIC_PRESERVE_ATIME );
+
+  if ( up_folder->mime_detector == NULL) {
+    log_it( L_CRITICAL,"Can't init MIME detection library" );
+    free( up_folder );
+    return -1;
+  }
+
+#ifndef _WIN32
+  if( 0 != magic_load( up_folder->mime_detector, NULL) ) {
+#else
+  if( 0 != magic_load( up_folder->mime_detector, "data.mag" )  ) {
+#endif
+
+    log_it( L_CRITICAL, "Can't load MIME magic detection database" );
+    magic_close( up_folder->mime_detector );
+    free( up_folder );
+    return -2;
+  }
+
+  dap_http_add_proc(  sh, 
+                      url_path, 
+                      up_folder, 
+                      NULL,
+                      NULL,
+                      dap_http_folder_headers_read,
+                      dap_http_folder_headers_write,
+                      dap_http_folder_data_read,
+                      dap_http_folder_data_write,
+                      NULL );
+    return 0;
+}
+
+/**
+ * @brief dap_http_folder_headers_read Signal thats HTTP client is now going to output the data
+ * @param cl_ht HTTP client instance
+ * @param arg Not used
+ */
+void dap_http_folder_headers_read(dap_http_client_t * cl_ht, void * arg)
+{
+    (void) arg;
+    cl_ht->state_write=DAP_HTTP_CLIENT_STATE_START;
+    cl_ht->state_read=cl_ht->keep_alive?DAP_HTTP_CLIENT_STATE_START:DAP_HTTP_CLIENT_STATE_NONE;
+
+    dap_events_socket_set_writable_unsafe(cl_ht->esocket,true);
+    dap_events_socket_set_readable_unsafe(cl_ht->esocket, cl_ht->keep_alive);
+}
+
+#ifdef _WIN32
+time_t FileTimeToUnixTime( FILETIME ft )
+{
+  ULARGE_INTEGER ull;
+ 
+  ull.LowPart = ft.dwLowDateTime;
+  ull.HighPart = ft.dwHighDateTime;
+ 
+  return ull.QuadPart / 10000000ULL - 11644473600ULL;
+}
+#endif
+
+/**
+ * @brief dap_http_folder_headers Prepare response HTTP headers for file folder request
+ * @param cl_ht HTTP client instane
+ * @param arg Not used
+ */
+void dap_http_folder_headers_write( dap_http_client_t *cl_ht, void * arg)
+{
+  (void) arg;
+  // Get specific data for folder URL processor
+  dap_http_url_proc_folder_t * up_folder=(dap_http_url_proc_folder_t*) cl_ht->proc->_inheritor;
+
+  // Init specific file response data for HTTP client instance
+  cl_ht->_inheritor=DAP_NEW_Z(dap_http_file_t);
+
+  dap_http_file_t* cl_ht_file=DAP_HTTP_FILE(cl_ht);
+  cl_ht_file->client=cl_ht;
+
+  // Produce local path for file to open
+  dap_snprintf(cl_ht_file->local_path,sizeof(cl_ht_file->local_path),"%s/%s", up_folder->local_path, cl_ht->url_path );
+  log_it(L_DEBUG, "Check %s file", cl_ht_file->local_path);
+
+#ifndef _WIN32
+
+  struct stat file_stat;
+
+  if ( stat(cl_ht_file->local_path, &file_stat) != 0 ) 
+    goto err;
+
+  cl_ht->out_last_modified  = file_stat.st_mtime;
+  cl_ht->out_content_length = file_stat.st_size;
+
+#else
+
+  FILETIME CreationTime;
+  FILETIME LastAccessTime;
+  FILETIME LastWriteTime;
+
+  HANDLE fileh = CreateFileA( cl_ht_file->local_path, 
+                              GENERIC_READ, 
+                              FILE_SHARE_READ, 
+                              NULL, 
+                              OPEN_EXISTING, 
+                              FILE_ATTRIBUTE_ARCHIVE, 
+                              NULL 
+                 );
+
+  if ( fileh == INVALID_HANDLE_VALUE ) 
+    goto err;
+
+  GetFileTime( fileh,
+               &CreationTime,
+               &LastAccessTime,
+               &LastWriteTime );
+
+  cl_ht->out_last_modified  = FileTimeToUnixTime( LastWriteTime );
+  cl_ht->out_content_length = GetFileSize( fileh, NULL );
+
+  CloseHandle( fileh );
+
+#endif
+
+  cl_ht_file->fd = fopen( cl_ht_file->local_path, "rb" );
+
+  if ( cl_ht_file->fd == NULL ) {
+    log_it(L_ERROR, "Can't open %s: %s",cl_ht_file->local_path,strerror(errno));
+    cl_ht->reply_status_code = Http_Status_NotFound;
+    strncpy( cl_ht->reply_reason_phrase, "Not Found", sizeof(cl_ht->reply_reason_phrase)-1 );
+  }
+  else {
+    cl_ht->reply_status_code = Http_Status_OK;
+    strncpy( cl_ht->reply_reason_phrase,"OK",sizeof(cl_ht->reply_reason_phrase)-1 );
+
+    const char *mime_type = magic_file( up_folder->mime_detector, cl_ht_file->local_path );
+    if( mime_type ) {
+      strncpy(cl_ht->out_content_type,mime_type,sizeof(cl_ht->out_content_type)-1);
+      log_it( L_DEBUG, "MIME type detected: '%s'", mime_type );
+    }
+    else {
+      cl_ht->reply_status_code=Http_Status_NotFound;
+      cl_ht->esocket->flags |= DAP_SOCK_SIGNAL_CLOSE;
+      log_it(L_WARNING,"Can't detect MIME type of %s file: %s",cl_ht_file->local_path,magic_error(up_folder->mime_detector));
+    }
+  }
+
+  return;
+
+err:
+
+  log_it( L_WARNING, "Can't get file info: %s", strerror(errno) );
+  cl_ht->reply_status_code = 404;
+  strncpy( cl_ht->reply_reason_phrase, "Not Found", sizeof(cl_ht->reply_reason_phrase)-1 );
+
+  return;
+}
+
+/**
+ * @brief dap_http_folder_read HTTP client callback for reading function for the folder processing
+ * @param cl_ht HTTP client instance
+ * @param arg Pointer to int with return bytes number
+ */
+void dap_http_folder_data_read(dap_http_client_t * cl_ht, void * arg)
+{
+    int * bytes_return = (int*) arg; // Return number of read bytes
+    //Do nothing
+    *bytes_return=cl_ht->esocket->buf_in_size;
+}
+
+/**
+ * @brief dap_http_folder_write HTTP client callback for writting function for the folder processing
+ * @param cl_ht HTTP client instance
+ * @param arg
+ */
+void dap_http_folder_data_write(dap_http_client_t * cl_ht, void * arg)
+{
+    (void) arg;
+    dap_http_file_t * cl_ht_file= DAP_HTTP_FILE(cl_ht);
+    cl_ht->esocket->buf_out_size=fread(cl_ht->esocket->buf_out,1,sizeof(cl_ht->esocket->buf_out),cl_ht_file->fd);
+    cl_ht_file->position+=cl_ht->esocket->buf_out_size;
+    dap_events_socket_set_writable_unsafe(cl_ht->esocket, true);
+
+    if(feof(cl_ht_file->fd)!=0){
+        log_it(L_INFO, "All the file %s is sent out",cl_ht_file->local_path);
+        //strncat(cl_ht->client->buf_out+cl_ht->client->buf_out_size,"\r\n",sizeof(cl_ht->client->buf_out));
+        fclose(cl_ht_file->fd);
+        dap_events_socket_set_writable_unsafe(cl_ht->esocket,false);
+
+        if ( !cl_ht->keep_alive )
+            cl_ht->esocket->flags |= DAP_SOCK_SIGNAL_CLOSE;
+
+        cl_ht->state_write=DAP_HTTP_CLIENT_STATE_NONE;
+    }
+}
+
diff --git a/dap-sdk/net/server/http_server/dap_http_simple.c b/dap-sdk/net/server/http_server/dap_http_simple.c
index b8beddd0981899b1c3e943d9ac55d9ef681a22a5..9428a6f00d77ed74601667fa6a974debb43086f8 100644
--- a/dap-sdk/net/server/http_server/dap_http_simple.c
+++ b/dap-sdk/net/server/http_server/dap_http_simple.c
@@ -45,6 +45,9 @@ See more details here <http://www.gnu.org/licenses/>.
 
 #include "dap_common.h"
 #include "dap_config.h"
+#include "dap_worker.h"
+#include "dap_events.h"
+#include "dap_proc_thread.h"
 #include "dap_http.h"
 #include "dap_http_client.h"
 #include "dap_http_simple.h"
@@ -59,16 +62,10 @@ See more details here <http://www.gnu.org/licenses/>.
 
 #define LOG_TAG "dap_http_simple"
 
-static void s_headers_read( dap_http_client_t *cl_ht, void *arg );
-static void s_data_write( dap_http_client_t *a_http_client, void *a_arg );
-static void s_data_read( dap_http_client_t * cl_ht, void *arg );
-void *dap_http_simple_proc( dap_http_simple_t * cl_sh );
-
-static void *loop_http_simple_proc( void *arg );
-
-static void async_control_proc( void );
-static void queue_http_request_put( dap_http_simple_t *cl_sh );
-
+static void s_http_client_headers_read( dap_http_client_t *cl_ht, void *arg );
+static void s_http_client_data_read( dap_http_client_t * cl_ht, void *arg );
+static void s_http_client_data_write( dap_http_client_t * a_http_client, void *a_arg );
+static bool s_proc_queue_callback(dap_proc_thread_t * a_thread, void *a_arg );
 
 typedef struct dap_http_simple_url_proc {
 
@@ -99,91 +96,16 @@ static bool is_unknown_user_agents_pass = false;
 
 #define DAP_HTTP_SIMPLE_URL_PROC(a) ((dap_http_simple_url_proc_t*) (a)->_inheritor)
 
-///static struct ev_loop* http_simple_loop;
-///static ev_async async_watcher_http_simple;
-
-static pthread_mutex_t mutex_on_queue_http_response = PTHREAD_MUTEX_INITIALIZER;
-static pthread_t http_simple_loop_thread;
-static bool bSimpleLoopThreadQuitSignal = false;
-
-static dap_http_simple_t **s_requests = NULL;
-static dap_http_simple_t **s_requestsproc = NULL;
-
-static uint32_t s_requests_count = 0;
-static uint32_t s_requestsproc_count = 0;
-
 static void _free_user_agents_list( void );
 
 int dap_http_simple_module_init( )
 {
-  s_requests = DAP_NEW_Z_SIZE(dap_http_simple_t*, sizeof(dap_http_simple_t *) * DAP_HTTP_SIMPLE_REQUEST_MAX * 2 );
-  if ( !s_requests ) {
-
-    log_it( L_ERROR, "Out of memory" );
-    return -1;
-  }
-
-  s_requestsproc = s_requests + DAP_HTTP_SIMPLE_REQUEST_MAX;
-  s_requests_count = 0;
-
-  bSimpleLoopThreadQuitSignal = false;
-  pthread_create( &http_simple_loop_thread, NULL, loop_http_simple_proc, NULL );
-
-  return 0;
+    return 0;
 }
 
 void dap_http_simple_module_deinit( void )
 {
-  bSimpleLoopThreadQuitSignal = true;
-
-  pthread_mutex_destroy( &mutex_on_queue_http_response );
-  pthread_join( http_simple_loop_thread, NULL );
-
-  _free_user_agents_list( );
-
-  if ( s_requests ) {
-    free( s_requests );
-    s_requests = NULL;
-  } 
-}
-
-//#define SIMPLE_LOOP_SLEEP   25 // ms
-#define SIMPLE_LOOP_SLEEP   50 // ms
-
-static struct timespec simple_loop_sleep = { 0, SIMPLE_LOOP_SLEEP * 1000 * 1000 };
-
-static void *loop_http_simple_proc( void *arg )
-{
-  log_it( L_NOTICE, "Start loop http simple thread" );
-
-  do {
-
-    pthread_mutex_lock( &mutex_on_queue_http_response );
-    if ( s_requests_count ) {
-
-      s_requestsproc_count = s_requests_count;
-      s_requests_count = 0;
-      memcpy( s_requestsproc, s_requests, sizeof(void *) * s_requestsproc_count );
-      pthread_mutex_unlock( &mutex_on_queue_http_response );
-
-      for ( uint32_t i = 0; i < s_requestsproc_count; ++ i ) {
-        dap_http_simple_proc( s_requestsproc[i] );
-        s_requestsproc[i]->http->client->no_close = false;
-//        free( s_requestsproc[i] ); // ???
-      }
-    }
-    else {
-      pthread_mutex_unlock( &mutex_on_queue_http_response );
-      #ifndef _WIN32
-        nanosleep( &simple_loop_sleep, NULL );
-      #else
-        Sleep( SIMPLE_LOOP_SLEEP );
-      #endif
-    }
-
-  } while( !bSimpleLoopThreadQuitSignal );
-
-  return NULL;
+    _free_user_agents_list( );
 }
 
 /**
@@ -204,8 +126,8 @@ void dap_http_simple_proc_add( dap_http_t *a_http, const char *a_url_path, size_
                      l_url_proc, // Internal structure
                      NULL, // Contrustor
                      NULL, //  Destructor
-                     s_headers_read, NULL, // Headers read, write
-                     s_data_read, s_data_write, // Data read, write
+                     s_http_client_headers_read, NULL, // Headers read, write
+                     s_http_client_data_read, s_http_client_data_write, // Data read, write
                      NULL); // errror
 }
 
@@ -253,6 +175,7 @@ END:
   return result;
 }
 
+
 bool dap_http_simple_set_supported_user_agents( const char *user_agents, ... )
 {
   va_list argptr;
@@ -305,14 +228,10 @@ inline static bool _is_supported_user_agents_list_setted()
 inline static void _set_only_write_http_client_state(dap_http_client_t* http_client)
 {
 //  log_it(L_DEBUG,"_set_only_write_http_client_state");
-//  Sleep(300);
-
-  dap_client_remote_ready_to_read(http_client->client,false);
-//  http_client->state_write=DAP_HTTP_CLIENT_STATE_NONE;
 
   http_client->state_write=DAP_HTTP_CLIENT_STATE_START;
-  dap_client_remote_ready_to_write(http_client->client,true);
-//  http_client->state_write=DAP_HTTP_CLIENT_STATE_START;
+  dap_events_socket_set_writable_unsafe(http_client->esocket,true);
+  dap_events_socket_set_readable_unsafe(http_client->esocket, false);
 }
 
 static void _copy_reply_and_mime_to_response( dap_http_simple_t *cl_sh )
@@ -326,12 +245,12 @@ static void _copy_reply_and_mime_to_response( dap_http_simple_t *cl_sh )
     return;
   }
 
-  cl_sh->http->out_content_length = cl_sh->reply_size;
-  strcpy( cl_sh->http->out_content_type, cl_sh->reply_mime );
+  cl_sh->http_client->out_content_length = cl_sh->reply_size;
+  strcpy( cl_sh->http_client->out_content_type, cl_sh->reply_mime );
   return;
 }
 
-inline static void _write_response_bad_request( dap_http_simple_t * cl_sh,
+inline static void _write_response_bad_request( dap_http_simple_t * a_http_simple,
                                                const char* error_msg )
 {
 //  log_it(L_DEBUG,"_write_response_bad_request");
@@ -341,75 +260,84 @@ inline static void _write_response_bad_request( dap_http_simple_t * cl_sh,
   json_object_object_add( jobj, "error", json_object_new_string(error_msg) );
 
   log_it( L_DEBUG, "error message %s",  json_object_to_json_string(jobj) );
-  cl_sh->http->reply_status_code = Http_Status_BadRequest;
+  a_http_simple->http_client->reply_status_code = Http_Status_BadRequest;
 
   const char* json_str = json_object_to_json_string( jobj );
-  dap_http_simple_reply(cl_sh, (void*) json_str,
+  dap_http_simple_reply(a_http_simple, (void*) json_str,
                           (size_t) strlen(json_str) );
 
-  strcpy( cl_sh->reply_mime, "application/json" );
+  strcpy( a_http_simple->reply_mime, "application/json" );
 
-  _copy_reply_and_mime_to_response( cl_sh );
+  _copy_reply_and_mime_to_response( a_http_simple );
 
   json_object_put( jobj ); // free obj
-  _set_only_write_http_client_state( cl_sh->http );
 }
 
 /**
  * @brief dap_http_simple_proc Execute procession callback and switch to write state
  * @param cl_sh HTTP simple client instance
  */
-void* dap_http_simple_proc( dap_http_simple_t *cl_sh )
+bool s_proc_queue_callback(dap_proc_thread_t * a_thread, void * a_arg )
 {
-//  log_it(L_DEBUG, "dap http simple proc");
+    (void) a_thread;
+     dap_http_simple_t *l_http_simple = (dap_http_simple_t*) a_arg;
+    log_it(L_DEBUG, "dap http simple proc");
 //  Sleep(300);
 
     http_status_code_t return_code = (http_status_code_t)0;
 
     if(_is_supported_user_agents_list_setted() == true) {
-        dap_http_header_t *header = dap_http_header_find(cl_sh->http->in_headers, "User-Agent");
+        dap_http_header_t *header = dap_http_header_find(l_http_simple->http_client->in_headers, "User-Agent");
         if(header == NULL && is_unknown_user_agents_pass == false) {
-            const char* error_msg = "Not found User-Agent HTTP header";
-            _write_response_bad_request(cl_sh, error_msg);
-            return NULL;
+            const char error_msg[] = "Not found User-Agent HTTP header";
+            _write_response_bad_request(l_http_simple, error_msg);
+            _set_only_write_http_client_state( l_http_simple->http_client);
+            dap_events_socket_assign_on_worker_mt(l_http_simple->esocket, l_http_simple->worker);
+            return true;
         }
 
         if(_is_user_agent_supported(header->value) == false) {
             log_it(L_DEBUG, "Not supported user agent in request: %s", header->value);
             const char* error_msg = "User-Agent version not supported. Update your software";
-            _write_response_bad_request(cl_sh, error_msg);
-            return NULL;
+            _write_response_bad_request(l_http_simple, error_msg);
+            _set_only_write_http_client_state( l_http_simple->http_client);
+            dap_events_socket_assign_on_worker_mt(l_http_simple->esocket, l_http_simple->worker);
+            return true;
         }
     }
 
-    DAP_HTTP_SIMPLE_URL_PROC(cl_sh->http->proc)->proc_callback(cl_sh,&return_code);
+    DAP_HTTP_SIMPLE_URL_PROC(l_http_simple->http_client->proc)->proc_callback(l_http_simple,&return_code);
 
     if(return_code) {
         log_it(L_DEBUG, "Request was processed well return_code=%d", return_code);
-        cl_sh->http->reply_status_code = (uint16_t)return_code;
-        _copy_reply_and_mime_to_response(cl_sh);
+        l_http_simple->http_client->reply_status_code = (uint16_t)return_code;
+        _copy_reply_and_mime_to_response(l_http_simple);
     } else {
         log_it(L_ERROR, "Request was processed with ERROR");
-        cl_sh->http->reply_status_code = Http_Status_InternalServerError;
+        l_http_simple->http_client->reply_status_code = Http_Status_InternalServerError;
     }
 
-    _set_only_write_http_client_state(cl_sh->http);
-    return NULL;
+    _set_only_write_http_client_state( l_http_simple->http_client);
+    dap_events_socket_assign_on_worker_mt(l_http_simple->esocket, l_http_simple->worker);
+
+    return true;
 }
 
 
-static void s_headers_read( dap_http_client_t *a_http_client, void *a_arg )
+static void s_http_client_headers_read( dap_http_client_t *a_http_client, void *a_arg )
 {
     (void) a_arg;
 
     a_http_client->_inheritor = DAP_NEW_Z( dap_http_simple_t );
-
+    dap_http_simple_t * l_http_simple = DAP_HTTP_SIMPLE(a_http_client);
     //  log_it(L_DEBUG,"dap_http_simple_headers_read");
     //  Sleep(300);
 
-    DAP_HTTP_SIMPLE(a_http_client)->http = a_http_client;
-    DAP_HTTP_SIMPLE(a_http_client)->reply_size_max = DAP_HTTP_SIMPLE_URL_PROC( a_http_client->proc )->reply_size_max;
-    DAP_HTTP_SIMPLE(a_http_client)->reply_byte = DAP_NEW_Z_SIZE(uint8_t, DAP_HTTP_SIMPLE(a_http_client)->reply_size_max );
+    l_http_simple->esocket = a_http_client->esocket;
+    l_http_simple->http_client = a_http_client;
+    l_http_simple->worker = a_http_client->esocket->worker;
+    l_http_simple->reply_size_max = DAP_HTTP_SIMPLE_URL_PROC( a_http_client->proc )->reply_size_max;
+    l_http_simple->reply_byte = DAP_NEW_Z_SIZE(uint8_t, DAP_HTTP_SIMPLE(a_http_client)->reply_size_max );
 
     if( a_http_client->in_content_length ) {
         // dbg if( a_http_client->in_content_length < 3){
@@ -425,21 +353,51 @@ static void s_headers_read( dap_http_client_t *a_http_client, void *a_arg )
             log_it(L_ERROR, "Not defined content-length %u in request", a_http_client->in_content_length);
     } else {
         log_it( L_DEBUG, "No data section, execution proc callback" );
-        queue_http_request_put( DAP_HTTP_SIMPLE(a_http_client) );
+        dap_events_socket_remove_from_worker_unsafe(a_http_client->esocket,a_http_client->esocket->worker);
+        dap_proc_queue_add_callback( l_http_simple->worker->proc_queue, s_proc_queue_callback, l_http_simple);
+
     }
 }
 
-void s_data_read( dap_http_client_t *a_http_client, void * a_arg )
+static void s_http_client_data_write( dap_http_client_t * a_http_client, void *a_arg )
+{
+    (void) a_arg;
+    dap_http_simple_t *l_http_simple = DAP_HTTP_SIMPLE( a_http_client );
+
+    //  log_it(L_DEBUG,"dap_http_simple_data_write");
+    //  Sleep(300);
+
+    if ( !l_http_simple->reply ) {
+        a_http_client->esocket->flags |= DAP_SOCK_SIGNAL_CLOSE;
+        log_it( L_WARNING, "No reply to write, close connection" );
+        return;
+    }
+
+    l_http_simple->reply_sent += dap_events_socket_write_unsafe( a_http_client->esocket,
+                                              l_http_simple->reply_byte + l_http_simple->reply_sent,
+                                              a_http_client->out_content_length - l_http_simple->reply_sent );
+    dap_events_socket_set_writable_unsafe(a_http_client->esocket, true);
+
+    if ( l_http_simple->reply_sent >= a_http_client->out_content_length ) {
+        log_it(L_INFO, "All the reply (%u) is sent out", a_http_client->out_content_length );
+        //cl_ht->client->signal_close=cl_ht->keep_alive;
+        a_http_client->esocket->flags |= DAP_SOCK_SIGNAL_CLOSE;
+        //dap_client_ready_to_write(cl_ht->client,false);
+        DAP_DELETE(l_http_simple->reply );
+    }
+}
+
+void s_http_client_data_read( dap_http_client_t *a_http_client, void * a_arg )
 {
     int *ret = (int *)a_arg;
 
-    //  log_it(L_DEBUG,"dap_http_simple_data_read");
+    //log_it(L_DEBUG,"dap_http_simple_data_read");
     //  Sleep(300);
 
     dap_http_simple_t *l_http_simple = DAP_HTTP_SIMPLE(a_http_client);
 
-    size_t bytes_to_read = (a_http_client->client->buf_in_size + l_http_simple->request_size) < a_http_client->in_content_length ?
-                            a_http_client->client->buf_in_size : ( a_http_client->in_content_length - l_http_simple->request_size );
+    size_t bytes_to_read = (a_http_client->esocket->buf_in_size + l_http_simple->request_size) < a_http_client->in_content_length ?
+                            a_http_client->esocket->buf_in_size : ( a_http_client->in_content_length - l_http_simple->request_size );
 
     if( bytes_to_read ) {
         // Oops! The client sent more data than write in the CONTENT_LENGTH header
@@ -450,68 +408,33 @@ void s_data_read( dap_http_client_t *a_http_client, void * a_arg )
             l_http_simple->request = DAP_REALLOC(l_http_simple->request, l_http_simple->request_size_max);
         }
         if(l_http_simple->request){// request_byte=request
-            memcpy( l_http_simple->request_byte + l_http_simple->request_size, a_http_client->client->buf_in, bytes_to_read );
+            memcpy( l_http_simple->request_byte + l_http_simple->request_size, a_http_client->esocket->buf_in, bytes_to_read );
             l_http_simple->request_size += bytes_to_read;
         }
     }
-
+    *ret = (int) a_http_client->esocket->buf_in_size;
     if( l_http_simple->request_size >= a_http_client->in_content_length ) {
 
         // bool isOK=true;
-        log_it( L_DEBUG,"Data collected" );
-        queue_http_request_put( l_http_simple );
+        log_it( L_INFO,"Data for http_simple_request collected" );
+        dap_events_socket_remove_from_worker_unsafe(a_http_client->esocket,a_http_client->esocket->worker);
+        dap_proc_queue_add_callback( l_http_simple->worker->proc_queue , s_proc_queue_callback, l_http_simple);
     }
-
-    *ret = (int) a_http_client->client->buf_in_size;
 }
 
 
-/**
- * @brief dap_http_simple_data_write
- * @param a_http_client
- * @param a_arg
- */
-static void s_data_write( dap_http_client_t *a_http_client, void *a_arg )
-{
-  (void) a_arg;
-  dap_http_simple_t *cl_st = DAP_HTTP_SIMPLE( a_http_client );
-
-//  log_it(L_DEBUG,"dap_http_simple_data_write");
-//  Sleep(300);
-
-  if ( !cl_st->reply ) {
-
-    a_http_client->client->flags |= DAP_SOCK_SIGNAL_CLOSE;
-    log_it( L_WARNING, "No reply to write, close connection" );
-
-    return;
-  }
-
-  cl_st->reply_sent += dap_client_remote_write( a_http_client->client,
-                                              cl_st->reply_byte + cl_st->reply_sent,
-                                              a_http_client->out_content_length - cl_st->reply_sent );
-
-  if ( cl_st->reply_sent >= a_http_client->out_content_length ) {
-    log_it(L_INFO, "All the reply (%u) is sent out", a_http_client->out_content_length );
-    //cl_ht->client->signal_close=cl_ht->keep_alive;
-    a_http_client->client->flags |= DAP_SOCK_SIGNAL_CLOSE;
-    //dap_client_ready_to_write(cl_ht->client,false);
-  }
-
-  free( cl_st->reply );
-}
-
 /**
  * @brief dap_http_simple_reply Add data to the reply buffer
  * @param shs HTTP simple client instance
  * @param data
  * @param data_size
  */
-size_t dap_http_simple_reply( dap_http_simple_t *a_http_simple, void *a_data, size_t a_data_size )
+size_t dap_http_simple_reply(dap_http_simple_t *a_http_simple, void *a_data, size_t a_data_size )
 {
     size_t l_data_copy_size = (a_data_size > (a_http_simple->reply_size_max - a_http_simple->reply_size) ) ? (a_http_simple->reply_size_max - a_http_simple->reply_size) : a_data_size;
 
-    memcpy( a_http_simple->reply_byte + a_http_simple->reply_size, a_data, l_data_copy_size );
+    memcpy(a_http_simple->reply_byte+a_http_simple->reply_size, a_data,l_data_copy_size );
+
     a_http_simple->reply_size += l_data_copy_size;
 
     return l_data_copy_size;
@@ -522,7 +445,7 @@ size_t dap_http_simple_reply( dap_http_simple_t *a_http_simple, void *a_data, si
  * @param shs
  * @param data
  */
-size_t dap_http_simple_reply_f( dap_http_simple_t * shs, const char * data, ... )
+size_t dap_http_simple_reply_f(dap_http_simple_t * shs, const char * data, ... )
 {
   char buf[4096];
   va_list va;
@@ -538,26 +461,6 @@ size_t dap_http_simple_reply_f( dap_http_simple_t * shs, const char * data, ...
     return 0;
 }
 
-inline void queue_http_request_put( dap_http_simple_t *cl_sh )
-{
-//  dap_http_simple_proc( cl_sh );
-
-  pthread_mutex_lock( &mutex_on_queue_http_response );
-
-  if ( s_requests_count >= DAP_HTTP_SIMPLE_REQUEST_MAX ) {
-
-    log_it( L_NOTICE, "Requests Buffer is FULL( %u ) ignore request" );
-    pthread_mutex_unlock( &mutex_on_queue_http_response );
-    return;
-  }
-
-  log_it( L_WARNING, "queue_http_request_put >>> %u", s_requests_count );
-
-  s_requests[ s_requests_count ++ ] = cl_sh;
-  cl_sh->http->client->no_close = true;
-
-  pthread_mutex_unlock( &mutex_on_queue_http_response );
-}
 
 /* Key Expired deprecated code */
 
diff --git a/dap-sdk/net/server/http_server/http_client/dap_http_client.c b/dap-sdk/net/server/http_server/http_client/dap_http_client.c
index 81cdd8cdfec2f2f98f544a7a50858864cb902ec2..59f30cf660aefe3d5977ac80c5397f792e3355b6 100644
--- a/dap-sdk/net/server/http_server/http_client/dap_http_client.c
+++ b/dap-sdk/net/server/http_server/http_client/dap_http_client.c
@@ -36,7 +36,7 @@
 #include <pthread.h>
 
 #include "dap_common.h"
-#include "dap_client_remote.h"
+#include "dap_events_socket.h"
 
 #include "dap_http.h"
 #include "http_status_code.h"
@@ -44,11 +44,7 @@
 #include "dap_http_header.h"
 #include "dap_http_client.h"
 
-#define LOG_TAG "http_client"
-
-//#define BUF_SIZE 2048
-
-void dap_http_client_out_header_generate( dap_http_client_t *cl_ht );
+#define LOG_TAG "dap_http_client"
 
 /**
  * @brief dap_http_client_init Init HTTP client module
@@ -73,21 +69,20 @@ void dap_http_client_deinit( )
  * @param cl HTTP Client instance
  * @param arg Additional argument (usualy not used)
  */
-void dap_http_client_new( dap_client_remote_t *cl, void *arg )
+void dap_http_client_new( dap_events_socket_t *cl, void *arg )
 {
-  (void) arg;
+    (void) arg;
 
-  log_it( L_NOTICE, "dap_http_client_new" );
 
-  cl->_inheritor = DAP_NEW_Z( dap_http_client_t );
+    cl->_inheritor = DAP_NEW_Z( dap_http_client_t );
 
-  dap_http_client_t *cl_ht = DAP_HTTP_CLIENT( cl );
-  cl_ht->client = cl;
-  cl_ht->http = DAP_HTTP( cl->server );
-  cl_ht->state_read = DAP_HTTP_CLIENT_STATE_START;
-  cl_ht->state_write = DAP_HTTP_CLIENT_STATE_NONE;
+    dap_http_client_t *cl_ht = DAP_HTTP_CLIENT( cl );
+    cl_ht->esocket = cl;
+    cl_ht->http = DAP_HTTP( cl->server );
+    cl_ht->state_read = DAP_HTTP_CLIENT_STATE_START;
+    cl_ht->state_write = DAP_HTTP_CLIENT_STATE_NONE;
 
-  return;
+    return;
 }
 
 /**
@@ -95,25 +90,27 @@ void dap_http_client_new( dap_client_remote_t *cl, void *arg )
  * @param cl HTTP Client instance
  * @param arg Additional argument (usualy not used)
  */
-void dap_http_client_delete( dap_client_remote_t * cl, void *arg )
+void dap_http_client_delete( dap_events_socket_t * cl, void *arg )
 {
-  dap_http_client_t *cl_ht = DAP_HTTP_CLIENT( cl );
-
-  while( cl_ht->in_headers )
-    dap_http_header_remove( &cl_ht->in_headers, cl_ht->in_headers );
+    dap_http_client_t *cl_ht = DAP_HTTP_CLIENT( cl );
+    if (cl_ht == NULL){ // Client is in proc callback in another thread so we don't delete it
+        return;
+    }
+    while( cl_ht->in_headers )
+        dap_http_header_remove( &cl_ht->in_headers, cl_ht->in_headers );
 
-  while( cl_ht->out_headers )
-    dap_http_header_remove( &cl_ht->out_headers, cl_ht->out_headers );
+    while( cl_ht->out_headers )
+        dap_http_header_remove( &cl_ht->out_headers, cl_ht->out_headers );
 
-  if( cl_ht->proc ) {
-    if( cl_ht->proc->delete_callback ) {
-      cl_ht->proc->delete_callback( cl_ht, NULL );
+    if( cl_ht->proc ) {
+        if( cl_ht->proc->delete_callback ) {
+          cl_ht->proc->delete_callback( cl_ht, NULL );
+        }
     }
-  }
 
-  if( cl_ht->_inheritor ) {
-    free( cl_ht->_inheritor );
-  }
+    if( cl_ht->_inheritor ) {
+        free( cl_ht->_inheritor );
+    }
 
   (void) arg;
 }
@@ -203,7 +200,7 @@ int32_t  z_rootdirname( char *path, uint32_t len )
     ++ptr;
   }
 
-  int32_t len2 = (uint32_t)(ptr - path);
+  uint32_t len2 = (uint32_t)(ptr - path);
   if ( len2 == len )
     return 0;
 
@@ -212,6 +209,13 @@ int32_t  z_rootdirname( char *path, uint32_t len )
   return len2;
 }
 
+/**
+ * @brief dap_http_request_line_parse
+ * @param cl_ht
+ * @param buf
+ * @param buf_length
+ * @return
+ */
 bool dap_http_request_line_parse( dap_http_client_t *cl_ht, char *buf, size_t buf_length )
 {
   size_t pos;
@@ -293,13 +297,18 @@ bool dap_http_request_line_parse( dap_http_client_t *cl_ht, char *buf, size_t bu
   return cl_ht->url_path[0] && cl_ht->action[0];
 }
 
-static inline void ReportErrorAndRestart( dap_client_remote_t *cl, dap_http_client_t *cl_ht )
+/**
+ * @brief s_report_error_and_restart
+ * @param cl
+ * @param cl_ht
+ */
+static inline void s_report_error_and_restart( dap_events_socket_t *cl, dap_http_client_t *cl_ht )
 {
   cl->buf_in_size = 0;
   cl_ht->state_read = DAP_HTTP_CLIENT_STATE_NONE;
 
-  dap_client_remote_ready_to_read( cl_ht->client, false );
-  dap_client_remote_ready_to_write( cl_ht->client, true );
+  dap_events_socket_set_readable_unsafe( cl_ht->esocket, false );
+  dap_events_socket_set_writable_unsafe( cl_ht->esocket, true );
 
   cl_ht->reply_status_code = 505;
   strcpy( cl_ht->reply_reason_phrase, "Error" );
@@ -313,214 +322,155 @@ static inline void ReportErrorAndRestart( dap_client_remote_t *cl, dap_http_clie
  * @param cl HTTP Client instance
  * @param arg Additional argument (usualy not used)
  */
-void dap_http_client_read( dap_client_remote_t *cl, void *arg )
+void dap_http_client_read( dap_events_socket_t *a_esocket, void *arg )
 {
-    char buf_line[4096] = {'\0'};
-  dap_http_client_t *cl_ht = DAP_HTTP_CLIENT( cl );
+    dap_http_client_t *l_http_client = DAP_HTTP_CLIENT( a_esocket );
 
 //  log_it( L_DEBUG, "dap_http_client_read..." );
-  //log_it( L_DEBUG, "HTTP client in state read %d taked bytes in input %lu", cl_ht->state_read, cl->buf_in_size );
-
-  do {
-    switch( cl_ht->state_read ) {
-
-    case DAP_HTTP_CLIENT_STATE_START: { // Beginning of the session. We try to detect
-
-      char  *peol;
-      uint32_t eol;
-
-      if (!(peol = (char*)memchr(cl->buf_in, 10, cl->buf_in_size))) { /// search LF
-          peol = (char*)memchr(cl->buf_in, 13, cl->buf_in_size);
-      }
-
-      if (peol) {
-          eol = peol - cl->buf_in;
-          if (eol <= 0) {
-              eol = cl->buf_in_size - 2;
-          }
-      } else {
-          log_it( L_WARNING, "Single-line, possibly trash, input detected");
-          eol = cl->buf_in_size - 2;
-      }
-
-      if ( eol + 3 >= sizeof(buf_line) ) {
-        log_it( L_WARNING,"Too big line in request, more than %llu symbols - thats very strange", sizeof(buf_line) - 3 );
-        ReportErrorAndRestart( cl, cl_ht );
-        break;
-      }
-
-      memcpy( buf_line, cl->buf_in, eol + 1 ); // copy with LF
-
-      dap_client_remote_shrink_buf_in( cl, eol + 1 );
-      buf_line[ eol + 2 ] = 0; // null terminate
-
-      // parse http_request_line
-      if ( !dap_http_request_line_parse(cl_ht, buf_line, eol + 1) ) {
-
-        log_it( L_WARNING, "Input: Wrong request line '%s'", buf_line );
-        ReportErrorAndRestart( cl, cl_ht );
-        break;
-      }
-
-//    uint32_t action_len;
-//    uint32_t url_path_len;
-
-      char *query_string;
-
-      if( (query_string = strchr(cl_ht->url_path, '?')) != NULL ) {
-
-        size_t len_after = strlen( query_string + 1 );
-
-        if ( len_after ) {
-          if( len_after > (sizeof(cl_ht->in_query_string) - 1) )
-            len_after = sizeof(cl_ht->in_query_string) - 1;
-  
-          if ( strstr(query_string, "HTTP/1.1") )
-            strncpy( cl_ht->in_query_string, query_string + 1, len_after - 11 );
-          else
-            strncpy( cl_ht->in_query_string,query_string + 1, len_after );
-
-          if ( cl_ht->in_query_string[strlen(cl_ht->in_query_string) - 1] == ' ' )
-            cl_ht->in_query_string[strlen(cl_ht->in_query_string) - 1] = 0;
-
-          query_string[0] = 0;
-        }
-      }
-
-      log_it( L_WARNING, "Input: %s request for %s document (query string '%s')", cl_ht->action, cl_ht->url_path, cl_ht->in_query_string ? cl_ht->in_query_string : ""  );
-
-      dap_http_url_proc_t *url_proc;
-      int32_t tpos = z_dirname( cl_ht->url_path, 0 );
-      log_it( L_WARNING, "cl_ht->url_path(dir) = %s", cl_ht->url_path );
-
-      HASH_FIND_STR( cl_ht->http->url_proc, cl_ht->url_path, url_proc );  // Find URL processor
-
-      cl_ht->proc = url_proc;
-
-      if ( tpos )
-        cl_ht->url_path[ tpos ] = '/';
-
-      char *ptr = z_basename( cl_ht->url_path, 0 );
-      log_it( L_WARNING, "basename = %s", ptr );
-
-//      log_it( L_WARNING, "cl_ht->client->socket = %u efd %u", cl_ht->client->socket, cl_ht->client->efd );
-
-      memmove( cl_ht->url_path, ptr, strlen(ptr) + 1 );
-
-      log_it( L_WARNING, "cl_ht->url_path = %s", cl_ht->url_path );
-
-      if ( url_proc ) {
-        cl_ht->state_read = DAP_HTTP_CLIENT_STATE_HEADERS;
-      }
-      else {
-        log_it( L_WARNING, "Input: unprocessed URL request %s is rejected", cl_ht->url_path );
-        ReportErrorAndRestart( cl, cl_ht );
-        break;
-      }
-
-    }
-    break;
-
-    case DAP_HTTP_CLIENT_STATE_HEADERS: { // Parse input headers
-
-//      log_it( L_WARNING, "DAP_HTTP_CLIENT_STATE_HEADERS" );
-      char  *peol;
-      uint32_t eol;
-
-      if ( !(peol = (char *)memchr(cl->buf_in, 10, cl->buf_in_size)) ) { /// search LF
-        log_it( L_WARNING, "DAP_HTTP_CLIENT_STATE_HEADERS: no LF" );
-        ReportErrorAndRestart( cl, cl_ht );
-        break;
-      }
-
-      eol = peol - cl->buf_in;
-
-//      int eol = detect_end_of_line( cl->buf_in, cl->buf_in_size );
-
-//      if ( eol < 0 ) {
-//        log_it( L_WARNING, "DAP_HTTP_CLIENT_STATE_HEADERS: no LF" );
-//        return;
-//      }
-
-      int parse_ret;
-      memcpy( buf_line, cl->buf_in, eol + 1 );
-      buf_line[eol-1] = 0;
-
-      parse_ret = dap_http_header_parse( cl_ht, buf_line );
-
-//      log_it( L_WARNING, "cl_ht->client->socket = %u efd %u", cl_ht->client->socket, cl_ht->client->efd );
-
-        //  log_it(L_WARNINGNG, "++ ALL HEADERS TO PARSE [%s]", buf_line);
-      if( parse_ret < 0 )
-        log_it( L_WARNING, "Input: not a valid header '%s'", buf_line );
-
-      else if ( parse_ret == 1 ) {
-
-        log_it( L_INFO, "Input: HTTP headers are over" );
-
-        if ( cl_ht->proc->access_callback ) {
-
-//          log_it( L_WARNING, "access_callback" );
-
-          bool isOk = true;
-          cl_ht->proc->access_callback( cl_ht, &isOk );
-          if ( !isOk ) {
-            log_it( L_NOTICE, "Access restricted" );
-            ReportErrorAndRestart( cl, cl_ht );
-          }
-        }
-
-        if ( cl_ht->proc->headers_read_callback ) {
-          log_it( L_WARNING, "headers_read_callback" );
-          cl_ht->proc->headers_read_callback( cl_ht, NULL );
-        }
-
-        // If no headers callback we go to the DATA processing
-        if( cl_ht->in_content_length ) {
-            log_it( L_WARNING, "headers -> DAP_HTTP_CLIENT_STATE_DATA" );
-            cl_ht->state_read = DAP_HTTP_CLIENT_STATE_DATA;
-        } 
-        else {
-                          //log_it
-                          //cl_ht->state_read=DAP_HTTP_CLIENT_STATE_NONE;
-                          //cl_ht->client->ready_to_read=t;
-                          //cl_ht->client->signal_close=!cl_ht->keep_alive;
-        }
-      } // parse_ret == 1
-
-      dap_client_remote_shrink_buf_in( cl, eol + 1 );
-    }
-    break;
-
-    case DAP_HTTP_CLIENT_STATE_DATA:
-    {
-           //   log_it(L_WARNINGNG, "DBG_#002 [%s] [%s]",             cl_ht->in_query_string, cl_ht->url_path);
-
-      size_t read_bytes = 0;
-      if ( cl_ht->proc->data_read_callback ) {
-//            log_it( L_WARNING, "cl_ht->proc->data_read_callback()" );
-
-        //while(cl_ht->client->buf_in_size){
-        cl_ht->proc->data_read_callback( cl_ht, &read_bytes );
-        dap_client_remote_shrink_buf_in( cl, read_bytes );
-                //}
-      } 
-      else {
-        log_it( L_WARNING, "data_read callback is NULL in DAP_HTTP_CLIENT_STATE_DATA" );
-        cl->buf_in_size = 0;
-      }
-    } 
-    break;
-
-    case DAP_HTTP_CLIENT_STATE_NONE: {
-      cl->buf_in_size = 0;
-    }
-    break;
-
-    } // switch
-
-  } while ( cl->buf_in_size > 0 );
-
+    do{
+        //log_it( L_DEBUG, "HTTP client in state read %d taked bytes in input %lu", l_http_client->state_read, a_esocket->buf_in_size );
+        switch( l_http_client->state_read ) {
+            case DAP_HTTP_CLIENT_STATE_START: { // Beginning of the session. We try to detect
+                char l_buf_line[4096];
+                char  *peol;
+                uint32_t eol;
+
+                if (!(peol = (char*)memchr(a_esocket->buf_in, 10, a_esocket->buf_in_size))) { /// search LF
+                    peol = (char*)memchr(a_esocket->buf_in, 13, a_esocket->buf_in_size);
+                }
+
+                if (peol) {
+                    eol = peol - a_esocket->buf_in_str;
+                    if (eol <= 0) {
+                        eol = a_esocket->buf_in_size - 2;
+                    }
+                } else {
+                    log_it( L_WARNING, "Single-line, possibly trash, input detected");
+                    eol = a_esocket->buf_in_size - 2;
+                }
+
+                if ( eol + 3 >= sizeof(l_buf_line) ) {
+                    log_it( L_WARNING,"Too big line in request, more than %llu symbols - thats very strange", sizeof(l_buf_line) - 3 );
+                    s_report_error_and_restart( a_esocket, l_http_client );
+                    break;
+                }
+
+                memcpy( l_buf_line, a_esocket->buf_in, eol + 1 ); // copy with LF
+
+                dap_events_socket_shrink_buf_in( a_esocket, eol + 1 );
+                l_buf_line[ eol + 2 ] = 0; // null terminate
+
+                // parse http_request_line
+                if ( !dap_http_request_line_parse(l_http_client, l_buf_line, eol + 1) ) {
+                    log_it( L_WARNING, "Input: Wrong request line '%s'", l_buf_line );
+                    s_report_error_and_restart( a_esocket, l_http_client );
+                    break;
+                }
+
+                char *l_query_string;
+                if( (l_query_string = strchr(l_http_client->url_path, '?')) != NULL ) {
+                    size_t len_after = strlen( l_query_string + 1 );
+
+                    if ( len_after ) {
+                        if( len_after > (sizeof(l_http_client->in_query_string) - 1) ){
+                            len_after = sizeof(l_http_client->in_query_string) - 1;
+                        }
+
+                        if ( strstr(l_query_string, "HTTP/1.1") ){
+                            strncpy( l_http_client->in_query_string, l_query_string + 1, len_after - 11 );
+                        }else{
+                            strncpy( l_http_client->in_query_string,l_query_string + 1, len_after );
+                        }
+
+                        if ( l_http_client->in_query_string[strlen(l_http_client->in_query_string) - 1] == ' ' ){
+                            l_http_client->in_query_string[strlen(l_http_client->in_query_string) - 1] = 0;
+                        }
+                        l_query_string[0] = 0;
+                    }
+                }
+
+                log_it( L_INFO, "Input: %s request for %s document (query string '%s')", l_http_client->action, l_http_client->url_path, l_http_client->in_query_string[0] ? l_http_client->in_query_string : ""  );
+
+                dap_http_url_proc_t *url_proc;
+                int32_t tpos = z_dirname( l_http_client->url_path, 0 );
+                HASH_FIND_STR( l_http_client->http->url_proc, l_http_client->url_path, url_proc );  // Find URL processor
+                l_http_client->proc = url_proc;
+
+                if ( tpos ){
+                    l_http_client->url_path[ tpos ] = '/';
+                }
+                char *ptr = z_basename( l_http_client->url_path, 0 );
+                memmove( l_http_client->url_path, ptr, strlen(ptr) + 1 );
+
+                if ( url_proc ) {
+                    l_http_client->state_read = DAP_HTTP_CLIENT_STATE_HEADERS;
+                } else {
+                    log_it( L_WARNING, "Input: unprocessed URL request %s is rejected", l_http_client->url_path );
+                    s_report_error_and_restart( a_esocket, l_http_client );
+                    break;
+                }
+            } break;
+
+            case DAP_HTTP_CLIENT_STATE_HEADERS: { // Parse input headers
+                char l_buf_line[4096];
+                char  *l_str_eol;
+                uint32_t l_eol_pos;
+
+                if ( !(l_str_eol = (char *)memchr(a_esocket->buf_in, 10, a_esocket->buf_in_size)) ) { /// search LF
+                    log_it( L_WARNING, "DAP_HTTP_CLIENT_STATE_HEADERS: no LF" );
+                    s_report_error_and_restart( a_esocket, l_http_client );
+                    break;
+                }
+
+                l_eol_pos = l_str_eol - a_esocket->buf_in_str;
+
+                int parse_ret;
+                memcpy( l_buf_line, a_esocket->buf_in, l_eol_pos + 1 );
+                l_buf_line[l_eol_pos-1] = 0;
+
+                parse_ret = dap_http_header_parse( l_http_client, l_buf_line );
+
+                if( parse_ret < 0 ){
+                    log_it( L_WARNING, "Input: not a valid header '%s'", l_buf_line );
+                }else if ( parse_ret == 1 ) {
+                    log_it( L_INFO, "Input: HTTP headers are over" );
+                    if ( l_http_client->proc->access_callback ) {
+                        bool isOk = true;
+                        l_http_client->proc->access_callback( l_http_client, &isOk );
+                        if ( !isOk ) {
+                            log_it( L_NOTICE, "Access restricted" );
+                            s_report_error_and_restart( a_esocket, l_http_client );
+                        }
+                    }
+
+                    if ( l_http_client->proc->headers_read_callback ) {
+                        l_http_client->proc->headers_read_callback( l_http_client, NULL );
+                    }
+
+                    // If no headers callback we go to the DATA processing
+                    if( l_http_client->in_content_length ) {
+                        //log_it( L_DEBUG, "headers -> DAP_HTTP_CLIENT_STATE_DATA" );
+                        l_http_client->state_read = DAP_HTTP_CLIENT_STATE_DATA;
+                    }
+                }
+                dap_events_socket_shrink_buf_in( a_esocket, l_eol_pos + 1 );
+            } break;
+            case DAP_HTTP_CLIENT_STATE_DATA:{
+                size_t read_bytes = 0;
+                //log_it(L_DEBUG, "dap_http_client_read: DAP_HTTP_CLIENT_STATE_DATA");
+                if ( l_http_client->proc->data_read_callback ) {
+                    l_http_client->proc->data_read_callback( l_http_client, &read_bytes );
+                    dap_events_socket_shrink_buf_in( a_esocket, read_bytes );
+                } else {
+                    log_it( L_WARNING, "data_read callback is NULL in DAP_HTTP_CLIENT_STATE_DATA" );
+                    a_esocket->buf_in_size = 0;
+                }
+            } break;
+            case DAP_HTTP_CLIENT_STATE_NONE: {
+                a_esocket->buf_in_size = 0;
+            } break;
+        } // switch
+    } while (a_esocket->buf_in_size);
 //  log_it( L_DEBUG, "dap_http_client_read...exit" );
 //  Sleep(100);
 }
@@ -530,65 +480,64 @@ void dap_http_client_read( dap_client_remote_t *cl, void *arg )
  * @param cl HTTP Client instance
  * @param arg Additional argument (usualy not used)
  */
-void dap_http_client_write( dap_client_remote_t * cl, void *arg )
+void dap_http_client_write( dap_events_socket_t * cl, void *arg )
 {
-//  log_it( L_DEBUG, "dap_http_client_write..." );
-
-  (void) arg;
-  dap_http_client_t *cl_ht = DAP_HTTP_CLIENT( cl );
-
- //   log_it(L_WARNING,"HTTP client write callback in state %d",cl_ht->state_write);
-
-  switch( cl_ht->state_write ) {
-    case DAP_HTTP_CLIENT_STATE_NONE:
-      return;
-    case DAP_HTTP_CLIENT_STATE_START:
-    {
-      if ( cl_ht->proc )
-        if ( cl_ht->proc->headers_write_callback )
-          cl_ht->proc->headers_write_callback( cl_ht, NULL );
-
-      log_it( L_DEBUG,"Output: HTTP response with %u status code", cl_ht->reply_status_code );
-
-      dap_client_remote_write_f( cl,"HTTP/1.1 %u %s\r\n",cl_ht->reply_status_code, cl_ht->reply_reason_phrase[0] ?
-                        cl_ht->reply_reason_phrase : http_status_reason_phrase(cl_ht->reply_status_code) );
-
-      dap_http_client_out_header_generate( cl_ht );
-      cl_ht->state_write = DAP_HTTP_CLIENT_STATE_HEADERS;
-    }
-    break;
-
-    case DAP_HTTP_CLIENT_STATE_HEADERS:
-    {
-      dap_http_header_t *hdr = cl_ht->out_headers;
-      if ( hdr == NULL ) {
-        log_it(L_DEBUG, "Output: headers are over (reply status code %u)",cl_ht->reply_status_code);
-        dap_client_remote_write_f( cl,"\r\n" );
-        if ( cl_ht->out_content_length || cl_ht->out_content_ready ) {
-          cl_ht->state_write=DAP_HTTP_CLIENT_STATE_DATA;
-        }
-        else {
-          log_it( L_DEBUG, "Nothing to output" );
-          cl_ht->state_write = DAP_HTTP_CLIENT_STATE_NONE;
-          dap_client_remote_ready_to_write( cl, false );
-          cl->flags |= DAP_SOCK_SIGNAL_CLOSE;
+    //  log_it( L_DEBUG, "dap_http_client_write..." );
+
+    (void) arg;
+    dap_http_client_t *l_http_client = DAP_HTTP_CLIENT( cl );
+    //log_it(L_WARNING,"HTTP client write callback in state %d",l_http_client->state_write);
+
+    switch( l_http_client->state_write ) {
+        case DAP_HTTP_CLIENT_STATE_NONE:
+            return;
+        case DAP_HTTP_CLIENT_STATE_START:{
+            if ( l_http_client->proc )
+                if ( l_http_client->proc->headers_write_callback )
+                    l_http_client->proc->headers_write_callback( l_http_client, NULL );
+
+            log_it( L_INFO," HTTP response with %u status code", l_http_client->reply_status_code );
+            dap_events_socket_write_f_unsafe(cl, "HTTP/1.1 %u %s\r\n",l_http_client->reply_status_code, l_http_client->reply_reason_phrase[0] ?
+                            l_http_client->reply_reason_phrase : http_status_reason_phrase(l_http_client->reply_status_code) );
+            dap_events_socket_set_writable_unsafe(cl, true);
+            dap_http_client_out_header_generate( l_http_client );
+            l_http_client->state_write = DAP_HTTP_CLIENT_STATE_HEADERS;
+        } break;
+
+        case DAP_HTTP_CLIENT_STATE_HEADERS: {
+            dap_http_header_t *hdr = l_http_client->out_headers;
+            if ( hdr == NULL ) {
+                log_it(L_DEBUG, "Output: headers are over (reply status code %u content_lentgh %u)",
+                       l_http_client->reply_status_code, l_http_client->out_content_length);
+                dap_events_socket_write_f_unsafe(cl, "\r\n");
+                dap_events_socket_set_writable_unsafe(cl, true);
+                if ( l_http_client->out_content_length || l_http_client->out_content_ready ) {
+                    l_http_client->state_write=DAP_HTTP_CLIENT_STATE_DATA;
+                } else {
+                    log_it( L_DEBUG, "Nothing to output" );
+                    l_http_client->state_write = DAP_HTTP_CLIENT_STATE_NONE;
+                    dap_events_socket_set_writable_unsafe( cl, false );
+                    cl->flags |= DAP_SOCK_SIGNAL_CLOSE;
+                }
+                dap_events_socket_set_readable_unsafe( cl, true );
+            } else {
+                //log_it(L_WARNING,"Output: header %s: %s",hdr->name,hdr->value);
+                dap_events_socket_write_f_unsafe(cl, "%s: %s\r\n", hdr->name, hdr->value);
+                dap_events_socket_set_writable_unsafe(cl, true);
+                dap_http_header_remove( &l_http_client->out_headers, hdr );
+            }
+        } break;
+        case DAP_HTTP_CLIENT_STATE_DATA:
+        {
+          if ( l_http_client->proc ){
+            if ( l_http_client->proc->data_write_callback ){
+                l_http_client->proc->data_write_callback( l_http_client, NULL );
+            }
+          }else{
+              log_it(L_WARNING, "No http proc, nothing to write");
+          }
         }
-        dap_client_remote_ready_to_read( cl, true );
-      }
-      else {
-        //log_it(L_WARNING,"Output: header %s: %s",hdr->name,hdr->value);
-        dap_client_remote_write_f( cl, "%s: %s\r\n", hdr->name,hdr->value );
-        dap_http_header_remove( &cl_ht->out_headers, hdr );
-      }
-    }
-    break;
-    case DAP_HTTP_CLIENT_STATE_DATA:
-    {
-      if ( cl_ht->proc )
-        if ( cl_ht->proc->data_write_callback )
-          cl_ht->proc->data_write_callback( cl_ht, NULL );
-    }
-    break;
+        break;
   }
 }
 
@@ -634,7 +583,7 @@ void dap_http_client_out_header_generate(dap_http_client_t *cl_ht)
  * @param cl HTTP Client instance
  * @param arg Additional argument (usualy not used)
  */
-void dap_http_client_error( struct dap_client_remote *cl, void *arg )
+void dap_http_client_error( dap_events_socket_t *cl, int arg )
 {
   (void) arg;
 
diff --git a/dap-sdk/net/server/http_server/http_client/dap_http_header.c b/dap-sdk/net/server/http_server/http_client/dap_http_header.c
index 68b964040fdd2a223754772ef25229ed35e461f0..e2458cadeff4b56331854ff6b474db6f4a0a7d03 100644
--- a/dap-sdk/net/server/http_server/http_client/dap_http_header.c
+++ b/dap-sdk/net/server/http_server/http_client/dap_http_header.c
@@ -34,7 +34,7 @@
 #include <pthread.h>
 
 #include "dap_common.h"
-#include "dap_client_remote.h"
+#include "dap_events_socket.h"
 #include "dap_http_client.h"
 #include "dap_http_header.h"
 
diff --git a/dap-sdk/net/server/http_server/http_client/include/dap_http_client.h b/dap-sdk/net/server/http_server/http_client/include/dap_http_client.h
index f90569be39404776caee3d90c15bc566a834d1ca..864233216d48cfb1fda03baacfcb1c1b2f909bb7 100644
--- a/dap-sdk/net/server/http_server/http_client/include/dap_http_client.h
+++ b/dap-sdk/net/server/http_server/http_client/include/dap_http_client.h
@@ -17,15 +17,11 @@
     You should have received a copy of the GNU Lesser General Public License
     along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
 */
-
-
-#ifndef _DAP_HTTP_CLIENT_H_
-#define _DAP_HTTP_CLIENT_H_
-
+#pragma once
 #include <stdint.h>
 #include <time.h>
 #include <stdbool.h>
-#include "dap_client_remote.h"
+#include "dap_events_socket.h"
 
 struct dap_http_client;
 struct dap_http;
@@ -39,6 +35,7 @@ typedef enum dap_http_client_state{
 } dap_http_client_state_t;
 
 typedef void (*dap_http_client_callback_t) (struct dap_http_client *,void * arg); // Callback for specific client operations
+typedef void (*dap_http_client_callback_error_t) (struct dap_http_client *,int); // Callback for specific client operations
 
 typedef struct dap_http_client
 {
@@ -66,7 +63,7 @@ typedef struct dap_http_client
     time_t out_last_modified;
     bool out_connection_close;
 
-    dap_client_remote_t *client;
+    dap_events_socket_t *esocket;
     struct dap_http * http;
 
     uint16_t reply_status_code;
@@ -87,16 +84,15 @@ extern "C" {
 
 int dap_http_client_init( );
 void dap_http_client_deinit( );
+void dap_http_client_new( dap_events_socket_t * cl,void *arg ); // Creates HTTP client's internal structure
+void dap_http_client_delete( dap_events_socket_t * cl,void *arg ); // Free memory for HTTP client's internal structure
 
-void dap_http_client_new( dap_client_remote_t * cl,void *arg ); // Creates HTTP client's internal structure
-void dap_http_client_delete( dap_client_remote_t * cl,void *arg ); // Free memory for HTTP client's internal structure
-
-void dap_http_client_read( dap_client_remote_t * cl,void *arg ); // Process read event
-void dap_http_client_write( dap_client_remote_t * cl,void *arg ); // Process write event
-void dap_http_client_error( dap_client_remote_t * cl,void *arg ); // Process error event
+void dap_http_client_read( dap_events_socket_t * cl,void *arg ); // Process read event
+void dap_http_client_write( dap_events_socket_t * cl,void *arg ); // Process write event
+void dap_http_client_error( dap_events_socket_t * cl,int arg ); // Process error event
+void dap_http_client_out_header_generate( dap_http_client_t *cl_ht );
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif
diff --git a/dap-sdk/net/server/http_server/include/dap_http.h b/dap-sdk/net/server/http_server/include/dap_http.h
index 646811940151ee8b8d46f158e90fa6b48165d153..0d1fcfb84f5ff0d6ddc30451e8f225c2537cc974 100644
--- a/dap-sdk/net/server/http_server/include/dap_http.h
+++ b/dap-sdk/net/server/http_server/include/dap_http.h
@@ -23,7 +23,7 @@ See more details here <http://www.gnu.org/licenses/>.
 #pragma once
 
 #include "dap_server.h"
-#include "dap_client_remote.h"
+#include "dap_events_socket.h"
 #include "dap_http_header.h"
 #include "dap_http_client.h"
 #include "uthash.h"
@@ -45,7 +45,7 @@ typedef struct dap_http_url_proc{
 
     dap_http_client_callback_t data_read_callback;
     dap_http_client_callback_t data_write_callback;
-    dap_http_client_callback_t error_callback;
+    dap_http_client_callback_error_t error_callback;
 
     dap_http_client_callback_t access_callback;
 
@@ -75,5 +75,5 @@ void dap_http_add_proc(dap_http_t *sh, const char *url_path, void *internal
                              ,dap_http_client_callback_t headers_write_callback
                              ,dap_http_client_callback_t data_read_callback
                              ,dap_http_client_callback_t data_write_callback
-                             ,dap_http_client_callback_t error_callback ); // Add custom procesor for the HTTP server
+                             ,dap_http_client_callback_error_t error_callback ); // Add custom procesor for the HTTP server
 
diff --git a/dap-sdk/net/server/http_server/include/dap_http_folder.h b/dap-sdk/net/server/http_server/include/dap_http_folder.h
index 3dec0498a19076fff6cf71e8b4eed3f10ce7c3bc..530afb1e2e43ca00154ccf8611946a048c318acc 100644
--- a/dap-sdk/net/server/http_server/include/dap_http_folder.h
+++ b/dap-sdk/net/server/http_server/include/dap_http_folder.h
@@ -1,31 +1,30 @@
 /*
- Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc
-  All rights reserved.
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Ltd.   https://demlabs.net
+ * Copyright  (c) 2017
+ * All rights reserved.
 
- This file is part of DAP (Deus Applications Prototypes) the open source project
+ This file is part of DAP SDK the open source project
 
-    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
-    it under the terms of the GNU Lesser General Public License as published by
+    DAP SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
     the Free Software Foundation, either version 3 of the License, or
     (at your option) any later version.
 
-    DAP is distributed in the hope that it will be useful,
+    DAP SDK is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU Lesser General Public License for more details.
+    GNU General Public License for more details.
 
-    You should have received a copy of the GNU Lesser General Public License
-    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
+    You should have received a copy of the GNU General Public License
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
 */
-
-#ifndef _DAP_HTTP_FOLDER_H_
-#define _DAP_HTTP_FOLDER_H_
-
+#pragma once
 struct dap_http;
 
-extern int dap_http_folder_init();
-extern void dap_http_folder_deinit();
+int dap_http_folder_init(void);
+void dap_http_folder_deinit(void);
 
-extern int dap_http_folder_add(struct dap_http *sh, const char * url_path, const char * local_path); // Add folder for reading to the HTTP server
+int dap_http_folder_add(struct dap_http *sh, const char * url_path, const char * local_path); // Add folder for reading to the HTTP server
 
-#endif
diff --git a/dap-sdk/net/server/http_server/include/dap_http_simple.h b/dap-sdk/net/server/http_server/include/dap_http_simple.h
index 0dda2401f49d982c7528307fce9d706dc802f822..bd2ccc1a517751da27a8fa59ba8f3efcff42825f 100644
--- a/dap-sdk/net/server/http_server/include/dap_http_simple.h
+++ b/dap-sdk/net/server/http_server/include/dap_http_simple.h
@@ -35,28 +35,29 @@ struct dap_http_simple;
 typedef void ( *dap_http_simple_callback_t )( struct dap_http_simple *, void * );
 
 typedef struct dap_http_simple {
-
-  dap_http_client_t *http;
-
-  union {
-    void *request;
-    char *request_str;
-    uint8_t * request_byte;
-  };
-
-  union {
-    void *reply;
-    uint8_t *reply_byte;
-    char *reply_str;
-  };
-
-  size_t request_size;
-  size_t request_size_max;
-  size_t reply_size;
-  size_t reply_size_max;
-  size_t reply_sent;
-
-  char reply_mime[256];
+    dap_events_socket_t * esocket;
+    dap_worker_t * worker;
+    dap_http_client_t * http_client;
+    union {
+        void *request;
+        char *request_str;
+        uint8_t * request_byte;
+    };
+
+    union {
+        void *reply;
+        uint8_t *reply_byte;
+        char *reply_str;
+    };
+    size_t content_length;
+
+    size_t request_size;
+    size_t request_size_max;
+    size_t reply_size;
+    size_t reply_size_max;
+    size_t reply_sent;
+
+    char reply_mime[256];
 
    // dap_http_simple_callback_t reply_proc_post_callback;
 } dap_http_simple_t;
diff --git a/dap-sdk/net/stream/ch/dap_stream_ch.c b/dap-sdk/net/stream/ch/dap_stream_ch.c
index 2d589d439fe0fe1b0bc3dda5d079b1dab7fd70c1..b28f693ab8148ae67d6eaaf399d612a694a8fcf6 100644
--- a/dap-sdk/net/stream/ch/dap_stream_ch.c
+++ b/dap-sdk/net/stream/ch/dap_stream_ch.c
@@ -36,12 +36,13 @@
 #include <pthread.h>
 
 #include "dap_common.h"
-#include "dap_client_remote.h"
+#include "dap_events_socket.h"
 #include "dap_http_client.h"
 #include "dap_stream.h"
 #include "dap_stream_ch.h"
 #include "dap_stream_ch_proc.h"
 #include "dap_stream_ch_pkt.h"
+#include "dap_stream_worker.h"
 
 #define LOG_TAG "dap_stream_ch"
 
@@ -88,53 +89,50 @@ dap_stream_ch_t* dap_stream_ch_new(dap_stream_t* a_stream, uint8_t id)
 {
     stream_ch_proc_t * proc=stream_ch_proc_find(id);
     if(proc){
-        dap_stream_ch_t* ret = DAP_NEW_Z(dap_stream_ch_t);
-        ret->stream = a_stream;
-        ret->proc = proc;
-        ret->ready_to_read = true;
+        dap_stream_ch_t* l_ch_new = DAP_NEW_Z(dap_stream_ch_t);
+        l_ch_new->me = l_ch_new;
+        l_ch_new->stream = a_stream;
+        l_ch_new->proc = proc;
+        l_ch_new->ready_to_read = true;
 
-        pthread_mutex_init(&(ret->mutex),NULL);
-        if(ret->proc->new_callback)
-            ret->proc->new_callback(ret,NULL);
+        // Init on stream worker
+        dap_stream_worker_t * l_stream_worker = a_stream->stream_worker;
+        l_ch_new->stream_worker = l_stream_worker;
+        HASH_ADD(hh_worker,l_stream_worker->channels, me,sizeof (void*),l_ch_new);
 
-        pthread_rwlock_wrlock(&a_stream->rwlock);
-        a_stream->channel[ret->stream->channel_count] = ret;
+        pthread_mutex_init(&(l_ch_new->mutex),NULL);
+
+        // Proc new callback
+        if(l_ch_new->proc->new_callback)
+            l_ch_new->proc->new_callback(l_ch_new,NULL);
+
+        a_stream->channel[l_ch_new->stream->channel_count] = l_ch_new;
         a_stream->channel_count++;
-        pthread_rwlock_unlock(&a_stream->rwlock);
 
         struct dap_stream_ch_table_t *l_new_ch = DAP_NEW_Z(struct dap_stream_ch_table_t);
-        l_new_ch->ch = ret;
+        l_new_ch->ch = l_ch_new;
         pthread_mutex_lock(&s_ch_table_lock);
         HASH_ADD_PTR(s_ch_table, ch, l_new_ch);
         pthread_mutex_unlock(&s_ch_table_lock);
 
-        return ret;
+
+        return l_ch_new;
     }else{
         log_it(L_WARNING, "Unknown stream processor with id %uc",id);
         return NULL;
     }
 }
 
-struct dap_stream_ch_table_t *dap_stream_ch_valid(dap_stream_ch_t *a_ch)
-{
-    struct dap_stream_ch_table_t *l_ret;
-    if(!a_ch)
-        return false;
-    pthread_mutex_lock(&s_ch_table_lock);
-    HASH_FIND_PTR(s_ch_table, &a_ch, l_ret);
-    if (l_ret) {
-        pthread_mutex_lock(&a_ch->mutex);
-    }
-    pthread_mutex_unlock(&s_ch_table_lock);
-    return l_ret;
-}
-
 /**
  * @brief stream_ch_delete Delete channel instance
  * @param ch Channel delete
  */
 void dap_stream_ch_delete(dap_stream_ch_t *a_ch)
 {
+    dap_stream_worker_t * l_stream_worker = a_ch->stream_worker;
+    HASH_DELETE(hh_worker,l_stream_worker->channels, a_ch);
+
+
     pthread_mutex_lock(&s_ch_table_lock);
     struct dap_stream_ch_table_t *l_ret;;
     HASH_FIND_PTR(s_ch_table, &a_ch, l_ret);
@@ -170,24 +168,13 @@ void dap_stream_ch_delete(dap_stream_ch_t *a_ch)
  * @param a_ch
  * @param a_is_ready
  */
-void dap_stream_ch_set_ready_to_read(dap_stream_ch_t * a_ch,bool a_is_ready)
+void dap_stream_ch_set_ready_to_read_unsafe(dap_stream_ch_t * a_ch,bool a_is_ready)
 {
-    if (!dap_stream_ch_valid(a_ch)) {
-        return;
-    }
     if( a_ch->ready_to_read != a_is_ready){
         //log_it(L_DEBUG,"Change channel '%c' to %s", (char) ch->proc->id, is_ready?"true":"false");
         a_ch->ready_to_read=a_is_ready;
-        if(a_ch->stream->conn_udp)
-            dap_udp_client_ready_to_read(a_ch->stream->conn,a_is_ready);
-        // for stream server
-        else if(a_ch->stream->conn)
-            dap_client_remote_ready_to_read( a_ch->stream->conn,a_is_ready);
-        // for stream client
-        else if(a_ch->stream->events_socket)
-            dap_events_socket_set_readable( a_ch->stream->events_socket, a_is_ready);
+        dap_events_socket_set_readable_unsafe(a_ch->stream->esocket, a_is_ready);
     }
-    pthread_mutex_unlock(&a_ch->mutex);
 }
 
 /**
@@ -195,56 +182,14 @@ void dap_stream_ch_set_ready_to_read(dap_stream_ch_t * a_ch,bool a_is_ready)
  * @param ch
  * @param is_ready
  */
-void dap_stream_ch_set_ready_to_write(dap_stream_ch_t * ch,bool is_ready)
+void dap_stream_ch_set_ready_to_write_unsafe(dap_stream_ch_t * ch,bool is_ready)
 {
-    if (!dap_stream_ch_valid(ch)) {
-        return;
-    }
     if(ch->ready_to_write!=is_ready){
         //log_it(L_DEBUG,"Change channel '%c' to %s", (char) ch->proc->id, is_ready?"true":"false");
         ch->ready_to_write=is_ready;
         if(is_ready && ch->stream->conn_http)
             ch->stream->conn_http->state_write=DAP_HTTP_CLIENT_STATE_DATA;
-        if(ch->stream->conn_udp)
-            dap_udp_client_ready_to_write(ch->stream->conn,is_ready);
-        // for stream server
-        else if(ch->stream->conn)
-            dap_client_remote_ready_to_write(ch->stream->conn,is_ready);
-        // for stream client
-        else if(ch->stream->events_socket)
-            dap_events_socket_set_writable(ch->stream->events_socket, is_ready);
+        dap_events_socket_set_writable_unsafe(ch->stream->esocket, is_ready);
     }
-    pthread_mutex_unlock(&ch->mutex);
 }
 
-/**
- * @brief dap_stream_ch_get_ready_to_read
- * @param a_ch
- * @return
- */
-bool dap_stream_ch_get_ready_to_read(dap_stream_ch_t * a_ch)
-{
-    if (!dap_stream_ch_valid(a_ch)) {
-        return false;
-    }
-    bool l_ret;
-    l_ret = a_ch->ready_to_read;
-    pthread_mutex_unlock(&a_ch->mutex);
-    return l_ret;
-}
-
-/**
- * @brief dap_stream_ch_get_ready_to_write
- * @param a_ch
- * @return
- */
-bool dap_stream_ch_get_ready_to_write(dap_stream_ch_t * a_ch)
-{
-    if (!dap_stream_ch_valid(a_ch)) {
-        return false;
-    }
-    bool l_ret;
-    l_ret = a_ch->ready_to_write;
-    pthread_mutex_unlock(&a_ch->mutex);
-    return l_ret;
-}
diff --git a/dap-sdk/net/stream/ch/dap_stream_ch_pkt.c b/dap-sdk/net/stream/ch/dap_stream_ch_pkt.c
index db22f60fae5d208182e50fefebc60077ada7869d..ab462092341907aff6aa4fda8094bcdbc5c6bdb0 100644
--- a/dap-sdk/net/stream/ch/dap_stream_ch_pkt.c
+++ b/dap-sdk/net/stream/ch/dap_stream_ch_pkt.c
@@ -41,12 +41,13 @@
 #include "dap_enc.h"
 #include "dap_enc_key.h"
 
-#include "dap_client_remote.h"
+#include "dap_events_socket.h"
 #include "dap_stream.h"
 #include "dap_stream_ch.h"
 #include "dap_stream_ch_pkt.h"
 #include "dap_stream_ch_proc.h"
 #include "dap_stream_pkt.h"
+#include "dap_stream_worker.h"
 
 #define LOG_TAG "dap_stream_ch_pkt"
 
@@ -65,6 +66,92 @@ void dap_stream_ch_pkt_deinit()
 
 }
 
+/**
+ * @brief dap_stream_ch_pkt_write_f_mt
+ * @param a_ch
+ * @param a_type
+ * @param a_str
+ * @return
+ */
+size_t dap_stream_ch_pkt_write_f_mt(dap_stream_worker_t * a_worker , dap_stream_ch_t *a_ch, uint8_t a_type, const char * a_format,...)
+{
+    va_list ap;
+    va_start(ap,a_format);
+    int l_data_size = dap_vsnprintf(NULL,0,a_format,ap);
+    if (l_data_size <0 ){
+        log_it(L_ERROR,"Can't write out formatted data '%s' with values",a_format);
+        return 0;
+    }
+    l_data_size++; // To calc trailing zero
+    dap_stream_worker_msg_io_t * l_msg = DAP_NEW_Z(dap_stream_worker_msg_io_t);
+    l_msg->ch = a_ch;
+    l_msg->ch_pkt_type = a_type;
+    l_msg->data = DAP_NEW_SIZE(void,l_data_size);
+    l_msg->flags_set = DAP_SOCK_READY_TO_WRITE;
+    l_data_size = dap_vsnprintf(l_msg->data,0,a_format,ap);
+    if (l_data_size <0 ){
+        log_it(L_ERROR,"Can't write out formatted data '%s' with values",a_format);
+        DAP_DELETE(l_msg);
+        return 0;
+    }
+    l_data_size++;
+    l_msg->data_size = l_data_size;
+    int l_ret= dap_events_socket_queue_ptr_send(a_worker->queue_ch_io , l_msg );
+    if (l_ret!=0){
+        log_it(L_ERROR, "Wasn't send pointer to queue: code %d", l_ret);
+        DAP_DELETE(l_msg);
+        return 0;
+    }
+    return l_data_size;
+
+}
+
+/**
+ * @brief dap_stream_ch_pkt_write_mt
+ * @param a_ch
+ * @param a_type
+ * @param a_data
+ * @param a_data_size
+ * @return
+ */
+size_t dap_stream_ch_pkt_write_mt(dap_stream_worker_t * a_worker , dap_stream_ch_t *a_ch, uint8_t a_type, const void * a_data, size_t a_data_size)
+{
+    dap_stream_worker_msg_io_t * l_msg = DAP_NEW_Z(dap_stream_worker_msg_io_t);
+    l_msg->ch = a_ch;
+    l_msg->ch_pkt_type = a_type;
+    l_msg->data = DAP_NEW_SIZE(void,a_data_size);
+    l_msg->flags_set = DAP_SOCK_READY_TO_WRITE;
+    l_msg->data_size = a_data_size;
+    memcpy( l_msg->data, a_data, a_data_size);
+    int l_ret= dap_events_socket_queue_ptr_send(a_worker->queue_ch_io , l_msg );
+    if (l_ret!=0){
+        log_it(L_ERROR, "Wasn't send pointer to queue: code %d", l_ret);
+        DAP_DELETE(l_msg);
+        return 0;
+    }
+    return a_data_size;
+}
+
+/**
+ * @brief dap_stream_ch_check_unsafe
+ * @param a_worker
+ * @param a_ch
+ * @return
+ */
+bool dap_stream_ch_check_unsafe(dap_stream_worker_t * a_worker,dap_stream_ch_t * a_ch)
+{
+    if (a_ch){
+        if ( a_worker->channels){
+            dap_stream_ch_t * l_ch = NULL;
+            HASH_FIND(hh_worker,a_worker->channels ,&a_ch, sizeof(a_ch), l_ch );
+            return l_ch == a_ch;
+        }else
+            return false;
+    }else
+        return false;
+}
+
+
 
 /**
  * @brief stream_ch_pkt_write
@@ -73,16 +160,12 @@ void dap_stream_ch_pkt_deinit()
  * @param data_size
  * @return
  */
-size_t dap_stream_ch_pkt_write(struct dap_stream_ch * a_ch,  uint8_t a_type, const void * a_data, size_t a_data_size)
+size_t dap_stream_ch_pkt_write_unsafe(dap_stream_ch_t * a_ch,  uint8_t a_type, const void * a_data, size_t a_data_size)
 {
-    if (! a_data_size){
-        log_it(L_WARNING,"Zero data size to write out in channel");
-        return 0;
-    }
-    if (!dap_stream_ch_valid(a_ch)) {
+    if (!a_data_size || !a_ch || !a_data) {
+        log_it(L_WARNING, "NULL ptr or zero data size to write out in channel");
         return 0;
     }
-
     //log_it(L_DEBUG,"Output: Has %u bytes of %c type for %c channel id",data_size, (char)type, (char) ch->proc->id );
 
     dap_stream_ch_pkt_hdr_t l_hdr;
@@ -93,29 +176,34 @@ size_t dap_stream_ch_pkt_write(struct dap_stream_ch * a_ch,  uint8_t a_type, con
     l_hdr.type=a_type;
     l_hdr.enc_type = a_ch->proc->enc_type;
 
-    pthread_rwlock_wrlock(&a_ch->stream->rwlock);
     l_hdr.seq_id=a_ch->stream->seq_id;
     a_ch->stream->seq_id++;
-    pthread_rwlock_unlock(&a_ch->stream->rwlock);
 
     if ( dap_stream_get_dump_packet_headers() ){
         log_it(L_INFO,"Outgoing channel packet: id='%c' size=%u type=0x%02Xu seq_id=0x%016X enc_type=0x%02hhX",
             (char) l_hdr.id, l_hdr.size, l_hdr.type, l_hdr.seq_id , l_hdr.enc_type );
     }
 
+    uint8_t * l_buf_selected = a_ch->buf;
+    uint8_t * l_buf_allocated = NULL;
+    size_t  l_buf_size_required = a_data_size + sizeof(l_hdr);
 
-    if(a_data_size+sizeof(l_hdr)> sizeof(a_ch->buf) ){
-        log_it(L_ERROR,"Too big data size %lu, bigger than encryption buffer size %lu", a_data_size, sizeof(a_ch->buf));
-        a_data_size=sizeof(a_ch->buf)-sizeof(l_hdr);
+    if(l_buf_size_required > sizeof(a_ch->buf) ){
+        log_it(L_WARNING,"packet size is way too big: %lu bytes", a_data_size);
+        l_buf_allocated = DAP_NEW_Z_SIZE(uint8_t, l_buf_size_required);
+        l_buf_selected = l_buf_allocated;
     }
-    memcpy(a_ch->buf,&l_hdr,sizeof(l_hdr) );
+    
+    memcpy(l_buf_selected,&l_hdr,sizeof(l_hdr) );
     if( a_data_size )
-        memcpy(a_ch->buf+sizeof(l_hdr),a_data,a_data_size );
+        memcpy(l_buf_selected+sizeof(l_hdr),a_data,a_data_size );
 
-    size_t l_ret=dap_stream_pkt_write(a_ch->stream,a_ch->buf,a_data_size+sizeof(l_hdr));
+    size_t l_ret=dap_stream_pkt_write_unsafe(a_ch->stream,l_buf_selected,a_data_size+sizeof(l_hdr));
     a_ch->stat.bytes_write+=a_data_size;
     a_ch->ready_to_write=true;
-    pthread_mutex_unlock( &a_ch->mutex);
+
+    if(l_buf_allocated)
+        DAP_DELETE(l_buf_allocated);
     return l_ret;
 
 }
@@ -126,14 +214,13 @@ size_t dap_stream_ch_pkt_write(struct dap_stream_ch * a_ch,  uint8_t a_type, con
  * @param str
  * @return
  */
-size_t dap_stream_ch_pkt_write_f(struct dap_stream_ch * a_ch, uint8_t a_type, const char * a_str,...)
+size_t dap_stream_ch_pkt_write_f_unsafe(struct dap_stream_ch * a_ch, uint8_t a_type, const char * a_str,...)
 {
     char l_buf[4096];
     va_list ap;
     va_start(ap,a_str);
     dap_vsnprintf(l_buf,sizeof(l_buf),a_str,ap);
     va_end(ap);
-    size_t ret=dap_stream_ch_pkt_write(a_ch,a_type,l_buf,strlen(l_buf));
+    size_t ret=dap_stream_ch_pkt_write_unsafe(a_ch,a_type,l_buf,strlen(l_buf));
     return ret;
 }
-
diff --git a/dap-sdk/net/stream/ch/include/dap_stream_ch.h b/dap-sdk/net/stream/ch/include/dap_stream_ch.h
index ff3368e064f2d65e0a8163696c78a687f7bf2eb9..a4da8d255f3d8d2f6b266eef94f699fdaae96ef6 100644
--- a/dap-sdk/net/stream/ch/include/dap_stream_ch.h
+++ b/dap-sdk/net/stream/ch/include/dap_stream_ch.h
@@ -23,8 +23,9 @@
 #include <stdbool.h>
 #include <pthread.h>
 #include <stdint.h>
-
+#include "uthash.h"
 typedef struct dap_stream dap_stream_t;
+typedef struct dap_stream_worker dap_stream_worker_t;
 typedef struct dap_stream_pkt dap_stream_pkt_t;
 typedef struct dap_stream_ch_proc dap_stream_ch_proc_t;
 typedef struct dap_stream_ch dap_stream_ch_t;
@@ -39,6 +40,7 @@ typedef struct dap_stream_ch{
     bool ready_to_write;
     bool ready_to_read;
     dap_stream_t * stream;
+    dap_stream_worker_t * stream_worker;
     struct{
         uint64_t bytes_write;
         uint64_t bytes_read;
@@ -48,21 +50,17 @@ typedef struct dap_stream_ch{
 
     dap_stream_ch_proc_t * proc;
     void * internal;
+    struct dap_stream_ch *me;
+    UT_hash_handle hh_worker;
 } dap_stream_ch_t;
 
 int dap_stream_ch_init();
 void dap_stream_ch_deinit();
 
 dap_stream_ch_t* dap_stream_ch_new( dap_stream_t * dap_stream,uint8_t id);
-
-void dap_stream_ch_set_ready_to_read(dap_stream_ch_t * ch,bool is_ready);
-void dap_stream_ch_set_ready_to_write(dap_stream_ch_t * ch,bool is_ready);
-
-bool dap_stream_ch_get_ready_to_read(dap_stream_ch_t *a_ch);
-bool dap_stream_ch_get_ready_to_write(dap_stream_ch_t *a_ch);
-
+void dap_stream_ch_set_ready_to_read_unsafe(dap_stream_ch_t * ch,bool is_ready);
+void dap_stream_ch_set_ready_to_write_unsafe(dap_stream_ch_t * ch,bool is_ready);
 void dap_stream_ch_delete(dap_stream_ch_t *a_ch);
 
-struct dap_stream_ch_table_t *dap_stream_ch_valid(dap_stream_ch_t *a_ch);
 
 #endif
diff --git a/dap-sdk/net/stream/ch/include/dap_stream_ch_pkt.h b/dap-sdk/net/stream/ch/include/dap_stream_ch_pkt.h
index 24049870056463045363967e8066fa5209162ffc..47dfac6ebf540ba7bb56f772575480683ab6d252 100644
--- a/dap-sdk/net/stream/ch/include/dap_stream_ch_pkt.h
+++ b/dap-sdk/net/stream/ch/include/dap_stream_ch_pkt.h
@@ -1,5 +1,5 @@
 /*
- Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc
+ Copyright (c) 2020 (c) DeM Labs Ltd http://demlabs.net
   All rights reserved.
 
  This file is part of DAP (Deus Applications Prototypes) the open source project
@@ -26,7 +26,13 @@
 
 #include <stdint.h>
 #include <stddef.h>
-struct dap_stream_ch;
+
+#include "dap_enc_key.h"
+
+typedef struct dap_stream_ch dap_stream_ch_t;
+typedef struct dap_stream_session dap_stream_session_t;
+typedef struct dap_events_socket dap_events_socket_t;
+typedef struct dap_stream_worker dap_stream_worker_t;
 typedef struct dap_stream_ch_pkt_hdr{
     uint8_t id;   // Channel id
     uint8_t enc_type; // Zero if not encrypted
@@ -45,6 +51,10 @@ typedef struct dap_stream_ch_pkt{
 int dap_stream_ch_pkt_init();
 void dap_stream_ch_pkt_deinit();
 
-size_t dap_stream_ch_pkt_write_f(struct dap_stream_ch * a_ch, uint8_t a_type, const char * a_str,...);
-size_t dap_stream_ch_pkt_write(struct dap_stream_ch * a_ch,  uint8_t a_type, const void * a_data, size_t a_data_size);
+size_t dap_stream_ch_pkt_write_f_unsafe(struct dap_stream_ch * a_ch, uint8_t a_type, const char * a_str,...);
+size_t dap_stream_ch_pkt_write_unsafe(struct dap_stream_ch * a_ch,  uint8_t a_type, const void * a_data, size_t a_data_size);
+
+bool dap_stream_ch_check_unsafe(dap_stream_worker_t * a_worker,dap_stream_ch_t * a_ch);
 
+size_t dap_stream_ch_pkt_write_f_mt(dap_stream_worker_t * a_worker , dap_stream_ch_t *a_ch, uint8_t a_type, const char * a_str,...);
+size_t dap_stream_ch_pkt_write_mt(dap_stream_worker_t * a_worker , dap_stream_ch_t *a_ch,  uint8_t a_type, const void * a_data, size_t a_data_size);
diff --git a/dap-sdk/net/stream/ch/include/dap_stream_ch_proc.h b/dap-sdk/net/stream/ch/include/dap_stream_ch_proc.h
index 1847aa42bfd323b28cf39bf550a1c448958856dd..f3ea2c410c3e1c3b78329ba964816d05e03ab05f 100644
--- a/dap-sdk/net/stream/ch/include/dap_stream_ch_proc.h
+++ b/dap-sdk/net/stream/ch/include/dap_stream_ch_proc.h
@@ -37,14 +37,14 @@ typedef struct dap_stream_ch_proc{
     void * internal;
 } stream_ch_proc_t;
 
-extern int stream_ch_proc_init();
-extern void stream_ch_proc_deinit();
+int stream_ch_proc_init();
+void stream_ch_proc_deinit();
 
-extern void dap_stream_ch_proc_add(uint8_t id,
+void dap_stream_ch_proc_add(uint8_t id,
                           dap_stream_ch_callback_t new_callback, dap_stream_ch_callback_t delete_callback,
                           dap_stream_ch_callback_t packet_in_callback,
                           dap_stream_ch_callback_t packet_out_callback
                           );
-extern stream_ch_proc_t* stream_ch_proc_find(uint8_t id);
+stream_ch_proc_t* stream_ch_proc_find(uint8_t id);
 
 #endif
diff --git a/dap-sdk/net/stream/session/dap_stream_session.c b/dap-sdk/net/stream/session/dap_stream_session.c
index d2faca7c9e40c7560d7902e39ac508d05572b94d..1dcfa0c62168210cf60170b677c5b31e0dbfe74b 100644
--- a/dap-sdk/net/stream/session/dap_stream_session.c
+++ b/dap-sdk/net/stream/session/dap_stream_session.c
@@ -38,7 +38,7 @@
 #define LOG_TAG "dap_stream_session"
 
 dap_stream_session_t * sessions=NULL;
-
+pthread_mutex_t sessions_mutex = PTHREAD_MUTEX_INITIALIZER;
 int stream_session_close2(dap_stream_session_t * s);
 static void * session_check(void * data);
 
@@ -52,27 +52,16 @@ void dap_stream_session_deinit()
 {
     dap_stream_session_t *current, *tmp;
     log_it(L_INFO,"Destroy all the sessions");
-
+    pthread_mutex_lock(&sessions_mutex);
       HASH_ITER(hh, sessions, current, tmp) {
           HASH_DEL(sessions,current);
-          stream_session_close2(current);
-      }
-}
-
-void dap_stream_session_list()
-{
-    dap_stream_session_t *current, *tmp;
-
-    log_it(L_INFO,"=== sessions list ======");
-
-      HASH_ITER( hh, sessions, current, tmp ) {
-      log_it(L_INFO,"ID %u session %X", current->id, current);
-
-//          HASH_DEL(sessions,current);
-//          stream_session_close2(current);
+          if (current->callback_delete)
+              current->callback_delete(current, NULL);
+          if (current->_inheritor )
+              DAP_DELETE(current->_inheritor);
+          DAP_DELETE(current);
       }
-
-    log_it(L_INFO,"=== sessions list ======");
+    pthread_mutex_unlock(&sessions_mutex);
 }
 
 
@@ -99,8 +88,9 @@ dap_stream_session_t * dap_stream_session_pure_new()
     ret->create_empty=true;
     ret->enc_type = 0x01; // Default encryption type
     log_it(L_DEBUG,"Timestamp %u",(unsigned int) ret->time_created);
+    pthread_mutex_lock(&sessions_mutex);
     HASH_ADD_INT(sessions,id,ret);
-
+    pthread_mutex_unlock(&sessions_mutex);
     return ret;
 }
 
@@ -114,29 +104,64 @@ dap_stream_session_t * dap_stream_session_new(unsigned int media_id, bool open_p
     return ret;
 }
 
-dap_stream_session_t *dap_stream_session_id( unsigned int id )
+/**
+ * @brief dap_stream_session_id_mt
+ * @param id
+ * @return
+ */
+dap_stream_session_t *dap_stream_session_id_mt( unsigned int id )
 {
     dap_stream_session_t *ret;
+    dap_stream_session_lock();
     HASH_FIND_INT( sessions, &id, ret );
+    dap_stream_session_unlock();
+    return ret;
+}
 
+/**
+ * @brief dap_stream_session_id_unsafe
+ * @param id
+ * @return
+ */
+dap_stream_session_t *dap_stream_session_id_unsafe( unsigned int id )
+{
+    dap_stream_session_t *ret;
+    HASH_FIND_INT( sessions, &id, ret );
     return ret;
 }
 
+/**
+ * @brief dap_stream_session_lock
+ */
+void dap_stream_session_lock()
+{
+    pthread_mutex_lock(&sessions_mutex);
+}
+
+/**
+ * @brief dap_stream_session_unlock
+ */
+void dap_stream_session_unlock()
+{
+    pthread_mutex_unlock(&sessions_mutex);
+}
 
-int dap_stream_session_close(unsigned int id)
+
+int dap_stream_session_close_mt(unsigned int id)
 {
     log_it(L_INFO,"Close session id %u", id);
 
 //    dap_stream_session_list();
-
-    dap_stream_session_t *l_s = dap_stream_session_id( id );
-
+    dap_stream_session_lock();
+    dap_stream_session_t *l_s = dap_stream_session_id_unsafe( id );
     if(!l_s) {
         log_it(L_WARNING, "Session id %u not found", id);
         return -1;
     }
 
-    return stream_session_close2(l_s);
+    int ret = stream_session_close2(l_s);
+    dap_stream_session_unlock();
+    return ret;
 }
 
 int stream_session_close2(dap_stream_session_t * a_session)
diff --git a/dap-sdk/net/stream/session/include/dap_stream_session.h b/dap-sdk/net/stream/session/include/dap_stream_session.h
index 2f8d9e624d23a5eebb694515b06796f31aac87f7..921c9ff700227301a39eef1d946e699925796eb7 100644
--- a/dap-sdk/net/stream/session/include/dap_stream_session.h
+++ b/dap-sdk/net/stream/session/include/dap_stream_session.h
@@ -72,7 +72,11 @@ void dap_stream_session_deinit();
 
 dap_stream_session_t * dap_stream_session_pure_new();
 dap_stream_session_t * dap_stream_session_new(unsigned int media_id, bool open_preview);
-dap_stream_session_t * dap_stream_session_id(unsigned int id);
+dap_stream_session_t * dap_stream_session_id_mt(unsigned int id);
+dap_stream_session_t *dap_stream_session_id_unsafe( unsigned int id );
+void dap_stream_session_lock();
+void dap_stream_session_unlock();
+
 int dap_stream_session_open(dap_stream_session_t * a_session); /*Lock for opening for single client , return 0 if ok*/
-int dap_stream_session_close(unsigned int id);
+int dap_stream_session_close_mt(unsigned int id);
 
diff --git a/dap-sdk/net/stream/stream/dap_stream.c b/dap-sdk/net/stream/stream/dap_stream.c
index ee3b1fd7d5abeee6d461ae2c2d310fd1735fe5fe..35b1dc91dc4cc1c10d8a467f1eef7a603cb5719a 100644
--- a/dap-sdk/net/stream/stream/dap_stream.c
+++ b/dap-sdk/net/stream/stream/dap_stream.c
@@ -26,6 +26,8 @@
 #include <stdint.h>
 #include <unistd.h>
 
+#include <mqueue.h>
+
 #ifdef _WIN32
 #include <winsock2.h>
 #include <windows.h>
@@ -45,33 +47,32 @@
 #include "dap_stream_session.h"
 #include "dap_events_socket.h"
 
-#include "dap_client_remote.h"
 #include "dap_http.h"
 #include "dap_http_client.h"
 #include "dap_http_header.h"
 #include "dap_udp_server.h"
+#include "dap_stream_worker.h"
 
-
-#define LOG_TAG "stream"
+#define LOG_TAG "dap_stream"
 #define HEADER_WITH_SIZE_FIELD 12  //This count of bytes enough for allocate memory for stream packet
 
-void stream_proc_pkt_in(dap_stream_t * sid);
+static void s_stream_proc_pkt_in(dap_stream_t * a_stream);
 
 // Callbacks for HTTP client
-void stream_headers_read(dap_http_client_t * sh, void * arg); // Prepare stream when all headers are read
+static void s_http_client_headers_read(dap_http_client_t * a_http_client, void * a_arg); // Prepare stream when all headers are read
 
-void s_headers_write(dap_http_client_t * sh, void * arg); // Output headers
-void s_data_write(dap_http_client_t * sh, void * arg); // Write the data
-void stream_data_read(dap_http_client_t * sh, void * arg); // Read the data
+static void s_http_client_headers_write(dap_http_client_t * a_http_client, void * a_arg); // Output headers
+static void s_http_client_data_write(dap_http_client_t * a_http_client, void * a_arg); // Write the data
+static void s_http_client_data_read(dap_http_client_t * a_http_client, void * a_arg); // Read the data
 
-void s_data_read(dap_client_remote_t* sh, void * arg);
-void stream_dap_data_write(dap_client_remote_t* sh, void * arg);
-void stream_dap_delete(dap_client_remote_t* sh, void * arg);
-void stream_dap_new(dap_client_remote_t* sh,void * arg);
+static void s_esocket_data_read(dap_events_socket_t* a_esocket, void * a_arg);
+static void s_esocket_write(dap_events_socket_t* a_esocket, void * a_arg);
+static void s_esocket_callback_delete(dap_events_socket_t* a_esocket, void * a_arg);
+static void s_udp_esocket_new(dap_events_socket_t* a_esocket,void * a_arg);
 
 // Internal functions
-dap_stream_t * stream_new(dap_http_client_t * a_sh); // Create new stream
-void stream_delete(dap_http_client_t * sh, void * arg);
+static dap_stream_t * s_stream_new(dap_http_client_t * a_http_client); // Create new stream
+static void s_http_client_delete(dap_http_client_t * a_esocket, void * a_arg);
 
 //struct ev_loop *keepalive_loop;
 pthread_t keepalive_thread;
@@ -79,8 +80,7 @@ pthread_t keepalive_thread;
 static dap_stream_t  *s_stream_keepalive_list = NULL;
 static pthread_mutex_t s_mutex_keepalive_list;
 
-static void start_keepalive( dap_stream_t *sid );
-static void keepalive_cb( void );
+static void s_keepalive_cb( void );
 
 static bool s_keep_alive_loop_quit_signal = false;
 static bool s_dump_packet_headers = false;
@@ -88,28 +88,7 @@ static bool s_dump_packet_headers = false;
 bool dap_stream_get_dump_packet_headers(){ return  s_dump_packet_headers; }
 
 static struct timespec keepalive_loop_sleep = { 0, STREAM_KEEPALIVE_TIMEOUT * 1000 * 1000  };
-
-// Start keepalive stream
-static void *stream_loop( void *arg )
-{
-    UNUSED(arg);
-//    keepalive_loop = ev_loop_new(0);
-//    ev_loop(keepalive_loop, 0);
-  do {
-
-    #ifndef _WIN32
-      //nanosleep( &keepalive_loop_sleep, NULL );
-      sleep( STREAM_KEEPALIVE_TIMEOUT );
-    #else
-      Sleep( STREAM_KEEPALIVE_TIMEOUT * 1000 );
-    #endif
-
-    keepalive_cb( );
-
-  } while ( !s_keep_alive_loop_quit_signal );
-
-  return NULL;
-}
+static bool s_detect_loose_packet(dap_stream_t * a_stream);
 
 /**
  * @brief stream_init Init stream module
@@ -121,10 +100,13 @@ int dap_stream_init( bool a_dump_packet_headers)
         log_it(L_CRITICAL, "Can't init channel types submodule");
         return -1;
     }
-    s_dump_packet_headers = a_dump_packet_headers;
+    if( dap_stream_worker_init() != 0 ){
+        log_it(L_CRITICAL, "Can't init stream worker extention submodule");
+        return -2;
+    }
 
+    s_dump_packet_headers = a_dump_packet_headers;
     s_keep_alive_loop_quit_signal = false;
-
     pthread_mutex_init( &s_mutex_keepalive_list, NULL );
     //pthread_create( &keepalive_thread, NULL, stream_loop, NULL );
 
@@ -151,114 +133,63 @@ void dap_stream_deinit()
  * @param sh HTTP server instance
  * @param url URL
  */
-void dap_stream_add_proc_http(struct dap_http * sh, const char * url)
+void dap_stream_add_proc_http(struct dap_http * a_http, const char * a_url)
 {
-    dap_http_add_proc(sh,url,NULL,NULL,stream_delete,stream_headers_read,s_headers_write,stream_data_read,s_data_write,NULL);
+    dap_http_add_proc(a_http,a_url
+                      ,NULL, // _internal
+                      NULL, // New
+                      s_http_client_delete, // Delete
+                      s_http_client_headers_read, // Headers read
+                      s_http_client_headers_write, // Headerts write
+                      s_http_client_data_read, // Data read
+                      s_http_client_data_write, // Data write
+                      NULL); // Error callback
 }
 
 /**
  * @brief stream_add_proc_udp Add processor callback for streaming
- * @param sh UDP server instance
+ * @param a_udp_server UDP server instance
  */
-void dap_stream_add_proc_udp(dap_udp_server_t * sh)
+void dap_stream_add_proc_udp(dap_udp_server_t * a_udp_server)
 {
-    dap_server_t* server =  sh->dap_server;
-    server->client_read_callback = s_data_read;
-    server->client_write_callback = stream_dap_data_write;
-    server->client_delete_callback = stream_dap_delete;
-    server->client_new_callback = stream_dap_new;
+    dap_server_t* l_server =  a_udp_server->dap_server;
+    l_server->client_callbacks.read_callback = s_esocket_data_read;
+    l_server->client_callbacks.write_callback = s_esocket_write;
+    l_server->client_callbacks.delete_callback = s_esocket_callback_delete;
+    l_server->client_callbacks.new_callback = s_udp_esocket_new;
 }
 
 /**
  * @brief stream_states_update
- * @param sid stream instance
+ * @param a_stream stream instance
  */
-void stream_states_update(struct dap_stream *sid)
+void stream_states_update(struct dap_stream *a_stream)
 {
-    if(sid->conn_http)
-        sid->conn_http->state_write=DAP_HTTP_CLIENT_STATE_START;
+    if(a_stream->conn_http)
+        a_stream->conn_http->state_write=DAP_HTTP_CLIENT_STATE_START;
     size_t i;
     bool ready_to_write=false;
-    for(i=0;i<sid->channel_count; i++)
-        ready_to_write|=sid->channel[i]->ready_to_write;
-    if(sid->conn_udp)
-        dap_udp_client_ready_to_write(sid->conn_udp->client,ready_to_write);
-    else
-        dap_client_remote_ready_to_write(sid->conn,ready_to_write);
-    if(sid->conn_http)
-        sid->conn_http->out_content_ready=true;
+    for(i=0;i<a_stream->channel_count; i++)
+        ready_to_write|=a_stream->channel[i]->ready_to_write;
+    dap_events_socket_set_writable_unsafe(a_stream->esocket,ready_to_write);
+    if(a_stream->conn_http)
+        a_stream->conn_http->out_content_ready=true;
 }
 
-/**
- * @brief stream_header_read Read headers callback for HTTP
- * @param cl_ht HTTP client structure
- * @param arg Not used
- */
-void stream_headers_read(dap_http_client_t * cl_ht, void * arg)
-{
-    (void) arg;
 
-   // char * raw=0;
-   // int raw_size;
-    unsigned int id=0;
-
-//    log_it(L_DEBUG,"Prepare data stream");
-    if(cl_ht->in_query_string[0]){
-        log_it(L_INFO,"Query string [%s]",cl_ht->in_query_string);
-//        if(sscanf(cl_ht->in_query_string,"fj913htmdgaq-d9hf=%u",&id)==1){
-        if(sscanf(cl_ht->in_query_string,"session_id=%u",&id) == 1 ||
-                sscanf(cl_ht->in_query_string,"fj913htmdgaq-d9hf=%u",&id) == 1) {
-            dap_stream_session_t * ss=NULL;
-            ss=dap_stream_session_id(id);
-            if(ss==NULL){
-                log_it(L_ERROR,"No session id %u was found",id);
-                cl_ht->reply_status_code=404;
-                strcpy(cl_ht->reply_reason_phrase,"Not found");
-            }else{
-                log_it(L_INFO,"Session id %u was found with channels = %s",id,ss->active_channels);
-                if(dap_stream_session_open(ss)==0){ // Create new stream
-                    dap_stream_t * sid = stream_new(cl_ht);
-                    sid->session=ss;
-                    dap_http_header_t *header = dap_http_header_find(cl_ht->in_headers, "Service-Key");
-                    if (header)
-                        ss->service_key = strdup(header->value);
-                    size_t count_channels = strlen(ss->active_channels);
-                    for(size_t i = 0; i < count_channels; i++) {
-                        dap_stream_ch_new(sid, ss->active_channels[i]);
-                        //sid->channel[i]->ready_to_write = true;
-                    }
-
-                    cl_ht->reply_status_code=200;
-                    strcpy(cl_ht->reply_reason_phrase,"OK");
-                    cl_ht->state_read=DAP_HTTP_CLIENT_STATE_DATA;
-                    dap_client_remote_ready_to_read(cl_ht->client,true);
-
-                    stream_states_update(sid);
-                }else{
-                    log_it(L_ERROR,"Can't open session id %u",id);
-                    cl_ht->reply_status_code=404;
-                    strcpy(cl_ht->reply_reason_phrase,"Not found");
-                }
-            }
-        }
-    }else{
-        log_it(L_ERROR,"No query string");
-    }
-}
 
 /**
  * @brief stream_new_udp Create new stream instance for UDP client
  * @param sh DAP client structure
  */
-dap_stream_t * stream_new_udp(dap_client_remote_t * sh)
+dap_stream_t * stream_new_udp(dap_events_socket_t * a_esocket)
 {
     dap_stream_t * ret=(dap_stream_t*) calloc(1,sizeof(dap_stream_t));
 
-    ret->conn = sh;
-    ret->conn_udp=sh->_inheritor;
+    ret->esocket = a_esocket;
     ret->buf_defrag_size = 0;
 
-    sh->_internal=ret;
+    a_esocket->_inheritor = ret;
 
     log_it(L_NOTICE,"New stream instance udp");
     return ret;
@@ -269,11 +200,11 @@ dap_stream_t * stream_new_udp(dap_client_remote_t * sh)
  * @param id session id
  * @param cl DAP client structure
  */
-void check_session( unsigned int a_id, dap_client_remote_t *a_client_remote )
+void check_session( unsigned int a_id, dap_events_socket_t *a_esocket )
 {
     dap_stream_session_t *l_session = NULL;
 
-    l_session = dap_stream_session_id( a_id );
+    l_session = dap_stream_session_id_mt( a_id );
 
     if ( l_session == NULL ) {
         log_it(L_ERROR,"No session id %u was found",a_id);
@@ -289,11 +220,11 @@ void check_session( unsigned int a_id, dap_client_remote_t *a_client_remote )
     }
 
     dap_stream_t *l_stream;
-
-    if ( DAP_STREAM(a_client_remote) == NULL )
-        l_stream = stream_new_udp( a_client_remote );
+    dap_http_client_t *l_http_client = DAP_HTTP_CLIENT(a_esocket);
+    if ( DAP_STREAM(l_http_client) == NULL )
+        l_stream = stream_new_udp( a_esocket );
     else
-        l_stream = DAP_STREAM( a_client_remote );
+        l_stream = DAP_STREAM( l_http_client );
 
     l_stream->session = l_session;
 
@@ -302,42 +233,43 @@ void check_session( unsigned int a_id, dap_client_remote_t *a_client_remote )
 
     log_it( L_INFO, "Opened stream session technical and data channels" );
 
-    size_t count_channels = strlen(l_session->active_channels);
+    //size_t count_channels = strlen(l_session->active_channels);
     for (size_t i =0; i<sizeof (l_session->active_channels); i++ )
         if ( l_session->active_channels[i])
             dap_stream_ch_new( l_stream, l_session->active_channels[i] );
 
     stream_states_update( l_stream );
 
-    if ( DAP_STREAM(a_client_remote)->conn_udp )
-        dap_udp_client_ready_to_read( a_client_remote, true );
-    else
-        dap_client_remote_ready_to_read( a_client_remote, true );
+    dap_events_socket_set_readable_unsafe( a_esocket, true );
 
-    start_keepalive( l_stream );
 }
 
 /**
  * @brief stream_new Create new stream instance for HTTP client
  * @return New stream_t instance
  */
-dap_stream_t * stream_new(dap_http_client_t * a_sh)
+dap_stream_t * s_stream_new(dap_http_client_t * a_http_client)
 {
-    dap_stream_t * ret=(dap_stream_t*) calloc(1,sizeof(dap_stream_t));
+    dap_stream_t * ret= DAP_NEW_Z(dap_stream_t);
 
-    pthread_rwlock_init( &ret->rwlock, NULL);
-    ret->conn = a_sh->client;
-    ret->conn_http=a_sh;
+    ret->esocket = a_http_client->esocket;
+    ret->stream_worker = (dap_stream_worker_t*) a_http_client->esocket->worker->_inheritor;
+    ret->conn_http=a_http_client;
     ret->buf_defrag_size = 0;
     ret->seq_id = 0;
     ret->client_last_seq_id_packet = (size_t)-1;
 
-    ret->conn->_internal=ret;
+    a_http_client->_inheritor=ret;
 
     log_it(L_NOTICE,"New stream instance");
     return ret;
 }
 
+
+/**
+ * @brief dap_stream_delete
+ * @param a_stream
+ */
 void dap_stream_delete(dap_stream_t *a_stream)
 {
     if(a_stream == NULL) {
@@ -348,21 +280,16 @@ void dap_stream_delete(dap_stream_t *a_stream)
     if(s_stream_keepalive_list){
         DL_DELETE(s_stream_keepalive_list, a_stream);
     }
-    a_stream->conn_udp = NULL;
-    a_stream->conn = NULL;
-    a_stream->events_socket = NULL;
     pthread_mutex_unlock(&s_mutex_keepalive_list);
 
     while (a_stream->channel_count) {
         dap_stream_ch_delete(a_stream->channel[a_stream->channel_count - 1]);
     }
 
-    pthread_rwlock_wrlock(&a_stream->rwlock);
     if(a_stream->session)
-        dap_stream_session_close(a_stream->session->id);
+        dap_stream_session_close_mt(a_stream->session->id); // TODO make stream close after timeout, not momentaly
     a_stream->session = NULL;
-    pthread_rwlock_unlock(&a_stream->rwlock);
-    pthread_rwlock_destroy(&a_stream->rwlock);
+    a_stream->esocket = NULL;
     DAP_DELETE(a_stream);
     log_it(L_NOTICE,"Stream connection is over");
 }
@@ -372,12 +299,14 @@ void dap_stream_delete(dap_stream_t *a_stream)
  * @param sh DAP client instance
  * @param arg Not used
  */
-void stream_dap_delete(dap_client_remote_t* sh, void * arg)
+static void s_esocket_callback_delete(dap_events_socket_t* a_esocket, void * a_arg)
 {
-    UNUSED(arg);
-    if (!sh)
+    UNUSED(a_arg);
+    if (!a_esocket)
         return;
-    dap_stream_t *l_stream = DAP_STREAM(sh);
+    dap_http_client_t *l_http_client = DAP_HTTP_CLIENT(a_esocket);
+    dap_stream_t *l_stream = DAP_STREAM(l_http_client);
+    l_http_client->_inheritor = NULL; // To prevent double free
     dap_stream_delete(l_stream);
 }
 
@@ -387,41 +316,16 @@ void stream_dap_delete(dap_client_remote_t* sh, void * arg)
  * @param a_es
  * @return
  */
-dap_stream_t* dap_stream_new_es(dap_events_socket_t * a_es)
+dap_stream_t* dap_stream_new_es_client(dap_events_socket_t * a_esocket)
 {
     dap_stream_t * ret= DAP_NEW_Z(dap_stream_t);
-    pthread_rwlock_init( &ret->rwlock, NULL);
-    ret->events_socket = a_es;
+    ret->esocket = a_esocket;
     ret->buf_defrag_size=0;
     ret->is_client_to_uplink = true;
-
-    log_it(L_NOTICE,"New stream with events socket instance for %s",a_es->hostaddr);
+    log_it(L_NOTICE,"New stream with events socket instance for %s",a_esocket->hostaddr);
     return ret;
 }
 
-/**
- * @brief s_headers_write Prepare headers for output. Creates stream structure
- * @param sh HTTP client instance
- * @param arg Not used
- */
-void s_headers_write(dap_http_client_t * sh, void *arg)
-{
-    (void) arg;
-
-    if(sh->reply_status_code==200){
-        dap_stream_t *sid=DAP_STREAM(sh->client);
-
-        dap_http_out_header_add(sh,"Content-Type","application/octet-stream");
-        dap_http_out_header_add(sh,"Connnection","keep-alive");
-        dap_http_out_header_add(sh,"Cache-Control","no-cache");
-
-        if(sid->stream_size>0)
-            dap_http_out_header_add_f(sh,"Content-Length","%u", (unsigned int) sid->stream_size );
-
-        sh->state_read=DAP_HTTP_CLIENT_STATE_DATA;
-        dap_client_remote_ready_to_read(sh->client,true);
-    }
-}
 
 /**
  Function for keepalive loop
@@ -442,75 +346,195 @@ static void keepalive_cb (EV_P_ ev_timer *w, int revents)
 }
 **/
 
-static void keepalive_cb( void )
-{
-  dap_stream_t  *l_stream, *tmp;
-  return;
-  pthread_mutex_lock( &s_mutex_keepalive_list );
-  DL_FOREACH_SAFE( s_stream_keepalive_list, l_stream, tmp ) {
-    if ( l_stream->keepalive_passed < STREAM_KEEPALIVE_PASSES ) {
-      dap_stream_send_keepalive( l_stream );
-      l_stream->keepalive_passed += 1;
-    }
-    else {
-      log_it( L_INFO, "Client disconnected" );
-      DL_DELETE( s_stream_keepalive_list, l_stream );
-      stream_dap_delete( l_stream->conn, NULL );
-    }
-  }
 
-  pthread_mutex_unlock( &s_mutex_keepalive_list );
-}
+/**
+ * @brief stream_header_read Read headers callback for HTTP
+ * @param a_http_client HTTP client structure
+ * @param a_arg Not used
+ */
+void s_http_client_headers_read(dap_http_client_t * a_http_client, void * a_arg)
+{
+    (void) a_arg;
 
+   // char * raw=0;
+   // int raw_size;
+    unsigned int id=0;
 
+    //log_it(L_DEBUG,"Prepare data stream");
+    if(a_http_client->in_query_string[0]){
+        log_it(L_INFO,"Query string [%s]",a_http_client->in_query_string);
+//        if(sscanf(cl_ht->in_query_string,"fj913htmdgaq-d9hf=%u",&id)==1){
+        if(sscanf(a_http_client->in_query_string,"session_id=%u",&id) == 1 ||
+                sscanf(a_http_client->in_query_string,"fj913htmdgaq-d9hf=%u",&id) == 1) {
+            dap_stream_session_t * ss=NULL;
+            ss=dap_stream_session_id_mt(id);
+            if(ss==NULL){
+                log_it(L_ERROR,"No session id %u was found",id);
+                a_http_client->reply_status_code=404;
+                strcpy(a_http_client->reply_reason_phrase,"Not found");
+            }else{
+                log_it(L_INFO,"Session id %u was found with channels = %s",id,ss->active_channels);
+                if(dap_stream_session_open(ss)==0){ // Create new stream
+                    dap_stream_t * sid = s_stream_new(a_http_client);
+                    sid->session=ss;
+                    dap_http_header_t *header = dap_http_header_find(a_http_client->in_headers, "Service-Key");
+                    if (header)
+                        ss->service_key = strdup(header->value);
+                    size_t count_channels = strlen(ss->active_channels);
+                    for(size_t i = 0; i < count_channels; i++) {
+                        dap_stream_ch_t * l_ch = dap_stream_ch_new(sid, ss->active_channels[i]);
+                        l_ch->ready_to_read = true;
+                        //sid->channel[i]->ready_to_write = true;
+                    }
 
+                    a_http_client->reply_status_code=200;
+                    strcpy(a_http_client->reply_reason_phrase,"OK");
+                    stream_states_update(sid);
+                    a_http_client->state_read=DAP_HTTP_CLIENT_STATE_DATA;
+                    a_http_client->state_write=DAP_HTTP_CLIENT_STATE_START;
+                    dap_events_socket_set_readable_unsafe(a_http_client->esocket,true);
+                    dap_events_socket_set_writable_unsafe(a_http_client->esocket,true); // Dirty hack, because previous function shouldn't
+                    //                                                                    // set write flag off but it does!
+                }else{
+                    log_it(L_ERROR,"Can't open session id %u",id);
+                    a_http_client->reply_status_code=404;
+                    strcpy(a_http_client->reply_reason_phrase,"Not found");
+                }
+            }
+        }
+    }else{
+        log_it(L_ERROR,"No query string");
+    }
+}
 
 /**
- * @brief start_keepalive Start keepalive signals exchange for stream
- * @param sid Stream instance
+ * @brief s_http_client_headers_write Prepare headers for output. Creates stream structure
+ * @param sh HTTP client instance
+ * @param arg Not used
  */
-void start_keepalive( dap_stream_t *sid ) {
-    return;
-//    keepalive_loop = EV_DEFAULT;
-//    sid->keepalive_watcher.data = sid;
-//    ev_timer_init (&sid->keepalive_watcher, keepalive_cb, STREAM_KEEPALIVE_TIMEOUT, STREAM_KEEPALIVE_TIMEOUT);
-//    ev_timer_start (keepalive_loop, &sid->keepalive_watcher);
-  pthread_mutex_lock( &s_mutex_keepalive_list );
-  DL_APPEND( s_stream_keepalive_list, sid );
-  pthread_mutex_unlock( &s_mutex_keepalive_list );
+static void s_http_client_headers_write(dap_http_client_t * a_http_client, void *a_arg)
+{
+    (void) a_arg;
+    //log_it(L_DEBUG,"s_http_client_headers_write()");
+    if(a_http_client->reply_status_code==200){
+        dap_stream_t *sid=DAP_STREAM(a_http_client);
+
+        dap_http_out_header_add(a_http_client,"Content-Type","application/octet-stream");
+        dap_http_out_header_add(a_http_client,"Connnection","keep-alive");
+        dap_http_out_header_add(a_http_client,"Cache-Control","no-cache");
+
+        if(sid->stream_size>0)
+            dap_http_out_header_add_f(a_http_client,"Content-Length","%u", (unsigned int) sid->stream_size );
+
+        a_http_client->state_read=DAP_HTTP_CLIENT_STATE_DATA;
+        dap_events_socket_set_readable_unsafe(a_http_client->esocket,true);
+    }
 }
 
 /**
  * @brief stream_data_write HTTP data write callback
- * @param sh HTTP client instance
- * @param arg Not used
+ * @param a_http_client HTTP client instance
+ * @param a_arg Not used
  */
-void s_data_write(dap_http_client_t * sh, void * arg)
+static void s_http_client_data_write(dap_http_client_t * a_http_client, void * a_arg)
 {
-    (void) arg;
+    (void) a_arg;
 
-    if(sh->reply_status_code==200){
-        stream_dap_data_write(sh->client,arg);
+    if( a_http_client->reply_status_code == 200 ){
+        s_esocket_write(a_http_client->esocket, a_arg);
     }else{
-        log_it(L_WARNING, "Wrong request, reply status code is %u",sh->reply_status_code);
+        log_it(L_WARNING, "Wrong request, reply status code is %u",a_http_client->reply_status_code);
     }
 }
 
 /**
  * @brief s_data_read
- * @param sh
- * @param arg
+ * @param a_client
+ * @param a_arg
  */
-void s_data_read(dap_client_remote_t* a_client, void * arg)
+static void s_esocket_data_read(dap_events_socket_t* a_client, void * a_arg)
 {
-    dap_stream_t * l_stream =DAP_STREAM(a_client);
-    int * ret = (int *) arg;
+    dap_http_client_t *l_http_client = DAP_HTTP_CLIENT(a_client);
+    dap_stream_t * l_stream =DAP_STREAM(l_http_client);
+    int * l_ret = (int *) a_arg;
 
     if (s_dump_packet_headers ) {
         log_it(L_DEBUG,"dap_stream_data_read: ready_to_write=%s, client->buf_in_size=%u" ,
                (a_client->flags & DAP_SOCK_READY_TO_WRITE)?"true":"false", a_client->buf_in_size );
     }
-    *ret = dap_stream_data_proc_read( l_stream);
+    *l_ret = dap_stream_data_proc_read( l_stream);
+}
+
+
+
+/**
+ * @brief stream_dap_data_write Write callback for UDP client
+ * @param sh DAP client instance
+ * @param arg Not used
+ */
+static void s_esocket_write(dap_events_socket_t* a_esocket , void * a_arg){
+    (void) a_arg;
+    size_t i;
+    bool l_ready_to_write=false;
+    dap_http_client_t *l_http_client = DAP_HTTP_CLIENT(a_esocket);
+    //log_it(L_DEBUG,"Process channels data output (%u channels)", DAP_STREAM(l_http_client)->channel_count );
+    for(i=0;i<DAP_STREAM(l_http_client)->channel_count; i++){
+        dap_stream_ch_t * ch = DAP_STREAM(l_http_client)->channel[i];
+        if(ch->ready_to_write){
+            if(ch->proc->packet_out_callback)
+                ch->proc->packet_out_callback(ch,NULL);
+            l_ready_to_write|=ch->ready_to_write;
+        }
+    }
+    if (s_dump_packet_headers ) {
+        log_it(L_DEBUG,"dap_stream_data_write: ready_to_write=%s client->buf_out_size=%u" ,
+               l_ready_to_write?"true":"false", a_esocket->buf_out_size );
+    }
+    dap_events_socket_set_writable_unsafe(a_esocket, l_ready_to_write);
+    //log_it(L_DEBUG,"stream_dap_data_write ok");
+}
+
+/**
+ * @brief stream_dap_new New connection callback for UDP client
+ * @param sh DAP client instance
+ * @param arg Not used
+ */
+static void s_udp_esocket_new(dap_events_socket_t* a_esocket, void * a_arg){
+    stream_new_udp(a_esocket);
+}
+
+
+/**
+ * @brief stream_data_read HTTP data read callback. Read packet and passes that to the channel's callback
+ * @param sh HTTP client instance
+ * @param arg Processed number of bytes
+ */
+static void s_http_client_data_read(dap_http_client_t * sh, void * arg)
+{
+    s_esocket_data_read(sh->esocket,arg);
+}
+
+
+
+/**
+ * @brief stream_delete Delete stream and free its resources
+ * @param sid Stream id
+ */
+static void s_http_client_delete(dap_http_client_t * sh, void * arg)
+{
+    s_esocket_callback_delete(sh->esocket,arg);
+}
+
+/**
+ * @brief dap_stream_set_ready_to_write
+ * @param a_stream
+ * @param a_is_ready
+ */
+void dap_stream_set_ready_to_write(dap_stream_t * a_stream,bool a_is_ready)
+{
+    if(a_is_ready && a_stream->conn_http)
+        a_stream->conn_http->state_write=DAP_HTTP_CLIENT_STATE_DATA;
+    dap_events_socket_set_writable_unsafe(a_stream->esocket,a_is_ready);
 }
 
 /**
@@ -523,8 +547,8 @@ size_t dap_stream_data_proc_read (dap_stream_t *a_stream)
     bool found_sig=false;
     dap_stream_pkt_t * pkt=NULL;
 
-    char *buf_in = (a_stream->conn) ? (char*)a_stream->conn->buf_in : (char*)a_stream->events_socket->buf_in;
-    size_t buf_in_size = (a_stream->conn) ? a_stream->conn->buf_in_size : a_stream->events_socket->buf_in_size;
+    char *buf_in = (a_stream->esocket) ? (char*)a_stream->esocket->buf_in : (char*)a_stream->esocket->buf_in;
+    size_t buf_in_size = (a_stream->esocket) ? a_stream->esocket->buf_in_size : a_stream->esocket->buf_in_size;
     uint8_t *proc_data = (uint8_t *)buf_in;//a_stream->conn->buf_in;
     bool proc_data_defrag=false; // We are or not in defrag buffer
     size_t read_bytes_to=0;
@@ -573,7 +597,7 @@ size_t dap_stream_data_proc_read (dap_stream_t *a_stream)
                 a_stream->pkt_buf_in = NULL;
             }
             else{
-                stream_proc_pkt_in(a_stream);
+                s_stream_proc_pkt_in(a_stream);
             }
         }
         proc_data = (uint8_t *)(buf_in + buf_in_size - bytes_left_to_read);//proc_data=(a_stream->conn->buf_in + a_stream->conn->buf_in_size - bytes_left_to_read);
@@ -613,7 +637,7 @@ size_t dap_stream_data_proc_read (dap_stream_t *a_stream)
         bytes_left_to_read -= pkt_offset ;
         found_sig=true;
 
-        dap_stream_pkt_t *temp_pkt = dap_stream_pkt_detect( (uint8_t*)pkt + 1 ,pkt->hdr.size+sizeof(stream_pkt_hdr_t) );
+        //dap_stream_pkt_t *temp_pkt = dap_stream_pkt_detect( (uint8_t*)pkt + 1 ,pkt->hdr.size+sizeof(stream_pkt_hdr_t) );
 
         if(bytes_left_to_read  <(pkt->hdr.size+sizeof(stream_pkt_hdr_t) )){ // Is all the packet in da buf?
             read_bytes_to=bytes_left_to_read;
@@ -644,7 +668,7 @@ size_t dap_stream_data_proc_read (dap_stream_t *a_stream)
             if(a_stream->pkt_buf_in_data_size==(pkt->hdr.size + sizeof(stream_pkt_hdr_t))){
             //    log_it(INFO,"All the packet is present in da buffer (hdr.size=%u read_bytes_to=%u buf_in_size=%u)"
             //           ,sid->pkt_buf_in->hdr.size,read_bytes_to,sid->conn->buf_in_size);
-                stream_proc_pkt_in(a_stream);
+                s_stream_proc_pkt_in(a_stream);
             }else if(a_stream->pkt_buf_in_data_size>pkt->hdr.size + sizeof(stream_pkt_hdr_t)){
                 //log_it(L_WARNING,"Input: packet buffer has %u bytes more than we need, they're lost",a_stream->pkt_buf_in_data_size-pkt->hdr.size);
             }else{
@@ -675,126 +699,49 @@ size_t dap_stream_data_proc_read (dap_stream_t *a_stream)
     return buf_in_size;//a_stream->conn->buf_in_size;
 }
 
-
-/**
- * @brief stream_dap_data_write Write callback for UDP client
- * @param sh DAP client instance
- * @param arg Not used
- */
-void stream_dap_data_write(dap_client_remote_t* a_client , void * arg){
-    size_t i;
-    (void) arg;
-    bool ready_to_write=false;
-    //log_it(L_DEBUG,"Process channels data output (%u channels)", DAP_STREAM(a_client )->channel_count );
-
-    for(i=0;i<DAP_STREAM(a_client )->channel_count; i++){
-        dap_stream_ch_t * ch = DAP_STREAM(a_client )->channel[i];
-        if(ch->ready_to_write){
-            if(ch->proc->packet_out_callback)
-                ch->proc->packet_out_callback(ch,NULL);
-            ready_to_write|=ch->ready_to_write;
-        }
-    }
-    if (s_dump_packet_headers ) {
-        log_it(L_DEBUG,"dap_stream_data_write: ready_to_write=%s client->buf_out_size=%u" ,
-               ready_to_write?"true":"false", a_client->buf_out_size );
-    }
-
-  /*  if(STREAM(sh)->conn_udp)
-        dap_udp_client_ready_to_write(STREAM(sh)->conn,ready_to_write);
-    else
-        dap_client_ready_to_write(sh,ready_to_write);*/
-    //log_it(L_ERROR,"No stream_data_write_callback is defined");
-
-    //log_it(L_DEBUG,"stream_dap_data_write ok");
-}
-
-/**
- * @brief stream_dap_new New connection callback for UDP client
- * @param sh DAP client instance
- * @param arg Not used
- */
-void stream_dap_new(dap_client_remote_t* sh, void * arg){
-//    dap_stream_t *sid = stream_new_udp(sh);
-    stream_new_udp(sh);
-}
-
-
-static bool _detect_loose_packet(dap_stream_t * a_stream)
-{
-    dap_stream_ch_pkt_t * ch_pkt = (dap_stream_ch_pkt_t *) a_stream->pkt_cache;
-
-    pthread_rwlock_wrlock (&a_stream->rwlock);
-
-    int count_loosed_packets = ch_pkt->hdr.seq_id - (a_stream->client_last_seq_id_packet + 1);
-    if(count_loosed_packets > 0)
-    {
-        log_it(L_WARNING, "Detected loosed %d packets. "
-                          "Last read seq_id packet: %d Current: %d", count_loosed_packets,
-               a_stream->client_last_seq_id_packet, ch_pkt->hdr.seq_id);
-    } else if(count_loosed_packets < 0) {
-        if(a_stream->client_last_seq_id_packet != 0 && ch_pkt->hdr.seq_id != 0) {
-        log_it(L_WARNING, "Something wrong. count_loosed packets %d can't less than zero. "
-                          "Last read seq_id packet: %d Current: %d", count_loosed_packets,
-               a_stream->client_last_seq_id_packet, ch_pkt->hdr.seq_id);
-        } // else client don't support seqid functionality
-    }
-//    log_it(L_DEBUG, "Packet seq id: %d", ch_pkt->hdr.seq_id);
-//    log_it(L_DEBUG, "Last seq id: %d", sid->last_seq_id_packet);
-    a_stream->client_last_seq_id_packet = ch_pkt->hdr.seq_id;
-    pthread_rwlock_unlock (&a_stream->rwlock);
-
-    return false;
-}
-
-
 /**
  * @brief stream_proc_pkt_in
  * @param sid
  */
-void stream_proc_pkt_in(dap_stream_t * a_stream)
+static void s_stream_proc_pkt_in(dap_stream_t * a_stream)
 {
-    pthread_rwlock_wrlock( &a_stream->rwlock );
     dap_stream_pkt_t * l_pkt = a_stream->pkt_buf_in;
     size_t l_pkt_size = a_stream->pkt_buf_in_data_size;
     a_stream->pkt_buf_in=NULL;
     a_stream->pkt_buf_in_data_size=0;
     a_stream->keepalive_passed = 0;
-    pthread_rwlock_unlock (&a_stream->rwlock);
 
     if(l_pkt->hdr.type == STREAM_PKT_TYPE_DATA_PACKET)
     {
         dap_stream_ch_pkt_t * l_ch_pkt = (dap_stream_ch_pkt_t *) a_stream->pkt_cache;
 
-        if(dap_stream_pkt_read(a_stream,l_pkt, l_ch_pkt, sizeof(a_stream->pkt_cache))==0){
+        if(dap_stream_pkt_read_unsafe(a_stream,l_pkt, l_ch_pkt, sizeof(a_stream->pkt_cache))==0){
             log_it(L_WARNING, "Input: can't decode packet size=%d",l_pkt_size);
             DAP_DELETE(l_pkt);
             return;
         }
 
-        _detect_loose_packet(a_stream);
+        s_detect_loose_packet(a_stream);
 
         // Find channel
-        dap_stream_ch_t * ch = NULL;
-        pthread_rwlock_wrlock (&a_stream->rwlock);
+        dap_stream_ch_t * l_ch = NULL;
         for(size_t i=0;i<a_stream->channel_count;i++){
             if(a_stream->channel[i]->proc){
                 if(a_stream->channel[i]->proc->id == l_ch_pkt->hdr.id ){
-                    ch=a_stream->channel[i];
+                    l_ch=a_stream->channel[i];
                 }
             }
         }
-        pthread_rwlock_unlock (&a_stream->rwlock);
 
-        if(ch){
-            ch->stat.bytes_read+=l_ch_pkt->hdr.size;
-            if(ch->proc)
-                if(ch->proc->packet_in_callback){
+        if(l_ch){
+            l_ch->stat.bytes_read+=l_ch_pkt->hdr.size;
+            if(l_ch->proc)
+                if(l_ch->proc->packet_in_callback){
                     if ( s_dump_packet_headers ){
                         log_it(L_INFO,"Income channel packet: id='%c' size=%u type=0x%02Xu seq_id=0x%016X enc_type=0x%02X",(char) l_ch_pkt->hdr.id,
                             l_ch_pkt->hdr.size, l_ch_pkt->hdr.type, l_ch_pkt->hdr.seq_id , l_ch_pkt->hdr.enc_type);
                     }
-                    ch->proc->packet_in_callback(ch,l_ch_pkt);
+                    l_ch->proc->packet_in_callback(l_ch,l_ch_pkt);
                 }
 
         } else if(l_ch_pkt->hdr.id == TECHICAL_CHANNEL_ID && l_ch_pkt->hdr.type == STREAM_CH_PKT_TYPE_KEEPALIVE){
@@ -806,54 +753,62 @@ void stream_proc_pkt_in(dap_stream_t * a_stream)
         stream_srv_pkt_t * srv_pkt = DAP_NEW(stream_srv_pkt_t);
         memcpy(srv_pkt, l_pkt->data,sizeof(stream_srv_pkt_t));
         uint32_t session_id = srv_pkt->session_id;
-        check_session(session_id,a_stream->conn);
+        check_session(session_id,a_stream->esocket);
         DAP_DELETE(srv_pkt);
     } else {
         log_it(L_WARNING, "Unknown header type");
     }
 
-
-//    ev_timer_again (keepalive_loop, &a_stream->keepalive_watcher);
-    start_keepalive( a_stream );
     DAP_DELETE(l_pkt);
 }
 
 /**
- * @brief stream_data_read HTTP data read callback. Read packet and passes that to the channel's callback
- * @param sh HTTP client instance
- * @param arg Processed number of bytes
+ * @brief _detect_loose_packet
+ * @param a_stream
+ * @return
  */
-void stream_data_read(dap_http_client_t * sh, void * arg)
+static bool s_detect_loose_packet(dap_stream_t * a_stream)
 {
-    s_data_read(sh->client,arg);
-}
-
+    dap_stream_ch_pkt_t * l_ch_pkt = (dap_stream_ch_pkt_t *) a_stream->pkt_cache;
 
+    int l_count_loosed_packets = l_ch_pkt->hdr.seq_id - (a_stream->client_last_seq_id_packet + 1);
+    if(l_count_loosed_packets > 0)
+    {
+        log_it(L_WARNING, "Detected loosed %d packets. "
+                          "Last read seq_id packet: %d Current: %d", l_count_loosed_packets,
+               a_stream->client_last_seq_id_packet, l_ch_pkt->hdr.seq_id);
+    } else if(l_count_loosed_packets < 0) {
+        if(a_stream->client_last_seq_id_packet != 0 && l_ch_pkt->hdr.seq_id != 0) {
+        log_it(L_WARNING, "Something wrong. count_loosed packets %d can't less than zero. "
+                          "Last read seq_id packet: %d Current: %d", l_count_loosed_packets,
+               a_stream->client_last_seq_id_packet, l_ch_pkt->hdr.seq_id);
+        } // else client don't support seqid functionality
+    }
+//    log_it(L_DEBUG, "Packet seq id: %d", ch_pkt->hdr.seq_id);
+//    log_it(L_DEBUG, "Last seq id: %d", sid->last_seq_id_packet);
+    a_stream->client_last_seq_id_packet = l_ch_pkt->hdr.seq_id;
 
-/**
- * @brief stream_delete Delete stream and free its resources
- * @param sid Stream id
- */
-void stream_delete(dap_http_client_t * sh, void * arg)
-{
-    stream_dap_delete(sh->client,arg);
+    return false;
 }
 
-/**
- * @brief dap_stream_set_ready_to_write
- * @param a_stream
- * @param a_is_ready
- */
-void dap_stream_set_ready_to_write(dap_stream_t * a_stream,bool a_is_ready)
+
+static void s_keepalive_cb( void )
 {
-    if(a_is_ready && a_stream->conn_http)
-        a_stream->conn_http->state_write=DAP_HTTP_CLIENT_STATE_DATA;
-    if(a_stream->conn_udp)
-        dap_udp_client_ready_to_write(a_stream->conn,a_is_ready);
-    // for stream server
-    else if(a_stream->conn)
-        dap_client_remote_ready_to_write(a_stream->conn,a_is_ready);
-    // for stream client
-    else if(a_stream->events_socket)
-        dap_events_socket_set_writable(a_stream->events_socket, a_is_ready);
+  dap_stream_t  *l_stream, *tmp;
+  return;
+  pthread_mutex_lock( &s_mutex_keepalive_list );
+  DL_FOREACH_SAFE( s_stream_keepalive_list, l_stream, tmp ) {
+    if ( l_stream->keepalive_passed < STREAM_KEEPALIVE_PASSES ) {
+      dap_stream_send_keepalive( l_stream );
+      l_stream->keepalive_passed += 1;
+    }
+    else {
+      log_it( L_INFO, "Client disconnected" );
+      DL_DELETE( s_stream_keepalive_list, l_stream );
+      s_esocket_callback_delete( l_stream->esocket, NULL );
+    }
+  }
+
+  pthread_mutex_unlock( &s_mutex_keepalive_list );
 }
+
diff --git a/dap-sdk/net/stream/stream/dap_stream_ctl.c b/dap-sdk/net/stream/stream/dap_stream_ctl.c
index 21bd39eb99423262c6199bc573df54b2b48036e8..ef5d72345ae8dbb122417fbf8f92a739da045fd1 100644
--- a/dap-sdk/net/stream/stream/dap_stream_ctl.c
+++ b/dap-sdk/net/stream/stream/dap_stream_ctl.c
@@ -44,7 +44,7 @@
 
 #include "dap_http.h"
 #include "dap_http_client.h"
-#include "dap_client_remote.h"
+#include "dap_events_socket.h"
 #include "dap_http_simple.h"
 
 #include "dap_stream_session.h"
@@ -146,7 +146,7 @@ void s_proc(struct dap_http_simple *a_http_simple, void * a_arg)
             dap_random_string_fill(key_str, KEX_KEY_STR_SIZE);
             ss->key = dap_enc_key_new_generate( s_socket_forward_key.type, key_str, KEX_KEY_STR_SIZE,
                                                NULL, 0, s_socket_forward_key.size);
-            dap_http_header_t *l_hdr_key_id = dap_http_header_find(a_http_simple->http->in_headers, "KeyID");
+            dap_http_header_t *l_hdr_key_id = dap_http_header_find(a_http_simple->http_client->in_headers, "KeyID");
             if (l_hdr_key_id) {
                 dap_enc_ks_key_t *l_ks_key = dap_enc_ks_find(l_hdr_key_id->value);
                 if (!l_ks_key) {
diff --git a/dap-sdk/net/stream/stream/dap_stream_pkt.c b/dap-sdk/net/stream/stream/dap_stream_pkt.c
index d50740bb9889ce7bfa5c92cba1e93fc1c4eafbfe..9642362c3cb2f06c839b935572e88e7b291c446d 100644
--- a/dap-sdk/net/stream/stream/dap_stream_pkt.c
+++ b/dap-sdk/net/stream/stream/dap_stream_pkt.c
@@ -25,6 +25,7 @@
 #include <stdlib.h>
 #include <stddef.h>
 #include <stdint.h>
+#include <unistd.h>
 
 #ifdef WIN32
 #include <winsock2.h>
@@ -39,7 +40,8 @@
 //#include "config.h"
 
 
-#include "dap_client_remote.h"
+#include "dap_events_socket.h"
+#include "dap_worker.h"
 #include "dap_http_client.h"
 
 #include "dap_enc.h"
@@ -105,7 +107,7 @@ static size_t s_encode_dummy(const void * a_buf, size_t a_buf_size, void * a_buf
  * @param pkt
  * @param buf_out
  */
-size_t dap_stream_pkt_read( dap_stream_t * a_stream, dap_stream_pkt_t * a_pkt, void * a_buf_out, size_t a_buf_out_size)
+size_t dap_stream_pkt_read_unsafe( dap_stream_t * a_stream, dap_stream_pkt_t * a_pkt, void * a_buf_out, size_t a_buf_out_size)
 {
     size_t ds = a_stream->session->key->dec_na(a_stream->session->key,a_pkt->data,a_pkt->hdr.size,a_buf_out, a_buf_out_size);
 //    log_it(L_DEBUG,"Stream decoded %lu bytes ( last bytes 0x%02x 0x%02x 0x%02x 0x%02x ) ", ds,
@@ -119,6 +121,7 @@ size_t dap_stream_pkt_read( dap_stream_t * a_stream, dap_stream_pkt_t * a_pkt, v
 }
 
 
+#define DAP_STREAM_CH_PKT_ENCRYPTION_OVERHEAD 200 //in fact is's about 2*16+15 for OAES
 
 /**
  * @brief stream_ch_pkt_write
@@ -128,42 +131,61 @@ size_t dap_stream_pkt_read( dap_stream_t * a_stream, dap_stream_pkt_t * a_pkt, v
  * @return
  */
 
-size_t dap_stream_pkt_write(dap_stream_t * a_stream, const void * a_data, size_t a_data_size)
+size_t dap_stream_pkt_write_unsafe(dap_stream_t * a_stream, const void * a_data, size_t a_data_size)
 {
     size_t ret=0;
     stream_pkt_hdr_t pkt_hdr;
 
-    if(a_data_size > STREAM_BUF_SIZE_MAX ){
-        log_it(L_ERROR,"Too big data size %lu, bigger than encryption buffer size %lu",a_data_size,sizeof(a_stream->buf));
-        a_data_size=sizeof(a_stream->buf);
+    uint8_t * l_buf_allocated = NULL;
+    uint8_t * l_buf_selected = a_stream->buf;
+    size_t  l_buf_size_required = a_data_size + DAP_STREAM_CH_PKT_ENCRYPTION_OVERHEAD;
+    
+    if(l_buf_size_required > sizeof(a_stream->buf) ){
+        l_buf_allocated = DAP_NEW_SIZE(uint8_t, l_buf_size_required);
+        l_buf_selected = l_buf_allocated;
     }
 
     memset(&pkt_hdr,0,sizeof(pkt_hdr));
     memcpy(pkt_hdr.sig,c_dap_stream_sig,sizeof(pkt_hdr.sig));
 
-    pkt_hdr.size =(uint32_t) a_stream->session->key->enc_na(a_stream->session->key, a_data,a_data_size,a_stream->buf, STREAM_BUF_SIZE_MAX);
-//    printf("*[dap_stream_pkt_write] size=%d key=0x%x _inheritor_size=%d\n", pkt_hdr.size, sid->session->key,
-//            sid->session->key->_inheritor_size);
+    pkt_hdr.size =(uint32_t) dap_enc_code( a_stream->session->key, a_data,a_data_size,l_buf_selected, l_buf_size_required, DAP_ENC_DATA_TYPE_RAW);
 
-    if(a_stream->conn_udp){
-        ret+=dap_udp_client_write(a_stream->conn,&pkt_hdr,sizeof(pkt_hdr));
-        ret+=dap_udp_client_write(a_stream->conn,a_stream->buf,pkt_hdr.size);
-        dap_client_remote_ready_to_write(a_stream->conn, true);
-    }
-    else if(a_stream->conn){
-        ret+=dap_client_remote_write(a_stream->conn,&pkt_hdr,sizeof(pkt_hdr));
-        ret+=dap_client_remote_write(a_stream->conn,a_stream->buf,pkt_hdr.size);
-        dap_client_remote_ready_to_write(a_stream->conn, true);
-    }
-    else if(a_stream->events_socket) {
-        ret += dap_events_socket_write(a_stream->events_socket, &pkt_hdr, sizeof(pkt_hdr));
-        ret += dap_events_socket_write(a_stream->events_socket, a_stream->buf, pkt_hdr.size);
-        dap_events_socket_set_writable(a_stream->events_socket, true);
-    }
+    ret+=dap_events_socket_write_unsafe(a_stream->esocket,&pkt_hdr,sizeof(pkt_hdr));
+    ret+=dap_events_socket_write_unsafe(a_stream->esocket,l_buf_selected,pkt_hdr.size);
+    dap_events_socket_set_writable_unsafe(a_stream->esocket, true);
 
+    if(l_buf_allocated)
+        DAP_DELETE(l_buf_allocated);
     return ret;
 }
 
+/**
+ * @brief dap_stream_pkt_write_mt
+ * @param a_stream_session
+ * @param a_es
+ * @param a_data
+ * @param a_data_size
+ * @return
+ */
+size_t dap_stream_pkt_write_mt(dap_worker_t * a_w,dap_events_socket_t *a_es, dap_enc_key_t *a_key, const void * a_data, size_t a_data_size)
+{
+    dap_worker_msg_io_t * l_msg = DAP_NEW_Z(dap_worker_msg_io_t);
+    stream_pkt_hdr_t *l_pkt_hdr;
+    l_msg->data_size = 16-a_data_size%16+a_data_size+sizeof(*l_pkt_hdr);
+    l_msg->data = DAP_NEW_SIZE(void,l_msg->data_size);
+    l_pkt_hdr=(stream_pkt_hdr_t*) l_msg->data;
+    memset(l_pkt_hdr,0,sizeof(*l_pkt_hdr));
+    memcpy(l_pkt_hdr->sig,c_dap_stream_sig,sizeof(l_pkt_hdr->sig));
+    l_msg->data_size=sizeof (*l_pkt_hdr) +dap_enc_code(a_key, a_data,a_data_size, ((byte_t*)l_msg->data)+sizeof (*l_pkt_hdr),l_msg->data_size-sizeof (*l_pkt_hdr),DAP_ENC_DATA_TYPE_RAW);
+
+    int l_ret= dap_events_socket_queue_ptr_send(a_w->queue_es_io, l_msg );
+    if (l_ret!=0){
+        log_it(L_ERROR, "Wasn't send pointer to queue: code %d", l_ret);
+        DAP_DELETE(l_msg);
+        return 0;
+    }
+    return a_data_size;
+}
 
 
 /**
@@ -176,7 +198,5 @@ void dap_stream_send_keepalive(dap_stream_t * a_stream)
     l_pkt.id = TECHICAL_CHANNEL_ID;
     l_pkt.type=STREAM_CH_PKT_TYPE_KEEPALIVE;
 
-    if( dap_stream_pkt_write( a_stream, &l_pkt, sizeof(l_pkt) ) )
-        dap_stream_set_ready_to_write( a_stream, true );
+    dap_stream_pkt_write_unsafe( a_stream, &l_pkt, sizeof(l_pkt) );
 }
-
diff --git a/dap-sdk/net/stream/stream/dap_stream_worker.c b/dap-sdk/net/stream/stream/dap_stream_worker.c
new file mode 100644
index 0000000000000000000000000000000000000000..fe374507f386098af0efc7fad49e6f5973ad5c6b
--- /dev/null
+++ b/dap-sdk/net/stream/stream/dap_stream_worker.c
@@ -0,0 +1,88 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Ltd.   https://demlabs.net
+ * Copyright  (c) 2020
+ * All rights reserved.
+
+ This file is part of DAP SDK the open source project
+
+    DAP SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DAP SDK is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "dap_common.h"
+#include "dap_events.h"
+#include "dap_events_socket.h"
+#include "dap_stream_worker.h"
+#include "dap_stream_ch_pkt.h"
+
+#define LOG_TAG "dap_stream_worker"
+
+static void s_ch_io_callback(dap_events_socket_t * a_es, void * a_msg);
+
+/**
+ * @brief dap_stream_worker_init
+ * @return
+ */
+int dap_stream_worker_init()
+{
+    uint32_t l_worker_count = dap_events_worker_get_count();
+    for (uint32_t i = 0; i < l_worker_count; i++){
+        dap_worker_t * l_worker = dap_events_worker_get(i);
+        if (!l_worker) {
+            log_it(L_CRITICAL,"Can't init stream worker, woreker thread don't exist");
+            return -2;
+        }
+        if (l_worker->_inheritor){
+            log_it(L_CRITICAL,"Can't init stream worker, core worker has already inheritor");
+            return -1;
+        }
+        dap_stream_worker_t *l_stream_worker =  DAP_NEW_Z(dap_stream_worker_t);
+        l_worker->_inheritor = l_stream_worker;
+        l_stream_worker->worker = l_worker;
+        l_stream_worker->queue_ch_io = dap_events_socket_create_type_queue_ptr_mt( l_worker, s_ch_io_callback);
+    }
+    return 0;
+}
+
+/**
+ * @brief s_ch_io_callback
+ * @param a_es
+ * @param a_msg
+ */
+static void s_ch_io_callback(dap_events_socket_t * a_es, void * a_msg)
+{
+    dap_stream_worker_t * l_stream_worker = DAP_STREAM_WORKER( a_es->worker );
+    dap_stream_worker_msg_io_t * l_msg = (dap_stream_worker_msg_io_t*) a_msg;
+
+    // Check if it was removed from the list
+    dap_stream_ch_t *l_msg_ch = NULL;
+    HASH_FIND(hh_worker, l_stream_worker->channels , &l_msg->ch , sizeof (void*), l_msg_ch );
+    if ( l_msg_ch == NULL){
+        log_it(L_DEBUG, "We got i/o message for client thats now not in list. Lost %u data", l_msg->data_size);
+        DAP_DELETE(l_msg);
+        return;
+    }
+
+    if (l_msg->flags_set & DAP_SOCK_READY_TO_READ)
+        dap_stream_ch_set_ready_to_read_unsafe(l_msg_ch, true);
+    if (l_msg->flags_unset & DAP_SOCK_READY_TO_READ)
+        dap_stream_ch_set_ready_to_read_unsafe(l_msg_ch, false);
+    if (l_msg->flags_set & DAP_SOCK_READY_TO_WRITE)
+        dap_stream_ch_set_ready_to_write_unsafe(l_msg_ch, true);
+    if (l_msg->flags_unset & DAP_SOCK_READY_TO_WRITE)
+        dap_stream_ch_set_ready_to_write_unsafe(l_msg_ch, false);
+    if (l_msg->data_size && l_msg->data)
+        dap_stream_ch_pkt_write_unsafe(l_msg_ch, l_msg->ch_pkt_type, l_msg->data,l_msg->data_size);
+    DAP_DELETE(l_msg);
+}
diff --git a/dap-sdk/net/stream/stream/include/dap_stream.h b/dap-sdk/net/stream/stream/include/dap_stream.h
index 2e3aa9c2853cebbf29d7573f369ed3530b0d9d31..888be346b5ae1b3b43b0d3aea5bc9004bfc999e1 100644
--- a/dap-sdk/net/stream/stream/include/dap_stream.h
+++ b/dap-sdk/net/stream/stream/include/dap_stream.h
@@ -52,15 +52,11 @@ typedef void (*dap_stream_callback)( dap_stream_t *,void*);
 
 typedef struct dap_stream {
     int id;
-    pthread_rwlock_t rwlock;
     dap_stream_session_t * session;
-    struct dap_client_remote * conn; // Connection
-
+    dap_events_socket_t * esocket; // Connection
+    dap_stream_worker_t * stream_worker;
     struct dap_http_client * conn_http; // HTTP-specific
 
-    struct dap_udp_client * conn_udp; // UDP-client
-    dap_events_socket_t * events_socket;
-
     char * service_key;
 
     bool is_live;
@@ -93,7 +89,7 @@ typedef struct dap_stream {
 
 } dap_stream_t;
 
-#define DAP_STREAM(a) ((dap_stream_t *) (a)->_internal )
+#define DAP_STREAM(a) ((dap_stream_t *) (a)->_inheritor )
 
 int dap_stream_init(bool a_dump_packet_headers);
 
@@ -105,7 +101,7 @@ void dap_stream_add_proc_http(dap_http_t * sh, const char * url);
 
 void dap_stream_add_proc_udp(dap_udp_server_t * sh);
 
-dap_stream_t* dap_stream_new_es(dap_events_socket_t * a_es);
+dap_stream_t* dap_stream_new_es_client(dap_events_socket_t * a_es);
 size_t dap_stream_data_proc_read(dap_stream_t * a_stream);
 size_t dap_stream_data_proc_write(dap_stream_t * a_stream);
 void dap_stream_delete(dap_stream_t * a_stream);
diff --git a/dap-sdk/net/stream/stream/include/dap_stream_ctl.h b/dap-sdk/net/stream/stream/include/dap_stream_ctl.h
index 94a5d62ee2dcc1b644db7c8e657c44a46fade8df..56fe6e995554b46dbe186ffb0906712194979452 100644
--- a/dap-sdk/net/stream/stream/include/dap_stream_ctl.h
+++ b/dap-sdk/net/stream/stream/include/dap_stream_ctl.h
@@ -19,10 +19,12 @@
 */
 
 #pragma once
-typedef struct dap_http dap_http_t;
 
+#include "dap_enc.h"
+typedef struct dap_http dap_http_t;
 #define KEX_KEY_STR_SIZE 128
 
+
 int dap_stream_ctl_init(dap_enc_key_type_t socket_forward_key_type,
                         size_t socket_forward_key_size);
 void dap_stream_ctl_deinit();
diff --git a/dap-sdk/net/stream/stream/include/dap_stream_pkt.h b/dap-sdk/net/stream/stream/include/dap_stream_pkt.h
index ce6fd70636e35133c9f6076896a911fd913e4472..34beb4e381cb71bbda533701ebfa49c2b6deab16 100644
--- a/dap-sdk/net/stream/stream/include/dap_stream_pkt.h
+++ b/dap-sdk/net/stream/stream/include/dap_stream_pkt.h
@@ -21,10 +21,11 @@
 #pragma once
 #include <stdint.h>
 #include <stddef.h>
-
-#define STREAM_PKT_SIZE_MAX 500000
-struct dap_stream;
+#include "dap_enc_key.h"
+#include "dap_events_socket.h"
+#define STREAM_PKT_SIZE_MAX 100000
 typedef struct dap_stream dap_stream_t;
+typedef struct dap_stream_session dap_stream_session_t;
 #define STREAM_PKT_TYPE_DATA_PACKET 0x00
 #define STREAM_PKT_TYPE_SERVICE_PACKET 0xff
 //#define STREAM_PKT_TYPE_KEEPALIVE 0x11
@@ -53,9 +54,10 @@ extern const uint8_t c_dap_stream_sig[8];
 
 dap_stream_pkt_t * dap_stream_pkt_detect(void * a_data, size_t data_size);
 
-size_t dap_stream_pkt_read(dap_stream_t * a_stream, dap_stream_pkt_t * a_pkt, void * a_buf_out, size_t a_buf_out_size);
+size_t dap_stream_pkt_read_unsafe(dap_stream_t * a_stream, dap_stream_pkt_t * a_pkt, void * a_buf_out, size_t a_buf_out_size);
 
-size_t dap_stream_pkt_write(dap_stream_t * a_stream, const void * data, size_t a_data_size);
+size_t dap_stream_pkt_write_unsafe(dap_stream_t * a_stream, const void * data, size_t a_data_size);
+size_t dap_stream_pkt_write_mt (dap_worker_t * a_w, dap_events_socket_t *a_es, dap_enc_key_t *a_key, const void * data, size_t a_data_size);
 
 void dap_stream_send_keepalive( dap_stream_t * a_stream);
 
diff --git a/dap-sdk/net/stream/stream/include/dap_stream_worker.h b/dap-sdk/net/stream/stream/include/dap_stream_worker.h
new file mode 100644
index 0000000000000000000000000000000000000000..3058cdf8d68e39e48e88e5cd0f6d72a7de3caf93
--- /dev/null
+++ b/dap-sdk/net/stream/stream/include/dap_stream_worker.h
@@ -0,0 +1,44 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Ltd.   https://demlabs.net
+ * Copyright  (c) 2020
+ * All rights reserved.
+
+ This file is part of DAP SDK the open source project
+
+    DAP SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DAP SDK is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+#include "dap_worker.h"
+#include "dap_stream_ch.h"
+
+typedef struct dap_stream_worker {
+    dap_worker_t * worker;
+    dap_events_socket_t *queue_ch_io; // IO queue for channels
+    dap_stream_ch_t * channels; // Client channels assigned on worker. Unsafe list, operate only in worker's context
+} dap_stream_worker_t;
+
+#define DAP_STREAM_WORKER(a) ((dap_stream_worker_t*) (a->_inheritor)  )
+
+typedef struct dap_stream_worker_msg_io {
+    dap_stream_ch_t * ch; // Channel that has operations with
+    uint32_t flags_set; // set flags
+    uint32_t flags_unset; // unset flags
+    uint8_t ch_pkt_type;
+    void * data;
+    size_t data_size;
+} dap_stream_worker_msg_io_t;
+
+int dap_stream_worker_init();
diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c
index dd0910e8f6d156746a39d7f02766a4ed672533ac..b7d05539b15f8fd2de45a09918ff039f52b82cfa 100644
--- a/modules/chain/dap_chain.c
+++ b/modules/chain/dap_chain.c
@@ -24,7 +24,7 @@
 #include <dap_chain_ledger.h>
 #include <sys/types.h>
 #include <dirent.h>
-
+#include <stdc-predef.h>
 #include <unistd.h>
 
 #include "dap_common.h"
@@ -255,9 +255,9 @@ dap_chain_t * dap_chain_load_from_cfg(dap_ledger_t* a_ledger, const char * a_cha
 
             // Recognize chains id
             if ( (l_chain_id_str = dap_config_get_item_str(l_cfg,"chain","id")) != NULL ){
-                if ( sscanf(l_chain_id_str,"0x%016llX",& l_chain_id_u ) !=1 ){
-                    if ( sscanf(l_chain_id_str,"0x%016llx",&l_chain_id_u) !=1 ) {
-                        if ( sscanf(l_chain_id_str,"%llu",&l_chain_id_u ) !=1 ){
+                if ( sscanf(l_chain_id_str,"0x%"DAP_UINT64_FORMAT_X,& l_chain_id_u ) !=1 ){
+                    if ( sscanf(l_chain_id_str,"0x%"DAP_UINT64_FORMAT_x,&l_chain_id_u) !=1 ) {
+                        if ( sscanf(l_chain_id_str,"%"DAP_UINT64_FORMAT_u,&l_chain_id_u ) !=1 ){
                             log_it (L_ERROR,"Can't recognize '%s' string as chain net id, hex or dec",l_chain_id_str);
                             dap_config_close(l_cfg);
                             return NULL;
@@ -269,7 +269,7 @@ dap_chain_t * dap_chain_load_from_cfg(dap_ledger_t* a_ledger, const char * a_cha
 
 
             if (l_chain_id_str ) {
-                log_it (L_NOTICE, "Chain id 0x%016lX  ( \"%s\" )",l_chain_id.uint64 , l_chain_id_str) ;
+                log_it (L_NOTICE, "Chain id 0x%016"DAP_UINT64_FORMAT_x"  ( \"%s\" )",l_chain_id.uint64 , l_chain_id_str) ;
             }else {
                 log_it (L_ERROR,"Wasn't recognized '%s' string as chain net id, hex or dec",l_chain_id_str);
                 dap_config_close(l_cfg);
diff --git a/modules/chain/dap_chain_cell.c b/modules/chain/dap_chain_cell.c
index 4d7f76f0aa01c735677f9d345b2e5ccd78bfb01a..cb84cba7ab0887ef6f28847e2e6d44d04e95df0d 100644
--- a/modules/chain/dap_chain_cell.c
+++ b/modules/chain/dap_chain_cell.c
@@ -134,7 +134,7 @@ int dap_chain_cell_load(dap_chain_t * a_chain, const char * a_cell_file_path)
                         if ( l_element_size > 0 ){
                             dap_chain_atom_ptr_t * l_element = DAP_NEW_Z_SIZE (dap_chain_atom_ptr_t, l_element_size );
                             if ( fread( l_element,1,l_element_size,l_cell->file_storage ) == l_element_size ) {
-                                a_chain->callback_atom_add (a_chain, l_element );
+                                a_chain->callback_atom_add (a_chain, l_element, l_element_size);
                             }
                         } else {
                             log_it (L_ERROR, "Zero element size, file is corrupted");
@@ -270,13 +270,12 @@ int dap_chain_cell_file_update( dap_chain_cell_t * a_cell)
     if ( a_cell->file_storage ){
         dap_chain_t * l_chain = a_cell->chain;
         dap_chain_atom_iter_t *l_atom_iter = l_chain->callback_atom_iter_create (l_chain);
-        dap_chain_atom_ptr_t *l_atom = l_chain->callback_atom_iter_get_first(l_atom_iter);
-        size_t l_atom_size = l_chain->callback_atom_get_size(l_atom);
+        size_t l_atom_size = 0;
+        dap_chain_atom_ptr_t *l_atom = l_chain->callback_atom_iter_get_first(l_atom_iter, &l_atom_size);
         while ( l_atom  && l_atom_size){
             if ( dap_chain_cell_file_append (a_cell,l_atom, l_atom_size) <0 )
                 break;
-            l_atom = l_chain->callback_atom_iter_get_next( l_atom_iter );
-            l_atom_size = l_chain->callback_atom_get_size(l_atom);
+            l_atom = l_chain->callback_atom_iter_get_next( l_atom_iter, &l_atom_size );
         }
     }else {
             log_it (L_ERROR,"Can't write cell 0x%016X file \"%s\"",a_cell->id.uint64, a_cell->file_storage_path);
diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h
index 0888d5eaa2a8de225cb84c9666365042581c0872..86f4782d85f2e2720f72e56a7c5a305f2c0ee0b5 100644
--- a/modules/chain/include/dap_chain.h
+++ b/modules/chain/include/dap_chain.h
@@ -45,15 +45,16 @@ typedef void * dap_chain_atom_ptr_t;
 typedef struct dap_chain_atom_iter{
     dap_chain_t * chain;
     dap_chain_atom_ptr_t cur;
+    size_t cur_size;
     void * cur_item;
     void * _inheritor;
 } dap_chain_atom_iter_t;
 
 typedef enum dap_chain_atom_verify_res{
-    ATOM_ACCEPT,
-    ATOM_PASS,
-    ATOM_REJECT,
-    ATOM_MOVE_TO_THRESHOLD
+    ATOM_ACCEPT=0,
+    ATOM_PASS=1,
+    ATOM_REJECT=2,
+    ATOM_MOVE_TO_THRESHOLD=3
 } dap_chain_atom_verify_res_t;
 
 typedef dap_chain_t* (*dap_chain_callback_new_t)(void);
@@ -62,22 +63,20 @@ typedef void (*dap_chain_callback_t)(dap_chain_t *);
 typedef int (*dap_chain_callback_new_cfg_t)(dap_chain_t*, dap_config_t *);
 typedef void (*dap_chain_callback_ptr_t)(dap_chain_t *, void * );
 
-typedef dap_chain_atom_verify_res_t (*dap_chain_callback_atom_t)(dap_chain_t *, dap_chain_atom_ptr_t );
-typedef dap_chain_atom_verify_res_t (*dap_chain_callback_atom_verify_t)(dap_chain_t *, dap_chain_atom_ptr_t );
-typedef int (*dap_chain_callback_atom_size_t)(dap_chain_t *, dap_chain_atom_ptr_t ,size_t);
+typedef dap_chain_atom_verify_res_t (*dap_chain_callback_atom_t)(dap_chain_t *, dap_chain_atom_ptr_t, size_t );
+typedef dap_chain_atom_verify_res_t (*dap_chain_callback_atom_verify_t)(dap_chain_t *, dap_chain_atom_ptr_t , size_t);
 typedef size_t (*dap_chain_callback_atom_get_hdr_size_t)(void);
-typedef size_t (*dap_chain_callback_atom_hdr_get_size_t)(dap_chain_atom_ptr_t );
 
 typedef dap_chain_atom_iter_t* (*dap_chain_callback_atom_iter_create_t)(dap_chain_t * );
-typedef dap_chain_atom_iter_t* (*dap_chain_callback_atom_iter_create_from_t)(dap_chain_t * ,dap_chain_atom_ptr_t);
-typedef dap_chain_atom_ptr_t (*dap_chain_callback_atom_iter_get_first_t)(dap_chain_atom_iter_t * );
-typedef dap_chain_datum_t* (*dap_chain_callback_atom_get_datum)(dap_chain_atom_ptr_t );
-typedef dap_chain_atom_ptr_t (*dap_chain_callback_atom_iter_find_by_hash_t)(dap_chain_atom_iter_t * ,dap_chain_hash_fast_t *);
+typedef dap_chain_atom_iter_t* (*dap_chain_callback_atom_iter_create_from_t)(dap_chain_t * ,dap_chain_atom_ptr_t, size_t);
+typedef dap_chain_atom_ptr_t (*dap_chain_callback_atom_iter_get_first_t)(dap_chain_atom_iter_t * , size_t*);
+typedef dap_chain_datum_t* (*dap_chain_callback_atom_get_datum)(dap_chain_atom_ptr_t, size_t );
+typedef dap_chain_atom_ptr_t (*dap_chain_callback_atom_iter_find_by_hash_t)(dap_chain_atom_iter_t * ,dap_chain_hash_fast_t *,size_t*);
 typedef dap_chain_datum_tx_t* (*dap_chain_callback_tx_find_by_hash_t)(dap_chain_t * ,dap_chain_hash_fast_t *);
 
-typedef dap_chain_atom_ptr_t * (*dap_chain_callback_atom_iter_get_atoms_t)(dap_chain_atom_iter_t * ,size_t * );
+typedef dap_chain_atom_ptr_t * (*dap_chain_callback_atom_iter_get_atoms_t)(dap_chain_atom_iter_t * ,size_t* ,size_t**);
 
-typedef dap_chain_atom_ptr_t (*dap_chain_callback_atom_iter_get_next_t)(dap_chain_atom_iter_t *  );
+typedef dap_chain_atom_ptr_t (*dap_chain_callback_atom_iter_get_next_t)(dap_chain_atom_iter_t *  ,size_t*);
 typedef void (*dap_chain_callback_atom_iter_delete_t)(dap_chain_atom_iter_t *  );
 
 typedef size_t (*dap_chain_datum_callback_datum_pool_proc_add_t)(dap_chain_t * , dap_chain_datum_t **, size_t );
@@ -126,7 +125,6 @@ typedef struct dap_chain{
     dap_chain_datum_callback_datum_pool_proc_add_with_group_t callback_datums_pool_proc_with_group;
 
     dap_chain_callback_atom_get_hdr_size_t callback_atom_get_hdr_static_size; // Get atom header's size
-    dap_chain_callback_atom_hdr_get_size_t callback_atom_get_size; // Get atom's size from header
 
     dap_chain_callback_atom_iter_create_t callback_atom_iter_create;
     dap_chain_callback_atom_iter_create_from_t callback_atom_iter_create_from;
diff --git a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c
index ddd9ad790d4ae25e45da02c3385ab112e9d4dc33..cd4c5958021f28578725720bfb35ff21e2bba44f 100644
--- a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c
+++ b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c
@@ -141,7 +141,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                                                                 a_ch->stream->session->_inheritor : NULL;
     if ( ! l_srv_session ){
         log_it( L_ERROR, "Not defined service session, switching off packet input process");
-        dap_stream_ch_set_ready_to_read(a_ch, false);
+        dap_stream_ch_set_ready_to_read_unsafe(a_ch, false);
         return;
     }
     dap_stream_ch_chain_net_srv_pkt_error_t l_err;
@@ -152,14 +152,15 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
             // for send test data
             case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_REQUEST:{
                 int l_err_code = 0;
-                dap_stream_ch_chain_net_srv_pkt_test_t *l_request = (dap_stream_ch_chain_net_srv_pkt_request_t*) l_ch_pkt->data;
+                dap_stream_ch_chain_net_srv_pkt_test_t *l_request = (dap_stream_ch_chain_net_srv_pkt_test_t*) l_ch_pkt->data;
                 size_t l_request_size = l_request->data_size + sizeof(dap_stream_ch_chain_net_srv_pkt_test_t);
                 if(l_ch_pkt->hdr.size != l_request_size) {
                     log_it(L_WARNING, "Wrong request size, less or more than required");
                     break;
                 }
-
-                gettimeofday(&l_request->recv_time2, NULL);
+                struct timeval l_recvtime2;
+                gettimeofday(&l_recvtime2, NULL);
+                memcpy(&l_request->recv_time2,&l_recvtime2,sizeof (l_recvtime2));
                 //printf("\n%lu.%06lu \n", (unsigned long) l_request->recv_time2.tv_sec, (unsigned long) l_request->recv_time2.tv_usec);
                 dap_chain_hash_fast_t l_data_hash;
                 dap_hash_fast(l_request->data, l_request->data_size, &l_data_hash);
@@ -175,12 +176,17 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                 randombytes(l_request_out->data, l_request_out->data_size);
                 l_request_out->err_code = l_err_code;
                 dap_hash_fast(l_request_out->data, l_request_out->data_size, &l_request_out->data_hash);
-                memcpy(l_request_out->ip_send, a_ch->stream->conn->s_ip, sizeof(l_request_out->ip_send));
-                gettimeofday(&l_request_out->send_time2, NULL);
+                strncpy(l_request_out->ip_send,a_ch->stream->esocket->hostaddr  , sizeof(l_request_out->ip_send)-1);
+
+                // Thats to prevent unaligned pointer
+                struct timeval l_tval;
+                gettimeofday(&l_tval, NULL);
+                l_request_out->send_time2.tv_sec = l_tval.tv_sec;
+                l_request_out->send_time2.tv_usec = l_tval.tv_usec;
 
                 // send response
-                if(dap_stream_ch_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_RESPONSE, l_request_out, l_request_out->data_size + sizeof(dap_stream_ch_chain_net_srv_pkt_test_t))) {
-                        dap_stream_ch_set_ready_to_write(a_ch, true);
+                if(dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_RESPONSE, l_request_out, l_request_out->data_size + sizeof(dap_stream_ch_chain_net_srv_pkt_test_t))) {
+                        dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
                     }
                 DAP_DELETE(l_request_out);
 
@@ -188,7 +194,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
             break;
             // for receive test data.
             case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_RESPONSE: {
-                dap_stream_ch_chain_net_srv_pkt_test_t *l_request = (dap_stream_ch_chain_net_srv_pkt_request_t *) l_ch_pkt->data;
+                dap_stream_ch_chain_net_srv_pkt_test_t *l_request = (dap_stream_ch_chain_net_srv_pkt_test_t *) l_ch_pkt->data;
                 size_t l_request_size = l_request->data_size + sizeof(dap_stream_ch_chain_net_srv_pkt_test_t);
                 if(l_ch_pkt->hdr.size != l_request_size) {
                     log_it(L_WARNING, "Wrong request size, less or more than required");
@@ -200,7 +206,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                 if(!dap_hash_fast_compare(&l_data_hash, &(l_request->data_hash))) {
                     l_request->err_code += 4;
                 }
-                dap_stream_ch_set_ready_to_write(a_ch, false);
+                dap_stream_ch_set_ready_to_write_unsafe(a_ch, false);
             }
             break;
 
@@ -226,13 +232,13 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                     l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_SERVICE_NOT_FOUND;
 
                 if ( l_err.code ){
-                    dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
+                    dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
                     if (l_srv && l_srv->callback_response_error)
                         l_srv->callback_response_error(l_srv,0,NULL,&l_err,sizeof (l_err) );
                     break;
                 }
 
-                dap_ledger_t * l_ledger = dap_chain_ledger_by_net_name( l_net->pub.name);
+                dap_ledger_t * l_ledger =l_net->pub.ledger;
                 dap_chain_datum_tx_t * l_tx = NULL;
                 dap_chain_tx_out_cond_t * l_tx_out_cond = NULL;
                 if (l_srv->pricelist ){ // Is present pricelist, not free service
@@ -240,7 +246,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                     if ( !l_ledger ){ // No ledger
                         log_it( L_WARNING, "No Ledger");
                         l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_NETWORK_NO_LEDGER ;
-                        dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
+                        dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
                         if (l_srv->callback_response_error)
                                 l_srv->callback_response_error(l_srv,0,NULL,&l_err,sizeof (l_err) );
                         break;
@@ -252,7 +258,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                         /// TODO Add tx cond treshold and ability to provide service before the transaction comes from CDB
                         ///
                         l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_FOUND ;
-                        dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
+                        dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
                         if (l_srv->callback_response_error)
                                 l_srv->callback_response_error(l_srv,0,NULL,&l_err,sizeof (l_err) );
                         break;
@@ -265,7 +271,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                         log_it( L_WARNING, "No conditioned output");
 
                         l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NO_COND_OUT ;
-                        dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
+                        dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
                         if (l_srv->callback_response_error)
                                 l_srv->callback_response_error(l_srv,0,NULL,&l_err,sizeof (l_err) );
                         break;
@@ -276,7 +282,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                         log_it( L_WARNING, "Wrong service uid in request, tx expect to close its output with 0x%016lX",
                                 l_tx_out_cond->subtype.srv_pay.srv_uid );
                         l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_WRONG_SRV_UID  ;
-                        dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
+                        dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
                         if (l_srv->callback_response_error)
                                 l_srv->callback_response_error(l_srv,0,NULL,&l_err,sizeof (l_err) );
                         break;
@@ -287,7 +293,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                 if ( !l_usage ){ // Usage can't add
                     log_it( L_WARNING, "Usage can't add");
                     l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_USAGE_CANT_ADD;
-                    dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
+                    dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
                     if (l_srv->callback_response_error)
                             l_srv->callback_response_error(l_srv,0,NULL,&l_err,sizeof (l_err) );
                     break;
@@ -296,9 +302,11 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                 l_err.usage_id = l_usage->id;
 
                 // Create one client
-                l_usage->clients = DAP_NEW_Z( dap_chain_net_srv_client_t);
-                l_usage->clients->ch = a_ch;
-                l_usage->clients->ts_created = time(NULL);
+                l_usage->client = DAP_NEW_Z( dap_chain_net_srv_client_t);
+                l_usage->client->stream_worker = a_ch->stream_worker;
+                l_usage->client->ch = a_ch;
+                l_usage->client->session_id = a_ch->stream->session->id;
+                l_usage->client->ts_created = time(NULL);
                 l_usage->tx_cond = l_tx;
                 memcpy(&l_usage->tx_cond_hash, &l_request->hdr.tx_cond,sizeof (l_usage->tx_cond_hash));
                 l_usage->ts_created = time(NULL);
@@ -326,18 +334,18 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                                 l_ticker, l_net->pub.name );
                         dap_chain_net_srv_usage_delete(l_srv_session, l_usage);
                         l_err.code =DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN;
-                        dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
+                        dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
                         if (l_srv->callback_response_error)
-                                l_srv->callback_response_error(l_srv,l_usage->id,l_usage->clients,&l_err,sizeof (l_err) );
+                                l_srv->callback_response_error(l_srv,l_usage->id,l_usage->client,&l_err,sizeof (l_err) );
                         break;
                     }
                 }
                 int ret;
-                if ( (ret= l_srv->callback_requested(l_srv,l_usage->id, l_usage->clients, l_request, l_ch_pkt->hdr.size  ) )!= 0 ){
+                if ( (ret= l_srv->callback_requested(l_srv,l_usage->id, l_usage->client, l_request, l_ch_pkt->hdr.size  ) )!= 0 ){
                     log_it( L_WARNING, "Request canceled by service callback, return code %d", ret);
                     dap_chain_net_srv_usage_delete(l_srv_session, l_usage);
                     l_err.code = (uint32_t) ret ;
-                    dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
+                    dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
                     if (l_srv->callback_response_error)
                             l_srv->callback_response_error(l_srv,l_usage->id, NULL,&l_err,sizeof (l_err) );
                     break;
@@ -348,12 +356,12 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                         l_usage->price = l_price;
                         // TODO extend callback to pass ext and ext size from service callbacks
                         l_receipt = dap_chain_net_srv_issue_receipt( l_usage->service, l_usage, l_usage->price,NULL,0 );
-                        dap_stream_ch_pkt_write( l_usage->clients->ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_REQUEST ,
+                        dap_stream_ch_pkt_write_unsafe( a_ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_REQUEST ,
                                                  l_receipt, l_receipt->size);
 
                     }else{
                         l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_PRICE_NOT_FOUND ;
-                        dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
+                        dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
                         if (l_srv->callback_response_error)
                                 l_srv->callback_response_error( l_srv, l_usage->id, NULL, &l_err, sizeof( l_err ) );
                     }
@@ -368,13 +376,13 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                     l_success->hdr.net_id.uint64 = l_usage->net->pub.id.uint64;
                     l_success->hdr.srv_uid.uint64 = l_usage->service->uid.uint64;
 
-                    if (dap_stream_ch_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_SUCCESS,
+                    if (dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_SUCCESS,
                                                  l_success, l_success_size)) {
-                        dap_stream_ch_set_ready_to_write(a_ch, true);
+                        dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
                     }
 
                     if ( l_usage->service->callback_receipt_first_success )
-                        l_usage->service->callback_receipt_first_success ( l_usage->service, l_usage->id,  l_usage->clients, NULL, 0 );
+                        l_usage->service->callback_receipt_first_success ( l_usage->service, l_usage->id,  l_usage->client, NULL, 0 );
                     DAP_DELETE(l_success);
 
                 }
@@ -402,9 +410,9 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
             if(l_srv && l_srv->callback_client_sign_request) {
                 // Sign receipt
                 l_srv->callback_client_sign_request(l_srv, 0, NULL, &l_receipt_new, l_receipt_size);
-                if(dap_stream_ch_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_RESPONSE,
+                if(dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_RESPONSE,
                         l_receipt_new, l_receipt_new->size)) {
-                    dap_stream_ch_set_ready_to_write(a_ch, true);
+                    dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
                 }
             }
                 DAP_DELETE(l_receipt_new);
@@ -436,9 +444,9 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                     if ( !l_is_found || ! l_usage ){
                         log_it(L_WARNING, "Can't find receipt in usages thats equal to response receipt");
                         l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_CANT_FIND ;
-                        dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
+                        dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
                         if (l_usage && l_usage->service && l_usage->service->callback_response_error)
-                                l_usage->service->callback_response_error(l_usage->service,l_usage->id, l_usage->clients,&l_err,sizeof (l_err) );
+                                l_usage->service->callback_response_error(l_usage->service,l_usage->id, l_usage->client,&l_err,sizeof (l_err) );
                         break;
                     }
                     l_err.usage_id = l_usage->id;
@@ -448,9 +456,9 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                     if (! l_usage->tx_cond ){
                         log_it(L_WARNING, "No tx out in usage");
                         l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_FOUND ;
-                        dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
+                        dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
                         if (l_usage->service->callback_response_error)
-                                l_usage->service->callback_response_error( l_usage->service, l_usage->id, l_usage->clients,
+                                l_usage->service->callback_response_error( l_usage->service, l_usage->id, l_usage->client,
                                                                           &l_err, sizeof (l_err) );
                         break;
                     }
@@ -460,18 +468,18 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
 
                     if ( ! l_tx_out_cond ){ // No conditioned output
                         l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NO_COND_OUT ;
-                        dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
+                        dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
                         if (l_usage->service->callback_response_error)
-                                l_usage->service->callback_response_error( l_usage->service, l_usage->id, l_usage->clients,&l_err,sizeof (l_err) );
+                                l_usage->service->callback_response_error( l_usage->service, l_usage->id, l_usage->client,&l_err,sizeof (l_err) );
                         break;
                     }
                     // get a second signature - from the client (first sign in server, second sign in client)
                     dap_sign_t * l_receipt_sign = dap_chain_datum_tx_receipt_sign_get( l_receipt, l_receipt_size, 1);
                     if ( ! l_receipt_sign ){
                         l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_CANT_FIND ;
-                        dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
+                        dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
                         if (l_usage->service->callback_response_error)
-                                l_usage->service->callback_response_error( l_usage->service, l_usage->id, l_usage->clients,
+                                l_usage->service->callback_response_error( l_usage->service, l_usage->id, l_usage->client,
                                                                            &l_err, sizeof (l_err) );
                         break;
                     }
@@ -483,9 +491,9 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
 
                     if( memcmp ( l_pkey_hash.raw, l_tx_out_cond->subtype.srv_pay.pkey_hash.raw , sizeof(l_pkey_hash) ) != 0 ){
                         l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_WRONG_PKEY_HASH ;
-                        dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
+                        dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
                         if (l_usage->service->callback_response_error)
-                                l_usage->service->callback_response_error(l_usage->service,l_usage->id, l_usage->clients,&l_err,sizeof (l_err) );
+                                l_usage->service->callback_response_error(l_usage->service,l_usage->id, l_usage->client,&l_err,sizeof (l_err) );
                         break;
                     }
 
@@ -548,12 +556,12 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                         memcpy(l_success->custom_data, l_tx_in_hash, sizeof(dap_chain_hash_fast_t));
                         DAP_DELETE(l_tx_in_hash);
                     }
-                    dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_SUCCESS ,
+                    dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_SUCCESS ,
                                                  l_success, l_success_size);
                     DAP_DELETE(l_success);
 
                     if ( l_is_first_sign && l_usage->service->callback_receipt_first_success){
-                        if( l_usage->service->callback_receipt_first_success(l_usage->service,l_usage->id,  l_usage->clients,
+                        if( l_usage->service->callback_receipt_first_success(l_usage->service,l_usage->id,  l_usage->client,
                                                                     l_receipt, l_receipt_size ) !=0 ){
                             log_it(L_NOTICE, "No success by service callback, inactivating service usage");
                             l_usage->is_active = false;
@@ -561,11 +569,11 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                         // issue receipt next
                         l_usage->receipt_next = dap_chain_net_srv_issue_receipt( l_usage->service, l_usage, l_usage->price ,NULL,0);
                         l_usage->receipt_next_size = l_usage->receipt_next->size;
-                        dap_stream_ch_pkt_write( l_usage->clients->ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_REQUEST ,
+                        dap_stream_ch_pkt_write_unsafe( a_ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_REQUEST ,
                                                  l_usage->receipt_next, l_usage->receipt_next->size);
 
                     }else if ( l_usage->service->callback_receipt_next_success){
-                        if (l_usage->service->callback_receipt_next_success(l_usage->service,l_usage->id,  l_usage->clients,
+                        if (l_usage->service->callback_receipt_next_success(l_usage->service,l_usage->id,  l_usage->client,
                                                                     l_receipt, l_receipt_size ) != 0 ){
                             log_it(L_NOTICE, "No success by service callback, inactivating service usage");
                             l_usage->is_active = false;
@@ -585,10 +593,12 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                 dap_chain_net_srv_t * l_srv = dap_chain_net_srv_get(l_success->hdr.srv_uid);
                 if ( l_srv && l_srv->callback_client_success){
                     // Create client for client)
-                    dap_chain_net_srv_client_t *l_clients = DAP_NEW_Z( dap_chain_net_srv_client_t);
-                    l_clients->ch = a_ch;
-                    l_clients->ts_created = time(NULL);
-                    l_srv->callback_client_success(l_srv, l_success->hdr.usage_id,  l_clients, l_success, l_success_size );
+                    dap_chain_net_srv_client_t *l_client = DAP_NEW_Z( dap_chain_net_srv_client_t);
+                    l_client->ch = a_ch;
+                    l_client->stream_worker = a_ch->stream_worker;
+                    l_client->ts_created = time(NULL);
+                    l_client->session_id = a_ch->stream->session->id;
+                    l_srv->callback_client_success(l_srv, l_success->hdr.usage_id,  l_client, l_success, l_success_size );
                     //l_success->hdr.net_id, l_success->hdr.srv_uid, l_success->hdr.usage_id
                 }
             } break;
@@ -601,25 +611,25 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                 dap_stream_ch_chain_net_srv_pkt_data_t * l_pkt =(dap_stream_ch_chain_net_srv_pkt_data_t *) l_ch_pkt->data;
                 size_t l_pkt_size = l_ch_pkt->hdr.size - sizeof (dap_stream_ch_chain_net_srv_pkt_data_t);
                 dap_chain_net_srv_t * l_srv = dap_chain_net_srv_get( l_pkt->hdr.srv_uid);
-                dap_chain_net_srv_usage_t * l_usage = dap_chain_net_srv_usage_find( l_srv_session, l_pkt->hdr.usage_id );
+                dap_chain_net_srv_usage_t * l_usage = dap_chain_net_srv_usage_find_unsafe( l_srv_session, l_pkt->hdr.usage_id );
 
                 // If service not found
                 if ( l_srv == NULL){
                     l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_SERVICE_NOT_FOUND ;
                     l_err.srv_uid = l_pkt->hdr.srv_uid;
-                    dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
+                    dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
                     break;
                 }
                 // Check if callback is not present
                 if ( l_srv->callback_stream_ch_read == NULL ){
                     l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_SERVICE_CH_NOT_FOUND ;
                     l_err.srv_uid = l_pkt->hdr.srv_uid;
-                    dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
+                    dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
                     break;
                 }
                 // Call callback if present
 
-                l_srv->callback_stream_ch_read( l_srv,l_usage->id, l_usage->clients, l_pkt->data, l_pkt_size );
+                l_srv->callback_stream_ch_read( l_srv,l_usage->id, l_usage->client, l_pkt->data, l_pkt_size );
 
 
             } break;
@@ -650,7 +660,7 @@ void s_stream_ch_packet_out(dap_stream_ch_t* a_ch , void* a_arg)
 {
     (void) a_arg;
 
-    dap_stream_ch_set_ready_to_write(a_ch, false);
+    dap_stream_ch_set_ready_to_write_unsafe(a_ch, false);
     // Callback should note that after write action it should restore write flag if it has more data to send on next iteration
     dap_chain_net_srv_call_write_all( a_ch);
 }
diff --git a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.h b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.h
index f6b83f171919a1d99abfff45a5cfa156cb3a5380..ced85e9ac1bb8bba8a12a71edd3208982f33d8f0 100644
--- a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.h
+++ b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.h
@@ -44,4 +44,4 @@ typedef struct dap_stream_ch_chain_net_srv {
 
 void dap_stream_ch_chain_net_srv_set_srv_uid(dap_stream_ch_t* a_ch, dap_chain_net_srv_uid_t a_srv_uid);
 uint8_t dap_stream_ch_chain_net_srv_get_id();
-
+int dap_stream_ch_chain_net_srv_init(void);
diff --git a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv_pkt.c b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv_pkt.c
index 1ec2de169a8d7df4db04f2d42d706c8f97debce7..a6f028efe7734c86f29fc4b16783f71c50c1e32a 100644
--- a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv_pkt.c
+++ b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv_pkt.c
@@ -50,7 +50,7 @@ size_t dap_stream_ch_chain_net_srv_pkt_data_write(dap_stream_ch_t *a_ch,
     l_pkt_data->hdr.srv_uid = a_srv_uid;
     l_pkt_data->hdr.usage_id = a_usage_id;
     memcpy( l_pkt_data->data, a_data, a_data_size);
-    size_t l_ret  = dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_DATA , l_pkt_data, l_pkt_data_size);
+    size_t l_ret  = dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_DATA , l_pkt_data, l_pkt_data_size);
     DAP_DELETE(l_pkt_data);
     return l_ret;
 }
diff --git a/modules/channel/chain-net/dap_stream_ch_chain_net.c b/modules/channel/chain-net/dap_stream_ch_chain_net.c
index 74dcd903c674c4f4e93b15f8ca5c9da53562adbc..3bc1d829ddea5eb4a4a7e0883de688ec00334cc3 100644
--- a/modules/channel/chain-net/dap_stream_ch_chain_net.c
+++ b/modules/channel/chain-net/dap_stream_ch_chain_net.c
@@ -186,7 +186,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
     dap_chain_net_session_data_t *l_session_data = session_data_find(a_ch->stream->session->id);
     if (l_session_data == NULL) {
         log_it(L_ERROR, "Can't find chain net session for stream session %d", a_ch->stream->session->id);
-        dap_stream_ch_set_ready_to_write(a_ch, false);
+        dap_stream_ch_set_ready_to_write_unsafe(a_ch, false);
     }
 
     if(l_ch_chain_net) {
@@ -210,7 +210,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
         if (l_error) {
             dap_stream_ch_chain_net_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_ERROR ,
                                               l_ch_chain_net_pkt->hdr.net_id, l_err_str, strlen(l_err_str) + 1);
-            dap_stream_ch_set_ready_to_write(a_ch, true);
+            dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
         }
         //size_t l_ch_chain_net_pkt_data_size = (size_t) l_ch_pkt->hdr.size - sizeof (l_ch_chain_net_pkt->hdr);
         if (!l_error && l_ch_chain_net_pkt) {
@@ -219,7 +219,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                 case DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_DBG: {
                     dap_stream_ch_chain_net_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_PING,
                                                       l_ch_chain_net_pkt->hdr.net_id, NULL, 0);
-                    dap_stream_ch_set_ready_to_write(a_ch, true);
+                    dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
                 }
                     break;
                     // received ping request - > send pong request
@@ -227,13 +227,13 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                     //log_it(L_INFO, "Get STREAM_CH_CHAIN_NET_PKT_TYPE_PING");
                     dap_stream_ch_chain_net_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_PONG,
                                                       l_ch_chain_net_pkt->hdr.net_id,NULL, 0);
-                    dap_stream_ch_set_ready_to_write(a_ch, true);
+                    dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
                 }
                     break;
                     // receive pong request -> send nothing
                 case DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_PONG: {
                     //log_it(L_INFO, "Get STREAM_CH_CHAIN_NET_PKT_TYPE_PONG");
-                    dap_stream_ch_set_ready_to_write(a_ch, false);
+                    dap_stream_ch_set_ready_to_write_unsafe(a_ch, false);
                 }
                 break;
                 case DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_NODE_ADDR: {
@@ -246,7 +246,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                         log_it(L_WARNING,"Wrong data secion size %u",l_ch_chain_net_pkt_data_size,
                                sizeof (dap_chain_node_addr_t));
                     }
-                    dap_stream_ch_set_ready_to_write(a_ch, false);
+                    dap_stream_ch_set_ready_to_write_unsafe(a_ch, false);
                 }break;
                 case DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_NODE_ADDR_LEASE: {
                     log_it(L_INFO, "Get CH_CHAIN_NET_PKT_TYPE_NODE_ADDR_LEASE");
@@ -258,7 +258,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                             char l_err_str[]="ERROR_NET_INVALID_ID";
                             dap_stream_ch_chain_net_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_ERROR ,
                                                               l_ch_chain_net_pkt->hdr.net_id, l_err_str,sizeof (l_err_str));
-                            dap_stream_ch_set_ready_to_write(a_ch, true);
+                            dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
                             log_it(L_ERROR, "Invalid net id in packet");
                         } else {
                             if (dap_db_set_cur_node_addr_exp( l_addr->uint64, l_net->pub.name ))
@@ -271,7 +271,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                         log_it(L_WARNING,"Wrong data secion size %u",l_ch_chain_net_pkt_data_size,
                                sizeof (dap_chain_node_addr_t));
                     }
-                    dap_stream_ch_set_ready_to_write(a_ch, false);
+                    dap_stream_ch_set_ready_to_write_unsafe(a_ch, false);
                 }break;
                 // get current node address
                 case DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_NODE_ADDR_REQUEST: {
@@ -283,7 +283,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                     // send cur node addr
                     dap_stream_ch_chain_net_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_NODE_ADDR,
                                                       l_ch_chain_net_pkt->hdr.net_id, &l_addr, l_send_data_len);
-                    dap_stream_ch_set_ready_to_write(a_ch, true);
+                    dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
                 } break;
                 case DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_NODE_ADDR_LEASE_REQUEST: {
                     log_it(L_INFO, "Get STREAM_CH_CHAIN_NET_PKT_TYPE_NODE_ADDR_REQUEST");
@@ -293,12 +293,12 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                         char l_err_str[]="ERROR_NET_INVALID_ID";
                         dap_stream_ch_chain_net_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_ERROR , l_net->pub.id,
                                                           l_err_str,sizeof (l_err_str));
-                        dap_stream_ch_set_ready_to_write(a_ch, true);
+                        dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
                     } else {
                         dap_chain_node_addr_t *l_addr_new = dap_chain_node_gen_addr(l_net, &l_net->pub.cell_id );
                         dap_stream_ch_chain_net_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_NODE_ADDR_LEASE ,
                                                          l_ch_chain_net_pkt->hdr.net_id, l_addr_new, sizeof (*l_addr_new));
-                        dap_stream_ch_set_ready_to_write(a_ch, true);
+                        dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
                         memcpy( &l_session_data->addr_remote,l_addr_new,sizeof (*l_addr_new) );
                         DAP_DELETE(l_addr_new);
                     }
@@ -323,5 +323,5 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
  */
 void s_stream_ch_packet_out(dap_stream_ch_t* a_ch, void* a_arg)
 {
-    dap_stream_ch_set_ready_to_write(a_ch, false);
+    dap_stream_ch_set_ready_to_write_unsafe(a_ch, false);
 }
diff --git a/modules/channel/chain-net/dap_stream_ch_chain_net_pkt.c b/modules/channel/chain-net/dap_stream_ch_chain_net_pkt.c
index d5626fc7e9f219c3d1a67881569dbb2dc72d8e52..717fc1d7153b20ccf04bec758baea230d5c78fa3 100644
--- a/modules/channel/chain-net/dap_stream_ch_chain_net_pkt.c
+++ b/modules/channel/chain-net/dap_stream_ch_chain_net_pkt.c
@@ -41,7 +41,7 @@ size_t dap_stream_ch_chain_net_pkt_write(dap_stream_ch_t *a_ch, uint8_t a_type,d
     l_net_pkt->hdr.version = 1;
     l_net_pkt->hdr.net_id.uint64 = a_net_id.uint64;
     memcpy( l_net_pkt->data, a_data, a_data_size);
-    size_t l_ret  = dap_stream_ch_pkt_write(a_ch, a_type , l_net_pkt, l_net_pkt_size);
+    size_t l_ret  = dap_stream_ch_pkt_write_unsafe(a_ch, a_type , l_net_pkt, l_net_pkt_size);
     DAP_DELETE(l_net_pkt);
     return l_ret;
 }
diff --git a/modules/channel/chain/dap_stream_ch_chain.c b/modules/channel/chain/dap_stream_ch_chain.c
index 140bf61c3c3c2d6ec73f4998d7eccefa2fedbc6a..607a183509803aa709b230b7353c527da02fae72 100644
--- a/modules/channel/chain/dap_stream_ch_chain.c
+++ b/modules/channel/chain/dap_stream_ch_chain.c
@@ -46,6 +46,10 @@
 #include "dap_hash.h"
 #include "utlist.h"
 
+#include "dap_worker.h"
+#include "dap_events.h"
+#include "dap_proc_thread.h"
+
 #include "dap_chain.h"
 #include "dap_chain_datum.h"
 #include "dap_chain_cs.h"
@@ -55,6 +59,7 @@
 #include "dap_chain_global_db_remote.h"
 
 #include "dap_stream.h"
+#include "dap_stream_worker.h"
 #include "dap_stream_ch_pkt.h"
 #include "dap_stream_ch.h"
 #include "dap_stream_ch_proc.h"
@@ -118,6 +123,258 @@ void s_stream_ch_delete(dap_stream_ch_t* a_ch, void* a_arg)
     pthread_mutex_destroy(&DAP_STREAM_CH_CHAIN(a_ch)->mutex);
 }
 
+
+bool s_sync_chains_callback(dap_proc_thread_t *a_thread, void *a_arg)
+{
+    UNUSED(a_thread);
+    dap_stream_ch_t *l_ch = (dap_stream_ch_t *)a_arg;
+    dap_stream_ch_chain_t *l_ch_chain = DAP_STREAM_CH_CHAIN(l_ch);
+
+    dap_chain_t * l_chain = dap_chain_find_by_id(l_ch_chain->request_net_id, l_ch_chain->request_chain_id);
+
+    dap_chain_atom_ptr_t * l_lasts = NULL;
+    size_t *l_lasts_sizes = NULL;
+    size_t l_lasts_count = 0;
+    dap_chain_atom_iter_t* l_iter = l_chain->callback_atom_iter_create(l_chain);
+    l_ch_chain->request_atom_iter = l_iter;
+    l_lasts = l_chain->callback_atom_iter_get_lasts(l_iter, &l_lasts_count, &l_lasts_sizes);
+    log_it(L_INFO, "Found %d last atoms for synchronization", l_lasts_count);
+    if (l_lasts && l_lasts_sizes) {
+        for(long int i = 0; i < l_lasts_count; i++) {
+            dap_chain_atom_item_t * l_item = NULL;
+            dap_chain_hash_fast_t l_atom_hash;
+            dap_hash_fast(l_lasts[i], l_lasts_sizes[i], &l_atom_hash);
+            pthread_mutex_lock(&l_ch_chain->mutex);
+            HASH_FIND(hh, l_ch_chain->request_atoms_lasts, &l_atom_hash, sizeof(l_atom_hash),
+                    l_item);
+            if(l_item == NULL) { // Not found, add new lasts
+                l_item = DAP_NEW_Z(dap_chain_atom_item_t);
+                l_item->atom = l_lasts[i];
+                l_item->atom_size = l_lasts_sizes[i];
+                memcpy(&l_item->atom_hash, &l_atom_hash, sizeof(l_atom_hash));
+                HASH_ADD(hh, l_ch_chain->request_atoms_lasts, atom_hash, sizeof(l_atom_hash),
+                        l_item);
+            }
+            pthread_mutex_unlock(&l_ch_chain->mutex);
+        }
+        // first packet
+        l_ch_chain->state = CHAIN_STATE_SYNC_CHAINS;
+        dap_chain_node_addr_t l_node_addr = { 0 };
+        dap_chain_net_t *l_net = dap_chain_net_by_id(l_ch_chain->request_net_id);
+        l_node_addr.uint64 = l_net ? dap_db_get_cur_node_addr(l_net->pub.name) : 0;
+        dap_stream_ch_chain_pkt_write_unsafe(l_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_FIRST_CHAIN,
+                l_ch_chain->request_net_id, l_ch_chain->request_chain_id,
+                l_ch_chain->request_cell_id, &l_node_addr, sizeof(dap_chain_node_addr_t));
+    }
+    else {
+        // last packet
+        dap_stream_ch_chain_sync_request_t l_request;
+        memset(&l_request,0,sizeof (l_request));
+        dap_stream_ch_chain_pkt_write_unsafe(l_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_CHAINS,
+                l_ch_chain->request_net_id, l_ch_chain->request_chain_id,
+                l_ch_chain->request_cell_id, &l_request, sizeof(l_request));
+        l_ch_chain->state = CHAIN_STATE_IDLE;
+    }
+    DAP_DELETE(l_lasts);
+    DAP_DELETE(l_iter);
+    dap_stream_ch_set_ready_to_write_unsafe(l_ch, true);
+    dap_events_socket_assign_on_worker_mt(l_ch->stream->esocket, l_ch->stream_worker->worker);
+    return true;
+}
+
+bool s_sync_gdb_callback(dap_proc_thread_t *a_thread, void *a_arg)
+{
+    UNUSED(a_thread);
+    dap_stream_ch_t *l_ch = (dap_stream_ch_t *)a_arg;
+    dap_stream_ch_chain_t *l_ch_chain = DAP_STREAM_CH_CHAIN(l_ch);
+
+    // Get log diff
+    l_ch_chain->request_last_ts = dap_db_log_get_last_id();
+    //log_it(L_DEBUG, "Requested transactions %llu:%llu", l_request->id_start, (uint64_t ) l_ch_chain->request_last_ts);
+    uint64_t l_start_item = l_ch_chain->request.id_start;
+    // If the current global_db has been truncated, but the remote node has not known this
+    if(l_ch_chain->request.id_start > l_ch_chain->request_last_ts) {
+        l_start_item = 0;
+    }
+    dap_chain_net_t *l_net = dap_chain_net_by_id(l_ch_chain->request_net_id);
+    dap_list_t *l_add_groups = dap_chain_net_get_add_gdb_group(l_net, l_ch_chain->request.node_addr);
+    dap_db_log_list_t *l_db_log = dap_db_log_list_start(l_start_item + 1, l_add_groups);
+    dap_chain_node_addr_t l_node_addr = { 0 };
+    l_node_addr.uint64 = l_net ? dap_db_get_cur_node_addr(l_net->pub.name) : 0;
+    dap_stream_ch_chain_pkt_write_unsafe(l_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_FIRST_GLOBAL_DB,
+            l_ch_chain->request_net_id, l_ch_chain->request_chain_id,
+            l_ch_chain->request_cell_id, &l_node_addr, sizeof(dap_chain_node_addr_t));
+    if(l_db_log) {
+        //log_it(L_DEBUG, "Start getting items %u:%u", l_request->id_start + 1,l_db_log->items_number);//dap_list_length(l_list));
+        // Add it to outgoing list
+        l_ch_chain->request_global_db_trs = l_db_log;
+        l_ch_chain->db_iter = NULL;
+        l_ch_chain->state = CHAIN_STATE_SYNC_GLOBAL_DB;
+    } else {
+        dap_stream_ch_chain_sync_request_t l_request = {};
+        //log_it(L_DEBUG, "No items to sync from %u", l_request->id_start + 1);
+        l_request.node_addr.uint64 = l_net ? dap_db_get_cur_node_addr(l_net->pub.name) : 0;
+        l_request.id_start = dap_db_log_get_last_id_remote(l_ch_chain->request.node_addr.uint64);
+        dap_stream_ch_chain_pkt_write_unsafe(l_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB,
+                                             l_ch_chain->request_net_id, l_ch_chain->request_chain_id,
+                                             l_ch_chain->request_cell_id, &l_request, sizeof(l_request));
+        l_ch_chain->state = CHAIN_STATE_IDLE;
+        if(l_ch_chain->callback_notify_packet_out)
+            l_ch_chain->callback_notify_packet_out(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB,
+                                                    NULL, 0, l_ch_chain->callback_notify_arg);
+    }
+    //log_it(L_INFO, "Prepared %u items for sync", l_db_log->items_number - l_request->id_start);
+    // go to send data from list [in s_stream_ch_packet_out()]
+    // no data to send -> send one empty message DAP_STREAM_CH_CHAIN_PKT_TYPE_GLOBAL_DB_SYNCED
+    dap_stream_ch_set_ready_to_write_unsafe(l_ch, true);
+    dap_events_socket_assign_on_worker_mt(l_ch->stream->esocket, l_ch->stream_worker->worker);
+    return true;
+}
+
+bool s_chain_pkt_callback(dap_proc_thread_t *a_thread, void *a_arg)
+{
+    UNUSED(a_thread);
+    dap_stream_ch_t *l_ch = (dap_stream_ch_t *)a_arg;
+    dap_stream_ch_chain_t *l_ch_chain = DAP_STREAM_CH_CHAIN(l_ch);
+    dap_chain_t * l_chain = dap_chain_find_by_id(l_ch_chain->request_net_id, l_ch_chain->request_chain_id);
+    if (!l_chain) {
+        log_it(L_WARNING, "No chain found for DAP_STREAM_CH_CHAIN_PKT_TYPE_CHAIN");
+        return true;
+    }
+
+    dap_chain_hash_fast_t l_atom_hash = {};
+    dap_chain_atom_ptr_t l_atom_copy = l_ch_chain->pkt_data;
+    uint64_t l_atom_copy_size = l_ch_chain->pkt_data_size;
+    l_ch_chain->pkt_data = NULL;
+    l_ch_chain->pkt_data_size = 0;
+    if( l_atom_copy && l_atom_copy_size){
+        dap_hash_fast(l_atom_copy, l_atom_copy_size, &l_atom_hash);
+        dap_chain_atom_iter_t *l_atom_iter = l_chain->callback_atom_iter_create(l_chain);
+        size_t l_atom_size =0;
+        if ( l_chain->callback_atom_find_by_hash(l_atom_iter, &l_atom_hash, &l_atom_size) == NULL ) {
+            dap_chain_atom_verify_res_t l_atom_add_res = l_chain->callback_atom_add(l_chain, l_atom_copy, l_atom_copy_size);
+            if(l_atom_add_res == ATOM_ACCEPT && dap_chain_has_file_store(l_chain)) {
+                // append to file
+                dap_chain_cell_t *l_cell = dap_chain_cell_create_fill(l_chain, l_ch_chain->request_cell_id);
+                // add one atom only
+                int l_res = dap_chain_cell_file_append(l_cell, l_atom_copy, l_atom_copy_size);
+                // rewrite all file
+                //l_res = dap_chain_cell_file_update(l_cell);
+                if(!l_cell || l_res < 0) {
+                    log_it(L_ERROR, "Can't save event 0x%x to the file '%s'", l_atom_hash,
+                            l_cell ? l_cell->file_storage_path : "[null]");
+                }
+                // delete cell and close file
+                dap_chain_cell_delete(l_cell);
+            }
+            if(l_atom_add_res == ATOM_PASS)
+                DAP_DELETE(l_atom_copy);
+        } else {
+            DAP_DELETE(l_atom_copy);
+        }
+        l_chain->callback_atom_iter_delete(l_atom_iter);
+    }else
+        log_it(L_WARNING, "In proc thread got stream ch packet with pkt_size: %zd and pkt_data: %p", l_atom_copy_size, l_atom_copy);
+    dap_events_socket_assign_on_worker_mt(l_ch->stream->esocket, l_ch->stream_worker->worker);
+    return true;
+}
+
+bool s_gdb_pkt_callback(dap_proc_thread_t *a_thread, void *a_arg)
+{
+    UNUSED(a_thread);
+    dap_stream_ch_t *l_ch = (dap_stream_ch_t *)a_arg;
+    dap_stream_ch_chain_t *l_ch_chain = DAP_STREAM_CH_CHAIN(l_ch);
+    dap_chain_t * l_chain = dap_chain_find_by_id(l_ch_chain->request_net_id, l_ch_chain->request_chain_id);
+
+    size_t l_data_obj_count = 0;
+    // deserialize data & Parse data from dap_db_log_pack()
+    dap_store_obj_t *l_store_obj = dap_db_log_unpack(l_ch_chain->pkt_data,l_ch_chain->pkt_data_size, &l_data_obj_count);
+    //log_it(L_INFO, "In: l_data_obj_count = %d", l_data_obj_count );
+
+    for(size_t i = 0; i < l_data_obj_count; i++) {
+        // timestamp for exist obj
+        time_t l_timestamp_cur = 0;
+        // obj to add
+        dap_store_obj_t* l_obj = l_store_obj + i;
+        // read item from base;
+        size_t l_count_read = 0;
+        dap_store_obj_t *l_read_obj = dap_chain_global_db_driver_read(l_obj->group,
+                l_obj->key, &l_count_read);
+        // get timestamp for the exist entry
+        if(l_read_obj)
+            l_timestamp_cur = l_read_obj->timestamp;
+        // get timestamp for the deleted entry
+        else
+        {
+            l_timestamp_cur = global_db_gr_del_get_timestamp(l_obj->group, l_obj->key);
+        }
+
+        //check whether to apply the received data into the database
+        bool l_apply = true;
+        if(l_obj->timestamp < l_timestamp_cur)
+            l_apply = false;
+        else if(l_obj->type == 'd') {
+            // already deleted
+            if(!l_read_obj)
+                l_apply = false;
+        }
+        else if(l_obj->type == 'a') {
+            bool l_is_the_same_present = false;
+            if(l_read_obj &&
+                    l_read_obj->value_len == l_obj->value_len &&
+                    !memcmp(l_read_obj->value, l_obj->value, l_obj->value_len))
+                l_is_the_same_present = true;
+            // this data already present in global_db and not obsolete (out of date)
+            if(l_read_obj && (l_is_the_same_present || l_read_obj->timestamp >= l_store_obj->timestamp))
+                l_apply = false;
+        }
+        if(l_read_obj)
+            dap_store_obj_free(l_read_obj, l_count_read);
+
+        if(!l_apply) {
+            // If request was from defined node_addr we update its state
+            if(l_ch_chain->request.node_addr.uint64) {
+                dap_db_log_set_last_id_remote(l_ch_chain->request.node_addr.uint64, l_obj->id);
+            }
+            continue;
+        }
+
+        char l_ts_str[50];
+        dap_time_to_str_rfc822(l_ts_str, sizeof(l_ts_str), l_store_obj[i].timestamp);
+        /*log_it(L_DEBUG, "Unpacked log history: type='%c' (0x%02hhX) group=\"%s\" key=\"%s\""
+                " timestamp=\"%s\" value_len=%u  ",
+                (char ) l_store_obj[i].type, l_store_obj[i].type, l_store_obj[i].group,
+                l_store_obj[i].key, l_ts_str, l_store_obj[i].value_len);*/
+        // apply received transaction
+        dap_chain_t *l_chain = dap_chain_find_by_id(l_ch_chain->request_net_id, l_ch_chain->request_chain_id);
+        if(l_chain) {
+            if(l_chain->callback_datums_pool_proc_with_group){
+                void * restrict l_store_obj_value = l_store_obj->value;
+                l_chain->callback_datums_pool_proc_with_group(l_chain,
+                        (dap_chain_datum_t** restrict) l_store_obj_value, 1,
+                        l_store_obj[i].group);
+            }
+        }
+        // save data to global_db
+        if(!dap_chain_global_db_obj_save(l_obj, 1)) {
+            dap_stream_ch_chain_pkt_write_error(l_ch, l_ch_chain->request_net_id,
+                                                l_ch_chain->request_chain_id, l_ch_chain->request_cell_id,
+                                                "ERROR_GLOBAL_DB_INTERNAL_NOT_SAVED");
+            dap_stream_ch_set_ready_to_write_unsafe(l_ch, true);
+        } else {
+            // If request was from defined node_addr we update its state
+            if(l_ch_chain->request.node_addr.uint64) {
+                dap_db_log_set_last_id_remote(l_ch_chain->request.node_addr.uint64, l_obj->id);
+            }
+            //log_it(L_DEBUG, "Added new GLOBAL_DB history pack");
+        }
+    }
+    if(l_store_obj)
+        dap_store_obj_free(l_store_obj, l_data_obj_count);
+    dap_events_socket_assign_on_worker_mt(l_ch->stream->esocket, l_ch->stream_worker->worker);
+    return true;
+}
+
 /**
  * @brief s_stream_ch_packet_in
  * @param a_ch
@@ -125,145 +382,75 @@ void s_stream_ch_delete(dap_stream_ch_t* a_ch, void* a_arg)
  */
 void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
 {
-    //static char *s_net_name = NULL;
     dap_stream_ch_chain_t * l_ch_chain = DAP_STREAM_CH_CHAIN(a_ch);
-    if(l_ch_chain) {
-        dap_stream_ch_pkt_t * l_ch_pkt = (dap_stream_ch_pkt_t *) a_arg;
-        dap_stream_ch_chain_pkt_t * l_chain_pkt = (dap_stream_ch_chain_pkt_t *) l_ch_pkt->data;
-        uint8_t l_acl_idx = dap_chain_net_acl_idx_by_id(l_chain_pkt->hdr.net_id);
-        bool l_error = false;
-        char l_err_str[64];
-        if (l_acl_idx == (uint8_t)-1) {
-            log_it(L_ERROR, "Invalid net id in packet");
-            strcpy(l_err_str, "ERROR_NET_INVALID_ID");
-            l_error = true;
-        }
-        if (!l_error && a_ch->stream->session->acl && !a_ch->stream->session->acl[l_acl_idx]) {
-            log_it(L_WARNING, "Unauthorized request attempt to network %s",
-                   dap_chain_net_by_id(l_chain_pkt->hdr.net_id)->pub.name);
-            strcpy(l_err_str, "ERROR_NET_NOT_AUTHORIZED");
-            l_error = true;
-        }
-        if (l_error) {
+    if (!l_ch_chain) {
+        return;
+    }
+    dap_stream_ch_pkt_t * l_ch_pkt = (dap_stream_ch_pkt_t *) a_arg;
+    dap_stream_ch_chain_pkt_t * l_chain_pkt = (dap_stream_ch_chain_pkt_t *) l_ch_pkt->data;
+    if (!l_chain_pkt) {
+        return;
+    }
+    size_t l_chain_pkt_data_size = l_ch_pkt->hdr.size - sizeof(l_chain_pkt->hdr);
+    uint8_t l_acl_idx = dap_chain_net_acl_idx_by_id(l_chain_pkt->hdr.net_id);
+    if (l_acl_idx == (uint8_t)-1) {
+        log_it(L_ERROR, "Invalid net id in packet");
+        if (l_ch_pkt->hdr.type == DAP_STREAM_CH_CHAIN_PKT_TYPE_ERROR) {
+            if(l_ch_chain->callback_notify_packet_in) {
+                l_ch_chain->callback_notify_packet_in(l_ch_chain, l_ch_pkt->hdr.type, l_chain_pkt,
+                                                      l_chain_pkt_data_size, l_ch_chain->callback_notify_arg);
+            }
+        } else {
             dap_stream_ch_chain_pkt_write_error(a_ch, l_chain_pkt->hdr.net_id,
-                    l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id, l_err_str);
-            dap_stream_ch_set_ready_to_write(a_ch, true);
+                                                l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id,
+                                                "ERROR_NET_INVALID_ID");
+            dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
         }
-        size_t l_chain_pkt_data_size = l_ch_pkt->hdr.size - sizeof(l_chain_pkt->hdr);
-        if (!l_error && l_chain_pkt) {
-            switch (l_ch_pkt->hdr.type) {
-            case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_ALL: {
-                log_it(L_INFO, "In:  SYNCED_ALL pkt");
-            }
-                break;
-            case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB: {
-                log_it(L_INFO, "In:  SYNCED_GLOBAL_DB pkt");
-                /*if(s_net_name) {
-                 DAP_DELETE(s_net_name);
-                 s_net_name = NULL; //"kelvin-testnet"
-                 }*/
-            }
-                break;
-            case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB_GROUP: {
-                log_it(L_INFO, "In:  SYNCED_GLOBAL_DB_GROUP pkt");
-                /*if(s_net_name) {
-                 DAP_DELETE(s_net_name);
-                 s_net_name = NULL; //"kelvin-testnet"
-                 }*/
-            }
-                break;
-            case DAP_STREAM_CH_CHAIN_PKT_TYPE_FIRST_GLOBAL_DB_GROUP: {
-                log_it(L_INFO, "In:  SYNCED_GLOBAL_DB_GROUP pkt");
-            }
-                break;
-
-            case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_CHAINS: {
-                log_it(L_INFO, "In:  SYNCED_CHAINS pkt");
-            }
-                break;
-            case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_CHAINS: {
-                //log_it(L_INFO, "In:  SYNC_CHAINS pkt");
-                dap_chain_t * l_chain = dap_chain_find_by_id(l_chain_pkt->hdr.net_id, l_chain_pkt->hdr.chain_id);
-                if(l_chain) {
-                    if(l_ch_chain->state != CHAIN_STATE_IDLE) {
-                        log_it(L_INFO, "Can't process SYNC_CHAINS request because not in idle state");
-                        dap_stream_ch_chain_pkt_write_error(a_ch, l_chain_pkt->hdr.net_id,
-                                l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id,
-                                "ERROR_STATE_NOT_IN_IDLE");
-                    } else {
-                        // fill ids
-                        if(l_chain_pkt_data_size == sizeof(dap_stream_ch_chain_sync_request_t)) {
-                            dap_stream_ch_chain_sync_request_t * l_request =
-                                    (dap_stream_ch_chain_sync_request_t *) l_chain_pkt->data;
-                            memcpy(&l_ch_chain->request, l_request, l_chain_pkt_data_size);
-                            memcpy(&l_ch_chain->request_cell_id, &l_chain_pkt->hdr.cell_id,
-                                    sizeof(dap_chain_cell_id_t));
-                            memcpy(&l_ch_chain->request_net_id, &l_chain_pkt->hdr.net_id, sizeof(dap_chain_net_id_t));
-                            memcpy(&l_ch_chain->request_chain_id, &l_chain_pkt->hdr.chain_id, sizeof(dap_chain_id_t));
-                        }
-
-                        dap_chain_atom_ptr_t * l_lasts = NULL;
-                        size_t l_lasts_size = 0;
-                        dap_chain_atom_iter_t* l_iter = l_chain->callback_atom_iter_create(l_chain);
-                        l_ch_chain->request_atom_iter = l_iter;
-                        l_lasts = l_chain->callback_atom_iter_get_lasts(l_iter, &l_lasts_size);
-                        if(l_lasts) {
-                            for(size_t i = 0; i < l_lasts_size; i++) {
-                                dap_chain_atom_item_t * l_item = NULL;
-                                dap_chain_hash_fast_t l_atom_hash;
-                                dap_hash_fast(l_lasts[i], l_chain->callback_atom_get_size(l_lasts[i]),
-                                        &l_atom_hash);
-                                pthread_mutex_lock(&l_ch_chain->mutex);
-                                HASH_FIND(hh, l_ch_chain->request_atoms_lasts, &l_atom_hash, sizeof(l_atom_hash),
-                                        l_item);
-                                if(l_item == NULL) { // Not found, add new lasts
-                                    l_item = DAP_NEW_Z(dap_chain_atom_item_t);
-                                    l_item->atom = l_lasts[i];
-                                    memcpy(&l_item->atom_hash, &l_atom_hash, sizeof(l_atom_hash));
-                                    HASH_ADD(hh, l_ch_chain->request_atoms_lasts, atom_hash, sizeof(l_atom_hash),
-                                            l_item);
-                                }
-                                pthread_mutex_unlock(&l_ch_chain->mutex);
-                                //else
-                                //    DAP_DELETE(l_lasts[i]);
-                            }
-                            // first packet
-                            l_ch_chain->state = CHAIN_STATE_SYNC_CHAINS;
-                            dap_chain_node_addr_t l_node_addr = { 0 };
-                            dap_chain_net_t *l_net = dap_chain_net_by_id(l_ch_chain->request_net_id);
-                            l_node_addr.uint64 = l_net ? dap_db_get_cur_node_addr(l_net->pub.name) : 0;
-                            dap_stream_ch_chain_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_FIRST_CHAIN,
-                                    l_ch_chain->request_net_id, l_ch_chain->request_chain_id,
-                                    l_ch_chain->request_cell_id, &l_node_addr, sizeof(dap_chain_node_addr_t));
-                        }
-                        else {
-                            // last packet
-                            dap_stream_ch_chain_sync_request_t l_request = { { 0 } };
-                            l_request.id_start = 0;//dap_db_log_get_last_id_remote(l_ch_chain->request.node_addr.uint64);
-                            dap_stream_ch_chain_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_CHAINS,
-                                    l_ch_chain->request_net_id, l_ch_chain->request_chain_id,
-                                    l_ch_chain->request_cell_id, &l_request, sizeof(l_request));
-                            l_ch_chain->state = CHAIN_STATE_IDLE;
-                        }
+        return;
+    }
+    if (a_ch->stream->session->acl && !a_ch->stream->session->acl[l_acl_idx]) {
+        log_it(L_WARNING, "Unauthorized request attempt to network %s",
+               dap_chain_net_by_id(l_chain_pkt->hdr.net_id)->pub.name);
+        dap_stream_ch_chain_pkt_write_error(a_ch, l_chain_pkt->hdr.net_id,
+                                            l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id,
+                                            "ERROR_NET_NOT_AUTHORIZED");
+        dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
+        return;
+    }
+    switch (l_ch_pkt->hdr.type) {
+    case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_ALL: {
+        log_it(L_INFO, "In:  SYNCED_ALL pkt");
+    }
+        break;
+    case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB: {
+        log_it(L_INFO, "In:  SYNCED_GLOBAL_DB pkt");
+    }
+        break;
+    case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB_GROUP: {
+        log_it(L_INFO, "In:  SYNCED_GLOBAL_DB_GROUP pkt");
+    }
+        break;
+    case DAP_STREAM_CH_CHAIN_PKT_TYPE_FIRST_GLOBAL_DB_GROUP: {
+        log_it(L_INFO, "In:  SYNCED_GLOBAL_DB_GROUP pkt");
+    }
+        break;
 
-                        DAP_DELETE(l_lasts);
-                        DAP_DELETE(l_iter);
-                    }
-                    dap_stream_ch_set_ready_to_write(a_ch, true);
-                }
-            }
-                break;
-            case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB: {
-                log_it(L_INFO, "In:  SYNC_GLOBAL_DB pkt");
-                if(l_ch_chain->state != CHAIN_STATE_IDLE) {
-                    log_it(L_INFO, "Can't process SYNC_GLOBAL_DB request because not in idle state");
-                    dap_stream_ch_chain_pkt_write_error(a_ch, l_chain_pkt->hdr.net_id,
-                            l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id,
-                            "ERROR_STATE_NOT_IN_IDLE");
-                    dap_stream_ch_set_ready_to_write(a_ch, true);
-                    break;
-                }
-                // receive the latest global_db revision of the remote node -> go to send mode
+    case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_CHAINS: {
+        log_it(L_INFO, "In:  SYNCED_CHAINS pkt");
+    }
+        break;
+    case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_CHAINS: {
+        log_it(L_INFO, "In:  SYNC_CHAINS pkt");
+        dap_chain_t * l_chain = dap_chain_find_by_id(l_chain_pkt->hdr.net_id, l_chain_pkt->hdr.chain_id);
+        if(l_chain) {
+            if(l_ch_chain->state != CHAIN_STATE_IDLE) {
+                log_it(L_INFO, "Can't process SYNC_CHAINS request because not in idle state");
+                dap_stream_ch_chain_pkt_write_error(a_ch, l_chain_pkt->hdr.net_id,
+                        l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id,
+                        "ERROR_STATE_NOT_IN_IDLE");
+                dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
+            } else {
+                // fill ids
                 if(l_chain_pkt_data_size == sizeof(dap_stream_ch_chain_sync_request_t)) {
                     dap_stream_ch_chain_sync_request_t * l_request =
                             (dap_stream_ch_chain_sync_request_t *) l_chain_pkt->data;
@@ -271,264 +458,138 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                     memcpy(&l_ch_chain->request_cell_id, &l_chain_pkt->hdr.cell_id, sizeof(dap_chain_cell_id_t));
                     memcpy(&l_ch_chain->request_net_id, &l_chain_pkt->hdr.net_id, sizeof(dap_chain_net_id_t));
                     memcpy(&l_ch_chain->request_chain_id, &l_chain_pkt->hdr.chain_id, sizeof(dap_chain_id_t));
-
-                    // Get log diff
-                    l_ch_chain->request_last_ts = dap_db_log_get_last_id();
-                    //log_it(L_DEBUG, "Requested transactions %llu:%llu", l_request->id_start,
-                    //        (uint64_t ) l_ch_chain->request_last_ts);
-                    //dap_list_t *l_list = dap_db_log_get_list(l_request->id_start + 1);
-                    uint64_t l_start_item = l_request->id_start;
-                    // If the current global_db has been truncated, but the remote node has not known this
-                    if(l_request->id_start > l_ch_chain->request_last_ts) {
-                        l_start_item = 0;
-                    }
-                    dap_chain_net_t *l_net = dap_chain_net_by_id(l_chain_pkt->hdr.net_id);
-                    dap_list_t *l_add_groups = dap_chain_net_get_add_gdb_group(l_net, l_request->node_addr);
-                    dap_db_log_list_t *l_db_log = dap_db_log_list_start(l_start_item + 1, l_add_groups);
-                    if(l_db_log) {
-                        //log_it(L_DEBUG, "Start getting items %u:%u", l_request->id_start + 1,l_db_log->items_number);//dap_list_length(l_list));
-                        // Add it to outgoing list
-                        l_ch_chain->request_global_db_trs = l_db_log;//l_list;
-                        //dap_list_t *l_last = dap_list_last(l_list);
-                        //if(l_last)
-                        //    l_last->next = l_ch_chain->request_global_db_trs;
-                        //l_ch_chain->request_global_db_trs = l_list;
-                        l_ch_chain->state = CHAIN_STATE_SYNC_GLOBAL_DB;
-
-                        dap_chain_node_addr_t l_node_addr = { 0 };
-                        dap_chain_net_t *l_net = dap_chain_net_by_id(l_ch_chain->request_net_id);
-                        l_node_addr.uint64 = l_net ? dap_db_get_cur_node_addr(l_net->pub.name) : 0;
-                        dap_stream_ch_chain_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_FIRST_GLOBAL_DB,
-                                l_ch_chain->request_net_id, l_ch_chain->request_chain_id,
-                                l_ch_chain->request_cell_id, &l_node_addr, sizeof(dap_chain_node_addr_t));
-
-                    } else {
-                        dap_chain_node_addr_t l_node_addr = { 0 };
-                        dap_chain_net_t *l_net = dap_chain_net_by_id(l_ch_chain->request_net_id);
-                        l_node_addr.uint64 = l_net ? dap_db_get_cur_node_addr(l_net->pub.name) : 0;
-                        dap_stream_ch_chain_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_FIRST_GLOBAL_DB,
-                                l_ch_chain->request_net_id, l_ch_chain->request_chain_id,
-                                l_ch_chain->request_cell_id, &l_node_addr, sizeof(dap_chain_node_addr_t));
-
-                        dap_stream_ch_chain_sync_request_t l_request = {};
-                        //log_it(L_DEBUG, "No items to sync from %u", l_request->id_start + 1);
-                        l_request.node_addr.uint64 = l_net ? dap_db_get_cur_node_addr(l_net->pub.name) : 0;
-                        l_request.id_start = dap_db_log_get_last_id_remote(l_ch_chain->request.node_addr.uint64);
-                        dap_stream_ch_chain_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB,
-                                l_ch_chain->request_net_id, l_ch_chain->request_chain_id,
-                                l_ch_chain->request_cell_id, &l_request, sizeof(l_request));
-//                            dap_stream_ch_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB ,&l_request,
-//                                                    sizeof (l_request));
-                        l_ch_chain->state = CHAIN_STATE_IDLE;
-                        if(l_ch_chain->callback_notify_packet_out)
-                            l_ch_chain->callback_notify_packet_out(l_ch_chain,
-                            DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB,
-                            NULL, 0, l_ch_chain->callback_notify_arg);
-                    }
-                    //log_it(L_INFO, "Prepared %u items for sync", l_db_log->items_number - l_request->id_start);//dap_list_length(l_ch_chain->request_global_db_trs));
-                    // go to send data from list [in s_stream_ch_packet_out()]
-                    // no data to send -> send one empty message DAP_STREAM_CH_CHAIN_PKT_TYPE_GLOBAL_DB_SYNCED
-                    dap_stream_ch_set_ready_to_write(a_ch, true);
-                }
-                else {
-                    log_it(L_ERROR, "Get DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB session_id=%u bad request",
-                            a_ch->stream->session->id);
-                    dap_stream_ch_chain_pkt_write_error(a_ch, l_chain_pkt->hdr.net_id,
-                            l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id,
-                            "ERROR_SYNC_GLOBAL_DB_REQUEST_BAD");
-                    dap_stream_ch_set_ready_to_write(a_ch, true);
-                }
-            }
-                break;
-                // first packet of data with source node address
-            case DAP_STREAM_CH_CHAIN_PKT_TYPE_FIRST_CHAIN: {
-                log_it(L_INFO, "In: FIRST_CHAIN data_size=%d", l_chain_pkt_data_size);
-                if(l_chain_pkt_data_size == sizeof(dap_chain_node_addr_t))
-                    memcpy(&l_ch_chain->request.node_addr, l_chain_pkt->data, l_chain_pkt_data_size);
-            }
-                break;
-            case DAP_STREAM_CH_CHAIN_PKT_TYPE_CHAIN: {
-                //log_it(L_INFO, "In: CHAIN pkt");
-                dap_chain_t * l_chain = dap_chain_find_by_id(l_chain_pkt->hdr.net_id, l_chain_pkt->hdr.chain_id);
-                if(l_chain) {
-                    // Expect atom element in
-                    if(l_chain_pkt_data_size > 0) {
-                        dap_chain_hash_fast_t l_atom_hash = {};
-                        dap_hash_fast(l_chain_pkt->data, l_chain_pkt_data_size, &l_atom_hash);
-                        dap_chain_atom_iter_t *l_atom_iter = l_chain->callback_atom_iter_create(l_chain);
-                        if (!l_chain->callback_atom_find_by_hash(l_atom_iter, &l_atom_hash)) {
-                            dap_chain_atom_ptr_t l_atom_copy = DAP_CALLOC(1, l_chain_pkt_data_size);
-                            memcpy(l_atom_copy, l_chain_pkt->data, l_chain_pkt_data_size);
-                            dap_chain_atom_verify_res_t l_atom_add_res = l_chain->callback_atom_add(l_chain, l_atom_copy);
-                            if(l_atom_add_res == ATOM_ACCEPT && dap_chain_has_file_store(l_chain)) {
-                                // append to file
-                                dap_chain_cell_id_t l_cell_id;
-                                l_cell_id.uint64 = l_chain_pkt->hdr.cell_id.uint64;
-                                dap_chain_cell_t *l_cell = dap_chain_cell_create_fill(l_chain, l_cell_id);
-                                // add one atom only
-                                int l_res = dap_chain_cell_file_append(l_cell, l_chain_pkt->data, l_chain_pkt_data_size);
-                                // rewrite all file
-                                //l_res = dap_chain_cell_file_update(l_cell);
-                                if(!l_cell || l_res < 0) {
-                                    log_it(L_ERROR, "Can't save event 0x%x to the file '%s'", l_chain_pkt->data,
-                                            l_cell ? l_cell->file_storage_path : "[null]");
-                                }
-                                // delete cell and close file
-                                dap_chain_cell_delete(l_cell);
-                            }
-                            if(l_atom_add_res == ATOM_PASS)
-                                DAP_DELETE(l_atom_copy);
-                        }
-                        l_chain->callback_atom_iter_delete(l_atom_iter);
-                    } else {
-                        log_it(L_WARNING, "Empty chain packet");
-                        dap_stream_ch_chain_pkt_write_error(a_ch, l_chain_pkt->hdr.net_id,
-                                l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id,
-                                "ERROR_CHAIN_PACKET_EMPTY");
-                        dap_stream_ch_set_ready_to_write(a_ch, true);
-                    }
-                }
             }
-                break;
-                // first packet of data with source node address
-            case DAP_STREAM_CH_CHAIN_PKT_TYPE_FIRST_GLOBAL_DB: {
-                log_it(L_INFO, "In: FIRST_GLOBAL_DB data_size=%d", l_chain_pkt_data_size);
-                if(l_chain_pkt_data_size == sizeof(dap_chain_node_addr_t))
-                    memcpy(&l_ch_chain->request.node_addr, l_chain_pkt->data, l_chain_pkt_data_size);
-                //memcpy(&l_ch_chain->request_cell_id, &l_chain_pkt->hdr.cell_id, sizeof(dap_chain_cell_id_t));
-                //memcpy(&l_ch_chain->request_net_id, &l_chain_pkt->hdr.net_id, sizeof(dap_chain_net_id_t));
-                //memcpy(&l_ch_chain->request_chain_id, &l_chain_pkt->hdr.chain_id, sizeof(dap_chain_id_t));
+                dap_events_socket_remove_from_worker_unsafe(a_ch->stream->esocket, a_ch->stream_worker->worker);
+                dap_proc_queue_add_callback(a_ch->stream_worker->worker->proc_queue, s_sync_chains_callback, a_ch);
             }
-                break;
-            case DAP_STREAM_CH_CHAIN_PKT_TYPE_GLOBAL_DB: {
-                //log_it(L_INFO, "In: GLOBAL_DB data_size=%d", l_chain_pkt_data_size);
-                // get transaction and save it to global_db
-                if(l_chain_pkt_data_size > 0) {
-                    //session_data_t *l_data = session_data_find(a_ch->stream->session->id);
-                    size_t l_data_obj_count = 0;
-                    // deserialize data
-                    dap_store_obj_t *l_store_obj = dap_db_log_unpack((uint8_t*) l_chain_pkt->data,
-                            l_chain_pkt_data_size, &l_data_obj_count); // Parse data from dap_db_log_pack()
-//                    log_it(L_INFO, "In: l_data_obj_count = %d", l_data_obj_count );
-
-                    for(size_t i = 0; i < l_data_obj_count; i++) {
-                        // timestamp for exist obj
-                        time_t l_timestamp_cur = 0;
-                        // obj to add
-                        dap_store_obj_t* l_obj = l_store_obj + i;
-                        // read item from base;
-                        size_t l_count_read = 0;
-                        dap_store_obj_t *l_read_obj = dap_chain_global_db_driver_read(l_obj->group,
-                                l_obj->key, &l_count_read);
-                        // get timestamp for the exist entry
-                        if(l_read_obj)
-                            l_timestamp_cur = l_read_obj->timestamp;
-                        // get timestamp for the deleted entry
-                        else
-                        {
-                            l_timestamp_cur = global_db_gr_del_get_timestamp(l_obj->group, l_obj->key);
-                        }
-
-                        //check whether to apply the received data into the database
-                        bool l_apply = true;
-                        if(l_obj->timestamp < l_timestamp_cur)
-                            l_apply = false;
-                        else if(l_obj->type == 'd') {
-                            // already deleted
-                            if(!l_read_obj)
-                                l_apply = false;
-                        }
-                        else if(l_obj->type == 'a') {
-                            bool l_is_the_same_present = false;
-                            if(l_read_obj &&
-                                    l_read_obj->value_len == l_obj->value_len &&
-                                    !memcmp(l_read_obj->value, l_obj->value, l_obj->value_len))
-                                l_is_the_same_present = true;
-                            // this data already present in global_db and not obsolete (out of date)
-                            if(l_read_obj && (l_is_the_same_present || l_read_obj->timestamp >= l_store_obj->timestamp))
-                                l_apply = false;
-                        }
-                        if(l_read_obj)
-                            dap_store_obj_free(l_read_obj, l_count_read);
-
-                        if(!l_apply) {
-                            // If request was from defined node_addr we update its state
-                            if(l_ch_chain->request.node_addr.uint64) {
-                                dap_db_log_set_last_id_remote(l_ch_chain->request.node_addr.uint64, l_obj->id);
-                            }
-                            continue;
-                        }
-
-                        char l_ts_str[50];
-                        dap_time_to_str_rfc822(l_ts_str, sizeof(l_ts_str), l_store_obj[i].timestamp);
-                        /*log_it(L_DEBUG, "Unpacked log history: type='%c' (0x%02hhX) group=\"%s\" key=\"%s\""
-                                " timestamp=\"%s\" value_len=%u  ",
-                                (char ) l_store_obj[i].type, l_store_obj[i].type, l_store_obj[i].group,
-                                l_store_obj[i].key, l_ts_str, l_store_obj[i].value_len);*/
-                        // apply received transaction
-                        dap_chain_t *l_chain = dap_chain_find_by_id(l_chain_pkt->hdr.net_id, l_chain_pkt->hdr.chain_id);
-                        if(l_chain) {
-                            if(l_chain->callback_datums_pool_proc_with_group)
-                                l_chain->callback_datums_pool_proc_with_group(l_chain,
-                                        (dap_chain_datum_t**) &(l_store_obj->value), 1,
-                                        l_store_obj[i].group);
-                        }
-                        // save data to global_db
-                        if(!dap_chain_global_db_obj_save(l_obj, 1)) {
-                            dap_stream_ch_chain_pkt_write_error(a_ch, l_chain_pkt->hdr.net_id,
-                                    l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id,
-                                    "ERROR_GLOBAL_DB_INTERNAL_NOT_SAVED");
-                            dap_stream_ch_set_ready_to_write(a_ch, true);
-                        } else {
-                            // If request was from defined node_addr we update its state
-                            if(l_ch_chain->request.node_addr.uint64) {
-                                dap_db_log_set_last_id_remote(l_ch_chain->request.node_addr.uint64,
-                                        l_obj->id);
-                            }
-                            //log_it(L_DEBUG, "Added new GLOBAL_DB history pack");
-                        }
-                    }
-                    if(l_store_obj)
-                        dap_store_obj_free(l_store_obj, l_data_obj_count);
-
-                } else {
-                    log_it(L_WARNING, "Packet with GLOBAL_DB atom has zero body size");
-                }
-            }
-                break;
-            case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB_RVRS: {
-                dap_stream_ch_chain_sync_request_t l_sync_gdb = {};
-                memcpy(&l_sync_gdb, l_chain_pkt->data, l_chain_pkt_data_size);
-                dap_chain_net_t *l_net = dap_chain_net_by_id(l_chain_pkt->hdr.net_id);
-                l_sync_gdb.node_addr.uint64 = dap_chain_net_get_cur_addr(l_net) ?
-                                                  dap_chain_net_get_cur_addr(l_net)->uint64 :
-                                                  dap_db_get_cur_node_addr(l_net->pub.name);
-                // Get last timestamp in log
-                l_sync_gdb.id_start = (uint64_t) dap_db_log_get_last_id_remote(l_ch_chain->request.node_addr.uint64);
-                // no limit
-                l_sync_gdb.id_end = (uint64_t)0;
-                dap_stream_ch_chain_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB, l_chain_pkt->hdr.net_id,
-                                              l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id, &l_sync_gdb, sizeof(l_sync_gdb));
-            }
-            case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_CHAINS_RVRS: {
-                dap_stream_ch_chain_sync_request_t l_sync_chains = {};
-                dap_stream_ch_chain_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_CHAINS, l_chain_pkt->hdr.net_id,
-                                              l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id, &l_sync_chains, sizeof(l_sync_chains));
-            }
-            default: {
+        }
+    }
+        break;
+    case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB: {
+        log_it(L_INFO, "In:  SYNC_GLOBAL_DB pkt");
+        if(l_ch_chain->state != CHAIN_STATE_IDLE) {
+            log_it(L_INFO, "Can't process SYNC_GLOBAL_DB request because not in idle state");
+            dap_stream_ch_chain_pkt_write_error(a_ch, l_chain_pkt->hdr.net_id,
+                    l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id,
+                    "ERROR_STATE_NOT_IN_IDLE");
+            dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
+            break;
+        }
+        // receive the latest global_db revision of the remote node -> go to send mode
+        if(l_chain_pkt_data_size == sizeof(dap_stream_ch_chain_sync_request_t)) {
+            dap_stream_ch_chain_sync_request_t * l_request =
+                    (dap_stream_ch_chain_sync_request_t *) l_chain_pkt->data;
+            memcpy(&l_ch_chain->request, l_request, l_chain_pkt_data_size);
+            memcpy(&l_ch_chain->request_cell_id, &l_chain_pkt->hdr.cell_id, sizeof(dap_chain_cell_id_t));
+            memcpy(&l_ch_chain->request_net_id, &l_chain_pkt->hdr.net_id, sizeof(dap_chain_net_id_t));
+            memcpy(&l_ch_chain->request_chain_id, &l_chain_pkt->hdr.chain_id, sizeof(dap_chain_id_t));
+            dap_events_socket_remove_from_worker_unsafe(a_ch->stream->esocket, a_ch->stream_worker->worker);
+            dap_proc_queue_add_callback(a_ch->stream_worker->worker->proc_queue, s_sync_gdb_callback, a_ch);
+        }
+        else {
+            log_it(L_ERROR, "Get DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB session_id=%u bad request",
+                    a_ch->stream->session->id);
+            dap_stream_ch_chain_pkt_write_error(a_ch, l_chain_pkt->hdr.net_id,
+                    l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id,
+                    "ERROR_SYNC_GLOBAL_DB_REQUEST_BAD");
+            dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
+        }
+    }
+        break;
+        // first packet of data with source node address
+    case DAP_STREAM_CH_CHAIN_PKT_TYPE_FIRST_CHAIN: {
+        log_it(L_INFO, "In: FIRST_CHAIN data_size=%d", l_chain_pkt_data_size);
+        if(l_chain_pkt_data_size == sizeof(dap_chain_node_addr_t))
+            memcpy(&l_ch_chain->request.node_addr, l_chain_pkt->data, l_chain_pkt_data_size);
+    }
+        break;
+    case DAP_STREAM_CH_CHAIN_PKT_TYPE_CHAIN: {
+        log_it(L_INFO, "In: CHAIN pkt data_size=%d", l_chain_pkt_data_size);
+        dap_chain_t * l_chain = dap_chain_find_by_id(l_chain_pkt->hdr.net_id, l_chain_pkt->hdr.chain_id);
+        if(l_chain) {
+            // Expect atom element in
+            if(l_chain_pkt_data_size > 0) {
+                memcpy(&l_ch_chain->request_net_id, &l_chain_pkt->hdr.net_id, sizeof(dap_chain_net_id_t));
+                memcpy(&l_ch_chain->request_chain_id, &l_chain_pkt->hdr.chain_id, sizeof(dap_chain_id_t));
+                memcpy(&l_ch_chain->request_cell_id, &l_chain_pkt->hdr.cell_id, sizeof(dap_chain_cell_id_t));
+                l_ch_chain->pkt_data = DAP_CALLOC(1, l_chain_pkt_data_size);
+                memcpy(l_ch_chain->pkt_data, l_chain_pkt->data, l_chain_pkt_data_size);
+                l_ch_chain->pkt_data_size = l_chain_pkt_data_size;
+                dap_events_socket_remove_from_worker_unsafe(a_ch->stream->esocket, a_ch->stream_worker->worker);
+                dap_proc_queue_add_callback(a_ch->stream_worker->worker->proc_queue, s_chain_pkt_callback, a_ch);
+            } else {
+                log_it(L_WARNING, "Empty chain packet");
                 dap_stream_ch_chain_pkt_write_error(a_ch, l_chain_pkt->hdr.net_id,
-                                                    l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id,
-                                                    "ERROR_UNKNOWN_CHAIN_PKT_TYPE");
-                }
+                        l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id,
+                        "ERROR_CHAIN_PACKET_EMPTY");
+                dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
             }
-            if(l_ch_chain->callback_notify_packet_in)
-                l_ch_chain->callback_notify_packet_in(l_ch_chain, l_ch_pkt->hdr.type, l_chain_pkt,
-                        l_chain_pkt_data_size, //l_ch_pkt->hdr.size,
-                        l_ch_chain->callback_notify_arg);
         }
     }
+        break;
+        // first packet of data with source node address
+    case DAP_STREAM_CH_CHAIN_PKT_TYPE_FIRST_GLOBAL_DB: {
+        log_it(L_INFO, "In: FIRST_GLOBAL_DB data_size=%d", l_chain_pkt_data_size);
+        if(l_chain_pkt_data_size == sizeof(dap_chain_node_addr_t))
+            memcpy(&l_ch_chain->request.node_addr, l_chain_pkt->data, l_chain_pkt_data_size);
+    }
+        break;
+    case DAP_STREAM_CH_CHAIN_PKT_TYPE_GLOBAL_DB: {
+        log_it(L_INFO, "In: GLOBAL_DB data_size=%d", l_chain_pkt_data_size);
+        // get transaction and save it to global_db
+        if(l_chain_pkt_data_size > 0) {
+            memcpy(&l_ch_chain->request_net_id, &l_chain_pkt->hdr.net_id, sizeof(dap_chain_net_id_t));
+            memcpy(&l_ch_chain->request_chain_id, &l_chain_pkt->hdr.chain_id, sizeof(dap_chain_id_t));
+            memcpy(&l_ch_chain->request_cell_id, &l_chain_pkt->hdr.cell_id, sizeof(dap_chain_cell_id_t));
+            l_ch_chain->pkt_data = DAP_CALLOC(1, l_chain_pkt_data_size);
+            memcpy(l_ch_chain->pkt_data, l_chain_pkt->data, l_chain_pkt_data_size);
+            l_ch_chain->pkt_data_size = l_chain_pkt_data_size;
+            dap_events_socket_remove_from_worker_unsafe(a_ch->stream->esocket, a_ch->stream_worker->worker);
+            dap_proc_queue_add_callback(a_ch->stream_worker->worker->proc_queue, s_gdb_pkt_callback, a_ch);
+        } else {
+            log_it(L_WARNING, "Packet with GLOBAL_DB atom has zero body size");
+            dap_stream_ch_chain_pkt_write_error(a_ch, l_chain_pkt->hdr.net_id,
+                    l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id,
+                    "ERROR_GLOBAL_DB_PACKET_EMPTY");
+            dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
+        }
+    }
+        break;
+    case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB_RVRS: {
+        dap_stream_ch_chain_sync_request_t l_sync_gdb = {};
+        memcpy(&l_sync_gdb, l_chain_pkt->data, l_chain_pkt_data_size);
+        dap_chain_net_t *l_net = dap_chain_net_by_id(l_chain_pkt->hdr.net_id);
+        l_sync_gdb.node_addr.uint64 = dap_chain_net_get_cur_addr(l_net) ?
+                                          dap_chain_net_get_cur_addr(l_net)->uint64 :
+                                          dap_db_get_cur_node_addr(l_net->pub.name);
+        // Get last timestamp in log
+        l_sync_gdb.id_start = (uint64_t) dap_db_log_get_last_id_remote(l_ch_chain->request.node_addr.uint64);
+        // no limit
+        l_sync_gdb.id_end = (uint64_t)0;
+        dap_stream_ch_chain_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB, l_chain_pkt->hdr.net_id,
+                                      l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id, &l_sync_gdb, sizeof(l_sync_gdb));
+    }
+        break;
+    case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_CHAINS_RVRS: {
+        dap_stream_ch_chain_sync_request_t l_sync_chains = {};
+        dap_stream_ch_chain_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_CHAINS, l_chain_pkt->hdr.net_id,
+                                      l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id, &l_sync_chains, sizeof(l_sync_chains));
+    }
+        break;
+    case DAP_STREAM_CH_CHAIN_PKT_TYPE_ERROR:
+        break;
+    default: {
+        dap_stream_ch_chain_pkt_write_error(a_ch, l_chain_pkt->hdr.net_id,
+                                            l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id,
+                                            "ERROR_UNKNOWN_CHAIN_PKT_TYPE");
+        }
+    }
+    if(l_ch_chain->callback_notify_packet_in)
+        l_ch_chain->callback_notify_packet_in(l_ch_chain, l_ch_pkt->hdr.type, l_chain_pkt,
+                                              l_chain_pkt_data_size, l_ch_chain->callback_notify_arg);
 }
 
+
 /**
  * @brief dap_stream_ch_chain_go_idle
  * @param a_ch_chain
@@ -553,160 +614,106 @@ void dap_stream_ch_chain_go_idle ( dap_stream_ch_chain_t * a_ch_chain)
     HASH_ITER( hh, a_ch_chain->request_atoms_processed, l_atom_item, l_atom_item_tmp )
         HASH_DEL(a_ch_chain->request_atoms_processed, l_atom_item);
     pthread_mutex_unlock(&a_ch_chain->mutex);
-    dap_stream_ch_set_ready_to_write(a_ch_chain->ch, false);
-
 }
 
-/**
- * @brief s_stream_ch_packet_out
- * @param ch
- * @param arg
- */
-void s_stream_ch_packet_out(dap_stream_ch_t* a_ch, void* a_arg)
+bool s_process_gdb_iter(dap_stream_ch_t *a_ch)
 {
-    (void) a_arg;
-
     dap_stream_ch_chain_t *l_ch_chain = DAP_STREAM_CH_CHAIN(a_ch);
+    dap_db_log_list_t *l_db_list = l_ch_chain->request_global_db_trs;
+    dap_store_obj_pkt_t *l_pkt = (dap_store_obj_pkt_t *)l_ch_chain->db_iter->data;
+    uint32_t l_pkt_size = sizeof(dap_store_obj_pkt_t) + l_pkt->data_size;
+    log_it(L_INFO, "Send one global_db record packet len=%d (rest=%d/%d items)", l_pkt_size,
+           dap_db_log_list_get_count_rest(l_db_list), dap_db_log_list_get_count(l_db_list));
+    dap_stream_ch_chain_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_GLOBAL_DB,
+                                         l_ch_chain->request_net_id, l_ch_chain->request_chain_id,
+                                         l_ch_chain->request_cell_id, l_pkt, l_pkt_size);
+    dap_list_t *l_iter = dap_list_next(l_ch_chain->db_iter);
+    if (l_iter) {
+        l_ch_chain->db_iter = l_iter;
+    } else {
+        l_ch_chain->stats_request_gdb_processed++;
+        l_ch_chain->db_iter = dap_list_first(l_ch_chain->db_iter);
+        dap_list_free_full(l_ch_chain->db_iter, free);
+        l_ch_chain->db_iter = NULL;
+    }
+    return true;
+}
+
+bool s_out_pkt_callback(dap_proc_thread_t *a_thread, void *a_arg)
+{
+    UNUSED(a_thread);
+    dap_stream_ch_t *l_ch = (dap_stream_ch_t *)a_arg;
+    dap_stream_ch_chain_t *l_ch_chain = DAP_STREAM_CH_CHAIN(l_ch);
 
     //log_it( L_DEBUG,"s_stream_ch_packet_out state=%d", l_ch_chain ? l_ch_chain->state : -1);
     //  log_it( L_DEBUG,"l_ch_chain %X", l_ch_chain );
-
+    bool l_packet_out = false;
     switch (l_ch_chain->state) {
+
         case CHAIN_STATE_IDLE: {
             dap_stream_ch_chain_go_idle(l_ch_chain);
         } break;
 
-        case CHAIN_STATE_SYNC_ALL:
-
         case CHAIN_STATE_SYNC_GLOBAL_DB: {
-
-            // Get log diff
-            //size_t l_data_size_out = 0;
-
-            dap_db_log_list_t *l_db_list = l_ch_chain->request_global_db_trs; //dap_list_last( l_ch_chain->request_global_db_trs );
-            dap_global_db_obj_t *l_obj = dap_db_log_list_get(l_db_list);
-
-            if (1) {
-                //dap_list_t *l_list = l_ch_chain->request_global_db_trs; //dap_list_last( l_ch_chain->request_global_db_trs );
-                bool l_is_stop = true; //l_list ? false : true;
-                while(l_obj) {
-
-                    size_t l_items_total = dap_db_log_list_get_count(l_db_list);
-                    size_t l_items_rest = dap_db_log_list_get_count_rest(l_db_list);
-
+            if (l_ch_chain->db_iter) {
+                l_packet_out = s_process_gdb_iter(l_ch);
+            } else {
+                dap_global_db_obj_t *l_obj;
+                do { // Get log diff
                     size_t l_item_size_out = 0;
-                    uint8_t *l_item = dap_db_log_pack(l_obj, &l_item_size_out);
-                    // Item not found, maybe it has deleted? Then go to the next item
-                    if(!l_item || !l_item_size_out) {
-                        //log_it(L_WARNING, "Log pack returned NULL??? data=0x%x (nothing to send) (rest=%d records)", l_obj,
-                         //       l_items_rest);
-                        l_item_size_out = 0;
-                        //dap_stream_ch_set_ready_to_write(a_ch, false);
-
-                        // go to next item
-                        l_obj = dap_db_log_list_get(l_db_list);
-                        //if(l_obj)
-                        //    continue;
-                        // stop global_db sync
-                        //else
-                        //    break;
-                    }
-                    else {
-                        //log_it(L_INFO, "Send one global_db record data=0x%x len=%d (rest=%d/%d items)", l_item, l_item_size_out,
-                        //        l_items_rest, l_items_total);
-                        dap_stream_ch_chain_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_GLOBAL_DB,
-                                l_ch_chain->request_net_id, l_ch_chain->request_chain_id,
-                                l_ch_chain->request_cell_id, l_item, l_item_size_out);
-                        l_ch_chain->stats_request_gdb_processed++;
-                        //dap_stream_ch_set_ready_to_write(a_ch, true);
-                        //sleep(1);
-
-                        DAP_DELETE(l_item);
-                        // sent the record, another will be sent
-                        l_is_stop = false;
+                    l_obj = dap_db_log_list_get(l_ch_chain->request_global_db_trs);
+                    l_ch_chain->db_iter = dap_db_log_pack(l_obj, &l_item_size_out);
+                    if (l_ch_chain->db_iter && l_item_size_out) {
                         break;
                     }
-                    // remove current item from list and go to next item
-                    /*dap_chain_global_db_obj_delete((dap_global_db_obj_t *) l_list->data);
-                    l_ch_chain->request_global_db_trs = dap_list_delete_link(l_ch_chain->request_global_db_trs, l_list);
-                    // nothing was sent
-                    if(!l_item_size_out) {
-                        l_list = l_ch_chain->request_global_db_trs;
-                        // go to next item
-                        if(l_list)
-                            continue;
-                        // stop global_db sync
-                        else
-                            break;
-                    }*/
-                }
-
-                if(l_is_stop){
+                    // Item not found, maybe it has deleted? Then go to the next item
+                } while (l_obj);
+                if (l_ch_chain->db_iter) {
+                    l_packet_out = s_process_gdb_iter(l_ch);
+                } else {
                     //log_it(L_DEBUG, "l_obj == 0, STOP");
-                    // If we don't need to send chains after
-//                    if(l_ch_chain->state != CHAIN_STATE_SYNC_ALL){
-//                        dap_stream_ch_chain_go_idle(l_ch_chain);
-//                    }else if(l_ch_chain->state == CHAIN_STATE_SYNC_GLOBAL_DB)
-                    {
-                        // free log list
-                        l_ch_chain->request_global_db_trs = NULL;
-                        dap_db_log_list_delete(l_db_list);
-
-                        // last message
-
-                        dap_stream_ch_chain_sync_request_t l_request = {};
-                        dap_chain_net_t *l_net = dap_chain_net_by_id(l_ch_chain->request_net_id);
-                        l_request.node_addr.uint64 = l_net ? dap_db_get_cur_node_addr(l_net->pub.name) : 0;
-                        l_request.id_start = dap_db_log_get_last_id_remote(l_ch_chain->request.node_addr.uint64);
-                        l_request.id_end = 0;
-
-                        log_it( L_DEBUG,"Syncronized database:  last id %llu, items syncronyzed %llu ", l_request.id_start,
-                                l_ch_chain->stats_request_gdb_processed );
-
-                        dap_stream_ch_chain_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB,
-                                l_ch_chain->request_net_id, l_ch_chain->request_chain_id,
-                                l_ch_chain->request_cell_id, &l_request, sizeof(l_request));
-
-                        if(l_ch_chain->callback_notify_packet_out)
-                            l_ch_chain->callback_notify_packet_out(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB,
-                            NULL, 0, l_ch_chain->callback_notify_arg);
-
-                        if(l_ch_chain->state != CHAIN_STATE_SYNC_ALL)
-                            dap_stream_ch_chain_go_idle(l_ch_chain);
-                    }
+                    // free log list
+                    dap_db_log_list_delete(l_ch_chain->request_global_db_trs);
+                    l_ch_chain->request_global_db_trs = NULL;
+                    // last message
+                    dap_stream_ch_chain_sync_request_t l_request = {};
+                    dap_chain_net_t *l_net = dap_chain_net_by_id(l_ch_chain->request_net_id);
+                    l_request.node_addr.uint64 = l_net ? dap_db_get_cur_node_addr(l_net->pub.name) : 0;
+                    l_request.id_start = dap_db_log_get_last_id_remote(l_ch_chain->request.node_addr.uint64);
+                    l_request.id_end = 0;
+
+                    log_it( L_DEBUG,"Syncronized database:  last id %llu, items syncronyzed %llu ", l_request.id_start,
+                            l_ch_chain->stats_request_gdb_processed );
+
+                    dap_stream_ch_chain_pkt_write_unsafe(l_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB,
+                            l_ch_chain->request_net_id, l_ch_chain->request_chain_id,
+                            l_ch_chain->request_cell_id, &l_request, sizeof(l_request));
+                    l_packet_out = true;
+
+                    if(l_ch_chain->callback_notify_packet_out)
+                        l_ch_chain->callback_notify_packet_out(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB,
+                        NULL, 0, l_ch_chain->callback_notify_arg);
+                    dap_stream_ch_chain_go_idle(l_ch_chain);
                 }
             }
+        } break;
 
-        }
-        if(l_ch_chain->state != CHAIN_STATE_SYNC_ALL)
-            break;
-
-            // Synchronize chains
+        // Synchronize chains
         case CHAIN_STATE_SYNC_CHAINS: {
             //log_it(L_DEBUG, "CHAIN_STATE_SYNC_CHAINS");
             dap_chain_t * l_chain = dap_chain_find_by_id(l_ch_chain->request_net_id, l_ch_chain->request_chain_id);
-            /*
-            // alternative way to get l_chain
-            if(!l_ch_chain->request_atom_iter) {
-                log_it(L_ERROR, "CHAIN_STATE_SYNC_CHAINS not ready to send chains");
-                l_ch_chain->state = CHAIN_STATE_IDLE;
-                break;
-            }
-            //dap_chain_atom_iter_t* l_iter = l_chain->callback_atom_iter_create(l_chain);
-            dap_chain_t * l_chain = l_ch_chain->request_atom_iter->chain;
-            */
-
             dap_chain_atom_item_t * l_atom_item = NULL, *l_atom_item_tmp = NULL;//, *l_chains_lasts_new = NULL;
             if(l_ch_chain->request_atoms_lasts == NULL) { // All chains synced
-                dap_stream_ch_chain_sync_request_t l_request = { { 0 } };
+                dap_stream_ch_chain_sync_request_t l_request;
+                memset(&l_request,0,sizeof (l_request));
                 uint8_t l_send_pkt_type = l_ch_chain->state == CHAIN_STATE_SYNC_CHAINS ?
                         DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_CHAINS :
                         DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_ALL;
                 // last message
-                dap_stream_ch_chain_pkt_write(a_ch,
-                        l_send_pkt_type,
-                        l_ch_chain->request_net_id, l_ch_chain->request_chain_id,
-                        l_ch_chain->request_cell_id, &l_request, sizeof(l_request));
+                dap_stream_ch_chain_pkt_write_unsafe(l_ch, l_send_pkt_type,
+                                                     l_ch_chain->request_net_id, l_ch_chain->request_chain_id,
+                                                     l_ch_chain->request_cell_id, &l_request, sizeof(l_request));
+                l_packet_out = true;
                 log_it( L_DEBUG,"Synced: %llu atoms processed",
                                         l_ch_chain->stats_request_atoms_processed);
                 dap_stream_ch_chain_go_idle(l_ch_chain);
@@ -729,53 +736,70 @@ void s_stream_ch_packet_out(dap_stream_ch_t* a_ch, void* a_arg)
                                 l_atom_item_proc);
 
                         // Then flush it out to the remote
-                        size_t l_atom_size = l_chain->callback_atom_get_size(l_atom_item->atom);
-                        dap_stream_ch_chain_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_CHAIN, l_ch_chain->request_net_id,
-                                l_ch_chain->request_chain_id, l_ch_chain->request_cell_id,
-                                l_atom_item->atom, l_atom_size);
+                        size_t l_atom_size = l_atom_item->atom_size;
+                        log_it(L_INFO, "Send one chain packet len=%d", l_atom_size);
+                        dap_stream_ch_chain_pkt_write_unsafe(l_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_CHAIN, l_ch_chain->request_net_id,
+                                                             l_ch_chain->request_chain_id, l_ch_chain->request_cell_id,
+                                                             l_atom_item->atom, l_atom_size);
+                        l_packet_out = true;
                         l_ch_chain->stats_request_atoms_processed++;
                         // Then parse links and populate new lasts
-                        size_t l_lasts_size = 0;
+                        size_t l_links_count = 0;
                         dap_chain_atom_ptr_t * l_links = NULL;
-
-                        dap_chain_atom_iter_t* l_iter = l_chain->callback_atom_iter_create_from(l_chain, l_atom_item->atom);
-                        l_links = l_chain->callback_atom_iter_get_links(l_iter, &l_lasts_size);
-                        //DAP_DELETE(l_atom_item->atom);
+                        size_t *l_links_sizes = NULL;
+                        dap_chain_atom_iter_t* l_iter = l_chain->callback_atom_iter_create_from(l_chain, l_atom_item->atom, l_atom_item->atom_size);
+                        l_links = l_chain->callback_atom_iter_get_links(l_iter, &l_links_count, &l_links_sizes);
                         DAP_DELETE(l_iter);
-                        //l_links = l_chain->callback_atom_iter_get_links(l_atom_item->atom, &l_lasts_size);
-
-                        for(size_t i = 0; i < l_lasts_size; i++) { // Find links
-                            dap_chain_atom_item_t * l_link_item = NULL;
-                            dap_chain_hash_fast_t l_link_hash;
-                            dap_hash_fast(l_links[i], l_chain->callback_atom_get_size(l_links[i]),
-                                    &l_link_hash);
-                            // Check link in processed atims
-                            HASH_FIND(hh, l_ch_chain->request_atoms_processed, &l_link_hash, sizeof(l_link_hash), l_link_item);
-                            if(l_link_item == NULL) { // Not found, add new lasts
-                                l_link_item = DAP_NEW_Z(dap_chain_atom_item_t);
-                                l_link_item->atom = l_links[i];// do not use memory cause it will be deleted
-                                memcpy(&l_link_item->atom_hash, &l_link_hash, sizeof(l_link_hash));
-                                //HASH_ADD(hh, l_chains_lasts_new, atom_hash, sizeof(l_link_hash), l_link_item);
-                                HASH_ADD(hh, l_ch_chain->request_atoms_lasts, atom_hash, sizeof(l_link_hash), l_link_item);
+                        if (l_links && l_links_sizes) {
+                            for(size_t i = 0; i < l_links_count; i++) { // Find links
+                                dap_chain_atom_item_t * l_link_item = NULL;
+                                dap_chain_hash_fast_t l_link_hash;
+                                dap_hash_fast(l_links[i], l_links_sizes[i], &l_link_hash);
+                                // Check link in processed atims
+                                HASH_FIND(hh, l_ch_chain->request_atoms_processed, &l_link_hash, sizeof(l_link_hash), l_link_item);
+                                if(l_link_item == NULL) { // Not found, add new lasts
+                                    l_link_item = DAP_NEW_Z(dap_chain_atom_item_t);
+                                    l_link_item->atom = l_links[i];// do not use memory cause it will be deleted
+                                    l_link_item->atom_size = l_links_sizes[i];
+                                    memcpy(&l_link_item->atom_hash, &l_link_hash, sizeof(l_link_hash));
+                                    HASH_ADD(hh, l_ch_chain->request_atoms_lasts, atom_hash, sizeof(l_link_hash), l_link_item);
+                                }
                             }
-                            //else
-                            //    DAP_DELETE(l_links[i]);
+                            DAP_DELETE(l_links);
                         }
-                        DAP_DELETE(l_links);
                         HASH_DEL(l_ch_chain->request_atoms_lasts, l_atom_item);
                         break;
-                    }
-                    else{
+                    } else {
                         HASH_DEL(l_ch_chain->request_atoms_lasts, l_atom_item);
                     }
                 }
                 pthread_mutex_unlock(&l_ch_chain->mutex);
             }
-            //assert(l_ch_chain->request_atoms_lasts == NULL);
-            //l_ch_chain->request_atoms_lasts = l_chains_lasts_new;
-        }
-        break;
-
+        } break;
+        default: break;
+    }
+    if (l_packet_out) {
+        dap_stream_ch_set_ready_to_write_unsafe(l_ch, true);
     }
+    dap_events_socket_assign_on_worker_mt(l_ch->stream->esocket, l_ch->stream_worker->worker);
+    return true;
+}
 
+/**
+ * @brief s_stream_ch_packet_out
+ * @param ch
+ * @param arg
+ */
+void s_stream_ch_packet_out(dap_stream_ch_t* a_ch, void* a_arg)
+{
+    (void) a_arg;
+    if (a_ch->stream->esocket->buf_out_size > DAP_EVENTS_SOCKET_BUF / 2) {
+        return;
+    }
+    dap_stream_ch_set_ready_to_write_unsafe(a_ch, false);
+    dap_stream_ch_chain_t *l_ch_chain = DAP_STREAM_CH_CHAIN(a_ch);
+    if (l_ch_chain && l_ch_chain->state != CHAIN_STATE_IDLE) {
+        dap_events_socket_remove_from_worker_unsafe(a_ch->stream->esocket, a_ch->stream_worker->worker);
+        dap_proc_queue_add_callback(a_ch->stream_worker->worker->proc_queue, s_out_pkt_callback, a_ch);
+    }
 }
diff --git a/modules/channel/chain/dap_stream_ch_chain_pkt.c b/modules/channel/chain/dap_stream_ch_chain_pkt.c
index bbb00965cc5b7b69af2f318d515b47b117d37fc5..19cc566016f4a6da7dced3ae83de9970c270cd00 100644
--- a/modules/channel/chain/dap_stream_ch_chain_pkt.c
+++ b/modules/channel/chain/dap_stream_ch_chain_pkt.c
@@ -48,9 +48,9 @@ dap_stream_ch_chain_state_t dap_stream_ch_chain_pkt_type_to_dap_stream_ch_chain_
  * @param data_size
  * @return
  */
-size_t dap_stream_ch_chain_pkt_write(dap_stream_ch_t *a_ch, uint8_t a_type,dap_chain_net_id_t a_net_id,
-                                     dap_chain_id_t a_chain_id, dap_chain_cell_id_t a_cell_id,
-        const void * a_data, size_t a_data_size)
+size_t dap_stream_ch_chain_pkt_write_unsafe(dap_stream_ch_t *a_ch, uint8_t a_type,dap_chain_net_id_t a_net_id,
+                                            dap_chain_id_t a_chain_id, dap_chain_cell_id_t a_cell_id,
+                                            const void * a_data, size_t a_data_size)
 {
     dap_stream_ch_chain_pkt_t * l_chain_pkt;
     size_t l_chain_pkt_size = sizeof (l_chain_pkt->hdr) + a_data_size;
@@ -63,7 +63,27 @@ size_t dap_stream_ch_chain_pkt_write(dap_stream_ch_t *a_ch, uint8_t a_type,dap_c
     if (a_data_size && a_data)
         memcpy( l_chain_pkt->data, a_data, a_data_size);
 
-    size_t l_ret  = dap_stream_ch_pkt_write(a_ch, a_type , l_chain_pkt, l_chain_pkt_size);
+    size_t l_ret  = dap_stream_ch_pkt_write_unsafe(a_ch, a_type , l_chain_pkt, l_chain_pkt_size);
+    DAP_DELETE(l_chain_pkt);
+    return l_ret;
+}
+
+size_t dap_stream_ch_chain_pkt_write_mt(dap_stream_worker_t *a_worker, dap_stream_ch_t *a_ch, uint8_t a_type,dap_chain_net_id_t a_net_id,
+                                        dap_chain_id_t a_chain_id, dap_chain_cell_id_t a_cell_id,
+                                        const void * a_data, size_t a_data_size)
+{
+    dap_stream_ch_chain_pkt_t * l_chain_pkt;
+    size_t l_chain_pkt_size = sizeof (l_chain_pkt->hdr) + a_data_size;
+    l_chain_pkt = DAP_NEW_Z_SIZE(dap_stream_ch_chain_pkt_t, l_chain_pkt_size );
+    l_chain_pkt->hdr.version = 1;
+    l_chain_pkt->hdr.net_id.uint64 = a_net_id.uint64;
+    l_chain_pkt->hdr.cell_id.uint64 = a_cell_id.uint64;
+    l_chain_pkt->hdr.chain_id.uint64 = a_chain_id.uint64;
+
+    if (a_data_size && a_data)
+        memcpy( l_chain_pkt->data, a_data, a_data_size);
+
+    size_t l_ret  = dap_stream_ch_pkt_write_mt(a_worker, a_ch, a_type , l_chain_pkt, l_chain_pkt_size);
     DAP_DELETE(l_chain_pkt);
     return l_ret;
 }
diff --git a/modules/channel/chain/include/dap_stream_ch_chain.h b/modules/channel/chain/include/dap_stream_ch_chain.h
index 0e5e6793752fb76e882827b48c986ca4c75ed039..9e576b7656c964ae5dbe01f999b38f7dcb6fedb5 100644
--- a/modules/channel/chain/include/dap_stream_ch_chain.h
+++ b/modules/channel/chain/include/dap_stream_ch_chain.h
@@ -41,6 +41,7 @@ typedef void (*dap_stream_ch_chain_callback_packet_t)(dap_stream_ch_chain_t*, ui
 typedef struct dap_chain_atom_item{
     dap_chain_hash_fast_t atom_hash;
     dap_chain_atom_ptr_t atom;
+    size_t atom_size;
     UT_hash_handle hh;
 } dap_chain_atom_item_t;
 
@@ -48,12 +49,15 @@ typedef struct dap_stream_ch_chain {
     pthread_mutex_t mutex;
     dap_stream_ch_t * ch;
 
-    dap_db_log_list_t *request_global_db_trs; // list of transactions
+    dap_db_log_list_t *request_global_db_trs; // list of global db records
+    dap_list_t *db_iter;
     dap_stream_ch_chain_state_t state;
 
     dap_chain_atom_iter_t * request_atom_iter;
     dap_chain_atom_item_t * request_atoms_lasts;
     dap_chain_atom_item_t * request_atoms_processed;
+    uint8_t *pkt_data;
+    uint64_t pkt_data_size;
     uint64_t stats_request_atoms_processed;
     uint64_t stats_request_gdb_processed;
     dap_stream_ch_chain_sync_request_t request;
diff --git a/modules/channel/chain/include/dap_stream_ch_chain_pkt.h b/modules/channel/chain/include/dap_stream_ch_chain_pkt.h
index 47903691f86ad4677b5cb46bf7eeb8c9fc68ed0f..a56e07c49053032fc1e2e054ca3a673e4aadf1ae 100644
--- a/modules/channel/chain/include/dap_stream_ch_chain_pkt.h
+++ b/modules/channel/chain/include/dap_stream_ch_chain_pkt.h
@@ -57,7 +57,7 @@ typedef enum dap_stream_ch_chain_state{
     CHAIN_STATE_IDLE=0,
     CHAIN_STATE_SYNC_CHAINS,
     CHAIN_STATE_SYNC_GLOBAL_DB,
-    CHAIN_STATE_SYNC_ALL,
+    CHAIN_STATE_SYNC_ALL
 } dap_stream_ch_chain_state_t;
 
 typedef struct dap_stream_ch_chain_sync_request{
@@ -97,12 +97,16 @@ static const char* c_dap_stream_ch_chain_pkt_type_str[]={
 
 dap_stream_ch_chain_state_t dap_stream_ch_chain_pkt_type_to_dap_stream_ch_chain_state(char a_state);
 
-size_t dap_stream_ch_chain_pkt_write(dap_stream_ch_t *a_ch, uint8_t a_type,dap_chain_net_id_t a_net_id,
-                                     dap_chain_id_t a_chain_id, dap_chain_cell_id_t a_cell_id,
-        const void * a_data, size_t a_data_size);
+size_t dap_stream_ch_chain_pkt_write_unsafe(dap_stream_ch_t *a_ch, uint8_t a_type, dap_chain_net_id_t a_net_id,
+                                            dap_chain_id_t a_chain_id, dap_chain_cell_id_t a_cell_id,
+                                            const void * a_data, size_t a_data_size);
+
+size_t dap_stream_ch_chain_pkt_write_mt(dap_stream_worker_t *a_worker, dap_stream_ch_t *a_ch, uint8_t a_type, dap_chain_net_id_t a_net_id,
+                                        dap_chain_id_t a_chain_id, dap_chain_cell_id_t a_cell_id,
+                                        const void * a_data, size_t a_data_size);
 
 inline static size_t dap_stream_ch_chain_pkt_write_error(dap_stream_ch_t *a_ch, dap_chain_net_id_t a_net_id,
                                                   dap_chain_id_t a_chain_id, dap_chain_cell_id_t a_cell_id, const char * a_err_string )
 {
-    return  dap_stream_ch_chain_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_ERROR, a_net_id, a_chain_id, a_cell_id, a_err_string,strlen (a_err_string)+1 );
+    return  dap_stream_ch_chain_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_ERROR, a_net_id, a_chain_id, a_cell_id, a_err_string,strlen (a_err_string)+1 );
 }
diff --git a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
index ac632bf6be2fc51c38ce3ee651cd95e6abffeba6..60b04baf49f1a973f1ae0739752db6c60366b58b 100644
--- a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
+++ b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
@@ -66,9 +66,9 @@ typedef struct dap_chain_cs_dag_poa_pvt
 static void s_callback_delete(dap_chain_cs_dag_t * a_dag);
 static int s_callback_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg);
 static int s_callback_created(dap_chain_t * a_chain, dap_config_t *a_chain_cfg);
-static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_event_t * a_dag_event);
+static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_event_t * a_dag_event, size_t a_dag_event_size);
 static dap_chain_cs_dag_event_t * s_callback_event_create(dap_chain_cs_dag_t * a_dag, dap_chain_datum_t * a_datum,
-                                                          dap_chain_hash_fast_t * a_hashes, size_t a_hashes_count);
+                                                          dap_chain_hash_fast_t * a_hashes, size_t a_hashes_count, size_t* a_event_size);
 // CLI commands
 static int s_cli_dag_poa(int argc, char ** argv, void *arg_func, char **str_reply);
 
@@ -109,6 +109,7 @@ void dap_chain_cs_dag_poa_deinit(void)
  */
 static int s_cli_dag_poa(int argc, char ** argv, void *arg_func, char **a_str_reply)
 {
+    (void) arg_func;
     int ret = -666;
     int arg_index = 1;
     dap_chain_net_t * l_chain_net = NULL;
@@ -165,9 +166,9 @@ static int s_cli_dag_poa(int argc, char ** argv, void *arg_func, char **a_str_re
                                                   l_event_hash_str);
                 ret = -30;
             }else {
-                dap_chain_cs_dag_event_t *l_event_new = dap_chain_cs_dag_event_copy_with_sign_add(l_event,l_poa_pvt->events_sign_cert->enc_key );
+                dap_chain_cs_dag_event_t *l_event_new = dap_chain_cs_dag_event_copy_with_sign_add(l_event, l_event_size,l_poa_pvt->events_sign_cert->enc_key );
                 dap_chain_hash_fast_t l_event_new_hash;
-                dap_chain_cs_dag_event_calc_hash(l_event_new,&l_event_new_hash);
+                dap_chain_cs_dag_event_calc_hash(l_event_new, l_event_size,&l_event_new_hash);
                 //size_t l_event_new_size = dap_chain_cs_dag_event_calc_size(l_event_new);
                 char * l_event_new_hash_hex_str = dap_chain_hash_fast_to_str_new(&l_event_new_hash);
                 char * l_event_new_hash_base58_str = dap_enc_base58_encode_hash_to_str(&l_event_new_hash);
@@ -319,7 +320,7 @@ static void s_callback_delete(dap_chain_cs_dag_t * a_dag)
  * @return
  */
 static dap_chain_cs_dag_event_t * s_callback_event_create(dap_chain_cs_dag_t * a_dag, dap_chain_datum_t * a_datum,
-                                                          dap_chain_hash_fast_t * a_hashes, size_t a_hashes_count)
+                                                          dap_chain_hash_fast_t * a_hashes, size_t a_hashes_count, size_t* a_event_size)
 {
     dap_return_val_if_fail(a_dag && a_dag->chain && DAP_CHAIN_CS_DAG_POA(a_dag), NULL);
     dap_chain_net_t * l_net = dap_chain_net_by_name( a_dag->chain->net_name );
@@ -330,7 +331,7 @@ static dap_chain_cs_dag_event_t * s_callback_event_create(dap_chain_cs_dag_t * a
     }
     if ( s_seed_mode || (a_hashes && a_hashes_count) ){
         dap_chain_cs_dag_event_t * l_event = dap_chain_cs_dag_event_new( a_dag->chain->id, l_net->pub.cell_id, a_datum,
-                                                         PVT(l_poa)->events_sign_cert->enc_key, a_hashes, a_hashes_count);
+                                                         PVT(l_poa)->events_sign_cert->enc_key, a_hashes, a_hashes_count,a_event_size);
         return l_event;
     }else
         return NULL;
@@ -344,17 +345,30 @@ static dap_chain_cs_dag_event_t * s_callback_event_create(dap_chain_cs_dag_t * a
  * @param a_dag_event
  * @return
  */
-static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_event_t * a_dag_event)
+static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_event_t * a_dag_event, size_t a_dag_event_size)
 {
     dap_chain_cs_dag_poa_pvt_t * l_poa_pvt = PVT ( DAP_CHAIN_CS_DAG_POA( a_dag ) );
+    size_t l_offset_from_beginning = dap_chain_cs_dag_event_calc_size_excl_signs(a_dag_event,a_dag_event_size);
+    if( l_offset_from_beginning >= a_dag_event_size){
+        log_it(L_WARNING,"Incorrect size with event %p: caled size excl signs %zd is bigger or equal then event size %zd",
+               a_dag_event, l_offset_from_beginning, a_dag_event_size);
+        return -7; // Incorrest size
+    }
     if ( a_dag_event->header.signs_count >= l_poa_pvt->auth_certs_count_verify ){
         size_t l_verified = 0;
         for ( uint16_t i = 0; i < a_dag_event->header.signs_count; i++ ) {
-            dap_sign_t * l_sign = dap_chain_cs_dag_event_get_sign(a_dag_event, 0);
+            if (l_offset_from_beginning == a_dag_event_size)
+                break;
+            dap_sign_t * l_sign = dap_chain_cs_dag_event_get_sign(a_dag_event,a_dag_event_size , 0);
             if ( l_sign == NULL){
                 log_it(L_WARNING, "Event is NOT signed with anything");
                 return -4;
             }
+            l_offset_from_beginning += dap_sign_get_size( l_sign);
+            if (l_offset_from_beginning > a_dag_event_size){
+                log_it(L_WARNING,"Incorrect size with event %p", a_dag_event);
+                return -7;
+            }
             for (uint16_t j = 0; j < l_poa_pvt->auth_certs_count; j++) {
                 if (dap_cert_compare_with_sign ( l_poa_pvt->auth_certs[j], l_sign) == 0)
                     l_verified++;
@@ -367,10 +381,11 @@ static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_
                 }
                 dap_chain_addr_t l_addr = {};
                 dap_chain_addr_fill(&l_addr, l_sign->header.type, &l_pkey_hash, a_dag->chain->net_id);
-                dap_chain_datum_t *l_datum = (dap_chain_datum_t *)dap_chain_cs_dag_event_get_datum(a_dag_event);
+                dap_chain_datum_t *l_datum = (dap_chain_datum_t *)dap_chain_cs_dag_event_get_datum(a_dag_event, a_dag_event_size);
                 if (l_datum->header.type_id == DAP_CHAIN_DATUM_TX) {
                     dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_datum->data;
                     if (!dap_chain_net_srv_stake_validator(&l_addr, l_tx)) {
+                        log_it(L_WARNING,"Not passed stake validator event %p", a_dag_event);
                         return -6;
                     }
                 }
@@ -378,7 +393,9 @@ static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_
 
         }
         return l_verified >= l_poa_pvt->auth_certs_count_verify ? 0 : -1;
-    }else
-       return -2; // Wrong signatures number
+    }else{
+        log_it(L_WARNING,"Wrong signatures number with event %p", a_dag_event);
+        return -2; // Wrong signatures number
+    }
 }
 
diff --git a/modules/consensus/dag-pos/dap_chain_cs_dag_pos.c b/modules/consensus/dag-pos/dap_chain_cs_dag_pos.c
index fc3337dcef13d408ac1a63ed4e7f89dc3a0e9c21..597ea51c63afaf5db0f92c5567c1fc847866389c 100644
--- a/modules/consensus/dag-pos/dap_chain_cs_dag_pos.c
+++ b/modules/consensus/dag-pos/dap_chain_cs_dag_pos.c
@@ -49,9 +49,9 @@ typedef struct dap_chain_cs_dag_pos_pvt
 static void s_callback_delete(dap_chain_cs_dag_t * a_dag);
 static int s_callback_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg);
 static int s_callback_created(dap_chain_t * a_chain, dap_config_t *a_chain_cfg);
-static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_event_t * a_dag_event);
+static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_event_t * a_dag_event, size_t a_dag_event_size);
 static dap_chain_cs_dag_event_t * s_callback_event_create(dap_chain_cs_dag_t * a_dag, dap_chain_datum_t * a_datum,
-                                                          dap_chain_hash_fast_t * a_hashes, size_t a_hashes_count);
+                                                          dap_chain_hash_fast_t * a_hashes, size_t a_hashes_count, size_t *a_dag_event_size);
 
 /**
  * @brief dap_chain_cs_dag_pos_init
@@ -186,7 +186,8 @@ static void s_callback_delete(dap_chain_cs_dag_t * a_dag)
  * @return
  */
 static dap_chain_cs_dag_event_t * s_callback_event_create(dap_chain_cs_dag_t * a_dag, dap_chain_datum_t * a_datum,
-                                                          dap_chain_hash_fast_t * a_hashes, size_t a_hashes_count)
+                                                          dap_chain_hash_fast_t * a_hashes, size_t a_hashes_count,
+                                                          size_t *a_dag_event_size)
 {
     dap_return_val_if_fail(a_dag && a_dag->chain && DAP_CHAIN_CS_DAG_POS(a_dag) && a_datum, NULL);
     dap_chain_net_t * l_net = dap_chain_net_by_name( a_dag->chain->net_name );
@@ -198,7 +199,7 @@ static dap_chain_cs_dag_event_t * s_callback_event_create(dap_chain_cs_dag_t * a
     }
     if(a_datum || (a_hashes && a_hashes_count)) {
         dap_chain_cs_dag_event_t * l_event = dap_chain_cs_dag_event_new(a_dag->chain->id, l_net->pub.cell_id, a_datum,
-        PVT(l_pos)->events_sign_wallet->enc_key, a_hashes, a_hashes_count);
+        PVT(l_pos)->events_sign_wallet->enc_key, a_hashes, a_hashes_count, a_dag_event_size);
         return l_event;
     } else
         return NULL;
@@ -210,21 +211,27 @@ static dap_chain_cs_dag_event_t * s_callback_event_create(dap_chain_cs_dag_t * a
  * @param a_dag_event
  * @return
  */
-static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_event_t * a_dag_event)
+static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_event_t * a_dag_event, size_t a_dag_event_size)
 {
 
     dap_chain_cs_dag_pos_t * l_pos =DAP_CHAIN_CS_DAG_POS( a_dag ) ;
     dap_chain_cs_dag_pos_pvt_t * l_pos_pvt = PVT ( DAP_CHAIN_CS_DAG_POS( a_dag ) );
 
-    if(a_dag->chain->ledger == NULL)
+    if(a_dag->chain->ledger == NULL){
+        log_it(L_CRITICAL,"Ledger is NULL can't check PoS on this chain %s", a_dag->chain->name);
         return -3;
+    }
 
+    if (sizeof (a_dag_event->header)>= a_dag_event_size){
+        log_it(L_WARNING,"Incorrect size with event %p on chain %s", a_dag_event, a_dag->chain->name);
+        return  -7;
+    }
     if ( a_dag_event->header.signs_count >= l_pos_pvt->confirmations_minimum ){
         uint16_t l_verified_num = 0;
         dap_chain_addr_t l_addr = { 0 };
 
         for ( size_t l_sig_pos=0; l_sig_pos < a_dag_event->header.signs_count; l_sig_pos++ ){
-            dap_sign_t * l_sign = dap_chain_cs_dag_event_get_sign(a_dag_event, 0);
+            dap_sign_t * l_sign = dap_chain_cs_dag_event_get_sign(a_dag_event, 0,a_dag_event_size);
             if ( l_sign == NULL){
                 log_it(L_WARNING, "Event is NOT signed with anything");
                 return -4;
@@ -238,10 +245,11 @@ static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_
             dap_chain_addr_fill(&l_addr, l_sign->header.type, &l_pkey_hash, a_dag->chain->net_id);
 
             if (l_sig_pos == 0) {
-                dap_chain_datum_t *l_datum = (dap_chain_datum_t *)dap_chain_cs_dag_event_get_datum(a_dag_event);
+                dap_chain_datum_t *l_datum = (dap_chain_datum_t *)dap_chain_cs_dag_event_get_datum(a_dag_event,a_dag_event_size);
                 if (l_datum->header.type_id == DAP_CHAIN_DATUM_TX) {
                     dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_datum->data;
                     if (!dap_chain_net_srv_stake_validator(&l_addr, l_tx)) {
+                        log_it(L_WARNING,"Not passed stake validator with event %p on chain %s", a_dag_event, a_dag->chain->name);
                         return -6;
                     }
                 }
@@ -287,6 +295,8 @@ static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_
             log_it(L_WARNING, "Wrong event: only %su/%su signs are valid", l_verified_num, l_pos_pvt->confirmations_minimum );
             return -2;
         }
-    }else
-       return -2; // Wrong signatures number
+    }else{
+        log_it(L_WARNING,"Wrong signature number with event %p on chain %s", a_dag_event, a_dag->chain->name);
+        return -2; // Wrong signatures number
+    }
 }
diff --git a/modules/consensus/none/dap_chain_cs_none.c b/modules/consensus/none/dap_chain_cs_none.c
index 5086bc7adea914a2e9a423db8feeea8bec9a4572..f68ce988c17733f7bc2ef0354ae48308afc0ba96 100644
--- a/modules/consensus/none/dap_chain_cs_none.c
+++ b/modules/consensus/none/dap_chain_cs_none.c
@@ -68,30 +68,29 @@ typedef struct dap_chain_gdb_private
 static int dap_chain_gdb_ledger_load(dap_chain_gdb_t *a_gdb, dap_chain_net_t *a_net);
 
 // Atomic element organization callbacks
-static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t); //    Accept new event in gdb
-static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t); //    Verify new event in gdb
-static size_t s_chain_callback_atom_hdr_get_size(dap_chain_atom_ptr_t); //    Get gdb event size
+static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t, size_t); //    Accept new event in gdb
+static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t, size_t); //    Verify new event in gdb
 static size_t s_chain_callback_atom_get_static_hdr_size(void); //    Get gdb event header size
 
 static dap_chain_atom_iter_t* s_chain_callback_atom_iter_create(dap_chain_t * a_chain);
 static dap_chain_atom_iter_t* s_chain_callback_atom_iter_create_from(dap_chain_t * a_chain,
-        dap_chain_atom_ptr_t a);
+        dap_chain_atom_ptr_t a, size_t a_atom_size);
 
 // Delete iterator
 static void s_chain_callback_atom_iter_delete(dap_chain_atom_iter_t * a_atom_iter); //    Get the fisrt event from gdb
 
 static dap_chain_atom_ptr_t s_chain_callback_atom_iter_find_by_hash(dap_chain_atom_iter_t * a_atom_iter,
-        dap_chain_hash_fast_t * a_atom_hash);
+        dap_chain_hash_fast_t * a_atom_hash, size_t * a_atom_size);
 static dap_chain_atom_ptr_t s_chain_callback_atom_iter_find_by_tx_hash(dap_chain_atom_iter_t * a_atom_iter ,
-                                                                       dap_chain_hash_fast_t * a_atom_hash);
+                                                                       dap_chain_hash_fast_t * a_atom_hash, size_t * a_atom_size);
 
 // Get event(s) from gdb
-static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_first(dap_chain_atom_iter_t * a_atom_iter); //    Get the fisrt event from gdb
-static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_next(dap_chain_atom_iter_t * a_atom_iter); //    Get the next event from gdb
+static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_first(dap_chain_atom_iter_t * a_atom_iter, size_t * a_atom_size); //    Get the fisrt event from gdb
+static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_next(dap_chain_atom_iter_t * a_atom_iter, size_t * a_atom_size); //    Get the next event from gdb
 static dap_chain_atom_ptr_t *s_chain_callback_atom_iter_get_links(dap_chain_atom_iter_t * a_atom_iter,
-        size_t * a_links_size_ptr); //    Get list of linked events
+        size_t * a_links_size_ptr, size_t ** a_lasts_sizes_ptr); //    Get list of linked events
 static dap_chain_atom_ptr_t *s_chain_callback_atom_iter_get_lasts(dap_chain_atom_iter_t * a_atom_iter,
-        size_t * a_lasts_size_ptr); //    Get list of linked events
+        size_t * a_lasts_size_ptr, size_t ** a_lasts_sizes_ptr); //    Get list of linked events
 
 static size_t s_chain_callback_datums_pool_proc(dap_chain_t * a_chain, dap_chain_datum_t ** a_datums,
         size_t a_datums_size);
@@ -185,7 +184,6 @@ int dap_chain_gdb_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
     // Atom element callbacks
     a_chain->callback_atom_add = s_chain_callback_atom_add; // Accept new element in chain
     a_chain->callback_atom_verify = s_chain_callback_atom_verify; // Verify new element in chain
-    a_chain->callback_atom_get_size = s_chain_callback_atom_hdr_get_size; // Get dag event size
     a_chain->callback_atom_get_hdr_static_size = s_chain_callback_atom_get_static_hdr_size; // Get dag event hdr size
 
     a_chain->callback_atom_iter_create = s_chain_callback_atom_iter_create;
@@ -263,7 +261,6 @@ const char* dap_chain_gdb_get_group(dap_chain_t * a_chain)
 static int dap_chain_gdb_ledger_load(dap_chain_gdb_t *a_gdb, dap_chain_net_t *a_net)
 {
     dap_chain_gdb_private_t *l_gdb_priv = PVT(a_gdb);
-    dap_list_t *l_datum_list = NULL, *l_list_tmp = NULL;
     // protect from reloading
     if(dap_chain_ledger_count( a_net->pub.ledger ) > 0)
         return 0;
@@ -275,19 +272,10 @@ static int dap_chain_gdb_ledger_load(dap_chain_gdb_t *a_gdb, dap_chain_net_t *a_
     dap_global_db_obj_t *data = dap_chain_global_db_gr_load(l_gdb_priv->group_datums , &l_data_size);
     // make list of datums
     for(size_t i = 0; i < l_data_size; i++) {
-        l_datum_list = dap_list_append(l_datum_list, data[i].value);
-    }
-    // sort list by time
-    //l_datum_list = dap_list_sort(l_datum_list, (dap_callback_compare_t) compare_datum_items);
-    l_list_tmp = l_datum_list;
-    // add datum_tx from list to ledger
-    while(l_list_tmp) {
-        dap_chain_datum_t *l_datum = (dap_chain_datum_t*) l_list_tmp->data;
-        s_chain_callback_atom_add(a_gdb->chain,l_datum);
-        l_list_tmp = dap_list_next(l_list_tmp);
+        s_chain_callback_atom_add(a_gdb->chain,data[i].value, data[i].value_len);
+
     }
     dap_chain_global_db_objs_delete(data, l_data_size);
-    dap_list_free(l_datum_list);
     return 0;
 }
 
@@ -302,7 +290,7 @@ static size_t s_chain_callback_datums_pool_proc(dap_chain_t * a_chain, dap_chain
 {
     for(size_t i = 0; i < a_datums_count; i++) {
         dap_chain_datum_t * l_datum = a_datums[i];
-        s_chain_callback_atom_add(a_chain, l_datum );
+        s_chain_callback_atom_add(a_chain, l_datum,dap_chain_datum_size(l_datum) );
     }
     return a_datums_count;
 }
@@ -321,11 +309,16 @@ static size_t s_chain_callback_datums_pool_proc_with_group(dap_chain_t * a_chain
  * @param a_datums
  * @param a_datums_size
  */
-static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom)
+static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size)
 {
     dap_chain_gdb_t * l_gdb = DAP_CHAIN_GDB(a_chain);
     dap_chain_gdb_private_t *l_gdb_priv = PVT(l_gdb);
     dap_chain_datum_t *l_datum = (dap_chain_datum_t*) a_atom;
+    if ( a_atom_size < l_datum->header.data_size+ sizeof (l_datum->header) ){
+        log_it(L_INFO,"Corrupted atom rejected: wrong size %zd not equel or less atom size %zd",l_datum->header.data_size+ sizeof (l_datum->header),
+               a_atom_size);
+        return ATOM_REJECT;
+    }
     switch (l_datum->header.type_id) {
         case DAP_CHAIN_DATUM_TOKEN_DECL:{
             dap_chain_datum_token_t *l_token = (dap_chain_datum_token_t*) l_datum->data;
@@ -369,22 +362,14 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
  * @param a_atom
  * @return
  */
-static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom)
+static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size)
 {
     (void) a_chain;
     (void) a_atom;
+    (void) a_atom_size;
     return ATOM_ACCEPT;
 }
 
-/**
- * @brief s_chain_callback_atom_get_size Get size of atomic element
- * @param a_atom
- * @return
- */
-static size_t s_chain_callback_atom_hdr_get_size(dap_chain_atom_ptr_t a_atom)
-{
-    return ((dap_chain_datum_t *) a_atom)->header.data_size +sizeof (((dap_chain_datum_t *) a_atom)->header);
-}
 
 /**
  * @brief s_chain_callback_atom_get_static_hdr_size
@@ -416,7 +401,7 @@ static dap_chain_atom_iter_t* s_chain_callback_atom_iter_create(dap_chain_t * a_
  * @return
  */
 static dap_chain_atom_iter_t* s_chain_callback_atom_iter_create_from(dap_chain_t * a_chain,
-        dap_chain_atom_ptr_t a_atom)
+        dap_chain_atom_ptr_t a_atom, size_t a_atom_size)
 {
     dap_chain_atom_iter_t * l_iter = DAP_NEW_Z(dap_chain_atom_iter_t);
     l_iter->chain = a_chain;
@@ -441,7 +426,7 @@ static void s_chain_callback_atom_iter_delete(dap_chain_atom_iter_t * a_atom_ite
  * @return
  */
 static dap_chain_atom_ptr_t s_chain_callback_atom_iter_find_by_hash(dap_chain_atom_iter_t * a_atom_iter,
-        dap_chain_hash_fast_t * a_atom_hash)
+        dap_chain_hash_fast_t * a_atom_hash, size_t *a_atom_size)
 {
     char * l_key = dap_chain_hash_fast_to_str_new(a_atom_hash);
     size_t l_ret_size;
@@ -449,6 +434,7 @@ static dap_chain_atom_ptr_t s_chain_callback_atom_iter_find_by_hash(dap_chain_at
     dap_chain_gdb_t * l_gdb = DAP_CHAIN_GDB(a_atom_iter->chain );
     l_ret = dap_chain_global_db_gr_get(l_key,&l_ret_size,
                                        PVT ( l_gdb )->group_datums  );
+    *a_atom_size = l_ret_size;
     return l_ret;
 }
 
@@ -457,7 +443,7 @@ static dap_chain_atom_ptr_t s_chain_callback_atom_iter_find_by_hash(dap_chain_at
  * @param a_atom_iter
  * @return
  */
-static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_first(dap_chain_atom_iter_t * a_atom_iter)
+static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_first(dap_chain_atom_iter_t * a_atom_iter, size_t *a_atom_size)
 {
     dap_chain_datum_t * l_datum = NULL;
     a_atom_iter->cur_item = PVT ( DAP_CHAIN_GDB(a_atom_iter->chain) )->hash_items;
@@ -468,7 +454,9 @@ static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_first(dap_chain_atom_
         if (a_atom_iter->cur) // This iterator should clean up data for it because its allocate it
             DAP_DELETE( a_atom_iter->cur);
         a_atom_iter->cur = l_datum;
-    }
+        *a_atom_size = l_datum_size;
+    }else
+        *a_atom_size = 0;
     return l_datum;
 }
 
@@ -477,7 +465,7 @@ static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_first(dap_chain_atom_
  * @param a_atom_iter
  * @return
  */
-static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_next(dap_chain_atom_iter_t * a_atom_iter)
+static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_next(dap_chain_atom_iter_t * a_atom_iter,size_t *a_atom_size)
 {
     dap_chain_datum_t * l_datum = NULL;
     a_atom_iter->cur_item = a_atom_iter->cur_item?
@@ -490,7 +478,9 @@ static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_next(dap_chain_atom_i
         if (a_atom_iter->cur) // This iterator should clean up data for it because its allocate it
             DAP_DELETE( a_atom_iter->cur);
         a_atom_iter->cur = l_datum;
-    }
+        *a_atom_size = l_datum_size;
+    }else
+        *a_atom_size = 0;
     return l_datum;
 }
 
@@ -501,10 +491,11 @@ static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_next(dap_chain_atom_i
  * @return
  */
 static dap_chain_atom_ptr_t* s_chain_callback_atom_iter_get_links(dap_chain_atom_iter_t * a_atom_iter,
-        size_t * a_links_size_ptr)
+        size_t * a_links_size_ptr, size_t **a_links_sizes_ptr)
 {
     (void) a_atom_iter;
     (void) a_links_size_ptr;
+    (void) a_links_sizes_ptr;
     return NULL;
 }
 
@@ -515,10 +506,11 @@ static dap_chain_atom_ptr_t* s_chain_callback_atom_iter_get_links(dap_chain_atom
  * @return
  */
 static dap_chain_atom_ptr_t* s_chain_callback_atom_iter_get_lasts(dap_chain_atom_iter_t * a_atom_iter,
-        size_t * a_lasts_size_ptr)
+        size_t * a_lasts_size_ptr,  size_t **a_links_sizes_ptr)
 {
     (void) a_atom_iter;
     (void) a_lasts_size_ptr;
+    (void) a_links_sizes_ptr;
     return NULL;
 }
 
diff --git a/modules/global-db/dap_chain_global_db_driver.c b/modules/global-db/dap_chain_global_db_driver.c
index b1e80583100dff38df943ec1daddc158b286f400..fd07a1bda401d4a7667c7b4377629862718659c5 100644
--- a/modules/global-db/dap_chain_global_db_driver.c
+++ b/modules/global-db/dap_chain_global_db_driver.c
@@ -196,53 +196,64 @@ static size_t dap_db_get_size_pdap_store_obj_t(pdap_store_obj_t store_obj)
  * @param a_size_out[out] size of output structure
  * @return NULL in case of an error
  */
-dap_store_obj_pkt_t *dap_store_packet_multiple(pdap_store_obj_t a_store_obj, time_t a_timestamp,
+dap_list_t *dap_store_packet_multiple(pdap_store_obj_t a_store_obj, time_t a_timestamp,
         size_t a_store_obj_count)
 {
-    if(!a_store_obj || a_store_obj_count < 1)
+    if (!a_store_obj || a_store_obj_count < 1)
         return NULL;
-    size_t l_data_size_out = sizeof(uint32_t); // size of output data
+
     // calculate output structure size
-    for(size_t l_q = 0; l_q < a_store_obj_count; ++l_q)
+    dap_list_t *l_ret = NULL;
+    dap_store_obj_pkt_t *l_pkt;
+    uint32_t l_obj_count = 0, l_data_size_out = 0;
+    for (size_t l_q = 0; l_q < a_store_obj_count; ++l_q) {
         l_data_size_out += dap_db_get_size_pdap_store_obj_t(&a_store_obj[l_q]);
-
-    dap_store_obj_pkt_t *l_pkt = DAP_NEW_Z_SIZE(dap_store_obj_pkt_t, sizeof(dap_store_obj_pkt_t) + l_data_size_out);
-    l_pkt->data_size = l_data_size_out;
-    l_pkt->timestamp = a_timestamp;
-    uint64_t l_offset = 0;
-    uint32_t l_count = (uint32_t) a_store_obj_count;
-    memcpy(l_pkt->data + l_offset, &l_count, sizeof(uint32_t));
-    l_offset += sizeof(uint32_t);
-    for(size_t l_q = 0; l_q < a_store_obj_count; ++l_q) {
-        dap_store_obj_t obj = a_store_obj[l_q];
-        //uint16_t section_size = (uint16_t) dap_strlen(obj.section);
-        uint16_t group_size = (uint16_t) dap_strlen(obj.group);
-        uint16_t key_size = (uint16_t) dap_strlen(obj.key);
-        memcpy(l_pkt->data + l_offset, &obj.type, sizeof(int));
-        l_offset += sizeof(int);
-        //memcpy(l_pkt->data + l_offset, &section_size, sizeof(uint16_t));
-        //l_offset += sizeof(uint16_t);
-        //memcpy(l_pkt->data + l_offset, obj.section, section_size);
-        //l_offset += section_size;
-        memcpy(l_pkt->data + l_offset, &group_size, sizeof(uint16_t));
-        l_offset += sizeof(uint16_t);
-        memcpy(l_pkt->data + l_offset, obj.group, group_size);
-        l_offset += group_size;
-        memcpy(l_pkt->data + l_offset, &obj.id, sizeof(uint64_t));
-        l_offset += sizeof(uint64_t);
-        memcpy(l_pkt->data + l_offset, &obj.timestamp, sizeof(time_t));
-        l_offset += sizeof(time_t);
-        memcpy(l_pkt->data + l_offset, &key_size, sizeof(uint16_t));
-        l_offset += sizeof(uint16_t);
-        memcpy(l_pkt->data + l_offset, obj.key, key_size);
-        l_offset += key_size;
-        memcpy(l_pkt->data + l_offset, &obj.value_len, sizeof(size_t));
-        l_offset += sizeof(size_t);
-        memcpy(l_pkt->data + l_offset, obj.value, obj.value_len);
-        l_offset += obj.value_len;
+        if (l_data_size_out > DAP_CHAIN_PKT_EXPECT_SIZE || (l_q == a_store_obj_count - 1 && l_data_size_out)) {
+            l_pkt = DAP_NEW_Z_SIZE(dap_store_obj_pkt_t, sizeof(dap_store_obj_pkt_t) + l_data_size_out);
+            l_pkt->data_size = l_data_size_out;
+            l_pkt->timestamp = a_timestamp;
+            l_pkt->obj_count = l_q + 1 - l_obj_count;
+            l_ret = dap_list_append(l_ret, l_pkt);
+            l_data_size_out = 0;
+            l_obj_count = l_q + 1;
+        }
     }
-    assert(l_data_size_out == l_offset);
-    return l_pkt;
+    l_obj_count = 0;
+    for (dap_list_t *l_iter = l_ret; l_iter; l_iter = dap_list_next(l_iter)) {
+        l_pkt = (dap_store_obj_pkt_t *)l_iter->data;
+        uint64_t l_offset = 0;
+        for(size_t l_q = 0; l_q < l_pkt->obj_count; ++l_q) {
+            dap_store_obj_t obj = a_store_obj[l_obj_count + l_q];
+            //uint16_t section_size = (uint16_t) dap_strlen(obj.section);
+            uint16_t group_size = (uint16_t) dap_strlen(obj.group);
+            uint16_t key_size = (uint16_t) dap_strlen(obj.key);
+            memcpy(l_pkt->data + l_offset, &obj.type, sizeof(int));
+            l_offset += sizeof(int);
+            //memcpy(l_pkt->data + l_offset, &section_size, sizeof(uint16_t));
+            //l_offset += sizeof(uint16_t);
+            //memcpy(l_pkt->data + l_offset, obj.section, section_size);
+            //l_offset += section_size;
+            memcpy(l_pkt->data + l_offset, &group_size, sizeof(uint16_t));
+            l_offset += sizeof(uint16_t);
+            memcpy(l_pkt->data + l_offset, obj.group, group_size);
+            l_offset += group_size;
+            memcpy(l_pkt->data + l_offset, &obj.id, sizeof(uint64_t));
+            l_offset += sizeof(uint64_t);
+            memcpy(l_pkt->data + l_offset, &obj.timestamp, sizeof(time_t));
+            l_offset += sizeof(time_t);
+            memcpy(l_pkt->data + l_offset, &key_size, sizeof(uint16_t));
+            l_offset += sizeof(uint16_t);
+            memcpy(l_pkt->data + l_offset, obj.key, key_size);
+            l_offset += key_size;
+            memcpy(l_pkt->data + l_offset, &obj.value_len, sizeof(size_t));
+            l_offset += sizeof(size_t);
+            memcpy(l_pkt->data + l_offset, obj.value, obj.value_len);
+            l_offset += obj.value_len;
+        }
+        l_obj_count += l_pkt->obj_count;
+        assert(l_pkt->data_size == l_offset);
+    }
+    return l_ret;
 }
 /**
  * deserialization
@@ -255,9 +266,7 @@ dap_store_obj_t *dap_store_unpacket_multiple(const dap_store_obj_pkt_t *pkt, siz
     if(!pkt || pkt->data_size < 1)
         return NULL;
     uint64_t offset = 0;
-    uint32_t count;
-    memcpy(&count, pkt->data, sizeof(uint32_t));
-    offset += sizeof(uint32_t);
+    uint32_t count = pkt->obj_count;
     dap_store_obj_t *store_obj = DAP_NEW_Z_SIZE(dap_store_obj_t, count * sizeof(struct dap_store_obj));
     for(size_t q = 0; q < count; ++q) {
         dap_store_obj_t *obj = store_obj + q;
diff --git a/modules/global-db/dap_chain_global_db_hist.c b/modules/global-db/dap_chain_global_db_hist.c
index c2683b156035b3ac7eab75ef6fed3f7d9cf45301..4ac96d14723d9dba34e479c32cba8cfc776cce10 100644
--- a/modules/global-db/dap_chain_global_db_hist.c
+++ b/modules/global-db/dap_chain_global_db_hist.c
@@ -77,7 +77,7 @@ static char* dap_db_new_history_timestamp()
  *
  * return dap_store_obj_pkt_t*
  */
-uint8_t* dap_db_log_pack(dap_global_db_obj_t *a_obj, size_t *a_data_size_out)
+dap_list_t* dap_db_log_pack(dap_global_db_obj_t *a_obj, size_t *a_data_size_out)
 {
     if(!a_obj)
         return NULL;
@@ -122,15 +122,18 @@ uint8_t* dap_db_log_pack(dap_global_db_obj_t *a_obj, size_t *a_data_size_out)
         i++;
     }
     // serialize data
-    dap_store_obj_pkt_t *l_data_out = dap_store_packet_multiple(l_store_obj, l_timestamp, l_count);
+    dap_list_t *l_data_out = dap_store_packet_multiple(l_store_obj, l_timestamp, l_count);
 
     dap_store_obj_free(l_store_obj, l_count);
     dap_strfreev(l_keys);
 
     if(l_data_out && a_data_size_out) {
-        *a_data_size_out = sizeof(dap_store_obj_pkt_t) + l_data_out->data_size;
+        *a_data_size_out = 0;
+        for (dap_list_t *l_iter = l_data_out; l_iter; l_iter = dap_list_next(l_iter)) {
+            *a_data_size_out += sizeof(dap_store_obj_pkt_t) + ((dap_store_obj_pkt_t *)l_data_out)->data_size;
+        }
     }
-    return (uint8_t*) l_data_out;
+    return l_data_out;
 
 }
 
@@ -1326,7 +1329,6 @@ dap_db_log_list_t* dap_db_log_list_start(uint64_t first_id, dap_list_t *a_add_gr
     dap_db_log_list_t *l_dap_db_log_list = DAP_NEW_Z(dap_db_log_list_t);
 
     size_t l_add_groups_num = 0;// number of group
-    //size_t l_add_groups_items_num = 0;// number items in all groups
     dap_list_t *l_add_groups_mask = a_add_groups_mask;
     // calc l_add_groups_num
     while(l_add_groups_mask) {
@@ -1337,7 +1339,6 @@ dap_db_log_list_t* dap_db_log_list_start(uint64_t first_id, dap_list_t *a_add_gr
         l_add_groups_mask = dap_list_next(l_add_groups_mask);
     }
 
-    //size_t l_add_groups_num = dap_list_length(a_add_groups_mask);
     size_t l_data_size_out_main = dap_chain_global_db_driver_count(GROUP_LOCAL_HISTORY, first_id);
     size_t *l_data_size_out_add_items = DAP_NEW_Z_SIZE(size_t, sizeof(size_t) * l_add_groups_num);
     uint64_t *l_group_last_id = DAP_NEW_Z_SIZE(uint64_t, sizeof(uint64_t) * l_add_groups_num);
@@ -1366,9 +1367,6 @@ dap_db_log_list_t* dap_db_log_list_start(uint64_t first_id, dap_list_t *a_add_gr
     }
     if(!(l_data_size_out_main + l_data_size_out_add_items_count))
         return NULL;
-    // debug
-//    if(l_data_size_out>11)
-//        l_data_size_out = 11;
     l_dap_db_log_list->item_start = first_id;
     l_dap_db_log_list->item_last = first_id + l_data_size_out_main;
     l_dap_db_log_list->items_number_main = l_data_size_out_main;
@@ -1381,31 +1379,9 @@ dap_db_log_list_t* dap_db_log_list_start(uint64_t first_id, dap_list_t *a_add_gr
     l_dap_db_log_list->group_names = l_group_names;
     l_dap_db_log_list->group_cur = -1;
     l_dap_db_log_list->add_groups = a_add_groups_mask;
-    // there are too few items, read items right now
-    if(0) {//l_data_size_out <= 10) {
-        dap_list_t *l_list = NULL;
-        // read first items
-        size_t l_objs_count = 0;
-        dap_store_obj_t *l_objs = dap_chain_global_db_cond_load(GROUP_LOCAL_HISTORY, first_id, &l_objs_count);
-        for(size_t i = 0; i < l_objs_count; i++) {
-            dap_store_obj_t *l_obj_cur = l_objs + i;
-            dap_global_db_obj_t *l_item = DAP_NEW(dap_global_db_obj_t);
-            l_item->id = l_obj_cur->id;
-            l_item->key = dap_strdup(l_obj_cur->key);
-            l_item->value = (uint8_t*) dap_strdup((char*) l_obj_cur->value);
-            l_list = dap_list_append(l_list, l_item);
-        }
-        l_dap_db_log_list->list_write = l_list;
-        l_dap_db_log_list->list_read = l_list;
-        //log_it(L_DEBUG, "loaded items n=%d", l_data_size_out);
-        dap_store_obj_free(l_objs, l_objs_count);
-    }
-    // start thread for items loading
-    else {
-        l_dap_db_log_list->is_process = true;
-        pthread_mutex_init(&l_dap_db_log_list->list_mutex, NULL);
-        pthread_create(&l_dap_db_log_list->thread, NULL, s_list_thread_proc, l_dap_db_log_list);
-    }
+    l_dap_db_log_list->is_process = true;
+    pthread_mutex_init(&l_dap_db_log_list->list_mutex, NULL);
+    pthread_create(&l_dap_db_log_list->thread, NULL, s_list_thread_proc, l_dap_db_log_list);
     return l_dap_db_log_list;
 }
 
diff --git a/modules/global-db/include/dap_chain_global_db.h b/modules/global-db/include/dap_chain_global_db.h
index 4ac3c5a9a341967527090abafd49e33c3499e618..76ae0627161424824ce8d44a65eb493be464bcf3 100644
--- a/modules/global-db/include/dap_chain_global_db.h
+++ b/modules/global-db/include/dap_chain_global_db.h
@@ -119,7 +119,7 @@ char* dap_chain_global_db_hash(const uint8_t *data, size_t data_size);
 char* dap_chain_global_db_hash_fast(const uint8_t *data, size_t data_size);
 
 // Get data according the history log
-uint8_t* dap_db_log_pack(dap_global_db_obj_t *a_obj, size_t *a_data_size_out);
+dap_list_t* dap_db_log_pack(dap_global_db_obj_t *a_obj, size_t *a_data_size_out);
 
 // Get data according the history log
 //char* dap_db_history_tx(dap_chain_hash_fast_t * a_tx_hash, const char *a_group_mempool);
diff --git a/modules/global-db/include/dap_chain_global_db_driver.h b/modules/global-db/include/dap_chain_global_db_driver.h
index c8d7ef9c5297971699256e5cfe12ed8e68f53e9d..4bccdc9e0905fa1ee4423aca3459065b331c29de 100644
--- a/modules/global-db/include/dap_chain_global_db_driver.h
+++ b/modules/global-db/include/dap_chain_global_db_driver.h
@@ -29,6 +29,8 @@
 #include "dap_common.h"
 #include "dap_list.h"
 
+#define DAP_CHAIN_PKT_EXPECT_SIZE 7168
+
 typedef struct dap_store_obj {
 	uint64_t id;
     time_t timestamp;
@@ -42,8 +44,9 @@ typedef struct dap_store_obj {
 }DAP_ALIGN_PACKED dap_store_obj_t, *pdap_store_obj_t;
 
 typedef struct dap_store_obj_pkt {
-	time_t timestamp;
-	size_t data_size;
+    uint64_t timestamp;
+    uint64_t data_size;
+    uint32_t obj_count;
 	uint8_t data[];
 }__attribute__((packed)) dap_store_obj_pkt_t;
 
@@ -90,7 +93,7 @@ bool dap_chain_global_db_driver_is(const char *a_group, const char *a_key);
 size_t dap_chain_global_db_driver_count(const char *a_group, uint64_t id);
 dap_list_t* dap_chain_global_db_driver_get_groups_by_mask(const char *a_group_mask);
 
-dap_store_obj_pkt_t *dap_store_packet_multiple(pdap_store_obj_t a_store_obj,
+dap_list_t *dap_store_packet_multiple(pdap_store_obj_t a_store_obj,
 		time_t a_timestamp, size_t a_store_obj_count);
 dap_store_obj_t *dap_store_unpacket_multiple(const dap_store_obj_pkt_t *a_pkt,
 		size_t *a_store_obj_count);
diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c
index 9b4c4ebe29990324b568e1323b28a9d8ef8a9eac..c5150e1cfd84094cb2abaee51480592e0c446545 100644
--- a/modules/mempool/dap_chain_mempool.c
+++ b/modules/mempool/dap_chain_mempool.c
@@ -887,15 +887,15 @@ void chain_mempool_proc(struct dap_http_simple *cl_st, void * arg)
 {
     http_status_code_t * return_code = (http_status_code_t*) arg;
     // save key while it alive, i.e. still exist
-    dap_enc_key_t *key = dap_enc_ks_find_http(cl_st->http);
+    dap_enc_key_t *key = dap_enc_ks_find_http(cl_st->http_client);
     //dap_enc_key_serealize_t *key_ser = dap_enc_key_serealize(key_tmp);
     //dap_enc_key_t *key = dap_enc_key_deserealize(key_ser, sizeof(dap_enc_key_serealize_t));
 
     // read header
     dap_http_header_t *hdr_session_close_id =
-            (cl_st->http) ? dap_http_header_find(cl_st->http->in_headers, "SessionCloseAfterRequest") : NULL;
+            (cl_st->http_client) ? dap_http_header_find(cl_st->http_client->in_headers, "SessionCloseAfterRequest") : NULL;
     dap_http_header_t *hdr_key_id =
-            (hdr_session_close_id && cl_st->http) ? dap_http_header_find(cl_st->http->in_headers, "KeyID") : NULL;
+            (hdr_session_close_id && cl_st->http_client) ? dap_http_header_find(cl_st->http_client->in_headers, "KeyID") : NULL;
 
     enc_http_delegate_t *dg = enc_http_request_decode(cl_st);
     if(dg) {
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index 2f54a6c98138bf589bd0dc8a0c8840c419867e0c..fb3731e98df40e5610f20bdd12398dc30b09f9d5 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -23,11 +23,12 @@
     along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 #include <stdlib.h>
-#define _XOPEN_SOURCE       /* See feature_test_macros(7) */
+#include <stdint.h>
+#include <stddef.h>
 #include <stdio.h>
-#include <time.h>
+
+
 #include <stdlib.h>
 #include <stddef.h>
 #include <stdint.h>
@@ -88,7 +89,9 @@
 #include <dirent.h>
 
 #define _XOPEN_SOURCE       /* See feature_test_macros(7) */
+#ifndef __USE_XOPEN
 #define __USE_XOPEN
+#endif
 #define _GNU_SOURCE
 #include <time.h>
 
@@ -265,17 +268,23 @@ void dap_chain_net_sync_gdb_broadcast(void *a_arg, const char a_op_code, const c
         l_obj->type = (uint8_t)a_op_code;
         DAP_DELETE(l_obj->group);
         l_obj->group = dap_strdup(a_group);
-        dap_store_obj_pkt_t *l_data_out = dap_store_packet_multiple(l_obj, l_obj->timestamp, 1);
+        dap_list_t *l_list_out = dap_store_packet_multiple(l_obj, l_obj->timestamp, 1);
+        // Expect only one element in list
+        dap_store_obj_pkt_t *l_data_out = (dap_store_obj_pkt_t *)l_list_out->data;
         dap_store_obj_free(l_obj, 1);
         dap_chain_t *l_chain = dap_chain_net_get_chain_by_name(l_net, "gdb");
         dap_chain_id_t l_chain_id = l_chain ? l_chain->id : (dap_chain_id_t) {};
         for (dap_list_t *l_tmp = PVT(l_net)->links; l_tmp; l_tmp = dap_list_next(l_tmp)) {
             dap_chain_node_client_t *l_node_client = (dap_chain_node_client_t *)l_tmp->data;
             dap_stream_ch_t *l_ch_chain = dap_client_get_stream_ch(l_node_client->client, dap_stream_ch_chain_get_id());
-            dap_stream_ch_chain_pkt_write(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_GLOBAL_DB, l_net->pub.id,
-                                          l_chain_id, l_net->pub.cell_id, l_data_out, sizeof(dap_store_obj_pkt_t) + l_data_out->data_size);
+            if (!l_ch_chain) {
+                continue;
+            }
+            dap_stream_ch_chain_pkt_write_unsafe(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_GLOBAL_DB, l_net->pub.id,
+                                                 l_chain_id, l_net->pub.cell_id, l_data_out,
+                                                 sizeof(dap_store_obj_pkt_t) + l_data_out->data_size);
         }
-        DAP_DELETE(l_data_out);
+        dap_list_free_full(l_list_out, free);
     }
 }
 
@@ -295,6 +304,7 @@ static void s_gbd_history_callback_notify (void * a_arg, const char a_op_code, c
     if (!a_arg) {
         return;
     }
+    dap_chain_node_mempool_autoproc_notify(a_arg, a_op_code, a_prefix, a_group, a_key, a_value, a_value_len);
     dap_chain_net_sync_gdb_broadcast(a_arg, a_op_code, a_prefix, a_group, a_key, a_value, a_value_len);
     if (s_srv_callback_notify) {
         s_srv_callback_notify(a_arg, a_op_code, a_prefix, a_group, a_key, a_value, a_value_len);
@@ -321,7 +331,7 @@ static void s_chain_callback_notify(void * a_arg, dap_chain_t *a_chain, dap_chai
                 log_it(L_DEBUG,"Can't get stream_ch for id='%c' ", l_ch_id);
                 continue;
             }
-            dap_stream_ch_chain_pkt_write(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_CHAIN, l_net->pub.id,
+            dap_stream_ch_chain_pkt_write_unsafe(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_CHAIN, l_net->pub.id,
                                           a_chain->id, a_id, a_atom, a_atom_size);
         }
     }
@@ -385,10 +395,10 @@ static int s_net_states_proc(dap_chain_net_t * l_net)
                 case NODE_ROLE_ARCHIVE:
                 case NODE_ROLE_CELL_MASTER: {
                     // Add other root nodes as synchronization links
-                    while (dap_list_length(l_pvt_net->links_info) < s_max_links_count) {
-                        int i = rand() % l_pvt_net->seed_aliases_count;
+                    for (int i = 0; i < MIN(s_max_links_count, l_pvt_net->seed_aliases_count); i++) {
                         dap_chain_node_addr_t *l_link_addr = dap_chain_node_alias_find(l_net, l_pvt_net->seed_aliases[i]);
-                        dap_chain_node_info_read(l_net, l_link_addr);
+                        dap_chain_node_info_t *l_link_node_info = dap_chain_node_info_read(l_net, l_link_addr);
+                        l_pvt_net->links_info = dap_list_append(l_pvt_net->links_info, l_link_node_info);
                     }
                 } break;
                 case NODE_ROLE_FULL:
@@ -467,6 +477,7 @@ static int s_net_states_proc(dap_chain_net_t * l_net)
                     l_pvt_net->links = dap_list_remove(l_pvt_net->links, l_node_client);
                     continue;
                 }
+                dap_stream_worker_t *l_worker = dap_client_get_stream_worker(l_node_client->client);
                 dap_stream_ch_chain_sync_request_t l_sync_gdb = {};
                 // Get last timestamp in log
                 l_sync_gdb.id_start = (uint64_t) dap_db_log_get_last_id_remote(l_node_client->remote_node_addr.uint64);
@@ -480,17 +491,16 @@ static int s_net_states_proc(dap_chain_net_t * l_net)
                 // find dap_chain_id_t
                 dap_chain_t *l_chain = dap_chain_net_get_chain_by_name(l_net, "gdb");
                 dap_chain_id_t l_chain_id = l_chain ? l_chain->id : (dap_chain_id_t ) {};
-
-                size_t l_res = dap_stream_ch_chain_pkt_write(dap_client_get_stream_ch(l_node_client->client, dap_stream_ch_chain_get_id()),
-                                                            DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB, l_net->pub.id, l_chain_id,
-                                                            l_net->pub.cell_id, &l_sync_gdb, sizeof(l_sync_gdb));
+                l_node_client->state = NODE_CLIENT_STATE_CONNECTED;
+                size_t l_res = dap_stream_ch_chain_pkt_write_mt(l_worker, l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB, l_net->pub.id,
+                                                                l_chain_id, l_net->pub.cell_id, &l_sync_gdb, sizeof(l_sync_gdb));
                 if (l_res == 0) {
                     log_it(L_WARNING, "Can't send GDB sync request");
                     continue;
                 }
 
                 // wait for finishing of request
-                int timeout_ms = 300000; // 5 min = 300 sec = 300 000 ms
+                int timeout_ms = 30000; // 5 min = 300 sec = 300 000 ms
                 // TODO add progress info to console
                 l_res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_SYNCED, timeout_ms);
                 switch (l_res) {
@@ -503,21 +513,19 @@ static int s_net_states_proc(dap_chain_net_t * l_net)
                 default:
                     log_it(L_INFO, "Node sync error %d",l_res);
                 }
-                if (!dap_client_get_stream_ch(l_node_client->client, dap_stream_ch_chain_get_id())) {
-                    l_res = dap_stream_ch_chain_pkt_write(dap_client_get_stream_ch(l_node_client->client, dap_stream_ch_chain_get_id()),
-                                                          DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB_RVRS, l_net->pub.id, l_chain_id,
-                                                          l_net->pub.cell_id, &l_sync_gdb, sizeof(l_sync_gdb));
-                    l_res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_SYNCED, timeout_ms);
-                    switch (l_res) {
-                    case -1:
-                        log_it(L_WARNING,"Timeout with link sync");
-                        break;
-                    case 0:
-                        log_it(L_INFO, "Node sync completed");
-                        break;
-                    default:
-                        log_it(L_INFO, "Node sync error %d",l_res);
-                    }
+                l_node_client->state = NODE_CLIENT_STATE_CONNECTED;
+                l_res = dap_stream_ch_chain_pkt_write_mt(l_worker, l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB_RVRS, l_net->pub.id,
+                                                         l_chain_id, l_net->pub.cell_id, &l_sync_gdb, sizeof(l_sync_gdb));
+                l_res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_SYNCED, timeout_ms);
+                switch (l_res) {
+                case -1:
+                    log_it(L_WARNING, "Timeout with reverse link sync");
+                    break;
+                case 0:
+                    log_it(L_INFO, "Node reverse sync completed");
+                    break;
+                default:
+                    log_it(L_INFO, "Node reverse sync error %d",l_res);
                 }
                 l_tmp = dap_list_next(l_tmp);
             }
@@ -543,52 +551,50 @@ static int s_net_states_proc(dap_chain_net_t * l_net)
                     l_pvt_net->links = dap_list_remove(l_pvt_net->links, l_node_client);
                     continue;
                 }
+                dap_stream_worker_t *l_worker = dap_client_get_stream_worker(l_node_client->client);
                 dap_chain_t * l_chain = NULL;
                 int l_res = 0;
                 DL_FOREACH (l_net->pub.chains, l_chain) {
                     l_node_client->state = NODE_CLIENT_STATE_CONNECTED;
                     dap_stream_ch_chain_sync_request_t l_request ;
                     memset(&l_request, 0, sizeof (l_request));
-                    dap_stream_ch_chain_pkt_write(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_CHAINS, l_net->pub.id,
-                                                  l_chain->id, l_net->pub.cell_id, &l_request, sizeof(l_request));
+                    dap_stream_ch_chain_pkt_write_mt(l_worker, l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_CHAINS, l_net->pub.id,
+                                                     l_chain->id, l_net->pub.cell_id, &l_request, sizeof(l_request));
                     // wait for finishing of request
-                    int timeout_ms = 120000; // 2 min = 120 sec = 120 000 ms
-                    // TODO add progress info to console
-                    if (dap_client_get_stream_ch(l_node_client->client, dap_stream_ch_chain_get_id())) {
-                        l_res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_SYNCED, timeout_ms);
-                        switch (l_res) {
-                        case -1:
-                            log_it(L_WARNING,"Timeout with sync of chain '%s' ", l_chain->name);
-                            break;
-                        case 0:
-                            l_need_flush = true;
-                            log_it(L_INFO, "Sync of chain '%s' completed ", l_chain->name);
-                            break;
-                        default:
-                            log_it(L_ERROR, "Sync of chain '%s' error %d", l_chain->name,l_res);
-                        }
+                    int timeout_ms = 20000; // 2 min = 120 sec = 120 000 ms
+                    // TODO add progress info to console                      
+                    l_res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_SYNCED, timeout_ms);
+                    switch (l_res) {
+                    case -1:
+                        log_it(L_WARNING,"Timeout with sync of chain '%s' ", l_chain->name);
+                        break;
+                    case 0:
+                        l_need_flush = true;
+                        log_it(L_INFO, "Sync of chain '%s' completed ", l_chain->name);
+                        break;
+                    default:
+                        log_it(L_ERROR, "Sync of chain '%s' error %d", l_chain->name,l_res);
                     }
-                    if (dap_client_get_stream_ch(l_node_client->client, dap_stream_ch_chain_get_id())) {
-                        dap_stream_ch_chain_pkt_write(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_CHAINS_RVRS, l_net->pub.id,
-                                                      l_chain->id, l_net->pub.cell_id, &l_request, sizeof(l_request));
-                        l_res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_SYNCED, timeout_ms);
-                        switch (l_res) {
-                        case -1:
-                            log_it(L_WARNING,"Timeout with reverse sync of chain '%s' ", l_chain->name);
-                            break;
-                        case 0:
-                            l_need_flush = true;
-                            log_it(L_INFO, "Reverse sync of chain '%s' completed ", l_chain->name);
-                            // set time of last sync
-                            {
-                                struct timespec l_to;
-                                clock_gettime(CLOCK_MONOTONIC, &l_to);
-                                l_pvt_net->last_sync = l_to.tv_sec;
-                            }
-                            break;
-                        default:
-                            log_it(L_ERROR, "Reverse sync of chain '%s' error %d", l_chain->name,l_res);
+                    l_node_client->state = NODE_CLIENT_STATE_CONNECTED;
+                    dap_stream_ch_chain_pkt_write_mt(l_worker, l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_CHAINS_RVRS, l_net->pub.id,
+                                                     l_chain->id, l_net->pub.cell_id, &l_request, sizeof(l_request));
+                    l_res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_SYNCED, timeout_ms);
+                    switch (l_res) {
+                    case -1:
+                        log_it(L_WARNING,"Timeout with reverse sync of chain '%s' ", l_chain->name);
+                        break;
+                    case 0:
+                        l_need_flush = true;
+                        log_it(L_INFO, "Reverse sync of chain '%s' completed ", l_chain->name);
+                        // set time of last sync
+                        {
+                            struct timespec l_to;
+                            clock_gettime(CLOCK_MONOTONIC, &l_to);
+                            l_pvt_net->last_sync = l_to.tv_sec;
                         }
+                        break;
+                    default:
+                        log_it(L_ERROR, "Reverse sync of chain '%s' error %d", l_chain->name,l_res);
                     }
                 }
                 l_tmp = dap_list_next(l_tmp);
@@ -761,8 +767,7 @@ static dap_chain_net_t *s_net_new(const char * a_id, const char * a_name ,
     PVT(ret)->state_proc_cond = CreateEventA( NULL, FALSE, FALSE, NULL );
 #endif
 
-    //    if ( sscanf(a_id,"0x%016lx", &ret->pub.id.uint64 ) == 1 ){
-    if ( sscanf(a_id,"0x%016llx", &ret->pub.id.uint64 ) == 1 ){
+    if ( sscanf(a_id,"0x%016lx", &ret->pub.id.uint64 ) == 1 ){
         if (strcmp (a_node_role, "root_master")==0){
             PVT(ret)->node_role.enums = NODE_ROLE_ROOT_MASTER;
             log_it (L_NOTICE, "Node role \"root master\" selected");
@@ -895,7 +900,7 @@ void dap_chain_net_load_all()
 }
 
 void s_set_reply_text_node_status(char **a_str_reply, dap_chain_net_t * a_net){
-    const char* l_node_address_text_block = NULL;
+    char* l_node_address_text_block = NULL;
     dap_chain_node_addr_t l_cur_node_addr = { 0 };
     l_cur_node_addr.uint64 = dap_chain_net_get_cur_addr(a_net) ? dap_chain_net_get_cur_addr(a_net)->uint64 : dap_db_get_cur_node_addr(a_net->pub.name);
     if(!l_cur_node_addr.uint64)
@@ -903,7 +908,7 @@ void s_set_reply_text_node_status(char **a_str_reply, dap_chain_net_t * a_net){
     else
         l_node_address_text_block = dap_strdup_printf(", cur node address " NODE_ADDR_FP_STR,NODE_ADDR_FP_ARGS_S(l_cur_node_addr));
 
-    const char* l_sync_current_link_text_block = NULL;
+    char* l_sync_current_link_text_block = NULL;
     if(PVT(a_net)->state == NET_STATE_LINKS_PREPARE ||
        PVT(a_net)->state == NET_STATE_LINKS_CONNECTING ||
        PVT(a_net)->state == NET_STATE_SYNC_GDB ||
@@ -1534,7 +1539,7 @@ int s_net_load(const char * a_net_name, uint16_t a_acl_idx)
             else{
                 l_node_addr = DAP_NEW_Z(dap_chain_node_addr_t);
                 bool parse_succesfully = false;
-                if ( sscanf(l_node_addr_str, "0x%016llx",&l_node_addr->uint64 ) == 1 ){
+                if ( sscanf(l_node_addr_str, "0x%016" DAP_UINT64_FORMAT_x ,&l_node_addr->uint64 ) == 1 ){
                     log_it(L_DEBUG, "Parse node address with format 0x016llx");
                     parse_succesfully = true;
                 }
@@ -1688,7 +1693,7 @@ int s_net_load(const char * a_net_name, uint16_t a_acl_idx)
                 char ** l_proc_chains = dap_config_get_array_str(l_cfg,"role-master" , "proc_chains", &l_proc_chains_count );
                 for ( size_t i = 0; i< l_proc_chains_count ; i++){
                     dap_chain_id_t l_chain_id = {{0}};
-                    if(dap_sscanf( l_proc_chains[i], "0x%16lX",  &l_chain_id.uint64) ==1 || dap_scanf("0x%16lx",  &l_chain_id.uint64) == 1){
+                    if(dap_sscanf( l_proc_chains[i], "0x%16"DAP_UINT64_FORMAT_X,  &l_chain_id.uint64) ==1 || dap_scanf("0x%16"DAP_UINT64_FORMAT_x,  &l_chain_id.uint64) == 1){
                         dap_chain_t * l_chain = dap_chain_find_by_id(l_net->pub.id, l_chain_id );
                         if ( l_chain ){
                             l_chain->is_datum_pool_proc = true;
diff --git a/modules/net/dap_chain_node.c b/modules/net/dap_chain_node.c
index 749937380ec332edeabf35a7b4b59ca6087787c6..22484d478b6ae9870866abafc8c1b1719b48faba 100644
--- a/modules/net/dap_chain_node.c
+++ b/modules/net/dap_chain_node.c
@@ -239,53 +239,38 @@ dap_chain_node_info_t* dap_chain_node_info_read( dap_chain_net_t * a_net,dap_cha
     return node_info;
 }*/
 
-int dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_node_role_t a_role)
+bool dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_node_role_t a_role, dap_chain_datum_t *a_datum)
 {
-    char *l_gdb_group_mempool = NULL;
-    if (!a_chain) {
-        return -1;
+    bool l_need_process = false;
+    for (uint16_t j = 0; j < a_chain->autoproc_datum_types_count; j++) {
+        if (a_datum->header.type_id == a_chain->autoproc_datum_types[j]) {
+            l_need_process = true;
+            break;
+        }
     }
-    l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool(a_chain);
-    size_t l_objs_size = 0;
-    dap_global_db_obj_t *l_objs = dap_chain_global_db_gr_load(l_gdb_group_mempool, &l_objs_size);
-    if (l_objs_size) {
-        for (size_t i = 0; i < l_objs_size; i++) {
-            dap_chain_datum_t *l_datum = (dap_chain_datum_t *)l_objs[i].value;
-            bool l_need_process = false;
-            for (uint16_t j = 0; j < a_chain->autoproc_datum_types_count; j++) {
-                if (l_datum->header.type_id == a_chain->autoproc_datum_types[j]) {
-                    l_need_process = true;
-                    break;
-                }
+    if (!l_need_process)
+        return false;
+    if (a_datum->header.type_id == DAP_CHAIN_DATUM_TX) {
+        dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)a_datum->data;
+        dap_chain_tx_in_t *l_tx_in = (dap_chain_tx_in_t *)dap_chain_datum_tx_item_get(l_tx, NULL, TX_ITEM_TYPE_IN, NULL);
+        // Is not it a base transaction?
+        if (l_tx_in && !dap_hash_fast_is_blank(&l_tx_in->header.tx_prev_hash)) {
+            if (a_role.enums == NODE_ROLE_ROOT) {
+                return false;
             }
-            if (!l_need_process)
-                continue;
-            if (l_datum->header.type_id == DAP_CHAIN_DATUM_TX) {
-                dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_datum->data;
-                dap_chain_tx_in_t *l_tx_in = (dap_chain_tx_in_t *)dap_chain_datum_tx_item_get(l_tx, NULL, TX_ITEM_TYPE_IN, NULL);
-                // Is not it a base transaction?
-                if (l_tx_in && !dap_hash_fast_is_blank(&l_tx_in->header.tx_prev_hash)) {
-                    if (a_role.enums == NODE_ROLE_ROOT) {
-                        continue;
-                    }
-                }
-            }
-            if (a_chain->callback_datums_pool_proc(a_chain, &l_datum, 1) != 1) {
-                continue;
-            } // Delete processed objects
-            dap_chain_global_db_gr_del(dap_strdup(l_objs[i].key), l_gdb_group_mempool);
         }
-        dap_chain_global_db_objs_delete(l_objs, l_objs_size);
     }
-    DAP_DELETE(l_gdb_group_mempool);
-    return 0;
+    if (a_chain->callback_datums_pool_proc(a_chain, &a_datum, 1) != 1) {
+        return false;
+    }
+    return true;
 }
 
-void dap_chain_node_mempool_periodic(void *a_param)
+static bool s_mempool_auto = false;
+
+bool dap_chain_node_mempool_autoproc_init()
 {
-    UNUSED(a_param);
     uint16_t l_net_count;
-    bool l_mempool_auto;
     bool l_mempool_auto_default = false;
     dap_chain_net_t **l_net_list = dap_chain_net_list(&l_net_count);
     for (uint16_t i = 0; i < l_net_count; i++) {
@@ -299,44 +284,67 @@ void dap_chain_node_mempool_periodic(void *a_param)
                 l_mempool_auto_default = true;
                 break;
             default:
-                l_mempool_auto_default = false;
+                break;
         }
-
-        l_mempool_auto = dap_config_get_item_bool_default(g_config, "mempool", "auto_proc", l_mempool_auto_default);
-        if (l_mempool_auto) {
+        s_mempool_auto = dap_config_get_item_bool_default(g_config, "mempool", "auto_proc", l_mempool_auto_default);
+        if (s_mempool_auto) {
             dap_chain_t *l_chain;
             DL_FOREACH(l_net_list[i]->pub.chains, l_chain) {
-                dap_chain_node_mempool_process(l_chain, l_role);
+                if (!l_chain) {
+                    continue;
+                }
+                char *l_gdb_group_mempool = NULL;
+                l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool(l_chain);
+                size_t l_objs_size = 0;
+                dap_global_db_obj_t *l_objs = dap_chain_global_db_gr_load(l_gdb_group_mempool, &l_objs_size);
+                if (l_objs_size) {
+                    for (size_t i = 0; i < l_objs_size; i++) {
+                        dap_chain_datum_t *l_datum = (dap_chain_datum_t *)l_objs[i].value;
+                        if (dap_chain_node_mempool_process(l_chain, l_role, l_datum)) {
+                            // Delete processed objects
+                            dap_chain_global_db_gr_del(dap_strdup(l_objs[i].key), l_gdb_group_mempool);
+                        }
+                    }
+                    dap_chain_global_db_objs_delete(l_objs, l_objs_size);
+                }
+                DAP_DELETE(l_gdb_group_mempool);
             }
         }
     }
     DAP_DELETE(l_net_list);
+    return s_mempool_auto;
 }
 
-static void *s_mempool_timer = NULL;
-
 /**
- * @brief dap_chain_node_mempool_init
- * @return
+ * @brief dap_chain_node_mempool_deinit
  */
-int dap_chain_node_mempool_init()
+void dap_chain_node_mempool_autoproc_deinit()
 {
-    s_mempool_timer = dap_interval_timer_create(DAP_CHAIN_NODE_MEMPOOL_INTERVAL, dap_chain_node_mempool_periodic, 0);
-    if (s_mempool_timer) {
-        return 0;
-    } else {
-        return -1;
-    }
+    s_mempool_auto = false;
 }
 
-/**
- * @brief dap_chain_node_mempool_deinit
- */
-void dap_chain_node_mempool_deinit()
+void dap_chain_node_mempool_autoproc_notify(void *a_arg, const char a_op_code, const char *a_prefix, const char *a_group,
+                                             const char *a_key, const void *a_value, const size_t a_value_len)
 {
-    if (s_mempool_timer) {
-        dap_interval_timer_delete(s_mempool_timer);
-        s_mempool_timer = NULL;
+    UNUSED(a_prefix);
+    UNUSED(a_value_len);
+    if (!a_arg || !a_value || !s_mempool_auto || a_op_code != 'a') {
+        return;
+    }
+    dap_chain_net_t *l_net = (dap_chain_net_t *)a_arg;
+    dap_chain_t *l_chain;
+    DL_FOREACH(l_net->pub.chains, l_chain) {
+        if (!l_chain) {
+            continue;
+        }
+        char *l_gdb_group_str = dap_chain_net_get_gdb_group_mempool(l_chain);
+        if (!strcmp(a_group, l_gdb_group_str)) {
+            dap_chain_datum_t *l_datum = (dap_chain_datum_t *)a_value;
+            dap_chain_node_role_t l_role = dap_chain_net_get_role(l_net);
+            if (dap_chain_node_mempool_process(l_chain, l_role, l_datum)) {
+                dap_chain_global_db_gr_del(dap_strdup(a_key), l_gdb_group_str);
+            }
+        }
+        DAP_DELETE(l_gdb_group_str);
     }
 }
-
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index 15eb060d90b8c5b8ade107eeafef3099889df408..6c3f58918094a1439dc9d335ea7d3d682f56caec 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -1098,7 +1098,7 @@ int com_node(int a_argc, char ** a_argv, void *arg_func, char **a_str_reply)
                 DAP_DELETE(l_remote_node_info);
                 return -1;*/
             }
-            /*                if(0 == dap_stream_ch_chain_pkt_write(l_ch_chain, DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_NODE_ADDR_REQUEST,
+            /*                if(0 == dap_stream_ch_chain_pkt_write_unsafe(l_ch_chain, DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_NODE_ADDR_REQUEST,
              l_net->pub.id, l_chain_id_null, l_chain_cell_id_null, &l_sync_request,
              sizeof(l_sync_request))) {
              dap_chain_node_cli_set_reply_text(a_str_reply, "Error: Cant send sync chains request");
@@ -1130,7 +1130,7 @@ int com_node(int a_argc, char ** a_argv, void *arg_func, char **a_str_reply)
         //l_s_ch_chain->request_cell_id.uint64 = l_chain_cell_id_null.uint64;
         //memcpy(&l_s_ch_chain->request, &l_sync_request, sizeof(l_sync_request));
 
-        if(0 == dap_stream_ch_chain_pkt_write(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB,
+        if(0 == dap_stream_ch_chain_pkt_write_unsafe(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB,
                 l_net->pub.id, l_chain_id_null, l_chain_cell_id_null, &l_sync_request,
                 sizeof(l_sync_request))) {
             dap_chain_node_cli_set_reply_text(a_str_reply, "Error: Can't send sync chains request");
@@ -1139,7 +1139,7 @@ int com_node(int a_argc, char ** a_argv, void *arg_func, char **a_str_reply)
             DAP_DELETE(l_remote_node_info);
             return -1;
         }
-        dap_stream_ch_set_ready_to_write(l_ch_chain, true);
+        dap_stream_ch_set_ready_to_write_unsafe(l_ch_chain, true);
         // wait for finishing of request
         int timeout_ms = 420000; // 7 min = 420 sec = 420 000 ms
         // TODO add progress info to console
@@ -1165,7 +1165,7 @@ int com_node(int a_argc, char ** a_argv, void *arg_func, char **a_str_reply)
             l_node_client->state = NODE_CLIENT_STATE_CONNECTED;
             // send request
             dap_stream_ch_chain_sync_request_t l_sync_request = { { 0 } };
-            if(0 == dap_stream_ch_chain_pkt_write(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_CHAINS,
+            if(0 == dap_stream_ch_chain_pkt_write_unsafe(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_CHAINS,
                     l_net->pub.id, l_chain->id, l_remote_node_info->hdr.cell_id, &l_sync_request,
                     sizeof(l_sync_request))) {
                 dap_chain_node_cli_set_reply_text(a_str_reply, "Error: Can't send sync chains request");
@@ -1176,7 +1176,7 @@ int com_node(int a_argc, char ** a_argv, void *arg_func, char **a_str_reply)
                 return -3;
             }
             log_it(L_NOTICE, "Requested syncronization for chain \"%s\"", l_chain->name);
-            dap_stream_ch_set_ready_to_write(l_ch_chain, true);
+            dap_stream_ch_set_ready_to_write_unsafe(l_ch_chain, true);
 
             // wait for finishing of request
             timeout_ms = 120000; // 2 min = 120 sec = 120 000 ms
@@ -2001,7 +2001,7 @@ int com_token_decl_sign(int argc, char ** argv, void *arg_func, char ** a_str_re
     }
 }
 
-void s_com_mempool_list_print_for_chain(const dap_chain_net_t * a_net, const dap_chain_t * a_chain, dap_string_t * a_str_tmp, const char *a_hash_out_type){
+void s_com_mempool_list_print_for_chain(dap_chain_net_t * a_net, dap_chain_t * a_chain, dap_string_t * a_str_tmp, const char *a_hash_out_type){
     char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool(a_chain);
     if(!l_gdb_group_mempool){
         dap_string_append_printf(a_str_tmp, "%s.%s: chain not found\n", a_net->pub.name, a_chain->name);
diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c
index c34c4e7e817e7b5ea945fdadd717d4e4b9c8a01a..7838fc19203efa50aca9f8872f2f8f8d41a798e5 100644
--- a/modules/net/dap_chain_node_cli_cmd_tx.c
+++ b/modules/net/dap_chain_node_cli_cmd_tx.c
@@ -94,15 +94,14 @@ char* dap_db_history_tx(dap_chain_hash_fast_t* a_tx_hash, dap_chain_t * a_chain,
     dap_tx_data_t *l_tx_data_hash = NULL;
     // load transactions
     dap_chain_atom_iter_t *l_atom_iter = a_chain->callback_atom_iter_create(a_chain);
-    dap_chain_atom_ptr_t *l_atom = a_chain->callback_atom_iter_get_first(l_atom_iter);
-    size_t l_atom_size = a_chain->callback_atom_get_size(l_atom);
+    size_t l_atom_size = 0;
+    dap_chain_atom_ptr_t *l_atom = a_chain->callback_atom_iter_get_first(l_atom_iter, &l_atom_size);
 
     while(l_atom && l_atom_size) {
         dap_chain_datum_t *l_datum = (dap_chain_datum_t*) l_atom;
         if(!l_datum && l_datum->header.type_id != DAP_CHAIN_DATUM_TX) {
             // go to next transaction
-            l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter);
-            l_atom_size = a_chain->callback_atom_get_size(l_atom);
+            l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter, &l_atom_size);
             continue;
         }
         dap_tx_data_t *l_tx_data = NULL;
@@ -181,8 +180,7 @@ char* dap_db_history_tx(dap_chain_hash_fast_t* a_tx_hash, dap_chain_t * a_chain,
         // search tx with a_tx_hash
         if(!dap_hash_fast_compare(a_tx_hash, &l_tx_hash)) {
             // go to next transaction
-            l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter);
-            l_atom_size = a_chain->callback_atom_get_size(l_atom);
+            l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter, &l_atom_size);
             continue;
         }
         // found a_tx_hash now
@@ -200,7 +198,7 @@ char* dap_db_history_tx(dap_chain_hash_fast_t* a_tx_hash, dap_chain_t * a_chain,
         l_list_tmp = l_list_out_items;
         while(l_list_tmp) {
             const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t*) l_list_tmp->data;
-            dap_tx_data_t *l_tx_data_prev = NULL;
+            //dap_tx_data_t *l_tx_data_prev = NULL;
 
             const char *l_token_str = NULL;
             if(l_tx_data)
@@ -311,18 +309,18 @@ char* dap_db_history_addr(dap_chain_addr_t * a_addr, dap_chain_t * a_chain, cons
     dap_tx_data_t *l_tx_data_hash = NULL;
     // load transactions
     dap_chain_atom_iter_t *l_atom_iter = a_chain->callback_atom_iter_create(a_chain);
-    dap_chain_atom_ptr_t *l_atom = a_chain->callback_atom_iter_get_first(l_atom_iter);
+    size_t l_atom_size=0;
+    dap_chain_atom_ptr_t *l_atom = a_chain->callback_atom_iter_get_first(l_atom_iter, &l_atom_size);
     if (!l_atom) {
         return NULL;
     }
-    size_t l_atom_size = a_chain->callback_atom_get_size(l_atom);
 
     while(l_atom && l_atom_size) {
-        dap_chain_datum_t *l_datum = a_chain->callback_atom_get_datum ? a_chain->callback_atom_get_datum(l_atom) : (dap_chain_datum_t*)l_atom;
+        dap_chain_datum_t *l_datum = a_chain->callback_atom_get_datum ? a_chain->callback_atom_get_datum(l_atom, l_atom_size) :
+                                                                        (dap_chain_datum_t*)l_atom;
         if(!l_datum || l_datum->header.type_id != DAP_CHAIN_DATUM_TX) {
             // go to next transaction
-            l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter);
-            l_atom_size = a_chain->callback_atom_get_size(l_atom);
+            l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter, &l_atom_size);
             continue;
         }
         // transaction
@@ -656,8 +654,7 @@ char* dap_db_history_addr(dap_chain_addr_t * a_addr, dap_chain_t * a_chain, cons
         DAP_DELETE(l_time_str);
 
         // go to next transaction
-        l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter);
-        l_atom_size = l_atom ? a_chain->callback_atom_get_size(l_atom) : 0;
+        l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter, &l_atom_size);
     }
 
     // delete hashes
diff --git a/modules/net/dap_chain_node_client.c b/modules/net/dap_chain_node_client.c
index 598041a8475773de9ddbb42254ca7bfdd6619c5a..ce8848a5b700b483664c4b38b216606b78721546 100644
--- a/modules/net/dap_chain_node_client.c
+++ b/modules/net/dap_chain_node_client.c
@@ -50,6 +50,7 @@
 #include "dap_chain_global_db_remote.h"
 #include "dap_chain_global_db_hist.h"
 #include "dap_chain_net_srv_common.h"
+#include "dap_stream_worker.h"
 #include "dap_stream_ch_pkt.h"
 #include "dap_stream_ch_chain.h"
 #include "dap_stream_ch_chain_pkt.h"
@@ -126,6 +127,7 @@ static void s_stage_status_error_callback(dap_client_t *a_client, void *a_arg)
         SetEvent( l_node_client->wait_cond );
 #endif
         pthread_mutex_unlock(&l_node_client->wait_mutex);
+        return;
     }
 
     if(l_node_client && l_node_client->keep_connection &&
@@ -273,127 +275,19 @@ static void s_ch_chain_callback_notify_packet_in(dap_stream_ch_chain_t* a_ch_cha
             l_request = (dap_stream_ch_chain_sync_request_t*) a_pkt->data;
 
         if(l_request) {
-            uint64_t l_id_last_here = 1;
-            // for sync chain not used time
-            //if(a_pkt_type != DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_CHAINS)
-            //    l_id_last_here =(uint64_t) dap_db_log_get_last_id();
-            if(1) {//if(l_request->id_start < l_id_last_here) {
-                log_it(L_INFO, "Remote is synced but we have updates for it");
-                bool l_is_sync = true;
-                // Get log diff
-                if(a_pkt_type == DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB) {
-                    a_ch_chain->request_last_ts = dap_db_log_get_last_id();
-                    uint64_t l_start_item = l_request->id_start;
-                    dap_db_log_list_t *l_db_log = NULL;
-                    // If the current global_db has been truncated, but the remote node has not known this
-                    uint64_t l_last_id = dap_db_log_get_last_id();
-                    if(l_request->id_start > a_ch_chain->request_last_ts){
-                        dap_chain_net_t *l_net = dap_chain_net_by_id(a_pkt->hdr.net_id);
-                        dap_list_t *l_add_groups = dap_chain_net_get_add_gdb_group(l_net, a_ch_chain->request.node_addr);
-                        l_db_log = dap_db_log_list_start(l_start_item + 1, l_add_groups);
-                        if(!l_db_log)
-                            l_start_item = 0;
-                    }
-                    //dap_list_t *l_list = dap_db_log_get_list(l_request->id_start + 1);
-                    if(!l_db_log){
-                        dap_chain_net_t *l_net = dap_chain_net_by_id(a_pkt->hdr.net_id);
-                        dap_list_t *l_add_groups = dap_chain_net_get_add_gdb_group(l_net, a_ch_chain->request.node_addr);
-                        l_db_log = dap_db_log_list_start(l_start_item + 1, l_add_groups);
-                    }
-                    if(l_db_log) {
-                        // Add it to outgoing list
-                        //l_list->prev = a_ch_chain->request_global_db_trs;
-                        a_ch_chain->request_global_db_trs = l_db_log;//l_list;
-                    }
-                    else
-                        l_is_sync = false;
-                }
-                if(l_is_sync) {
-                    a_ch_chain->request_net_id.uint64 = a_pkt->hdr.net_id.uint64;
-                    a_ch_chain->request_cell_id.uint64 = a_pkt->hdr.cell_id.uint64;
-                    a_ch_chain->request_chain_id.uint64 = a_pkt->hdr.chain_id.uint64;
-                    a_ch_chain->state = dap_stream_ch_chain_pkt_type_to_dap_stream_ch_chain_state(a_pkt_type);//CHAIN_STATE_SYNC_CHAINS;//GLOBAL_DB;
-
-                    // type of first packet
-                    uint8_t l_type =
-                            (a_pkt_type != DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_CHAINS) ?
-                                    DAP_STREAM_CH_CHAIN_PKT_TYPE_FIRST_GLOBAL_DB :
-                                    DAP_STREAM_CH_CHAIN_PKT_TYPE_FIRST_CHAIN;
-                    if(l_type == DAP_STREAM_CH_CHAIN_PKT_TYPE_FIRST_CHAIN)
-                    {
-                        dap_chain_t * l_chain = dap_chain_find_by_id(a_pkt->hdr.net_id, a_pkt->hdr.chain_id);
-                        if (l_chain ){
-                            dap_chain_atom_iter_t* l_iter = l_chain ? l_chain->callback_atom_iter_create(l_chain) : NULL;
-                            if ( l_iter ){
-                                //a_ch_chain->request_atom_iter = l_iter;
-
-                                dap_chain_atom_ptr_t * l_lasts = NULL;
-                                size_t l_lasts_size = 0;
-                                l_lasts = l_chain->callback_atom_iter_get_lasts(l_iter, &l_lasts_size);
-                                if ( l_lasts){
-                                    for(size_t i = 0; i < l_lasts_size; i++) {
-                                        dap_chain_atom_item_t * l_item = NULL;
-                                        dap_chain_hash_fast_t l_atom_hash;
-                                        dap_hash_fast(l_lasts[i], l_chain->callback_atom_get_size(l_lasts[i]), &l_atom_hash);
-                                        pthread_mutex_lock(&a_ch_chain->mutex);
-                                        HASH_FIND(hh, a_ch_chain->request_atoms_lasts, &l_atom_hash, sizeof(l_atom_hash), l_item);
-                                        if(l_item == NULL) { // Not found, add new lasts
-                                            l_item = DAP_NEW_Z(dap_chain_atom_item_t);
-                                            l_item->atom = l_lasts[i];
-                                            memcpy(&l_item->atom_hash, &l_atom_hash, sizeof(l_atom_hash));
-                                            HASH_ADD(hh, a_ch_chain->request_atoms_lasts, atom_hash, sizeof(l_atom_hash), l_item);
-                                        }
-                                        //else
-                                        //    DAP_DELETE(l_lasts[i]);
-                                        pthread_mutex_unlock(&a_ch_chain->mutex);
-                                    }
-                                    DAP_DELETE(l_lasts);
-                                }
-                                DAP_DELETE(l_iter);
-                            }else{
-                                log_it(L_ERROR, "Can't create iterator for chain_id 0x%016X", a_pkt->hdr.chain_id );
-                            }
-                        }else {
-                            log_it(L_WARNING, "Can't find chain_id 0x%016X", a_pkt->hdr.chain_id );
-                        }
-                    }
-                    dap_chain_node_addr_t l_node_addr = { 0 };
-                    dap_chain_net_t *l_net = dap_chain_net_by_id(a_ch_chain->request_net_id);
-                    l_node_addr.uint64 = l_net ? dap_db_get_cur_node_addr(l_net->pub.name) : 0;
-                    dap_stream_ch_chain_pkt_write(a_ch_chain->ch, l_type,
-                            a_ch_chain->request_net_id, a_ch_chain->request_chain_id,
-                            a_ch_chain->request_cell_id, &l_node_addr, sizeof(dap_chain_node_addr_t));
-
-                    log_it(L_INFO, "Sync for remote tr type=%d", a_pkt_type);//_count=%d", dap_list_length(l_list));
-                    dap_stream_ch_set_ready_to_write(a_ch_chain->ch, true);
-                }
-                else {
-                    log_it(L_INFO, "Remote node has lastes timestamp for us type=%d", a_pkt_type);
-                    pthread_mutex_lock(&l_node_client->wait_mutex);
-                    l_node_client->state = NODE_CLIENT_STATE_SYNCED;
-#ifndef _WIN32
-                    pthread_cond_signal(&l_node_client->wait_cond);
-#else
-                    SetEvent( l_node_client->wait_cond );
-#endif
-                    pthread_mutex_unlock(&l_node_client->wait_mutex);
-                }
-            }
-        } else {
-            log_it(L_INFO, "Sync notify without request to sync back, stay in SYNCED state");
-            pthread_mutex_lock(&l_node_client->wait_mutex);
-            l_node_client->state = NODE_CLIENT_STATE_SYNCED;
+            // Process it if need
+        }
+        log_it(L_INFO, "Sync notify without request to sync back, stay in SYNCED state");
+        pthread_mutex_lock(&l_node_client->wait_mutex);
+        l_node_client->state = NODE_CLIENT_STATE_SYNCED;
 #ifndef _WIN32
-            pthread_cond_signal(&l_node_client->wait_cond);
+        pthread_cond_signal(&l_node_client->wait_cond);
 #else
-            SetEvent( l_node_client->wait_cond );
+        SetEvent( l_node_client->wait_cond );
 #endif
-            pthread_mutex_unlock(&l_node_client->wait_mutex);
-        }
-
-    }
-    default: {
+        pthread_mutex_unlock(&l_node_client->wait_mutex);
     }
+    default: break;
     }
 }
 
@@ -492,7 +386,7 @@ static void s_ch_chain_callback_notify_packet_R(dap_stream_ch_chain_net_srv_t* a
     switch (a_pkt_type) {
     // get new generated current node address
     case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_RESPONSE: {
-            dap_stream_ch_chain_net_srv_pkt_test_t *l_request = (dap_stream_ch_chain_net_srv_pkt_request_t *) a_pkt->data;
+            dap_stream_ch_chain_net_srv_pkt_test_t *l_request = (dap_stream_ch_chain_net_srv_pkt_test_t *) a_pkt->data;
             size_t l_request_size = l_request->data_size + sizeof(dap_stream_ch_chain_net_srv_pkt_test_t);
             if(a_pkt->hdr.size != l_request_size) {
                 log_it(L_WARNING, "Wrong request size, less or more than required");
@@ -622,13 +516,11 @@ int dap_chain_node_client_send_ch_pkt(dap_chain_node_client_t *a_client, uint8_t
     if(!a_client || a_client->state < NODE_CLIENT_STATE_CONNECTED)
         return -1;
 
-//    dap_stream_t *l_stream = dap_client_get_stream(a_client->client);
+    dap_stream_worker_t *l_stream_worker = dap_client_get_stream_worker(a_client->client);
     dap_stream_ch_t * l_ch = dap_client_get_stream_ch(a_client->client, a_ch_id);
     if(l_ch) {
 //        dap_stream_ch_chain_net_t * l_ch_chain = DAP_STREAM_CH_CHAIN_NET(l_ch);
-
-        dap_stream_ch_pkt_write(l_ch, a_type, a_pkt_data, a_pkt_data_size);
-        dap_stream_ch_set_ready_to_write(l_ch, true);
+        dap_stream_ch_pkt_write_mt(l_stream_worker , l_ch , a_type, a_pkt_data, a_pkt_data_size);
         return 0;
     } else
         return -1;
diff --git a/modules/net/dap_chain_node_ping.c b/modules/net/dap_chain_node_ping.c
index 72c9c0978737881e89c6ee29244a295fcca4b17c..67ab55b30619a724a521050cb7a782deaebb7e17 100644
--- a/modules/net/dap_chain_node_ping.c
+++ b/modules/net/dap_chain_node_ping.c
@@ -24,7 +24,8 @@
 //#include <sys/socket.h>
 #include <time.h>
 #include <errno.h>
-#define _GNU_SOURCE             /* See feature_test_macros(7) */
+#define _GNU_SOURCE
+#define __USE_GNU   /* See feature_test_macros(7) */
 #include <pthread.h>
 
 #include "dap_common.h"
diff --git a/modules/net/dap_dns_server.c b/modules/net/dap_dns_server.c
index 1f000b8a45d37d92528cba78e1f2f4ca0f9e62f3..8c6907d31e1d1cfe2dfce67005a5db4309669fc7 100644
--- a/modules/net/dap_dns_server.c
+++ b/modules/net/dap_dns_server.c
@@ -26,7 +26,7 @@
 #include "dap_dns_server.h"
 #include "dap_udp_server.h"
 #include "dap_udp_client.h"
-#include "dap_client_remote.h"
+#include "dap_events_socket.h"
 #include "dap_common.h"
 #include "dap_chain_net.h"
 #include "dap_chain_node.h"
@@ -191,7 +191,7 @@ dap_dns_zone_callback_t dap_dns_zone_find(char *hostname) {
  * @param arg Unused
  * @return none
  */
-void dap_dns_client_read(dap_client_remote_t *client, void * arg) {
+void dap_dns_client_read(dap_events_socket_t *client, void * arg) {
     UNUSED(arg);
     if (client->buf_in_size < DNS_HEADER_SIZE) {        // Bad request
         return;
@@ -200,7 +200,7 @@ void dap_dns_client_read(dap_client_remote_t *client, void * arg) {
     dap_dns_buf_t *dns_reply = DAP_NEW(dap_dns_buf_t);
     dns_message->data = DAP_NEW_SIZE(char, client->buf_in_size + 1);
     dns_message->data[client->buf_in_size] = 0;
-    dap_client_remote_read(client, dns_message->data, client->buf_in_size);
+    dap_events_socket_pop_from_buf_in(client, dns_message->data, client->buf_in_size);
     dns_message->ptr = 0;
 
     // Parse incoming DNS message
@@ -332,8 +332,8 @@ void dap_dns_client_read(dap_client_remote_t *client, void * arg) {
     dns_reply->data[2] = msg_flags.val >> 8;
     dns_reply->data[3] = msg_flags.val;
     // Send DNS reply
-    dap_udp_client_write(client, dns_reply->data, dns_reply->ptr);
-    dap_udp_client_ready_to_write(client, true);
+    dap_events_socket_write_unsafe( client, dns_reply->data, dns_reply->ptr);
+    dap_events_socket_set_writable_unsafe( client, true);
     dap_string_free(dns_hostname, true);
 cleanup:
     DAP_DELETE(dns_reply->data);
@@ -351,10 +351,10 @@ void dap_dns_server_start() {
         log_it(L_ERROR, "Can't start DNS server");
         return;
     }
-    s_dns_server->instance->client_read_callback = dap_dns_client_read;
-    s_dns_server->instance->client_write_callback = NULL;
-    s_dns_server->instance->client_new_callback = NULL;
-    s_dns_server->instance->client_delete_callback = NULL;
+    s_dns_server->instance->client_callbacks.read_callback = dap_dns_client_read;
+    s_dns_server->instance->client_callbacks.write_callback = NULL;
+    s_dns_server->instance->client_callbacks.new_callback = NULL;
+    s_dns_server->instance->client_callbacks.delete_callback = NULL;
     dap_dns_zone_register(&s_root_alias[0], dap_dns_resolve_hostname);  // root resolver
     pthread_create(&s_dns_server->udp_thread, NULL, (void *)dap_udp_server_loop, s_dns_server->instance);
 }
diff --git a/modules/net/include/dap_chain_node.h b/modules/net/include/dap_chain_node.h
index 78931e2864782a8b0b015598f505bda2635dc3b0..0277aefb71f3b59b11f3e64c2ad20cb77556bdd0 100644
--- a/modules/net/include/dap_chain_node.h
+++ b/modules/net/include/dap_chain_node.h
@@ -141,6 +141,8 @@ inline static char* dap_chain_node_addr_to_hash_str(dap_chain_node_addr_t *addre
     return a_key;
 }
 
-int dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_node_role_t a_role);
-int dap_chain_node_mempool_init();
-void dap_chain_node_mempool_deinit();
+bool dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_node_role_t a_role, dap_chain_datum_t *a_datum);
+bool dap_chain_node_mempool_autoproc_init();
+void dap_chain_node_mempool_autoproc_deinit();
+void dap_chain_node_mempool_autoproc_notify(void *a_arg, const char a_op_code, const char *a_prefix, const char *a_group,
+                                             const char *a_key, const void *a_value, const size_t a_value_len);
diff --git a/modules/net/srv/dap_chain_net_srv_client.c b/modules/net/srv/dap_chain_net_srv_client.c
index c9f43454f35b06cfe2e9e6b5e58bb4337d21ae66..595a2802107b989c6d0c02a0a9c5a4d27b07934e 100644
--- a/modules/net/srv/dap_chain_net_srv_client.c
+++ b/modules/net/srv/dap_chain_net_srv_client.c
@@ -42,7 +42,7 @@ int dap_chain_net_srv_client_init(dap_chain_net_srv_uid_t a_uid,
         dap_chain_net_srv_callback_data_t a_callback_response_error,
         dap_chain_net_srv_callback_data_t a_callback_receipt_next_success,
         dap_chain_net_srv_callback_data_t a_callback_client_success,
-        dap_chain_net_srv_callback_data_t a_callback_client_sign_request,
+        dap_chain_net_srv_callback_sign_request_t a_callback_client_sign_request,
         void *a_inhertor) {
 
     dap_chain_net_srv_t *l_srv_custom = dap_chain_net_srv_get(a_uid);
diff --git a/modules/net/srv/dap_chain_net_srv_order.c b/modules/net/srv/dap_chain_net_srv_order.c
index 948ec9a6d09a74172d4f099fd38fac44fb9d430a..8aba700a30215b038b580b8d0ee49744bd6684e3 100644
--- a/modules/net/srv/dap_chain_net_srv_order.c
+++ b/modules/net/srv/dap_chain_net_srv_order.c
@@ -514,10 +514,9 @@ void dap_chain_net_srv_order_dump_to_string(dap_chain_net_srv_order_t *a_order,d
 static void s_srv_order_callback_notify(void *a_arg, const char a_op_code, const char *a_prefix, const char *a_group,
                                    const char *a_key, const void *a_value, const size_t a_value_len)
 {
-    (void) a_op_code;
     UNUSED(a_prefix);
     UNUSED(a_value_len);
-    if (!a_arg || !a_value || !dap_config_get_item_bool_default(g_config, "srv", "order_signed_only", false)) {
+    if (!a_arg || !a_value || a_op_code != 'a' || !dap_config_get_item_bool_default(g_config, "srv", "order_signed_only", false)) {
         return;
     }
     dap_chain_net_t *l_net = (dap_chain_net_t *)a_arg;
diff --git a/modules/net/srv/dap_chain_net_srv_stream_session.c b/modules/net/srv/dap_chain_net_srv_stream_session.c
index f5f1517b0e884fc9ccb8dd4f6cc3e5c927a08d7b..d5a20c27358fd4bc42af90c283ecc85aa18d4c37 100644
--- a/modules/net/srv/dap_chain_net_srv_stream_session.c
+++ b/modules/net/srv/dap_chain_net_srv_stream_session.c
@@ -86,8 +86,8 @@ void dap_chain_net_srv_usage_delete (dap_chain_net_srv_stream_session_t * a_srv_
 {
     if ( a_usage->receipt )
         DAP_DELETE( a_usage->receipt );
-    if ( a_usage->clients ){
-        for (dap_chain_net_srv_client_t * l_srv_client = a_usage->clients, * tmp = NULL; l_srv_client; ){
+    if ( a_usage->client ){
+        for (dap_chain_net_srv_client_t * l_srv_client = a_usage->client, * tmp = NULL; l_srv_client; ){
             tmp = l_srv_client;
             l_srv_client = l_srv_client->next;
             DAP_DELETE( tmp);
@@ -107,12 +107,10 @@ void dap_chain_net_srv_usage_delete (dap_chain_net_srv_stream_session_t * a_srv_
  * @param a_usage_id
  * @return
  */
-dap_chain_net_srv_usage_t* dap_chain_net_srv_usage_find (dap_chain_net_srv_stream_session_t * a_srv_session,
+dap_chain_net_srv_usage_t* dap_chain_net_srv_usage_find_unsafe (dap_chain_net_srv_stream_session_t * a_srv_session,
                                                                              uint32_t a_usage_id)
 {
     dap_chain_net_srv_usage_t * l_ret = NULL;
-    pthread_mutex_lock(&a_srv_session->parent->mutex);
     HASH_FIND_INT(a_srv_session->usages, &a_usage_id, l_ret);
-    pthread_mutex_unlock(&a_srv_session->parent->mutex);
     return  l_ret;
 }
diff --git a/modules/net/srv/include/dap_chain_net_srv.h b/modules/net/srv/include/dap_chain_net_srv.h
index 4673bff67e3f8f40ad79a4e242221446feb59792..c7de7e8f0c988d173597e837c08dffc02c2ad979 100755
--- a/modules/net/srv/include/dap_chain_net_srv.h
+++ b/modules/net/srv/include/dap_chain_net_srv.h
@@ -33,6 +33,7 @@ typedef struct dap_chain_net_srv dap_chain_net_srv_t;
 
 typedef void (*dap_chain_net_srv_callback_t)(dap_chain_net_srv_t *, dap_chain_net_srv_client_t *);
 typedef int (*dap_chain_net_srv_callback_data_t)(dap_chain_net_srv_t *, uint32_t, dap_chain_net_srv_client_t *, const void *, size_t );
+typedef int (*dap_chain_net_srv_callback_sign_request_t)(dap_chain_net_srv_t *, uint32_t, dap_chain_net_srv_client_t *, dap_chain_datum_tx_receipt_t **, size_t );
 typedef void (*dap_chain_net_srv_callback_ch_t)(dap_chain_net_srv_t *, dap_stream_ch_t *);
 
 typedef struct dap_chain_net_srv
@@ -63,7 +64,7 @@ typedef struct dap_chain_net_srv
     // Client have to start service
     dap_chain_net_srv_callback_data_t callback_client_success;
     // Client have to sign receipt
-    dap_chain_net_srv_callback_data_t callback_client_sign_request;
+    dap_chain_net_srv_callback_sign_request_t callback_client_sign_request;
 
     // Pointer to inheritor object
     void * _inhertor;
@@ -108,5 +109,5 @@ int dap_chain_net_srv_client_init(dap_chain_net_srv_uid_t a_uid,
         dap_chain_net_srv_callback_data_t a_callback_response_error,
         dap_chain_net_srv_callback_data_t a_callback_receipt_next_success,
         dap_chain_net_srv_callback_data_t a_callback_client_success,
-        dap_chain_net_srv_callback_data_t a_callback_client_sign_request,
+        dap_chain_net_srv_callback_sign_request_t a_callback_client_sign_request,
         void *a_inhertor);
diff --git a/modules/net/srv/include/dap_chain_net_srv_client.h b/modules/net/srv/include/dap_chain_net_srv_client.h
index d25801c9cfd3d9c06da8269fc9efc1c347074693..724fbccf13e700285620574f3c73da2902fe8e3d 100644
--- a/modules/net/srv/include/dap_chain_net_srv_client.h
+++ b/modules/net/srv/include/dap_chain_net_srv_client.h
@@ -27,14 +27,19 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
 #include <time.h>
 
 
+#include "dap_enc_key.h"
+#include "dap_stream_session.h"
+#include "dap_stream_worker.h"
 #include "dap_chain_net_srv_common.h"
 #include "dap_chain_net_remote.h"
 
 
 typedef struct dap_chain_net_srv_client
 {
+    dap_stream_ch_t * ch; // Use ONLY in own context, not thread-safe
     time_t ts_created;
-    dap_stream_ch_t *ch; // For direct connections
+    dap_stream_worker_t * stream_worker;
+    int session_id;
     dap_chain_net_remote_t *net_remote; // For remotes
     uint64_t bytes_received;
     uint64_t bytes_sent;
diff --git a/modules/net/srv/include/dap_chain_net_srv_common.h b/modules/net/srv/include/dap_chain_net_srv_common.h
index d45ace6791a839ce7019b8b642c7de519b4fc737..d4141c574611305fc4eab2795fd847ef890c03f1 100755
--- a/modules/net/srv/include/dap_chain_net_srv_common.h
+++ b/modules/net/srv/include/dap_chain_net_srv_common.h
@@ -73,7 +73,7 @@ typedef struct dap_chain_net_srv_abstract
     char decription[128];
 }DAP_ALIGN_PACKED dap_chain_net_srv_abstract_t;
 
-typedef void (*dap_chain_callback_trafic_t)(dap_client_remote_t *, dap_stream_ch_t *);
+typedef void (*dap_chain_callback_trafic_t)(dap_events_socket_t *, dap_stream_ch_t *);
 
 typedef struct dap_chain_net_srv_price
 {
diff --git a/modules/net/srv/include/dap_chain_net_srv_stream_session.h b/modules/net/srv/include/dap_chain_net_srv_stream_session.h
index 29c506e8ebf04197184a34d2e42f0b2edf74be42..a47a16c9bc76a751b3c50319430cc69926b5dded 100644
--- a/modules/net/srv/include/dap_chain_net_srv_stream_session.h
+++ b/modules/net/srv/include/dap_chain_net_srv_stream_session.h
@@ -50,7 +50,7 @@ typedef struct dap_chain_net_srv_usage{
     dap_chain_net_srv_price_t * price; // Price for issue next receipt
     size_t receipt_size;
     size_t receipt_next_size;
-    dap_chain_net_srv_client_t * clients;
+    dap_chain_net_srv_client_t * client;
     dap_chain_datum_tx_t * tx_cond;
     dap_chain_hash_fast_t tx_cond_hash;
     char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
@@ -61,15 +61,30 @@ typedef struct dap_chain_net_srv_usage{
 
 typedef void (*dap_response_success_callback_t) (dap_stream_ch_chain_net_srv_pkt_success_t*, void*);
 
+typedef struct dap_net_stats{
+        uintmax_t bytes_sent;
+        uintmax_t bytes_recv;
+        uintmax_t bytes_sent_lost;
+        uintmax_t bytes_recv_lost;
+
+        uintmax_t packets_sent;
+        uintmax_t packets_recv;
+        uintmax_t packets_sent_lost;
+        intmax_t packets_recv_lost;
+} dap_net_stats_t;
+
 typedef struct dap_chain_net_srv_stream_session {
     dap_stream_session_t * parent;
     dap_chain_net_srv_usage_t * usages;
     dap_chain_net_srv_usage_t * usage_active;
 
-    uint128_t limits_bytes; // Bytes left
+    uintmax_t limits_bytes; // Bytes left
     time_t limits_ts; // Timestamp until its activte
     dap_chain_net_srv_price_unit_uid_t limits_units_type;
 
+    // Some common stats
+    volatile dap_net_stats_t stats;
+
     time_t ts_activated;
     dap_sign_t* user_sign; // User's signature for auth if reconnect
 
@@ -85,5 +100,5 @@ dap_chain_net_srv_usage_t* dap_chain_net_srv_usage_add (dap_chain_net_srv_stream
                                                                             dap_chain_net_t * a_net, dap_chain_net_srv_t * a_srv);
 void dap_chain_net_srv_usage_delete (dap_chain_net_srv_stream_session_t * a_srv_session,
                                                                                dap_chain_net_srv_usage_t* a_usage);
-dap_chain_net_srv_usage_t* dap_chain_net_srv_usage_find (dap_chain_net_srv_stream_session_t * a_srv_session,
+dap_chain_net_srv_usage_t* dap_chain_net_srv_usage_find_unsafe (dap_chain_net_srv_stream_session_t * a_srv_session,
                                                                              uint32_t a_usage_id);
diff --git a/modules/service/stake/dap_chain_net_srv_stake.c b/modules/service/stake/dap_chain_net_srv_stake.c
index 77f964178c05dce2c2c742a98c8022ee838aab86..58405ee7720603a91d3c5f580eb47eed537d7ed8 100644
--- a/modules/service/stake/dap_chain_net_srv_stake.c
+++ b/modules/service/stake/dap_chain_net_srv_stake.c
@@ -24,6 +24,7 @@
 
 #include <math.h>
 #include "dap_string.h"
+#include "dap_enc_base58.h"
 #include "dap_chain_common.h"
 #include "dap_chain_node_cli.h"
 #include "dap_chain_mempool.h"
diff --git a/modules/service/vpn/dap_chain_net_srv_vpn.c b/modules/service/vpn/dap_chain_net_srv_vpn.c
index d6e5d5b305ceb7172d3babb326dab09ee94e36aa..aaf563d863221a664b0a72364784bf60975043ec 100644
--- a/modules/service/vpn/dap_chain_net_srv_vpn.c
+++ b/modules/service/vpn/dap_chain_net_srv_vpn.c
@@ -53,7 +53,7 @@
 #include "dap_strfuncs.h"
 #include "dap_config.h"
 
-#include "dap_client_remote.h"
+#include "dap_events_socket.h"
 #include "dap_http_client.h"
 
 #include "dap_stream.h"
@@ -74,58 +74,73 @@
 
 #define LOG_TAG "dap_chain_net_srv_vpn"
 
-#define DAP_TUN_IN_WORKER
-
 #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 ipv4_lease_last;
     struct in_addr ipv4_network_mask;
-    struct in_addr ipv4_host;
     struct in_addr ipv4_network_addr;
+    struct in_addr ipv4_gw;
     int tun_ctl_fd;
     int tun_fd;
     struct ifreq ifr;
+    bool auto_cpu_reassignment;
 
-#ifdef DAP_TUN_IN_WORKER
-    dap_events_socket_t * tun_events_socket;
-#endif
     ch_vpn_pkt_t * pkt_out[400];
     size_t pkt_out_size;
     size_t pkt_out_rindex;
     size_t pkt_out_windex;
     pthread_mutex_t pkt_out_mutex;
-
+    pthread_rwlock_t rwlock;
 } vpn_local_network_t;
 
+// Message for QUEUE_PTR operations
+struct tun_socket_msg{
+    enum{
+        TUN_SOCKET_MSG_IP_ASSIGNED,
+        TUN_SOCKET_MSG_IP_UNASSIGNED,
+        TUN_SOCKET_MSG_CH_VPN_SEND,
+        TUN_SOCKET_MSG_ESOCKET_REASSIGNED,
+        TUN_SOCKET_MSG_NONE
+    } type;
+    dap_chain_net_srv_ch_vpn_t * ch_vpn;
+    dap_events_socket_t * esocket;
+    bool is_reassigned_once;
+    union{
+        struct{ // Esocket reassigment
+            uint32_t worker_id;
+            struct in_addr addr;
+        } esocket_reassigment;
+        struct{  // IP assign/unassign
+            uint32_t worker_id;
+            struct in_addr addr;
+            uint32_t usage_id;
+        } ip_assigment;
+        struct{  // IP assign/unassign
+            uint32_t worker_id;
+            struct in_addr addr;
+        } ip_unassigment;
+        struct{ // CH VPN send operation
+            ch_vpn_pkt_t * pkt;
+        } ch_vpn_send;
+    };
+};
+
+
+ch_sf_tun_socket_t ** s_tun_sockets = NULL;
+dap_events_socket_t ** s_tun_sockets_queue_msg = NULL;
+uint32_t s_tun_sockets_count = 0;
+bool s_debug_more = false;
+
 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;
 static pthread_mutex_t s_sf_socks_mutex;
 static pthread_cond_t s_sf_socks_cond;
-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_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 );
@@ -138,16 +153,9 @@ static int s_callback_receipt_next_success(dap_chain_net_srv_t * a_srv, uint32_t
                     const void * a_receipt_next, size_t a_receipt_next_size);
 
 
-// Tunnel threads
-static void *srv_ch_sf_thread(void * a_arg);
-static void *srv_ch_sf_thread_raw(void *arg);
-static void s_tun_create(void);
-static void s_tun_destroy(void);
-
-
 // Stream callbacks
-static void s_new(dap_stream_ch_t* ch, void* arg);
-static void srv_ch_vpn_delete(dap_stream_ch_t* ch, void* arg);
+static void s_ch_vpn_new(dap_stream_ch_t* ch, void* arg);
+static void s_ch_vpn_delete(dap_stream_ch_t* ch, void* arg);
 static void s_ch_packet_in(dap_stream_ch_t* ch, void* a_arg);
 static void s_ch_packet_out(dap_stream_ch_t* ch, void* arg);
 
@@ -160,55 +168,329 @@ static void s_update_limits(dap_stream_ch_t * a_ch ,
                            dap_chain_net_srv_stream_session_t * a_srv_session,
                            dap_chain_net_srv_usage_t * a_usage, size_t a_bytes);
 
-#ifdef DAP_TUN_IN_WORKER
+static void m_es_tun_new(dap_events_socket_t * a_es, void * arg);
 static void m_es_tun_delete(dap_events_socket_t * a_es, void * arg);
 static void m_es_tun_read(dap_events_socket_t * a_es, void * arg);
-static void m_es_tun_error(dap_events_socket_t * a_es, void * arg);
+static void m_es_tun_error(dap_events_socket_t * a_es,int arg);
+
+static void s_tun_recv_msg_callback(dap_events_socket_t * a_esocket_queue, void * a_msg );
+static void s_tun_send_msg_ip_assigned(uint32_t a_worker_id, dap_chain_net_srv_ch_vpn_t * a_ch_vpn, struct in_addr a_addr);
+static void s_tun_send_msg_ip_assigned_all(dap_chain_net_srv_ch_vpn_t * a_ch_vpn, struct in_addr a_addr);
+static void s_tun_send_msg_ip_unassigned(uint32_t a_worker_id, dap_chain_net_srv_ch_vpn_t * a_ch_vpn, struct in_addr a_addr);
+static void s_tun_send_msg_ip_unassigned_all(dap_chain_net_srv_ch_vpn_t * a_ch_vpn, struct in_addr a_addr);
+
+static int s_tun_deattach_queue(int fd);
+static int s_tun_attach_queue(int fd);
+
 
-bool is_dap_tun_in_worker(void)
+static bool s_tun_client_send_data(dap_chain_net_srv_ch_vpn_info_t * a_ch_vpn_info, const void * a_data, size_t a_data_size);
+static size_t s_stream_session_esocket_send(dap_chain_net_srv_stream_session_t * l_srv_session, dap_events_socket_t * l_es, const void * a_data, size_t a_data_size );
+static bool s_tun_client_send_data_unsafe(dap_chain_net_srv_ch_vpn_t * l_ch_vpn, ch_vpn_pkt_t * l_pkt_out);
+
+
+static bool s_tun_client_send_data_unsafe(dap_chain_net_srv_ch_vpn_t * l_ch_vpn, ch_vpn_pkt_t * l_pkt_out)
 {
-#ifdef DAP_TUN_IN_WORKER
+    dap_chain_net_srv_stream_session_t * l_srv_session = DAP_CHAIN_NET_SRV_STREAM_SESSION (l_ch_vpn->ch->stream->session );
+    dap_chain_net_srv_usage_t * l_usage = dap_chain_net_srv_usage_find_unsafe(l_srv_session,  l_ch_vpn->usage_id);
+
+    size_t l_data_to_send = (l_pkt_out->header.op_data.data_size + sizeof(l_pkt_out->header));
+    size_t l_data_sent = dap_stream_ch_pkt_write_unsafe(l_ch_vpn->ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, l_pkt_out, l_data_to_send);
+    s_update_limits(l_ch_vpn->ch,l_srv_session,l_usage, l_data_sent );
+    if ( l_data_sent < l_data_to_send){
+        log_it(L_WARNING, "Wasn't sent all the data in tunnel (%zd was sent from %zd): probably buffer overflow", l_data_sent, l_data_to_send);
+        l_srv_session->stats.bytes_recv_lost += l_data_to_send - l_data_sent;
+        l_srv_session->stats.packets_recv_lost++;
+        return false;
+    }else{
+        l_srv_session->stats.bytes_recv += l_data_sent;
+        l_srv_session->stats.packets_recv++;
+        return true;
+    }
+}
+
+static bool s_tun_client_send_data(dap_chain_net_srv_ch_vpn_info_t * l_ch_vpn_info, const void * a_data, size_t a_data_size)
+{
+    assert(a_data_size > sizeof (struct iphdr));
+    ch_vpn_pkt_t *l_pkt_out = DAP_NEW_Z_SIZE(ch_vpn_pkt_t, sizeof(l_pkt_out->header) + a_data_size);
+    l_pkt_out->header.op_code = VPN_PACKET_OP_CODE_VPN_RECV;
+    l_pkt_out->header.sock_id = s_raw_server->tun_fd;
+    l_pkt_out->header.usage_id = l_ch_vpn_info->usage_id;
+    l_pkt_out->header.op_data.data_size = a_data_size;
+    memcpy(l_pkt_out->data, a_data, a_data_size);
+
+    struct in_addr l_in_daddr;
+    l_in_daddr.s_addr = ((struct iphdr* ) l_pkt_out->data)->daddr;
+
+    if(l_ch_vpn_info->is_on_this_worker){
+        if( dap_events_socket_check_unsafe(l_ch_vpn_info->worker, l_ch_vpn_info->esocket ) ){
+            if(s_debug_more){
+                char l_str_daddr[INET_ADDRSTRLEN];
+                inet_ntop(AF_INET,&l_in_daddr,l_str_daddr,sizeof (l_in_daddr));
+                log_it(L_DEBUG, "Sent packet size %zd for desitnation in own context", a_data_size);
+            }
+
+            s_tun_client_send_data_unsafe(l_ch_vpn_info->ch_vpn,l_pkt_out);
+            DAP_DELETE(l_pkt_out);
+        }else{
+            log_it(L_WARNING, "Was no esocket %p on worker #%u, lost %zd data",l_ch_vpn_info->esocket, l_ch_vpn_info->worker->id,a_data_size );
+            DAP_DELETE(l_pkt_out);
+            return false;
+        }
+
+    }else{
+        struct tun_socket_msg * l_msg= DAP_NEW_Z(struct tun_socket_msg);
+        l_msg->type = TUN_SOCKET_MSG_CH_VPN_SEND;
+        l_msg->ch_vpn = l_ch_vpn_info->ch_vpn;
+        l_msg->esocket = l_ch_vpn_info->esocket;
+        l_msg->ch_vpn_send.pkt = l_pkt_out;
+        if (dap_events_socket_queue_ptr_send(l_ch_vpn_info->queue_msg, l_msg) != 0 ){
+            log_it(L_WARNING, "Lost %zd data send in tunnel send operation in alien context: queue is overfilled?",a_data_size );
+            DAP_DELETE(l_msg);
+            DAP_DELETE(l_pkt_out);
+            return false;
+        }
+        if(s_debug_more){
+            char l_str_daddr[INET_ADDRSTRLEN];
+            inet_ntop(AF_INET,&l_in_daddr,l_str_daddr,sizeof (l_in_daddr));
+            log_it(L_INFO, "Sent packet for desitnation %zd between contexts",a_data_size);
+        }
+
+    }
     return true;
-#else
-    return false;
-#endif
 }
 
-//TODO: create .new_callback for event sockets
-int s_tun_event_stream_create()
+/**
+ * @brief s_tun_recv_msg_callback
+ * @param a_esocket_queue
+ * @param a_msg
+ */
+static void s_tun_recv_msg_callback(dap_events_socket_t * a_esocket_queue, void * a_msg )
+{
+    struct tun_socket_msg * l_msg = (struct tun_socket_msg*) a_msg;
+    switch (l_msg->type) {
+        case TUN_SOCKET_MSG_ESOCKET_REASSIGNED:{
+            assert(l_msg->esocket_reassigment.worker_id < s_tun_sockets_count);
+            ch_sf_tun_socket_t * l_tun_sock = s_tun_sockets[a_esocket_queue->worker->id];
+            assert(l_tun_sock);
+
+            dap_chain_net_srv_ch_vpn_info_t * l_info = NULL;
+            HASH_FIND(hh,l_tun_sock->clients,&l_msg->esocket_reassigment.addr , sizeof (l_msg->esocket_reassigment.addr), l_info);
+            if (l_info){ // Updating info
+                l_info->worker = dap_events_worker_get(l_msg->esocket_reassigment.worker_id);
+                l_info->queue_msg = s_tun_sockets_queue_msg[l_msg->esocket_reassigment.worker_id];
+                l_info->is_reassigned_once = true;
+                l_info->is_on_this_worker =(a_esocket_queue->worker->id == l_msg->esocket_reassigment.worker_id);
+            }else{
+                if(dap_log_level_get() <= L_INFO){
+                    char l_addrbuf[17];
+                    inet_ntop(AF_INET,&l_msg->esocket_reassigment.addr, l_addrbuf, sizeof (l_addrbuf));
+                    log_it(L_INFO,"Reassigment message for address %s on worker %u comes but no such address was found on tun socket %u",
+                           l_addrbuf, l_msg->esocket_reassigment.worker_id,
+                           a_esocket_queue->worker->id);
+                }
+            }
+        } break;
+        case TUN_SOCKET_MSG_IP_ASSIGNED:{
+            assert(l_msg->ip_assigment.worker_id < s_tun_sockets_count);
+            ch_sf_tun_socket_t * l_tun_sock = s_tun_sockets[a_esocket_queue->worker->id];
+            assert(l_tun_sock);
+
+            dap_chain_net_srv_ch_vpn_info_t * l_new_info = NULL;
+            HASH_FIND(hh,l_tun_sock->clients,&l_msg->ip_assigment.addr, sizeof (l_msg->ip_assigment.addr), l_new_info);
+            if( l_new_info){
+                char l_addrbuf[17];
+                inet_ntop(AF_INET,&l_msg->ip_assigment.addr, l_addrbuf, sizeof (l_addrbuf));
+                log_it(L_WARNING, "Already assigned address %s on tun sock #%u", l_addrbuf, l_tun_sock->worker_id);
+            }else{
+                l_new_info = DAP_NEW_Z(dap_chain_net_srv_ch_vpn_info_t);
+                l_new_info->ch_vpn = l_msg->ch_vpn;
+                l_new_info->addr_ipv4 = l_msg->ip_assigment.addr;
+                l_new_info->queue_msg = s_tun_sockets_queue_msg[l_msg->ip_assigment.worker_id];
+                l_new_info->usage_id = l_msg->ip_assigment.usage_id;
+                l_new_info->is_reassigned_once = l_msg->is_reassigned_once;
+                l_new_info->is_on_this_worker = (l_msg->ip_assigment.worker_id == a_esocket_queue->worker->id);
+                l_new_info->esocket = l_msg->esocket;
+                l_new_info->worker = dap_events_worker_get(l_msg->ip_assigment.worker_id);
+                HASH_ADD(hh,l_tun_sock->clients, addr_ipv4, sizeof (l_new_info->addr_ipv4), l_new_info);
+            }
+
+        }break;
+        case TUN_SOCKET_MSG_IP_UNASSIGNED:{
+            assert(l_msg->ip_unassigment.worker_id < s_tun_sockets_count);
+            ch_sf_tun_socket_t * l_tun_sock = s_tun_sockets[a_esocket_queue->worker->id];
+            assert(l_tun_sock);
+
+            dap_chain_net_srv_ch_vpn_info_t * l_new_info = NULL;
+            HASH_FIND(hh,l_tun_sock->clients,&l_msg->ip_unassigment.addr, sizeof (l_msg->ip_unassigment.addr), l_new_info);
+            if( l_new_info){
+                HASH_DELETE(hh, l_tun_sock->clients, l_new_info);
+                DAP_DELETE(l_new_info);
+                if( dap_log_level_get() <= L_INFO){
+                    char l_addrbuf[INET_ADDRSTRLEN];
+                    inet_ntop(AF_INET,&l_msg->ip_unassigment.addr, l_addrbuf, sizeof (l_addrbuf));
+                    log_it(L_INFO, "Unassigned %s address from tun sock #%u", l_addrbuf, l_tun_sock->worker_id);
+                }
+            }else{
+                char l_addrbuf[INET_ADDRSTRLEN];
+                inet_ntop(AF_INET,&l_msg->ip_unassigment.addr, l_addrbuf, sizeof (l_addrbuf));
+                log_it(L_WARNING, "Can't fund address %s on tun sock #%u to unassign it", l_addrbuf, l_tun_sock->worker_id);
+            }
+
+        }break;
+        case TUN_SOCKET_MSG_CH_VPN_SEND:{
+            if(dap_events_socket_check_unsafe(a_esocket_queue->worker, l_msg->esocket ) )
+                s_tun_client_send_data_unsafe(l_msg->ch_vpn,l_msg->ch_vpn_send.pkt);
+            DAP_DELETE(l_msg->ch_vpn_send.pkt);
+        }break;
+        default:log_it(L_ERROR,"Wrong tun socket message type %d", l_msg->type);
+    }
+    DAP_DELETE(l_msg);
+}
+
+/**
+ * @brief s_tun_send_msg_ip_assigned
+ * @param a_worker_id
+ * @param a_ch_vpn
+ * @param a_addr
+ */
+static void s_tun_send_msg_ip_assigned(uint32_t a_worker_id, dap_chain_net_srv_ch_vpn_t * a_ch_vpn, struct in_addr a_addr )
 {
-  static dap_events_socket_callbacks_t l_s_callbacks = {
-          .read_callback = m_es_tun_read,// for server
-          .write_callback = NULL,// for client
-          .error_callback = m_es_tun_error,
-          .delete_callback = m_es_tun_delete
-  };
-
-  s_raw_server->tun_events_socket = dap_events_socket_wrap_no_add(NULL,
-                                                                  s_raw_server->tun_fd, &l_s_callbacks);
-  s_raw_server->tun_events_socket->type = DESCRIPTOR_TYPE_FILE;
-  dap_events_socket_create_after(s_raw_server->tun_events_socket);
-  s_raw_server->tun_events_socket->_inheritor = s_raw_server;
-
-  return 0;
+    struct tun_socket_msg * l_msg = DAP_NEW_Z(struct tun_socket_msg);
+    l_msg->type = TUN_SOCKET_MSG_IP_ASSIGNED;
+    l_msg->ch_vpn = a_ch_vpn;
+    l_msg->esocket = a_ch_vpn->ch->stream->esocket;
+    l_msg->is_reassigned_once = a_ch_vpn->ch->stream->esocket->was_reassigned;
+    l_msg->ip_assigment.addr = a_addr;
+    l_msg->ip_assigment.worker_id = a_ch_vpn->ch->stream_worker->worker->id;
+    l_msg->ip_assigment.usage_id = a_ch_vpn->usage_id;
+
+    if (dap_events_socket_queue_ptr_send(s_tun_sockets_queue_msg[a_worker_id], l_msg) != 0){
+        log_it(L_WARNING, "Cant send new  ip assign message to the tun msg queue #%u", a_worker_id);
+    }
+}
+
+/**
+ * @brief s_tun_send_msg_ip_assigned_all
+ * @param a_ch_vpn
+ * @param a_addr
+ */
+static void s_tun_send_msg_ip_assigned_all(dap_chain_net_srv_ch_vpn_t * a_ch_vpn, struct in_addr a_addr)
+{
+    for( uint32_t i=0; i< s_tun_sockets_count; i++)
+        s_tun_send_msg_ip_assigned(i, a_ch_vpn , a_addr );
+}
+
+/**
+ * @brief s_tun_send_msg_ip_unassigned
+ * @param a_worker_id
+ * @param a_ch_vpn
+ * @param a_addr
+ */
+static void s_tun_send_msg_ip_unassigned(uint32_t a_worker_id, dap_chain_net_srv_ch_vpn_t * a_ch_vpn, struct in_addr a_addr)
+{
+    struct tun_socket_msg * l_msg = DAP_NEW_Z(struct tun_socket_msg);
+    l_msg->type = TUN_SOCKET_MSG_IP_UNASSIGNED;
+    l_msg->ch_vpn = a_ch_vpn;
+    l_msg->ip_unassigment.addr = a_addr;
+    l_msg->ip_unassigment.worker_id = a_ch_vpn->ch->stream_worker->worker->id;
+    l_msg->esocket = a_ch_vpn->ch->stream->esocket;
+    l_msg->is_reassigned_once = a_ch_vpn->ch->stream->esocket->was_reassigned;
+
+    if ( dap_events_socket_queue_ptr_send(s_tun_sockets_queue_msg[a_worker_id], l_msg) != 0 ) {
+        log_it(L_WARNING, "Cant send new  ip unassign message to the tun msg queue #%u", a_worker_id);
+    }
 }
-#endif
+
+/**
+ * @brief s_tun_send_msg_ip_unassigned_all
+ * @param a_ch_vpn
+ * @param a_addr
+ */
+static void s_tun_send_msg_ip_unassigned_all(dap_chain_net_srv_ch_vpn_t * a_ch_vpn, struct in_addr a_addr)
+{
+    for( uint32_t i=0; i< s_tun_sockets_count; i++)
+        s_tun_send_msg_ip_unassigned(i, a_ch_vpn, a_addr);
+}
+
+/**
+ * @brief s_tun_send_msg_esocket_reasigned_mt
+ * @param a_worker_id
+ * @param a_ch_vpn
+ * @param a_esocket
+ * @param a_addr
+ * @param a_esocket_worker_id
+ */
+static void s_tun_send_msg_esocket_reasigned_mt(uint32_t a_worker_id, dap_chain_net_srv_ch_vpn_t * a_ch_vpn, dap_events_socket_t * a_esocket,
+                                                struct in_addr a_addr, uint32_t a_esocket_worker_id)
+{
+    struct tun_socket_msg * l_msg = DAP_NEW_Z(struct tun_socket_msg);
+    l_msg->type = TUN_SOCKET_MSG_ESOCKET_REASSIGNED ;
+    l_msg->ch_vpn = a_ch_vpn;
+    l_msg->ip_unassigment.addr = a_addr;
+    l_msg->ip_unassigment.worker_id = a_esocket_worker_id;
+    l_msg->esocket = a_esocket;
+    l_msg->is_reassigned_once = true;
+
+    if (dap_events_socket_queue_ptr_send(s_tun_sockets_queue_msg[a_worker_id], l_msg) != 0){
+        log_it(L_WARNING, "Cant send esocket reassigment message to the tun msg queue #%u", a_worker_id);
+    }
+}
+
+static void s_tun_send_msg_esocket_reasigned_all_mt(dap_chain_net_srv_ch_vpn_t * a_ch_vpn, dap_events_socket_t * a_esocket,
+                                                    struct in_addr a_addr, uint32_t a_worker_id)
+{
+    for( uint32_t i=0; i< s_tun_sockets_count; i++)
+        s_tun_send_msg_esocket_reasigned_mt(i, a_ch_vpn, a_esocket, a_addr, a_worker_id);
+}
+
+
+/**
+ * @brief s_tun_event_stream_create
+ * @param a_worker
+ * @param a_tun_fd
+ * @return
+ */
+dap_events_socket_t * s_tun_event_stream_create(dap_worker_t * a_worker, int a_tun_fd)
+{
+    assert(a_worker);
+    dap_events_socket_callbacks_t l_s_callbacks;
+    memset(&l_s_callbacks,0,sizeof (l_s_callbacks));
+    l_s_callbacks.new_callback = m_es_tun_new;
+    l_s_callbacks.read_callback = m_es_tun_read;
+    l_s_callbacks.error_callback = m_es_tun_error;
+    l_s_callbacks.delete_callback = m_es_tun_delete;
+
+    s_tun_deattach_queue(a_tun_fd);
+
+    dap_events_socket_t * l_es = dap_events_socket_wrap_no_add(a_worker->events ,
+                                          a_tun_fd, &l_s_callbacks);
+    l_es->type = DESCRIPTOR_TYPE_FILE;
+    dap_events_socket_assign_on_worker_mt(l_es, a_worker);
+
+    return l_es;
+}
+
 
 static int s_callback_client_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_success, size_t a_success_size)
 {
-    if(!a_srv || !a_srv_client || !a_srv_client->ch || !a_success || a_success_size < sizeof(dap_stream_ch_chain_net_srv_pkt_success_t))
+    if(!a_srv || !a_srv_client || !a_srv_client->stream_worker || !a_success || a_success_size < sizeof(dap_stream_ch_chain_net_srv_pkt_success_t))
         return -1;
     dap_stream_ch_chain_net_srv_pkt_success_t * l_success = (dap_stream_ch_chain_net_srv_pkt_success_t*) a_success;
 
+    dap_stream_session_lock();
+    dap_stream_session_t *l_stream_session = dap_stream_session_id_unsafe(a_srv_client->session_id);
     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_stream_session->_inheritor;
+
     dap_chain_net_srv_vpn_t* l_srv_vpn = (dap_chain_net_srv_vpn_t*) a_srv->_inhertor;
     //a_srv_client->ch->
     dap_chain_net_t * l_net = dap_chain_net_by_id(l_success->hdr.net_id);
     dap_chain_net_srv_usage_t *l_usage = dap_chain_net_srv_usage_add(l_srv_session, l_net, a_srv);
-    if(!l_usage)
+    if(!l_usage){
+        dap_stream_session_unlock();
         return -2;
+    }
 
     dap_chain_net_srv_ch_vpn_t * l_srv_ch_vpn =
             (dap_chain_net_srv_ch_vpn_t*) a_srv_client->ch->stream->channel[DAP_CHAIN_NET_SRV_VPN_ID] ?
@@ -223,29 +505,6 @@ static int s_callback_client_success(dap_chain_net_srv_t * a_srv, uint32_t a_usa
 
     dap_stream_ch_t *l_ch = dap_chain_net_vpn_client_get_stream_ch();
 
-    int remote_sock_id = 0;//l_vpn_pkt->header.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 = l_ch->stream->events_socket->socket;
-    sf_sock->ch = l_ch;
-    pthread_mutex_init(&sf_sock->mutex, NULL);
-    dap_chain_net_srv_ch_vpn_t *f = CH_VPN(a_srv_client->ch);
-    //pthread_mutex_lock(&s_sf_socks_mutex);
-    pthread_mutex_lock(&l_srv_ch_vpn->mutex);
-    HASH_ADD_INT(l_srv_ch_vpn->socks, id, sf_sock);
-    pthread_mutex_unlock(&l_srv_ch_vpn->mutex);
-    //HASH_ADD_INT(CH_VPN(a_srv_client->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);
-
-    //!!!//l_usage->receipt = ;
-
-    /*
-     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);
-     if ( ! l_usage->is_active
-     */
 
     if(l_ch) { // Is present in hash table such destination address
         size_t l_ipv4_str_len = 0; //dap_strlen(a_ipv4_str);
@@ -256,29 +515,24 @@ static int s_callback_client_success(dap_chain_net_srv_t * a_srv, uint32_t a_usa
         //pkt_out->header.op_connect.addr_size = l_ipv4_str_len; //remoteAddrBA.length();
         //pkt_out->header.op_connect.port = a_port;
         //memcpy(pkt_out->data, a_ipv4_str, l_ipv4_str_len);
-        sf_sock->pkt_out[sf_sock->pkt_out_size] = pkt_out;
-        sf_sock->pkt_out_size++;
 
-        dap_stream_ch_pkt_write(l_ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pkt_out,
+        dap_stream_ch_pkt_write_unsafe(l_ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pkt_out,
                 pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
-        dap_stream_ch_set_ready_to_write(l_ch, true);
+        dap_stream_ch_set_ready_to_write_unsafe(l_ch, true);
         //DAP_DELETE(pkt_out);
     }
 
-
-
-
     // usage is present, we've accepted packets
-    dap_stream_ch_set_ready_to_read( l_srv_ch_vpn->ch , true );
+    dap_stream_ch_set_ready_to_read_unsafe( l_srv_ch_vpn->ch , true );
     return 0;
 }
 
 static int callback_client_sign_request(dap_chain_net_srv_t * a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_t * a_srv_client,
-                    const void **a_receipt, size_t a_receipt_size)
+                    dap_chain_datum_tx_receipt_t **a_receipt, size_t a_receipt_size)
 {
-    dap_chain_datum_tx_receipt_t *l_receipt = (dap_chain_datum_tx_receipt_t*)*a_receipt;
+    dap_chain_datum_tx_receipt_t *l_receipt = *a_receipt;
     char *l_gdb_group = dap_strdup_printf("local.%s", DAP_CHAIN_NET_SRV_VPN_CDB_GDB_PREFIX);
-    char *l_wallet_name = dap_chain_global_db_gr_get(dap_strdup("wallet_name"), NULL, l_gdb_group);
+    char *l_wallet_name = (char*) dap_chain_global_db_gr_get(dap_strdup("wallet_name"), NULL, l_gdb_group);
 
     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, dap_chain_wallet_get_path(g_config));
     if(l_wallet) {
@@ -296,7 +550,7 @@ static int callback_client_sign_request(dap_chain_net_srv_t * a_srv, uint32_t a_
 /*
  * Client VPN init (after dap_chain_net_srv_vpn_init!)
  */
-int dap_chain_net_srv_client_vpn_init(dap_config_t * g_config) {
+int dap_chain_net_srv_client_vpn_init(dap_config_t * l_config) {
     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_get(l_uid);
     dap_chain_net_srv_vpn_t* l_srv_vpn = l_srv ? (dap_chain_net_srv_vpn_t*) l_srv->_inhertor : NULL;
@@ -305,10 +559,12 @@ int dap_chain_net_srv_client_vpn_init(dap_config_t * g_config) {
         l_srv_vpn = DAP_NEW_Z(dap_chain_net_srv_vpn_t);
         if(l_srv)
             l_srv->_inhertor = l_srv_vpn;
-        dap_stream_ch_proc_add(DAP_STREAM_CH_ID_NET_SRV_VPN, s_new, srv_ch_vpn_delete, s_ch_packet_in, s_ch_packet_out);
+        dap_stream_ch_proc_add(DAP_STREAM_CH_ID_NET_SRV_VPN, s_ch_vpn_new, s_ch_vpn_delete, s_ch_packet_in, s_ch_packet_out);
         pthread_mutex_init(&s_sf_socks_mutex, NULL);
         pthread_cond_init(&s_sf_socks_cond, NULL);
     }
+
+
     if(!dap_chain_net_srv_client_init(l_uid, s_callback_requested,
             s_callback_response_success, s_callback_response_error,
             s_callback_receipt_next_success,
@@ -325,130 +581,195 @@ int dap_chain_net_srv_client_vpn_init(dap_config_t * g_config) {
     return 0;
 }
 
-/**
- * @brief dap_stream_ch_vpn_init Init actions for VPN stream channel
- * @param vpn_addr Zero if only client mode. Address if the node shares its local VPN
- * @param vpn_mask Zero if only client mode. Mask if the node shares its local VPN
- * @return 0 if everything is okay, lesser then zero if errors
- */
-int dap_chain_net_srv_vpn_init(dap_config_t * g_config) {
+
+
+int s_vpn_tun_create(dap_config_t * g_config)
+{
     const char *c_addr = dap_config_get_item_str(g_config, "srv_vpn", "network_address");
     const char *c_mask = dap_config_get_item_str(g_config, "srv_vpn", "network_mask");
-    if(c_addr && c_mask) {
-        s_srv_vpn_addr = strdup(c_addr);
-        s_srv_vpn_mask = strdup(c_mask);
+    if(!c_addr || !c_mask){
+        log_it(L_ERROR, "%s: error while reading network parameters from config (network_address and network_mask)", __PRETTY_FUNCTION__);
+        DAP_DELETE((void*)c_addr);
+        DAP_DELETE((void*)c_mask);
+        return -1;
+    }
 
-        s_raw_server = DAP_NEW_Z(vpn_local_network_t);
-        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);
+    inet_aton(c_addr, &s_raw_server->ipv4_network_addr );
+    inet_aton(c_mask, &s_raw_server->ipv4_network_mask );
+    s_raw_server->ipv4_gw.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_gw.s_addr;
+
+    s_raw_server->auto_cpu_reassignment = dap_config_get_item_bool_default(g_config, "srv_vpn", "auto_cpu_reassignment", false);
+    log_it(L_NOTICE,"auto cpu reassignment is set to '%s'", s_raw_server->auto_cpu_reassignment);
+
+    memset(&s_raw_server->ifr, 0, sizeof(s_raw_server->ifr));
+    s_raw_server->ifr.ifr_flags = IFF_TUN | IFF_MULTI_QUEUE| IFF_NO_PI;
+
+    uint32_t l_cpu_count = dap_get_cpu_count(); // maybe replace with getting s_threads_count directly
+    log_it(L_NOTICE,"%s: trying to initialize multiqueue for %u workers", __PRETTY_FUNCTION__, l_cpu_count);
+    s_tun_sockets_count = l_cpu_count;
+    s_tun_sockets = DAP_NEW_Z_SIZE(ch_sf_tun_socket_t*,s_tun_sockets_count*sizeof(ch_sf_tun_socket_t*));
+    s_tun_sockets_queue_msg =  DAP_NEW_Z_SIZE(dap_events_socket_t*,s_tun_sockets_count*sizeof(dap_events_socket_t*));
+    int err = -1;
+    for( uint8_t i =0; i< l_cpu_count; i++){
+        dap_worker_t * l_worker = dap_events_worker_get(i);
+        assert( l_worker );
+        int l_tun_fd;
+        if( (l_tun_fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0 ) {
+            log_it(L_ERROR,"Opening /dev/net/tun error: '%s'", strerror(errno));
+            err = -100;
+            break;
+        }
+        log_it(L_DEBUG,"Opening /dev/net/tun:%u", i);
+        if( (err = ioctl(l_tun_fd, TUNSETIFF, (void *)& s_raw_server->ifr)) < 0 ) {
+            log_it(L_CRITICAL, "ioctl(TUNSETIFF) error: '%s' ",strerror(errno));
+            close(l_tun_fd);
+            break;
+        }
+        s_tun_deattach_queue(l_tun_fd);
+        s_tun_event_stream_create(l_worker, l_tun_fd);
+    }
 
-#ifdef DAP_TUN_IN_WORKER
-        s_tun_create();
+    if (! err ){
+        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->ipv4_gw),c_mask);
+        snprintf(buf,sizeof(buf),"ip link set %s up",s_raw_server->ifr.ifr_name);
+        system(buf);
+        snprintf(buf,sizeof(buf),"ip addr add %s/%s dev %s ",inet_ntoa(s_raw_server->ipv4_gw),c_mask, s_raw_server->ifr.ifr_name );
+        system(buf);
+    }
 
-        if(s_raw_server->tun_fd == -1){
-          log_it(L_CRITICAL,"Error creating file descriptor for /dev/net/tun device");
-          return -2;
-        }
+    return err;
+}
 
-        s_tun_event_stream_create();
-#else
-        pthread_create(&srv_sf_socks_raw_pid, NULL, srv_ch_sf_thread_raw, NULL);
-#endif
+/**
+* @brief ch_sf_tun_init
+* @return
+*/
+int s_vpn_tun_init()
+{
+    s_raw_server=DAP_NEW_Z(vpn_local_network_t);
+    pthread_rwlock_init(&s_raw_server->rwlock, 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_pid, NULL, srv_ch_sf_thread, NULL);
-        dap_stream_ch_proc_add(DAP_STREAM_CH_ID_NET_SRV_VPN, s_new, srv_ch_vpn_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_requested,
-                                                            s_callback_response_success, s_callback_response_error,
-                                                            s_callback_receipt_next_success);
-        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;
-
-        /* ! IMPORTANT ! This fetch is single-action and cannot be further reused, since it modifies the stored config data
-         * ! it also must NOT be freed within this module !
-         */
-        char **l_pricelist = dap_config_get_array_str(g_config, "srv_vpn", "pricelist", &l_pricelist_count); // must not be freed!
-        for (uint16_t i = 0; i < l_pricelist_count; i++) {
-            dap_chain_net_srv_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_price_t);
-            short l_iter = 0;
-            char *l_ctx;
-            for (char *l_price_token = strtok_r(l_pricelist[i], ":", &l_ctx); l_price_token || l_iter == 6; l_price_token = strtok_r(NULL, ":", &l_ctx), ++l_iter) {
-                //log_it(L_DEBUG, "Tokenizer: %s", l_price_token);
-                switch (l_iter) {
-                case 0:
-                    l_price->net_name = l_price_token;
-                    if (!(l_price->net = dap_chain_net_by_name(l_price->net_name))) {
-                        log_it(L_ERROR, "Error parsing pricelist: can't find network \"%s\"", l_price_token);
-                        DAP_DELETE(l_price);
-                        break;
-                    }
-                    continue;
-                case 1:
-                    l_price->value_coins = atof(l_price_token);
-                    if (!(l_price->value_datoshi = (uint64_t)dap_chain_coins_to_balance((long double)l_price->value_coins))) {
-                        log_it(L_ERROR, "Error parsing pricelist: text on 2nd position \"%s\" is not floating number", l_price_token);
-                        l_iter = 0;
-                        DAP_DELETE(l_price);
-                        break;
-                    }
-                    continue;
-                case 2:
-                    dap_stpcpy(l_price->token, l_price_token);
-                    continue;
-                case 3:
-                    l_price->units = strtoul(l_price_token, NULL, 10);
-                    if (!l_price->units) {
-                        log_it(L_ERROR, "Error parsing pricelist: text on 4th position \"%s\" is not unsigned integer", l_price_token);
-                        l_iter = 0;
-                        DAP_DELETE(l_price);
-                        break;
-                    }
-                    continue;
-                case 4:
-                    if (!strcmp(l_price_token,      "SEC"))
-                        l_price->units_uid.enm = SERV_UNIT_SEC;
-                    else if (!strcmp(l_price_token, "DAY"))
-                        l_price->units_uid.enm = SERV_UNIT_DAY;
-                    else if (!strcmp(l_price_token, "MB"))
-                        l_price->units_uid.enm = SERV_UNIT_MB;
-                    else {
-                        log_it(L_ERROR, "Error parsing pricelist: wrong unit type \"%s\"", l_price_token);
-                        l_iter = 0;
-                        DAP_DELETE(l_price);
-                        break;
-                    }
-                    continue;
-                case 5:
-                    if (!(l_price->wallet = dap_chain_wallet_open(l_price_token, dap_config_get_item_str_default(g_config, "resources", "wallets_path", NULL)))) {
-                        log_it(L_ERROR, "Error parsing pricelist: can't open wallet \"%s\"", l_price_token);
-                        l_iter = 0;
-                        DAP_DELETE(l_price);
-                        break;
-                    }
-                    continue;
-                case 6:
-                    log_it(L_INFO, "Price item correct, added to service");
-                    DL_APPEND(l_srv->pricelist, l_price);
+    return 0;
+}
+
+int s_vpn_service_create(dap_config_t * g_config){
+    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_requested,
+                                                        s_callback_response_success, s_callback_response_error,
+                                                        s_callback_receipt_next_success);
+
+    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;
+
+    // Read if we need to dump all pkt operations
+    s_debug_more= dap_config_get_item_bool_default(g_config,"srv_vpn", "debug_more",false);
+
+
+    //! IMPORTANT ! This fetch is single-action and cannot be further reused, since it modifies the stored config data
+    //! it also must NOT be freed within this module !
+    char **l_pricelist = dap_config_get_array_str(g_config, "srv_vpn", "pricelist", &l_pricelist_count); // must not be freed!
+    for (uint16_t i = 0; i < l_pricelist_count; i++) {
+        dap_chain_net_srv_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_price_t);
+        short l_iter = 0;
+        char *l_ctx;
+        for (char *l_price_token = strtok_r(l_pricelist[i], ":", &l_ctx); l_price_token || l_iter == 6; l_price_token = strtok_r(NULL, ":", &l_ctx), ++l_iter) {
+            //log_it(L_DEBUG, "Tokenizer: %s", l_price_token);
+            switch (l_iter) {
+            case 0:
+                l_price->net_name = l_price_token;
+                if (!(l_price->net = dap_chain_net_by_name(l_price->net_name))) {
+                    log_it(L_ERROR, "Error parsing pricelist: can't find network \"%s\"", l_price_token);
+                    DAP_DELETE(l_price);
+                    break;
+                }
+                continue;
+            case 1:
+                l_price->value_coins = atof(l_price_token);
+                if (!(l_price->value_datoshi = (uint64_t)dap_chain_coins_to_balance((long double)l_price->value_coins))) {
+                    log_it(L_ERROR, "Error parsing pricelist: text on 2nd position \"%s\" is not floating number", l_price_token);
+                    l_iter = 0;
+                    DAP_DELETE(l_price);
+                    break;
+                }
+                continue;
+            case 2:
+                dap_stpcpy(l_price->token, l_price_token);
+                continue;
+            case 3:
+                l_price->units = strtoul(l_price_token, NULL, 10);
+                if (!l_price->units) {
+                    log_it(L_ERROR, "Error parsing pricelist: text on 4th position \"%s\" is not unsigned integer", l_price_token);
+                    l_iter = 0;
+                    DAP_DELETE(l_price);
                     break;
-                default:
+                }
+                continue;
+            case 4:
+                if (!strcmp(l_price_token,      "SEC"))
+                    l_price->units_uid.enm = SERV_UNIT_SEC;
+                else if (!strcmp(l_price_token, "DAY"))
+                    l_price->units_uid.enm = SERV_UNIT_DAY;
+                else if (!strcmp(l_price_token, "MB"))
+                    l_price->units_uid.enm = SERV_UNIT_MB;
+                else {
+                    log_it(L_ERROR, "Error parsing pricelist: wrong unit type \"%s\"", l_price_token);
+                    l_iter = 0;
+                    DAP_DELETE(l_price);
                     break;
                 }
-                log_it(L_DEBUG, "Done with price item %d", i);
-                break; // double break exits tokenizer loop and steps to next price item
+                continue;
+            case 5:
+                if (!(l_price->wallet = dap_chain_wallet_open(l_price_token, dap_config_get_item_str_default(g_config, "resources", "wallets_path", NULL)))) {
+                    log_it(L_ERROR, "Error parsing pricelist: can't open wallet \"%s\"", l_price_token);
+                    l_iter = 0;
+                    DAP_DELETE(l_price);
+                    break;
+                }
+                continue;
+            case 6:
+                log_it(L_INFO, "Price item correct, added to service");
+                DL_APPEND(l_srv->pricelist, l_price);
+                break;
+            default:
+                break;
             }
+            log_it(L_DEBUG, "Done with price item %d", i);
+            break; // double break exits tokenizer loop and steps to next price item
         }
+    }
+    return 0;
 
-        return 0;
-        //int retVal = dap_chain_net_srv_vpn_cmd_init();
-        //return retVal;
+}
+
+
+/**
+ * @brief dap_stream_ch_vpn_init Init actions for VPN stream channel
+ * @param g_config
+ * @return 0 if everything is okay, lesser then zero if errors
+ */
+int dap_chain_net_srv_vpn_init(dap_config_t * g_config) {
+    s_vpn_tun_init();
+
+    log_it(L_DEBUG,"Initializing TUN driver...");
+    if(s_vpn_tun_create(g_config) != 0){
+        log_it(L_CRITICAL, "Error initializing TUN device driver!");
+        return -1;
     }
-    return -1;
+    log_it(L_INFO,"TUN driver configured successfuly");
+    s_vpn_service_create(g_config);
+    dap_stream_ch_proc_add(DAP_STREAM_CH_ID_NET_SRV_VPN, s_ch_vpn_new, s_ch_vpn_delete, s_ch_packet_in,
+            s_ch_packet_out);
+
+    return 0;
 }
 
 /**
@@ -492,7 +813,7 @@ static int s_callback_response_success(dap_chain_net_srv_t * a_srv, uint32_t a_u
 //    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;
-    dap_chain_net_srv_usage_t * l_usage_active= dap_chain_net_srv_usage_find(l_srv_session,a_usage_id);
+    dap_chain_net_srv_usage_t * l_usage_active= dap_chain_net_srv_usage_find_unsafe(l_srv_session,a_usage_id);
     dap_chain_net_srv_ch_vpn_t * l_srv_ch_vpn =(dap_chain_net_srv_ch_vpn_t*) a_srv_client->ch->stream->channel[DAP_CHAIN_NET_SRV_VPN_ID] ?
             a_srv_client->ch->stream->channel[DAP_CHAIN_NET_SRV_VPN_ID]->internal : NULL;
 
@@ -505,21 +826,19 @@ static int s_callback_response_success(dap_chain_net_srv_t * a_srv, uint32_t a_u
 
     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);
-    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);
-
     l_srv_session->usage_active = l_usage_active;
     l_srv_session->usage_active->is_active = true;
     log_it(L_NOTICE,"Enable VPN service");
 
     if ( l_srv_ch_vpn ){ // If channel is already opened
 
-        dap_stream_ch_set_ready_to_read( l_srv_ch_vpn->ch , true );
+        dap_stream_ch_set_ready_to_read_unsafe( l_srv_ch_vpn->ch , true );
 
         l_srv_ch_vpn->usage_id = a_usage_id;
         // So complicated to update usage client to be sure that nothing breaks it
@@ -551,7 +870,7 @@ static int s_callback_receipt_next_success(dap_chain_net_srv_t * a_srv, uint32_t
 
     log_it(L_INFO, "Next receipt successfuly accepted");
     // usage is present, we've accepted packets
-    dap_stream_ch_set_ready_to_read( l_srv_ch_vpn->ch , true );
+    dap_stream_ch_set_ready_to_read_unsafe( l_srv_ch_vpn->ch , true );
     return 0;
 }
 
@@ -571,72 +890,6 @@ static int s_callback_response_error(dap_chain_net_srv_t * a_srv, uint32_t a_usa
 }
 
 
-/**
- * @brief s_tun_create
- */
-static void s_tun_create(void)
-{
-    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));
-    } else {
-        int err;
-        memset(&s_raw_server->ifr, 0, sizeof(s_raw_server->ifr));
-        s_raw_server->ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
-        if((err = ioctl(s_raw_server->tun_ctl_fd, TUNSETIFF, (void *) &s_raw_server->ifr)) < 0) {
-            log_it(L_CRITICAL, "ioctl(TUNSETIFF) error: '%s' ", strerror(errno));
-            close(s_raw_server->tun_ctl_fd);
-            s_raw_server->tun_ctl_fd = -1;
-            s_raw_server->tun_fd = -1;
-        } 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->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->ipv4_host),
-                    s_srv_vpn_mask,
-                    s_raw_server->ifr.ifr_name);
-            res = system(buf);
-            res = 0;
-        }
-    }
-    pthread_rwlock_unlock(& s_raw_server_rwlock);
-
-}
-
-/**
- * @brief s_tun_destroy
- */
-static void s_tun_destroy(void)
-{
-    pthread_rwlock_wrlock(& s_raw_server_rwlock);
-#ifdef DAP_TUN_IN_WORKER
-    dap_events_socket_kill_socket(s_raw_server->tun_events_socket);
-#endif
-    close(s_raw_server->tun_fd);
-    s_raw_server->tun_fd = -1;
-    pthread_rwlock_unlock(& s_raw_server_rwlock);
-}
-
-
-/**
- * @brief ch_sf_socket_delete
- * @param sf
- */
-static void ch_sf_socket_delete(ch_vpn_socket_proxy_t * a_vpn_socket_proxy)
-{
-    close(a_vpn_socket_proxy->sock);
-    pthread_mutex_destroy(& (a_vpn_socket_proxy->mutex) );
-    if (a_vpn_socket_proxy)
-        DAP_DELETE(a_vpn_socket_proxy);
-}
 
 
 /**
@@ -644,22 +897,22 @@ static void ch_sf_socket_delete(ch_vpn_socket_proxy_t * a_vpn_socket_proxy)
  * @param ch
  * @param arg
  */
-void s_new(dap_stream_ch_t* a_stream_ch, void* a_arg)
+void s_ch_vpn_new(dap_stream_ch_t* a_ch, void* a_arg)
 {
     (void) a_arg;
-
-    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);
-
-    if(a_stream_ch->stream->session->_inheritor == NULL && a_stream_ch->stream->session != NULL)
-        dap_chain_net_srv_stream_session_create(a_stream_ch->stream->session);
+    a_ch->stream->esocket->flags |= DAP_SOCK_REASSIGN_ONCE; // We will try to reassign on another worker
+                                                            // to use FlowControl if its present in system
+                                                            // If not - we prevent jumping between workers with this trick
+    a_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_ch);
+
+    if(a_ch->stream->session->_inheritor == NULL && a_ch->stream->session != NULL)
+        dap_chain_net_srv_stream_session_create(a_ch->stream->session);
     dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_VPN_ID };
     l_srv_vpn->net_srv = dap_chain_net_srv_get(l_uid);
-    l_srv_vpn->ch = a_stream_ch;
+    l_srv_vpn->ch = a_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);
+    dap_chain_net_srv_stream_session_t * l_srv_session = (dap_chain_net_srv_stream_session_t *) a_ch->stream->session->_inheritor;
 
     l_srv_vpn->usage_id = l_srv_session->usage_active?  l_srv_session->usage_active->id : 0;
 
@@ -669,9 +922,7 @@ void s_new(dap_stream_ch_t* a_stream_ch, void* a_arg)
         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);
     }
@@ -683,17 +934,19 @@ void s_new(dap_stream_ch_t* a_stream_ch, void* a_arg)
  * @param ch
  * @param arg
  */
-void srv_ch_vpn_delete(dap_stream_ch_t* ch, void* arg)
+void s_ch_vpn_delete(dap_stream_ch_t* ch, void* arg)
 {
-    //log_it(L_DEBUG, "ch_sf_delete() for %s", ch->stream->conn->s_ip); <<- causes segfault
     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 = false;
     if ( l_ch_vpn->addr_ipv4.s_addr ){ // if leased address
+        s_tun_send_msg_ip_unassigned_all(l_ch_vpn, l_ch_vpn->addr_ipv4); // Signal all the workers that we're switching off
+
         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 );
@@ -717,64 +970,14 @@ void srv_ch_vpn_delete(dap_stream_ch_t* ch, void* arg)
 
     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);
-        if(l_ch_vpn->socks){
-            HASH_DEL(l_ch_vpn->socks, cur);
-        }
-        if(cur)
-            free(cur);
-    }
-
-    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 s_ch_proxy_delete(ch_vpn_socket_proxy_t * a_sock_proxy)
-{
-    if( !a_sock_proxy)
-        return;
-
-    if(a_sock_proxy->sock > 0)
-        close(a_sock_proxy->sock);
-    // wait while mutex will be released if it be locked
-    pthread_mutex_lock(&a_sock_proxy->mutex);
-    pthread_mutex_unlock(&a_sock_proxy->mutex);
-
-    pthread_mutex_destroy(&(a_sock_proxy->mutex));
-    DAP_DELETE(a_sock_proxy);
-}
-
-static ch_vpn_pkt_t* srv_ch_sf_raw_read()
-{
-    ch_vpn_pkt_t*ret = NULL;
-    pthread_mutex_lock(&s_raw_server->pkt_out_mutex);
-    if(s_raw_server->pkt_out_rindex == (sizeof(s_raw_server->pkt_out) / sizeof(s_raw_server->pkt_out[0]))) {
-        s_raw_server->pkt_out_rindex = 0; // ring the buffer!
-    }
-    if((s_raw_server->pkt_out_rindex != s_raw_server->pkt_out_windex) || (s_raw_server->pkt_out_size == 0)) {
-        ret = s_raw_server->pkt_out[s_raw_server->pkt_out_rindex];
-        s_raw_server->pkt_out_rindex++;
-        s_raw_server->pkt_out_size--;
-    } //else
-      //  log_it(L_WARNING, "Packet drop on raw_read() operation, ring buffer is full");
-    pthread_mutex_unlock(&s_raw_server->pkt_out_mutex);
-    return ret;
 }
 
 /**
@@ -811,18 +1014,18 @@ static void s_update_limits(dap_stream_ch_t * a_ch ,
                     } break;
                     default: {
                         log_it(L_WARNING, "VPN doesnt accept serv unit type 0x%08X for limits_ts", a_usage->receipt->receipt_info.units_type.uint32 );
-                        dap_stream_ch_set_ready_to_write(a_ch,false);
-                        dap_stream_ch_set_ready_to_read(a_ch,false);
-                        dap_stream_ch_pkt_write( a_usage->clients->ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
+                        dap_stream_ch_set_ready_to_write_unsafe(a_ch,false);
+                        dap_stream_ch_set_ready_to_read_unsafe(a_ch,false);
+                        dap_stream_ch_pkt_write_unsafe( a_usage->client->ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
                     }
                 }
 
                 //l_ch_vpn->limits_ts = time(NULL) + l_usage->receipt->receipt
             }else {
                 log_it( L_NOTICE, "No activate receipt in usage, switch off write callback for channel");
-                dap_stream_ch_set_ready_to_write(a_ch,false);
-                dap_stream_ch_set_ready_to_read(a_ch,false);
-                dap_stream_ch_pkt_write( a_usage->clients->ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
+                dap_stream_ch_set_ready_to_write_unsafe(a_ch,false);
+                dap_stream_ch_set_ready_to_read_unsafe(a_ch,false);
+                dap_stream_ch_pkt_write_unsafe( a_usage->client->ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
             }
         }
     }else if ( a_srv_session->limits_bytes ){
@@ -852,18 +1055,18 @@ static void s_update_limits(dap_stream_ch_t * a_ch ,
                     } break;
                     default: {
                         log_it(L_WARNING, "VPN doesnt accept serv unit type 0x%08X for limits_bytes", a_usage->receipt->receipt_info.units_type.uint32 );
-                        dap_stream_ch_set_ready_to_write(a_ch,false);
-                        dap_stream_ch_set_ready_to_read(a_ch,false);
-                        dap_stream_ch_pkt_write( a_usage->clients->ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
+                        dap_stream_ch_set_ready_to_write_unsafe(a_ch,false);
+                        dap_stream_ch_set_ready_to_read_unsafe(a_ch,false);
+                        dap_stream_ch_pkt_write_unsafe( a_usage->client->ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
                     }
                 }
 
 
             }else {
                 log_it( L_NOTICE, "No activate receipt in usage, switch off write callback for channel");
-                dap_stream_ch_set_ready_to_write(a_ch,false);
-                dap_stream_ch_set_ready_to_read(a_ch,false);
-                dap_stream_ch_pkt_write( a_usage->clients->ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
+                dap_stream_ch_set_ready_to_write_unsafe(a_ch,false);
+                dap_stream_ch_set_ready_to_read_unsafe(a_ch,false);
+                dap_stream_ch_pkt_write_unsafe( a_usage->client->ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
 
             }
 
@@ -875,7 +1078,7 @@ static void s_update_limits(dap_stream_ch_t * a_ch ,
         if ( a_usage->receipt){
             dap_chain_datum_tx_receipt_t * l_receipt =dap_chain_net_srv_issue_receipt(a_usage->service, a_usage,a_usage->price,NULL,0 );
             a_usage->receipt_next = l_receipt;
-            dap_stream_ch_pkt_write( a_usage->clients->ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_REQUEST ,
+            dap_stream_ch_pkt_write_unsafe( a_usage->client->ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_REQUEST ,
                                      l_receipt, l_receipt->size);
         }
     }
@@ -889,12 +1092,164 @@ static void send_pong_pkt(dap_stream_ch_t* a_ch)
     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_PONG;
 
-    dap_stream_ch_pkt_write(a_ch, 'd', pkt_out,
+    dap_stream_ch_pkt_write_unsafe(a_ch, 'd', pkt_out,
             pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
-    dap_stream_ch_set_ready_to_write(a_ch, true);
+    dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
     free(pkt_out);
 }
 
+void s_ch_packet_in_vpn_address_request(dap_stream_ch_t* a_ch, dap_chain_net_srv_usage_t * a_usage){
+    dap_chain_net_srv_ch_vpn_t *l_ch_vpn = CH_VPN(a_ch);
+    dap_chain_net_srv_vpn_t * l_srv_vpn =(dap_chain_net_srv_vpn_t *) a_usage->service->_inhertor;
+    dap_chain_net_srv_stream_session_t * l_srv_session= DAP_CHAIN_NET_SRV_STREAM_SESSION(l_ch_vpn->ch->stream->session);
+
+    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.op_code = VPN_PACKET_OP_CODE_PROBLEM;
+        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 = a_usage->id;
+
+        size_t l_data_to_write = pkt_out->header.op_data.data_size + sizeof(pkt_out->header);
+        size_t l_data_wrote = dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pkt_out,
+                l_data_to_write);
+        if (l_data_wrote < l_data_to_write){
+            log_it(L_WARNING, "Buffer overfilled: can't send packet with VPN_PROBLEM_CODE_ALREADY_ASSIGNED_ADDR: sent only %zd from %zd",
+                    l_data_wrote,l_data_to_write );
+            l_srv_session->stats.bytes_sent_lost += l_data_to_write - l_data_wrote;
+            l_srv_session->stats.packets_sent_lost++;
+        }else{
+            l_srv_session->stats.packets_sent++;
+            l_srv_session->stats.bytes_sent+= l_data_wrote;
+        }
+        return;
+    }
+    dap_chain_net_srv_vpn_item_ipv4_t * l_item_ipv4 = l_srv_vpn->ipv4_unleased;
+    if ( l_item_ipv4){
+        log_it(L_WARNING,"We have unleased ip address");
+        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_network_addr));
+        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_gw);
+        l_pkt_out->header.usage_id = a_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_gw ,
+                sizeof(s_raw_server->ipv4_gw));
+
+        size_t l_data_to_write =  l_pkt_out->header.op_data.data_size + sizeof(l_pkt_out->header);
+        size_t l_data_wrote = dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA , l_pkt_out,
+                l_data_to_write);
+        if (l_data_wrote < l_data_to_write){
+            log_it(L_WARNING, "Buffer overfilled: can't send packet with VPN_PACKET_OP_CODE_VPN_ADDR_REPLY: sent only %zd from %zd",
+                    l_data_wrote,l_data_to_write );
+            dap_chain_net_srv_stream_session_t * l_srv_session= DAP_CHAIN_NET_SRV_STREAM_SESSION(l_ch_vpn->ch->stream->session);
+            assert(l_srv_session);
+            l_srv_session->stats.bytes_sent_lost += l_data_to_write - l_data_wrote;
+            l_srv_session->stats.packets_sent_lost++;
+        }else{
+            log_it(L_NOTICE, "VPN client address %s leased", inet_ntoa(l_ch_vpn->addr_ipv4));
+            log_it(L_INFO, "\tnet gateway %s", inet_ntoa(s_raw_server->ipv4_network_addr));
+            log_it(L_INFO, "\tnet mask %s", inet_ntoa(s_raw_server->ipv4_network_mask));
+            log_it(L_INFO, "\tgw %s", inet_ntoa(s_raw_server->ipv4_gw));
+            log_it(L_INFO, "\tlast_addr %s", inet_ntoa(s_raw_server->ipv4_lease_last));
+            l_srv_vpn->ipv4_unleased = l_item_ipv4->next;
+            DAP_DELETE(l_item_ipv4);
+            l_srv_session->stats.packets_sent++;
+            l_srv_session->stats.bytes_sent+= l_data_wrote;
+            s_tun_send_msg_ip_assigned_all(l_ch_vpn, l_ch_vpn->addr_ipv4);
+        }
+    }else{
+        struct in_addr n_addr = { 0 }, n_addr_max;
+        n_addr.s_addr = ntohl(s_raw_server->ipv4_lease_last.s_addr);
+        n_addr.s_addr++;
+        n_addr_max.s_addr = (ntohl(s_raw_server->ipv4_gw.s_addr)
+                             | ~ntohl(s_raw_server->ipv4_network_mask.s_addr));
+
+        //  Just for log output we revert it back and forward
+        n_addr.s_addr = htonl(n_addr.s_addr);
+        n_addr_max.s_addr = htonl(n_addr_max.s_addr);
+        log_it(L_DEBUG, "Check if is address is lesser than");
+        log_it(L_DEBUG,"    new_address     = %s", inet_ntoa(n_addr));
+        log_it(L_DEBUG,"    new_address_max = %s", inet_ntoa(n_addr_max));
+        n_addr.s_addr = ntohl(n_addr.s_addr);
+        n_addr_max.s_addr = ntohl(n_addr_max.s_addr);
+        if(n_addr.s_addr <= n_addr_max.s_addr ) {
+            n_addr.s_addr = htonl(n_addr.s_addr);
+            n_addr_max.s_addr = htonl(n_addr_max.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;
+            l_ch_vpn->addr_ipv4.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_gw ));
+            log_it(L_INFO, "\tnet mask %s", inet_ntoa(s_raw_server->ipv4_network_mask));
+            log_it(L_INFO, "\tnet addr %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_gw));
+            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_gw);
+            pkt_out->header.usage_id = a_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_gw,
+                    sizeof(s_raw_server->ipv4_gw));
+
+            size_t l_data_to_write = pkt_out->header.op_data.data_size + sizeof(pkt_out->header);
+            size_t l_data_wrote = dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pkt_out,
+                                       l_data_to_write);
+            if (l_data_wrote < l_data_to_write){
+                log_it(L_WARNING, "Buffer overfilled: can't send packet with VPN_PACKET_OP_CODE_VPN_ADDR_REPLY: sent only %zd from %zd",
+                        l_data_wrote,l_data_to_write );
+                dap_chain_net_srv_stream_session_t * l_srv_session= DAP_CHAIN_NET_SRV_STREAM_SESSION(l_ch_vpn->ch->stream->session);
+                assert(l_srv_session);
+                l_srv_session->stats.bytes_sent_lost += l_data_to_write - l_data_wrote;
+                l_srv_session->stats.packets_sent_lost++;
+            }else{
+                l_srv_session->stats.packets_sent++;
+                l_srv_session->stats.bytes_sent+= l_data_wrote;
+                s_tun_send_msg_ip_assigned_all(l_ch_vpn, l_ch_vpn->addr_ipv4);
+            }
+        } 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 = a_usage->id;
+            pkt_out->header.op_problem.code = VPN_PROBLEM_CODE_NO_FREE_ADDR;
+            size_t l_data_to_write = pkt_out->header.op_data.data_size + sizeof(pkt_out->header);
+            size_t l_data_wrote = dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pkt_out,
+                    pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
+            if (l_data_wrote < l_data_to_write){
+                log_it(L_WARNING, "Buffer overfilled: can't send packet with VPN_PACKET_OP_CODE_PROBLEM: sent only %zd from %zd",
+                        l_data_wrote,l_data_to_write );
+                dap_chain_net_srv_stream_session_t * l_srv_session= DAP_CHAIN_NET_SRV_STREAM_SESSION(l_ch_vpn->ch->stream->session);
+                assert(l_srv_session);
+                l_srv_session->stats.bytes_sent_lost += l_data_to_write - l_data_wrote;
+                l_srv_session->stats.packets_sent_lost++;
+            }else{
+                l_srv_session->stats.packets_sent++;
+                l_srv_session->stats.bytes_sent+= l_data_wrote;
+            }
+        }
+    }
+}
+
 /**
  * @brief stream_sf_packet_in
  * @param ch
@@ -905,380 +1260,137 @@ void s_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
     dap_stream_ch_pkt_t * l_pkt = (dap_stream_ch_pkt_t *) a_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);
+    dap_chain_net_srv_usage_t * l_usage = dap_chain_net_srv_usage_find_unsafe(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);
-        dap_stream_ch_set_ready_to_read(a_ch,false);
+        dap_stream_ch_set_ready_to_write_unsafe(a_ch,false);
+        dap_stream_ch_set_ready_to_read_unsafe(a_ch,false);
         return;
     }
 
     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);
-        dap_stream_ch_set_ready_to_read(a_ch,false);
+        dap_stream_ch_set_ready_to_write_unsafe(a_ch,false);
+        dap_stream_ch_set_ready_to_read_unsafe(a_ch,false);
         return;
     }
 
     // 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;
+    //dap_chain_net_srv_vpn_t * l_srv_vpn =(dap_chain_net_srv_vpn_t *) l_usage->service->_inhertor;
 
-    //if ( pkt->hdr.type == DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_CLIENT )
-    //    dap_chain_net_vpn_client_pkt_in( a_ch, l_pkt);
-    if(l_pkt->hdr.type != DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_CLIENT) {
-        static bool client_connected = false;
-        ch_vpn_pkt_t * l_vpn_pkt = (ch_vpn_pkt_t *) l_pkt->data;
-        size_t l_vpn_pkt_size = l_pkt->hdr.size - sizeof (l_vpn_pkt->header);
+    ch_vpn_pkt_t * l_vpn_pkt = (ch_vpn_pkt_t *) l_pkt->data;
+    size_t l_vpn_pkt_size = l_pkt->hdr.size - sizeof (l_vpn_pkt->header);
 
-        int remote_sock_id = l_vpn_pkt->header.sock_id;
+    if (s_debug_more)
+        log_it(L_INFO, "Got srv_vpn packet with op_code=0x%02x", l_vpn_pkt->header.op_code);
 
-        //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) {
+    if(l_vpn_pkt->header.op_code >= 0xb0) { // Raw packets
+        switch (l_vpn_pkt->header.op_code) {
             case VPN_PACKET_OP_CODE_PING:
-                a_ch->stream->events_socket->last_ping_request = time(NULL);
+                a_ch->stream->esocket->last_ping_request = time(NULL);
+                l_srv_session->stats.bytes_recv += l_vpn_pkt_size;
+                l_srv_session->stats.packets_recv++;
                 send_pong_pkt(a_ch);
-                break;
+            break;
             case VPN_PACKET_OP_CODE_PONG:
-                a_ch->stream->events_socket->last_ping_request = time(NULL);
-                break;
+                a_ch->stream->esocket->last_ping_request = time(NULL);
+                l_srv_session->stats.bytes_recv += l_vpn_pkt_size;
+                l_srv_session->stats.packets_recv++;
+            break;
             // for client
             case VPN_PACKET_OP_CODE_VPN_ADDR_REPLY: { // Assigned address for peer
                 if(ch_sf_tun_addr_leased(CH_VPN(a_ch), l_vpn_pkt, l_vpn_pkt_size) < 0) {
                     log_it(L_ERROR, "Can't create tun");
-                }
-            }
-            break;
+                }else
+                    s_tun_send_msg_ip_assigned_all(CH_VPN(a_ch), CH_VPN(a_ch)->addr_ipv4);
+                l_srv_session->stats.bytes_recv += l_vpn_pkt_size;
+                l_srv_session->stats.packets_recv++;
+            } break;
             // for server
             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.op_code = VPN_PACKET_OP_CODE_PROBLEM;
-                    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));
-                    dap_stream_ch_set_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){
-                    log_it(L_WARNING,"We have unleased ip address");
-                    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));
-                    log_it(L_NOTICE, "VPN client address %s leased", inet_ntoa(l_ch_vpn->addr_ipv4));
-                    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));
-                    //dap_stream_ch_set_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_max;
-                    n_addr.s_addr = ntohl(s_raw_server->ipv4_lease_last.s_addr);
-                    n_addr.s_addr++;
-                    n_addr_max.s_addr = (ntohl(s_raw_server->ipv4_network_addr.s_addr)
-                                         | ~ntohl(s_raw_server->ipv4_network_mask.s_addr));
-
-                    //  Just for log output we revert it back and forward
-                    n_addr.s_addr = htonl(n_addr.s_addr);
-                    n_addr_max.s_addr = htonl(n_addr_max.s_addr);
-                    log_it(L_DEBUG, "Check if is address is lesser than");
-                    log_it(L_DEBUG,"    new_address     = %s", inet_ntoa(n_addr));
-                    log_it(L_DEBUG,"    new_address_max = %s", inet_ntoa(n_addr_max));
-                    n_addr.s_addr = ntohl(n_addr.s_addr);
-                    n_addr_max.s_addr = ntohl(n_addr_max.s_addr);
-                    if(n_addr.s_addr <= n_addr_max.s_addr ) {
-                        n_addr.s_addr = htonl(n_addr.s_addr);
-                        n_addr_max.s_addr = htonl(n_addr_max.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;
-                        l_ch_vpn->addr_ipv4.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));
-
-                        if(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))) {
-                            dap_stream_ch_set_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));
-                        dap_stream_ch_set_ready_to_write(a_ch, true);
-                    }
-                }
-            }
-                break;
+                s_ch_packet_in_vpn_address_request(a_ch, l_usage);
+                l_srv_session->stats.bytes_recv += l_vpn_pkt_size;
+                l_srv_session->stats.packets_recv++;
+            } break;
             // for client only
             case VPN_PACKET_OP_CODE_VPN_RECV:{
-                a_ch->stream->events_socket->last_ping_request = time(NULL); // not ping, but better  ;-)
-                            ch_sf_tun_send(CH_VPN(a_ch), l_vpn_pkt->data, l_vpn_pkt->header.op_data.data_size);
-            }
-            break;
+                a_ch->stream->esocket->last_ping_request = time(NULL); // not ping, but better  ;-)
+                // Find tun socket for current worker
+                ch_sf_tun_socket_t * l_tun = s_tun_sockets[a_ch->stream_worker->worker->id];
+                assert(l_tun);
+                s_stream_session_esocket_send(l_srv_session, l_tun->es, l_vpn_pkt->data, l_vpn_pkt->header.op_data.data_size);
+            } break;
 
             // for servier only
             case VPN_PACKET_OP_CODE_VPN_SEND: {
-                struct in_addr in_saddr, in_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[43], str_saddr[43];
-                strncpy(str_saddr, inet_ntoa(in_saddr), sizeof(str_saddr)-1);
-                strncpy(str_daddr, inet_ntoa(in_daddr), sizeof(str_daddr)-1);
-
-                // The packet can't be written, errno == EINVAL !!!
-                //log_it(L_DEBUG, "VPN packet, source: %s; dest: %s", inet_ntoa(in_saddr), inet_ntoa(in_daddr));
-                int ret;
-                //if( ch_sf_raw_write(STREAM_SF_PACKET_OP_CODE_RAW_SEND, sf_pkt->data, sf_pkt->op_data.data_size)<0){
-                /*struct sockaddr_in sin = { 0 };
-                sin.sin_family = AF_INET;
-                sin.sin_port = 0;
-                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, 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(a_ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pkt_out,
-                            pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
-                    dap_stream_ch_set_ready_to_write(a_ch, true);
-                } else {
-                    s_update_limits (a_ch, l_srv_session, l_usage,(size_t) ret );
-                    //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);
-                }
-                //}
-            }
-                break;
+                ch_sf_tun_socket_t * l_tun = s_tun_sockets[a_ch->stream_worker->worker->id];
+                assert(l_tun);
+                // Unsafely send it
+                size_t l_ret = s_stream_session_esocket_send(l_srv_session, l_tun->es, l_vpn_pkt->data, l_vpn_pkt->header.op_data.data_size);
+                if( l_ret)
+                    s_update_limits (a_ch, l_srv_session, l_usage,l_ret );
+            } break;
             default:
                 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(l_vpn_pkt->header.op_code != VPN_PACKET_OP_CODE_CONNECT) {
-
-                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(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 (l_vpn_pkt->header.op_code) {
-                    case VPN_PACKET_OP_CODE_SEND: {
-                        if(client_connected == false)
-                        {
-                            log_it(L_WARNING, "Drop Packet! User not connected!"); // Client need send
-                            pthread_mutex_unlock(&s_sf_socks_mutex);
-                            break;
-                        }
-                        int ret;
-                        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(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);
-                            HASH_DELETE(hh_sock, sf_socks_client, sf_sock);
-
-                            struct epoll_event ev = {0, {0}};
-                            ev.data.fd = sf_sock->sock;
-                            ev.events = EPOLLIN;
-                            if(epoll_ctl(sf_socks_epoll_fd, EPOLL_CTL_DEL, sf_sock->sock, &ev) < 0) {
-                                log_it(L_ERROR, "Can't remove sock_id %d from the epoll fd", remote_sock_id);
-                                //stream_ch_pkt_write_f(ch,'i',"sock_id=%d op_code=0x%02x result=-2",sf_pkt->sock_id, sf_pkt->op_code);
-                            } else {
-                                log_it(L_NOTICE, "Removed sock_id %d from the the epoll fd", remote_sock_id);
-                                //stream_ch_pkt_write_f(ch,'i',"sock_id=%d op_code=0x%02x result=0",sf_pkt->sock_id, sf_pkt->op_code);
-                            }
-                            pthread_mutex_unlock(&s_sf_socks_mutex);
-
-                            s_ch_proxy_delete(sf_sock);
-                        } else {
-                            sf_sock->bytes_sent += ret;
-                            pthread_mutex_unlock(&sf_sock->mutex);
-                        }
-                        //log_it(L_INFO, "Send action from %d sock_id (sf_packet size %lu,  ch packet size %lu, have sent %d)"
-                        //        , sf_sock->id, sf_pkt->header.op_data.data_size, l_pkt->hdr.size, ret);
-                    }
-                        break;
-                    case VPN_PACKET_OP_CODE_DISCONNECT: {
-                        log_it(L_INFO, "Disconnect action from %d sock_id", sf_sock->id);
-
-                        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);
-                        HASH_DELETE(hh_sock, sf_socks_client, sf_sock);
-                        struct epoll_event ev  = {0, {0}};;
-                        ev.data.fd = sf_sock->sock;
-                        ev.events = EPOLLIN;
-                        if(epoll_ctl(sf_socks_epoll_fd, EPOLL_CTL_DEL, sf_sock->sock, &ev) < 0) {
-                            log_it(L_ERROR, "Can't remove sock_id %d to the epoll fd", remote_sock_id);
-                            //stream_ch_pkt_write_f(ch,'i',"sock_id=%d op_code=%uc result=-2",sf_pkt->sock_id, sf_pkt->op_code);
-                        } else {
-                            log_it(L_NOTICE, "Removed sock_id %d from the epoll fd", remote_sock_id);
-                            //stream_ch_pkt_write_f(ch,'i',"sock_id=%d op_code=%uc result=0",sf_pkt->sock_id, sf_pkt->op_code);
-                        }
-                        pthread_mutex_unlock(&s_sf_socks_mutex);
-
-                        pthread_mutex_unlock(&sf_sock->mutex);
-                        s_ch_proxy_delete(sf_sock);
-                    }
-                        break;
-                    default: {
-                        log_it(L_WARNING, "Unprocessed op code 0x%02x", l_vpn_pkt->header.op_code);
-                        pthread_mutex_unlock(&sf_sock->mutex);
-                    }
-                    }
-                } //else
-                  //  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(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 =
-                            (l_vpn_pkt->header.op_connect.addr_size > (sizeof(addr_str) - 1)) ?
-                                    (sizeof(addr_str) - 1) :
-                                    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(l_vpn_pkt->header.op_connect.port);
-
-                    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, 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, l_vpn_pkt->header.op_connect.port);
-                    } else {
-                        int s;
-                        if((s = socket(AF_INET, SOCK_STREAM, 0)) >= 0) {
-                            log_it(L_DEBUG, "Socket is created (%d)", s);
-                            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,
-                                        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 = a_ch;
-                                pthread_mutex_init(&sf_sock->mutex, NULL);
-
-                                pthread_mutex_lock(&s_sf_socks_mutex);
-                                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);
-                                log_it(L_DEBUG, "Added %d sock_id with sock %d to the hash table", sf_sock->id,
-                                        sf_sock->sock);
-                                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(a_ch)->mutex));
-
-                                struct epoll_event ev = {0, {0}};
-                                ev.data.fd = s;
-                                ev.events = EPOLLIN | EPOLLERR;
-
-                                if(epoll_ctl(sf_socks_epoll_fd, EPOLL_CTL_ADD, s, &ev) == -1) {
-                                    log_it(L_ERROR, "Can't add sock_id %d to the epoll fd", remote_sock_id);
-                                    //stream_ch_pkt_write_f(ch,'i',"sock_id=%d op_code=%uc result=-2",sf_pkt->sock_id, sf_pkt->op_code);
-                                } else {
-                                    log_it(L_NOTICE, "Added sock_id %d  with sock %d to the epoll fd", remote_sock_id, s);
-                                    log_it(L_NOTICE, "Send Connected packet to User");
-                                    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(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;
-                                }
-                                dap_stream_ch_set_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(a_ch, 'i', "sock_id=%d op_code=%c result=-1",
-                                        l_vpn_pkt->header.sock_id, l_vpn_pkt->header.op_code);
-                                dap_stream_ch_set_ready_to_write(a_ch, true);
-                            }
-                        } else {
-                            log_it(L_ERROR, "Can't create the socket");
-                        }
-                    }
-                }
-            }
         }
     }
 }
 
+/**
+ * @brief s_stream_session_esocket_send
+ * @param l_srv_session
+ * @param l_es
+ * @param a_data
+ * @param a_data_size
+ */
+static size_t s_stream_session_esocket_send(dap_chain_net_srv_stream_session_t * l_srv_session, dap_events_socket_t * l_es, const void * a_data, size_t a_data_size )
+{
+    // Lets first try to send it directly with write() call
+    ssize_t l_direct_wrote;
+    size_t l_ret = 0;
+    if (l_es->type == DESCRIPTOR_TYPE_FILE )
+        l_direct_wrote =  write(l_es->fd, a_data, a_data_size);
+    else
+        l_direct_wrote =  send(l_es->fd, a_data, a_data_size, MSG_DONTWAIT | MSG_NOSIGNAL);
+    int l_errno = errno;
+
+    size_t l_data_left_to_send=0;
+    if (l_direct_wrote > 0){
+        l_ret += l_direct_wrote;
+        if((size_t) l_direct_wrote < a_data_size){ // If we sent not all - lets put tail in buffer
+           l_data_left_to_send = a_data_size-l_direct_wrote;
+        }else{
+            l_srv_session->stats.packets_sent++;
+            l_srv_session->stats.bytes_sent+= l_direct_wrote;
+        }
+    }else{
+        l_data_left_to_send = a_data_size;
+        l_direct_wrote=0;
+        if(l_errno != EAGAIN && l_errno != EWOULDBLOCK){
+            char l_errbuf[128];
+            strerror_r(l_errno, l_errbuf, sizeof (l_errbuf));
+            log_it(L_WARNING,"Error with data sent: \"%s\" code %d",l_errbuf, l_errno);
+        }
+    }
+
+    if(l_data_left_to_send){
+        //if ( dap_events_socket_write_unsafe( l_es, a_data +l_direct_wrote,l_data_left_to_send
+        //                                     ) < l_data_left_to_send ){
+            //log_it(L_WARNING,"Loosing data, probably buffers are overfilling, lost %zd bytes", l_data_left_to_send);
+            log_it(L_WARNING,"Loosing data, lost %zd bytes", l_data_left_to_send);
+            l_srv_session->stats.bytes_sent_lost += l_data_left_to_send;
+            l_srv_session->stats.packets_sent_lost++;
+        /*}else{
+            l_ret += l_data_left_to_send;
+            l_srv_session->stats.packets_sent++;
+            l_srv_session->stats.bytes_sent+= l_direct_wrote;
+        }*/
+    }
+    return l_ret;
+}
+
 /**
  * @brief stream_sf_packet_out Packet Out Ch callback
  * @param ch
@@ -1287,407 +1399,132 @@ void s_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
 static void s_ch_packet_out(dap_stream_ch_t* a_ch, void* a_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);
 
-    dap_chain_net_srv_usage_t * l_usage = dap_chain_net_srv_usage_find(l_srv_session,  l_ch_vpn->usage_id);
+    dap_chain_net_srv_usage_t * l_usage = dap_chain_net_srv_usage_find_unsafe(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);
-        dap_stream_ch_set_ready_to_read(a_ch,false);
+        dap_stream_ch_set_ready_to_write_unsafe(a_ch,false);
+        dap_stream_ch_set_ready_to_read_unsafe(a_ch,false);
         return;
     }
 
     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);
-        dap_stream_ch_set_ready_to_read(a_ch,false);
-        if (l_usage->clients)
-            dap_stream_ch_pkt_write( l_usage->clients->ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
+        dap_stream_ch_set_ready_to_write_unsafe(a_ch,false);
+        dap_stream_ch_set_ready_to_read_unsafe(a_ch,false);
+        if (l_usage->client)
+            dap_stream_ch_pkt_write_unsafe( l_usage->client->ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
         return;
     }
     if ( (! l_usage->is_free) && (! l_usage->receipt) ){
         log_it(L_WARNING, "No active receipt, switching off");
-        dap_stream_ch_set_ready_to_write(a_ch,false);
-        dap_stream_ch_set_ready_to_read(a_ch,false);
-        if (l_usage->clients)
-            dap_stream_ch_pkt_write( l_usage->clients->ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
+        dap_stream_ch_set_ready_to_write_unsafe(a_ch,false);
+        dap_stream_ch_set_ready_to_read_unsafe(a_ch,false);
+        if (l_usage->client)
+            dap_stream_ch_pkt_write_unsafe( l_usage->client->ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
         return;
     }
+    // Check for empty buffer out here to prevent warnings in worker
+    if ( ! a_ch->stream->esocket->buf_out_size )
+        dap_events_socket_set_writable_unsafe(a_ch->stream->esocket,false);
 
-    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) {
-                    size_t l_wrote_size;
-                    if((l_wrote_size = 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)))>0 ) {
-                        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;
-                    }
-                    s_update_limits (a_ch, l_srv_session, l_usage,l_wrote_size );
-                }
-            }
-        }
-
-        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_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));
-            s_ch_proxy_delete(cur);
-        } else
-            pthread_mutex_unlock(&(cur->mutex));
-    }
-    if(l_is_smth_out) {
-        if(a_ch->stream->conn_http)
-            a_ch->stream->conn_http->state_write = DAP_HTTP_CLIENT_STATE_DATA;
-    }
-
-    dap_stream_ch_set_ready_to_write(a_ch, l_is_smth_out);
 }
 
-/**
- * @brief stream_sf_disconnect
- * @param sf
- */
-void srv_stream_sf_disconnect(ch_vpn_socket_proxy_t * sf_sock)
+void m_es_tun_delete(dap_events_socket_t * a_es, void * arg)
 {
-    struct epoll_event ev = {0, {0}};
-    ev.data.fd = sf_sock->sock;
-    ev.events = EPOLLIN | EPOLLERR;
-    if(epoll_ctl(sf_socks_epoll_fd, EPOLL_CTL_DEL, sf_sock->sock, &ev) == -1) {
-        log_it(L_ERROR, "Can't del sock_id %d from the epoll fd", sf_sock->id);
-        //stream_ch_pkt_write_f(sf->ch,'i',"sock_id=%d op_code=%uc result=-1",sf->id, STREAM_SF_PACKET_OP_CODE_RECV);
-    } else {
-        log_it(L_ERROR, "Removed sock_id %d from the epoll fd", sf_sock->id);
-        //stream_ch_pkt_write_f(sf->ch,'i',"sock_id=%d op_code=%uc result=0",sf->id, STREAM_SF_PACKET_OP_CODE_RECV);
-    }
-
-    // Compise signal to disconnect to another side, with special opcode STREAM_SF_PACKET_OP_CODE_DISCONNECT
-    ch_vpn_pkt_t * pkt_out;
-    pkt_out = (ch_vpn_pkt_t*) calloc(1, sizeof(pkt_out->header) + 1);
-    pkt_out->header.op_code = VPN_PACKET_OP_CODE_DISCONNECT;
-    pkt_out->header.sock_id = sf_sock->id;
-    sf_sock->pkt_out[sf_sock->pkt_out_size] = pkt_out;
-    sf_sock->pkt_out_size++;
-    sf_sock->signal_to_delete = true;
+    s_tun_sockets[a_es->worker->id] = NULL;
+    dap_events_socket_remove_and_delete_unsafe(s_tun_sockets_queue_msg[a_es->worker->id],false);
+    log_it(L_NOTICE,"Destroyed TUN event socket");
 }
 
-/**
+void m_es_tun_read(dap_events_socket_t * a_es, void * arg)
+{
+    ch_sf_tun_socket_t * l_tun_socket = CH_SF_TUN_SOCKET(a_es);
+    assert(l_tun_socket);
+    size_t l_buf_in_size = a_es->buf_in_size;
+    //log_it(L_DEBUG,"m_es_tun_read() received ip pacet %u size", l_buf_in_size);
 
- Socket forward
- **/
+    if(l_buf_in_size) {
+        struct iphdr *iph = (struct iphdr*) a_es->buf_in;
+        struct in_addr l_in_daddr;
+        l_in_daddr.s_addr = iph->daddr;
 
-void * srv_ch_sf_thread(void * a_arg)
-{
-    UNUSED(a_arg);
-    struct epoll_event ev = {0, {0}}, events[SF_MAX_EVENTS] = { {0, {0}} };
-    //pthread_mutex_lock(&sf_socks_mutex);
-    sf_socks_epoll_fd = epoll_create(SF_MAX_EVENTS);
-    sigset_t sf_sigmask;
-    sigemptyset(&sf_sigmask);
-    sigaddset(&sf_sigmask, SIGUSR2);
-
-    while(1) {
-        int nfds = epoll_pwait(sf_socks_epoll_fd, events, SF_MAX_EVENTS, 10000, &sf_sigmask);
-        if(nfds < 0) {
-            //log_it(L_CRITICAL,"Can't run epoll_wait: %s",strerror(errno));
-            continue;
+        //
+        dap_chain_net_srv_ch_vpn_info_t * l_vpn_info = NULL;
+        // Try to find in worker's clients, without locks
+        if ( l_tun_socket->clients){
+            HASH_FIND_INT( l_tun_socket->clients,&l_in_daddr.s_addr,l_vpn_info );
         }
-        if(nfds > 0)
-            log_it(L_DEBUG, "Epolled %d fd", nfds);
-        else
-            continue;
-        int n;
-        for(n = 0; n < nfds; ++n) {
-            int s = events[n].data.fd;
-
-            ch_vpn_socket_proxy_t * l_socket_proxy = NULL;
-            pthread_mutex_lock(&s_sf_socks_mutex);
-            HASH_FIND(hh_sock, sf_socks_client, &s, sizeof(s), l_socket_proxy);
-            pthread_mutex_unlock(&s_sf_socks_mutex);
-            if( l_socket_proxy ) {
-                dap_chain_net_srv_stream_session_t * l_srv_session = DAP_CHAIN_NET_SRV_STREAM_SESSION (l_socket_proxy->ch->stream->session );
-                dap_chain_net_srv_ch_vpn_t *l_ch_vpn = CH_VPN(l_socket_proxy->ch);
-                dap_chain_net_srv_usage_t * l_usage = dap_chain_net_srv_usage_find(l_srv_session,  l_ch_vpn->usage_id);
-
-                if(events[n].events & EPOLLERR) {
-                    log_it(L_NOTICE, "Socket id %d has EPOLLERR flag on", s);
-                    pthread_mutex_lock(&(l_socket_proxy->mutex));
-                    srv_stream_sf_disconnect(l_socket_proxy);
-                    pthread_mutex_unlock(&(l_socket_proxy->mutex));
-                } else if(events[n].events & EPOLLIN) {
-                    char buf[1000000];
-                    ssize_t ret;
-                    pthread_mutex_lock(&(l_socket_proxy->mutex));
-                    if(l_socket_proxy->pkt_out_size < ((sizeof(l_socket_proxy->pkt_out) / sizeof(l_socket_proxy->pkt_out[0])) - 1)) {
-                        ret = recv(l_socket_proxy->sock, buf, sizeof(buf), 0);
-                        //log_it(L_DEBUG,"recv() returned %d",ret);
-                        if(ret > 0) {
-                            size_t buf_size = ret;
-                            s_update_limits(l_socket_proxy->ch,l_srv_session,l_usage,buf_size);
-                            if ( dap_stream_ch_get_ready_to_read(l_socket_proxy->ch) ){
-                                ch_vpn_pkt_t * pout;
-                                pout = l_socket_proxy->pkt_out[l_socket_proxy->pkt_out_size] = (ch_vpn_pkt_t *) calloc(1,
-                                        buf_size + sizeof(pout->header));
-                                pout->header.op_code = VPN_PACKET_OP_CODE_RECV;
-                                pout->header.sock_id = l_socket_proxy->id;
-                                pout->header.usage_id = l_usage->id;
-                                pout->header.op_data.data_size = buf_size;
-                                memcpy(pout->data, buf, buf_size);
-                                l_socket_proxy->pkt_out_size++;
-                                pthread_mutex_unlock(&(l_socket_proxy->mutex));
-                                dap_stream_ch_set_ready_to_write(l_socket_proxy->ch, true);
-                            }else{
-                                pthread_mutex_unlock(&(l_socket_proxy->mutex));
-                            }
-
-                        } else {
-                            log_it(L_NOTICE,
-                                    "Socket id %d returned error on recv() function - may be host has disconnected", s);
-                            pthread_mutex_unlock(&(l_socket_proxy->mutex));
-                            dap_stream_ch_set_ready_to_write(l_socket_proxy->ch, true);
-                            srv_stream_sf_disconnect(l_socket_proxy);
-                        }
-                    } else {
-                        log_it(L_WARNING, "Can't receive data, full of stack");
-                        pthread_mutex_unlock(&(l_socket_proxy->mutex));
-                    }
-                } else {
-                    log_it(L_WARNING, "Unprocessed flags 0x%08X", events[n].events);
-                }
-            } else {
-                if(epoll_ctl(sf_socks_epoll_fd, EPOLL_CTL_DEL, s, &ev) < 0) {
-                    log_it(L_ERROR, "Can't remove sock_id %d to the epoll fd", s);
-                } else {
-                    log_it(L_NOTICE, "Socket id %d is removed from the list", s);
-                }
+        // We found in local table, sending data (if possible)
+        if (l_vpn_info){
+            if ( !l_vpn_info->is_on_this_worker && !l_vpn_info->is_reassigned_once ){
+                log_it(L_NOTICE, "Reassigning from worker %u to %u", l_vpn_info->worker->id, a_es->worker->id);
+                l_vpn_info->is_reassigned_once = true;
+                s_tun_send_msg_esocket_reasigned_all_mt(l_vpn_info->ch_vpn, l_vpn_info->esocket, l_vpn_info->addr_ipv4,a_es->worker->id);
+                dap_events_socket_reassign_between_workers_mt( l_vpn_info->worker,l_vpn_info->esocket,a_es->worker);
             }
+            s_tun_client_send_data(l_vpn_info, a_es->buf_in, l_buf_in_size);
+        }else if(s_debug_more){
+            char l_str_daddr[INET_ADDRSTRLEN];
+            inet_ntop(AF_INET,&l_in_daddr,l_str_daddr,sizeof (l_in_daddr));
+            log_it(L_WARNING, "Can't find route for desitnation %s",l_str_daddr);
         }
-        //pthread_mutex_unlock(&sf_socks_mutex);
     }
-    return NULL;
+    a_es->buf_in_size=0; // NULL it out because read it all
 }
 
-static volatile bool s_srv_ch_sf_thread_raw_is_exit = false;
 
-/* Signal handler. */
-static void s_sig_handle (int sig)
+void m_es_tun_error(dap_events_socket_t * a_es, int arg)
 {
-    UNUSED(sig);
-    s_srv_ch_sf_thread_raw_is_exit = true;
+    if (! a_es->_inheritor)
+        return;
+    log_it(L_ERROR,"%s: error in socket %u (socket type %d)", __PRETTY_FUNCTION__, a_es->socket, a_es->type);
 }
 
-/**
- *
- *
- **/
-void* srv_ch_sf_thread_raw(void *arg)
+void m_es_tun_new(dap_events_socket_t * a_es, void * arg)
 {
-    UNUSED(arg);
-    s_tun_create();
-
-    if(s_raw_server->tun_fd <= 0) {
-        log_it(L_CRITICAL, "Tun/tap file descriptor is not initialized");
-        return NULL;
+    (void) arg;
+    ch_sf_tun_socket_t * l_tun_socket = DAP_NEW_Z(ch_sf_tun_socket_t);
+    if ( l_tun_socket ){
+        l_tun_socket->worker = a_es->worker;
+        l_tun_socket->worker_id = l_tun_socket->worker->id;
+        l_tun_socket->es = a_es;
+        s_tun_sockets_queue_msg[a_es->worker->id] = dap_events_socket_create_type_queue_ptr_unsafe(a_es->worker, s_tun_recv_msg_callback );
+        s_tun_sockets[a_es->worker->id] = l_tun_socket;
+
+        a_es->_inheritor = l_tun_socket;
+        s_tun_attach_queue( a_es->fd );
+        log_it(L_NOTICE,"New TUN event socket initialized for worker %u" , l_tun_socket->worker_id);
+
+    }else{
+        log_it(L_ERROR, "Can't allocate memory for tun socket");
     }
-    /*    if (fcntl(raw_server->tun_fd, F_SETFL, O_NONBLOCK) < 0){ ;
-     log_it(L_CRITICAL,"Can't switch tun/tap socket into the non-block mode");
-     return NULL;
-     }
-     if (fcntl(raw_server->tun_fd, F_SETFD, FD_CLOEXEC) < 0){;
-     log_it(L_CRITICAL,"Can't switch tun/tap socket to not be passed across execs");
-     return NULL;
-     }
-     */
-    uint8_t *l_tmp_buf;
-    ssize_t tmp_buf_size;
-    static int tun_MTU = 100000; /// TODO Replace with detection of MTU size
-
-    l_tmp_buf = (uint8_t *) alloca(tun_MTU);
-    if ( !l_tmp_buf){ // Can't allocate on stack
-        log_it(L_ERROR,"Can't allocate read buffer on stack, trying to get one from heap");
-        l_tmp_buf = DAP_NEW_SIZE(uint8_t, tun_MTU);
-    }
-    tmp_buf_size = 0;
-    log_it(L_INFO, "Tun/tap thread starts with MTU = %d", tun_MTU);
-
-    fd_set fds_read, fds_read_active;
-    sigset_t l_sig_mask_proc;
-    sigset_t l_sig_mask_orig;
-    sigemptyset (&l_sig_mask_proc);
-    sigaddset (&l_sig_mask_proc, SIGTERM);
-
-
-    FD_ZERO(&fds_read);
-    FD_SET(s_raw_server->tun_fd, &fds_read);
-    FD_SET(get_select_breaker(), &fds_read);
-    /// Main cycle
-    do {
-        fds_read_active = fds_read;
-        int ret = select(FD_SETSIZE, &fds_read_active, NULL, NULL, NULL);
-        //
-        if(ret > 0) {
-            if(FD_ISSET(get_select_breaker(), &fds_read_active)) { // Smth to send
-                ch_vpn_pkt_t* pkt = srv_ch_sf_raw_read();
-                if(pkt) {
-                    int write_ret = write(s_raw_server->tun_fd, pkt->data, pkt->header.op_data.data_size);
-                    if(write_ret > 0) {
-                        //log_it(L_DEBUG, "Wrote out %d bytes to the tun/tap interface", write_ret);
-                    } else {
-                        log_it(L_ERROR, "Tun/tap write %u bytes returned '%s' error, code (%d)",
-                                pkt->header.op_data.data_size, strerror(errno), write_ret);
-                    }
-                }
-            }
-
-            if(FD_ISSET(s_raw_server->tun_fd, &fds_read_active)) {
-                int l_read_ret = read(s_raw_server->tun_fd, l_tmp_buf, tun_MTU);
-                if(l_read_ret < 0) {
-                    log_it(L_CRITICAL, "Tun/tap read returned '%s' error, code (%d)", strerror(errno), l_read_ret);
-                    break;
-                } else {
-                    struct iphdr *iph = (struct iphdr*) l_tmp_buf;
-                    struct in_addr in_daddr, in_saddr;
-                    in_daddr.s_addr = iph->daddr;
-                    in_saddr.s_addr = iph->saddr;
-                    char str_daddr[42], str_saddr[42];
-                    dap_snprintf(str_saddr, sizeof(str_saddr), "%s",inet_ntoa(in_saddr) );
-                    dap_snprintf(str_daddr, sizeof(str_daddr), "%s",inet_ntoa(in_daddr) );
-
-                    //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_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(l_ch_vpn) { // Is present in hash table such destination address
-
-                        if (dap_stream_ch_get_ready_to_read(l_ch_vpn->ch ) ){
-                            dap_chain_net_srv_stream_session_t * l_srv_session = DAP_CHAIN_NET_SRV_STREAM_SESSION (l_ch_vpn->ch->stream->session );
-                            dap_chain_net_srv_usage_t * l_usage = dap_chain_net_srv_usage_find(l_srv_session,  l_ch_vpn->usage_id);
-                            ch_vpn_pkt_t *l_pkt_out = DAP_NEW_Z_SIZE(ch_vpn_pkt_t, sizeof(l_pkt_out->header) + l_read_ret);
-                            l_pkt_out->header.op_code = VPN_PACKET_OP_CODE_VPN_RECV;
-                            l_pkt_out->header.sock_id = s_raw_server->tun_fd;
-                            l_pkt_out->header.usage_id = l_ch_vpn->usage_id;
-                            l_pkt_out->header.op_data.data_size = l_read_ret;
-                            memcpy(l_pkt_out->data, l_tmp_buf, l_read_ret);
-                            dap_stream_ch_pkt_write(l_ch_vpn->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_update_limits(l_ch_vpn->ch,l_srv_session,l_usage, l_read_ret);
-                        }
-                    }
-                    pthread_rwlock_unlock(&s_clients_rwlock);\
-                }
-            }/*else {
-             log_it(L_CRITICAL,"select() has no tun handler in the returned set");
-             break;
-
-             }*/
-        } else {
-            //log_it(L_WARNING, "Select returned %d: %s", ret, strerror(errno));
-            //break;
-        }
-    } while(! s_srv_ch_sf_thread_raw_is_exit );
-    log_it(L_NOTICE, "Raw sockets listen thread is stopped");
-    s_tun_destroy();
-    return NULL;
-}
-
-#ifdef DAP_TUN_IN_WORKER
-void m_es_tun_delete(dap_events_socket_t * a_es, void * arg)
-{
-  log_it(L_WARNING, __PRETTY_FUNCTION__);
-  log_it(L_NOTICE, "Raw sockets listen thread is stopped");
-  dap_events_socket_kill_socket(s_raw_server->tun_events_socket);
-  s_tun_destroy();
 }
 
-void m_es_tun_write(dap_events_socket_t * a_es, void * arg)
-{
-
-}
-
-void m_es_tun_read(dap_events_socket_t * a_es, void * arg)
+/**
+ * @brief s_tun_attach_queue
+ * @param fd
+ * @return
+ */
+static int s_tun_attach_queue(int fd)
 {
-    const static int tun_MTU = 100000; /// TODO Replace with detection of MTU size
-    uint8_t l_tmp_buf[tun_MTU];
-
-    size_t l_read_ret;
-
-
-    l_read_ret = dap_events_socket_read(s_raw_server->tun_events_socket, l_tmp_buf, sizeof(l_tmp_buf));
-
-    if(l_read_ret > 0) {
-        struct iphdr *iph = (struct iphdr*) l_tmp_buf;
-        struct in_addr in_daddr, in_saddr;
-        in_daddr.s_addr = iph->daddr;
-        in_saddr.s_addr = iph->saddr;
-        char str_daddr[42], str_saddr[42];
-        dap_snprintf(str_saddr, sizeof(str_saddr), "%s",inet_ntoa(in_saddr) );
-        dap_snprintf(str_daddr, sizeof(str_daddr), "%s",inet_ntoa(in_daddr) );
-
-        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);
-
-        if(l_ch_vpn) { // Is present in hash table such destination address
-
-            if (dap_stream_ch_get_ready_to_read(l_ch_vpn->ch ) ){
-                dap_chain_net_srv_stream_session_t * l_srv_session = DAP_CHAIN_NET_SRV_STREAM_SESSION (l_ch_vpn->ch->stream->session );
-                dap_chain_net_srv_usage_t * l_usage = dap_chain_net_srv_usage_find(l_srv_session,  l_ch_vpn->usage_id);
-                ch_vpn_pkt_t *l_pkt_out = DAP_NEW_Z_SIZE(ch_vpn_pkt_t, sizeof(l_pkt_out->header) + l_read_ret);
-                l_pkt_out->header.op_code = VPN_PACKET_OP_CODE_VPN_RECV;
-                l_pkt_out->header.sock_id = s_raw_server->tun_fd;
-                l_pkt_out->header.usage_id = l_ch_vpn->usage_id;
-                l_pkt_out->header.op_data.data_size = l_read_ret;
-                memcpy(l_pkt_out->data, l_tmp_buf, l_read_ret);
-                dap_stream_ch_pkt_write(l_ch_vpn->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_update_limits(l_ch_vpn->ch,l_srv_session,l_usage, l_read_ret);
-            }
-        }
-        pthread_rwlock_unlock(&s_clients_rwlock);
-    }
-
-
-    dap_events_socket_set_readable(a_es, true);
+    struct ifreq ifr;
+    memset(&ifr, 0, sizeof(ifr));
+    ifr.ifr_flags = IFF_ATTACH_QUEUE;
+    return ioctl(fd, TUNSETQUEUE, (void *)&ifr);
 }
 
-void m_es_tun_error(dap_events_socket_t * a_es, void * arg)
+/**
+ * @brief s_tun_deattach_queue
+ * @param fd
+ * @return
+ */
+static int s_tun_deattach_queue(int fd)
 {
-  log_it(L_WARNING, __PRETTY_FUNCTION__);
+    struct ifreq ifr;
+    memset(&ifr, 0, sizeof(ifr));
+    ifr.ifr_flags = IFF_DETACH_QUEUE;
+    return ioctl(fd, TUNSETQUEUE, (void *)&ifr);
 }
-#endif
-
diff --git a/modules/service/vpn/dap_chain_net_srv_vpn_cmd.c b/modules/service/vpn/dap_chain_net_srv_vpn_cmd.c
index ce9f46417292427b0b42e8359cd9dbe1e8dddc0f..d676903d06a3d87c6d0dbd4f3930ba43bb5feee3 100644
--- a/modules/service/vpn/dap_chain_net_srv_vpn_cmd.c
+++ b/modules/service/vpn/dap_chain_net_srv_vpn_cmd.c
@@ -230,6 +230,5 @@ int com_vpn_client(int a_argc, char ** a_argv, void *arg_func, char **a_str_repl
 
 int dap_chain_net_srv_vpn_cmd_init()
 {
-
-
+    return 0;
 }
diff --git a/modules/service/vpn/dap_chain_net_vpn_client.c b/modules/service/vpn/dap_chain_net_vpn_client.c
index 41f1d101f801ac05c73c4ff2b55ea76a9b398fe9..35684d2e56e6c2fd1bc18079a7fb36d0a470e75f 100644
--- a/modules/service/vpn/dap_chain_net_vpn_client.c
+++ b/modules/service/vpn/dap_chain_net_vpn_client.c
@@ -81,14 +81,19 @@
 
 static EPOLL_HANDLE sf_socks_epoll_fd;
 
-static ch_vpn_socket_proxy_t *sf_socks = NULL;
-static ch_vpn_socket_proxy_t *sf_socks_client = NULL;
 
 static pthread_mutex_t sf_socks_mutex;
 
 static dap_chain_node_info_t *s_node_info = NULL;
 static dap_chain_node_client_t *s_vpn_client = NULL;
 
+dap_stream_worker_t* dap_chain_net_vpn_client_get_stream_worker(void)
+{
+    if(!s_vpn_client)
+        return NULL;
+    return dap_client_get_stream_worker( s_vpn_client->client );
+}
+
 dap_stream_ch_t* dap_chain_net_vpn_client_get_stream_ch(void)
 {
     if(!s_vpn_client)
@@ -477,8 +482,8 @@ int dap_chain_net_vpn_client_check(dap_chain_net_t *a_net, const char *a_ipv4_st
             l_request->time_connect_ms = l_dtime_connect_ms;
             gettimeofday(&l_request->send_time1, NULL);
             size_t l_request_size = l_request->data_size + sizeof(dap_stream_ch_chain_net_srv_pkt_test_t);
-            dap_stream_ch_pkt_write(l_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_REQUEST, l_request, l_request_size);
-            dap_stream_ch_set_ready_to_write(l_ch, true);
+            dap_stream_ch_pkt_write_unsafe(l_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_REQUEST, l_request, l_request_size);
+            dap_stream_ch_set_ready_to_write_unsafe(l_ch, true);
             DAP_DELETE(l_request);
         }
     }
@@ -568,8 +573,8 @@ int dap_chain_net_vpn_client_start(dap_chain_net_t *a_net, const char *a_ipv4_st
             //dap_chain_hash_fast_t l_request
             //.hdr.tx_cond = a_txCond.value();
 //    	    strncpy(l_request->hdr.token, a_token.toLatin1().constData(),sizeof (l_request->hdr.token)-1);
-            dap_stream_ch_pkt_write(l_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_REQUEST, &l_request, sizeof(l_request));
-            dap_stream_ch_set_ready_to_write(l_ch, true);
+            dap_stream_ch_pkt_write_unsafe(l_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_REQUEST, &l_request, sizeof(l_request));
+            dap_stream_ch_set_ready_to_write_unsafe(l_ch, true);
         }
     }
 
@@ -606,14 +611,6 @@ dap_chain_net_vpn_client_status_t dap_chain_net_vpn_client_status(void)
     return VPN_CLIENT_STATUS_STOPPED;
 }
 
-static void vpn_socket_delete(ch_vpn_socket_proxy_t * sf)
-{
-    close(sf->sock);
-    pthread_mutex_destroy(&(sf->mutex));
-    if(sf)
-        free(sf);
-}
-
 /**
  * @brief dap_chain_net_vpn_client_pkt_in
  * @param a_ch
@@ -664,200 +661,12 @@ void dap_chain_net_vpn_client_pkt_in(dap_stream_ch_t* a_ch, dap_stream_ch_pkt_t*
          a_ch->stream->events_socket->last_ping_request = time(NULL);
          break;
          */
-        default:
-            log_it(L_WARNING, "Can't process SF type 0x%02x", l_sf_pkt->header.op_code);
-        }
-    } else { // All except CONNECT
-        ch_vpn_socket_proxy_t * sf_sock = NULL;
-        if((l_sf_pkt->header.op_code != VPN_PACKET_OP_CODE_CONNECT) // tcp
-        && (l_sf_pkt->header.op_code != VPN_PACKET_OP_CODE_CONNECTED)) { //udp
-
-            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(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 (l_sf_pkt->header.op_code) {
-                case VPN_PACKET_OP_CODE_SEND: {
-                    int ret;
-                    if((ret = send(sf_sock->sock, l_sf_pkt->data, l_sf_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(a_ch)->mutex));
-                        HASH_DEL(CH_VPN(a_ch)->socks, sf_sock);
-                        pthread_mutex_unlock(&( CH_VPN(a_ch)->mutex));
-
-                        pthread_mutex_lock(&sf_socks_mutex);
-                        HASH_DELETE(hh2, sf_socks, sf_sock);
-                        HASH_DELETE(hh_sock, sf_socks_client, sf_sock);
-
-                        struct epoll_event ev = {0, {0}};
-                        ev.data.fd = sf_sock->sock;
-                        ev.events = EPOLLIN;
-                        if(epoll_ctl(sf_socks_epoll_fd, EPOLL_CTL_DEL, sf_sock->sock, &ev) < 0) {
-                            log_it(L_ERROR, "Can't remove sock_id %d from the epoll fd", remote_sock_id);
-                            //stream_ch_pkt_write_f(ch,'i',"sock_id=%d op_code=0x%02x result=-2",sf_pkt->sock_id, sf_pkt->op_code);
-                        } else {
-                            log_it(L_NOTICE, "Removed sock_id %d from the the epoll fd", remote_sock_id);
-                            //stream_ch_pkt_write_f(ch,'i',"sock_id=%d op_code=0x%02x result=0",sf_pkt->sock_id, sf_pkt->op_code);
-                        }
-                        pthread_mutex_unlock(&sf_socks_mutex);
-
-                        vpn_socket_delete(sf_sock);
-                    } else {
-                        sf_sock->bytes_sent += ret;
-                        pthread_mutex_unlock(&sf_sock->mutex);
-                    }
-                    log_it(L_INFO, "Send action from %d sock_id (sf_packet size %lu,  ch packet size %lu, have sent %d)"
-                            , sf_sock->id, l_sf_pkt->header.op_data.data_size, a_pkt->hdr.size, ret);
-                }
-                    break;
-                case VPN_PACKET_OP_CODE_DISCONNECT: {
-                    log_it(L_INFO, "Disconnect action from %d sock_id", sf_sock->id);
-
-                    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(&sf_socks_mutex);
-
-                    HASH_DELETE(hh2, sf_socks, sf_sock);
-                    HASH_DELETE(hh_sock, sf_socks_client, sf_sock);
-
-                    struct epoll_event ev = {0, {0}};
-                    ev.data.fd = sf_sock->sock;
-                    ev.events = EPOLLIN;
-                    if(epoll_ctl(sf_socks_epoll_fd, EPOLL_CTL_DEL, sf_sock->sock, &ev) < 0) {
-                        log_it(L_ERROR, "Can't remove sock_id %d to the epoll fd", remote_sock_id);
-                        //stream_ch_pkt_write_f(ch,'i',"sock_id=%d op_code=%uc result=-2",sf_pkt->sock_id, sf_pkt->op_code);
-                    } else {
-                        log_it(L_NOTICE, "Removed sock_id %d from the epoll fd", remote_sock_id);
-                        //stream_ch_pkt_write_f(ch,'i',"sock_id=%d op_code=%uc result=0",sf_pkt->sock_id, sf_pkt->op_code);
-                    }
-                    pthread_mutex_unlock(&sf_socks_mutex);
-
-                    pthread_mutex_unlock(&sf_sock->mutex);
-                    vpn_socket_delete(sf_sock);
-                }
-                    break;
-                default: {
-                    log_it(L_WARNING, "Unprocessed op code 0x%02x", l_sf_pkt->header.op_code);
-                    pthread_mutex_unlock(&sf_sock->mutex);
-                }
-                }
-            } else
-                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(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 =
-                        (l_sf_pkt->header.op_connect.addr_size > (sizeof(addr_str) - 1)) ?
-                                (sizeof(addr_str) - 1) :
-                                l_sf_pkt->header.op_connect.addr_size;
-                memset(&remote_addr, 0, sizeof(remote_addr));
-                remote_addr.sin_family = AF_INET;
-                remote_addr.sin_port = htons(l_sf_pkt->header.op_connect.port);
-
-                memcpy(addr_str, l_sf_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, l_sf_pkt->header.op_connect.port,
-                        l_sf_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, l_sf_pkt->header.op_connect.port);
-
-                    ch_vpn_pkt_t *l_pkt_out = DAP_NEW_Z(ch_vpn_pkt_t);
-                    l_pkt_out->header.op_code = VPN_PACKET_OP_CODE_PROBLEM;
-
-                    dap_stream_ch_pkt_write(a_ch, 'd', l_pkt_out,
-                            l_pkt_out->header.op_data.data_size + sizeof(l_pkt_out->header));
-                    dap_stream_ch_set_ready_to_write(a_ch, true);
-
-                    free(l_pkt_out);
-
-                } else {
-                    int s;
-                    if((s = socket(AF_INET,
-                            (l_sf_pkt->header.op_code == VPN_PACKET_OP_CODE_CONNECT) ?
-                            SOCK_STREAM :
-                                                                                       SOCK_DGRAM, 0)) >= 0) {
-                        log_it(L_DEBUG, "Socket is created (%d)", s);
-                        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,
-                                    l_sf_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 = a_ch;
-                            pthread_mutex_init(&sf_sock->mutex, NULL);
-
-                            pthread_mutex_lock(&sf_socks_mutex);
-                            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);
-                            log_it(L_DEBUG, "Added %d sock_id with sock %d to the hash table", sf_sock->id,
-                                    sf_sock->sock);
-                            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(&( CH_VPN(a_ch)->mutex));
-                            pthread_mutex_unlock(&sf_socks_mutex);
-
-                            struct epoll_event ev = { 0, {0} };
-                            ev.data.fd = s;
-                            ev.events = EPOLLIN | EPOLLERR;
-
-                            if(epoll_ctl(sf_socks_epoll_fd, EPOLL_CTL_ADD, s, &ev) == -1) {
-                                log_it(L_ERROR, "Can't add sock_id %d to the epoll fd", remote_sock_id);
-                                //stream_ch_pkt_write_f(ch,'i',"sock_id=%d op_code=%uc result=-2",sf_pkt->sock_id, sf_pkt->op_code);
-                            } else {
-                                log_it(L_NOTICE, "Added sock_id %d  with sock %d to the epoll fd", remote_sock_id, s);
-                                //stream_ch_pkt_write_f(ch,'i',"sock_id=%d op_code=%uc result=0",sf_pkt->sock_id, sf_pkt->op_code);
-                            }
-                            dap_stream_ch_set_ready_to_write(a_ch, true);
-                        } else {
-                            ch_vpn_pkt_t *l_pkt_out = (ch_vpn_pkt_t*) calloc(1, sizeof(l_pkt_out->header));
-                            l_pkt_out->header.op_code = VPN_PACKET_OP_CODE_PROBLEM;
-
-                            dap_stream_ch_pkt_write(a_ch, 'd', l_pkt_out,
-                                    l_pkt_out->header.op_data.data_size + sizeof(l_pkt_out->header));
-                            dap_stream_ch_set_ready_to_write(a_ch, true);
-
-                            free(l_pkt_out);
-
-                            log_it(L_INFO, "Can't connect to the remote server %s", addr_str);
-                            dap_stream_ch_pkt_write_f(a_ch, 'i', "sock_id=%d op_code=%c result=-1",
-                                    l_sf_pkt->header.sock_id, l_sf_pkt->header.op_code);
-                            dap_stream_ch_set_ready_to_write(a_ch, true);
-
-                        }
-                    } else {
-                        log_it(L_ERROR, "Can't create the socket");
-                        ch_vpn_pkt_t *l_pkt_out = (ch_vpn_pkt_t*) calloc(1, sizeof(l_pkt_out->header));
-                        l_pkt_out->header.op_code = VPN_PACKET_OP_CODE_PROBLEM;
-
-                        dap_stream_ch_pkt_write(a_ch, 'd', l_pkt_out,
-                                l_pkt_out->header.op_data.data_size + sizeof(l_pkt_out->header));
-                        dap_stream_ch_set_ready_to_write(a_ch, true);
-
-                        free(l_pkt_out);
-
-                    }
-                }
-            }
+            default:
+                log_it(L_WARNING, "Can't process SF type 0x%02x", l_sf_pkt->header.op_code);
         }
+
     }
+
 }
 
 /**
@@ -866,57 +675,6 @@ void dap_chain_net_vpn_client_pkt_in(dap_stream_ch_t* a_ch, dap_stream_ch_pkt_t*
  */
 void dap_chain_net_vpn_client_pkt_out(dap_stream_ch_t* a_ch)
 {
-    ch_vpn_socket_proxy_t * l_cur = NULL, *l_tmp;
-    bool l_is_smth_out = false;
-//    log_it(L_DEBUG,"Socket forwarding packet out callback: %u sockets in hashtable", HASH_COUNT(CH_VPN(ch)->socks) );
-    HASH_ITER(hh, CH_VPN(a_ch)->socks , l_cur, l_tmp)
-    {
-        bool l_signal_to_break = false;
-        pthread_mutex_lock(&(l_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(l_cur->pkt_out_size) {
-            for(i = 0; i < l_cur->pkt_out_size; i++) {
-                ch_vpn_pkt_t * pout = l_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;
-                        if(pout)
-                            free(pout);
-                        l_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(l_signal_to_break) {
-            pthread_mutex_unlock(&(l_cur->mutex));
-            break;
-        }
-        l_cur->pkt_out_size = 0;
-        if(l_cur->signal_to_delete) {
-            log_it(L_NOTICE, "Socket id %d got signal to be deleted", l_cur->id);
-            pthread_mutex_lock(&( CH_VPN(a_ch)->mutex));
-            HASH_DEL(CH_VPN(a_ch)->socks, l_cur);
-            pthread_mutex_unlock(&( CH_VPN(a_ch)->mutex));
-
-            pthread_mutex_lock(&(sf_socks_mutex));
-            HASH_DELETE(hh2, sf_socks, l_cur);
-            HASH_DELETE(hh_sock, sf_socks_client, l_cur);
-            pthread_mutex_unlock(&(sf_socks_mutex));
-
-            pthread_mutex_unlock(&(l_cur->mutex));
-            vpn_socket_delete(l_cur);
-        } else
-            pthread_mutex_unlock(&(l_cur->mutex));
-    }
     /*    ch->writable = isSmthOut;
      if(isSmthOut) {
      if(ch->stream->conn_http)
@@ -944,5 +702,4 @@ int dap_chain_net_vpn_client_init(dap_config_t * g_config)
 
 void dap_chain_net_vpn_client_deinit()
 {
-    pthread_mutex_destroy(&sf_socks_mutex);
 }
diff --git a/modules/service/vpn/dap_chain_net_vpn_client_tun.c b/modules/service/vpn/dap_chain_net_vpn_client_tun.c
index cde51a32662596848ce826e6fe2974f3d045177e..ca890bcfc029c4cf4b47e4cc8844dac5dec5096f 100644
--- a/modules/service/vpn/dap_chain_net_vpn_client_tun.c
+++ b/modules/service/vpn/dap_chain_net_vpn_client_tun.c
@@ -46,6 +46,7 @@
 #include "dap_strfuncs.h"
 #include "dap_stream.h"
 #include "dap_stream_ch_pkt.h"
+#include "dap_client.h"
 
 #include <arpa/inet.h>
 #include <fcntl.h>
@@ -71,7 +72,6 @@ static char *s_cur_ipv4_server = NULL;
 static const char *s_conn_name = "nodeVPNClient";
 static char *s_last_used_connection_name = NULL, *s_last_used_connection_device = NULL;
 
-static pthread_t s_thread_read_tun_id;
 static pthread_mutex_t s_clients_mutex;
 static dap_events_socket_t * s_tun_events_socket = NULL;
 
@@ -230,137 +230,6 @@ static bool is_local_address(const char *a_address)
 
 }
 
-/**
- * Thread for read from /dev/net/tun
- */
-static void* thread_read_tun(void *arg)
-{
-    //srv_ch_sf_tun_create();
-
-    if(s_fd_tun <= 0) {
-        log_it(L_CRITICAL, "Tun/tap file descriptor is not initialized");
-        return NULL;
-    }
-    /*    if (fcntl(raw_server->tun_fd, F_SETFL, O_NONBLOCK) < 0){ ;
-     log_it(L_CRITICAL,"Can't switch tun/tap socket into the non-block mode");
-     return NULL;
-     }
-     if (fcntl(raw_server->tun_fd, F_SETFD, FD_CLOEXEC) < 0){;
-     log_it(L_CRITICAL,"Can't switch tun/tap socket to not be passed across execs");
-     return NULL;
-     }
-     */
-    uint8_t *tmp_buf;
-//    ssize_t tmp_buf_size;
-    static int tun_MTU = 100000; /// TODO Replace with detection of MTU size
-
-    tmp_buf = (uint8_t *) calloc(1, tun_MTU);
-//    tmp_buf_size = 0;
-    log_it(L_INFO, "Tun/tap thread starts with MTU = %d", tun_MTU);
-
-    fd_set fds_read, fds_read_active;
-
-    FD_ZERO(&fds_read);
-    FD_SET(s_fd_tun, &fds_read);
-    FD_SET(get_select_breaker(), &fds_read);
-    /// Main cycle
-    do {
-        fds_read_active = fds_read;
-        int ret = select(FD_SETSIZE, &fds_read_active, NULL, NULL, NULL);
-        //
-        if(ret > 0) {
-            if(FD_ISSET(get_select_breaker(), &fds_read_active)) { // Smth to send
-                ch_vpn_pkt_t* pkt = NULL; //TODO srv_ch_sf_raw_read();
-                if(pkt) {
-                    int write_ret = write(s_fd_tun, pkt->data, pkt->header.op_data.data_size);
-                    if(write_ret > 0) {
-                        log_it(L_DEBUG, "Wrote out %d bytes to the tun/tap interface", write_ret);
-                    } else {
-                        log_it(L_ERROR, "Tun/tap write %u bytes returned '%s' error, code (%d)",
-                                pkt->header.op_data.data_size, strerror(errno), write_ret);
-                    }
-                }
-            }
-            // there is data in tun for sent to vpn server
-            if(FD_ISSET(s_fd_tun, &fds_read_active)) {
-                int read_ret = read(s_fd_tun, tmp_buf, tun_MTU);
-                if(read_ret < 0) {
-                    log_it(L_CRITICAL, "Tun/tap read returned '%s' error, code (%d)", strerror(errno), read_ret);
-                    break;
-                } else {
-                    struct iphdr *iph = (struct iphdr*) tmp_buf;
-                    struct in_addr in_daddr, in_saddr;
-                    // destination address
-                    in_daddr.s_addr = iph->daddr;
-                    // source address
-                    in_saddr.s_addr = iph->saddr;
-                    char str_daddr[42], str_saddr[42];
-                    strncpy(str_saddr, inet_ntoa(in_saddr), sizeof(str_saddr));
-                    strncpy(str_daddr, inet_ntoa(in_daddr), sizeof(str_daddr));
-
-                    if(iph->tot_len > (uint16_t) read_ret) {
-                        log_it(L_INFO, "Tun/Tap interface returned only the fragment (tot_len =%u  read_ret=%d) ",
-                                iph->tot_len, read_ret);
-                    }
-                    if(iph->tot_len < (uint16_t) read_ret) {
-                        log_it(L_WARNING, "Tun/Tap interface returned more then one packet (tot_len =%u  read_ret=%d) ",
-                                iph->tot_len, read_ret);
-                    }
-
-                    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_client_t *l_client = l_vpn_client ? l_vpn_client->client : NULL;
-                    //DAP_CLIENT_PVT(l_client);
-                    //dap_stream_ch_vpn_remote_single_t * raw_client = l_client->;
-
-//                    HASH_FIND_INT(raw_server->clients, &in_daddr.s_addr, raw_client);
-                    //                  HASH_ADD_INT(CH_SF(ch)->socks, id, sf_sock );
-                    //                  HASH_DEL(CH_SF(ch)->socks,sf_sock);
-//                    if(l_stream) { // Is present in hash table such destination address
-                    dap_stream_ch_t *l_stream = dap_chain_net_vpn_client_get_stream_ch();
-                    if(l_stream) {
-                        // form packet to vpn-server
-                        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_SEND; //VPN_PACKET_OP_CODE_VPN_RECV
-                        pkt_out->header.sock_id = s_fd_tun;
-                        pkt_out->header.op_data.data_size = read_ret;
-                        memcpy(pkt_out->data, tmp_buf, read_ret);
-
-                        pthread_mutex_lock(&s_clients_mutex);
-                        // sent packet to vpn server
-                        dap_stream_ch_pkt_write(l_stream, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pkt_out,
-                                pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
-                        dap_stream_ch_set_ready_to_write(l_stream, true);
-                        pthread_mutex_unlock(&s_clients_mutex);
-
-                        DAP_DELETE(pkt_out);
-                    }
-                    else {
-                        log_it(L_DEBUG, "No remote client for income IP packet with addr %s", inet_ntoa(in_daddr));
-                    }
-
-                }
-            }/*else {
-             log_it(L_CRITICAL,"select() has no tun handler in the returned set");
-             break;
-
-             }*/
-        } else {
-            log_it(L_CRITICAL, "Select returned %d", ret);
-            break;
-        }
-    } while(1);
-    log_it(L_NOTICE, "Raw sockets listen thread is stopped");
-    // close tun
-    if(s_fd_tun > 0) {
-        int l_fd_tun = s_fd_tun;
-        s_fd_tun = 0;
-        close(l_fd_tun);
-    }
-
-    return NULL;
-}
 
 int dap_chain_net_vpn_client_tun_init(const char *a_ipv4_server_str)
 {
@@ -393,7 +262,7 @@ static void m_client_tun_read(dap_events_socket_t * a_es, void * arg)
     log_it(L_WARNING, __PRETTY_FUNCTION__);
 
     do{
-        l_read_ret = dap_events_socket_read(a_es, l_tmp_buf, sizeof(l_tmp_buf));
+        l_read_ret = dap_events_socket_pop_from_buf_in(a_es, l_tmp_buf, sizeof(l_tmp_buf));
 
         if(l_read_ret > 0) {
             struct iphdr *iph = (struct iphdr*) l_tmp_buf;
@@ -404,8 +273,8 @@ static void m_client_tun_read(dap_events_socket_t * a_es, void * arg)
             dap_snprintf(str_saddr, sizeof(str_saddr), "%s",inet_ntoa(in_saddr) );
             dap_snprintf(str_daddr, sizeof(str_daddr), "%s",inet_ntoa(in_daddr) );
 
-            dap_stream_ch_t *l_stream = dap_chain_net_vpn_client_get_stream_ch();
-            if(l_stream) {
+            dap_stream_ch_t *l_ch = dap_chain_net_vpn_client_get_stream_ch();
+            if(l_ch) {
                 // form packet to vpn-server
                 ch_vpn_pkt_t *pkt_out = (ch_vpn_pkt_t*) calloc(1, sizeof(pkt_out->header) + l_read_ret);
                 pkt_out->header.op_code = VPN_PACKET_OP_CODE_VPN_SEND; //VPN_PACKET_OP_CODE_VPN_RECV
@@ -415,9 +284,8 @@ static void m_client_tun_read(dap_events_socket_t * a_es, void * arg)
 
                 pthread_mutex_lock(&s_clients_mutex);
                 // sent packet to vpn server
-                dap_stream_ch_pkt_write(l_stream, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pkt_out,
+                dap_stream_ch_pkt_write_mt(l_ch->stream_worker,l_ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, pkt_out,
                         pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
-                dap_stream_ch_set_ready_to_write(l_stream, true);
                 pthread_mutex_unlock(&s_clients_mutex);
 
                 DAP_DELETE(pkt_out);
@@ -428,12 +296,12 @@ static void m_client_tun_read(dap_events_socket_t * a_es, void * arg)
         }
     }while(l_read_ret > 0);
 
-    dap_events_socket_set_readable(a_es, true);
+    dap_events_socket_set_readable_unsafe(a_es, true);
 }
 
-static void m_client_tun_error(dap_events_socket_t * a_es, void * arg)
+static void m_client_tun_error(dap_events_socket_t * a_es, int a_arg)
 {
-  log_it(L_DEBUG, __PRETTY_FUNCTION__);
+  log_it(L_WARNING, " TUN client problems: code %d", a_arg);
 }
 
 int dap_chain_net_vpn_client_tun_create(const char *a_ipv4_addr_str, const char *a_ipv4_gw_str)
@@ -543,26 +411,19 @@ int dap_chain_net_vpn_client_tun_create(const char *a_ipv4_addr_str, const char
 
     pthread_mutex_init(&s_clients_mutex, NULL);
 
-    if(is_dap_tun_in_worker()) {
+    static dap_events_socket_callbacks_t l_s_callbacks = {
+            .read_callback = m_client_tun_read,// for server
+            .write_callback = m_client_tun_write,// for client
+            .error_callback = m_client_tun_error,
+            .delete_callback = m_client_tun_delete
+    };
 
-        static dap_events_socket_callbacks_t l_s_callbacks = {
-                .read_callback = m_client_tun_read,// for server
-                .write_callback = m_client_tun_write,// for client
-                .error_callback = m_client_tun_error,
-                .delete_callback = m_client_tun_delete
-        };
-
-        s_tun_events_socket = dap_events_socket_wrap_no_add(NULL, s_fd_tun, &l_s_callbacks);
-        s_tun_events_socket->type = DESCRIPTOR_TYPE_FILE;
-        dap_events_socket_create_after(s_tun_events_socket);
-        s_tun_events_socket->_inheritor = NULL;
-
-        return 0;
-    }
-    else {
-        pthread_create(&s_thread_read_tun_id, NULL, thread_read_tun, NULL);
-    }
+    s_tun_events_socket = dap_events_socket_wrap_no_add(dap_events_get_default(), s_fd_tun, &l_s_callbacks);
+    s_tun_events_socket->type = DESCRIPTOR_TYPE_FILE;
+    dap_worker_add_events_socket_auto(s_tun_events_socket);
+    s_tun_events_socket->_inheritor = NULL;
 
+    //return 0;
 
     //m_tunDeviceName = dev;
     //m_tunSocket = fd;
@@ -571,10 +432,9 @@ int dap_chain_net_vpn_client_tun_create(const char *a_ipv4_addr_str, const char
 
 int dap_chain_net_vpn_client_tun_delete(void)
 {
-    if(is_dap_tun_in_worker())
-    {
+    if(s_tun_events_socket) {
         pthread_mutex_lock(&s_clients_mutex);
-        dap_events_socket_kill_socket(s_tun_events_socket);
+        dap_events_socket_remove_and_delete_mt(s_tun_events_socket->worker, s_tun_events_socket);
         s_tun_events_socket = NULL;
         pthread_mutex_unlock(&s_clients_mutex);
     }
@@ -663,69 +523,57 @@ static void ch_sf_pkt_send(dap_stream_ch_t * a_ch, void * a_data, size_t a_data_
     }
     l_pkt_out = DAP_NEW_Z_SIZE(ch_vpn_pkt_t, l_pkt_out_size);
     l_pkt_out->header.op_code = VPN_PACKET_OP_CODE_VPN_RECV;
-    l_pkt_out->header.sock_id = a_ch->stream->events_socket->socket;
+    l_pkt_out->header.sock_id = a_ch->stream->esocket->socket;
     l_pkt_out->header.op_data.data_size = a_data_size;
     memcpy(l_pkt_out->data, a_data, a_data_size);
-    dap_stream_ch_pkt_write(a_ch, 'd', l_pkt_out, l_pkt_out_size);
-    dap_stream_ch_set_ready_to_write(a_ch, true);
+    dap_stream_ch_pkt_write_unsafe(a_ch, 'd', l_pkt_out, l_pkt_out_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;
-     default: passPacket=true;
-     }*/
-//    log_it(L_DEBUG,"==== ch_sf_tun_send()");
-    if(passPacket) {
-//        log_it(L_DEBUG,"==== ch_sf_tun_send() ++");
-        struct in_addr in_saddr, in_daddr, in_daddr_net;
-        in_saddr.s_addr = ((struct iphdr*) pkt_data)->saddr;
-        in_daddr.s_addr = ((struct iphdr*) pkt_data)->daddr;
-        in_daddr_net.s_addr = ch_sf->ch->stream->session->tun_client_addr.s_addr; //in_daddr_net.s_addr = in_daddr.s_addr & m_tun_server->int_network_mask.s_addr;
-        char * in_daddr_str = strdup(inet_ntoa(in_daddr));
-        char * in_saddr_str = strdup(inet_ntoa(in_saddr));
-
-        dap_stream_ch_t * l_route_ch = NULL; //ch_sf_peer_ch_find(ch_sf->ch->stream->session, pkt_data, pkt_data_size);
-
-        if(l_route_ch) {
-//            log_it(L_DEBUG, "Route packet %s=>%s to %d socket", in_saddr_str,in_daddr_str,l_route_ch->stream->events_socket->socket);
-            ch_sf_pkt_send(l_route_ch, pkt_data, pkt_data_size);
-//        }else /*if(m_tun_server->int_network.s_addr != in_daddr_net.s_addr )*/{ // No ways to route so write it out to the OS network stack
-//        }else if(ch_sf_peer_ch_find(NULL, pkt_data,pkt_data_size)){ // No ways to route so write it out to the OS network stack
-        } else { // if(!ch_sf_peer_ch_check(pkt_data,pkt_data_size)){ // No ways to route so write it out to the OS network stack
-            int ret;
-//            log_it(L_DEBUG, "Route packet %s=>%s size %u to the OS network stack",in_saddr_str,
-//                   in_daddr_str,pkt_data_size);
-            //if( ch_sf_raw_write(STREAM_SF_PACKET_OP_CODE_RAW_SEND, sf_pkt->data, sf_pkt->op_data.data_size)<0){
-            struct sockaddr_in sin = { 0 };
-            sin.sin_family = AF_INET;
-            sin.sin_port = 0;
-            sin.sin_addr.s_addr = in_daddr.s_addr;
-            if((ret = sendto(ch_sf->raw_l3_sock, pkt_data, pkt_data_size, 0, (struct sockaddr *) &sin, sizeof(sin)))
-                    < 0) {
-                //    if((ret = write(raw_server->tun_fd, sf_pkt->data, sf_pkt->header.op_data.data_size))<0){
-                log_it(L_ERROR, "write() returned error %d : '%s'", ret, strerror(errno));
-                //log_it(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_fd_tun;
-                dap_stream_ch_pkt_write(ch_sf->ch, 'd', pkt_out,
-                        pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
-                dap_stream_ch_set_ready_to_write(ch_sf->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);
-            }
-        }/*else log_it(L_ERROR,"I don't know what to do with packet");*/
-
-        if(in_daddr_str)
-            free(in_daddr_str);
-        if(in_saddr_str)
-            free(in_saddr_str);
+/**
+ * @brief ch_sf_tun_send
+ * @param ch_sf
+ * @param pkt_data
+ * @param pkt_data_size
+ */
+void ch_sf_tun_client_send(dap_chain_net_srv_ch_vpn_t * ch_sf, void * pkt_data, size_t pkt_data_size) {
+    log_it(L_CRITICAL, "Unimplemented tun_client_send");
+
+    struct in_addr in_saddr, in_daddr, in_daddr_net;
+    in_saddr.s_addr = ((struct iphdr*) pkt_data)->saddr;
+    in_daddr.s_addr = ((struct iphdr*) pkt_data)->daddr;
+    in_daddr_net.s_addr = ch_sf->ch->stream->session->tun_client_addr.s_addr; //in_daddr_net.s_addr = in_daddr.s_addr & m_tun_server->int_network_mask.s_addr;
+    char * in_daddr_str = strdup(inet_ntoa(in_daddr));
+    char * in_saddr_str = strdup(inet_ntoa(in_saddr));
+
+    int ret;
+    //            log_it(L_DEBUG, "Route packet %s=>%s size %u to the OS network stack",in_saddr_str,
+    //                   in_daddr_str,pkt_data_size);
+    //if( ch_sf_raw_write(STREAM_SF_PACKET_OP_CODE_RAW_SEND, sf_pkt->data, sf_pkt->op_data.data_size)<0){
+    struct sockaddr_in sin = { 0 };
+    sin.sin_family = AF_INET;
+    sin.sin_port = 0;
+    sin.sin_addr.s_addr = in_daddr.s_addr;
+    if((ret = /*sendto(ch_sf->raw_l3_sock, pkt_data, pkt_data_size, 0, (struct sockaddr *) &sin, sizeof(sin))*/-1  )
+            < 0) {
+        //    if((ret = write(raw_server->tun_fd, sf_pkt->data, sf_pkt->header.op_data.data_size))<0){
+        log_it(L_ERROR, "write() returned error %d : '%s'", ret, strerror(errno));
+        //log_it(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_fd_tun;
+        dap_stream_ch_pkt_write_unsafe(ch_sf->ch, 'd', pkt_out,
+                pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
+    } 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);
     }
+
+    if(in_daddr_str)
+    free(in_daddr_str);
+    if(in_saddr_str)
+    free(in_saddr_str);
 }
 
 /**
@@ -758,79 +606,13 @@ int ch_sf_tun_addr_leased(dap_chain_net_srv_ch_vpn_t * a_sf, ch_vpn_pkt_t * a_pk
 
     char l_addr_buf[INET_ADDRSTRLEN];
     char l_gw_buf[INET_ADDRSTRLEN];
-    //char l_netmask_buf[INET_ADDRSTRLEN];
-    //char l_netaddr_buf[INET_ADDRSTRLEN];
     inet_ntop(AF_INET, &l_addr, l_addr_buf, sizeof(l_addr_buf));
     inet_ntop(AF_INET, &l_gw, l_gw_buf, sizeof(l_gw_buf));
-    //inet_ntop(AF_INET, &l_netmask, l_netmask_buf, sizeof(l_netmask_buf));
-    //inet_ntop(AF_INET, &l_netaddr, l_netaddr_buf, sizeof(l_netaddr_buf));
+    log_it(L_INFO,"Leased address %s with gateway %s", l_addr, l_gw_buf);
 
     // start new tun connection with vpn address and vpn gateway
     int l_res = dap_chain_net_vpn_client_tun_create(l_addr_buf, l_gw_buf);
     return l_res;
 
-    //log_it(L_DEBUG, "Raw IP packet daddr:%s saddr:%s  %u from %d bytes sent to tun/tap interface",
-
-//    n_client->addr = l_addr.s_addr;
-//    if(a_sf->ch->stream->session) {
-//        a_sf->ch->stream->session->tun_client_addr.s_addr = l_addr.s_addr;
-//        a_sf->ch->stream->session->tun_client_gw.s_addr = l_gw.s_addr;
-//        a_sf->ch->stream->session->tun_client_mask.s_addr = l_netmask.s_addr;
-//    }
-//    HASH_ADD_INT(m_tun_server->clients, addr, n_client);
-//    char l_addr_buf[INET_ADDRSTRLEN];
-//    char l_netmask_buf[INET_ADDRSTRLEN];
-//    char l_netaddr_buf[INET_ADDRSTRLEN];
-//    char l_gw_buf[INET_ADDRSTRLEN];
-//    char* err;
-//    pthread_mutex_unlock(&m_tun_server->clients_mutex);
-//    inet_ntop(AF_INET, &l_addr, l_addr_buf, sizeof(l_addr_buf));
-//    inet_ntop(AF_INET, &l_gw, l_gw_buf, sizeof(l_gw_buf));
-//    inet_ntop(AF_INET, &l_netmask, l_netmask_buf, sizeof(l_netmask_buf));
-//    inet_ntop(AF_INET, &l_netaddr, l_netaddr_buf, sizeof(l_netaddr_buf));
-//    log_it(L_NOTICE, "Registred tunnel %s=>%s  to %s/%s via remote socket %d", l_addr_buf, l_gw_buf, l_netaddr_buf,
-//            l_netmask_buf,
-//            a_sf->ch->stream->events_socket->socket);
-//    if(a_sf->ch->stream->is_client_to_uplink) {
-//        log_it(L_NOTICE, "Assign address %s to the network device %s", l_addr_buf, m_tun_server->ifr.ifr_name);
-//        if(exec_with_ret_f(&err, "ip address add %s/%s dev %s", l_addr_buf, l_netmask_buf, m_tun_server->ifr.ifr_name))
-//                {
-//            log_it(L_ERROR,
-//                    "Can't assign ip address, leased from remote server. Routing to the remote network will not work");
-//            log_it(L_ERROR, "exec returns: '%s'", err);
-//        }
-//        ch_sf_tun_peer_add(a_sf, l_addr.s_addr, l_gw.s_addr, l_netmask.s_addr & l_gw.s_addr, l_netmask.s_addr);
-//
-//        size_t i;
-//        log_it(L_DEBUG, "Found %u networks in reply", l_route_net_count);
-//        for(i = 0; i < l_route_net_count; i++) {
-//            in_addr_t l_r_netaddr;
-//            in_addr_t l_r_netmask;
-//
-//            memcpy(&l_r_netaddr, a_pkt->data + (3 + i * 2) * sizeof(in_addr_t), sizeof(in_addr_t));
-//            memcpy(&l_r_netmask, a_pkt->data + (4 + i * 2) * sizeof(in_addr_t), sizeof(in_addr_t));
-//
-//            if(!l_r_netaddr && !l_r_netmask) {
-//                log_it(L_DEBUG, "Ignores default route from upstream");
-//                continue;
-//            }
-//
-////            ch_sf_tun_peer_add(a_sf, 0,0,l_r_netaddr,l_r_netmask);
-//            ch_sf_tun_peer_add(a_sf, l_r_netaddr, l_r_netmask, l_r_netaddr, l_r_netmask);
-//            inet_ntop(AF_INET, &l_r_netmask, l_netmask_buf, sizeof(l_netmask_buf));
-//            inet_ntop(AF_INET, &l_r_netaddr, l_netaddr_buf, sizeof(l_netaddr_buf));
-//
-////            if(!l_r_netaddr && !l_r_netmask){
-////                log_it(L_DEBUG,"Ignores default route from upstream");
-////                log_it(L_DEBUG," %s/%s ",l_netaddr_buf, l_netmask_buf);
-////                continue;
-////            }
-//
-//            char *l_cmd = dap_strdup_printf("route add -net %s netmask %s dev %s metric 2",
-//                    l_netaddr_buf, l_netmask_buf, m_tun_server->ifr.ifr_ifrn.ifrn_name);
-//            exe_bash_cmd(l_cmd);
-//        }
-//
-//    }
 }
 
diff --git a/modules/service/vpn/include/dap_chain_net_srv_vpn.h b/modules/service/vpn/include/dap_chain_net_srv_vpn.h
index b7896676fff8a42a18709dc31cf44262feeb9214..a073dbad18162e85af65f5412ef320c5bad25e10 100644
--- a/modules/service/vpn/include/dap_chain_net_srv_vpn.h
+++ b/modules/service/vpn/include/dap_chain_net_srv_vpn.h
@@ -26,10 +26,13 @@
 #pragma once
 #ifdef DAP_OS_UNIX
 #include <netinet/in.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
 #endif
 
 #include "dap_config.h"
 #include "dap_chain_net_srv.h"
+#include "dap_events.h"
 
 
 #define DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_CLIENT    0x01
@@ -87,36 +90,35 @@ typedef struct ch_vpn_pkt {
             } raw; // Raw access to OP bytes
         };
     } DAP_ALIGN_PACKED header;
-    uint8_t data[]; // Binary data nested by packet
+    byte_t data[]; // Binary data nested by packet
 }DAP_ALIGN_PACKED ch_vpn_pkt_t;
 
-/**
- * @struct ch_vpn_socket_proxy
- * @brief Internal data storage for single socket proxy functions. Usualy helpfull for\
-  *        port forwarding or for protecting single application's connection
- *
- **/
-typedef struct ch_vpn_socket_proxy {
-    int id;
-    int sock;
-    struct in_addr client_addr; // Used in raw L3 connections
-    pthread_mutex_t mutex;
-    dap_stream_ch_t * ch;
+typedef struct ch_sf_tun_socket ch_sf_tun_socket_t;
+typedef struct dap_chain_net_srv_ch_vpn dap_chain_net_srv_ch_vpn_t;
 
-    bool signal_to_delete;
-    ch_vpn_pkt_t * pkt_out[100];
-    size_t pkt_out_size;
 
-    uint64_t bytes_sent;
-    uint64_t bytes_recieved;
+// Copy is present on each tun socket
+typedef struct usage_client {
+    dap_chain_net_srv_ch_vpn_t * ch_vpn;
+    dap_chain_datum_tx_receipt_t * receipt;
+    size_t receipt_size;
+    uint32_t usage_id;
+    dap_chain_net_srv_t * srv;
+    ch_sf_tun_socket_t * tun_socket;
+    UT_hash_handle hh;
+} usage_client_t;
 
-    time_t time_created;
-    time_t time_lastused;
+typedef struct dap_chain_net_srv_ch_vpn_info dap_chain_net_srv_ch_vpn_info_t;
 
-    UT_hash_handle hh;
-    UT_hash_handle hh2;
-    UT_hash_handle hh_sock;
-} ch_vpn_socket_proxy_t;
+typedef struct ch_sf_tun_socket {
+    uint8_t worker_id;
+    dap_worker_t * worker;
+    dap_events_socket_t * es;
+    dap_chain_net_srv_ch_vpn_info_t * clients; // Remote clients identified by destination address
+    //UT_hash_handle hh;
+}ch_sf_tun_socket_t;
+
+#define CH_SF_TUN_SOCKET(a) ((ch_sf_tun_socket_t*) a->_inheritor )
 
 
 /**
@@ -130,16 +132,27 @@ typedef struct dap_chain_net_srv_ch_vpn
     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;
+    ch_sf_tun_socket_t * tun_socket;
 
     struct in_addr addr_ipv4;
     dap_stream_ch_t * ch;
     UT_hash_handle hh;
 } dap_chain_net_srv_ch_vpn_t;
 
+typedef struct dap_chain_net_srv_ch_vpn_info
+{
+    struct in_addr addr_ipv4;
+    bool is_on_this_worker;
+    bool is_reassigned_once;//Copy of esocket was_reassigned field. Used
+                            // to prevent jumping on systems without FlowControl
+    uint32_t usage_id;
+    dap_chain_net_srv_ch_vpn_t * ch_vpn;
+    dap_events_socket_t * queue_msg; // Message queue
+    dap_worker_t * worker;
+    dap_events_socket_t * esocket;
+    UT_hash_handle hh;
+}dap_chain_net_srv_ch_vpn_info_t;
 
 typedef struct dap_chain_net_srv_vpn_item_ipv4{
     struct in_addr addr;
@@ -155,8 +168,6 @@ typedef struct dap_chain_net_srv_vpn
 
 #define CH_VPN(a) ((dap_chain_net_srv_ch_vpn_t *) ((a)->internal) )
 
-bool is_dap_tun_in_worker(void);
-
 int dap_chain_net_srv_client_vpn_init(dap_config_t * g_config);
 
 int dap_chain_net_srv_vpn_init(dap_config_t * g_config);
diff --git a/modules/service/vpn/include/dap_chain_net_vpn_client.h b/modules/service/vpn/include/dap_chain_net_vpn_client.h
index c97f694c0adbdc5e1243d759b2ba1c63dc8d5246..5faf509bb8146bdcd271230957b67a9182755cf3 100644
--- a/modules/service/vpn/include/dap_chain_net_vpn_client.h
+++ b/modules/service/vpn/include/dap_chain_net_vpn_client.h
@@ -38,6 +38,7 @@ typedef enum dap_chain_net_vpn_client_status_enum{
 
 
 dap_stream_ch_t* dap_chain_net_vpn_client_get_stream_ch(void);
+dap_stream_worker_t* dap_chain_net_vpn_client_get_stream_worker(void);
 
 int dap_chain_net_vpn_client_update(dap_chain_net_t *a_net, const char *a_wallet_name, const char *a_str_token, uint64_t a_value_datoshi);
 int dap_chain_net_vpn_client_get_wallet_info(dap_chain_net_t *a_net, char **a_wallet_name, char **a_str_token, uint64_t *a_value_datoshi);
diff --git a/modules/service/vpn/include/dap_chain_net_vpn_client_tun.h b/modules/service/vpn/include/dap_chain_net_vpn_client_tun.h
index 8322907d10761622ec5260d1fca036b589d9be92..054b7642ad81f23f99e7787d692349cc0c1d459f 100644
--- a/modules/service/vpn/include/dap_chain_net_vpn_client_tun.h
+++ b/modules/service/vpn/include/dap_chain_net_vpn_client_tun.h
@@ -31,4 +31,4 @@ 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_ch_vpn_t * a_sf, ch_vpn_pkt_t * a_pkt, size_t a_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);
+void ch_sf_tun_client_send(dap_chain_net_srv_ch_vpn_t * ch_sf, void * pkt_data, size_t pkt_data_size);
diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c
index a2250e0abd53ce2b8ac181c44d596ace2e723d9c..c0de3cc2d7d37f9955134fec723f3fe6d9adebf8 100644
--- a/modules/type/dag/dap_chain_cs_dag.c
+++ b/modules/type/dag/dap_chain_cs_dag.c
@@ -56,6 +56,7 @@ typedef struct dap_chain_cs_dag_event_item {
     dap_chain_hash_fast_t hash;
     time_t ts_added;
     dap_chain_cs_dag_event_t *event;
+    size_t event_size;
     UT_hash_handle hh;
 } dap_chain_cs_dag_event_item_t;
 
@@ -78,29 +79,28 @@ typedef struct dap_chain_cs_dag_pvt {
 #define PVT(a) ((dap_chain_cs_dag_pvt_t *) a->_pvt )
 
 // Atomic element organization callbacks
-static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t );                      //    Accept new event in dag
-static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t );                   //    Verify new event in dag
-static size_t s_chain_callback_atom_hdr_get_size(dap_chain_atom_ptr_t );                                 //    Get dag event size
+static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t);                      //    Accept new event in dag
+static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t);                   //    Verify new event in dag
 static size_t s_chain_callback_atom_get_static_hdr_size(void);                               //    Get dag event header size
 
 static dap_chain_atom_iter_t* s_chain_callback_atom_iter_create(dap_chain_t * a_chain );
-static dap_chain_atom_iter_t* s_chain_callback_atom_iter_create_from(dap_chain_t * a_chain ,
-                                                                     dap_chain_atom_ptr_t a);
+static dap_chain_atom_iter_t* s_chain_callback_atom_iter_create_from(dap_chain_t *  ,
+                                                                     dap_chain_atom_ptr_t , size_t);
 
 
 static dap_chain_atom_ptr_t s_chain_callback_atom_iter_find_by_hash(dap_chain_atom_iter_t * a_atom_iter ,
-                                                                       dap_chain_hash_fast_t * a_atom_hash);
+                                                                       dap_chain_hash_fast_t * a_atom_hash, size_t * a_atom_size);
 static dap_chain_datum_tx_t* s_chain_callback_atom_iter_find_by_tx_hash(dap_chain_t * a_chain ,
                                                                        dap_chain_hash_fast_t * a_atom_hash);
 
-static dap_chain_datum_t* s_chain_callback_atom_get_datum(dap_chain_atom_ptr_t a_event);
+static dap_chain_datum_t* s_chain_callback_atom_get_datum(dap_chain_atom_ptr_t a_event, size_t a_atom_size);
 //    Get event(s) from dag
-static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_first( dap_chain_atom_iter_t * a_atom_iter ); //    Get the fisrt event from dag
-static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_next( dap_chain_atom_iter_t * a_atom_iter );  //    Get the next event from dag
-static dap_chain_atom_ptr_t *s_chain_callback_atom_iter_get_links( dap_chain_atom_iter_t * a_atom_iter ,
-                                                                  size_t * a_links_size_ptr );  //    Get list of linked events
-static dap_chain_atom_ptr_t *s_chain_callback_atom_iter_get_lasts( dap_chain_atom_iter_t * a_atom_iter ,
-                                                                  size_t * a_lasts_size_ptr );  //    Get list of linked events
+static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_first( dap_chain_atom_iter_t * a_atom_iter, size_t *a_atom_size ); //    Get the fisrt event from dag
+static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_next( dap_chain_atom_iter_t * a_atom_iter,size_t *a_atom_size );  //    Get the next event from dag
+static dap_chain_atom_ptr_t *s_chain_callback_atom_iter_get_links( dap_chain_atom_iter_t * a_atom_iter , size_t *a_links_size,
+                                                                  size_t ** a_links_size_ptr );  //    Get list of linked events
+static dap_chain_atom_ptr_t *s_chain_callback_atom_iter_get_lasts( dap_chain_atom_iter_t * a_atom_iter ,size_t *a_links_size,
+                                                                  size_t ** a_lasts_size_ptr );  //    Get list of linked events
 
 // Delete iterator
 static void s_chain_callback_atom_iter_delete(dap_chain_atom_iter_t * a_atom_iter );                  //    Get the fisrt event from dag
@@ -172,7 +172,6 @@ int dap_chain_cs_dag_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
     // Atom element callbacks
     a_chain->callback_atom_add = s_chain_callback_atom_add ;  // Accept new element in chain
     a_chain->callback_atom_verify = s_chain_callback_atom_verify ;  // Verify new element in chain
-    a_chain->callback_atom_get_size  = s_chain_callback_atom_hdr_get_size; // Get dag event size
     a_chain->callback_atom_get_hdr_static_size = s_chain_callback_atom_get_static_hdr_size; // Get dag event hdr size
 
     a_chain->callback_atom_iter_create = s_chain_callback_atom_iter_create;
@@ -248,16 +247,16 @@ void dap_chain_cs_dag_delete(dap_chain_t * a_chain)
 
 static int s_dap_chain_add_atom_to_ledger(dap_chain_cs_dag_t * a_dag, dap_ledger_t * a_ledger, dap_chain_cs_dag_event_item_t * a_event_item){
 
-  dap_chain_datum_t *l_datum = (dap_chain_datum_t*) dap_chain_cs_dag_event_get_datum(a_event_item->event);
+  dap_chain_datum_t *l_datum = (dap_chain_datum_t*) dap_chain_cs_dag_event_get_datum(a_event_item->event, a_event_item->event_size);
   switch (l_datum->header.type_id) {
     case DAP_CHAIN_DATUM_TOKEN_DECL: {
       dap_chain_datum_token_t *l_token = (dap_chain_datum_token_t*) l_datum->data;
-      dap_chain_ledger_token_add(a_ledger, l_token, l_datum->header.data_size);
+      return dap_chain_ledger_token_add(a_ledger, l_token, l_datum->header.data_size);
     }
       break;
     case DAP_CHAIN_DATUM_TOKEN_EMISSION: {
       dap_chain_datum_token_emission_t *l_token_emission = (dap_chain_datum_token_emission_t*) l_datum->data;
-      dap_chain_ledger_token_emission_add(a_ledger, l_token_emission, l_datum->header.data_size);
+      return dap_chain_ledger_token_emission_add(a_ledger, l_token_emission, l_datum->header.data_size);
     }
       break;
     case DAP_CHAIN_DATUM_TX: {
@@ -265,6 +264,7 @@ static int s_dap_chain_add_atom_to_ledger(dap_chain_cs_dag_t * a_dag, dap_ledger
       dap_chain_cs_dag_event_item_t * l_tx_event= DAP_NEW_Z(dap_chain_cs_dag_event_item_t);
       l_tx_event->ts_added = a_event_item->ts_added;
       l_tx_event->event = a_event_item->event;
+      l_tx_event->event_size = a_event_item->event_size;
       memcpy(&l_tx_event->hash, &a_event_item->hash, sizeof (l_tx_event->hash) );
 
       HASH_ADD(hh,PVT(a_dag)->tx_events,hash,sizeof (l_tx_event->hash),l_tx_event);
@@ -282,15 +282,21 @@ static int s_dap_chain_add_atom_to_ledger(dap_chain_cs_dag_t * a_dag, dap_ledger
 }
 
 static int s_dap_chain_add_atom_to_events_table(dap_chain_cs_dag_t * a_dag, dap_ledger_t * a_ledger, dap_chain_cs_dag_event_item_t * a_event_item ){
-    int res = a_dag->callback_cs_verify(a_dag,a_event_item->event);
+    int res = a_dag->callback_cs_verify(a_dag,a_event_item->event, a_event_item->event_size);
 
     if(res == 0){
+        char l_buf_hash[128];
+        dap_chain_hash_fast_to_str(&a_event_item->hash,l_buf_hash,sizeof(l_buf_hash)-1);
+        log_it(L_DEBUG,"Dag event %s checked, add it to ledger", l_buf_hash);
         res = s_dap_chain_add_atom_to_ledger(a_dag, a_ledger, a_event_item);
-
+        //All correct, no matter for result
         HASH_ADD(hh, PVT(a_dag)->events,hash,sizeof (a_event_item->hash), a_event_item);
         s_dag_events_lasts_process_new_last_event(a_dag, a_event_item);
+    } else {
+        char l_buf_hash[128];
+        dap_chain_hash_fast_to_str(&a_event_item->hash,l_buf_hash,sizeof(l_buf_hash)-1);
+        log_it(L_WARNING,"Dag event %s check failed: code %d", l_buf_hash,  res );
     }
-
     return res;
 }
 
@@ -312,9 +318,10 @@ static bool s_dap_chain_check_if_event_is_present(dap_chain_cs_dag_event_item_t
  * @brief s_chain_callback_atom_add Accept new event in dag
  * @param a_chain DAG object
  * @param a_atom
+ * @param a_atom_size
  * @return 0 if verified and added well, otherwise if not
  */
-static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom)
+static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size)
 {
     dap_chain_atom_verify_res_t ret = ATOM_ACCEPT;
     dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG(a_chain);
@@ -323,11 +330,12 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
     dap_chain_cs_dag_event_item_t * l_event_item = DAP_NEW_Z(dap_chain_cs_dag_event_item_t);
     pthread_rwlock_t * l_events_rwlock = &PVT(l_dag)->events_rwlock ;
     l_event_item->event = l_event;
+    l_event_item->event_size = a_atom_size;
     l_event_item->ts_added = time(NULL);
 
-    dap_hash_fast(l_event, dap_chain_cs_dag_event_calc_size(l_event),&l_event_item->hash );
+    dap_hash_fast(l_event, a_atom_size,&l_event_item->hash );
     dap_chain_hash_fast_t l_event_hash;
-    dap_chain_cs_dag_event_calc_hash(l_event,&l_event_hash);
+    dap_chain_cs_dag_event_calc_hash(l_event, a_atom_size,&l_event_hash);
 
     char * l_event_hash_str = dap_chain_hash_fast_to_str_new(&l_event_item->hash);
     log_it(L_DEBUG, "Processing event: %s...", l_event_hash_str);
@@ -344,8 +352,10 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
     }
 
     // verify hashes and consensus
-    if(ret == ATOM_ACCEPT)
-        ret = s_chain_callback_atom_verify (a_chain, a_atom);
+    if(ret == ATOM_ACCEPT){
+        ret = s_chain_callback_atom_verify (a_chain, a_atom, a_atom_size);
+        log_it(L_DEBUG, "Verified atom %p: code %d", a_atom, ret);
+    }
 
     if( ret == ATOM_MOVE_TO_THRESHOLD){
         HASH_ADD(hh, PVT(l_dag)->events_treshold,hash,sizeof (l_event_item->hash),  l_event_item);
@@ -427,7 +437,7 @@ static size_t s_chain_callback_datums_pool_proc(dap_chain_t * a_chain, dap_chain
                 int l_index = rand() % (int) l_events_round_new_size;
                 dap_chain_hash_fast_t l_hash;
                 dap_chain_cs_dag_event_t * l_event = (dap_chain_cs_dag_event_t *) l_events_round_new[l_index].value;
-                size_t l_event_size = dap_chain_cs_dag_event_calc_size(l_event);
+                size_t l_event_size = l_events_round_new[l_index].value_len;
                 dap_hash_fast(l_event, l_event_size,&l_hash);
 
                 bool l_is_already_in_event = false;
@@ -468,12 +478,13 @@ static size_t s_chain_callback_datums_pool_proc(dap_chain_t * a_chain, dap_chain
 
         if (l_hashes_linked || s_seed_mode ) {
             dap_chain_cs_dag_event_t * l_event = NULL;
+            size_t l_event_size = 0;
             if(l_dag->callback_cs_event_create)
-                l_event = l_dag->callback_cs_event_create(l_dag,l_datum,l_hashes,l_hashes_linked);
-            if ( l_event){ // Event is created
+                l_event = l_dag->callback_cs_event_create(l_dag,l_datum,l_hashes,l_hashes_linked,&l_event_size);
+            if ( l_event&&l_event_size){ // Event is created
 
                 if (l_dag->is_add_directy) {
-                    if (s_chain_callback_atom_add(a_chain, l_event) == ATOM_ACCEPT) {
+                    if (s_chain_callback_atom_add(a_chain, l_event, l_event_size) == ATOM_ACCEPT) {
                         // add events to file
                         if (!l_cell) {
                             l_cell = dap_chain_cell_create();
@@ -486,7 +497,7 @@ static size_t s_chain_callback_datums_pool_proc(dap_chain_t * a_chain, dap_chain
                             l_cell->id.uint64 = l_net ? l_net->pub.cell_id.uint64 : 0;
                             l_cell->file_storage_path = dap_strdup_printf("%0llx.dchaincell", l_cell->id.uint64);
                         }
-                        if (dap_chain_cell_file_append(l_cell, l_event, a_chain->callback_atom_get_size(l_event)) < 0) {
+                        if (dap_chain_cell_file_append(l_cell, l_event, l_event_size )  < 0) {
                             log_it(L_ERROR, "Can't add new event to the file '%s'", l_cell->file_storage_path);
                             continue;
                         }
@@ -500,10 +511,10 @@ static size_t s_chain_callback_datums_pool_proc(dap_chain_t * a_chain, dap_chain
                 // add to new round into global_db
                 else {
                     dap_chain_hash_fast_t l_event_hash;
-                    dap_chain_cs_dag_event_calc_hash(l_event, &l_event_hash);
+                    dap_chain_cs_dag_event_calc_hash(l_event,l_event_size, &l_event_hash);
                     char * l_event_hash_str = dap_chain_hash_fast_to_str_new(&l_event_hash);
                     if(dap_chain_global_db_gr_set(dap_strdup(l_event_hash_str), (uint8_t *) l_event,
-                            dap_chain_cs_dag_event_calc_size(l_event),
+                            l_event_size,
                             l_dag->gdb_group_events_round_new)) {
                         log_it(L_INFO, "Event %s placed in the new forming round", l_event_hash_str);
                         DAP_DELETE(l_event_hash_str);
@@ -570,12 +581,16 @@ dap_chain_cs_dag_event_t* dap_chain_cs_dag_find_event_by_hash(dap_chain_cs_dag_t
  * @param a_atom
  * @return
  */
-static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t  a_atom)
+static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t  a_atom,size_t a_atom_size)
 {
     dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG(a_chain);
     dap_chain_cs_dag_event_t * l_event = (dap_chain_cs_dag_event_t *) a_atom;
     dap_chain_atom_verify_res_t res = ATOM_ACCEPT;
 
+    if(sizeof (l_event->header) >= a_atom_size){
+        log_it(L_WARNING,"Size of atom is %zd that is equel or less then header %zd",a_atom_size,sizeof (l_event->header));
+        return  ATOM_REJECT;
+    }
     // genesis or seed mode
     if (l_event->header.hash_count == 0){
       if(s_seed_mode && !PVT(l_dag)->events)
@@ -583,7 +598,7 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_
 
       if (l_dag->is_static_genesis_event ){
         dap_chain_hash_fast_t l_event_hash;
-        dap_chain_cs_dag_event_calc_hash(l_event,&l_event_hash);
+        dap_chain_cs_dag_event_calc_hash(l_event,a_atom_size, &l_event_hash);
         if ( memcmp( &l_event_hash, &l_dag->static_genesis_event_hash, sizeof(l_event_hash) ) != 0 ){
           char * l_event_hash_str = dap_chain_hash_fast_to_str_new(&l_event_hash);
           char * l_genesis_event_hash_str = dap_chain_hash_fast_to_str_new(&l_dag->static_genesis_event_hash);
@@ -618,7 +633,7 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_
 
     //consensus
     if(res == ATOM_ACCEPT)
-        if(l_dag->callback_cs_verify ( l_dag, l_event ))
+        if(l_dag->callback_cs_verify ( l_dag, l_event,a_atom_size ))
             res = ATOM_REJECT;
 
     return res;
@@ -661,7 +676,8 @@ void s_dag_events_lasts_process_new_last_event(dap_chain_cs_dag_t * a_dag, dap_c
     dap_chain_cs_dag_event_item_t * l_event_last= DAP_NEW_Z(dap_chain_cs_dag_event_item_t);
     l_event_last->ts_added = a_event_item->ts_added;
     l_event_last->event = a_event_item->event;
-    dap_hash_fast(l_event_last->event, dap_chain_cs_dag_event_calc_size(l_event_last->event),&l_event_last->hash );
+    l_event_last->event_size = a_event_item->event_size;
+    dap_hash_fast(l_event_last->event, a_event_item->event_size,&l_event_last->hash );
     HASH_ADD(hh,PVT(a_dag)->events_lasts_unlinked,hash, sizeof(l_event_last->hash),l_event_last);
 }
 
@@ -678,7 +694,7 @@ int dap_chain_cs_dag_event_verify_hashes_with_treshold(dap_chain_cs_dag_t * a_da
     bool l_is_events_all_hashes = true;
     bool l_is_events_main_hashes = true;
 
-    if(a_event->header.hash_count == 0){
+    if (a_event->header.hash_count == 0) {
         //looks like an alternative genesis event
         return DAP_THRESHOLD_CONFLICTING;
     }
@@ -749,17 +765,6 @@ bool dap_chain_cs_dag_proc_treshold(dap_chain_cs_dag_t * a_dag, dap_ledger_t * a
     return res;
 }
 
-
-/**
- * @brief s_chain_callback_atom_get_size Get size of atomic element
- * @param a_atom
- * @return
- */
-static size_t s_chain_callback_atom_hdr_get_size(dap_chain_atom_ptr_t  a_atom)
-{
-    return dap_chain_cs_dag_event_calc_size( (dap_chain_cs_dag_event_t * ) a_atom);
-}
-
 /**
  * @brief s_chain_callback_atom_get_static_hdr_size
  * @param a_chain
@@ -777,7 +782,7 @@ static size_t s_chain_callback_atom_get_static_hdr_size()
  * @return
  */
 static dap_chain_atom_iter_t* s_chain_callback_atom_iter_create_from(dap_chain_t * a_chain ,
-                                                                     dap_chain_atom_ptr_t a_atom)
+                                                                     dap_chain_atom_ptr_t a_atom, size_t a_atom_size)
 {
     dap_chain_atom_iter_t * l_atom_iter = DAP_NEW_Z(dap_chain_atom_iter_t);
     l_atom_iter->chain = a_chain;
@@ -785,7 +790,7 @@ static dap_chain_atom_iter_t* s_chain_callback_atom_iter_create_from(dap_chain_t
 
     if ( a_atom ){
         dap_chain_hash_fast_t l_atom_hash;
-        dap_hash_fast(a_atom, a_chain->callback_atom_get_size(a_atom), &l_atom_hash );
+        dap_hash_fast(a_atom, a_atom_size, &l_atom_hash );
 
         dap_chain_cs_dag_event_item_t  * l_atom_item;
         HASH_FIND(hh, PVT(DAP_CHAIN_CS_DAG(a_chain))->events, &l_atom_hash, sizeof(l_atom_hash),l_atom_item );
@@ -812,10 +817,10 @@ static dap_chain_atom_iter_t* s_chain_callback_atom_iter_create(dap_chain_t * a_
  * @param a_atom_iter
  * @return
  */
-static dap_chain_datum_t* s_chain_callback_atom_get_datum(dap_chain_atom_ptr_t a_event)
+static dap_chain_datum_t* s_chain_callback_atom_get_datum(dap_chain_atom_ptr_t a_event, size_t a_atom_size)
 {
     if(a_event)
-        return dap_chain_cs_dag_event_get_datum((dap_chain_cs_dag_event_t*) a_event);
+        return dap_chain_cs_dag_event_get_datum((dap_chain_cs_dag_event_t*) a_event, a_atom_size);
     return NULL;
 }
 
@@ -824,16 +829,19 @@ static dap_chain_datum_t* s_chain_callback_atom_get_datum(dap_chain_atom_ptr_t a
  * @param a_atom_iter
  * @return
  */
-static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_first(dap_chain_atom_iter_t * a_atom_iter )
+static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_first(dap_chain_atom_iter_t * a_atom_iter, size_t * a_ret_size )
 {
     dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG(a_atom_iter->chain);
     dap_chain_cs_dag_pvt_t *l_dag_pvt = l_dag ? PVT(l_dag) : NULL;
     a_atom_iter->cur_item = l_dag_pvt->events;
     a_atom_iter->cur = (dap_chain_cs_dag_event_t*) (l_dag_pvt->events ? l_dag_pvt->events->event : NULL);
+    a_atom_iter->cur_size =l_dag_pvt->events->event_size;
 
 //    a_atom_iter->cur =  a_atom_iter->cur ?
 //                (dap_chain_cs_dag_event_t*) PVT (DAP_CHAIN_CS_DAG( a_atom_iter->chain) )->events->event : NULL;
 //    a_atom_iter->cur_item = PVT (DAP_CHAIN_CS_DAG( a_atom_iter->chain) )->events;
+    if (a_ret_size)
+        *a_ret_size = a_atom_iter->cur_size;
     return a_atom_iter->cur;
 }
 
@@ -843,27 +851,28 @@ static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_first(dap_chain_atom_
  * @param a_lasts_size_ptr
  * @return
  */
-static dap_chain_atom_ptr_t* s_chain_callback_atom_iter_get_lasts( dap_chain_atom_iter_t * a_atom_iter ,
-                                                                  size_t * a_lasts_size_ptr )
+static dap_chain_atom_ptr_t* s_chain_callback_atom_iter_get_lasts( dap_chain_atom_iter_t * a_atom_iter ,size_t * a_lasts_size,
+                                                                  size_t ** a_lasts_size_array )
 {
     dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG( a_atom_iter->chain );
-
-    *a_lasts_size_ptr = HASH_COUNT( PVT(l_dag)->events_lasts_unlinked );
-    if ( *a_lasts_size_ptr > 0 ) {
-        dap_chain_atom_ptr_t * l_ret = DAP_NEW_Z_SIZE( dap_chain_atom_ptr_t,
-                                           sizeof (dap_chain_atom_ptr_t*) * (*a_lasts_size_ptr) );
-
+    dap_chain_atom_ptr_t * l_ret = NULL;
+    pthread_rwlock_wrlock(&PVT(l_dag)->events_rwlock);
+    size_t l_lasts_size = HASH_COUNT( PVT(l_dag)->events_lasts_unlinked );
+    if ( l_lasts_size > 0 ) {
+        if( a_lasts_size)
+            *a_lasts_size = l_lasts_size;
+        l_ret = DAP_NEW_Z_SIZE(dap_chain_atom_ptr_t, sizeof(dap_chain_atom_ptr_t *) * l_lasts_size);
         dap_chain_cs_dag_event_item_t * l_event_item = NULL, *l_event_item_tmp = NULL;
         size_t i = 0;
-        pthread_rwlock_wrlock(&PVT(l_dag)->events_rwlock);
+        *a_lasts_size_array = DAP_NEW_Z_SIZE(size_t, sizeof(size_t) * l_lasts_size);
         HASH_ITER(hh,PVT(l_dag)->events_lasts_unlinked, l_event_item,l_event_item_tmp){
             l_ret[i] = l_event_item->event;
+            (*a_lasts_size_array)[i] = l_event_item->event_size;
             i++;
-        }
-        pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
-        return l_ret;
+        }    
     }
-    return NULL;
+    pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
+    return l_ret;
 }
 
 /**
@@ -872,8 +881,8 @@ static dap_chain_atom_ptr_t* s_chain_callback_atom_iter_get_lasts( dap_chain_ato
  * @param a_links_size_ptr
  * @return
  */
-static dap_chain_atom_ptr_t* s_chain_callback_atom_iter_get_links( dap_chain_atom_iter_t * a_atom_iter ,
-                                                                  size_t * a_links_size_ptr )
+static dap_chain_atom_ptr_t* s_chain_callback_atom_iter_get_links( dap_chain_atom_iter_t * a_atom_iter ,size_t* a_links_size,
+                                                                  size_t ** a_links_size_array )
 {
     if ( a_atom_iter->cur && a_atom_iter->chain){
         dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG( a_atom_iter->chain );
@@ -886,7 +895,9 @@ static dap_chain_atom_ptr_t* s_chain_callback_atom_iter_get_links( dap_chain_ato
         if ( l_event->header.hash_count > 0){
             dap_chain_atom_ptr_t * l_ret = DAP_NEW_Z_SIZE(dap_chain_atom_ptr_t,
                                                sizeof (dap_chain_atom_ptr_t*) * l_event->header.hash_count );
-            *a_links_size_ptr = l_event->header.hash_count;
+            if( a_links_size)
+                *a_links_size = l_event->header.hash_count;
+            *a_links_size_array = DAP_NEW_Z_SIZE(size_t, l_event->header.hash_count*sizeof (size_t));
             for (uint16_t i = 0; i < l_event->header.hash_count; i++){
                 dap_chain_cs_dag_event_item_t * l_link_item = NULL;
                 dap_chain_hash_fast_t * l_link_hash = (dap_chain_hash_fast_t *)
@@ -895,16 +906,17 @@ static dap_chain_atom_ptr_t* s_chain_callback_atom_iter_get_links( dap_chain_ato
                 HASH_FIND(hh, PVT(l_dag)->events,l_link_hash,sizeof(*l_link_hash),l_link_item);
                 if ( l_link_item ){
                     l_ret[i] = l_link_item->event;
+                    (*a_links_size_array)[i] = l_link_item->event_size;
                 }else {
                     char * l_link_hash_str = dap_chain_hash_fast_to_str_new(l_link_hash);
                     char * l_event_hash_str = l_event_item ? dap_chain_hash_fast_to_str_new(&l_event_item->hash) : NULL;
                     log_it(L_ERROR,"Can't find %s->%s links", l_event_hash_str ? l_event_hash_str : "[null]", l_link_hash_str);
                     DAP_DELETE(l_event_hash_str);
                     DAP_DELETE(l_link_hash_str);
-                    (*a_links_size_ptr)--;
+                    (*a_links_size_array)--;
                 }
             }
-            if(!(*a_links_size_ptr)){
+            if(!(*a_links_size_array)){
                 DAP_DELETE(l_ret);
                 l_ret = NULL;
             }
@@ -921,7 +933,7 @@ static dap_chain_atom_ptr_t* s_chain_callback_atom_iter_get_links( dap_chain_ato
  * @return
  */
 static dap_chain_atom_ptr_t s_chain_callback_atom_iter_find_by_hash(dap_chain_atom_iter_t * a_atom_iter ,
-                                                                       dap_chain_hash_fast_t * a_atom_hash)
+                                                                       dap_chain_hash_fast_t * a_atom_hash,size_t *a_atom_size)
 {
     dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG( a_atom_iter->chain );
     dap_chain_cs_dag_event_item_t * l_event_item = NULL;
@@ -929,6 +941,9 @@ static dap_chain_atom_ptr_t s_chain_callback_atom_iter_find_by_hash(dap_chain_at
     if ( l_event_item ){
         a_atom_iter->cur_item = l_event_item;
         a_atom_iter->cur = l_event_item->event;
+        a_atom_iter->cur_size= l_event_item->event_size;
+        if(a_atom_size)
+            *a_atom_size = l_event_item->event_size;
         return  l_event_item->event;
     }else
         return NULL;
@@ -942,7 +957,7 @@ static dap_chain_datum_tx_t* s_chain_callback_atom_iter_find_by_tx_hash(dap_chai
     dap_chain_cs_dag_event_item_t * l_event_item = NULL;
     HASH_FIND(hh, PVT(l_dag)->tx_events,a_atom_hash,sizeof(*a_atom_hash),l_event_item);
     if ( l_event_item ){
-        dap_chain_datum_t * l_datum = dap_chain_cs_dag_event_get_datum(l_event_item->event) ;
+        dap_chain_datum_t * l_datum = dap_chain_cs_dag_event_get_datum(l_event_item->event, l_event_item->event_size) ;
         return l_datum ? l_datum->header.data_size ? (dap_chain_datum_tx_t*) l_datum->data : NULL :NULL;
     }else
         return NULL;
@@ -953,7 +968,7 @@ static dap_chain_datum_tx_t* s_chain_callback_atom_iter_find_by_tx_hash(dap_chai
  * @param a_atom_iter
  * @return
  */
-static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_next( dap_chain_atom_iter_t * a_atom_iter )
+static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_next( dap_chain_atom_iter_t * a_atom_iter,size_t * a_atom_size )
 {
     if (a_atom_iter->cur ){
         dap_chain_cs_dag_event_item_t * l_event_item = (dap_chain_cs_dag_event_item_t*) a_atom_iter->cur_item;
@@ -962,6 +977,10 @@ static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_next( dap_chain_atom_
         // if l_event_item=NULL then items are over
         a_atom_iter->cur = l_event_item ? l_event_item->event : NULL;
     }
+    a_atom_iter->cur_size = a_atom_iter->cur?a_atom_iter->cur_size: 0;
+    if(a_atom_size)
+        *a_atom_size = a_atom_iter->cur_size;
+
     return a_atom_iter->cur;
 }
 
@@ -984,6 +1003,7 @@ static void s_chain_callback_atom_iter_delete(dap_chain_atom_iter_t * a_atom_ite
  */
 static int s_cli_dag(int argc, char ** argv, void *arg_func, char **a_str_reply)
 {
+    (void) arg_func;
     enum {
         SUBCMD_EVENT_CREATE,
         SUBCMD_EVENT_CANCEL,
@@ -992,13 +1012,13 @@ static int s_cli_dag(int argc, char ** argv, void *arg_func, char **a_str_reply)
         SUBCMD_UNDEFINED
     } l_event_subcmd={0};
 
-    const char* l_event_subcmd_str[]={
+    /*const char* l_event_subcmd_str[]={
         [SUBCMD_EVENT_CREATE]="create",
         [SUBCMD_EVENT_CANCEL]="cancel",
         [SUBCMD_EVENT_LIST]="list",
         [SUBCMD_EVENT_DUMP]="dump",
         [SUBCMD_UNDEFINED]="UNDEFINED"
-    };
+    };*/
 
 
     int arg_index = 1;
@@ -1082,7 +1102,7 @@ static int s_cli_dag(int argc, char ** argv, void *arg_func, char **a_str_reply)
                 dap_chain_cs_dag_event_t * l_event = (dap_chain_cs_dag_event_t*) l_objs[i].value;
                 size_t l_event_size = l_objs[i].value_len;
                 int l_ret_event_verify;
-                if ( ( l_ret_event_verify = l_dag->callback_cs_verify (l_dag,l_event) ) !=0 ){// if consensus accept the event
+                if ( ( l_ret_event_verify = l_dag->callback_cs_verify (l_dag,l_event,l_event_size) ) !=0 ){// if consensus accept the event
                     dap_string_append_printf( l_str_ret_tmp,
                             "Error! Event %s is not passing consensus verification, ret code %d\n",
                                               l_objs[i].key, l_ret_event_verify );
@@ -1092,9 +1112,9 @@ static int s_cli_dag(int argc, char ** argv, void *arg_func, char **a_str_reply)
                     dap_string_append_printf( l_str_ret_tmp, "Event %s verification passed\n", l_objs[i].key);
                     // If not verify only mode we add
                     if ( ! l_verify_only ){
-                        dap_chain_atom_ptr_t l_new_atom = (dap_chain_atom_ptr_t)dap_chain_cs_dag_event_copy(l_event); // produce deep copy of event;
+                        dap_chain_atom_ptr_t l_new_atom = (dap_chain_atom_ptr_t)dap_chain_cs_dag_event_copy(l_event, l_event_size); // produce deep copy of event;
                         memcpy(l_new_atom, l_event, l_event_size);
-                        if(s_chain_callback_atom_add(l_chain, l_new_atom) < 0) { // Add new atom in chain
+                        if(s_chain_callback_atom_add(l_chain, l_new_atom,l_event_size) < 0) { // Add new atom in chain
                             DAP_DELETE(l_new_atom);
                             dap_string_append_printf(l_str_ret_tmp, "Event %s not added in chain\n", l_objs[i].key);
                         }
@@ -1297,7 +1317,7 @@ static int s_cli_dag(int argc, char ** argv, void *arg_func, char **a_str_reply)
 
                     }else if ( strcmp(l_from_events_str,"events_lasts") == 0){
                         dap_chain_cs_dag_event_item_t * l_event_item = NULL;
-                        pthread_rwlock_wrlock(&PVT(l_dag)->events_rwlock);
+                        pthread_rwlock_rdlock(&PVT(l_dag)->events_rwlock);
                         HASH_FIND(hh,PVT(l_dag)->events_lasts_unlinked,&l_event_hash,sizeof(l_event_hash),l_event_item);
                         pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
                         if ( l_event_item )
@@ -1310,7 +1330,7 @@ static int s_cli_dag(int argc, char ** argv, void *arg_func, char **a_str_reply)
                         }
                     }else if ( strcmp(l_from_events_str,"events") == 0){
                         dap_chain_cs_dag_event_item_t * l_event_item = NULL;
-                        pthread_rwlock_wrlock(&PVT(l_dag)->events_rwlock);
+                        pthread_rwlock_rdlock(&PVT(l_dag)->events_rwlock);
                         HASH_FIND(hh,PVT(l_dag)->events,&l_event_hash,sizeof(l_event_hash),l_event_item);
                         pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
                         if ( l_event_item )
diff --git a/modules/type/dag/dap_chain_cs_dag_event.c b/modules/type/dag/dap_chain_cs_dag_event.c
index edf2b6621705cece4659efc2ddae1e91063a979d..a9d1d755b57b6591a1c395fe59d05aeebc0c3e34 100644
--- a/modules/type/dag/dap_chain_cs_dag_event.c
+++ b/modules/type/dag/dap_chain_cs_dag_event.c
@@ -45,8 +45,9 @@
  */
 dap_chain_cs_dag_event_t * dap_chain_cs_dag_event_new(dap_chain_id_t a_chain_id, dap_chain_cell_id_t a_cell_id, dap_chain_datum_t * a_datum
                                                 ,dap_enc_key_t * a_key ,
-                                                dap_chain_hash_fast_t * a_hashes, size_t a_hashes_count)
+                                                dap_chain_hash_fast_t * a_hashes, size_t a_hashes_count, size_t * a_event_size)
 {
+    assert(a_event_size);
     size_t l_hashes_size = sizeof(*a_hashes)*a_hashes_count;
     size_t l_datum_size =  dap_chain_datum_size(a_datum);
     dap_chain_cs_dag_event_t * l_event_new = NULL;
@@ -58,11 +59,15 @@ dap_chain_cs_dag_event_t * dap_chain_cs_dag_event_new(dap_chain_id_t a_chain_id,
     l_event_new->header.cell_id.uint64 = a_cell_id.uint64;
     l_event_new->header.chain_id.uint64 = a_chain_id.uint64;
     l_event_new->header.hash_count = a_hashes_count;
+    *a_event_size = sizeof (l_event_new->header);
 
-    if ( l_hashes_size )
+    if ( l_hashes_size ){
         memcpy(l_event_new->hashes_n_datum_n_signs, a_hashes, l_hashes_size );
+        *a_event_size += l_hashes_size;
+    }
 
     memcpy(l_event_new->hashes_n_datum_n_signs+l_hashes_size, a_datum,l_datum_size );
+    *a_event_size += l_datum_size;
 
     if ( a_key ){
         dap_sign_t * l_sign = dap_sign_create(a_key,l_event_new,
@@ -72,6 +77,7 @@ dap_chain_cs_dag_event_t * dap_chain_cs_dag_event_new(dap_chain_id_t a_chain_id,
             size_t l_sign_size = dap_sign_get_size(l_sign);
             l_event_new = (dap_chain_cs_dag_event_t* )DAP_REALLOC(l_event_new,l_event_size+l_sign_size );
             memcpy(l_event_new->hashes_n_datum_n_signs + l_hashes_size + l_datum_size, l_sign, l_sign_size);
+            *a_event_size += l_sign_size;
             l_event_size += l_sign_size;
             l_event_new->header.signs_count++;
             DAP_DELETE(l_sign);
@@ -91,13 +97,12 @@ dap_chain_cs_dag_event_t * dap_chain_cs_dag_event_new(dap_chain_id_t a_chain_id,
  * @param a_event_src
  * @return
  */
-dap_chain_cs_dag_event_t * dap_chain_cs_dag_event_copy(dap_chain_cs_dag_event_t *a_event_src)
+dap_chain_cs_dag_event_t * dap_chain_cs_dag_event_copy(dap_chain_cs_dag_event_t *a_event_src,size_t a_event_size)
 {
     if(!a_event_src)
         return NULL;
-    size_t l_event_size = dap_chain_cs_dag_event_calc_size(a_event_src);
-    dap_chain_cs_dag_event_t *l_event_new = DAP_NEW_Z_SIZE(dap_chain_cs_dag_event_t, l_event_size);
-    memcpy(l_event_new, a_event_src, l_event_size);
+    dap_chain_cs_dag_event_t *l_event_new = DAP_NEW_Z_SIZE(dap_chain_cs_dag_event_t, a_event_size);
+    memcpy(l_event_new, a_event_src, a_event_size);
     return l_event_new;
 }
 
@@ -107,16 +112,15 @@ dap_chain_cs_dag_event_t * dap_chain_cs_dag_event_copy(dap_chain_cs_dag_event_t
  * @param l_key
  * @return
  */
-dap_chain_cs_dag_event_t * dap_chain_cs_dag_event_copy_with_sign_add( dap_chain_cs_dag_event_t * a_event,
+dap_chain_cs_dag_event_t * dap_chain_cs_dag_event_copy_with_sign_add( dap_chain_cs_dag_event_t * a_event, size_t a_event_size,
                                                                       dap_enc_key_t * l_key)
 {
-    size_t l_event_size = dap_chain_cs_dag_event_calc_size( a_event );
-    size_t l_event_signing_size = dap_chain_cs_dag_event_calc_size_excl_signs( a_event );
+    size_t l_event_signing_size = dap_chain_cs_dag_event_calc_size_excl_signs( a_event ,a_event_size);
     dap_sign_t * l_sign = dap_sign_create(l_key,a_event,l_event_signing_size,0);
     size_t l_sign_size = dap_sign_get_size(l_sign);
-    dap_chain_cs_dag_event_t *l_event_new = DAP_NEW_Z_SIZE(dap_chain_cs_dag_event_t, l_event_size+l_sign_size);
-    memcpy(l_event_new, a_event,l_event_size);
-    memcpy(l_event_new+l_event_size,l_sign,l_sign_size);
+    dap_chain_cs_dag_event_t *l_event_new = DAP_NEW_Z_SIZE(dap_chain_cs_dag_event_t, a_event_size+l_sign_size);
+    memcpy(l_event_new, a_event,a_event_size);
+    memcpy(l_event_new+a_event_size,l_sign,l_sign_size);
     l_event_new->header.signs_count++;
     return l_event_new;
 }
@@ -127,16 +131,23 @@ dap_chain_cs_dag_event_t * dap_chain_cs_dag_event_copy_with_sign_add( dap_chain_
  * @param a_sign_number
  * @return
  */
-dap_sign_t * dap_chain_cs_dag_event_get_sign( dap_chain_cs_dag_event_t * a_event, uint16_t a_sign_number)
+dap_sign_t * dap_chain_cs_dag_event_get_sign( dap_chain_cs_dag_event_t * a_event, size_t a_event_size, uint16_t a_sign_number)
 {
+    size_t l_offset_passed = sizeof (a_event->header);
     if (a_event->header.signs_count > a_sign_number ){
-        size_t l_offset_to_sign = dap_chain_cs_dag_event_calc_size_excl_signs(a_event);
+        size_t l_offset_to_sign = dap_chain_cs_dag_event_calc_size_excl_signs(a_event,a_event_size);
+        l_offset_passed += l_offset_to_sign;
+        if ( l_offset_passed >= a_event_size)
+            return NULL;
         uint8_t * l_signs = ((uint8_t*) a_event)+l_offset_to_sign;
         uint16_t l_signs_offset = 0;
         uint16_t l_signs_passed;
         for ( l_signs_passed=0;  l_signs_passed < a_sign_number; l_signs_passed++){
             dap_sign_t * l_sign = (dap_sign_t *) (l_signs+l_signs_offset);
             l_signs_offset+=l_sign->header.sign_pkey_size+l_sign->header.sign_size+sizeof(l_sign->header);
+            l_offset_passed += l_offset_to_sign;
+            if ( l_offset_passed >= a_event_size)
+                return NULL;
         }
         return (dap_sign_t*) l_signs + l_signs_offset;
     }else
diff --git a/modules/type/dag/include/dap_chain_cs_dag.h b/modules/type/dag/include/dap_chain_cs_dag.h
index 74a974b5a6d1a568c0cb1915da15f52cc3798144..6befe38ae351a1f4d04298ef2a8b8f588ca3a3de 100644
--- a/modules/type/dag/include/dap_chain_cs_dag.h
+++ b/modules/type/dag/include/dap_chain_cs_dag.h
@@ -28,14 +28,14 @@
 typedef struct dap_chain_cs_dag dap_chain_cs_dag_t;
 
 typedef void (*dap_chain_cs_dag_callback_t)(dap_chain_cs_dag_t *);
-typedef int (*dap_chain_cs_dag_callback_event_t)(dap_chain_cs_dag_t *, dap_chain_cs_dag_event_t *);
+typedef int (*dap_chain_cs_dag_callback_event_t)(dap_chain_cs_dag_t *, dap_chain_cs_dag_event_t *,size_t);
 
 
 
 typedef dap_chain_cs_dag_event_t * (*dap_chain_cs_dag_callback_event_create_t)(dap_chain_cs_dag_t *,
                                                                                dap_chain_datum_t *,
                                                                                dap_chain_hash_fast_t *,
-                                                                               size_t);
+                                                                               size_t, size_t*);
 
 typedef struct dap_chain_cs_dag
 {
diff --git a/modules/type/dag/include/dap_chain_cs_dag_event.h b/modules/type/dag/include/dap_chain_cs_dag_event.h
index 39b898d9b1e9123e8ed62b068287a85a0c31d3e6..5f3661be72d0cf47ea6bb17fc73fb116c2b47ee3 100644
--- a/modules/type/dag/include/dap_chain_cs_dag_event.h
+++ b/modules/type/dag/include/dap_chain_cs_dag_event.h
@@ -49,7 +49,7 @@ typedef struct dap_chain_cs_dag_event {
 
 dap_chain_cs_dag_event_t * dap_chain_cs_dag_event_new(dap_chain_id_t a_chain_id, dap_chain_cell_id_t a_cell_id, dap_chain_datum_t * a_datum,
                                                 dap_enc_key_t * a_key,
-                                                dap_chain_hash_fast_t * a_hashes, size_t a_hashes_count);
+                                                dap_chain_hash_fast_t * a_hashes, size_t a_hashes_count, size_t * a_event_size);
 
 
 /**
@@ -57,23 +57,25 @@ dap_chain_cs_dag_event_t * dap_chain_cs_dag_event_new(dap_chain_id_t a_chain_id,
  * @param a_event
  * @return
  */
-static inline dap_chain_datum_t* dap_chain_cs_dag_event_get_datum(dap_chain_cs_dag_event_t * a_event)
+static inline dap_chain_datum_t* dap_chain_cs_dag_event_get_datum(dap_chain_cs_dag_event_t * a_event,size_t a_event_size)
 {
-    return (dap_chain_datum_t* ) (a_event->hashes_n_datum_n_signs
-            +a_event->header.hash_count*sizeof(dap_chain_hash_fast_t));
+    return  a_event->header.hash_count*sizeof(dap_chain_hash_fast_t)<=a_event_size?(dap_chain_datum_t* ) (a_event->hashes_n_datum_n_signs
+            +a_event->header.hash_count*sizeof(dap_chain_hash_fast_t)): NULL;
 }
 
-dap_chain_cs_dag_event_t * dap_chain_cs_dag_event_copy(dap_chain_cs_dag_event_t *a_event_src);
+dap_chain_cs_dag_event_t * dap_chain_cs_dag_event_copy(dap_chain_cs_dag_event_t *a_event_src, size_t a_event_size);
 
 // Important: returns new deep copy of event
-dap_chain_cs_dag_event_t * dap_chain_cs_dag_event_copy_with_sign_add( dap_chain_cs_dag_event_t * a_event, dap_enc_key_t * l_key);
-dap_sign_t * dap_chain_cs_dag_event_get_sign( dap_chain_cs_dag_event_t * a_event, uint16_t a_sign_number);
+dap_chain_cs_dag_event_t * dap_chain_cs_dag_event_copy_with_sign_add( dap_chain_cs_dag_event_t * a_event,size_t a_event_size, dap_enc_key_t * l_key);
+dap_sign_t * dap_chain_cs_dag_event_get_sign( dap_chain_cs_dag_event_t * a_event, size_t a_event_size, uint16_t a_sign_number);
 
 /**
  * @brief dap_chain_cs_dag_event_calc_size
  * @param a_event
  * @return
  */
+
+/**
 static inline size_t dap_chain_cs_dag_event_calc_size(dap_chain_cs_dag_event_t * a_event)
 {
     if(!a_event)
@@ -93,14 +95,16 @@ static inline size_t dap_chain_cs_dag_event_calc_size(dap_chain_cs_dag_event_t *
 
     return sizeof( a_event->header ) + l_hashes_size +l_signs_offset +l_datum_size;
 }
-
+**/
 /**
  * @brief dap_chain_cs_dag_event_calc_size_excl_signs
  * @param a_event
  * @return
  */
-static inline size_t dap_chain_cs_dag_event_calc_size_excl_signs(dap_chain_cs_dag_event_t * a_event)
+static inline ssize_t dap_chain_cs_dag_event_calc_size_excl_signs(dap_chain_cs_dag_event_t * a_event,size_t a_event_size)
 {
+    if (a_event_size< sizeof (a_event->header))
+        return -1;
     size_t l_hashes_size = a_event->header.hash_count*sizeof(dap_chain_hash_fast_t);
     dap_chain_datum_t * l_datum = (dap_chain_datum_t*) (a_event->hashes_n_datum_n_signs + l_hashes_size);
     size_t l_datum_size = dap_chain_datum_size(l_datum);
@@ -113,7 +117,7 @@ static inline size_t dap_chain_cs_dag_event_calc_size_excl_signs(dap_chain_cs_da
  * @param a_event
  * @param a_event_hash
  */
-static inline void dap_chain_cs_dag_event_calc_hash(dap_chain_cs_dag_event_t * a_event,dap_chain_hash_fast_t * a_event_hash)
+static inline void dap_chain_cs_dag_event_calc_hash(dap_chain_cs_dag_event_t * a_event,size_t a_event_size, dap_chain_hash_fast_t * a_event_hash)
 {
-    dap_hash_fast(a_event, dap_chain_cs_dag_event_calc_size (a_event) , a_event_hash);
+    dap_hash_fast(a_event, a_event_size , a_event_hash);
 }