From 7d4ec22375f097bad67386ce364af692fc0477b9 Mon Sep 17 00:00:00 2001
From: Dmitry Gerasimov <dmitriy.gerasimov@demlabs.net>
Date: Mon, 22 Aug 2022 17:54:55 +0700
Subject: [PATCH] [+] dap_config_load() for custom config loading [+]
 dap-sdk/plugin module for universal plugins. By default builtin binary loader
 [!] CLI server moved from dap_chain_net to the new module
 dap-sdk/net/cli_server [!] app-cli module moved from cellframe-sdk to dap-sdk
 [!] s_recv() -> dap_net_recv and also moved from dap_chain_net into the
 dap_net [*] DARWIN related fixes

---
 CMakeLists.txt                                |    8 +
 core/include/dap_common.h                     |   46 +
 core/include/dap_config.h                     |    1 +
 core/src/dap_config.c                         |  339 +++---
 io/dap_context.c                              |    7 +-
 io/dap_net.c                                  |   56 +
 io/include/dap_net.h                          |    2 +
 net/app-cli/CMakeLists.txt                    |   11 +
 net/app-cli/dap_app_cli.c                     |  221 ++++
 net/app-cli/dap_app_cli_net.c                 |  266 +++++
 net/app-cli/dap_app_cli_shell.c               |  356 ++++++
 net/app-cli/include/dap_app_cli.h             |   53 +
 net/app-cli/include/dap_app_cli_net.h         |   54 +
 net/app-cli/include/dap_app_cli_shell.h       |   53 +
 net/server/CMakeLists.txt                     |    2 +
 net/server/cli_server/CMakeLists.txt          |   11 +
 net/server/cli_server/dap_cli_server.c        | 1012 +++++++++++++++++
 .../cli_server/include/dap_cli_server.h       |   67 ++
 net/stream/stream/dap_stream.c                |    1 -
 plugin/CMakeLists.txt                         |   18 +
 plugin/include/dap_plugin.h                   |   56 +
 plugin/include/dap_plugin_binary.h            |   27 +
 plugin/include/dap_plugin_command.h           |   37 +
 plugin/include/dap_plugin_manifest.h          |   86 ++
 plugin/src/dap_plugin.c                       |  292 +++++
 plugin/src/dap_plugin_binary.c                |  128 +++
 plugin/src/dap_plugin_command.c               |  156 +++
 plugin/src/dap_plugin_manifest.c              |  289 +++++
 28 files changed, 3487 insertions(+), 168 deletions(-)
 create mode 100644 net/app-cli/CMakeLists.txt
 create mode 100644 net/app-cli/dap_app_cli.c
 create mode 100644 net/app-cli/dap_app_cli_net.c
 create mode 100644 net/app-cli/dap_app_cli_shell.c
 create mode 100644 net/app-cli/include/dap_app_cli.h
 create mode 100644 net/app-cli/include/dap_app_cli_net.h
 create mode 100644 net/app-cli/include/dap_app_cli_shell.h
 create mode 100644 net/server/cli_server/CMakeLists.txt
 create mode 100644 net/server/cli_server/dap_cli_server.c
 create mode 100644 net/server/cli_server/include/dap_cli_server.h
 create mode 100644 plugin/CMakeLists.txt
 create mode 100644 plugin/include/dap_plugin.h
 create mode 100644 plugin/include/dap_plugin_binary.h
 create mode 100644 plugin/include/dap_plugin_command.h
 create mode 100644 plugin/include/dap_plugin_manifest.h
 create mode 100644 plugin/src/dap_plugin.c
 create mode 100644 plugin/src/dap_plugin_binary.c
 create mode 100644 plugin/src/dap_plugin_command.c
 create mode 100644 plugin/src/dap_plugin_manifest.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0781b5dec..1a7d3a233 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,6 +14,14 @@ if (DAPSDK_MODULES MATCHES "crypto")
     add_subdirectory(crypto)
 endif()
 
+if (DAPSDK_MODULES MATCHES "app-cli")
+    add_subdirectory(net/app-cli)
+endif()
+
+if (DAPSDK_MODULES MATCHES "plugin")
+    add_subdirectory(plugin)
+endif()
+
 # I/O subsystem
 if (DAPSDK_MODULES MATCHES "io")
     add_subdirectory(io)
