From 6df86eea7ab96c44b88d868e5dadadc324971fbc Mon Sep 17 00:00:00 2001
From: Dmitriy Gerasimov <dm@cifercom.com>
Date: Fri, 12 Jan 2018 01:16:03 +0700
Subject: [PATCH] [*] DAP client state machine and other stuff

---
 client/CMakeLists.txt         |   2 +-
 client/dap_client.c           |  78 +++++++--
 client/dap_client.h           |  35 +++-
 client/dap_client_internal.c  |  40 ++---
 client/dap_client_internal.h  |   7 +-
 core/dap_common.c             |  32 +++-
 core/dap_common.h             |   1 +
 http/CMakeLists.txt           |   4 +-
 http/dap_http_client_simple.c | 321 ++++++++++++++++++++++++++++++++++
 http/dap_http_client_simple.h |  20 +++
 10 files changed, 483 insertions(+), 57 deletions(-)
 create mode 100644 http/dap_http_client_simple.c
 create mode 100644 http/dap_http_client_simple.h

diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt
index 2120d03f2c..c8a3bee84e 100644
--- a/client/CMakeLists.txt
+++ b/client/CMakeLists.txt
@@ -1,7 +1,7 @@
 cmake_minimum_required(VERSION 2.8)
 project (dap_client)
   
-set(CLIENT_SRCS dap_client.c dap_client_internal.c dap_client_remote.c dap_common.c)
+set(CLIENT_SRCS dap_client.c dap_client_internal.c dap_client_remote.c)
  
 add_library(${PROJECT_NAME} STATIC ${CLIENT_SRCS})
 
diff --git a/client/dap_client.c b/client/dap_client.c
index 9349956e8d..a7aa519560 100644
--- a/client/dap_client.c
+++ b/client/dap_client.c
@@ -1,8 +1,10 @@
-#include <stddef.h>
+#include <string.h>
+
 #include "dap_common.h"
 
+#include "dap_http_client.h"
+
 #include "dap_client.h"
-#include "dap_client_remote.h"
 #include "dap_client_internal.h"
 
 #define LOG_TAG "dap_client"
@@ -14,7 +16,8 @@
 int dap_client_init()
 {
     log_it(L_INFO, "Init DAP client module");
-    dap_client_remote_init();
+    dap_http_client_init();
+    dap_client_internal_init();
     return 0;
 }
 
@@ -23,23 +26,26 @@ int dap_client_init()
  */
 void dap_client_deinit()
 {
+    dap_client_internal_deinit();
+    dap_http_client_deinit();
     log_it(L_INFO, "Deinit DAP client module");
-    dap_client_remote_deinit();
 }
 
 /**
  * @brief dap_client_new
  * @param a_stage_status_callback
+ * @param a_stage_status_error_callback
  * @return
  */
-dap_client_t * dap_client_new(dap_client_callback_t a_stage_status_callback)
+dap_client_t * dap_client_new(dap_client_callback_t a_stage_status_callback
+                              ,dap_client_callback_t a_stage_status_error_callback )
 {
     // ALLOC MEM FOR dap_client
-    dap_client_t *l_client = CALLOC(dap_client_t);
+    dap_client_t *l_client = DAP_NEW_Z(dap_client_t);
     if (!l_client)
         goto MEM_ALLOC_ERR;
 
-    l_client->_internal  = CALLOC(dap_client_internal_t);
+    l_client->_internal  = DAP_NEW_Z(dap_client_internal_t);
     if (!l_client->_internal)
         goto MEM_ALLOC_ERR;
 
@@ -60,6 +66,7 @@ MEM_ALLOC_ERR:
 
     if (l_client)
         free (l_client);
+
 }
 
 /**
@@ -77,8 +84,7 @@ void dap_client_delete(dap_client_t * a_client)
  * @param a_client
  * @param a_stage_end
  */
