diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 2120d03f2c277454dfa33241eb15bc6272c0e1ce..c8a3bee84e4c9bacfd258793ba0f12240777ad7c 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 9349956e8dbee1bbc935df6921768db02a73cc2d..a7aa519560ae6854fc4b77ff489b4880e1314a74 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 1d706c3fbf318b3c04a8abf43aacf57034ff8e16..cab39b1d8caa3d2661a11e49906e45267c262389 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 e31965d831370996d1e56a291a587abd325a5b38..3121f559193d7ae328fa71f2e9e4e60f35e649d2 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 6b5b9aba0519ef5f8932fea9287750b8981b9c97..6cea070ab1de3e4f6a14c550d641766883b98c58 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 8f6a9ad4d7761c99a4ac2aebc39c2f72010fd78c..3dab918ae5c0e376794831a11beb1ff21afe5793 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 cce8b58cd58fb7b93523ec11f719602ac531bd69..f4750ccad508abee1e15f07937ae5c1d766d7388 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 caf4e162e283b4e6d6a47ad5e081852317899866..247ce38b74a0bf8894fbbc8d74ce6d8099d2e2bc 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 0000000000000000000000000000000000000000..534d7c25845da9bf57d160bdd214faa8322ca85a --- /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 0000000000000000000000000000000000000000..0711b6de42e6523d3d3faba09f6b09d34a4bd3ff --- /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