diff --git a/core/include/dap_common.h b/core/include/dap_common.h
index 972a8b990..1269d8eeb 100755
--- a/core/include/dap_common.h
+++ b/core/include/dap_common.h
@@ -511,6 +511,52 @@ char **dap_parse_items(const char *a_str, char a_delimiter, int *a_count, const
 
 unsigned int dap_crc32c(unsigned int crc, const void *buf, size_t buflen);
 
+static inline const char *dap_get_arch() { //Get current architecture, detectx nearly every architecture. Coded by Freak
+        #if defined(__x86_64__) || defined(_M_X64)
+        return "x86_64";
+        #elif defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86)
+        return "x86_32";
+        #elif defined(__ARM_ARCH_2__)
+        return "ARM2";
+        #elif defined(__ARM_ARCH_3__) || defined(__ARM_ARCH_3M__)
+        return "ARM3";
+        #elif defined(__ARM_ARCH_4T__) || defined(__TARGET_ARM_4T)
+        return "ARM4T";
+        #elif defined(__ARM_ARCH_5_) || defined(__ARM_ARCH_5E_)
+        return "ARM5"
+        #elif defined(__ARM_ARCH_6T2_) || defined(__ARM_ARCH_6T2_)
+        return "ARM6T2";
+        #elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
+        return "ARM6";
+        #elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
+        return "ARM7";
+        #elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
+        return "ARM7A";
+        #elif defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
+        return "ARM7R";
+        #elif defined(__ARM_ARCH_7M__)
+        return "ARM7M";
+        #elif defined(__ARM_ARCH_7S__)
+        return "ARM7S";
+        #elif defined(__aarch64__) || defined(_M_ARM64)
+        return "ARM64";
+        #elif defined(mips) || defined(__mips__) || defined(__mips)
+        return "MIPS";
+        #elif defined(__sh__)
+        return "SUPERH";
+        #elif defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) || defined(__POWERPC__) || defined(__ppc__) || defined(__PPC__) || defined(_ARCH_PPC)
+        return "POWERPC";
+        #elif defined(__PPC64__) || defined(__ppc64__) || defined(_ARCH_PPC64)
+        return "POWERPC64";
+        #elif defined(__sparc__) || defined(__sparc)
+        return "SPARC";
+        #elif defined(__m68k__)
+        return "M68K";
+        #else
+        return "UNKNOWN";
+        #endif
+    }
+
 #ifdef __MINGW32__
 int exec_silent(const char *a_cmd);
 #endif
diff --git a/core/include/dap_config.h b/core/include/dap_config.h
index 806bf6eac..944c32002 100755
--- a/core/include/dap_config.h
+++ b/core/include/dap_config.h
@@ -40,6 +40,7 @@ typedef struct dap_config{
 int dap_config_init(const char * a_configs_path);
 void dap_config_deinit();
 dap_config_t * dap_config_open(const char * a_name);
+dap_config_t * dap_config_load(const char * a_file_path);
 void dap_config_close(dap_config_t * a_config);
 
 const char * dap_config_path();
diff --git a/core/src/dap_config.c b/core/src/dap_config.c
index 27f0a2e3f..e4961e662 100755
--- a/core/src/dap_config.c
+++ b/core/src/dap_config.c
@@ -105,194 +105,207 @@ static uint16_t get_array_length(const char* str) {
  */
 dap_config_t * dap_config_open(const char * a_name)
 {
-    dap_config_t * ret = NULL;
+    dap_config_t * l_ret = NULL;
     if ( a_name ){
         log_it(L_DEBUG,"Looking for config name %s...",a_name);
         size_t l_config_path_size_max = strlen(a_name)+6+strlen(s_configs_path);
         char *l_config_path = DAP_NEW_SIZE(char,l_config_path_size_max);
         snprintf(l_config_path,l_config_path_size_max, "%s/%s.cfg",s_configs_path,a_name);
-        FILE * f = fopen(l_config_path,"r");
-        if ( f ){
-            fseek(f, 0, SEEK_END);
-            long buf_len = ftell(f);
-            char buf[buf_len];
-            fseek(f, 0L, SEEK_SET);
-            log_it(L_DEBUG,"Opened config %s",l_config_path);
-            ret = DAP_NEW_Z(dap_config_t);
-            dap_config_internal_t * l_config_internal = DAP_NEW_Z(dap_config_internal_t);
-            ret->_internal = l_config_internal;
-            size_t l_global_offset=0;
-            size_t l_buf_size=0;
-            size_t l_buf_pos_line_start=0;
-            size_t l_buf_pos_line_end=0;
-            dap_config_item_t * l_section_current = NULL ;
-            bool l_is_space_now = false;
-            while ( feof(f)==0){ // Break on lines
-                size_t i;
-                l_global_offset +=  (l_buf_size = fread(buf, 1, buf_len, f) );
-                for (i=0; i< l_buf_size; i++){
-                    if( (buf[i] == '\r') || (buf[i] == '\n' ) ){
-                        if( ! l_is_space_now){
-                            l_buf_pos_line_end = i;
-                            l_is_space_now = true;
-                            //if(l_buf_pos_line_end)
-                            //    l_buf_pos_line_end--;
-                            if(l_buf_pos_line_end != l_buf_pos_line_start ){ // Line detected
-                                char *l_line = NULL;
-                                size_t l_line_length = 0;
-                                size_t j;
-
-                                // Trimming spaces and skip the line if commented
-                                for ( j = l_buf_pos_line_start; j < l_buf_pos_line_end; j++ ){
-                                    if ( buf[j] == '#' )
-                                        break;
-                                    if (buf[j] != ' ' ){
-                                        l_line_length = (l_buf_pos_line_end - j);
-                                        break;
-                                    }
+        l_ret = dap_config_load(l_config_path);
+        DAP_DELETE(l_config_path);
+    }else{
+        log_it(L_ERROR,"Config name is NULL");
+    }
+    return l_ret;
+}
+
+/**
+ * @brief Load config from file
+ * @param a_file_path
+ * @return
+ */
+dap_config_t * dap_config_load(const char * a_file_path)
+{
+    dap_config_t * l_ret = NULL;
+
+    FILE * f = fopen(a_file_path,"r");
+    if ( f ){
+        fseek(f, 0, SEEK_END);
+        long buf_len = ftell(f);
+        char buf[buf_len];
+        fseek(f, 0L, SEEK_SET);
+        log_it(L_DEBUG,"Opened config %s",a_file_path);
+        l_ret = DAP_NEW_Z(dap_config_t);
+        dap_config_internal_t * l_config_internal = DAP_NEW_Z(dap_config_internal_t);
+        l_ret->_internal = l_config_internal;
+        size_t l_global_offset=0;
+        size_t l_buf_size=0;
+        size_t l_buf_pos_line_start=0;
+        size_t l_buf_pos_line_end=0;
+        dap_config_item_t * l_section_current = NULL ;
+        bool l_is_space_now = false;
+        while ( feof(f)==0){ // Break on lines
+            size_t i;
+            l_global_offset +=  (l_buf_size = fread(buf, 1, buf_len, f) );
+            for (i=0; i< l_buf_size; i++){
+                if( (buf[i] == '\r') || (buf[i] == '\n' ) ){
+                    if( ! l_is_space_now){
+                        l_buf_pos_line_end = i;
+                        l_is_space_now = true;
+                        //if(l_buf_pos_line_end)
+                        //    l_buf_pos_line_end--;
+                        if(l_buf_pos_line_end != l_buf_pos_line_start ){ // Line detected
+                            char *l_line = NULL;
+                            size_t l_line_length = 0;
+                            size_t j;
+
+                            // Trimming spaces and skip the line if commented
+                            for ( j = l_buf_pos_line_start; j < l_buf_pos_line_end; j++ ){
+                                if ( buf[j] == '#' )
+                                    break;
+                                if (buf[j] != ' ' ){
+                                    l_line_length = (l_buf_pos_line_end - j);
+                                    break;
                                 }
-                                if( l_line_length ){
-                                    l_line = DAP_NEW_SIZE(char,l_line_length+1);
-                                    memcpy(l_line,buf+j,l_line_length);
-                                    l_line[l_line_length] = 0;
-
-                                    // Process trimmed line
-                                    if( (l_line[0] == '[' ) && (l_line[l_line_length-1] == ']' ) ){ // Section detected
-                                        //log_it(L_DEBUG, "Raw line '%s'",l_line);
-                                        char * l_section_name = strdup(l_line+1);
-                                        size_t l_section_name_length = (l_line_length - 2);
-                                        l_section_name[l_section_name_length]='\0';
-                                        // log_it(L_DEBUG,"Config section '%s'",l_section_name);
-
-                                        dap_config_item_t * l_item_section = DAP_NEW_Z(dap_config_item_t);
-                                        strncpy(l_item_section->name,l_section_name,sizeof(l_item_section->name)-1);
-                                        l_item_section->item_next = l_config_internal->item_root;
-                                        l_config_internal->item_root = l_item_section;
-                                        free(l_section_name);
-
-                                        l_section_current = l_item_section;
-                                    }else{ // key-value line
-                                        //log_it(L_DEBUG,"Read line '%s'",l_line);
-                                        char l_param_name[sizeof(l_section_current->name)];
-                                        size_t l_param_name_size=0;
-                                        size_t l_param_value_size=0;
-                                        char l_param_value[1024];
-                                        l_param_name[0] = 0;
-                                        l_param_value[0] = 0;
-                                        for ( j = 0; j < l_line_length; j++ ){ // Parse param name
-                                            if ( ( l_line[j] == ' ' )|| ( l_line[j] == '=' ) ||( l_line[j] == '\t' ) ){ // Param name
-                                                l_param_name_size = j;
-                                                if (l_param_name_size > (sizeof(l_param_name) -1) ){
-                                                    l_param_name_size = (sizeof(l_param_name) - 1 );
-                                                    log_it(L_WARNING,"Too long param name in config, %zu is more than %zu maximum",
-                                                           j,sizeof(l_param_name) -1);
-                                                }
-                                                strncpy(l_param_name,l_line,j);
-                                                l_param_name[j] = 0;
-                                                break;
+                            }
+                            if( l_line_length ){
+                                l_line = DAP_NEW_SIZE(char,l_line_length+1);
+                                memcpy(l_line,buf+j,l_line_length);
+                                l_line[l_line_length] = 0;
+
+                                // Process trimmed line
+                                if( (l_line[0] == '[' ) && (l_line[l_line_length-1] == ']' ) ){ // Section detected
+                                    //log_it(L_DEBUG, "Raw line '%s'",l_line);
+                                    char * l_section_name = strdup(l_line+1);
+                                    size_t l_section_name_length = (l_line_length - 2);
+                                    l_section_name[l_section_name_length]='\0';
+                                    // log_it(L_DEBUG,"Config section '%s'",l_section_name);
+
+                                    dap_config_item_t * l_item_section = DAP_NEW_Z(dap_config_item_t);
+                                    strncpy(l_item_section->name,l_section_name,sizeof(l_item_section->name)-1);
+                                    l_item_section->item_next = l_config_internal->item_root;
+                                    l_config_internal->item_root = l_item_section;
+                                    free(l_section_name);
+
+                                    l_section_current = l_item_section;
+                                }else{ // key-value line
+                                    //log_it(L_DEBUG,"Read line '%s'",l_line);
+                                    char l_param_name[sizeof(l_section_current->name)];
+                                    size_t l_param_name_size=0;
+                                    size_t l_param_value_size=0;
+                                    char l_param_value[1024];
+                                    l_param_name[0] = 0;
+                                    l_param_value[0] = 0;
+                                    for ( j = 0; j < l_line_length; j++ ){ // Parse param name
+                                        if ( ( l_line[j] == ' ' )|| ( l_line[j] == '=' ) ||( l_line[j] == '\t' ) ){ // Param name
+                                            l_param_name_size = j;
+                                            if (l_param_name_size > (sizeof(l_param_name) -1) ){
+                                                l_param_name_size = (sizeof(l_param_name) - 1 );
+                                                log_it(L_WARNING,"Too long param name in config, %zu is more than %zu maximum",
+                                                       j,sizeof(l_param_name) -1);
                                             }
-
+                                            strncpy(l_param_name,l_line,j);
+                                            l_param_name[j] = 0;
+                                            break;
                                         }
 
-                                        for (; j < l_line_length; j++ ){ // Find beginning of param value
-                                            if ( ( l_line[j] != '\t' ) && ( l_line[j] != ' ' ) && ( l_line[j] != '=' ) ){
+                                    }
+
+                                    for (; j < l_line_length; j++ ){ // Find beginning of param value
+                                        if ( ( l_line[j] != '\t' ) && ( l_line[j] != ' ' ) && ( l_line[j] != '=' ) ){
+                                            break;
+                                        }
+                                    }
+                                    l_param_value_size = l_line_length - j;
+                                    if (l_param_value_size ){
+                                        if (l_param_value_size > (sizeof(l_param_value) -1) ){
+                                            l_param_value_size = (sizeof(l_param_value) - 1 );
+                                            log_it(L_WARNING,"Too long param value in config, %zu is more than %zu maximum",
+                                                   l_line_length - j,sizeof(l_param_value) -1);
+                                        }
+                                        strncpy(l_param_value,l_line +j, l_param_value_size);
+                                        l_param_value[l_param_value_size] = '\0';
+                                        for(int j=(int)l_param_value_size-1; j>=0; j--){
+                                            if( (l_param_value[j] ==' ') || (l_param_value[j] =='\t') ){
+                                                l_param_value[j] = '\0';
+                                            }else{
                                                 break;
                                             }
                                         }
-                                        l_param_value_size = l_line_length - j;
-                                        if (l_param_value_size ){
-                                            if (l_param_value_size > (sizeof(l_param_value) -1) ){
-                                                l_param_value_size = (sizeof(l_param_value) - 1 );
-                                                log_it(L_WARNING,"Too long param value in config, %zu is more than %zu maximum",
-                                                       l_line_length - j,sizeof(l_param_value) -1);
-                                            }
-                                            strncpy(l_param_value,l_line +j, l_param_value_size);
-                                            l_param_value[l_param_value_size] = '\0';
-                                            for(int j=(int)l_param_value_size-1; j>=0; j--){
-                                                if( (l_param_value[j] ==' ') || (l_param_value[j] =='\t') ){
-                                                    l_param_value[j] = '\0';
-                                                }else{
-                                                    break;
-                                                }
+                                    }
+                                //    log_it(L_DEBUG,"  Param '%s' = '%s'", l_param_name, l_param_value);
+                                    if (l_section_current){
+
+                                        if (l_param_value[0] == '[') {
+                                            if(l_param_value[1] == ']') {
+                                                //log_it(L_WARNING, "Empty array!");
+                                                DAP_DELETE(l_line);
+                                                continue;
                                             }
-                                        }
-                                    //    log_it(L_DEBUG,"  Param '%s' = '%s'", l_param_name, l_param_value);
-                                        if (l_section_current){
-
-                                            if (l_param_value[0] == '[') {
-                                                if(l_param_value[1] == ']') {
-                                                    //log_it(L_WARNING, "Empty array!");
-                                                    DAP_DELETE(l_line);
-                                                    continue;
-                                                }
-
-                                                // delete '[' and ']'
-                                                char* values = l_param_value + 1;
-                                                values[l_param_value_size-2] = 0;
-
-                                                dap_config_item_t * l_item = DAP_NEW_Z(dap_config_item_t);
-
-                                                strncpy(l_item->name,l_param_name,sizeof(l_item->name));
-                                                l_item->item_next = l_section_current->childs;
-                                                l_item->is_array = true;
-                                                l_section_current->childs = l_item;
-                                                l_item->array_length = get_array_length(l_param_value);
-                                                l_item->data_str_array = (char**) malloc (sizeof(char*) * l_item->array_length);
-                                                // parsing items in array
-                                                int j = 0;
-                                                char * l_tmp = NULL;
-                                                char *token = strtok_r(values, ",",&l_tmp);
-                                                while(token) {
-
-                                                    // trim token whitespace
-                                                    if (isspace(token[0]))
-                                                        token = token + 1;
-                                                    char *closer = strchr(token, ']');
-                                                    if (closer) /* last item in array */
-                                                        *closer = 0;
-
-                                                    l_item->data_str_array[j] = strdup(token);
-
-                                                    token = strtok_r(NULL, ",",&l_tmp);
-                                                    j++;
-                                                }
-                                                l_item->array_length = j;
-                                            } else {
-                                                dap_config_item_t * l_item = DAP_NEW_Z(dap_config_item_t);
-
-                                                strncpy(l_item->name,l_param_name,sizeof(l_item->name));
-                                                l_item->item_next = l_section_current->childs;
-                                                l_item->data_str = strdup (l_param_value);
-
-                                                l_section_current->childs = l_item;
+
+                                            // delete '[' and ']'
+                                            char* values = l_param_value + 1;
+                                            values[l_param_value_size-2] = 0;
+
+                                            dap_config_item_t * l_item = DAP_NEW_Z(dap_config_item_t);
+
+                                            strncpy(l_item->name,l_param_name,sizeof(l_item->name));
+                                            l_item->item_next = l_section_current->childs;
+                                            l_item->is_array = true;
+                                            l_section_current->childs = l_item;
+                                            l_item->array_length = get_array_length(l_param_value);
+                                            l_item->data_str_array = (char**) malloc (sizeof(char*) * l_item->array_length);
+                                            // parsing items in array
+                                            int j = 0;
+                                            char * l_tmp = NULL;
+                                            char *token = strtok_r(values, ",",&l_tmp);
+                                            while(token) {
+
+                                                // trim token whitespace
+                                                if (isspace(token[0]))
+                                                    token = token + 1;
+                                                char *closer = strchr(token, ']');
+                                                if (closer) /* last item in array */
+                                                    *closer = 0;
+
+                                                l_item->data_str_array[j] = strdup(token);
+
+                                                token = strtok_r(NULL, ",",&l_tmp);
+                                                j++;
                                             }
-                                        }else{
-                                            log_it(L_ERROR,"Can't add param to a tree without current section");
-                                        }
+                                            l_item->array_length = j;
+                                        } else {
+                                            dap_config_item_t * l_item = DAP_NEW_Z(dap_config_item_t);
 
+                                            strncpy(l_item->name,l_param_name,sizeof(l_item->name));
+                                            l_item->item_next = l_section_current->childs;
+                                            l_item->data_str = strdup (l_param_value);
+
+                                            l_section_current->childs = l_item;
+                                        }
+                                    }else{
+                                        log_it(L_ERROR,"Can't add param to a tree without current section");
                                     }
-                                    DAP_DELETE(l_line);
+
                                 }
+                                DAP_DELETE(l_line);
                             }
                         }
-                        continue;
-                    }else{
-                        if (l_is_space_now){
-                            l_is_space_now = false;
-                            l_buf_pos_line_start = i;
-                        }
+                    }
+                    continue;
+                }else{
+                    if (l_is_space_now){
+                        l_is_space_now = false;
+                        l_buf_pos_line_start = i;
                     }
                 }
             }
-            fclose(f);
-        }else{
-            log_it(L_ERROR,"Can't open config file '%s' (%s)",l_config_path,strerror(errno));
         }
-        DAP_DELETE(l_config_path);
+        fclose(f);
     }else{
-        log_it(L_ERROR,"Config name is NULL");
+        log_it(L_ERROR,"Can't open config file '%s' (%s)",a_file_path,strerror(errno));
     }
-    return ret;
+    return l_ret;
 }
 
 /**
diff --git a/io/dap_context.c b/io/dap_context.c
index 4b0ec46c0..99c1329b3 100644
--- a/io/dap_context.c
+++ b/io/dap_context.c
@@ -1159,8 +1159,7 @@ int dap_context_poll_update(dap_events_socket_t * a_esocket)
     u_short l_flags =a_esocket->kqueue_base_flags;
     u_int l_fflags =a_esocket->kqueue_base_fflags;
 
-    int l_kqueue_fd = a_esocket->worker? a_esocket->worker->kqueue_fd :
-                      a_esocket->proc_thread ? a_esocket->proc_thread->kqueue_fd : -1;
+    int l_kqueue_fd = a_esocket->context->kqueue_fd;
     if ( l_kqueue_fd == -1 ){
         log_it(L_ERROR, "Esocket is not assigned with anything ,exit");
     }
@@ -1190,8 +1189,8 @@ int dap_context_poll_update(dap_events_socket_t * a_esocket)
         }
     }
     if (l_is_error && l_errno == EBADF){
-        log_it(L_ATT,"Poll update: socket %d (%p ) disconnected, rise CLOSE flag to remove from queue, lost %"DAP_UINT64_FORMAT_U":%" DAP_UINT64_FORMAT_U
-                     " bytes",a_esocket->socket,a_esocket,a_esocket->buf_in_size,a_esocket->buf_out_size);
+        log_it(L_ATT,"Poll update: socket %d (%p ) disconnected, rise CLOSE flag to remove from queue, lost %zd:%zd bytes",
+               a_esocket->socket,a_esocket,a_esocket->buf_in_size,a_esocket->buf_out_size);
         a_esocket->flags |= DAP_SOCK_SIGNAL_CLOSE;
         a_esocket->buf_in_size = a_esocket->buf_out_size = 0; // Reset everything from buffer, we close it now all
     }else if ( l_is_error && l_errno != EINPROGRESS && l_errno != ENOENT){
diff --git a/io/dap_net.c b/io/dap_net.c
index 072388a71..862516695 100644
--- a/io/dap_net.c
+++ b/io/dap_net.c
@@ -1,3 +1,29 @@
+#ifndef _WIN32
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+//#include <unistd.h> // for close
+#include <fcntl.h>
+//#include <sys/poll.h>
+//#include <sys/select.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+//#define closesocket close
+//typedef int SOCKET;
+//#define SOCKET_ERROR    -1  // for win32 =  (-1)
+//#define INVALID_SOCKET  -1  // for win32 =  (SOCKET)(~0)
+// for Windows
+#else
+#include <winsock2.h>
+#include <windows.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <io.h>
+#endif
+
+#include <errno.h>
 #include <string.h>
 #include "dap_net.h"
 
@@ -47,3 +73,33 @@ int dap_net_resolve_host(const char *a_host, int ai_family, struct sockaddr *a_a
         freeaddrinfo(l_res);
     return -1;
 }
+
+/**
+ * @brief s_recv
+ * timeout in milliseconds
+ * return the number of read bytes (-1 err or -2 timeout)
+ * @param sock
+ * @param buf
+ * @param bufsize
+ * @param timeout
+ * @return long
+ */
+long dap_net_recv(SOCKET sd, unsigned char *buf, size_t bufsize, int timeout)
+{
+struct pollfd fds = {.fd = sd, .events = POLLIN};
+int res;
+
+    if ( !(res = poll(&fds, 1, timeout)) )
+        return -2;
+
+    if ( (res == 1) && !(fds.revents & POLLIN))
+        return -1;
+
+    if(res < 1)
+        return -1;
+
+    if ( 0 >= (res = recv(sd, (char *)buf, bufsize, 0)) )
+        printf("[s_recv] recv()->%d, errno: %d\n", res, errno);
+
+    return res;
+}
diff --git a/io/include/dap_net.h b/io/include/dap_net.h
index 2c79b8971..3a5c8350e 100644
--- a/io/include/dap_net.h
+++ b/io/include/dap_net.h
@@ -43,5 +43,7 @@
 #endif
 
 #include "dap_common.h"
+#include "dap_events_socket.h"
 
 int dap_net_resolve_host(const char *a_host, int ai_family, struct sockaddr *a_addr_out);
+long dap_net_recv(SOCKET sd, unsigned char *buf, size_t bufsize, int timeout);
diff --git a/net/app-cli/CMakeLists.txt b/net/app-cli/CMakeLists.txt
new file mode 100644
index 000000000..d3827063a
--- /dev/null
+++ b/net/app-cli/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.10)
+project (dap_app_cli)
+
+file(GLOB DAP_APP_CLI_SRCS *.c)
+
+file(GLOB DAP_APP_CLI_HEADERS include/*.h)
+
+add_library(${PROJECT_NAME} STATIC ${DAP_APP_CLI_SRCS} ${DAP_APP_CLI_HEADERS} )
+
+target_link_libraries(${PROJECT_NAME} dap_core dap_io dap_cli_server m)
+target_include_directories(${PROJECT_NAME} PUBLIC include/ )
diff --git a/net/app-cli/dap_app_cli.c b/net/app-cli/dap_app_cli.c
new file mode 100644
index 000000000..9d29d16ce
--- /dev/null
+++ b/net/app-cli/dap_app_cli.c
@@ -0,0 +1,221 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <kahovski@gmail.com>
+ * DeM Labs Inc.   https://demlabs.net
+ * DeM Labs Open source community https://github.com/demlabsinc
+ * Copyright  (c) 2017-2019
+ * 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 <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+//#include "dap_client.h"
+#include "dap_common.h"
+#include "dap_file_utils.h"
+#include "dap_strfuncs.h"
+#include "dap_cli_server.h"
+#include "dap_app_cli.h"
+#include "dap_app_cli_net.h"
+#include "dap_app_cli_shell.h"
+
+
+#ifdef _WIN32
+#include "registry.h"
+#endif
+
+
+/**
+ * split string to argc and argv
+ */
+static char** split_word(char *line, int *argc)
+{
+    if(!line)
+    {
+        if(argc)
+            *argc = 0;
+        return NULL ;
+    }
+    char **argv = calloc(sizeof(char*), strlen(line));
+    int n = 0;
+    char *s, *start = line;
+    size_t len = strlen(line);
+    for(s = line; s <= line + len; s++) {
+        if(whitespace(*s)) {
+            *s = '\0';
+            argv[n] = start;
+            s++;
+            // miss spaces
+            for(; whitespace(*s); s++)
+                ;
+            start = s;
+            n++;
+        }
+    }
+    // last param
+    if(len) {
+        argv[n] = start;
+        n++;
+    }
+    if(argc)
+        *argc = n;
+    return argv;
+}
+
+/*
+ * Execute a command line.
+ */
+int execute_line(dap_app_cli_connect_param_t *cparam, char *line)
+{
+    register int i;
+    dap_cli_cmd_t *command;
+    char *word;
+
+    /* Isolate the command word. */
+    i = 0;
+    while(line[i] && whitespace(line[i]))
+        i++;
+    word = line + i;
+
+    int argc = 0;
+    char **argv = split_word(word, &argc);
+
+    // Call the function
+    if(argc > 0) {
+        dap_app_cli_cmd_state_t cmd;
+        memset(&cmd, 0, sizeof(dap_app_cli_cmd_state_t));
+        cmd.cmd_name = (char *) argv[0];
+        cmd.cmd_param_count = argc - 1;
+        if(cmd.cmd_param_count > 0)
+            cmd.cmd_param = (char**) (argv + 1);
+        // Send command
+        int res = dap_app_cli_post_command(cparam, &cmd);
+        DAP_DELETE(argv);
+        return res;
+    }else{
+        DAP_DELETE(argv);
+        fprintf(stderr, "No command\n");
+        return -1;
+    }
+}
+
+/**
+ * Clear and delete memory of structure cmd_state
+ */
+void dap_app_cli_free_cmd_state(dap_app_cli_cmd_state_t *cmd) {
+    if(!cmd->cmd_param)
+        return;
+    for(int i = 0; i < cmd->cmd_param_count; i++)
+            {
+        DAP_DELETE(cmd->cmd_param[i]);
+    }
+    DAP_DELETE(cmd->cmd_res);
+    DAP_DELETE(cmd);
+}
+
+/**
+ *  Read and execute commands until EOF is reached.  This assumes that
+ *  the input source has already been initialized.
+ */
+int shell_reader_loop(dap_app_cli_connect_param_t *cparam)
+{
+    char *line, *s;
+
+    rl_initialize(); /* Bind our completer. */
+    int done = 0;
+    // Loop reading and executing lines until the user quits.
+    for(; done == 0;) {
+        // Read a line of input
+        line = rl_readline("> ");
+
+        if(!line)
+            break;
+
+        /* Remove leading and trailing whitespace from the line.
+         Then, if there is anything left, add it to the history list
+         and execute it. */
+        s = rl_stripwhite(line);
+
+        if(*s)
+        {
+            add_history(s);
+            execute_line(cparam, s);
+        }
+
+        DAP_DELETE(line);
+    }
+
+    return 0;
+}
+
+
+/**
+ * @brief dap_app_cli_main
+ * @param argc
+ * @param argv
+ * @return
+ */
+int dap_app_cli_main(const char * a_app_name, const char * a_socket_path, int a_argc, char **a_argv)
+{
+    dap_set_appname(a_app_name);
+    if (dap_common_init(dap_get_appname(), NULL,NULL) != 0) {
+        printf("Fatal Error: Can't init common functions module");
+        return -2;
+    }
+
+    dap_log_level_set(L_CRITICAL);
+#ifdef _WIN32
+    WSADATA wsaData;
+    WSAStartup(MAKEWORD(2,2), &wsaData);
+#endif
+    // connect to node
+    dap_app_cli_connect_param_t *cparam = dap_app_cli_connect( a_socket_path );
+    if(!cparam)
+    {
+        printf("Can't connect to %s on socket %s\n",dap_get_appname(), a_socket_path);
+        exit(-1);
+    }
+
+    if(a_argc > 1){
+        // Call the function
+        dap_app_cli_cmd_state_t cmd;
+        memset(&cmd, 0, sizeof(dap_app_cli_cmd_state_t));
+        cmd.cmd_name = strdup(a_argv[1]);
+        cmd.cmd_param_count = a_argc - 2;
+        if(cmd.cmd_param_count > 0)
+            cmd.cmd_param = (char**) (a_argv + 2);
+        // Send command
+        int res = dap_app_cli_post_command(cparam, &cmd);
+        dap_app_cli_disconnect(cparam);
+#ifdef _WIN32
+        WSACleanup();
+#endif
+        return res;
+    }else{
+        // command not found, start interactive shell
+        shell_reader_loop(cparam);
+        dap_app_cli_disconnect(cparam);
+    }
+#ifdef _WIN32
+        WSACleanup();
+#endif
+    return 0;
+}
+
diff --git a/net/app-cli/dap_app_cli_net.c b/net/app-cli/dap_app_cli_net.c
new file mode 100644
index 000000000..a1f37d22c
--- /dev/null
+++ b/net/app-cli/dap_app_cli_net.c
@@ -0,0 +1,266 @@
+/*
+ * Authors:
+ * Dmitriy A. Gerasimov <kahovski@gmail.com>
+ * Alexander Lysikov <alexander.lysikov@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * DeM Labs Open source community https://github.com/demlabsinc
+ * Copyright  (c) 2017-2019
+ * 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 <dap_client.h>
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <io.h>
+#else
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#endif
+
+#include "dap_common.h"
+#include "dap_string.h"
+#include "dap_strfuncs.h"
+#include "dap_cli_server.h" // for UNIX_SOCKET_FILE
+#include "dap_app_cli.h"
+#include "dap_app_cli_net.h"
+#include "dap_enc_base64.h"
+
+static int s_status;
+
+//staic function to receive http data
+static void dap_app_cli_http_read(dap_app_cli_connect_param_t *socket, dap_app_cli_cmd_state_t *l_cmd)
+{
+    ssize_t l_recv_len = recv(*socket, &l_cmd->cmd_res[l_cmd->cmd_res_cur], DAP_CLI_HTTP_RESPONSE_SIZE_MAX, 0);
+    if (l_recv_len == 0) {
+        s_status = DAP_CLI_ERROR_INCOMPLETE;
+        return;
+    }
+    if (l_recv_len == -1) {
+#ifdef DAP_OS_WINDOWS
+        int l_errno = WSAGetLastError();
+        if (l_errno == WSAEWOULDBLOCK) {
+#else
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+#endif
+            s_status = DAP_CLI_ERROR_TIMEOUT;
+        } else {
+            s_status = DAP_CLI_ERROR_SOCKET;
+        }
+        return;
+    }
+    l_cmd->cmd_res_cur +=(size_t) l_recv_len;
+    switch (s_status) {
+        case 1: {   // Find content length
+            const char *l_cont_len_str = "Content-Length: ";
+            char *l_str_ptr = strstr(l_cmd->cmd_res, l_cont_len_str);
+            if (l_str_ptr && strstr(l_str_ptr, "\r\n")) {
+                l_cmd->cmd_res_len = atoi(l_str_ptr + strlen(l_cont_len_str));
+                if (l_cmd->cmd_res_len == 0) {
+                    s_status = DAP_CLI_ERROR_FORMAT;
+                    break;
+                }
+                else {
+                    s_status++;
+                }
+            } else {
+                break;
+            }
+        }
+        case 2: {   // Find header end and throw out header
+            const char *l_head_end_str = "\r\n\r\n";
+            char *l_str_ptr = strstr(l_cmd->cmd_res, l_head_end_str);
+            if (l_str_ptr) {
+                l_str_ptr += strlen(l_head_end_str);
+                size_t l_head_size = l_str_ptr - l_cmd->cmd_res;
+                memmove(l_cmd->cmd_res, l_str_ptr, l_cmd->cmd_res_cur - l_head_size);
+                l_cmd->cmd_res_cur -= l_head_size;
+                // read rest of data
+                if(l_cmd->cmd_res_cur < l_cmd->cmd_res_len) {
+                    l_cmd->cmd_res = DAP_REALLOC(l_cmd->cmd_res, l_cmd->cmd_res_len + 1);
+                    while((l_cmd->cmd_res_len - l_cmd->cmd_res_cur) > 0) {
+                        ssize_t l_recv_len = recv(*socket, &l_cmd->cmd_res[l_cmd->cmd_res_cur], l_cmd->cmd_res_len - l_cmd->cmd_res_cur, 0);
+                        if(l_recv_len <= 0)
+                            break;
+                        l_cmd->cmd_res_cur += l_recv_len;
+                    }
+                }
+                s_status++;
+            } else {
+                break;
+            }
+        }
+        default:
+        case 3: {   // Complete command reply
+            if (l_cmd->cmd_res_cur == l_cmd->cmd_res_len) {
+                l_cmd->cmd_res[l_cmd->cmd_res_cur] = 0;
+                s_status = 0;
+            } else {
+                s_status = DAP_CLI_ERROR_FORMAT;
+            }
+        } break;
+    }
+}
+
+/**
+ * @brief dap_app_cli_connect
+ * @details Connect to node unix socket server
+ * @param a_socket_path
+ * @return if connect established, else NULL
+ */
+dap_app_cli_connect_param_t* dap_app_cli_connect(const char *a_socket_path)
+{
+    // set socket param
+    int buffsize = DAP_CLI_HTTP_RESPONSE_SIZE_MAX;
+#ifdef WIN32
+    // TODO connect to the named pipe "\\\\.\\pipe\\node_cli.pipe"
+    uint16_t l_cli_port = dap_config_get_item_uint16 ( g_config, "conserver", "listen_port_tcp");
+    if (!l_cli_port)
+        return NULL;
+    SOCKET l_socket = socket(AF_INET, SOCK_STREAM, 0);
+#else
+    if (!a_socket_path) {
+        return NULL;
+    }
+    // create socket
+    int l_socket = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (l_socket < 0) {
+        return NULL;
+    }
+    struct timeval l_to = {DAP_CLI_HTTP_TIMEOUT, 0};
+#endif
+    // connect
+    int l_addr_len;
+#ifdef WIN32
+    struct sockaddr_in l_remote_addr;
+    l_remote_addr.sin_family = AF_INET;
+    IN_ADDR _in_addr = { { .S_addr = htonl(INADDR_LOOPBACK) } };
+    l_remote_addr.sin_addr = _in_addr;
+    l_remote_addr.sin_port = l_cli_port;
+    l_addr_len = sizeof(struct sockaddr_in);
+#else
+    struct sockaddr_un l_remote_addr;
+    l_remote_addr.sun_family =  AF_UNIX;
+    strcpy(l_remote_addr.sun_path, a_socket_path);
+    l_addr_len = SUN_LEN(&l_remote_addr);
+#endif
+    if (connect(l_socket, (struct sockaddr *)&l_remote_addr, l_addr_len) == SOCKET_ERROR) {
+#ifdef __WIN32
+            _set_errno(WSAGetLastError());
+#endif
+        printf("Socket connection err: %d\n", errno);
+        closesocket(l_socket);
+        return NULL;
+    }
+    dap_app_cli_connect_param_t *l_ret = DAP_NEW(dap_app_cli_connect_param_t);
+    *l_ret = l_socket;
+    return l_ret;
+}
+
+/* if cli command argument contains one of the following symbol
+ argument is going to be encoded to base64 */
+static const char* s_dap_app_cli_forbidden_symbols[] = {"\r\n", ";", ""};
+
+bool s_dap_app_cli_cmd_contains_forbidden_symbol(const char * a_cmd_param){
+    for(int i = 0; s_dap_app_cli_forbidden_symbols[i][0] != '\0'; i++){
+        if(strstr(a_cmd_param, s_dap_app_cli_forbidden_symbols[i]))
+            return true;
+    }
+    return false;
+}
+
+/**
+ * Send request to kelvin-node
+ *
+ * return 0 if OK, else error code
+ */
+int dap_app_cli_post_command( dap_app_cli_connect_param_t *a_socket, dap_app_cli_cmd_state_t *a_cmd )
+{
+    if(!a_socket || !a_cmd || !a_cmd->cmd_name) {
+        assert(0);
+        return -1;
+    }
+    a_cmd->cmd_res = DAP_NEW_Z_SIZE(char, DAP_CLI_HTTP_RESPONSE_SIZE_MAX);
+    a_cmd->cmd_res_cur = 0;
+    dap_string_t *l_cmd_data = dap_string_new(a_cmd->cmd_name);
+    if (a_cmd->cmd_param) {
+        for (int i = 0; i < a_cmd->cmd_param_count; i++) {
+            if (a_cmd->cmd_param[i]) {
+                dap_string_append(l_cmd_data, "\r\n");
+                if(s_dap_app_cli_cmd_contains_forbidden_symbol(a_cmd->cmd_param[i])){
+                    char * l_cmd_param_base64 = dap_enc_strdup_to_base64(a_cmd->cmd_param[i]);
+                    dap_string_append(l_cmd_data, l_cmd_param_base64);
+                    DAP_DELETE(l_cmd_param_base64);
+                }else{
+                    dap_string_append(l_cmd_data, a_cmd->cmd_param[i]);
+                }
+            }
+        }
+    }
+    dap_string_append(l_cmd_data, "\r\n\r\n");
+    dap_string_t *l_post_data = dap_string_new("");
+    dap_string_printf(l_post_data, "POST /connect HTTP/1.1\r\n"
+                                   "Host: localhost\r\n"
+                                   "Content-Type: text/text\r\n"
+                                   "Content-Length: %zu\r\n"
+                                   "\r\n"
+                                   "%s", l_cmd_data->len, l_cmd_data->str);
+    send(*a_socket, l_post_data->str, l_post_data->len, 0);
+
+    //wait for command execution
+    time_t l_start_time = time(NULL);
+    s_status = 1;
+    while(s_status > 0) {
+        dap_app_cli_http_read(a_socket, a_cmd);
+        if (time(NULL) - l_start_time > DAP_CLI_HTTP_TIMEOUT)
+            s_status = DAP_CLI_ERROR_TIMEOUT;
+    }
+    // process result
+    if (a_cmd->cmd_res && !s_status) {
+        char **l_str = dap_strsplit(a_cmd->cmd_res, "\r\n", 1);
+        int l_cnt = dap_str_countv(l_str);
+        char *l_str_reply = NULL;
+        if (l_cnt == 2) {
+            //long l_err_code = strtol(l_str[0], NULL, 10);
+            l_str_reply = l_str[1];
+        }
+        printf("%s\n", (l_str_reply) ? l_str_reply : "no response");
+        dap_strfreev(l_str);
+    }
+    DAP_DELETE(a_cmd->cmd_res);
+    dap_string_free(l_cmd_data, true);
+    dap_string_free(l_post_data, true);
+    return s_status;
+}
+
+int dap_app_cli_disconnect(dap_app_cli_connect_param_t *a_socket)
+{
+    closesocket(*a_socket);
+    DAP_DELETE(a_socket);
+    return 0;
+}
diff --git a/net/app-cli/dap_app_cli_shell.c b/net/app-cli/dap_app_cli_shell.c
new file mode 100644
index 000000000..c1cf0201e
--- /dev/null
+++ b/net/app-cli/dap_app_cli_shell.c
@@ -0,0 +1,356 @@
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <getopt.h>
+#include <signal.h>
+#include <string.h>
+#include <assert.h>
+#include <setjmp.h>
+#include <locale.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <io.h>
+#include <pthread.h>
+#include <conio.h>
+#else
+#include <sys/ttydefaults.h>
+#endif
+
+#include "dap_common.h"
+#include "dap_app_cli.h"
+#include "dap_app_cli_shell.h"
+
+//#include "posixjmp.h"
+
+#ifndef savestring
+#define savestring(x) strcpy ((char *)malloc (1 + strlen (x)), (x))
+#endif
+
+typedef void rl_voidfunc_t(void);
+typedef void rl_vintfunc_t(int);
+
+/* Current prompt. */
+char *rl_prompt = (char *) NULL;
+int rl_visible_prompt_length = 0;
+
+/* Non-zero means we have been called at least once before. */
+static int rl_initialized;
+
+/* The stuff that gets printed out before the actual text of the line.
+ This is usually pointing to rl_prompt. */
+char *rl_display_prompt = (char *) NULL;
+
+/* Non-zero makes this the next keystroke to read. */
+int rl_pending_input = 0;
+
+/* Make this non-zero to return the current input_line. */
+int rl_done;
+/* Non-zero if the previous command was a kill command. */
+int _rl_last_command_was_kill = 0;
+
+/* Top level environment for readline_internal (). */
+jmp_buf _rl_top_level;
+
+/* Length of the current input line. */
+int rl_end;
+
+/* The character that can generate an EOF.  Really read from
+ the terminal driver... just defaulted here. */
+//int _rl_eof_char = CTRL('D');
+
+#define NEWLINE '\n'
+
+/* Input error; can be returned by (*rl_getc_function) if readline is reading
+ a top-level command (RL_ISSTATE (RL_STATE_READCMD)). */
+#define READERR         (-2)
+
+/* Possible state values for rl_readline_state */
+#define RL_STATE_NONE       0x000000        /* no state; before first call */
+
+#define RL_STATE_INITIALIZING   0x0000001   /* initializing */
+#define RL_STATE_INITIALIZED    0x0000002   /* initialization done */
+#define RL_STATE_READCMD    0x0000008   /* reading a command key */
+#define RL_STATE_INPUTPENDING   0x0020000   /* rl_execute_next called */
+#define RL_STATE_TERMPREPPED    0x0000004   /* terminal is prepped */
+
+/* Flags word encapsulating the current readline state. */
+unsigned long rl_readline_state = RL_STATE_NONE;
+
+#define RL_SETSTATE(x)      (rl_readline_state |= (x))
+#define RL_UNSETSTATE(x)    (rl_readline_state &= ~(x))
+#define RL_ISSTATE(x)       (rl_readline_state & (x))
+
+/* The names of the streams that we do input and output to. */
+FILE *rl_instream = (FILE *) NULL;
+FILE *rl_outstream = (FILE *) NULL;
+
+/**
+ * Read one symbol
+ */
+unsigned char rl_getc(FILE *stream)
+{
+    int result;
+    unsigned char c;
+
+    while(1)
+    {
+
+#if defined (__MINGW32__)
+        if (isatty (fileno (stream)))
+        return (_getch ()); /* "There is no error return." */
+#endif
+        result = 0;
+        if(result >= 0)
+            result = read(fileno(stream), &c, sizeof(unsigned char));
+        if(result == sizeof(unsigned char))
+            return (c);
+
+        /* If zero characters are returned, then the file that we are
+         reading from is empty!  Return EOF in that case. */
+        if(result == 0)
+            return (EOF);
+    }
+}
+
+/**
+ *  Set up the prompt and expand it.  Called from readline()
+ */
+int rl_set_prompt(const char *prompt)
+{
+    free(rl_prompt);
+    rl_prompt = prompt ? savestring(prompt) : (char *) NULL;
+    rl_display_prompt = rl_prompt ? rl_prompt : "";
+    fprintf(stdout, "%s", prompt);
+    fflush(stdout);
+    //rl_visible_prompt_length = rl_expand_prompt (rl_prompt);
+    return 0;
+}
+
+/**
+ *  Read a line of input.  Prompt with PROMPT.  An empty PROMPT means none.
+ *  A return value of NULL means that EOF was encountered.
+ */
+char *rl_readline(const char *prompt)
+{
+    int value_size = 3, value_len = 0;
+    char *value = DAP_NEW_Z_SIZE(char, value_size + 1);
+
+    // Set up the prompt
+    rl_set_prompt(prompt);
+
+    // Read a line of input from the global rl_instream, doing output on the global rl_outstream.
+    while(1)
+    {
+        unsigned char c = rl_getc(rl_instream);
+
+        if((char)c == EOF || c == NEWLINE)
+            break;
+        value[value_len] = c;
+        value_len++;
+        if(value_len == value_size) {
+            value_size += 32;
+            value = realloc(value, value_size + 1);
+        }
+    }
+    return (value);
+}
+
+static char* _rl_get_locale_var(const char *v)
+{
+    char *lspec;
+
+    lspec = getenv("LC_ALL");
+    if(lspec == 0 || *lspec == 0)
+        lspec = getenv(v);
+    if(lspec == 0 || *lspec == 0)
+        lspec = getenv("LANG");
+
+    return lspec;
+}
+
+/*
+ * Query the right environment variables and call setlocale() to initialize
+ * the C library locale settings.
+ */
+static char* _rl_init_locale(void)
+{
+    char *ret, *lspec;
+
+    /* Set the LC_CTYPE locale category from environment variables. */
+    lspec = _rl_get_locale_var("LC_CTYPE");
+    /* Since _rl_get_locale_var queries the right environment variables,
+     we query the current locale settings with setlocale(), and, if
+     that doesn't return anything, we set lspec to the empty string to
+     force the subsequent call to setlocale() to define the `native'
+     environment. */
+    if(lspec == 0 || *lspec == 0)
+        lspec = setlocale(LC_CTYPE, (char *) NULL);
+    if(lspec == 0)
+        lspec = "";
+    ret = setlocale(LC_CTYPE, lspec); /* ok, since it does not change locale */
+
+    //_rl_utf8locale = (ret && *ret) ? utf8locale (ret) : 0;
+
+    return ret;
+}
+
+/*
+ *  Initialize readline (and terminal if not already).
+ */
+int rl_initialize(void)
+{
+    /* If we have never been called before, initialize the
+     terminal and data structures. */
+    if(rl_initialized == 0)
+            {
+        RL_SETSTATE(RL_STATE_INITIALIZING);
+        rl_instream = (FILE *) stdin;
+        rl_outstream = (FILE *) stdout;
+        RL_UNSETSTATE(RL_STATE_INITIALIZING);
+        rl_initialized++;
+        RL_SETSTATE(RL_STATE_INITIALIZED);
+    }
+    else
+        (void) _rl_init_locale(); /* check current locale */
+    RL_SETSTATE(RL_STATE_INITIALIZING);
+    rl_instream = (FILE *) stdin;
+    rl_outstream = (FILE *) stdout;
+    RL_UNSETSTATE(RL_STATE_INITIALIZING);
+    return 0;
+}
+
+int parse_shell_options(char **argv, int arg_start, int arg_end)
+{
+    int arg_index;
+    int arg_character, on_or_off, next_arg, i;
+    char *o_option, *arg_string;
+
+    arg_index = arg_start;
+    while(arg_index != arg_end && (arg_string = argv[arg_index]) &&
+            (*arg_string == '-' || *arg_string == '+'))
+    {
+        /* There are flag arguments, so parse them. */
+        next_arg = arg_index + 1;
+
+        /* A single `-' signals the end of options.  From the 4.3 BSD sh.
+         An option `--' means the same thing; this is the standard
+         getopt(3) meaning. */
+        if(arg_string[0] == '-' &&
+                (arg_string[1] == '\0' ||
+                        (arg_string[1] == '-' && arg_string[2] == '\0')))
+            return (next_arg);
+
+        i = 1;
+        on_or_off = arg_string[0];
+        while( (arg_character = arg_string[i++]) != 0)
+        {
+            switch (arg_character)
+            {
+            case 'c':
+                //want_pending_command = 1;
+                break;
+
+            case 'l':
+                //make_login_shell = 1;
+                break;
+
+            case 's':
+                //read_from_stdin = 1;
+                break;
+
+            case 'o':
+                o_option = argv[next_arg];
+                if(o_option == 0)
+                        {
+                    //list_minus_o_opts(-1, (on_or_off == '-') ? 0 : 1);
+                    break;
+                }
+                //if(set_minus_o_option(on_or_off, o_option) != EXECUTION_SUCCESS)
+                //    exit(EX_BADUSAGE);
+                next_arg++;
+                break;
+
+            case 'O':
+                /* Since some of these can be overridden by the normal
+                 interactive/non-interactive shell initialization or
+                 initializing posix mode, we save the options and process
+                 them after initialization. */
+                o_option = argv[next_arg];
+                if(o_option == 0)
+                        {
+                    //shopt_listopt(o_option, (on_or_off == '-') ? 0 : 1);
+                    break;
+                }
+                //add_shopt_to_alist(o_option, on_or_off);
+                next_arg++;
+                break;
+
+            case 'D':
+                //dump_translatable_strings = 1;
+                break;
+
+            default:
+                break;
+//                if(change_flag(arg_character, on_or_off) == FLAG_ERROR)
+//                        {
+//                    report_error(_("%c%c: invalid option"), on_or_off, arg_character);
+//                    show_shell_usage(stderr, 0);
+//                    exit(EX_BADUSAGE);
+//                }
+            }
+        }
+        /* Can't do just a simple increment anymore -- what about
+         "bash -abouo emacs ignoreeof -hP"? */
+        arg_index = next_arg;
+    }
+
+    return (arg_index);
+}
+
+/**
+ *  Strip whitespace from the start and end of STRING.  Return a pointer into STRING.
+ */
+char * rl_stripwhite(char *string)
+{
+    register char *s, *t;
+
+    for(s = string; whitespace(*s); s++)
+        ;
+
+    if(*s == 0)
+        return (s);
+
+    t = s + strlen(s) - 1;
+    while(t > s && whitespace(*t))
+        t--;
+    *++t = '\0';
+
+    return s;
+}
+
+/* The structure used to store a history entry. */
+typedef struct _hist_entry {
+    char *line;
+    char *timestamp; /* char * rather than time_t for read/write */
+    char *data;
+} HIST_ENTRY;
+
+/**
+ *  Place STRING at the end of the history list.
+ */
+void add_history(const char *string)
+{
+    HIST_ENTRY *temp;
+    //   The data field is set to NULL
+    // TODO
+}
diff --git a/net/app-cli/include/dap_app_cli.h b/net/app-cli/include/dap_app_cli.h
new file mode 100644
index 000000000..944bb9c96
--- /dev/null
+++ b/net/app-cli/include/dap_app_cli.h
@@ -0,0 +1,53 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <kahovski@gmail.com>
+ * DeM Labs Inc.   https://demlabs.net
+ * DeM Labs Open source community https://github.com/demlabsinc
+ * Copyright  (c) 2017-2019
+ * 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>
+
+// command description
+typedef struct dap_app_cli_cmd_state {
+    char *cmd_name;
+    char **cmd_param;
+    int cmd_param_count;
+    int ret_code;
+    // for reply
+    char *cmd_res;
+    size_t cmd_res_len;
+    size_t cmd_res_cur;
+} dap_app_cli_cmd_state_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+ * Clear and delete memory of structure cmd_state
+ */
+void dap_app_cli_free_cmd_state(dap_app_cli_cmd_state_t *cmd);
+
+int dap_app_cli_main(const char * a_app_name, const char * a_socket_path, int argc, char **argv);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/net/app-cli/include/dap_app_cli_net.h b/net/app-cli/include/dap_app_cli_net.h
new file mode 100644
index 000000000..c4ffbd06d
--- /dev/null
+++ b/net/app-cli/include/dap_app_cli_net.h
@@ -0,0 +1,54 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <kahovski@gmail.com>
+ * DeM Labs Inc.   https://demlabs.net
+ * DeM Labs Open source community https://github.com/demlabsinc
+ * Copyright  (c) 2017-2019
+ * 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_app_cli.h"
+#include "dap_events_socket.h"
+
+#define DAP_CLI_HTTP_RESPONSE_SIZE_MAX 65536
+#define DAP_CLI_HTTP_TIMEOUT 10  // seconds
+#define DAP_CLI_ERROR_FORMAT    -1
+#define DAP_CLI_ERROR_TIMEOUT   -2
+#define DAP_CLI_ERROR_SOCKET    -3
+#define DAP_CLI_ERROR_INCOMPLETE -4
+
+// connection description
+typedef uint64_t dap_app_cli_connect_param_t;
+
+/**
+ * Connect to node unix socket server
+ *
+ * return struct connect_param if connect established, else NULL
+ */
+dap_app_cli_connect_param_t* dap_app_cli_connect(const char * a_socket_path);
+
+/**
+ * Send request to kelvin-node
+ *
+ * return 0 if OK, else error code
+ */
+int dap_app_cli_post_command(dap_app_cli_connect_param_t *socket, dap_app_cli_cmd_state_t *cmd);
+
+int dap_app_cli_disconnect(dap_app_cli_connect_param_t *socket);
diff --git a/net/app-cli/include/dap_app_cli_shell.h b/net/app-cli/include/dap_app_cli_shell.h
new file mode 100644
index 000000000..5fdfeb4a5
--- /dev/null
+++ b/net/app-cli/include/dap_app_cli_shell.h
@@ -0,0 +1,53 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <kahovski@gmail.com>
+ * DeM Labs Inc.   https://demlabs.net
+ * DeM Labs Open source community https://github.com/demlabsinc
+ * Copyright  (c) 2017-2019
+ * 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
+
+#ifndef whitespace
+#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
+#endif
+
+/*
+ *  Initialize readline (and terminal if not already).
+ */
+int rl_initialize(void);
+
+/**
+ *  Strip whitespace from the start and end of STRING.  Return a pointer into STRING.
+ */
+char * rl_stripwhite(char *string);
+
+/**
+ *  Read a line of input.  Prompt with PROMPT.  An empty PROMPT means none.
+ *  A return value of NULL means that EOF was encountered.
+ */
+char *rl_readline(const char *prompt);
+
+/**
+ *  Place STRING at the end of the history list.
+ */
+void add_history(const char *string);
+
+int parse_shell_options(char **argv, int arg_start, int arg_end);
+
diff --git a/net/server/CMakeLists.txt b/net/server/CMakeLists.txt
index 2ad3a1a3f..37e70acb3 100644
--- a/net/server/CMakeLists.txt
+++ b/net/server/CMakeLists.txt
@@ -1,11 +1,13 @@
 project(libdap-server C)
 cmake_minimum_required(VERSION 3.10)
 
+add_subdirectory(cli_server)
 add_subdirectory(notify_server)
 add_subdirectory(http_server)
 add_subdirectory(enc_server)
 add_subdirectory(json_rpc)
 
+
 if (BUILD_LIB_DAP_SERVER_TESTS)
     enable_testing()
     add_subdirectory(test)
diff --git a/net/server/cli_server/CMakeLists.txt b/net/server/cli_server/CMakeLists.txt
new file mode 100644
index 000000000..b67f12d27
--- /dev/null
+++ b/net/server/cli_server/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.10)
+project (dap_cli_server C)
+
+file(GLOB DAP_CLI_SRV_SRCS *.c)
+
+file(GLOB DAP_CLI_SRV_HEADERS include/*.h)
+
+add_library(${PROJECT_NAME} STATIC ${DAP_CLI_SRV_SRCS} ${DAP_CLI_SRV_HEADERS} )
+
+target_link_libraries(${PROJECT_NAME} dap_core dap_io m)
+target_include_directories(${PROJECT_NAME} PUBLIC include/ )
diff --git a/net/server/cli_server/dap_cli_server.c b/net/server/cli_server/dap_cli_server.c
new file mode 100644
index 000000000..4ba5f8560
--- /dev/null
+++ b/net/server/cli_server/dap_cli_server.c
@@ -0,0 +1,1012 @@
+/*
+ * Authors:
+ * Dmitriy A. Gerasimov <gerasimov.dmitriy@demlabs.net>
+ * Alexander Lysikov <alexander.lysikov@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * Cellframe  https://cellframe.net
+ * Copyright  (c) 2019-2021
+ * All rights reserved.
+
+ This file is part of Cellframe SDK
+
+ Cellframe 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.
+
+ Cellframe 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 Cellframe SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+//#include <glib.h>
+#include <unistd.h>
+
+#ifndef _WIN32
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+//#include <unistd.h> // for close
+#include <fcntl.h>
+//#include <sys/poll.h>
+//#include <sys/select.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+//#define closesocket close
+//typedef int SOCKET;
+//#define SOCKET_ERROR    -1  // for win32 =  (-1)
+//#define INVALID_SOCKET  -1  // for win32 =  (SOCKET)(~0)
+// for Windows
+#else
+#include <winsock2.h>
+#include <windows.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <io.h>
+#endif
+
+#include <pthread.h>
+
+#include "dap_common.h"
+#include "dap_strfuncs.h"
+#include "dap_file_utils.h"
+#include "dap_list.h"
+#include "dap_net.h"
+#include "dap_cli_server.h"
+
+#define LOG_TAG "dap_cli_server"
+
+#define MAX_CONSOLE_CLIENTS 16
+
+static SOCKET server_sockfd = -1; // network or local unix
+static uint32_t l_listen_port = 0;
+static bool s_debug_cli = false;
+
+#ifdef _WIN32
+  #define poll WSAPoll
+#endif
+
+static dap_cli_cmd_t * s_commands = NULL;
+
+
+static void* s_thread_one_client_func(void *args);
+static void* s_thread_main_func(void *args);
+static inline void s_cmd_add_ex(const char * a_name, dap_cli_server_cmd_callback_ex_t a_func, void *a_arg_func, const char *a_doc, const char *a_doc_ex);
+
+
+
+/**
+ * @brief dap_cli_server_init
+ * @param a_debug_more
+ * @param a_socket_path_or_address
+ * @param a_port
+ * @param a_permissions
+ * @return
+ */
+int dap_cli_server_init(bool a_debug_more,const char * a_socket_path_or_address, uint16_t a_port, const char * a_permissions)
+{
+    s_debug_cli = a_debug_more;
+#ifndef _WIN32
+    struct sockaddr_un l_server_addr={0};
+    l_server_addr.sun_family =  AF_UNIX;
+    snprintf(l_server_addr.sun_path,sizeof(l_server_addr.sun_path), "%s", a_socket_path_or_address);
+#else
+   pthread_t threadId;
+#endif
+
+    struct sockaddr_in server_addr;
+    SOCKET sockfd = -1;
+
+    // create thread for waiting of clients
+    pthread_t l_thread_id;
+
+    l_listen_port = dap_config_get_item_uint16_default( g_config, "conserver", "listen_port_tcp",0);
+
+    const char * l_listen_unix_socket_path = dap_config_get_item_str( g_config, "conserver", "listen_unix_socket_path");
+
+
+
+    const char * l_listen_unix_socket_permissions_str = dap_config_get_item_str( g_config, "conserver", "listen_unix_socket_permissions");
+    mode_t l_listen_unix_socket_permissions = 0770;
+
+    if ( l_listen_unix_socket_path && l_listen_unix_socket_permissions ) {
+        if ( l_listen_unix_socket_permissions_str ) {
+            uint16_t l_perms;
+            dap_sscanf(l_listen_unix_socket_permissions_str,"%ho", &l_perms);
+            l_listen_unix_socket_permissions = l_perms;
+        }
+        log_it( L_INFO, "Console interace on path %s (%04o) ", l_listen_unix_socket_path, l_listen_unix_socket_permissions );
+
+      #ifndef _WIN32
+
+        if ( server_sockfd >= 0 ) {
+            dap_cli_server_deinit();
+            server_sockfd = 0;
+        }
+
+        // create socket
+        sockfd = socket( AF_UNIX, SOCK_STREAM, 0 );
+        if( sockfd == INVALID_SOCKET )
+            return -1;
+
+        //int gdsg = sizeof(struct sockaddr_un);
+
+        // Creatuing directory if not created
+        char * l_listen_unix_socket_path_dir = dap_path_get_dirname(l_listen_unix_socket_path);
+        dap_mkdir_with_parents(l_listen_unix_socket_path_dir);
+        DAP_DELETE(l_listen_unix_socket_path_dir);
+
+        if ( access( l_listen_unix_socket_path , R_OK) != -1 )
+            unlink( l_listen_unix_socket_path );
+
+
+        // connecting the address with a socket
+        if( bind(sockfd, (const struct sockaddr*) &l_server_addr, sizeof(struct sockaddr_un)) == SOCKET_ERROR) {
+            // errno = EACCES  13  Permission denied
+            if ( errno == EACCES ) // EACCES=13
+                log_it( L_ERROR, "Server can't start(err=%d). Can't create file=%s [Permission denied]", errno,
+                        l_listen_unix_socket_path );
+            else
+                log_it( L_ERROR, "Server can't start(err=%d). May be problem with file=%s?", errno, l_listen_unix_socket_path );
+            closesocket( sockfd );
+            return -2;
+        }
+        chmod(l_listen_unix_socket_path,l_listen_unix_socket_permissions);
+
+      #else
+
+//    Sleep( 3000 );
+
+        if( pthread_create(&threadId, NULL, thread_pipe_func, (void*) (intptr_t) sockfd) != 0 ) {
+            closesocket( sockfd );
+            return -7;
+        }
+
+        return 0;
+      #endif
+
+    }
+    else if (l_listen_port ){
+
+        const char *l_listen_addr_str = dap_config_get_item_str(g_config, "conserver", "listen_address");
+
+        log_it( L_INFO, "Console interace on addr %s port %u ", l_listen_addr_str, l_listen_port );
+
+        server_addr.sin_family = AF_INET;
+#ifdef _WIN32
+        struct in_addr _in_addr = { { .S_addr = htonl(INADDR_LOOPBACK) } };
+        server_addr.sin_addr = _in_addr;
+        server_addr.sin_port = l_listen_port;
+#else
+        inet_pton( AF_INET, l_listen_addr_str, &server_addr.sin_addr );
+        server_addr.sin_port = htons( (uint16_t)l_listen_port );
+#endif
+        // create socket
+        if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET ) {
+#ifdef __WIN32
+            _set_errno(WSAGetLastError());
+#endif
+            log_it( L_ERROR, "Console Server: can't create socket, err %d", errno );
+            return -3;
+        }
+
+        // connecting the address with a socket
+        if ( bind(sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) == SOCKET_ERROR ) {
+#ifdef __WIN32
+            _set_errno(WSAGetLastError());
+#endif
+            log_it( L_ERROR, "Console Server: can't bind socket, err %d", errno );
+            closesocket( sockfd );
+            return -4;
+        }
+    }else {
+        log_it (L_INFO, "Not defined console interface");
+        return 0;
+    }
+
+    // turn on reception of connections
+    if( listen(sockfd, MAX_CONSOLE_CLIENTS) == SOCKET_ERROR )
+        return -5;
+
+    if( pthread_create(&l_thread_id, NULL, s_thread_main_func, (void*) (intptr_t) sockfd) != 0 ) {
+        closesocket( sockfd );
+        return -6;
+    }
+
+    // in order to thread not remain in state "dead" after completion
+    pthread_detach( l_thread_id );
+    server_sockfd = sockfd;
+
+    return 0;
+}
+
+/**
+ * @brief dap_cli_server_deinit
+ */
+void dap_cli_server_deinit()
+{
+    if(server_sockfd != INVALID_SOCKET)
+        closesocket(server_sockfd);
+#ifdef __WIN32
+    WSACleanup();
+#endif
+
+}
+
+/**
+ * @brief dap_cli_server_cmd_add
+ * @param a_name
+ * @param a_func
+ * @param a_doc
+ * @param a_doc_ex
+ */
+void dap_cli_server_cmd_add(const char * a_name, dap_cli_server_cmd_callback_t a_func, const char *a_doc, const char *a_doc_ex)
+{
+    s_cmd_add_ex(a_name, (dap_cli_server_cmd_callback_ex_t)(void *)a_func, NULL, a_doc, a_doc_ex);
+}
+
+/**
+ * @brief s_cmd_add_ex
+ * @param a_name
+ * @param a_func
+ * @param a_arg_func
+ * @param a_doc
+ * @param a_doc_ex
+ */
+static inline void s_cmd_add_ex(const char * a_name, dap_cli_server_cmd_callback_ex_t a_func, void *a_arg_func, const char *a_doc, const char *a_doc_ex)
+{
+    dap_cli_cmd_t *l_cmd_item = DAP_NEW_Z(dap_cli_cmd_t);
+    dap_snprintf(l_cmd_item->name,sizeof (l_cmd_item->name),"%s",a_name);
+    l_cmd_item->doc = strdup( a_doc);
+    l_cmd_item->doc_ex = strdup( a_doc_ex);
+    if (a_arg_func) {
+        l_cmd_item->func_ex = a_func;
+        l_cmd_item->arg_func = a_arg_func;
+    } else {
+        l_cmd_item->func = (dap_cli_server_cmd_callback_t )(void *)a_func;
+    }
+    HASH_ADD_STR(s_commands,name,l_cmd_item);
+    log_it(L_DEBUG,"Added command %s",l_cmd_item->name);
+}
+
+/**
+ * @brief int s_poll
+ * Wait for data
+ * timeout -  timeout in ms
+ * [Specifying a negative value in timeout means an infinite timeout.]
+ * [Specifying a timeout of zero causes poll() to return immediately, even if no file descriptors are ready.]
+ * return zero if the time limit expired
+ * return: >0 if data is present to read
+ * return: -1 if error
+ * @param socket
+ * @param timeout
+ * @return int
+ */
+static int s_poll( int sd, int timeout )
+{
+struct pollfd fds = {.fd = sd, .events = POLLIN};
+int res;
+
+    res = poll(&fds, 1, timeout);
+
+    return  (res == 1 && !(fds.revents & POLLIN)) ? -1 : res;
+}
+
+
+/**
+ * @brief is_valid_socket
+ * Check socket for validity
+ * @param sock
+ * @return true
+ * @return false
+ */
+static int is_valid_socket(SOCKET sd)
+{
+struct pollfd fds = {.fd = sd, .events = POLLIN};
+int res;
+
+    if ( 0 > (res = poll(&fds, 1, 0)) )
+        return false;
+
+    // event with an error code
+    if(res > 0)
+    {
+        // feature of disconnection under Windows
+        // under Windows, with socket closed fds.revents=POLLHUP, in Unix fds.events = POLLIN
+        if(fds.revents & (POLLERR | POLLHUP | POLLNVAL))
+            return false;
+
+        // feature of disconnection under Unix (QNX)
+        // under Windows, with socket closed res = 0, in Unix res = -1
+        char buf[2];
+        if ( 0 > (res = recv(sd, buf, 1, MSG_PEEK)) ) // MSG_PEEK  The data is treated as unread and the next recv() function shall still return this data.
+            return false;
+
+        // data in the buffer must be(count_desc>0), but read 0 bytes(res=0)
+        if(!res && (fds.revents & POLLIN))
+            return false;
+    }
+
+    return true;
+}
+
+
+/**
+ * @brief s_get_next_str
+ * Reading from the socket till arrival the specified string
+ *
+ * stop_str - string to which reading will continue
+ * del_stop_str - удалять ли строку для поиска в конце
+ * timeout - in ms
+ * return: string (if waited for final characters) or NULL, if the string requires deletion
+ * @param nSocket
+ * @param dwLen
+ * @param stop_str
+ * @param del_stop_str
+ * @param timeout
+ * @return char*
+ */
+char* s_get_next_str( SOCKET nSocket, int *dwLen, const char *stop_str, bool del_stop_str, int timeout )
+{
+    bool bSuccess = false;
+    long nRecv = 0; // count of bytes received
+    size_t stop_str_len = (stop_str) ? strlen(stop_str) : 0;
+    // if there is nothing to look for
+    if(!stop_str_len)
+        return NULL;
+    size_t lpszBuffer_len = 256;
+    char *lpszBuffer = DAP_NEW_Z_SIZE(char, lpszBuffer_len);
+    // received string will not be larger than MAX_REPLY_LEN
+
+    while(1) //nRecv < MAX_REPLY_LEN)
+    {
+        // read one byte
+        long ret = dap_net_recv(nSocket, (unsigned char *) (lpszBuffer + nRecv), 1, timeout);
+        //int ret = recv(nSocket,lpszBuffer+nRecv,1, 0);
+        if(ret <= 0)
+                {
+            break;
+        }
+        nRecv += ret;
+        //printf("**debug** socket=%d read  %d bytes '%0s'",nSocket, ret, (lpszBuffer + nRecv));
+        while((nRecv + 1) >= (long) lpszBuffer_len)
+        {
+            lpszBuffer_len *= 2;
+            lpszBuffer = (char*) realloc(lpszBuffer, lpszBuffer_len);
+        }
+        // search for the required string
+        if(nRecv >=  (long) stop_str_len) {
+            // found the required string
+            if(!strncasecmp(lpszBuffer + nRecv - stop_str_len, stop_str, stop_str_len)) {
+                bSuccess = true;
+                break;
+            }
+        }
+    };
+
+    // end reading
+
+    if(bSuccess) {
+        // delete the searched string
+        if(del_stop_str) {
+            lpszBuffer[nRecv -  (long) stop_str_len] = '\0';
+            if(dwLen)
+                *dwLen =(int) nRecv - (int) stop_str_len;
+        }
+        else {
+            lpszBuffer[nRecv] = '\0';
+            if(dwLen)
+                *dwLen = (int) nRecv;
+        }
+        char * l_buf_realloc = DAP_REALLOC(lpszBuffer,(size_t) *dwLen + 1);
+        if( l_buf_realloc)
+            lpszBuffer = l_buf_realloc;
+        return lpszBuffer;
+    }
+
+    // in case of an error or missing string
+
+    if(dwLen)
+        *dwLen = 0;
+
+    free(lpszBuffer);
+
+    return NULL;
+}
+
+/**
+ * threading function for processing a request from a client
+ */
+static void* s_thread_one_client_func(void *args)
+{
+SOCKET  newsockfd = (SOCKET) (intptr_t) args;
+int     str_len, marker = 0, timeout = 5000, argc = 0, is_data;
+dap_list_t *cmd_param_list = NULL;
+char    *str_header;
+
+    if(s_debug_cli)
+        log_it(L_DEBUG, "new connection sockfd=%"DAP_FORMAT_SOCKET, newsockfd);
+
+
+    while ( !(0 > (is_data = s_poll(newsockfd, timeout))) )                 // wait data from client
+    {
+        if ( !(is_data) )                                                   // timeout
+            continue;
+
+        if ( !is_valid_socket(newsockfd) )
+            break;
+
+        // receiving http header
+        if ( !(str_header = s_get_next_str(newsockfd, &str_len, "\r\n", true, timeout)) )
+            break;                                                          // bad format
+
+        if(str_header && !strlen(str_header) ) {
+            marker++;
+            if(marker == 1){
+                DAP_DELETE(str_header);
+                continue;
+            }
+        }
+
+        // filling parameters of command
+        if(marker == 1) {
+            cmd_param_list = dap_list_append(cmd_param_list, str_header);
+            //printf("g_list_append argc=%d command=%s ", argc, str_header);
+            argc++;
+        }
+        else
+            DAP_DEL_Z(str_header);
+
+        if(marker == 2 &&  cmd_param_list) {
+            dap_list_t *list = cmd_param_list;
+            // form command
+            argc = dap_list_length(list);
+            // command is found
+            if(argc >= 1) {
+              int l_verbose = 0;
+                char *cmd_name = list->data;
+                list = dap_list_next(list);
+                // execute command
+                char *str_cmd = dap_strdup_printf("%s", cmd_name);
+                dap_cli_cmd_t *l_cmd = dap_cli_server_cmd_find(cmd_name);
+                int res = -1;
+                char *str_reply = NULL;
+                if(l_cmd){
+                    while(list) {
+                        char *str_cmd_prev = str_cmd;
+                        str_cmd = dap_strdup_printf("%s;%s", str_cmd, list->data);
+                        list = dap_list_next(list);
+                        DAP_DELETE(str_cmd_prev);
+                    }
+                    if(l_cmd->overrides.log_cmd_call)
+                        l_cmd->overrides.log_cmd_call(str_cmd);
+                    else
+                        log_it(L_DEBUG, "execute command=%s", str_cmd);
+                    // exec command
+
+                    char **l_argv = dap_strsplit(str_cmd, ";", -1);
+                    // Call the command function
+                    if(l_cmd &&  l_argv && l_cmd->func) {
+                        if (l_cmd->arg_func) {
+                            res = l_cmd->func_ex(argc, l_argv, l_cmd->arg_func, &str_reply);
+                        } else {
+                            res = l_cmd->func(argc, l_argv, &str_reply);
+                        }
+                    } else if (l_cmd) {
+                        log_it(L_WARNING,"NULL arguments for input for command \"%s\"", str_cmd);
+                    }else {
+                        log_it(L_WARNING,"No function for command \"%s\" but it registred?!", str_cmd);
+                    }
+                    // find '-verbose' command
+                    l_verbose = dap_cli_server_cmd_find_option_val(l_argv, 1, argc, "-verbose", NULL);
+                    dap_strfreev(l_argv);
+                } else {
+                    str_reply = dap_strdup_printf("can't recognize command=%s", str_cmd);
+                    log_it(L_ERROR,"Reply string: \"%s\"", str_reply);
+                }
+                char *reply_body;
+                if(l_verbose)
+                  reply_body = dap_strdup_printf("%d\r\nret_code: %d\r\n%s\r\n", res, res, (str_reply) ? str_reply : "");
+                else
+                  reply_body = dap_strdup_printf("%d\r\n%s\r\n", res, (str_reply) ? str_reply : "");
+                // return the result of the command function
+                char *reply_str = dap_strdup_printf("HTTP/1.1 200 OK\r\n"
+                                                    "Content-Length: %d\r\n\r\n"
+                                                    "%s", strlen(reply_body), reply_body);
+                size_t l_reply_step = 32768;
+                size_t l_reply_len = strlen(reply_str);
+                size_t l_reply_rest = l_reply_len;
+
+                while(l_reply_rest) {
+                    size_t l_send_bytes = min(l_reply_step, l_reply_rest);
+                    int ret = send(newsockfd, reply_str + l_reply_len - l_reply_rest, l_send_bytes, 0);
+                    if(ret<=0)
+                        break;
+                    l_reply_rest-=l_send_bytes;
+                };
+
+                DAP_DELETE(str_reply);
+                DAP_DELETE(reply_str);
+                DAP_DELETE(reply_body);
+
+                DAP_DELETE(str_cmd);
+            }
+            dap_list_free_full(cmd_param_list, NULL);
+            break;
+        }
+    }
+    // close connection
+    int cs = closesocket(newsockfd);
+    if (s_debug_cli)
+        log_it(L_DEBUG, "close connection=%d sockfd=%"DAP_FORMAT_SOCKET, cs, newsockfd);
+
+    return NULL;
+}
+
+#ifdef _WIN32
+
+/**
+ * @brief p_get_next_str
+ *
+ * @param hPipe
+ * @param dwLen
+ * @param stop_str
+ * @param del_stop_str
+ * @param timeout
+ * @return char*
+ */
+char *p_get_next_str( HANDLE hPipe, int *dwLen, const char *stop_str, bool del_stop_str, int timeout )
+{
+    UNUSED(timeout);
+    bool bSuccess = false;
+    long nRecv = 0; // count of bytes received
+    size_t stop_str_len = (stop_str) ? strlen(stop_str) : 0;
+    // if there is nothing to look for
+
+    if(!stop_str_len)
+        return NULL;
+
+    size_t lpszBuffer_len = 256;
+    char *lpszBuffer = DAP_NEW_Z_SIZE(char, lpszBuffer_len);
+    // received string will not be larger than MAX_REPLY_LEN
+
+    while( 1 ) //nRecv < MAX_REPLY_LEN)
+    {
+      long ret = 0;
+        // read one byte
+//        long ret = s_recv( nSocket, (unsigned char *) (lpszBuffer + nRecv), 1, timeout);
+
+      bSuccess = ReadFile( hPipe, lpszBuffer + nRecv,
+         lpszBuffer_len - nRecv, (LPDWORD)&ret, NULL );
+
+        //int ret = recv(nSocket,lpszBuffer+nRecv,1, 0);
+        if ( ret <= 0 || !bSuccess )
+            break;
+
+        nRecv += ret;
+        //printf("**debug** socket=%d read  %d bytes '%0s'",nSocket, ret, (lpszBuffer + nRecv));
+
+        while((nRecv + 1) >= (long) lpszBuffer_len)
+        {
+            lpszBuffer_len *= 2;
+            lpszBuffer = (char*) realloc(lpszBuffer, lpszBuffer_len);
+        }
+
+        // search for the required string
+        if(nRecv >=  (long) stop_str_len) {
+            // found the required string
+            if(!strncasecmp(lpszBuffer + nRecv - stop_str_len, stop_str, stop_str_len)) {
+                bSuccess = true;
+                break;
+            }
+        }
+    };
+
+    // end reading
+
+    if(bSuccess) {
+        // delete the searched string
+        if(del_stop_str) {
+            lpszBuffer[nRecv -  (long) stop_str_len] = '\0';
+            if(dwLen)
+                *dwLen =(int) nRecv - (int) stop_str_len;
+        }
+        else {
+            lpszBuffer[nRecv] = '\0';
+            if(dwLen)
+                *dwLen = (int) nRecv;
+        }
+        lpszBuffer = DAP_REALLOC(lpszBuffer,(size_t) *dwLen + 1);
+        return lpszBuffer;
+    }
+
+    // in case of an error or missing string
+
+    if(dwLen)
+        *dwLen = 0;
+
+    free(lpszBuffer);
+
+    return NULL;
+}
+
+/**
+ * @brief thread_pipe_client_func
+ * threading function for processing a request from a client
+ * @param args
+ * @return void*
+ */
+static void *thread_pipe_client_func( void *args )
+{
+    HANDLE hPipe = (HANDLE)args;
+
+//    SOCKET newsockfd = (SOCKET) (intptr_t) args;
+    if(s_debug_cli)
+        log_it(L_INFO, "new connection pipe = %p", hPipe);
+
+    int str_len, marker = 0;
+    int timeout = 5000; // 5 sec
+    int argc = 0;
+
+    dap_list_t *cmd_param_list = NULL;
+
+    while( 1 )
+    {
+        // wait data from client
+//        int is_data = s_poll( newsockfd, timeout );
+        // timeout
+//        if(!is_data)
+//            continue;
+        // error (may be socket closed)
+//        if(is_data < 0)
+//            break;
+
+//        int is_valid = is_valid_socket(newsockfd);
+//        if(!is_valid)
+//        {
+//            break;
+//        }
+
+        // receiving http header
+        char *str_header = p_get_next_str( hPipe, &str_len, "\r\n", true, timeout );
+
+        // bad format
+        if(!str_header)
+            break;
+
+        if ( str_header && strlen(str_header) == 0) {
+            marker++;
+            if(marker == 1)
+                continue;
+        }
+
+        // filling parameters of command
+        if ( marker == 1 ) {
+            cmd_param_list = dap_list_append( cmd_param_list, str_header );
+            //printf("g_list_append argc=%d command=%s ", argc, str_header);
+            argc ++;
+        }
+        else
+            free( str_header );
+
+        if ( marker == 2 ) {
+
+            dap_list_t *list = cmd_param_list;
+            // form command
+
+            unsigned int argc = dap_list_length( list );
+            // command is found
+
+            if ( argc >= 1) {
+
+                int l_verbose = 0;
+                char *cmd_name = list->data;
+                list = dap_list_next( list );
+
+                // execute command
+                char *str_cmd = dap_strdup_printf( "%s", cmd_name );
+                dap_cli_cmd_t *l_cmd = dap_cli_server_cmd_find( cmd_name );
+                int res = -1;
+                char *str_reply = NULL;
+
+                if ( l_cmd ) {
+
+                    while( list ) {
+                        str_cmd = dap_strdup_printf( "%s;%s", str_cmd, list->data );
+                        list = dap_list_next(list);
+                    }
+
+                    log_it(L_INFO, "execute command = %s", str_cmd );
+                    // exec command
+
+                    char **l_argv = dap_strsplit( str_cmd, ";", -1 );
+                    // Call the command function
+
+                    if ( l_cmd &&  l_argv && l_cmd->func ) {
+                        if (l_cmd->arg_func) {
+                            res = l_cmd->func_ex(argc, l_argv, l_cmd->arg_func, &str_reply);
+                        } else {
+                            res = l_cmd->func(argc, l_argv, &str_reply);
+                        }
+                    }
+
+                    else if ( l_cmd ) {
+                        log_it(L_WARNING,"NULL arguments for input for command \"%s\"", str_cmd );
+                    }else {
+                        log_it(L_WARNING,"No function for command \"%s\" but it registred?!", str_cmd );
+                    }
+
+                    // find '-verbose' command
+                    l_verbose = dap_cli_server_cmd_find_option_val( l_argv, 1, argc, "-verbose", NULL );
+                    dap_strfreev( l_argv );
+
+                } else {
+                    str_reply = dap_strdup_printf("can't recognize command = %s", str_cmd );
+                    log_it( L_ERROR, str_reply );
+                }
+
+                char *reply_body;
+
+                if(l_verbose)
+                  reply_body = dap_strdup_printf("%d\r\nret_code: %d\r\n%s\r\n", res, res, (str_reply) ? str_reply : "");
+                else
+                  reply_body = dap_strdup_printf("%d\r\n%s\r\n", res, (str_reply) ? str_reply : "");
+
+                // return the result of the command function
+                char *reply_str = dap_strdup_printf( "HTTP/1.1 200 OK\r\n"
+                                                    "Content-Length: %d\r\n\r\n"
+                                                    "%s",
+                        strlen(reply_body), reply_body );
+
+                int ret;// = send( newsockfd, reply_str, strlen(reply_str) ,0 );
+
+                WriteFile( hPipe, reply_str, strlen(reply_str), (LPDWORD)&ret, NULL );
+
+                DAP_DELETE(str_reply);
+                DAP_DELETE(reply_str);
+                DAP_DELETE(reply_body);
+
+                DAP_DELETE(str_cmd);
+            }
+            dap_list_free_full(cmd_param_list, free);
+            break;
+        }
+    }
+
+    // close connection
+//    int cs = closesocket(newsockfd);
+
+    log_it( L_INFO, "close connection pipe = %p", hPipe );
+
+    FlushFileBuffers( hPipe );
+    DisconnectNamedPipe( hPipe );
+    CloseHandle( hPipe );
+
+    return NULL;
+}
+
+
+/**
+ * @brief thread_pipe_func
+ * main threading server function pipe win32
+ * @param args
+ * @return void*
+ */
+static void* thread_pipe_func( void *args )
+{
+   UNUSED(args);
+   BOOL   fConnected = FALSE;
+   pthread_t threadId;
+   HANDLE hPipe = INVALID_HANDLE_VALUE;
+   static const char *cPipeName = "\\\\.\\pipe\\node_cli.pipe";
+
+   for (;;)
+   {
+///      printf( "\nPipe Server: Main thread awaiting client connection on %s\n", lpszPipename );
+
+      hPipe = CreateNamedPipe(
+          cPipeName,                // pipe name
+          PIPE_ACCESS_DUPLEX,       // read/write access
+          PIPE_TYPE_MESSAGE |       // message type pipe
+          PIPE_READMODE_MESSAGE |   // message-read mode
+          PIPE_WAIT,                // blocking mode
+          PIPE_UNLIMITED_INSTANCES, // max. instances
+          4096,                     // output buffer size
+          4096,                     // input buffer size
+          0,                        // client time-out
+          NULL );                   // default security attribute
+
+      if ( hPipe == INVALID_HANDLE_VALUE ) {
+          log_it( L_ERROR, "CreateNamedPipe failed, GLE = %lu.\n", GetLastError() );
+          return NULL;
+      }
+
+      fConnected = ConnectNamedPipe( hPipe, NULL ) ? TRUE : ( GetLastError() == ERROR_PIPE_CONNECTED );
+
+      if ( fConnected )
+      {
+        log_it( L_INFO, "Client %p connected, creating a processing thread.\n", hPipe );
+
+        pthread_create( &threadId, NULL, thread_pipe_client_func, hPipe );
+        pthread_detach( threadId );
+      }
+      else
+         CloseHandle( hPipe );
+    }
+
+    return NULL;
+}
+#endif
+
+
+/**
+ * @brief thread_main_func
+ * main threading server function
+ * @param args
+ * @return void*
+ */
+static void* s_thread_main_func(void *args)
+{
+    SOCKET sockfd = (SOCKET) (intptr_t) args;
+    SOCKET newsockfd;
+
+    log_it( L_INFO, "Server start socket = %s", dap_config_get_item_str( g_config, "conserver", "listen_unix_socket_path") );
+    // wait of clients
+    while(1)
+    {
+        pthread_t threadId;
+        struct sockaddr_in peer;
+        socklen_t size = sizeof(peer);
+        // received a new connection request
+        if((newsockfd = accept(sockfd, (struct sockaddr*) &peer, &size)) == (SOCKET) -1) {
+            log_it(L_ERROR, "new connection break newsockfd=%"DAP_FORMAT_SOCKET, newsockfd);
+            break;
+        }
+        // create child thread for a client connection
+        pthread_create(&threadId, NULL, s_thread_one_client_func, (void*) (intptr_t) newsockfd);
+        // in order to thread not remain in state "dead" after completion
+        pthread_detach(threadId);
+    };
+    // close connection
+    int cs = closesocket(sockfd);
+    log_it(L_INFO, "Exit server thread=%d socket=%"DAP_FORMAT_SOCKET, cs, sockfd);
+    return NULL;
+}
+
+
+/**
+ * @brief dap_chain_node_cli_set_reply_text
+ * Write text to reply string
+ * @param str_reply
+ * @param str
+ * @param ...
+ */
+void dap_cli_server_cmd_set_reply_text(char **str_reply, const char *str, ...)
+{
+    if(str_reply) {
+        if(*str_reply) {
+            assert( *str_reply );
+            DAP_DELETE(*str_reply);
+            *str_reply = NULL;
+        }
+        va_list args;
+        va_start(args, str);
+        *str_reply = dap_strdup_vprintf(str, args); //*str_reply = dap_strdup(str);
+        va_end(args);
+    }
+}
+
+/**
+ * @brief dap_cli_server_cmd_check_option
+ * @param argv
+ * @param arg_start
+ * @param arg_end
+ * @param opt_name
+ * @return
+ */
+int dap_cli_server_cmd_check_option( char** argv, int arg_start, int arg_end, const char *opt_name)
+{
+    int arg_index = arg_start;
+    const char *arg_string;
+
+    while(arg_index < arg_end)
+    {
+        char * l_argv_cur = argv[arg_index];
+        arg_string = l_argv_cur;
+        // find opt_name
+        if(arg_string && opt_name && arg_string[0] && opt_name[0] && !strcmp(arg_string, opt_name)) {
+                return arg_index;
+        }
+        arg_index++;
+    }
+    return -1;
+}
+
+
+/**
+ * @brief dap_cli_server_cmd_find_option_val
+ * return index of string in argv, or 0 if not found
+ * @param argv
+ * @param arg_start
+ * @param arg_end
+ * @param opt_name
+ * @param opt_value
+ * @return int
+ */
+int dap_cli_server_cmd_find_option_val( char** argv, int arg_start, int arg_end, const char *opt_name, const char **opt_value)
+{
+    assert(argv);
+    int arg_index = arg_start;
+    const char *arg_string;
+    int l_ret_pos = 0;
+
+    while(arg_index < arg_end)
+    {
+        char * l_argv_cur = argv[arg_index];
+        arg_string = l_argv_cur;
+        // find opt_name
+        if(arg_string && opt_name && arg_string[0] && opt_name[0] && !strcmp(arg_string, opt_name)) {
+            // find opt_value
+            if(opt_value) {
+                arg_string = argv[++arg_index];
+                if(arg_string) {
+                    *opt_value = arg_string;
+                    return arg_index;
+                }
+                // for case if opt_name exist without value
+                else
+                    l_ret_pos = arg_index;
+            }
+            else
+                // need only opt_name
+                return arg_index;
+        }
+        arg_index++;
+    }
+    return l_ret_pos;
+}
+
+
+/**
+ * @brief dap_cli_server_cmd_apply_overrides
+ *
+ * @param a_name
+ * @param a_overrides
+ */
+void dap_cli_server_cmd_apply_overrides(const char * a_name, const dap_cli_server_cmd_override_t a_overrides)
+{
+    dap_cli_cmd_t *l_cmd_item = dap_cli_server_cmd_find(a_name);
+    if(l_cmd_item)
+        l_cmd_item->overrides = a_overrides;
+}
+
+/**
+ * @brief dap_cli_server_cmd_get_first
+ * @return
+ */
+dap_cli_cmd_t* dap_cli_server_cmd_get_first()
+{
+    return s_commands;
+}
+
+/**
+ * @brief dap_cli_server_cmd_find
+ * @param a_name
+ * @return
+ */
+dap_cli_cmd_t* dap_cli_server_cmd_find(const char *a_name)
+{
+    dap_cli_cmd_t *l_cmd_item = NULL;
+    HASH_FIND_STR(s_commands,a_name,l_cmd_item);
+    return l_cmd_item;
+}
diff --git a/net/server/cli_server/include/dap_cli_server.h b/net/server/cli_server/include/dap_cli_server.h
new file mode 100644
index 000000000..856888225
--- /dev/null
+++ b/net/server/cli_server/include/dap_cli_server.h
@@ -0,0 +1,67 @@
+/*
+ * Authors:
+ * Dmitriy A. Gerasimov <gerasimov.dmitriy@demlabs.net>
+ * Alexander Lysikov <alexander.lysikov@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * Cellframe  https://cellframe.net
+ * Copyright  (c) 2019-2022
+ * All rights reserved.
+
+ This file is part of Cellframe SDK
+
+ Cellframe 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.
+
+ Cellframe 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 Cellframe SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "dap_events_socket.h"
+#include "dap_common.h"
+#include "dap_config.h"
+#include "uthash.h"
+
+typedef int (*dap_cli_server_cmd_callback_ex_t)(int argc, char ** argv, void *arg_func, char **str_reply);
+typedef int (*dap_cli_server_cmd_callback_t)(int argc, char ** argv, char **str_reply);
+
+typedef void (*dap_cli_server_override_log_cmd_callback_t)(const char*);
+
+typedef struct dap_cli_server_cmd_override{
+    /* use it if you want to prevent logging of some sensetive data */
+    dap_cli_server_override_log_cmd_callback_t log_cmd_call;
+} dap_cli_server_cmd_override_t;
+
+typedef struct dap_cli_cmd{
+    char name[32]; /* User printable name of the function. */
+    union {
+        dap_cli_server_cmd_callback_t func; /* Function to call to do the job. */
+        dap_cli_server_cmd_callback_ex_t func_ex; /* Function with additional arg to call to do the job. */
+    };
+    void *arg_func; /* additional argument of function*/
+    char *doc; /* Documentation for this function.  */
+    char *doc_ex; /* Full documentation for this function.  */
+    dap_cli_server_cmd_override_t overrides; /* Used to change default behaviour */
+    UT_hash_handle hh;
+} dap_cli_cmd_t;
+
+
+int dap_cli_server_init(bool a_debug_more,const char * a_socket_path_or_address, uint16_t a_port, const char * a_permissions) ;
+void dap_cli_server_deinit();
+
+void dap_cli_server_cmd_add(const char * a_name, dap_cli_server_cmd_callback_t a_func, const char *a_doc, const char *a_doc_ex);
+void dap_cli_server_cmd_set_reply_text(char **str_reply, const char *str, ...);
+int dap_cli_server_cmd_find_option_val( char** argv, int arg_start, int arg_end, const char *opt_name, const char **opt_value);
+int dap_cli_server_cmd_check_option( char** argv, int arg_start, int arg_end, const char *opt_name);
+void dap_cli_server_cmd_apply_overrides(const char * a_name, const dap_cli_server_cmd_override_t a_overrides);
+
+dap_cli_cmd_t* dap_cli_server_cmd_get_first();
+dap_cli_cmd_t* dap_cli_server_cmd_find(const char *a_name);
diff --git a/net/stream/stream/dap_stream.c b/net/stream/stream/dap_stream.c
index b57af3ccd..a27f3928c 100644
--- a/net/stream/stream/dap_stream.c
+++ b/net/stream/stream/dap_stream.c
@@ -809,7 +809,6 @@ static void s_stream_proc_pkt_in(dap_stream_t * a_stream, dap_stream_pkt_t *a_pk
         a_stream->buf_fragments_size_total = 0;
         a_stream->buf_fragments_size_filled = 0;
     }
-    return true;
 }
 
 /**
diff --git a/plugin/CMakeLists.txt b/plugin/CMakeLists.txt
new file mode 100644
index 000000000..6ef731ee9
--- /dev/null
+++ b/plugin/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.0)
+project(dap_plugin C)
+
+set(CMAKE_VERBOSE_MAKEFILE ON)
+set(CMAKE_COLOR_MAKEFILE   ON)
+set(CMAKE_C_STANDARD 11)
+
+file(GLOB DAP_PLUGIN_SRCS src/*.c)
+file(GLOB DAP_PLUGIN_HEADERS include/*.h)
+
+add_library(${PROJECT_NAME} STATIC ${DAP_PLUGIN_SRCS} ${DAP_PLUGIN_HEADERS})
+
+target_link_libraries(${PROJECT_NAME})
+
+target_link_libraries(${PROJECT_NAME} dap_core dap_cli_server)
+
+target_include_directories(${PROJECT_NAME} PUBLIC include/ )
+
diff --git a/plugin/include/dap_plugin.h b/plugin/include/dap_plugin.h
new file mode 100644
index 000000000..e0ac75aa1
--- /dev/null
+++ b/plugin/include/dap_plugin.h
@@ -0,0 +1,56 @@
+/*
+* Authors:
+* Alexey V. Stratulat <alexey.stratulat@demlabs.net>
+* Dmitriy Gerasimov <dmitriy.gerasimov@demlabs.net
+* DeM Labs Inc.   https://demlabs.net
+* Copyright  (c) 2017-2022
+* 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
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include "dap_config.h"
+#include "dap_plugin_manifest.h"
+
+typedef int (*dap_plugin_type_callback_load_t)(dap_plugin_manifest_t * a_manifest, void ** a_pvt_data, char ** a_error_str );
+typedef int (*dap_plugin_type_callback_unload_t)(dap_plugin_manifest_t * a_manifest, void * a_pvt_data, char ** a_error_str );
+
+typedef struct dap_plugin_type_callbacks
+{
+    dap_plugin_type_callback_load_t load;
+    dap_plugin_type_callback_unload_t unload;
+} dap_plugin_type_callbacks_t;
+typedef enum dap_plugin_status{ STATUS_RUNNING, STATUS_STOPPED, STATUS_NONE } dap_plugin_status_t;
+
+int dap_plugin_init(const char * a_root_path);
+void dap_plugin_deinit();
+
+int dap_plugin_type_create(const char* a_name, dap_plugin_type_callbacks_t *a_callbacks);
+void dap_plugin_start_all();
+void dap_plugin_stop_all();
+dap_plugin_status_t dap_plugin_status(const char * a_name);
+int dap_plugin_stop(const char * a_name);
+int dap_plugin_start(const char * a_name);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/plugin/include/dap_plugin_binary.h b/plugin/include/dap_plugin_binary.h
new file mode 100644
index 000000000..48b634a6e
--- /dev/null
+++ b/plugin/include/dap_plugin_binary.h
@@ -0,0 +1,27 @@
+/*
+ * Authors:
+ * Dmitriy A. Gerasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * Cellframe  https://cellframe.net
+ * Copyright  (c) 2022
+ * All rights reserved.
+
+ This file is part of Cellframe SDK
+
+ Cellframe 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.
+
+ Cellframe 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 Cellframe SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+
+int dap_plugin_binary_init();
+void dap_plugin_binary_deinit();
diff --git a/plugin/include/dap_plugin_command.h b/plugin/include/dap_plugin_command.h
new file mode 100644
index 000000000..861c65ca5
--- /dev/null
+++ b/plugin/include/dap_plugin_command.h
@@ -0,0 +1,37 @@
+/*
+* Authors:
+* Alexey V. Stratulat <alexey.stratulat@demlabs.net>
+* DeM Labs Inc.   https://demlabs.net
+* DeM Labs Open source community https://gitlab.demlabs.net/cellframe/libdap-plugins-python
+* Copyright  (c) 2017-2020
+* 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
+
+#define _DAP_CHAIN_PLUGINS_COMMAND_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void dap_plugin_command_init(void);
+void dap_plugin_command_deinit(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/plugin/include/dap_plugin_manifest.h b/plugin/include/dap_plugin_manifest.h
new file mode 100644
index 000000000..825e86eb3
--- /dev/null
+++ b/plugin/include/dap_plugin_manifest.h
@@ -0,0 +1,86 @@
+/*
+* Authors:
+* Alexey V. Stratulat <alexey.stratulat@demlabs.net>
+* DeM Labs Inc.   https://demlabs.net
+* DeM Labs Open source community https://gitlab.demlabs.net/cellframe/libdap-plugins-python
+* Copyright  (c) 2017-2020
+* 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
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <stdbool.h>
+#include "uthash.h"
+#include "dap_config.h"
+
+typedef struct dap_plugin_manifest{
+    char name[64];
+    char *version;
+    char *author;
+    char *description;
+
+
+    char * type;// Plugin type
+    char * path;// Path to the directory
+    dap_config_t * config; // Config file
+
+    // Dependencies
+    struct dap_plugin_manifest_dependence *dependencies;  // Solved dependencies with links on same manifests
+    char **dependencies_names; // String list of dependencies
+    size_t dependencies_count; // Number of dependencies;
+
+    // Additional params
+    size_t params_count;
+    char ** params;
+
+    // Builtin plugin
+    bool is_builtin; // Doesn't allow to unload if true
+
+    // uthash handle
+    UT_hash_handle hh;
+}dap_plugin_manifest_t;
+
+typedef struct dap_plugin_manifest_dependence{
+    char name[64];
+    dap_plugin_manifest_t * manifest;
+    UT_hash_handle hh;
+}dap_plugin_manifest_dependence_t;
+
+int dap_plugin_manifest_init();
+void dap_plugin_manifest_deinit();
+
+dap_plugin_manifest_t* dap_plugin_manifest_all(void);
+dap_plugin_manifest_t *dap_plugin_manifest_find(const char *a_name);
+
+char* dap_plugin_manifests_get_list_dependencies(dap_plugin_manifest_t *a_element);
+
+dap_plugin_manifest_t* dap_plugin_manifest_add_from_file(const char *a_file_path);
+dap_plugin_manifest_t* dap_plugin_manifest_add_builtin(const char *a_name, const char * a_type,
+                                                            const char * a_author, const char * a_version,
+                                                            const char * a_description, char ** a_dependencies_names,
+                                                            size_t a_dependencies_count, char ** a_params, size_t a_params_count);
+
+bool dap_plugins_manifest_remove(const char *a_name);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/plugin/src/dap_plugin.c b/plugin/src/dap_plugin.c
new file mode 100644
index 000000000..2199a7ea1
--- /dev/null
+++ b/plugin/src/dap_plugin.c
@@ -0,0 +1,292 @@
+/*
+* Authors:
+* Alexey V. Stratulat <alexey.stratulat@demlabs.net>
+* Dmitriy Gerasimov <dmitriy.gerasimov@demlabs.net
+* DeM Labs Inc.   https://demlabs.net
+* Copyright  (c) 2017-2022
+* 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 "uthash.h"
+#include "dap_config.h"
+#include "dap_common.h"
+#include "dap_file_utils.h"
+#include "dap_plugin_manifest.h"
+#include "dap_plugin_command.h"
+#include "dap_plugin_binary.h"
+
+#include "dap_plugin.h"
+#include "dap_strfuncs.h"
+
+#define LOG_TAG "dap_plugin"
+
+static char *s_plugins_root_path = NULL;
+
+struct plugin_type{
+    char *name;
+    dap_plugin_type_callbacks_t callbacks;
+    UT_hash_handle hh;
+} * s_types;
+
+
+struct plugin_module{
+    char *name;
+    struct plugin_type *type;
+    dap_plugin_manifest_t *manifest;
+
+    void * pvt_data; // Here are placed type-related things
+    UT_hash_handle hh;
+};
+
+struct plugin_type *s_types = NULL; // List of all registred plugin types
+struct plugin_module *s_modules = NULL; // List of all loaded modules
+static int s_stop(dap_plugin_manifest_t * a_manifest);
+static int s_start(dap_plugin_manifest_t * a_manifest);
+
+static void s_solve_dependencies();
+
+
+/**
+ * @brief dap_plugin_init
+ * @param a_root_path
+ * @return
+ */
+int dap_plugin_init(const char * a_root_path)
+{
+    s_plugins_root_path = dap_strdup(a_root_path);
+
+    log_it(L_INFO, "Start plugins initialization on root path %s", s_plugins_root_path);
+    if (!dap_dir_test(s_plugins_root_path)){
+        log_it(L_ERROR, "Can't find \"%s\" directory", s_plugins_root_path);
+        return -1;
+    }
+
+    //Get list files
+    dap_list_name_directories_t *l_list_plugins_name = dap_get_subs(s_plugins_root_path);
+    dap_list_name_directories_t *l_element;
+    // Register manifests
+    log_it(L_DEBUG, "Start registration of manifests");
+    dap_plugin_manifest_init();
+    dap_plugin_command_init();
+
+    char *l_name_file = NULL;
+    LL_FOREACH(l_list_plugins_name, l_element){
+        log_it(L_NOTICE, "Registration of \"%s\" manifest", l_element->name_directory);
+        l_name_file = dap_strjoin("",s_plugins_root_path, "/", l_element->name_directory, "/manifest.json", NULL);
+        if (!dap_plugin_manifest_add_from_file(l_name_file)){
+            log_it(L_ERROR, "Registration of \"%s\" manifest is failed", l_element->name_directory);
+        }
+        DAP_FREE(l_name_file);
+    }
+    s_solve_dependencies();
+    return 0;
+}
+
+
+void dap_plugin_deinit(){
+    log_it(L_NOTICE, "Deinitialize plugins");
+    dap_plugin_stop_all();
+    dap_plugin_manifest_deinit();
+    dap_plugin_command_deinit();
+}
+
+
+
+/**
+ * @brief s_solve_dependencies
+ */
+static void s_solve_dependencies()
+{
+    // TODO solving dependencies
+}
+
+
+/**
+ * @brief Create new plugin type. Same name will be new plugin itself to make dependencies from plugin type as from plugin
+ * @param a_name Plugin type name
+ * @param a_callbacks Set of callbacks
+ * @return Returns 0 if success otherwise if not
+ */
+int dap_plugin_type_create(const char* a_name, dap_plugin_type_callbacks_t* a_callbacks)
+{
+    if(!a_name){
+        log_it(L_CRITICAL, "Can't create plugin type without name!");
+        return -1;
+    }
+    if(!a_callbacks){
+        log_it(L_CRITICAL, "Can't create plugin type without callbacks!");
+        return -2;
+    }
+    struct plugin_type * l_new = DAP_NEW_Z(struct plugin_type);
+    if(!l_new){
+        log_it(L_CRITICAL, "OOM on new type create");
+        return -3;
+    }
+    l_new->name = dap_strdup(a_name);
+    memcpy(&l_new->callbacks,a_callbacks,sizeof(l_new->callbacks));
+    return 0;
+}
+
+/**
+ * @brief dap_plugin_start_all
+ */
+void dap_plugin_start_all()
+{
+    dap_plugin_manifest_t * l_manifest, *l_tmp;
+    HASH_ITER(hh,dap_plugin_manifest_all(),l_manifest,l_tmp ){
+        s_start(l_manifest);
+    }
+}
+
+/**
+ * @brief dap_plugin_stop_all
+ */
+void dap_plugin_stop_all()
+{
+    dap_plugin_manifest_t * l_manifest, *l_tmp;
+    HASH_ITER(hh,dap_plugin_manifest_all(),l_manifest,l_tmp ){
+        s_stop(l_manifest);
+    }
+}
+
+/**
+ * @brief dap_plugin_stop
+ * @param a_name
+ * @return
+ */
+int dap_plugin_stop(const char * a_name)
+{
+    dap_plugin_manifest_t * l_manifest = dap_plugin_manifest_find(a_name);
+    if(l_manifest)
+        return s_stop(l_manifest);
+    else
+        return -4; // Not found
+
+}
+
+/**
+ * @brief Stop services by manifest
+ * @param a_manifest
+ * @return
+ */
+static int s_stop(dap_plugin_manifest_t * a_manifest)
+{
+    if(!a_manifest)
+        return -4;
+    struct plugin_module * l_module = NULL;
+    HASH_FIND_STR(s_modules, a_manifest->name , l_module);
+    if(! l_module){
+        log_it(L_ERROR, "Plugin \"%s\" is not loaded", a_manifest->type);
+        return -5;
+    }
+    // unload plugin
+    char * l_err_str = NULL;
+    int l_ret = l_module->type->callbacks.unload(a_manifest,l_module->pvt_data, &l_err_str);
+    if(l_ret){ // Error while unloading
+        log_it(L_ERROR, "Can't unload plugin \"%s\" because of error \"%s\" (code %d)",a_manifest->name,
+               l_err_str?l_err_str:"<UNKNOWN>", l_ret);
+        DAP_DELETE(l_err_str);
+    }else{
+        HASH_DELETE(hh, s_modules,l_module);
+        DAP_DELETE(l_module);
+    }
+    return l_ret;
+}
+
+/**
+ * @brief dap_plugin_start
+ * @param a_name
+ * @return
+ */
+int dap_plugin_start(const char * a_name)
+{
+    dap_plugin_manifest_t * l_manifest = dap_plugin_manifest_find(a_name);
+    if(l_manifest)
+        return s_start(l_manifest);
+    else
+        return -4; // Not found
+}
+
+/**
+ * @brief l_stop
+ * @param a_manifest
+ * @return
+ */
+static int s_start(dap_plugin_manifest_t * a_manifest)
+{
+    struct plugin_type * l_type = NULL;
+    HASH_FIND_STR(s_types, a_manifest->type, l_type);
+    if(! l_type){
+        log_it(L_ERROR, "Plugin type \"%s\" is not recognized", a_manifest->type);
+        return -1;
+    }
+    if (a_manifest->dependencies != NULL){
+        log_it(L_NOTICE, "Check for plugin %s dependencies", a_manifest->name);
+        // Check for dependencies, are they loaded
+        bool l_is_unsolved = false;
+        for(size_t i=0; i< a_manifest->dependencies_count; i++){
+            dap_plugin_manifest_dependence_t * l_dep = NULL;
+            HASH_FIND_STR(a_manifest->dependencies, a_manifest->dependencies_names[i], l_dep);
+            if (!l_dep){ // meet unsolved dependence
+                log_it(L_ERROR, "Unsolved dependence \"%s\"", a_manifest->dependencies_names[i]);
+                l_is_unsolved = true;
+            }
+        }
+        if(l_is_unsolved)
+            return -2;
+    }
+
+    // load plugin
+    char * l_err_str = NULL;
+    void * l_pvt_data = NULL;
+    int l_ret = l_type->callbacks.load(a_manifest,&l_pvt_data, &l_err_str);
+    if(l_ret){ // Error while loading
+        log_it(L_ERROR, "Can't load plugin \"%s\" because of error \"%s\" (code %d)",a_manifest->name,
+               l_err_str?l_err_str:"<UNKNOWN>", l_ret);
+        DAP_DELETE(l_err_str);
+    }else{ // Successfully
+        struct plugin_module * l_module = DAP_NEW_Z(struct plugin_module);
+        l_module->pvt_data = l_pvt_data;
+        strncpy(l_module->name, a_manifest->name, sizeof(l_module->name)-1);
+        l_module->type = l_type;
+        l_module->manifest = a_manifest;
+        HASH_ADD_STR(s_modules,name,l_module);
+    }
+    return l_ret;
+}
+
+/**
+ * @brief dap_plugin_status
+ * @param a_name
+ * @return
+ */
+dap_plugin_status_t dap_plugin_status(const char * a_name)
+{
+    struct plugin_module * l_module = NULL;
+    HASH_FIND_STR(s_modules,a_name,l_module);
+    if(l_module){
+        return STATUS_RUNNING;
+    }
+    dap_plugin_manifest_t * l_manifest = dap_plugin_manifest_find(a_name);
+    if(l_manifest)
+        return STATUS_STOPPED;
+    return STATUS_NONE;
+}
+
+
+
diff --git a/plugin/src/dap_plugin_binary.c b/plugin/src/dap_plugin_binary.c
new file mode 100644
index 000000000..6bf031d7f
--- /dev/null
+++ b/plugin/src/dap_plugin_binary.c
@@ -0,0 +1,128 @@
+/*
+ * Authors:
+ * Dmitriy A. Gerasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * Cellframe  https://cellframe.net
+ * Copyright  (c) 2022
+ * All rights reserved.
+
+ This file is part of Cellframe SDK
+
+ Cellframe 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.
+
+ Cellframe 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 Cellframe SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "dap_strfuncs.h"
+#ifdef DAP_OS_LINUX
+#include <dlfcn.h>
+#endif
+
+#include <assert.h>
+#include "dap_plugin.h"
+#include "dap_plugin_binary.h"
+#include "dap_plugin_manifest.h"
+
+#define LOG_TAG "dap_plugin_binary"
+
+typedef int (*plugin_init_callback_t)(dap_config_t * a_plugin_config, char ** a_error_str);
+typedef void (*plugin_deinit_callback_t)(void);
+
+static dap_plugin_manifest_t * s_manifest = NULL; // Own manifest
+
+static int s_type_callback_load(dap_plugin_manifest_t * a_manifest, void ** a_pvt_data, char ** a_error_str );
+static int s_type_callback_unload(dap_plugin_manifest_t * a_manifest, void * a_pvt_data, char ** a_error_str );
+
+struct binary_pvt_data{
+    void *handle;
+    plugin_init_callback_t callback_init;
+    plugin_deinit_callback_t callback_deinit;
+};
+
+/**
+ * @brief dap_plugin_binary_init
+ * @return
+ */
+int dap_plugin_binary_init()
+{
+    dap_plugin_type_callbacks_t l_callbacks={};
+    l_callbacks.load = s_type_callback_load;
+    l_callbacks.unload = s_type_callback_unload;
+    dap_plugin_type_create("bin",&l_callbacks);
+    s_manifest = dap_plugin_manifest_add_builtin("binary", "binary", "Demlabs Inc", "1.0","Binary shared library loader",NULL,0,NULL,0);
+    return 0;
+}
+
+/**
+ * @brief dap_plugin_binary_deinit
+ */
+void dap_plugin_binary_deinit()
+{
+
+}
+
+/**
+ * @brief s_type_callback_load
+ * @param a_manifest
+ * @param a_pvt_data
+ * @param a_error_str
+ * @return
+ */
+static int s_type_callback_load(dap_plugin_manifest_t * a_manifest, void ** a_pvt_data, char ** a_error_str )
+{
+    assert(a_pvt_data);
+    if(a_manifest == s_manifest) // Its our own manifest, do nothing we're already loaded
+        return 0;
+    struct binary_pvt_data * l_pvt_data= DAP_NEW_Z(struct binary_pvt_data);
+    *a_pvt_data = l_pvt_data;
+    #if defined (DAP_OS_LINUX) && !defined (__ANDROID__)
+    char * l_path = dap_strdup_printf("%s/%s.linux.common.%s.so",a_manifest->path,a_manifest->name,dap_get_arch());
+    l_pvt_data->handle = dlopen(l_path, RTLD_NOW); // Try with specified architecture first
+    if(l_pvt_data->handle){
+        l_pvt_data->callback_init = dlsym(l_pvt_data->handle, "plugin_init");
+        l_pvt_data->callback_deinit = dlsym(l_pvt_data->handle, "plugin_deinit");
+    }else{
+        log_it(L_ERROR,"Can't load %s module: %s (expected path %s)", a_manifest->name, l_path, dlerror());
+        *a_error_str = dap_strdup_printf("Can't load %s module: %s (expected path %s)", a_manifest->name, l_path, dlerror());
+        return -5;
+    }
+    #endif
+    if( l_pvt_data->callback_init){
+        return l_pvt_data->callback_init(a_manifest->config,a_error_str);
+    }else{
+        log_it(L_ERROR,"No \"plugin_init\" entry point in binary plugin") ;
+        *a_error_str = dap_strdup("No \"plugin_init\" entry point in binary plugin");
+        DAP_DELETE(l_pvt_data);
+        return -5;
+    }
+}
+
+/**
+ * @brief s_type_callback_unload
+ * @param a_manifest
+ * @param a_pvt_data
+ * @param a_error_str
+ * @return
+ */
+static int s_type_callback_unload(dap_plugin_manifest_t * a_manifest, void * a_pvt_data, char ** a_error_str )
+{
+    if(a_manifest == s_manifest) // Its our own manifest, do nothing we're can't be unloaded
+        return 0;
+    struct binary_pvt_data * l_pvt_data = (struct binary_pvt_data *) a_pvt_data;
+    assert(l_pvt_data);
+    if(l_pvt_data->callback_deinit)
+        l_pvt_data->callback_deinit();
+#if defined (DAP_OS_LINUX) && !defined (__ANDROID__)
+    dlclose(l_pvt_data->handle);
+#endif
+    return 0;
+}
diff --git a/plugin/src/dap_plugin_command.c b/plugin/src/dap_plugin_command.c
new file mode 100644
index 000000000..272aa3d1b
--- /dev/null
+++ b/plugin/src/dap_plugin_command.c
@@ -0,0 +1,156 @@
+
+#include "dap_common.h"
+#include "dap_strfuncs.h"
+#include "dap_cli_server.h"
+#include "dap_plugin_manifest.h"
+#include "dap_plugin.h"
+#include "uthash.h"
+#include "utlist.h"
+#include "dap_plugin_command.h"
+
+#define LOG_TAG "dap_plugin_command"
+
+static bool s_l_restart_plugins = false;
+
+static int s_command_handler(int a_argc, char **a_argv, char **a_str_reply);
+
+
+/**
+ * @brief dap_chain_plugins_command_create
+ */
+void dap_plugin_command_init(void)
+{
+    if (!s_l_restart_plugins){
+        dap_cli_server_cmd_add("plugin", s_command_handler,
+                                           "Commands for working with plugins:\n",
+                                           "plugin list\n"
+                                           "\tShow plugins list\n"
+                                           "plugin show <plugin name>\n"
+                                           "\tShow plugin details\n"
+                                           "plugin restart\n"
+                                           "\tRestart all plugins\n"
+                                           "plugin reload <plugin name>\n"
+                                           "\tRestart plugin <plugin name>\n\n");
+        s_l_restart_plugins = true;
+    }
+}
+
+/**
+ * @brief dap_plugin_command_deinit
+ */
+void dap_plugin_command_deinit(void)
+{
+
+}
+
+/**
+ * @brief s_command_handler
+ * @param a_argc
+ * @param a_argv
+ * @param a_str_reply
+ * @return
+ */
+static int s_command_handler(int a_argc, char **a_argv, char **a_str_reply)
+{
+    enum {
+        CMD_NONE, CMD_LIST, CMD_SHOW_NAME, CMD_RESTART, CMD_RELOAD_NAME
+    };
+    int l_arg_index = 1;
+    int l_cmd_name = CMD_NONE;
+    dap_plugin_manifest_t *l_manifest = NULL, *l_tmp = NULL;
+    const char * l_cmd_arg = NULL;
+    if (dap_cli_server_cmd_find_option_val(a_argv,l_arg_index, a_argc, "list", &l_cmd_arg))
+        l_cmd_name = CMD_LIST;
+    if (dap_cli_server_cmd_find_option_val(a_argv,l_arg_index, a_argc, "show", &l_cmd_arg))
+        l_cmd_name = CMD_SHOW_NAME;
+    if (dap_cli_server_cmd_find_option_val(a_argv,l_arg_index, a_argc, "restart", &l_cmd_arg))
+        l_cmd_name = CMD_RESTART;
+    if (dap_cli_server_cmd_find_option_val(a_argv,l_arg_index, a_argc, "reload", &l_cmd_arg))
+        l_cmd_name = CMD_RELOAD_NAME;
+    switch (l_cmd_name) {
+        case CMD_LIST:{
+            char *l_str = NULL;
+            l_str = dap_strdup("|\tName plugin\t|\tVersion\t|\tAuthor(s)\t|\n");
+            HASH_ITER(hh,dap_plugin_manifest_all(), l_manifest, l_tmp){
+                l_str = dap_strjoin(NULL,
+                                  l_str, "|\t",l_manifest->name, "\t|\t", l_manifest->version, "\t|\t", l_manifest->author, "\t|\n", NULL);
+
+            }
+            dap_cli_server_cmd_set_reply_text(a_str_reply, l_str);
+        }break;
+        case CMD_SHOW_NAME:
+            if(!l_cmd_arg){
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Need argument for this command");
+            }
+            HASH_FIND_STR(dap_plugin_manifest_all(), l_cmd_arg, l_manifest);
+            if(l_manifest){
+                char *l_deps = dap_plugin_manifests_get_list_dependencies(l_manifest);
+                dap_cli_server_cmd_set_reply_text(a_str_reply, " Name: %s\n Version: %s\n Author: %s\n"
+                                                               " Description: %s\n Dependencies: %s \n\n",
+                                                  l_manifest->name, l_manifest->version, l_manifest->author,
+                                                  l_manifest->description, l_deps?l_deps:" ");
+                if(l_deps)
+                    DAP_DELETE(l_deps);
+            } else {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't find a plugin named %s", l_cmd_arg);
+            }
+            break;
+        case CMD_RESTART:
+            log_it(L_NOTICE, "Restart python plugin module");
+            dap_plugin_stop_all();
+            dap_plugin_start_all();
+            log_it(L_NOTICE, "Restart completed");
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Restart completed");
+            break;
+        case CMD_RELOAD_NAME:{
+            int l_result;
+            l_result = dap_plugin_stop(l_cmd_arg);
+            switch (l_result) {
+                case 0: //All is good
+                    break;
+                case -4:
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "A plugin named \"%s\" was not found.", l_cmd_arg);
+                    break;
+                case -5:
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "A plugin named \"%s\" is not loaded", l_cmd_arg);
+                    break;
+                default:
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "An unforeseen error has occurred.");
+                    break;
+            }
+            if(l_result == 0){
+                l_result = dap_plugin_start(l_cmd_arg);
+                switch (l_result) {
+                    case 0:
+                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Restart \"%s\" plugin is completed successfully.", l_cmd_arg);
+                        break;
+                    case -1:
+                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Plugin \"%s\" has unsupported type, pls check manifest file", l_cmd_arg);
+                        break;
+                    case -2:
+                        dap_cli_server_cmd_set_reply_text(a_str_reply,
+                                                          "\"%s\" plugin has unresolved dependencies. Restart all plugins.",
+                                                          l_cmd_arg);
+                        break;
+                    case -3:
+                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Registration \"%s\" manifest for \"%s\" plugin is failed.", l_cmd_arg);
+                        break;
+                    case -4:
+                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Plugin \"%s\" was not found.", l_cmd_arg);
+                        break;
+                    case -5:
+                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Plugin \"%s\" can't load", l_cmd_arg);
+                        break;
+                    default:
+                        dap_cli_server_cmd_set_reply_text(a_str_reply, "An unforeseen error has occurred.");
+                        break;
+                }
+            }
+        }break;
+        default:
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Arguments are incorrect.");
+            break;
+
+    }
+    return 0;
+}
diff --git a/plugin/src/dap_plugin_manifest.c b/plugin/src/dap_plugin_manifest.c
new file mode 100644
index 000000000..32a511185
--- /dev/null
+++ b/plugin/src/dap_plugin_manifest.c
@@ -0,0 +1,289 @@
+#include "dap_common.h"
+#include "dap_config.h"
+#include "dap_strfuncs.h"
+#include "dap_file_utils.h"
+#include "json-c/json_object.h"
+#include "json-c/json_tokener.h"
+
+#include "dap_plugin_manifest.h"
+#include "uthash.h"
+#include <string.h>
+
+#define LOG_TAG "dap_plugin_manifest"
+
+dap_plugin_manifest_t* s_manifests = NULL;
+
+static void s_manifest_delete(dap_plugin_manifest_t *a_manifest);
+
+/**
+ * @brief dap_plugin_manifest_init
+ * @return
+ */
+int dap_plugin_manifest_init()
+{
+    return 0;
+}
+
+/**
+ * @brief dap_plugin_manifest_deinit
+ */
+void dap_plugin_manifest_deinit()
+{
+    dap_plugin_manifest_t *l_manifest, * l_tmp;
+    HASH_ITER(hh,s_manifests,l_manifest,l_tmp){
+        HASH_DELETE(hh, s_manifests, l_manifest);
+        s_manifest_delete(l_manifest);
+    }
+}
+
+
+/**
+ * @brief dap_plugin_manifest_add_from_scratch
+ * @param a_name
+ * @param a_type
+ * @param a_author
+ * @param a_version
+ * @param a_description
+ * @param a_dependencies_names
+ * @param a_dependencies_count
+ * @param a_params
+ * @param a_params_count
+ * @return
+ */
+dap_plugin_manifest_t* dap_plugin_manifest_add_builtin(const char *a_name, const char * a_type,
+                                                            const char * a_author, const char * a_version,
+                                                            const char * a_description, char ** a_dependencies_names,
+                                                            size_t a_dependencies_count, char ** a_params, size_t a_params_count)
+{
+    dap_plugin_manifest_t *l_manifest = NULL;
+    HASH_FIND_STR(s_manifests, a_name, l_manifest);
+    if(l_manifest){
+        log_it(L_ERROR, "Plugin name \"%s\" is already present", a_name);
+        return NULL;
+    }
+
+    l_manifest = DAP_NEW_Z(dap_plugin_manifest_t);
+    strncpy(l_manifest->name,a_name, sizeof(l_manifest->name)-1);
+    l_manifest->type = dap_strdup(a_type);
+    l_manifest->is_builtin = true;
+    l_manifest->author = dap_strdup(a_author);
+    l_manifest->version = dap_strdup(a_version);
+    l_manifest->description = dap_strdup(a_description);
+    l_manifest->dependencies_names = DAP_NEW_Z_SIZE(char *, sizeof(char*)* a_dependencies_count);
+    for(size_t i = 0; i < a_dependencies_count; i++){
+        l_manifest->dependencies_names[i] = dap_strdup (a_dependencies_names[i]);
+    }
+    l_manifest->dependencies_count = a_dependencies_count;
+
+    l_manifest->params_count = a_params_count;
+    l_manifest->params = DAP_NEW_Z_SIZE(char *, sizeof(char*)* a_params_count);
+    for(size_t i = 0; i < a_params_count; i++){
+        l_manifest->params[i] = dap_strdup (a_params[i]);
+    }
+    HASH_ADD_STR(s_manifests,name,l_manifest);
+    return l_manifest;
+}
+
+/**
+ * @brief dap_plugin_manifest_add_from_file
+ * @param file_path
+ * @return
+ */
+dap_plugin_manifest_t* dap_plugin_manifest_add_from_file(const char *a_file_path)
+{
+    //READ File in char
+    log_it(L_INFO, "Parse JSON file");
+    FILE *l_json_file = fopen(a_file_path, "rt");
+    if (l_json_file == NULL){
+        log_it(L_ERROR, "Can't open manifest file on path: %s", a_file_path);
+        return NULL;
+    }
+    fseek(l_json_file, 0, SEEK_END);
+    size_t size_file = (size_t)ftell(l_json_file);
+    char *l_json_data = DAP_NEW_SIZE(char, size_file);
+    rewind(l_json_file);
+    fread(l_json_data, sizeof(char), size_file, l_json_file);
+    fclose(l_json_file);
+    //Parse JSON
+    json_object *l_json_obj = json_tokener_parse(l_json_data);
+    json_object *l_json_name = NULL;
+    json_object *l_json_version = NULL;
+    json_object *l_json_dependencies = NULL;
+    json_object *l_json_author = NULL;
+    json_object *l_json_description = NULL;
+    json_object *l_json_path = NULL;
+    json_object *l_json_params = NULL;
+    json_object *l_json_type = NULL;
+
+    if (!json_object_object_get_ex(l_json_obj, "name", &l_json_name))
+        return NULL;
+    if (!json_object_object_get_ex(l_json_obj, "type", &l_json_type))
+        return NULL;
+    if (!json_object_object_get_ex(l_json_obj, "version", &l_json_version))
+        return NULL;
+    if (!json_object_object_get_ex(l_json_obj, "dependencies", &l_json_dependencies))
+        return NULL;
+    if (!json_object_object_get_ex(l_json_obj, "author", &l_json_author))
+        return NULL;
+    if (!json_object_object_get_ex(l_json_obj, "description", &l_json_description))
+        return NULL;
+    json_object_object_get_ex(l_json_obj, "description", &l_json_params);
+    json_object_object_get_ex(l_json_obj, "path", &l_json_path);
+
+    const char *l_name, *l_type, *l_version, *l_author, *l_description;
+    size_t l_dependencies_count, l_params_count;
+    char ** l_dependencies_names = NULL, **l_params = NULL;
+    l_name = json_object_get_string(l_json_name);
+
+    dap_plugin_manifest_t *l_manifest = NULL;
+    HASH_FIND_STR(s_manifests, l_name, l_manifest);
+    if(l_manifest){
+        log_it(L_ERROR, "Plugin name \"%s\" is already present", l_name);
+        DAP_DELETE(l_json_data);
+        return NULL;
+    }
+
+
+    l_type = json_object_get_string(l_json_type);
+    l_version = json_object_get_string(l_json_version);
+    l_author = json_object_get_string(l_json_author);
+    l_description = json_object_get_string(l_json_description);
+    l_dependencies_count = (size_t)json_object_array_length(l_json_dependencies);
+    l_params_count = (size_t)json_object_array_length(l_json_params);
+
+    // Read dependencies;
+    if(l_dependencies_count){
+        l_dependencies_names = DAP_NEW_SIZE(char*, sizeof(char*)* l_dependencies_count );
+        for (size_t i = 0; i <  l_dependencies_count; i++){
+            l_dependencies_names[i] = dap_strdup(json_object_get_string(json_object_array_get_idx(l_json_dependencies, i)));
+        }
+    }
+
+    // Read additional params
+    if(l_params_count){
+        l_params = DAP_NEW_SIZE(char*, sizeof(char*)* l_params_count );
+        for (size_t i = 0; i < l_params_count; i++){
+            l_params[i] = dap_strdup(json_object_get_string(json_object_array_get_idx(l_json_params, i)));
+        }
+    }
+
+    // Create manifest itself
+    l_manifest = DAP_NEW_Z(dap_plugin_manifest_t);
+    strncpy(l_manifest->name,l_name, sizeof(l_manifest->name)-1);
+    l_manifest->type = dap_strdup(l_type);
+    l_manifest->author = dap_strdup(l_author);
+    l_manifest->version = dap_strdup(l_version);
+    l_manifest->description = dap_strdup(l_description);
+    l_manifest->dependencies_names = l_dependencies_names;
+    l_manifest->dependencies_count = l_dependencies_count;
+    l_manifest->params_count = l_params_count;
+    l_manifest->params = l_params;
+    if(l_json_path){ // If targeted manualy plugin's path
+        l_manifest->path = dap_strdup(json_object_get_string(l_json_path));
+    }else{ // Compose it from plugin root path
+        l_manifest->path = dap_path_get_dirname(a_file_path);
+    }
+
+    char * l_config_path = dap_strdup_printf("%s/%s.cfg", l_manifest->path,l_manifest->name );
+    if(dap_file_test(l_config_path)) // If present custom config
+        l_manifest->config = dap_config_load(l_config_path);
+    DAP_DELETE(l_config_path);
+
+    HASH_ADD_STR(s_manifests,name,l_manifest);
+
+    json_object_put(l_json_dependencies);
+    json_object_put(l_json_description);
+    json_object_put(l_json_author);
+    json_object_put(l_json_version);
+    json_object_put(l_json_name);
+    DAP_FREE(l_json_obj);
+    DAP_FREE(l_json_data);
+    return l_manifest;
+}
+
+/**
+ * @brief Returns all the manifests declared in system
+ * @return
+ */
+dap_plugin_manifest_t* dap_plugin_manifest_all()
+{
+    return s_manifests;
+}
+
+/**
+ * @brief Find plugin manifest by its unique name
+ * @param a_name Plugin name
+ * @return Pointer to manifest object if found or NULL if not
+ */
+dap_plugin_manifest_t *dap_plugin_manifest_find(const char *a_name)
+{
+    dap_plugin_manifest_t *l_ret;
+    HASH_FIND_STR(s_manifests,a_name,l_ret);
+    return l_ret;
+}
+
+/**
+ * @brief Create string with list of dependencies, breaking by ","
+ * @param a_element
+ * @return
+ */
+char* dap_plugin_manifests_get_list_dependencies(dap_plugin_manifest_t *a_element)
+{
+    if (a_element->dependencies == NULL) {
+        return NULL;
+    } else {
+        char *l_result = "";
+        dap_plugin_manifest_dependence_t * l_dep, *l_tmp;
+        HASH_ITER(hh,a_element->dependencies,l_dep,l_tmp){
+            dap_plugin_manifest_t * l_dep_manifest = l_dep->manifest;
+            if (l_dep->hh.hh_next )
+                l_result = dap_strjoin(NULL, l_result, l_dep_manifest->name, ", ", NULL);
+            else
+                l_result = dap_strjoin(NULL, l_result, l_dep_manifest->name, NULL);
+        }
+        return l_result;
+    }
+}
+
+/**
+ * @brief s_manifest_delete
+ * @param a_manifest
+ */
+static void s_manifest_delete(dap_plugin_manifest_t *a_manifest)
+{
+    DAP_DELETE(a_manifest->name);
+    DAP_DELETE(a_manifest->version);
+    DAP_DELETE(a_manifest->author);
+    DAP_DELETE(a_manifest->description);
+    if(a_manifest->dependencies_names){
+        for(size_t i = 0; i< a_manifest->dependencies_count; i++)
+            DAP_DELETE(a_manifest->dependencies_names[i]);
+        DAP_DELETE(a_manifest->dependencies_names);
+    }
+    dap_plugin_manifest_dependence_t * l_dep, *l_tmp;
+    HASH_ITER(hh,a_manifest->dependencies,l_dep,l_tmp){
+        HASH_DELETE(hh, a_manifest->dependencies, l_dep);
+        DAP_DELETE(l_dep);
+    }
+    DAP_DELETE(a_manifest);
+
+}
+
+/**
+ * @brief dap_plugins_manifest_remove
+ * @param a_name
+ * @return
+ */
+bool dap_plugins_manifest_remove(const char *a_name)
+{
+    dap_plugin_manifest_t *l_manifest;
+    HASH_FIND_STR(s_manifests, a_name,l_manifest);
+    if(l_manifest)
+        HASH_DEL(s_manifests, l_manifest);
+    else
+        return false;
+
+    s_manifest_delete(l_manifest);
+    return true;
+}
+
-- 
GitLab