From c6e9a626726a7004fef5adac217cd053418760a0 Mon Sep 17 00:00:00 2001
From: Dmitriy Gerasimov <dm@cifercom.com>
Date: Wed, 27 Dec 2017 14:44:42 +0700
Subject: [PATCH] [+] Declarations for dap_client [+] Moved dap_client_remote
 from libdap-server (ex-dap_client)

---
 CMakeLists.txt             |  12 ++
 client/CMakeLists.txt      |  10 ++
 client/dap_client.c        | 167 +++++++++++++++++++++++++
 client/dap_client.h        |  69 ++++++++++
 client/dap_client_remote.c | 249 +++++++++++++++++++++++++++++++++++++
 client/dap_client_remote.h |  86 +++++++++++++
 core/CMakeLists.txt        |   2 +-
 7 files changed, 594 insertions(+), 1 deletion(-)
 create mode 100644 CMakeLists.txt
 create mode 100644 client/CMakeLists.txt
 create mode 100644 client/dap_client.c
 create mode 100644 client/dap_client.h
 create mode 100644 client/dap_client_remote.c
 create mode 100644 client/dap_client_remote.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000000..b1bce72dd7
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,12 @@
+project(libdap C)
+cmake_minimum_required(VERSION 2.8)
+
+add_subdirectory(core)
+add_subdirectory(crypt)
+add_subdirectory(client)
+add_subdirectory(http)
+
+include_directories("${INCLUDE_DIRECTORIES} ${dapcrypt_INCLUDE_DIRS}")
+include_directories("${INCLUDE_DIRECTORIES} ${dapcore_INCLUDE_DIRS}")
+include_directories("${INCLUDE_DIRECTORIES} ${daphttp_INCLUDE_DIRS}")
+include_directories("${INCLUDE_DIRECTORIES} ${dapclient_INCLUDE_DIRS}")
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt
new file mode 100644
index 0000000000..ed60b07fa1
--- /dev/null
+++ b/client/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8)
+project (dapclient)
+  
+set(CLIENT_SRCS dap_client_remote.c dap_client.c)
+ 
+add_library(${PROJECT_NAME} STATIC ${CORE_SRCS})
+
+set(${PROJECT_NAME}_DEFINITIONS CACHE INTERNAL "${PROJECT_NAME}: Definitions" FORCE)
+
+set(${PROJECT_NAME}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR} CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)
diff --git a/client/dap_client.c b/client/dap_client.c
new file mode 100644
index 0000000000..62dc62e0aa
--- /dev/null
+++ b/client/dap_client.c
@@ -0,0 +1,167 @@
+#include "common.h"
+
+#include "sap_client.h"
+#include "sap_client_internal.h"
+
+#define LOG_TAG "sap_client"
+
+/**
+ * @brief sap_client_init
+ * @return
+ */
+int sap_client_init()
+{
+    log_it(L_INFO, "Init SAP client module");
+    return 0;
+}
+
+/**
+ * @brief sap_client_deinit
+ */
+void sap_client_deinit()
+{
+    log_it(L_INFO, "Deinit SAP client module");
+}
+
+/**
+ * @brief sap_client_new
+ * @param a_stage_status_callback
+ * @return
+ */
+sap_client_t * sap_client_new(sap_client_callback_t a_stage_status_callback)
+{
+
+}
+
+/**
+ * @brief sap_client_delete
+ * @param a_client
+ */
+void sap_client_delete(sap_client_t * a_client)
+{
+
+}
+
+/**
+ * @brief sap_client_go_stage
+ * @param a_client
+ * @param a_stage_end
+ */
+void sap_client_go_stage(sap_client_t * a_client, sap_client_stage_t a_stage_end, sap_client_callback_t a_stage_end_callback)
+{
+
+}
+
+/**
+ * @brief sap_client_session_request
+ * @param a_client
+ * @param a_path
+ * @param a_request
+ * @param a_request_size
+ * @param a_response_proc
+ */
+void sap_client_session_request(sap_client_t * a_client, const char * a_path, void * a_request, size_t a_request_size,
+                                sap_client_callback_t a_response_proc)
+{
+
+}
+
+/**
+ * @brief sap_client_set_uplink
+ * @param a_client
+ * @param a_addr
+ * @param a_port
+ */
+void sap_client_set_uplink(sap_client_t * a_client,const char* a_addr, uint16_t a_port)
+{
+
+}
+
+/**
+ * @brief sap_client_set_credentials
+ * @param a_client
+ * @param a_user
+ * @param a_password
+ */
+void sap_client_set_credentials(sap_client_t * a_client,const char* a_user, const char * a_password)
+{
+
+}
+
+
+/**
+ * @brief sap_client_error_str
+ * @param a_client_error
+ * @return
+ */
+const char * sap_client_error_str(sap_client_error_t a_client_error)
+{
+    switch(a_client_error){
+        case SAP_CLIENT_ERROR_ENC_NO_KEY: return "ENC_NO_KEY";
+        case SAP_CLIENT_ERROR_ENC_WRONG_KEY: return "ENC_WRONG_KEY";
+        case SAP_CLIENT_ERROR_AUTH_WRONG_COOKIE: return "AUTH_WRONG_COOKIE";
+        case SAP_CLIENT_ERROR_AUTH_WRONG_CREDENTIALS: return "AUTH_WRONG_CREDENTIALS";
+        case SAP_CLIENT_ERROR_NETWORK_CONNECTION_TIMEOUT: return "NETWORK_CONNECTION_TIMEOUT";
+        case SAP_CLIENT_ERROR_NETWORK_CONNECTION_REFUSE: return "NETWORK_CONNECTION_REFUSE";
+        case SAP_CLIENT_ERROR_NETWORK_DISCONNECTED: return "NETWORK_DISCONNECTED";
+        case SAP_CLIENT_ERROR_STREAM_RESPONSE_WRONG: return "STREAM_RESPONSE_WRONG";
+        case SAP_CLIENT_ERROR_STREAM_RESPONSE_TIMEOUT: return "STREAM_RESPONSE_TIMEOUT";
+        case SAP_CLIENT_ERROR_STREAM_FREEZED: return "STREAM_FREEZED";
+        case SAP_CLIENT_ERROR_LICENSE: return "LICENSE_ERROR";
+        default : return "UNDEFINED";
+    }
+}
+
+/**
+ * @brief sap_client_get_stage
+ * @param a_client
+ * @return
+ */
+sap_client_stage_t sap_client_get_stage(sap_client_t * a_client)
+{
+    return SAP_CLIENT_INTERNAL(a_client)->stage;
+}
+
+/**
+ * @brief sap_client_get_stage_status_str
+ * @param a_client
+ * @return
+ */
+const char * sap_client_get_stage_status_str(sap_client_t *a_client)
+{
+    switch(SAP_CLIENT_INTERNAL(a_client)->stage_status){
+        case SAP_CLIENT_STAGE_STATUS_NONE: return "NONE";
+        case SAP_CLIENT_STAGE_STATUS_IN_PROGRESS: return "IN_PROGRESS";
+        case SAP_CLIENT_STAGE_STATUS_ERROR: return "ERROR";
+        case SAP_CLIENT_STAGE_STATUS_DONE: return "DONE";
+        default: return "UNDEFINED";
+    }
+}
+
+/**
+ * @brief sap_client_get_stage_str
+ * @param a_client
+ * @return
+ */
+const char * sap_client_get_stage_str(sap_client_t * a_client)
+{
+    switch(SAP_CLIENT_INTERNAL(a_client)->stage){
+        case SAP_CLIENT_STAGE_BEGIN: return "BEGIN";
+        case SAP_CLIENT_STAGE_ENC: return "ENC";
+        case SAP_CLIENT_STAGE_AUTH: return "AUTH";
+        case SAP_CLIENT_STAGE_STREAM_CTL: return "STREAM_CTL";
+        case SAP_CLIENT_STAGE_STREAM: return "STREAM";
+        case SAP_CLIENT_STAGE_NETCONF: return "NETCONF";
+        case SAP_CLIENT_STAGE_TUNNEL: return "TUNNEL";
+        default: return "UNDEFINED";
+    }
+}
+/**
+ * @brief sap_client_get_stage_status
+ * @param a_client
+ * @return
+ */
+sap_client_stage_status_t sap_client_get_stage_status(sap_client_t * a_client)
+{
+    return SAP_CLIENT_INTERNAL(a_client)->stage_status;
+}
diff --git a/client/dap_client.h b/client/dap_client.h
new file mode 100644
index 0000000000..a09cbadeee
--- /dev/null
+++ b/client/dap_client.h
@@ -0,0 +1,69 @@
+#ifndef _SAP_CLIENT_H_
+#define _SAP_CLIENT_H_
+#include <stdint.h>
+
+
+/**
+ * @brief The dap_client_stage enum. Top level of client's state machine
+ **/
+typedef enum dap_client_stage {
+    DAP_CLIENT_STAGE_BEGIN=0,
+    DAP_CLIENT_STAGE_ENC=1,
+    DAP_CLIENT_STAGE_AUTH=2,
+} 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_ERROR,
+    DAP_CLIENT_STAGE_STATUS_DONE,
+} dap_client_stage_status_t;
+
+typedef enum dap_client_error {
+    DAP_CLIENT_ERROR_UNDEFINED = 0,
+    DAP_CLIENT_ERROR_ENC_NO_KEY,
+    DAP_CLIENT_ERROR_ENC_WRONG_KEY,
+    DAP_CLIENT_ERROR_NETWORK_CONNECTION_TIMEOUT,
+    DAP_CLIENT_ERROR_NETWORK_CONNECTION_REFUSE,
+    DAP_CLIENT_ERROR_NETWORK_DISCONNECTED,
+} dap_client_error_t;
+
+
+/**
+ * @brief The dap_client struct
+ */
+typedef struct sap_client{
+    void * _internal;
+    void * _inheritor;
+} dap_client_t;
+
+typedef void (*dap_client_callback_t) (dap_client_t *, void*);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int dap_client_init();
+void dap_client_deinit();
+
+dap_client_t * dap_client_new(dap_client_callback_t a_stage_status_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_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);
+
+const char * dap_client_get_stage_str(dap_client_t * a_client);
+const char * dap_client_get_stage_status_str(dap_client_t * a_client);
+const char * dap_client_error_str(dap_client_error_t a_client_error);
+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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/client/dap_client_remote.c b/client/dap_client_remote.c
new file mode 100644
index 0000000000..d2f9d4aefa
--- /dev/null
+++ b/client/dap_client_remote.c
@@ -0,0 +1,249 @@
+/*
+ Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc
+  All rights reserved.
+
+ This file is part of DAP (Deus Applications Prototypes) the open source project
+
+    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DAP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <sys/epoll.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include "common.h"
+#include "dap_server.h"
+#include "dap_client.h"
+#include <ev.h>
+#define LOG_TAG "client"
+
+
+/**
+ * @brief dap_client_init Init clients module
+ * @return Zero if ok others if no
+ */
+int dap_client_init()
+{
+    log_it(NOTICE,"Initialized socket client module");
+    return 0;
+}
+
+/**
+ * @brief dap_client_deinit Deinit clients module
+ */
+void dap_client_deinit()
+{
+
+}
+
+/**
+ * @brief safe_client_create Create new client and add it to the list
+ * @param sh Server instance
+ * @param s Client's socket
+ * @return Pointer to the new list's node
+ */
+dap_client_t * dap_client_create(dap_server_t * sh, int s, ev_io* w_client)
+{
+    pthread_mutex_lock(&sh->mutex_on_hash);
+    log_it(DEBUG,"Client structure create");
+
+    dap_client_t * ret=(dap_client_t *) calloc(1,sizeof(dap_client_t));
+    ret->socket=s;
+    ret->server=sh;
+    ret->watcher_client = w_client;
+    ret->_ready_to_read=true;
+
+    HASH_ADD_INT( sh->clients, socket, ret);
+
+    if(sh->client_new_callback)
+        sh->client_new_callback(ret,NULL); // Init internal structure
+
+    pthread_mutex_unlock(&sh->mutex_on_hash);
+    return ret;
+}
+
+/**
+ * @brief dap_client_find
+ * @param sock
+ * @param sh
+ * @return
+ */
+dap_client_t * dap_client_find(int sock, struct dap_server * sh)
+{
+    pthread_mutex_lock(&sh->mutex_on_hash);
+    dap_client_t * ret=NULL;
+    HASH_FIND_INT(sh->clients,&sock,ret);
+    pthread_mutex_unlock(&sh->mutex_on_hash);
+    return ret;
+}
+
+/**
+ * @brief dap_client_ready_to_read
+ * @param sc
+ * @param isReady
+ */
+void dap_client_ready_to_read(dap_client_t * sc,bool is_ready)
+{
+    if(is_ready != sc->_ready_to_read) {
+
+        uint32_t events = 0;
+        sc->_ready_to_read=is_ready;
+
+        if(sc->_ready_to_read)
+            events |= EV_READ;
+
+        if(sc->_ready_to_write)
+            events |= EV_WRITE;
+
+        ev_io_set(sc->watcher_client, sc->socket, events );
+    }
+}
+
+/**
+ * @brief dap_client_ready_to_write
+ * @param sc
+ * @param isReady
+ */
+void dap_client_ready_to_write(dap_client_t * sc,bool is_ready)
+{
+    if(is_ready != sc->_ready_to_write) {
+
+        uint32_t events = 0;
+        sc->_ready_to_write=is_ready;
+
+        if(sc->_ready_to_read)
+            events |= EV_READ;
+
+        if(sc->_ready_to_write)
+            events |= EV_WRITE;
+
+        ev_io_set(sc->watcher_client, sc->socket, events );
+    }
+
+}
+
+
+/**
+ * @brief safe_client_remove Removes the client from the list
+ * @param sc Client instance
+ */
+void dap_client_remove(dap_client_t *sc, struct dap_server * sh)
+{
+    pthread_mutex_lock(&sh->mutex_on_hash);
+
+    log_it(DEBUG, "Client structure remove");
+    HASH_DEL(sc->server->clients,sc);
+
+    if(sc->server->client_delete_callback)
+        sc->server->client_delete_callback(sc,NULL); // Init internal structure
+    if(sc->internal)
+        free(sc->internal);
+
+    if(sc->socket)
+        close(sc->socket);
+    free(sc);
+    pthread_mutex_unlock(&sh->mutex_on_hash);
+}
+
+/**
+ * @brief dap_client_write Write data to the client
+ * @param sc Client instance
+ * @param data Pointer to data
+ * @param data_size Size of data to write
+ * @return Number of bytes that were placed into the buffer
+ */
+size_t dap_client_write(dap_client_t *sc, const void * data, size_t data_size)
+{
+     data_size = ((sc->buf_out_size+data_size)<(sizeof(sc->buf_out)))?data_size:(sizeof(sc->buf_out)-sc->buf_out_size );
+     memcpy(sc->buf_out+sc->buf_out_size,data,data_size);
+     sc->buf_out_size+=data_size;
+     return data_size;
+}
+
+/**
+ * @brief dap_client_write_f Write formatted text to the client
+ * @param sc Client instance
+ * @param format Format
+ * @return Number of bytes that were placed into the buffer
+ */
+size_t dap_client_write_f(dap_client_t *sc, const char * format,...)
+{
+    size_t max_data_size = sizeof(sc->buf_out)-sc->buf_out_size;
+    va_list ap;
+    va_start(ap,format);
+    int ret=vsnprintf(sc->buf_out+sc->buf_out_size,max_data_size,format,ap);
+    va_end(ap);
+    if(ret>0){
+        sc->buf_out_size+=ret;
+        return ret;
+    }else{
+        log_it(ERROR,"Can't write out formatted data '%s'",format);
+        return 0;
+    }
+}
+
+/**
+ * @brief dap_client_read Read data from input buffer
+ * @param sc Client instasnce
+ * @param data Pointer to memory where to store the data
+ * @param data_size Size of data to read
+ * @return Actual bytes number that were read
+ */
+size_t dap_client_read(dap_client_t *sc, void * data, size_t data_size)
+{
+	
+	printf("Size of package: %d\n", (int)data_size);
+	// дамп пакета
+	hexdump(data, data_size);
+
+    if (data_size < sc->buf_in_size) {
+        memcpy(data, sc->buf_in, data_size);
+        memmove(data, sc->buf_in + data_size, sc->buf_in_size - data_size);
+    } else {
+        if (data_size > sc->buf_in_size) {
+            data_size = sc->buf_in_size;
+        }
+        memcpy(data, sc->buf_in, data_size);
+    }
+    sc->buf_in_size -= data_size;
+    return data_size;
+}
+
+
+/**
+ * @brief shrink_client_buf_in Shrink input buffer (shift it left)
+ * @param cl Client instance
+ * @param shrink_size Size on wich we shrink the buffer with shifting it left
+ */
+void dap_client_shrink_buf_in(dap_client_t * cl, size_t shrink_size)
+{
+    if((shrink_size==0)||(cl->buf_in_size==0) ){
+        //log_it(WARNING, "DBG_#003");
+        return;
+    }else if(cl->buf_in_size>shrink_size){
+        size_t buf_size=cl->buf_in_size-shrink_size;
+        void * buf = malloc(buf_size);
+        memcpy(buf,cl->buf_in+ shrink_size,buf_size );
+        memcpy(cl->buf_in,buf,buf_size);
+        cl->buf_in_size=buf_size;
+        //log_it(WARNING, "DBG_#004");
+        free(buf);
+    }else {
+        //log_it(WARNING, "DBG_#005");
+        cl->buf_in_size=0;
+    }
+
+}
diff --git a/client/dap_client_remote.h b/client/dap_client_remote.h
new file mode 100644
index 0000000000..1868b4ddb2
--- /dev/null
+++ b/client/dap_client_remote.h
@@ -0,0 +1,86 @@
+/*
+ Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc
+  All rights reserved.
+
+ This file is part of DAP (Deus Applications Prototypes) the open source project
+
+    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DAP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _DAP_CLIENT_H
+#define _DAP_CLIENT_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include "uthash.h"
+#include <ev.h>
+
+
+struct dap_server;
+struct dap_client;
+
+typedef void (*dap_client_callback_t) (struct dap_client *,void * arg); // Callback for specific client operations
+
+#define DAP_CLIENT_BUF 100000
+
+typedef struct dap_client{
+    int socket;
+    bool signal_close;
+
+    bool _ready_to_write;
+    bool _ready_to_read;
+
+    uint32_t buf_out_zero_count;
+    char buf_in[DAP_CLIENT_BUF+1]; // Internal buffer for input data
+    size_t buf_in_size; // size of data that is in the input buffer
+
+    char buf_out[DAP_CLIENT_BUF+1]; // Internal buffer for output data
+
+    char hostaddr[1024]; // Address
+    char service[128];
+
+    size_t buf_out_size; // size of data that is in the output buffer
+
+    ev_io* watcher_client;
+
+    struct dap_server * server;
+
+    UT_hash_handle hh;
+
+    void * internal; // Internal data to specific client type, usualy states for state machine
+} dap_client_t; // Node of bidirectional list of clients
+
+
+
+extern int dap_client_init(); //  Init clients module
+extern void dap_client_deinit(); // Deinit clients module
+
+extern dap_client_t * dap_client_create(struct dap_server * sh, int s, ev_io* w_client); // Create new client and add it to the list
+extern dap_client_t * dap_client_find(int sock, struct dap_server * sh); // Find client by socket
+
+extern bool dap_client_is_ready_to_read(dap_client_t * sc);
+extern bool dap_client_is_ready_to_write(dap_client_t * sc);
+extern void dap_client_ready_to_read(dap_client_t * sc,bool is_ready);
+extern void dap_client_ready_to_write(dap_client_t * sc,bool is_ready);
+
+extern size_t dap_client_write(dap_client_t *sc, const void * data, size_t data_size);
+extern size_t dap_client_write_f(dap_client_t *sc, const char * format,...);
+extern size_t dap_client_read(dap_client_t *sc, void * data, size_t data_size);
+
+extern void dap_client_remove(dap_client_t *sc, struct dap_server * sh); // Removes the client from the list
+
+extern void dap_client_shrink_buf_in(dap_client_t * cl, size_t shrink_size);
+
+#endif
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
index 3678a54122..b4ce806776 100644
--- a/core/CMakeLists.txt
+++ b/core/CMakeLists.txt
@@ -1,7 +1,7 @@
 cmake_minimum_required(VERSION 2.8)
 project (dapcore)
   
-set(CORE_SRCS common.c config.c dap_client.c dap_server.c)
+set(CORE_SRCS common.c dap_client_remote.c)
  
 add_library(${PROJECT_NAME} STATIC ${CORE_SRCS})
 
-- 
GitLab