-void dap_client_go_stage(dap_client_t * a_client, dap_client_stage_t a_stage_end,
-                         dap_client_callback_t a_stage_end_callback)
+void dap_client_go_stage(dap_client_t * a_client, dap_client_stage_t a_stage_target, dap_client_callback_t a_stage_end_callback)
 {
     // ----- check parameters -----
     if(NULL == a_client) {
@@ -117,15 +123,18 @@ void dap_client_go_stage(dap_client_t * a_client, dap_client_stage_t a_stage_end
 }
 
 /**
- * @brief dap_client_session_request
+ * @brief dap_client_request_enc
  * @param a_client
  * @param a_path
+ * @param a_suburl
+ * @param a_query
  * @param a_request
  * @param a_request_size
  * @param a_response_proc
+ * @param a_response_error
  */
-void dap_client_session_request(dap_client_t * a_client, const char * a_path, void * a_request, size_t a_request_size,
-                                dap_client_callback_t a_response_proc)
+void dap_client_request_enc(dap_client_t * a_client, const char * a_path, const char * a_suburl,const char* a_query, void * a_request, size_t a_request_size,
+                                dap_client_callback_data_size_t a_response_proc, dap_client_callback_int_t a_response_error )
 {
     dap_client_internal_t * l_client_internal = DAP_CLIENT_INTERNAL(a_client);
     dap_client_internal_request_enc(l_client_internal, a_path, a_suburl, a_query,a_request,a_request_size, a_response_proc,a_response_error);
@@ -182,10 +191,23 @@ const char * dap_client_error_str(dap_client_error_t a_client_error)
         case DAP_CLIENT_ERROR_NETWORK_CONNECTION_TIMEOUT: return "NETWORK_CONNECTION_TIMEOUT";
         case DAP_CLIENT_ERROR_NETWORK_CONNECTION_REFUSE: return "NETWORK_CONNECTION_REFUSE";
         case DAP_CLIENT_ERROR_NETWORK_DISCONNECTED: return "NETWORK_DISCONNECTED";
+        case DAP_CLIENT_ERROR_STREAM_RESPONSE_WRONG: return "STREAM_RESPONSE_WRONG";
+        case DAP_CLIENT_ERROR_STREAM_RESPONSE_TIMEOUT: return "STREAM_RESPONSE_TIMEOUT";
+        case DAP_CLIENT_ERROR_STREAM_FREEZED: return "STREAM_FREEZED";
+        case DAP_CLIENT_ERROR_LICENSE: return "LICENSE_ERROR";
         default : return "UNDEFINED";
     }
 }
 
+/**
+ * @brief dap_client_get_error_str
+ * @param a_client
+ * @return
+ */
+const char * dap_client_get_error_str(dap_client_t * a_client)
+{
+   return dap_client_error_str( DAP_CLIENT_INTERNAL(a_client)->last_error );
+}
 /**
  * @brief dap_client_get_stage
  * @param a_client
@@ -201,9 +223,18 @@ dap_client_stage_t dap_client_get_stage(dap_client_t * a_client)
  * @param a_client
  * @return
  */
-const char * dap_client_get_stage_status_str(dap_client_t *a_client)
+const char * dap_client_get_stage_status_str(dap_client_t *a_client){
+    return dap_client_stage_status_str(DAP_CLIENT_INTERNAL(a_client)->stage_status);
+}
+
+/**
+ * @brief dap_client_stage_status_str
+ * @param a_stage_status
+ * @return
+ */
+const char * dap_client_stage_status_str(dap_client_stage_status_t a_stage_status)
 {
-    switch(DAP_CLIENT_INTERNAL(a_client)->stage_status){
+    switch(a_stage_status){
         case DAP_CLIENT_STAGE_STATUS_NONE: return "NONE";
         case DAP_CLIENT_STAGE_STATUS_IN_PROGRESS: return "IN_PROGRESS";
         case DAP_CLIENT_STAGE_STATUS_ERROR: return "ERROR";
@@ -217,12 +248,26 @@ const char * dap_client_get_stage_status_str(dap_client_t *a_client)
  * @param a_client
  * @return
  */
-const char * dap_client_get_stage_str(dap_client_t * a_client)
+const char * dap_client_get_stage_str(dap_client_t *a_client)
+{
+    return dap_client_stage_str(DAP_CLIENT_INTERNAL(a_client)->stage);
+}
+
+/**
+ * @brief dap_client_stage_str
+ * @param a_stage
+ * @return
+ */
+const char * dap_client_stage_str(dap_client_stage_t a_stage)
 {
-    switch(DAP_CLIENT_INTERNAL(a_client)->stage){
+    switch(a_stage){
         case DAP_CLIENT_STAGE_BEGIN: return "BEGIN";
         case DAP_CLIENT_STAGE_ENC: return "ENC";
         case DAP_CLIENT_STAGE_AUTH: return "AUTH";
+        case DAP_CLIENT_STAGE_STREAM_CTL: return "STREAM_CTL";
+        case DAP_CLIENT_STAGE_STREAM: return "STREAM";
+        case DAP_CLIENT_STAGE_NETCONF: return "NETCONF";
+        case DAP_CLIENT_STAGE_TUNNEL: return "TUNNEL";
         default: return "UNDEFINED";
     }
 }
@@ -235,3 +280,4 @@ dap_client_stage_status_t dap_client_get_stage_status(dap_client_t * a_client)
 {
     return DAP_CLIENT_INTERNAL(a_client)->stage_status;
 }
+
diff --git a/client/dap_client.h b/client/dap_client.h
index 1d706c3fbf..cab39b1d8c 100644
--- a/client/dap_client.h
+++ b/client/dap_client.h
@@ -1,6 +1,5 @@
 #ifndef _DAP_CLIENT_H_
 #define _DAP_CLIENT_H_
-
 #include <stdint.h>
 #include <stddef.h>
 
@@ -11,18 +10,23 @@ typedef enum dap_client_stage {
     DAP_CLIENT_STAGE_BEGIN=0,
     DAP_CLIENT_STAGE_ENC=1,
     DAP_CLIENT_STAGE_AUTH=2,
+    DAP_CLIENT_STAGE_STREAM_CTL=3,
+    DAP_CLIENT_STAGE_STREAM=4,
+    DAP_CLIENT_STAGE_NETCONF=5,
+    DAP_CLIENT_STAGE_TUNNEL=6,
 } dap_client_stage_t;
 
 typedef enum dap_client_stage_status {
     DAP_CLIENT_STAGE_STATUS_NONE=0,
     // Enc init stage
     DAP_CLIENT_STAGE_STATUS_IN_PROGRESS,
+    DAP_CLIENT_STAGE_STATUS_ABORTING,
     DAP_CLIENT_STAGE_STATUS_ERROR,
     DAP_CLIENT_STAGE_STATUS_DONE,
 } dap_client_stage_status_t;
 
 typedef enum dap_client_error {
-    DAP_CLIENT_ERROR_UNDEFINED = 0,
+    DAP_CLIENT_ERROR_NO = 0,
     DAP_CLIENT_ERROR_ENC_NO_KEY,
     DAP_CLIENT_ERROR_ENC_WRONG_KEY,
     DAP_CLIENT_ERROR_AUTH_WRONG_COOKIE,
@@ -30,6 +34,10 @@ typedef enum dap_client_error {
     DAP_CLIENT_ERROR_NETWORK_CONNECTION_TIMEOUT,
     DAP_CLIENT_ERROR_NETWORK_CONNECTION_REFUSE,
     DAP_CLIENT_ERROR_NETWORK_DISCONNECTED,
+    DAP_CLIENT_ERROR_STREAM_RESPONSE_WRONG,
+    DAP_CLIENT_ERROR_STREAM_RESPONSE_TIMEOUT,
+    DAP_CLIENT_ERROR_STREAM_FREEZED,
+    DAP_CLIENT_ERROR_LICENSE,
 } dap_client_error_t;
 
 
@@ -42,6 +50,14 @@ typedef struct dap_client{
 } dap_client_t;
 
 typedef void (*dap_client_callback_t) (dap_client_t *, void*);
+typedef void (*dap_client_callback_int_t) (dap_client_t *, int);
+typedef void (*dap_client_callback_data_size_t) (dap_client_t *, void *, size_t);
+
+#define DAP_UPLINK_PATH_ENC_INIT "enc_init"
+#define DAP_UPLINK_PATH_DB "db"
+#define DAP_UPLINK_PATH_STREAM_CTL "stream_ctl"
+#define DAP_UPLINK_PATH_STREAM "stream"
+#define DAP_UPLINK_PATH_LICENSE "license"
 
 #ifdef __cplusplus
 extern "C" {
@@ -50,20 +66,25 @@ extern "C" {
 int dap_client_init();
 void dap_client_deinit();
 
-dap_client_t * dap_client_new(dap_client_callback_t a_stage_status_callback);
+dap_client_t * dap_client_new(dap_client_callback_t a_stage_status_callback
+                              , dap_client_callback_t a_stage_status_error_callback );
 void dap_client_delete(dap_client_t * a_client);
 
 void dap_client_set_uplink(dap_client_t * a_client,const char* a_addr, uint16_t a_port);
-void dap_client_go_stage(dap_client_t * a_client, dap_client_stage_t a_stage_end, dap_client_callback_t a_stage_end_callback);
-
 void dap_client_set_credentials(dap_client_t * a_client,const char* a_user, const char * a_password);
+void dap_client_go_stage(dap_client_t * a_client, dap_client_stage_t a_stage_end, dap_client_callback_t a_stage_end_callback);
 
-void dap_client_enc_request(dap_client_t * a_client, const char * a_path, void * a_request, size_t a_request_size,
-                                dap_client_callback_t a_response_proc);
+void dap_client_request_enc(dap_client_t * a_client, const char * a_path,const char * a_suburl,const char* a_query, void * a_request, size_t a_request_size,
+                                dap_client_callback_data_size_t a_response_proc, dap_client_callback_int_t a_response_error);
 
 const char * dap_client_get_stage_str(dap_client_t * a_client);
+const char * dap_client_stage_str(dap_client_stage_t a_stage);
+
 const char * dap_client_get_stage_status_str(dap_client_t * a_client);
+const char * dap_client_stage_status_str(dap_client_stage_status_t a_stage_status);
 const char * dap_client_error_str(dap_client_error_t a_client_error);
+const char * dap_client_get_error_str(dap_client_t * a_client);
+
 dap_client_stage_t dap_client_get_stage(dap_client_t * a_client);
 dap_client_stage_status_t dap_client_get_stage_status(dap_client_t * a_client);
 
diff --git a/client/dap_client_internal.c b/client/dap_client_internal.c
index e31965d831..3121f55919 100644
--- a/client/dap_client_internal.c
+++ b/client/dap_client_internal.c
@@ -4,24 +4,17 @@
 #include <string.h>
 #include <assert.h>
 
-#include "enc_key.h"
-#include "enc.h"
-#include "common.h"
+#include "dap_enc_key.h"
+#include "dap_enc.h"
+#include "dap_common.h"
 
-#include "dap_http_client.h"
+#include "dap_http_client_simple.h"
 #include "dap_client_internal.h"
 
 #define LOG_TAG "dap_client_internal"
 
-const char s_key_domain_str[]="FZVSsPaYr2TB51Ly4QrMZ8x9c8WY2Vq7"
-                             "NVcHl173CFFBCG9GrnXDYFWh1UDqJp2l"
-                             "hDjwwoM7Qbsgz57heI57VjB1SxHQztIN"
-                             "MIn0454AE0oO55HLwMPnT9l1iSJhK9wo"
-                             "9ZyhGO0tSqz4qphVD0CBGr1z98qzKtk6"
-                             "iZ0eo3CacI2IycvXNjxX9B70weHR0jCP"
-                             "zkVqG5ObAxUsufUyHKD3NL8vSYQy6UlF"
-                             "1Wpjhzl67zPwuez0xIkl0ORoA8S9miE";
-enc_key_t * s_key_domain = NULL;
+const char s_key_domain_str[]="FZVSsPaYr2TB51L";
+dap_enc_key_t * s_key_domain = NULL;
 static void s_stage_status_after(dap_client_internal_t * a_client_internal);
 
 void m_enc_init_response(dap_client_t *, void *, size_t);
@@ -36,7 +29,7 @@ void m_request_error(int,void *);
  */
 int dap_client_internal_init()
 {
-    s_key_domain = enc_key_create(s_key_domain_str,ENC_KEY_TYPE_AES);
+    s_key_domain = dap_enc_key_new_from_str(DAP_ENC_KEY_TYPE_AES, s_key_domain_str);
     return 0;
 }
 
@@ -45,7 +38,7 @@ int dap_client_internal_init()
  */
 void dap_client_internal_deinit()
 {
-    enc_key_delete(s_key_domain);
+    dap_enc_key_delete(s_key_domain);
     s_key_domain = NULL;
 }
 
@@ -94,12 +87,12 @@ static void s_stage_status_after(dap_client_internal_t * a_client_internal)
                         break;
                     }
 
-                    char *l_key_str= enc_random_string_create(255);
+                    char *l_key_str= random_string_create(255);
                     char *l_key_session_data = (char*) calloc(1,256*2);
-                    enc_code(s_key_domain,l_key_str,strlen(l_key_str),l_key_session_data,ENC_DATA_TYPE_B64);
+                    dap_enc_code(s_key_domain,l_key_str,strlen(l_key_str),l_key_session_data,DAP_ENC_DATA_TYPE_B64);
 
 
-                    a_client_internal->session_key = enc_key_create(l_key_session_data,ENC_KEY_TYPE_AES);
+                    a_client_internal->session_key = dap_enc_key_new_from_str(DAP_ENC_KEY_TYPE_AES,l_key_session_data);
 
                     log_it(L_DEBUG,"Request size %u",strlen(l_key_str));
                     dap_client_internal_request( a_client_internal, DAP_UPLINK_PATH_ENC_INIT "/hsd9jslagd92abgjalp9h",
@@ -218,14 +211,15 @@ void dap_client_internal_request_enc(dap_client_internal_t * a_client_internal,
     a_client_internal->is_encrypted = true;
 
     if ( l_sub_url_size )
-        enc_code(a_client_internal->session_key,a_sub_url,l_sub_url_size,l_sub_url_enc,ENC_DATA_TYPE_B64);
+        dap_enc_code(a_client_internal->session_key,a_sub_url,l_sub_url_size,l_sub_url_enc,DAP_ENC_DATA_TYPE_B64);
 
     if ( l_query_size )
-        enc_code(a_client_internal->session_key,a_query,l_query_size,l_query_enc,ENC_DATA_TYPE_B64);
+        dap_enc_code(a_client_internal->session_key,a_query,l_query_size,l_query_enc,DAP_ENC_DATA_TYPE_B64);
 
 
     if ( a_request_size )
-        l_request_enc_size = enc_code(a_client_internal->session_key, a_request, a_request_size, l_request_enc, ENC_DATA_TYPE_RAW );
+        l_request_enc_size = dap_enc_code(a_client_internal->session_key, a_request, a_request_size
+                                          , l_request_enc, DAP_ENC_DATA_TYPE_RAW );
 
     if (a_path){
         if( l_sub_url_size ){
@@ -283,8 +277,8 @@ void m_request_response(void * a_response,size_t a_response_size,void * a_obj)
         char * l_response_dec = a_response_size? (char*) calloc(1,l_response_dec_size_max ) : NULL;
         size_t l_response_dec_size = 0;
         if ( a_response_size )
-            l_response_dec_size = enc_decode(a_client_internal->session_key,
-                                             a_response, a_response_size, l_response_dec, ENC_DATA_TYPE_RAW );
+            l_response_dec_size = dap_enc_decode(a_client_internal->session_key,
+                                             a_response, a_response_size, l_response_dec, DAP_ENC_DATA_TYPE_RAW );
 
         a_client_internal->request_response_callback(a_client_internal->client, l_response_dec, l_response_dec_size );
 
diff --git a/client/dap_client_internal.h b/client/dap_client_internal.h
index 6b5b9aba05..6cea070ab1 100644
--- a/client/dap_client_internal.h
+++ b/client/dap_client_internal.h
@@ -6,7 +6,7 @@
 #include "dap_client.h"
 
 typedef struct dap_events_socket_t dap_events_socket_t;
-typedef struct enc_key enc_key_t;
+typedef struct dap_enc_key dap_enc_key_t;
 typedef struct dap_http_client dap_http_client_t;
 
 typedef struct dap_client_internal
@@ -17,7 +17,7 @@ typedef struct dap_client_internal
 
     dap_events_socket_t * es_stream;
 
-    enc_key_t * session_key;
+    dap_enc_key_t * session_key;
     char  * session_key_id;
 
     char  * uplink_addr;
@@ -42,6 +42,8 @@ typedef struct dap_client_internal
 } dap_client_internal_t;
 
 #define DAP_CLIENT_INTERNAL(a) ((dap_client_internal_t*) a->_internal )
+
+
 int dap_client_internal_init();
 void dap_client_internal_deinit();
 
@@ -57,4 +59,5 @@ void dap_client_internal_request_enc(dap_client_internal_t * a_client_internal,
 
 void dap_client_internal_new(dap_client_internal_t * a_client_internal);
 void dap_client_internal_delete(dap_client_internal_t * a_client_internal);
+
 #endif
diff --git a/core/dap_common.c b/core/dap_common.c
index 8f6a9ad4d7..3dab918ae5 100644
--- a/core/dap_common.c
+++ b/core/dap_common.c
@@ -1,4 +1,4 @@
-#ifdef SAP_OS_ANDROID
+#ifdef DAP_OS_ANDROID
 #include <android/log.h>
 #endif
 
@@ -76,26 +76,26 @@ void _vlog_it(const char * log_tag,enum log_level ll, const char * format,va_lis
     static pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
 
     pthread_mutex_lock(&mutex);
-#ifdef SAP_OS_ANDROID
+#ifdef DAP_OS_ANDROID
     char buf[4096];
     vsnprintf(buf,sizeof(buf),format,ap);
     switch (ll) {
         case L_INFO:
-            __android_log_write(ANDROID_LOG_INFO,SAP_BRAND,buf);
+            __android_log_write(ANDROID_LOG_INFO,DAP_BRAND,buf);
         break;
         case L_WARNING:
-            __android_log_write(ANDROID_LOG_WARN,SAP_BRAND,buf);
+            __android_log_write(ANDROID_LOG_WARN,DAP_BRAND,buf);
         break;
         case L_ERROR:
-            __android_log_write(ANDROID_LOG_ERROR,SAP_BRAND,buf);
+            __android_log_write(ANDROID_LOG_ERROR,DAP_BRAND,buf);
         break;
         case L_CRITICAL:
-            __android_log_write(ANDROID_LOG_FATAL,SAP_BRAND,buf);
+            __android_log_write(ANDROID_LOG_FATAL,DAP_BRAND,buf);
             abort();
         break;
         case L_DEBUG:
         default:
-            __android_log_write(ANDROID_LOG_DEBUG,SAP_BRAND,buf);
+            __android_log_write(ANDROID_LOG_DEBUG,DAP_BRAND,buf);
     }
 #endif
     time_t t=time(NULL);
@@ -302,3 +302,21 @@ char * exec_with_ret_multistring(const char * a_cmd)
 FIN:
     return strdup(retbuf);
 }
+
+/**
+ * @brief random_string_create
+ * @param a_length
+ * @return
+ */
+char * random_string_create(size_t a_length)
+{
+    const char l_possible_chars[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+    char * ret = (char*) malloc(a_length+1);
+    size_t i;
+    for(i=0; i<a_length; ++i) {
+        int index = rand() % (sizeof(l_possible_chars)-1);
+        ret[i] = l_possible_chars[index];
+    }
+    return ret;
+}
diff --git a/core/dap_common.h b/core/dap_common.h
index cce8b58cd5..f4750ccad5 100644
--- a/core/dap_common.h
+++ b/core/dap_common.h
@@ -41,6 +41,7 @@ int get_select_breaker();
 int send_select_break();
 char * exec_with_ret(const char * a_cmd);
 char * exec_with_ret_multistring(const char * a_cmd);
+char * random_string_create(size_t a_length);
 
 #ifdef __cplusplus
 }
diff --git a/http/CMakeLists.txt b/http/CMakeLists.txt
index caf4e162e2..247ce38b74 100644
--- a/http/CMakeLists.txt
+++ b/http/CMakeLists.txt
@@ -1,9 +1,11 @@
 cmake_minimum_required(VERSION 2.8)
 project (dap_http)
   
-set(HTTP_SRCS dap_http_client.c dap_http_header.c)
+set(HTTP_SRCS dap_http_client.c dap_http_client_simple.c dap_http_header.c)
  
 add_library(${PROJECT_NAME} STATIC ${HTTP_SRCS})
+target_link_libraries(${PROJECT_NAME}  curl)
+
 include_directories("${dap_core_INCLUDE_DIRS}")
 include_directories("${dap_client_INCLUDE_DIRS}")
 add_definitions ("${dap_core_DEFINITIONS}")
diff --git a/http/dap_http_client_simple.c b/http/dap_http_client_simple.c
new file mode 100644
index 0000000000..534d7c2584
--- /dev/null
+++ b/http/dap_http_client_simple.c
@@ -0,0 +1,321 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <time.h>
+#include <curl/curl.h>
+
+#include "utlist.h"
+
+#include "dap_common.h"
+
+#include "dap_http_client.h"
+#include "dap_http_client_simple.h"
+
+typedef struct dap_http_client_internal{
+
+    dap_http_client_simple_callback_data_t response_callback;
+    dap_http_client_simple_callback_error_t error_callback;
+    void * obj;
+    uint8_t * request;
+    size_t request_size;
+    size_t request_sent_size;
+    struct curl_slist * request_headers;
+
+    uint8_t * response;
+    size_t response_size;
+    size_t response_size_max;
+} dap_http_client_internal_t;
+
+CURLM *m_curl_mh; // Multi-thread handle to stack lot of parallel requests
+pthread_t curl_pid=0;
+pthread_cond_t m_curl_cond = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t m_curl_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void *dap_http_client_thread(void * arg);
+size_t dap_http_client_curl_request_callback(char * a_ptr, size_t a_size, size_t a_nmemb, void * a_userdata);
+size_t dap_http_client_curl_response_callback(char * a_ptr, size_t a_size, size_t a_nmemb, void * a_userdata);
+void dap_http_client_internal_delete(dap_http_client_internal_t * a_client);
+
+#define DAP_HTTP_CLIENT_RESPONSE_SIZE_MAX 40960
+
+#define LOG_TAG "dap_http_client"
+
+/**
+ * @brief dap_http_client_init
+ * @return
+ */
+int dap_http_client_init()
+{
+    curl_global_init(CURL_GLOBAL_ALL);
+    m_curl_mh = curl_multi_init();
+    pthread_create(&curl_pid,NULL,dap_http_client_thread,NULL );
+    return 0;
+}
+
+/**
+ * @brief dap_http_client_deinit
+ */
+void dap_http_client_deinit()
+{
+    curl_multi_cleanup( m_curl_mh );
+}
+
+/**
+ * @brief dap_http_client_internal_delete
+ * @param a_client
+ */
+void dap_http_client_internal_delete(dap_http_client_internal_t * a_client_internal)
+{
+    if( a_client_internal->request_headers)
+          curl_slist_free_all( a_client_internal->request_headers );
+
+    if ( a_client_internal->request )
+        free(a_client_internal->request);
+
+    if ( a_client_internal->response )
+        free(a_client_internal->response);
+
+    free(a_client_internal);
+}
+
+/**
+ * @brief dap_http_client_simple_request
+ * @param a_url
+ * @param a_method
+ * @param a_request_content_type
+ * @param a_request
+ * @param a_request_size
+ * @param a_response_callback
+ * @param a_error_callback
+ * @param a_obj
+ */
+void dap_http_client_simple_request(const char * a_url, const char * a_method, const char* a_request_content_type, void *a_request, size_t a_request_size, dap_http_client_simple_callback_data_t a_response_callback,
+                                   dap_http_client_simple_callback_error_t a_error_callback, void *a_obj, void * a_custom)
+{
+    log_it(L_DEBUG,"Simple HTTP request with static predefined buffer (%lu bytes) on url '%s'",
+           DAP_HTTP_CLIENT_RESPONSE_SIZE_MAX, a_url);
+    CURL *l_curl_h = curl_easy_init();
+
+    dap_http_client_internal_t * l_client_internal = DAP_NEW_Z(dap_http_client_internal_t);
+    l_client_internal->error_callback = a_error_callback;
+    l_client_internal->response_callback = a_response_callback;
+    l_client_internal->obj = a_obj;
+
+    l_client_internal->response_size_max = DAP_HTTP_CLIENT_RESPONSE_SIZE_MAX;
+    l_client_internal->response = (uint8_t*) calloc(1,DAP_HTTP_CLIENT_RESPONSE_SIZE_MAX);
+
+    l_client_internal->request = malloc(a_request_size);
+    memcpy(l_client_internal->request, a_request, a_request_size);
+    l_client_internal->request_size = a_request_size;
+
+    if( ( a_request ) && ( (
+                              (strcmp( a_method , "POST" ) == 0)  ||
+                              (strcmp( a_method , "POST_ENC" ) == 0)
+                          ) ) ){
+        char l_buf[1024];
+        log_it ( L_DEBUG , "POST request with %u bytes of decoded data" , a_request_size );
+
+        if( a_request_content_type )
+            l_client_internal->request_headers = curl_slist_append(l_client_internal->request_headers, a_request_content_type );
+
+        if( a_custom )
+            l_client_internal->request_headers = curl_slist_append(l_client_internal->request_headers,(char*) a_custom );
+
+        snprintf(l_buf,sizeof(l_buf),"Content-Length: %lu", a_request_size );
+        l_client_internal->request_headers = curl_slist_append(l_client_internal->request_headers, l_buf);
+
+        //curl_easy_setopt( l_curl_h , CURLOPT_READDATA , l_client_internal );
+        curl_easy_setopt( l_curl_h , CURLOPT_POST , 1 );
+        curl_easy_setopt( l_curl_h , CURLOPT_POSTFIELDSIZE, a_request_size );
+
+    }
+    if(l_client_internal->request_headers)
+        curl_easy_setopt(l_curl_h, CURLOPT_HTTPHEADER, l_client_internal->request_headers);
+
+    curl_easy_setopt( l_curl_h , CURLOPT_PRIVATE, l_client_internal );
+    curl_easy_setopt( l_curl_h , CURLOPT_URL, a_url);
+
+    curl_easy_setopt( l_curl_h , CURLOPT_READDATA , l_client_internal  );
+    curl_easy_setopt( l_curl_h , CURLOPT_READFUNCTION , dap_http_client_curl_request_callback );
+
+    curl_easy_setopt( l_curl_h , CURLOPT_WRITEDATA , l_client_internal );
+    curl_easy_setopt( l_curl_h , CURLOPT_WRITEFUNCTION , dap_http_client_curl_response_callback );
+
+    curl_multi_add_handle( m_curl_mh, l_curl_h );
+    pthread_cond_signal( &m_curl_cond);
+    send_select_break();
+}
+
+/**
+ * @brief dap_http_client_curl_response_callback
+ * @param a_ptr
+ * @param a_size
+ * @param a_nmemb
+ * @param a_userdata
+ * @return
+ */
+size_t dap_http_client_curl_response_callback(char * a_ptr, size_t a_size, size_t a_nmemb, void * a_userdata)
+{
+    dap_http_client_internal_t * l_client_internal = (dap_http_client_internal_t *) a_userdata;
+    log_it(L_DEBUG, "Recieved %lu bytes in HTTP resonse", a_size*a_nmemb);
+    if( l_client_internal->response_size < l_client_internal->response_size_max){
+        size_t l_size = a_size * a_nmemb;
+        if( l_size > ( l_client_internal->response_size_max - l_client_internal->response_size) )
+            l_size = l_client_internal->response_size_max - l_client_internal->response_size;
+        memcpy(l_client_internal->response + l_client_internal->response_size,a_ptr,l_size);
+        l_client_internal->response_size += l_size;
+    }else{
+        log_it(L_WARNING,"Too big reply, %lu bytes a lost",a_size*a_nmemb);
+    }
+    return a_size*a_nmemb;
+}
+
+/**
+ * @brief dap_http_client_curl_request_callback
+ * @param a_ptr
+ * @param a_size
+ * @param a_nmemb
+ * @param a_userdata
+ * @return
+ */
+size_t dap_http_client_curl_request_callback(char * a_ptr, size_t a_size, size_t a_nmemb, void * a_userdata)
+{
+    dap_http_client_internal_t * l_client_internal = (dap_http_client_internal_t *) a_userdata;
+    size_t l_size = a_size * a_nmemb;
+    if( ( l_size + l_client_internal->request_sent_size) > l_client_internal->request_size )
+        l_size = l_client_internal->request_size - l_client_internal->request_sent_size;
+
+    if( l_size ) {
+        memcpy( a_ptr, l_client_internal->request + l_client_internal->request_sent_size, l_size );
+        l_client_internal->request_sent_size += l_size;
+    }
+    return l_size;
+}
+
+/**
+ * @brief dap_http_client_thread
+ * @param arg
+ */
+static void* dap_http_client_thread(void * arg)
+{
+    (void) arg;
+    bool l_still_running = true;
+    do {
+        struct timeval timeout;
+        int rc; /* select() return code */
+        CURLMcode mc; /* curl_multi_fdset() return code */
+
+        fd_set fdread;
+        fd_set fdwrite;
+        fd_set fdexcep;
+        int maxfd = -1;
+
+        long curl_timeo = -1;
+
+        FD_ZERO(&fdread);
+        FD_ZERO(&fdwrite);
+        FD_ZERO(&fdexcep);
+
+        /* set a suitable timeout to play around with */
+        timeout.tv_sec = 10;
+        timeout.tv_usec = 0;
+
+        curl_multi_timeout( m_curl_mh, &curl_timeo);
+        if(curl_timeo >= 0) {
+          timeout.tv_sec = curl_timeo / 1000;
+          if(timeout.tv_sec > 1)
+            timeout.tv_sec = 1;
+          else
+            timeout.tv_usec = (curl_timeo % 1000) * 1000;
+        }
+
+        /* get file descriptors from the transfers */
+        mc = curl_multi_fdset(m_curl_mh, &fdread, &fdwrite, &fdexcep, &maxfd);
+        FD_SET(get_select_breaker(),&fdread);
+        if(get_select_breaker() > maxfd)
+            maxfd = get_select_breaker();
+
+        if(mc != CURLM_OK) {
+          log_it(L_ERROR, "curl_multi_fdset() failed, code %d.\n", mc);
+          break;
+        }
+
+        /* On success the value of maxfd is guaranteed to be >= -1. We call
+           select(maxfd + 1, ...); specially in case of (maxfd == -1) there are
+           no fds ready yet so we call select(0, ...) --or Sleep() on Windows--
+           to sleep 100ms, which is the minimum suggested value in the
+           curl_multi_fdset() doc. */
+        if(maxfd == -1) {
+            //log_it(L_DEBUG, "Waiting for signal");
+            pthread_cond_wait(&m_curl_cond,&m_curl_mutex);
+        }  else {
+            //log_it(L_DEBUG, "Selecting stuff");
+          /* Note that on some platforms 'timeout' may be modified by select().
+             If you need access to the original value save a copy beforehand. */
+          rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);
+        }
+
+        switch(rc) {
+            case -1: {
+              /* select error */
+            } break;
+            case 0: /* timeout */
+            default: { /* action */
+              int l_curl_eh_count = 0;
+              curl_multi_perform( m_curl_mh , &l_curl_eh_count );
+               // Check if we have smth complete
+              struct CURLMsg *m;
+              do {
+                  int msgq = 0;
+                  m = curl_multi_info_read(m_curl_mh, &msgq);
+                  if(m && (m->msg == CURLMSG_DONE)) {
+                      CURL *e = m->easy_handle;
+                      char * l_private = NULL;
+                      int l_err_code = 0;
+                      curl_easy_getinfo( e, CURLINFO_PRIVATE, &l_private );
+                      if( l_private ){
+                          bool l_is_ok = false;
+                          dap_http_client_internal_t * l_client_internal = (dap_http_client_internal_t *) l_private;
+                          switch ( m->data.result){
+                              case CURLE_OUT_OF_MEMORY: l_err_code = 1 ; log_it(L_CRITICAL, "Out of memory"); break;
+                              case CURLE_COULDNT_CONNECT: l_err_code = 2 ; log_it(L_ERROR, "Couldn't connect to the destination server"); break;
+                              case CURLE_COULDNT_RESOLVE_HOST: l_err_code = 3 ; log_it(L_ERROR, "Couldn't resolve destination address"); break;
+                              case CURLE_OPERATION_TIMEDOUT: l_err_code = 4 ; log_it(L_ERROR, "HTTP request timeout"); break;
+                              case CURLE_URL_MALFORMAT: l_err_code = 5 ; log_it(L_ERROR, "Wrong URL format in the outgoing request"); break;
+                              case CURLE_WEIRD_SERVER_REPLY: l_err_code = 6 ; log_it(L_WARNING, "Weird server reply"); break;
+                              case CURLE_OK:{
+                                l_is_ok = true;
+                                log_it(L_DEBUG, "Response size %u",l_client_internal->response_size);
+                              }break;
+                              default: l_err_code = 12345;
+                          }
+                          if( l_is_ok){
+                                l_client_internal->response_callback(l_client_internal->response,
+                                                                   l_client_internal->response_size,
+                                                                   l_client_internal->obj );
+                          }else {
+                                log_it(L_WARNING, "HTTP request wasn't processed well with error code %d",m->data.result );
+                                l_client_internal->error_callback(l_err_code , l_client_internal->obj );
+
+                          }
+                          dap_http_client_internal_delete(l_client_internal);
+                      } else {
+                        log_it(L_CRITICAL, "Can't get private information from libcurl handle to perform the reply to SAP connection");
+                      }
+                      curl_multi_remove_handle(m_curl_mh, e);
+                      curl_easy_cleanup(e);
+                  }
+             } while(m);
+            } break;
+        }
+    } while(l_still_running);
+
+    return NULL;
+}
+
+
diff --git a/http/dap_http_client_simple.h b/http/dap_http_client_simple.h
new file mode 100644
index 0000000000..0711b6de42
--- /dev/null
+++ b/http/dap_http_client_simple.h
@@ -0,0 +1,20 @@
+#ifndef DAP_HTTP_CLIENT_H
+#define DAP_HTTP_CLIENT_H
+#include <stddef.h>
+struct dap_http_client_simple;
+typedef void (*dap_http_client_simple_callback_error_t) (int,void *); // Callback for specific http client operations
+typedef void (*dap_http_client_simple_callback_data_t) (void *,size_t,void *); // Callback for specific http client operations
+
+typedef struct dap_http_client_simple {
+    void * _inheritor;
+} dap_http_client_simple_t;
+
+int dap_http_client_init();
+void dap_http_client_deinit();
+
+void dap_http_client_simple_request(const char * a_url, const char * a_method,
+                                   const char* a_request_content_type , void *a_request, size_t a_request_size,
+                                   dap_http_client_simple_callback_data_t a_response_callback,
+                                   dap_http_client_simple_callback_error_t a_error_callback, void *a_obj, void * a_custom);
+
+#endif
-- 
GitLab