From b5a937bad68eea51e0741dfd3275fe10cc2d02bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B4=94=E4=B8=80=E9=B8=A3?= Date: Fri, 7 Sep 2018 17:42:57 +0800 Subject: [PATCH] fix memory leak bugs --- common/CMakeLists.txt | 5 +- common/include/tfe_rpc.h | 27 ++ common/src/tfe_future.cpp | 10 +- common/src/tfe_rpc.cpp | 242 +++++++++++++++ platform/CMakeLists.txt | 9 +- platform/include/internal/tfe_rpc.h | 35 --- platform/src/key_keeper.cpp | 450 +++++++++++++++++----------- platform/src/tfe_rpc.cpp | 258 ---------------- platform/test/test_key_keeper.cpp | 47 ++- platform/test/test_tfe_rpc.cpp | 227 +++++++++++++- 10 files changed, 804 insertions(+), 506 deletions(-) create mode 100644 common/include/tfe_rpc.h create mode 100644 common/src/tfe_rpc.cpp delete mode 100644 platform/include/internal/tfe_rpc.h delete mode 100644 platform/src/tfe_rpc.cpp diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 7dda4cb..d4e447d 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -1,4 +1,3 @@ - -add_library(common src/tfe_stat.cpp src/tfe_utils.cpp src/tfe_future.cpp src/tfe_http.cpp src/tfe_plugin.cpp) +add_library(common src/tfe_stat.cpp src/tfe_utils.cpp src/tfe_future.cpp src/tfe_http.cpp src/tfe_plugin.cpp src/tfe_rpc.cpp) target_include_directories(common PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) -target_link_libraries(common MESA_handle_logger) +target_link_libraries(common MESA_handle_logger libevent-static libevent-static-openssl libevent-static-pthreads) diff --git a/common/include/tfe_rpc.h b/common/include/tfe_rpc.h new file mode 100644 index 0000000..1c7de0d --- /dev/null +++ b/common/include/tfe_rpc.h @@ -0,0 +1,27 @@ +#pragma once +#include "tfe_future.h" +#include "event2/event.h" + +struct tfe_rpc_response_result{ + int status_code; + const char* status_msg; + char* data; + int len; +}; + +enum TFE_RPC_FLAG +{ + CHUNK_CB = 0, + DONE_CB, +}; + +enum TFE_RPC_METHOD +{ + GET = 0, + POST, +}; + + +struct tfe_rpc_response_result* tfe_rpc_release(void* result); + +void tfe_rpc_async_ask(struct future* f, const char* url, enum TFE_RPC_METHOD method, enum TFE_RPC_FLAG flag, const char* data, int data_len, struct event_base * evbase); diff --git a/common/src/tfe_future.cpp b/common/src/tfe_future.cpp index 1a15624..f89e6a5 100644 --- a/common/src/tfe_future.cpp +++ b/common/src/tfe_future.cpp @@ -25,7 +25,7 @@ struct _future_promise_debug int fsid_latency; int fsid_failed; long long succ_times; - struct timespec create_time; + struct timespec create_time; }; struct future { @@ -52,7 +52,7 @@ void future_promise_library_init(void) { return; } - + int value=0; memset(&g_FP_instance,0,sizeof(g_FP_instance)); MESA_htable_handle htable = MESA_htable_born(); @@ -90,7 +90,7 @@ void future_promise_library_init(void) } struct promise * future_to_promise(struct future * f) -{ +{ return (struct promise *) f; } struct field_get_set_args @@ -116,7 +116,7 @@ static long field_get_set_cb(void * data, const uchar * key, uint size, void * u field_id[1]=FS_register(args->fs_handle, FS_STYLE_FIELD, FS_CALC_SPEED,buff); args->fsid_failed=field_id[1]; ret = MESA_htable_add(args->htable, key, size, (void*)field_id); - assert(ret>=0); + assert(ret>=0); } else { @@ -134,7 +134,7 @@ struct future * future_create(const char* symbol, future_success_cb * cb_success p->f.cb_success = cb_success; p->f.cb_failed = cb_failed; strncpy(p->f.symbol,symbol,sizeof(p->f.symbol)); - + clock_gettime(CLOCK_MONOTONIC,&p->debug.create_time); long cb_ret=0; struct field_get_set_args args={.htable = g_FP_instance.name_table, .fs_handle = g_FP_instance.fs_handle}; diff --git a/common/src/tfe_rpc.cpp b/common/src/tfe_rpc.cpp new file mode 100644 index 0000000..d49da9a --- /dev/null +++ b/common/src/tfe_rpc.cpp @@ -0,0 +1,242 @@ +#include "tfe_rpc.h" +#include "event2/http.h" +#include "event2/http_struct.h" +#include "event2/event.h" +#include "event2/buffer.h" +#include "event2/dns.h" +#include "event2/thread.h" +#include "tfe_utils.h" +#include "MESA/MESA_handle_logger.h" +#include +#include +#include +#include +#include + +#define MODULE_NAME "tfe_rpc" + + +struct tfe_rpc_ctx +{ + struct event_base * evbase; + enum TFE_RPC_FLAG flag; +}; + +/* +//will be called after receiving and parsing the full header. It allows analyzing the header and possibly closing the connection by returning a value < 0. +int read_header_done_cb(struct evhttp_request* response, void* arg) +{ + //struct promise* p = (struct promise*)arg; + printf("call read_header_done_cb!\n"); + printf("< HTTP/1.1 %d %s\n", evhttp_request_get_response_code(response), evhttp_request_get_response_code_line(response)); + return 0; + struct evkeyvalq* headers = evhttp_request_get_input_headers(response); + struct evkeyval* header; + TAILQ_FOREACH(header, headers, next){ + MESA_handle_runtime_log(logger, RLOG_LV_INFO, MODULE_NAME, "< %s: %s\n", header->key, header->value); + } + MESA_handle_runtime_log(logger, RLOG_LV_INFO, MODULE_NAME, "< \n"); +} +*/ + +static void tfe_rpc_promise_free_ctx(void* ctx) +{ + free(ctx); + ctx = NULL; + return; +} + +static void _wrapped_promise_success(struct promise* p, void* result) +{ + struct tfe_rpc_ctx* ctx = (struct tfe_rpc_ctx*)promise_get_ctx(p); + struct tfe_rpc_response_result* _result = (struct tfe_rpc_response_result*)result; + if(ctx->flag == CHUNK_CB && _result->len > 0) + { + return; + } + if(ctx->evbase) + { + event_base_loopexit(ctx->evbase, 0); + } + //promise_dettach_ctx(p); + //tfe_rpc_promise_free_ctx(ctx); + promise_success(p, result); + return; +} + +static void _wrapped_promise_failed(struct promise * p, enum e_future_error error, const char * what) +{ + struct tfe_rpc_ctx* ctx = (struct tfe_rpc_ctx*)promise_get_ctx(p); + if(ctx->evbase) + { + event_base_loopexit(ctx->evbase, 0); + } + promise_failed(p, error, what); + //promise_dettach_ctx(p); + //ctx_destroy_cb(ctx); + return; +} + + +//will be called after every read of data with the same argument as the completion callback. Will never be called on an empty response. May drain the input buffer; it will be drained automatically on return. +//will drain automaticly +void read_chunk_cb(struct evhttp_request* response, void* arg) +{ + struct promise* p = (struct promise*)arg; + //printf("call get_chunk_cb\n"); + if(response == NULL) + { + return; + } + struct evbuffer* evbuf = evhttp_request_get_input_buffer(response); + if(evbuf == NULL) + { + return; + } + int evbuf_len = evbuffer_get_length(evbuf); + char* data = (char*)evbuffer_pullup(evbuf, evbuf_len); + //printf("data is %s\n", data==NULL ? "NULL":"NOT NULL"); + struct tfe_rpc_response_result* result = ALLOC(struct tfe_rpc_response_result, 1); + result->status_code = evhttp_request_get_response_code(response); + result->status_msg = evhttp_request_get_response_code_line(response); + result->data = data; + result->len = evbuf_len; + _wrapped_promise_success(p, result); + free(result); +} + +//The callback is executed when the request completed or an error occurred +void get_response_cb(struct evhttp_request* response, void* arg) +{ + //printf("call get_response_cb\n"); + read_chunk_cb(response, arg); +} + + +//On error, both the error callback and the regular callback will be called, error callback is called before the regular callback. +void request_error_cb(enum evhttp_request_error error, void* arg) +{ + //printf("call request_error_cb\n"); + struct promise* p = (struct promise*)arg; + switch(error) + { + case EVREQ_HTTP_TIMEOUT: + _wrapped_promise_failed(p, FUTURE_ERROR_TIMEOUT, "EVREQ_HTTP_TIMEOUT"); + break; + case EVREQ_HTTP_EOF: + _wrapped_promise_failed(p, FUTURE_ERROR_EXCEPTION, "EVREQ_HTTP_EOF"); + break; + case EVREQ_HTTP_INVALID_HEADER: + _wrapped_promise_failed(p, FUTURE_ERROR_EXCEPTION, "EVREQ_HTTP_INVALID_HEADER"); + break; + case EVREQ_HTTP_BUFFER_ERROR: + _wrapped_promise_failed(p, FUTURE_ERROR_EXCEPTION, "EVREQ_HTTP_BUFFER_ERROR"); + break; + case EVREQ_HTTP_REQUEST_CANCEL: + _wrapped_promise_failed(p, FUTURE_ERROR_CANCEL, "EVREQ_HTTP_REQUEST_CANCEL"); + break; + case EVREQ_HTTP_DATA_TOO_LONG: + _wrapped_promise_failed(p, FUTURE_ERROR_EXCEPTION, "EVREQ_HTTP_DATA_TOO_LONG"); + break; + default: + _wrapped_promise_failed(p, FUTURE_ERROR_EXCEPTION, "EVREQ_HTTP_UNKOWN_EXCEPTION"); + break; + } +} + +//when to close a connection ??? +//Set a callback for connection close +void connection_close_cb(struct evhttp_connection* connection, void* arg) +{ + //printf("call connection_close_cb\n"); +} + +//data is for POST. if method is GET, data should be NULL +void tfe_rpc_async_ask(struct future* f, const char* url, enum TFE_RPC_METHOD method, enum TFE_RPC_FLAG flag, const char* data, int data_len, struct event_base * evbase) +{ + struct promise* p = future_to_promise(f); + struct tfe_rpc_ctx* ctx = ALLOC(struct tfe_rpc_ctx, 1); + ctx->evbase = evbase; + ctx->flag = flag; + promise_set_ctx(p, (void*)ctx, tfe_rpc_promise_free_ctx); + if(!evbase) + { + _wrapped_promise_failed(p, FUTURE_ERROR_EXCEPTION, "event base is NULL"); + return; + } + struct evhttp_uri* uri = evhttp_uri_parse(url); + if(NULL == uri) + { + _wrapped_promise_failed(p, FUTURE_ERROR_EXCEPTION, "parse url failed!"); + return; + } + const char* host = evhttp_uri_get_host(uri); + if(!host) + { + _wrapped_promise_failed(p, FUTURE_ERROR_EXCEPTION, "parse host failed!"); + return; + } + int port = evhttp_uri_get_port(uri); + if(port < 0) + { + port = 80; + } + const char* path = evhttp_uri_get_path(uri); + const char* query = evhttp_uri_get_query(uri); + char request_url[TFE_STRING_MAX] = ""; + if(path == NULL || strnlen(path, TFE_STRING_MAX) == 0) + { + snprintf(request_url, TFE_STRING_MAX, "/"); + } + else + { + snprintf(request_url, TFE_STRING_MAX, "%s", path); + } + if(query && strnlen(query, TFE_STRING_MAX)) + { + strncat(request_url, "?", TFE_STRING_MAX); + strncat(request_url, query, TFE_STRING_MAX); + } + //printf("url:%s host:%s port:%d path:%s query:%s request_url:%s\n", url, host, port, path, query, request_url); + struct evdns_base* dnsbase = evdns_base_new(evbase, EVDNS_BASE_INITIALIZE_NAMESERVERS); + if (!dnsbase) + { + _wrapped_promise_failed(p, FUTURE_ERROR_EXCEPTION, "create dns base failed!"); + return; + } + struct evhttp_connection* connection = evhttp_connection_base_new(evbase, dnsbase, host, port); + if (!connection) + { + _wrapped_promise_failed(p, FUTURE_ERROR_EXCEPTION, "create connection failed!"); + return; + } + evhttp_connection_set_closecb(connection, connection_close_cb, evbase); + struct evhttp_request* request = evhttp_request_new(get_response_cb, (void*)p); + //evhttp_request_set_header_cb(request, read_header_done_cb); + if(flag == CHUNK_CB) + { + evhttp_request_set_chunked_cb(request, read_chunk_cb); + } + evhttp_request_set_error_cb(request, request_error_cb); + evhttp_add_header(evhttp_request_get_output_headers(request), "Host", host); + switch(method) + { + case GET: + evhttp_make_request(connection, request, EVHTTP_REQ_GET, request_url); + break; + case POST: + evbuffer_add(request->output_buffer, data, data_len); + evhttp_make_request(connection, request, EVHTTP_REQ_POST, request_url); + break; + default: + _wrapped_promise_failed(p, FUTURE_ERROR_EXCEPTION, "method is invalid!"); + return; + } +} + +struct tfe_rpc_response_result* tfe_rpc_release(void* result) +{ + struct tfe_rpc_response_result* response = (struct tfe_rpc_response_result*)result; + return response; +} + diff --git a/platform/CMakeLists.txt b/platform/CMakeLists.txt index 49e5919..b98b893 100644 --- a/platform/CMakeLists.txt +++ b/platform/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable(tfe src/key_keeper.cpp src/tfe_rpc.cpp src/kni_acceptor.cpp src/ssl_stream.cpp src/ssl_sess_cache.cpp src/ssl_utils.cc src/tcp_stream.cpp src/main.cpp src/proxy.cpp) +add_executable(tfe src/key_keeper.cpp src/kni_acceptor.cpp src/ssl_stream.cpp src/ssl_sess_cache.cpp src/ssl_utils.cc src/tcp_stream.cpp src/main.cpp src/proxy.cpp) target_include_directories(tfe PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include/external) target_include_directories(tfe PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include/internal) @@ -12,6 +12,7 @@ target_link_libraries(tfe pthread dl libevent-static-pthreads MESA_handle_logger MESA_prof_load + cjson MESA_htable wiredcfg MESA_field_stat) @@ -20,7 +21,7 @@ target_link_libraries(tfe -Wl,--whole-archive http -Wl,--no-whole-archive) install(TARGETS tfe RUNTIME DESTINATION ./) ### test_key_keeper -add_executable(test_key_keeper test/test_key_keeper.cpp src/key_keeper.cpp src/tfe_rpc.cpp src/ssl_stream.cpp src/ssl_sess_cache.cpp src/ssl_utils.cc src/tcp_stream.cpp) +add_executable(test_key_keeper test/test_key_keeper.cpp src/key_keeper.cpp src/ssl_sess_cache.cpp src/ssl_utils.cc ) target_include_directories(test_key_keeper PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include/internal) @@ -33,13 +34,14 @@ target_link_libraries(test_key_keeper pthread dl libevent-static-pthreads MESA_handle_logger MESA_prof_load + cjson MESA_htable wiredcfg MESA_field_stat) install(TARGETS test_key_keeper RUNTIME DESTINATION ./) ### test_tfe_rpc -add_executable(test_tfe_rpc test/test_tfe_rpc.cpp src/key_keeper.cpp src/tfe_rpc.cpp src/ssl_stream.cpp src/ssl_sess_cache.cpp src/ssl_utils.cc src/tcp_stream.cpp) +add_executable(test_tfe_rpc test/test_tfe_rpc.cpp src/key_keeper.cpp src/ssl_sess_cache.cpp src/ssl_utils.cc) target_include_directories(test_tfe_rpc PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include/internal) @@ -53,6 +55,7 @@ target_link_libraries(test_tfe_rpc pthread dl MESA_handle_logger MESA_prof_load MESA_htable wiredcfg + cjson MESA_field_stat) install(TARGETS test_tfe_rpc RUNTIME DESTINATION ./) diff --git a/platform/include/internal/tfe_rpc.h b/platform/include/internal/tfe_rpc.h deleted file mode 100644 index d009d63..0000000 --- a/platform/include/internal/tfe_rpc.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once -#include "tfe_future.h" -#include "event2/event.h" - -struct tfe_rpc_response_result{ - int status_code; - const char* status_msg; - const char* data; - int len; -}; - -enum TFE_RPC_FLAG -{ - CHUNK_CB = 0, - DONE_CB, -}; - -enum TFE_RPC_METHOD -{ - GET = 0, - POST, -}; - -struct tfe_rpc -{ - void* logger; -}; - -struct tfe_rpc* tfe_rpc_init(const char * profile, const char* section, void* logger); - -struct tfe_rpc* tfe_rpc_destroy(struct tfe_rpc *rpc); - -struct tfe_rpc_response_result* tfe_rpc_release(void* result); - -void tfe_rpc_async_ask(struct future* f, struct tfe_rpc* rpc, const char* url, int method, int flag, const char* data, int data_len, struct event_base * evbase); diff --git a/platform/src/key_keeper.cpp b/platform/src/key_keeper.cpp index 15a830e..aa163fd 100644 --- a/platform/src/key_keeper.cpp +++ b/platform/src/key_keeper.cpp @@ -6,15 +6,20 @@ #include "MESA/MESA_prof_load.h" #include "tfe_rpc.h" #include "event2/http.h" +#include "cjson/cJSON.h" #define HTABLE_MAX_KEY_LEN 256 #define KEYRING_EXSITED 0 #define KEYRING_NOT_EXSITED -1 struct key_keeper { - unsigned int mode; + char mode[TFE_STRING_MAX]; + char ca_path[TFE_STRING_MAX]; + char untrusted_ca_path[TFE_STRING_MAX]; char cert_store_host[TFE_STRING_MAX]; unsigned int cert_store_port; + unsigned int hash_slot_size; + unsigned int hash_expire_seconds; MESA_htable_handle htable; void* logger; }; @@ -35,11 +40,18 @@ struct key_keeper_promise_ctx { void* logger; MESA_htable_handle htable; - const uchar* key; + uchar* key; + struct future* f_certstore_rpc; unsigned int key_len; }; -static const uchar* get_key_by_cert(X509* cert, int keyring_id, unsigned int* len); +static void key_keeper_promise_free_ctx(void* ctx) +{ + struct key_keeper_promise_ctx* _ctx = (struct key_keeper_promise_ctx*)ctx; + free(_ctx->key); + _ctx->key = NULL; + free(_ctx); +} static struct keyring_private* keyring_new(void) { @@ -60,7 +72,7 @@ static struct keyring_private* keyring_new(void) * Passed OpenSSL objects are owned by cert_t; refcount will not be * incremented, stack will not be duplicated. */ -struct keyring* keyring_new3(EVP_PKEY *key, X509 *cert, STACK_OF(X509) *chain) +static struct keyring* keyring_new3(EVP_PKEY *key, X509 *cert, STACK_OF(X509) *chain) { struct keyring_private* kyr=NULL; kyr=keyring_new(); @@ -88,7 +100,7 @@ struct keyring* keyring_new3(EVP_PKEY *key, X509 *cert, STACK_OF(X509) *chain) } // Increment reference count. -void keyring_ref_inc(struct keyring_private* kyr) +static void keyring_ref_inc(struct keyring_private* kyr) { pthread_mutex_lock(&kyr->mutex); kyr->references++; @@ -183,9 +195,116 @@ void key_keeper_free_keyring(struct keyring *kyr) free(_kyr); } + +static X509* transform_cert_to_x509(const char* str) +{ + BIO *bio; + X509 *cert; + bio = BIO_new(BIO_s_mem()); + BIO_write(bio, (const void*)str, strnlen(str, TFE_STRING_MAX)); + cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); + BIO_free_all(bio); + return cert; +} + +static EVP_PKEY* transform_key_to_EVP(const char* str) +{ + BIO *mem; + mem = BIO_new_mem_buf(str, -1); + EVP_PKEY* key = PEM_read_bio_PrivateKey(mem, NULL, NULL, 0); + BIO_free(mem); + return key; +} + + +static void err_out(X509* cert, EVP_PKEY* key, STACK_OF(X509)* chain) +{ + if(cert) + { + X509_free(cert); + } + if(key) + { + EVP_PKEY_free(key); + } + if(chain) + { + sk_X509_pop_free(chain, X509_free); + } + return; +} + +static struct keyring* get_keyring_from_response(const char* data) +{ + X509* cert = NULL; + EVP_PKEY* key = NULL; + STACK_OF(X509)* chain = NULL; + if(data == NULL) + { + return NULL; + } + cJSON* data_json = cJSON_Parse(data); + if(data_json == NULL) + { + return NULL; + } + cJSON* cert_json = NULL; + cJSON* key_json = NULL; + cJSON* chain_json = NULL; + cert_json = cJSON_GetObjectItemCaseSensitive(data_json, "CERTIFICATE"); + key_json = cJSON_GetObjectItemCaseSensitive(data_json, "PRIVATE_KEY"); + chain_json = cJSON_GetObjectItemCaseSensitive(data_json, "CERTIFICATE_CHAIN"); + if (cert_json && cert_json->valuestring != NULL) + { + cert = transform_cert_to_x509(cert_json->valuestring); + } + if(cert == NULL) + { + err_out(cert, key, chain); + return NULL; + } + if (key_json && key_json->valuestring != NULL) + { + key = transform_key_to_EVP(key_json->valuestring); + } + if(key == NULL) + { + err_out(cert, key, chain); + return NULL; + } + if(chain_json == NULL) + { + err_out(cert, key, chain); + return NULL; + } + cJSON* chain_cert_json = NULL; + chain = sk_X509_new_null(); + cJSON_ArrayForEach(chain_cert_json, chain_json) + { + X509* chain_cert = NULL; + if (chain_cert_json && chain_cert_json->valuestring != NULL) + { + chain_cert = transform_cert_to_x509(chain_cert_json->valuestring); + } + if(chain_cert == NULL) + { + err_out(cert, key, chain); + return NULL; + } + sk_X509_push(chain, chain_cert); + } + struct keyring_private* _kyr= keyring_new(); + keyring_set_cert(_kyr, cert); + keyring_set_key(_kyr, key); + keyring_set_chain(_kyr, chain); + X509_free(cert); + EVP_PKEY_free(key); + sk_X509_pop_free(chain, X509_free); + return &(_kyr->head); +} + static long keyring_local_cache_query_cb(void * data, const uchar * key, uint size, void * user_arg) { - //data is (struct keyring*) struct keyring_private* kyr=(struct keyring_private*)data; if(kyr == NULL) { @@ -198,11 +317,8 @@ static long keyring_local_cache_query_cb(void * data, const uchar * key, uint si return KEYRING_EXSITED; } } -static void certstore_rpc_on_fail(enum e_future_error err, const char * what, void * user) -{ - struct promise * p = (struct promise *) user; - promise_failed(p, err, what); -} + + static struct keyring_private* generate_x509_keyring(X509* origin_cert, int keyring_id, const char* filename) { X509* ca = ssl_x509_load(filename); @@ -212,198 +328,64 @@ static struct keyring_private* generate_x509_keyring(X509* origin_cert, int keyr STACK_OF(X509)* chain = sk_X509_new_null(); sk_X509_push(chain, ca); sk_X509_push(chain, forge_cert); - struct keyring_private* ring= keyring_new(); - keyring_set_key(ring, forge_key); - keyring_set_cert(ring, forge_cert); - keyring_set_chain(ring, chain); - return ring; -} -//how to free -static X509* get_cert_from_response(const char* data, int len, void* logger) -{ - BIO *bio; - X509 *cert; - bio = BIO_new(BIO_s_mem()); - BIO_write(bio, (const void*)data, len); - cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); - return cert; -} - -static EVP_PKEY* get_key_from_response(const char* data, int len, void* logger) -{ - return NULL; -} - - -static STACK_OF(X509)* get_chain_from_response(const char* data, int len, void* logger) -{ - return NULL; + struct keyring_private* _kyr= keyring_new(); + keyring_set_key(_kyr, forge_key); + keyring_set_cert(_kyr, forge_cert); + keyring_set_chain(_kyr, chain); + X509_free(ca); + EVP_PKEY_free(cakey); + X509_free(forge_cert); + EVP_PKEY_free(forge_key); + sk_X509_pop_free(chain, X509_free); + return _kyr; } static void certstore_rpc_on_succ(void* result, void* user) { + //printf("call certstore_rpc_on_succ\n"); struct promise * p = (struct promise *) user; struct key_keeper_promise_ctx* ctx = (struct key_keeper_promise_ctx*)promise_get_ctx(p); MESA_htable_handle htable= ctx->htable; const uchar* key = ctx->key; unsigned int key_len = ctx->key_len; - //transform to x509 struct tfe_rpc_response_result* response = tfe_rpc_release(result); int status_code = response->status_code; const char* status_msg = response->status_msg; - const char* data = response->data; + char* data = response->data; int len = response->len; if(status_code == HTTP_OK) { - struct keyring_private* ring= keyring_new(); - X509* forge_cert = get_cert_from_response(data, len, NULL); - EVP_PKEY* forge_key = get_key_from_response(data, len, NULL); - STACK_OF(X509)* chain = get_chain_from_response(data, len, NULL); - keyring_set_key(ring, forge_key); - keyring_set_cert(ring, forge_cert); - keyring_set_chain(ring, chain); - promise_success(p, (void*)ring); - - int ret = MESA_htable_add(htable, key, key_len, (void*)ring); + *(data+len) = '\0'; + struct keyring* kyr= get_keyring_from_response(data); + promise_success(p, (void*)kyr); + int ret = MESA_htable_add(htable, key, key_len, (void*)kyr); if(ret<0) { - key_keeper_free_keyring((struct keyring*)ring); + key_keeper_free_keyring((struct keyring*)kyr); } } else { promise_failed(p, FUTURE_ERROR_EXCEPTION, status_msg); } + future_destroy(ctx->f_certstore_rpc); + //promise_dettach_ctx(p); + //ctx_destroy_cb((void*)ctx); } +static void certstore_rpc_on_fail(enum e_future_error err, const char * what, void * user) +{ + struct promise * p = (struct promise *) user; + promise_failed(p, err, what); + struct key_keeper_promise_ctx* ctx= (struct key_keeper_promise_ctx*)promise_get_ctx(p); + future_destroy(ctx->f_certstore_rpc); + //promise_dettach_ctx(p); + //ctx_destroy_cb((void*)ctx); +} -static int __wrapper_MESA_htable_set_opt(MESA_htable_handle table, enum MESA_htable_opt opt_type, unsigned int value); - -static MESA_htable_handle create_hash_table(unsigned int slot_size, unsigned int expire_seconds); - -static STACK_OF(X509)* get_chain_from_response(const char* data, int len, void* logger); /* * Certificate, including private key and keyring chain. */ - - -struct key_keeper* key_keeper_init(const char * profile, const char* section, void* logger) -{ - //load conf - //TODO free - struct key_keeper* keeper = ALLOC(struct key_keeper, 1); - keeper->logger = logger; - MESA_load_profile_uint_def(profile, section, "mode", &(keeper->mode), 1); - MESA_load_profile_string_def(profile, section, "cert_store_host", keeper->cert_store_host, sizeof(keeper->cert_store_host), "xxxxx"); - MESA_load_profile_uint_def(profile, section, "cert_store_port", &(keeper->cert_store_port), 80); - //TODO: argument - keeper->htable = create_hash_table(16,16); - return keeper; -} - -void key_keeper_destroy(struct key_keeper *keeper) -{ - free(keeper); - keeper = NULL; - return; -} - -struct keyring* key_keeper_release_keyring(future_result_t* result) -{ - struct keyring_private* kyr=(struct keyring_private*)result; - keyring_ref_inc(kyr); - return &(kyr->head); -} - -static void ctx_destory_cb(struct promise* p) -{ - -} - -//TODO: cert_not_valid -void key_keeper_async_ask(struct future * f, struct key_keeper * keeper, const char* sni, int keyring_id, X509 * origin_cert, int is_cert_valid, struct event_base * evbase) -{ - //get subject name from cert - - //current promise, belong to key_keeper - struct promise* p = future_to_promise(f); - struct key_keeper_promise_ctx* ctx = ALLOC(struct key_keeper_promise_ctx, 1); - //TODO free ctx!! - unsigned int len = 0; - const uchar* key = get_key_by_cert(origin_cert, keyring_id, &len); - ctx->logger = keeper->logger; - ctx->htable = keeper->htable; - ctx->key = key; - ctx->key_len = len; - promise_set_ctx(p, (void*)ctx, ctx_destory_cb); - long int cb_rtn = 0; - MESA_htable_search_cb(ctx->htable, (const unsigned char*)(ctx->key), ctx->key_len, keyring_local_cache_query_cb, p, &cb_rtn); - printf(cb_rtn == KEYRING_EXSITED ? "KEYRING_EXSITED\n": "KEYRING_NOT_EXSITED\n"); - if(cb_rtn == KEYRING_EXSITED) - { - return; - } - int mode = keeper->mode; - printf("mode is %s", mode == NORMAL ? "normal\n":"debug\n"); - switch(mode){ - case NORMAL: - { - struct future* f_tfe_rpc = future_create("tfe_rpc", certstore_rpc_on_succ, certstore_rpc_on_fail, p); - //TODO: init in main()? store in ctx - struct tfe_rpc* rpc = tfe_rpc_init(NULL, NULL, keeper->logger); - char url[TFE_STRING_MAX]; - const char host[] = "www.baidu.com"; - snprintf(url, TFE_STRING_MAX, "%s:%d?host=%s&flag=1&valid=1&kering_id=%d", keeper->cert_store_host, keeper->cert_store_port, host, keyring_id); - tfe_rpc_async_ask(f_tfe_rpc, rpc, url, GET, DONE_CB, NULL, 0, evbase); - break; - } - case DEBUG: - { - //TOOD: generate X509 cert - const char* filename = "./conf/mesalab-ca.pem"; - struct keyring_private* ring = generate_x509_keyring(origin_cert, keyring_id, filename); - if(ring) - { - promise_success(p, (void*)ring); - int ret = MESA_htable_add(ctx->htable, ctx->key, ctx->key_len, (void*)ring); - if(ret<0) - { - key_keeper_free_keyring((struct keyring*)ring); - } - else - { - printf("key %s is added to hash table\n", ctx->key); - } - } - else - { - promise_failed(p, FUTURE_ERROR_EXCEPTION, "generate X509 cert failed"); - } - break; - } - } - return; -} - - -static const uchar* -get_key_by_cert(X509* cert, int keyring_id, unsigned int* len) -{ - char* cert_fgr = NULL; - cert_fgr = ssl_x509_fingerprint(cert, 0); - char* key = (char*)malloc(HTABLE_MAX_KEY_LEN); - *key = '\0'; - if(cert == NULL) - { - return NULL; - } - snprintf(key, HTABLE_MAX_KEY_LEN, "%d:", keyring_id); - strncat(key, cert_fgr, HTABLE_MAX_KEY_LEN); - *len = strnlen(key, HTABLE_MAX_KEY_LEN); - return (const uchar*)key; -} - - static int __wrapper_MESA_htable_set_opt(MESA_htable_handle table, enum MESA_htable_opt opt_type, unsigned int value) { int ret = MESA_htable_set_opt(table, opt_type, &value, (int)(sizeof(value))); @@ -411,8 +393,7 @@ static int __wrapper_MESA_htable_set_opt(MESA_htable_handle table, enum MESA_hta return ret; } -static MESA_htable_handle -create_hash_table(unsigned int slot_size, unsigned int expire_seconds) +static MESA_htable_handle create_hash_table(unsigned int slot_size, unsigned int expire_seconds) { int ret = 0; unsigned max_num = slot_size * 4; @@ -435,5 +416,122 @@ create_hash_table(unsigned int slot_size, unsigned int expire_seconds) return htable; } +struct key_keeper* key_keeper_init(const char * profile, const char* section, void* logger) +{ + struct key_keeper* keeper = ALLOC(struct key_keeper, 1); + keeper->logger = logger; + MESA_load_profile_string_def(profile, section, "mode", keeper->mode, sizeof(keeper->mode), "debug"); + MESA_load_profile_string_def(profile, section, "ca_path", keeper->ca_path, sizeof(keeper->ca_path), "./conf/mesalab-ca.pem"); + MESA_load_profile_string_def(profile, section, "untrusted_ca_path", keeper->untrusted_ca_path, sizeof(keeper->untrusted_ca_path), "./conf/mesalab-ca.pem"); + MESA_load_profile_string_def(profile, section, "cert_store_host", keeper->cert_store_host, sizeof(keeper->cert_store_host), "xxxxx"); + MESA_load_profile_uint_def(profile, section, "cert_store_port", &(keeper->cert_store_port), 80); + MESA_load_profile_uint_def(profile, section, "hash_slot_size", &(keeper->hash_slot_size), 16); + MESA_load_profile_uint_def(profile, section, "hash_expire_seconds", &(keeper->hash_expire_seconds), 16); + keeper->htable = create_hash_table(keeper->hash_slot_size, keeper->hash_expire_seconds); + return keeper; +} + +void key_keeper_destroy(struct key_keeper *keeper) +{ + MESA_htable_destroy(keeper->htable, NULL); + free(keeper); + keeper = NULL; + return; +} + +struct keyring* key_keeper_release_keyring(future_result_t* result) +{ + struct keyring_private* kyr=(struct keyring_private*)result; + keyring_ref_inc(kyr); + return &(kyr->head); +} +static uchar* get_key_by_cert(X509* cert, int keyring_id, unsigned int* len) +{ + char* cert_fgr = NULL; + cert_fgr = ssl_x509_fingerprint(cert, 0); + char* key = (char*)malloc(HTABLE_MAX_KEY_LEN); + *key = '\0'; + if(cert == NULL) + { + return NULL; + } + snprintf(key, HTABLE_MAX_KEY_LEN, "%d:", keyring_id); + strncat(key, cert_fgr, HTABLE_MAX_KEY_LEN); + *len = strnlen(key, HTABLE_MAX_KEY_LEN); + free(cert_fgr); + return (uchar*)key; +} + + +void key_keeper_async_ask(struct future * f, struct key_keeper * keeper, const char* sni, int keyring_id, X509 * origin_cert, int is_cert_valid, struct event_base * evbase) +{ + struct promise* p = future_to_promise(f); + struct key_keeper_promise_ctx* ctx = ALLOC(struct key_keeper_promise_ctx, 1); + unsigned int len = 0; + uchar* key = get_key_by_cert(origin_cert, keyring_id, &len); + ctx->logger = keeper->logger; + ctx->htable = keeper->htable; + ctx->key = key; + ctx->key_len = len; + promise_set_ctx(p, (void*)ctx, key_keeper_promise_free_ctx); + long int cb_rtn = 0; + MESA_htable_search_cb(ctx->htable, (const unsigned char*)(ctx->key), ctx->key_len, keyring_local_cache_query_cb, p, &cb_rtn); + if(cb_rtn == KEYRING_EXSITED) + { + printf("KEYRING_EXSITED\n"); + return; + } + int mode = 0; + if(strncmp(keeper->mode, "debug", TFE_STRING_MAX) == 0) + { + mode = 1; + } + switch(mode){ + case NORMAL: + { + struct future* f_certstore_rpc = future_create("tfe_rpc", certstore_rpc_on_succ, certstore_rpc_on_fail, p); + ctx->f_certstore_rpc = f_certstore_rpc; + char url[TFE_STRING_MAX]; + char _sni[TFE_STRING_MAX] = "www.baidu.com"; + if(sni) + { + strncpy(_sni, sni, TFE_STRING_MAX); + } + snprintf(url, TFE_STRING_MAX, "http://%s:%d/ca?host=%s&flag=1&valid=1&keyring_id=%d", keeper->cert_store_host, keeper->cert_store_port, _sni, keyring_id); + printf("url is %s\n", url); + tfe_rpc_async_ask(f_certstore_rpc, url, GET, DONE_CB, NULL, 0, evbase); + break; + } + case DEBUG: + { + //TOOD: generate X509 cert + char* filename = NULL; + if(is_cert_valid == 1) + { + filename = keeper->ca_path; + } + else + { + filename = keeper->untrusted_ca_path; + } + struct keyring_private* ring = generate_x509_keyring(origin_cert, keyring_id, filename); + if(ring) + { + promise_success(p, (void*)ring); + int ret = MESA_htable_add(ctx->htable, ctx->key, ctx->key_len, (void*)ring); + if(ret<0) + { + key_keeper_free_keyring((struct keyring*)ring); + } + } + else + { + promise_failed(p, FUTURE_ERROR_EXCEPTION, "generate X509 cert failed"); + } + break; + } + } + return; +} diff --git a/platform/src/tfe_rpc.cpp b/platform/src/tfe_rpc.cpp deleted file mode 100644 index 327bb96..0000000 --- a/platform/src/tfe_rpc.cpp +++ /dev/null @@ -1,258 +0,0 @@ -#include "tfe_rpc.h" -#include "event2/http.h" -#include "event2/http_struct.h" -#include "event2/event.h" -#include "event2/buffer.h" -#include "event2/dns.h" -#include "event2/thread.h" -#include "tfe_utils.h" -#include "MESA/MESA_handle_logger.h" -#include -#include -#include -#include -#include - -#define MODULE_NAME "tfe_rpc" - -void promise_success_cb(const char* data, int len); - -struct req_ctx -{ - struct promise* promise; - void* logger; -}; - -//The callback is executed when the request completed or an error occurred -void -get_response_cb(struct evhttp_request* response, void* arg) -{ - struct req_ctx* ctx = (struct req_ctx*)arg; - void* logger = ctx->logger; - struct promise* p = ctx->promise; - MESA_handle_runtime_log(logger, RLOG_LV_INFO, MODULE_NAME, "call get_response_cb!"); - struct evbuffer* evbuf = evhttp_request_get_input_buffer(response); - int evbuf_len = evbuffer_get_length(evbuf); - char* data = (char*)evbuffer_pullup(evbuf, evbuf_len); - printf("data is %s\n", data==NULL ? "NULL":"NOT NULL"); - //promise_success_cb(data, evbuf_len); - //TODO: free - struct tfe_rpc_response_result* result = ALLOC(struct tfe_rpc_response_result, 1); - result->status_code = evhttp_request_get_response_code(response); - result->status_msg = evhttp_request_get_response_code_line(response); - result->data = data; - result->len = evbuf_len; - promise_success(p, result); -} - -//will be called after receiving and parsing the full header. It allows analyzing the header and possibly closing the connection by returning a value < 0. -int -read_header_done_cb(struct evhttp_request* response, void* arg) -{ - struct req_ctx* ctx = (struct req_ctx*)arg; - void* logger = ctx->logger; - MESA_handle_runtime_log(logger, RLOG_LV_INFO, MODULE_NAME, "call read_header_done_cb!"); - MESA_handle_runtime_log(logger, RLOG_LV_INFO, MODULE_NAME, "< HTTP/1.1 %d %s\n", evhttp_request_get_response_code(response), evhttp_request_get_response_code_line(response)); - return 0; - /* - struct evkeyvalq* headers = evhttp_request_get_input_headers(response); - struct evkeyval* header; - TAILQ_FOREACH(header, headers, next){ - MESA_handle_runtime_log(logger, RLOG_LV_INFO, MODULE_NAME, "< %s: %s\n", header->key, header->value); - } - MESA_handle_runtime_log(logger, RLOG_LV_INFO, MODULE_NAME, "< \n"); - */ -} - -//will be called after every read of data with the same argument as the completion callback. Will never be called on an empty response. May drain the input buffer; it will be drained automatically on return. -//will drain automaticly -void -read_chunk_cb(struct evhttp_request* response, void* arg) -{ - struct req_ctx* ctx = (struct req_ctx*)arg; - void* logger = ctx->logger; - struct promise* p = ctx->promise; - MESA_handle_runtime_log(logger, RLOG_LV_INFO, MODULE_NAME, "call read_chunk_cb!"); - struct evbuffer* evbuf = evhttp_request_get_input_buffer(response); - int evbuf_len = evbuffer_get_length(evbuf); - char* data = (char*)evbuffer_pullup(evbuf, evbuf_len); - struct tfe_rpc_response_result* result = ALLOC(struct tfe_rpc_response_result, 1); - result->status_code = evhttp_request_get_response_code(response); - result->status_msg = evhttp_request_get_response_code_line(response); - result->data = data; - result->len = evbuf_len; - promise_success(p, result); -} - -void -promise_success_cb(const char* data, int len) -{ - printf("len is %d, data is: \n", len); - char* data1 = (char*)malloc(len+1); - strncpy(data1, data, len); - data1[len] = '\0'; - printf("%s", data1); - free(data1); -} - - -//On error, both the error callback and the regular callback will be called, error callback is called before the regular callback. -void -request_error_cb(enum evhttp_request_error error, void* arg) -{ - struct req_ctx* ctx = (struct req_ctx*)arg; - void* logger = ctx->logger; - struct promise* p = ctx->promise; - MESA_handle_runtime_log(logger, RLOG_LV_FATAL, MODULE_NAME, "call request_error_cb, error code is %d!", error); - enum e_future_error error_map_table[6]; - error_map_table[EVREQ_HTTP_TIMEOUT] = FUTURE_ERROR_TIMEOUT; - error_map_table[EVREQ_HTTP_EOF] = FUTURE_ERROR_EXCEPTION; - error_map_table[EVREQ_HTTP_INVALID_HEADER] = FUTURE_ERROR_EXCEPTION; - error_map_table[EVREQ_HTTP_BUFFER_ERROR] = FUTURE_ERROR_EXCEPTION; - error_map_table[EVREQ_HTTP_REQUEST_CANCEL] = FUTURE_ERROR_CANCEL; - error_map_table[EVREQ_HTTP_DATA_TOO_LONG] = FUTURE_ERROR_EXCEPTION; - promise_failed(p, error_map_table[error], NULL); - //promise_fail_cb(); -} - -//when to close a connection ??? -//Set a callback for connection close -void -connection_close_cb(struct evhttp_connection* connection, void* arg) -{ - struct req_ctx* ctx = (struct req_ctx*)arg; - void* logger = ctx->logger; - MESA_handle_runtime_log(logger, RLOG_LV_FATAL, MODULE_NAME, "call connection_close_cb!"); -} - -struct -tfe_rpc * tfe_rpc_init(const char * profile, const char* section, void* logger) -{ - struct tfe_rpc* rpc = ALLOC(struct tfe_rpc, 1); - rpc->logger = logger; - return rpc; -} - - -//TODO: deep destory -struct tfe_rpc * -tfe_rpc_destroy(struct tfe_rpc *rpc) -{ - free(rpc); - rpc = NULL; - return rpc; -} - -//data is for POST. if method is GET, data should be NULL -void -tfe_rpc_async_ask(struct future* f, struct tfe_rpc* rpc, const char* url, int method, int flag, const char* data, int data_len, struct event_base * evbase) -{ - struct promise* p = future_to_promise(f); - void* logger = rpc->logger; - struct req_ctx* ctx = ALLOC(struct req_ctx, 1); - ctx->promise = p; - ctx->logger = logger; - assert(logger); - if(!evbase) - { - MESA_handle_runtime_log(logger, RLOG_LV_FATAL, MODULE_NAME, "event base is NULL"); - promise_failed(p, FUTURE_ERROR_EXCEPTION, "event base is NULL"); - return; - } - struct evhttp_uri* uri = evhttp_uri_parse(url); - if(NULL == uri) - { - MESA_handle_runtime_log(logger, RLOG_LV_FATAL, MODULE_NAME, "parse url failed!"); - promise_failed(p, FUTURE_ERROR_EXCEPTION, "parse url failed!"); - return; - } - const char* host = evhttp_uri_get_host(uri); - if(!host) - { - MESA_handle_runtime_log(logger, RLOG_LV_FATAL, MODULE_NAME, "parse host failed!"); - promise_failed(p, FUTURE_ERROR_EXCEPTION, "parse host failed!"); - return; - } - int port = evhttp_uri_get_port(uri); - if(port < 0) - { - port = 80; - } - const char* path = evhttp_uri_get_path(uri); - const char* request_url = path; - if(path == NULL || strlen(path) == 0) - { - request_url = "/"; - } - printf("url:%s host:%s port:%d path:%s request_url:%s\n", url, host, port, path, request_url); - struct evdns_base* dnsbase = evdns_base_new(evbase, EVDNS_BASE_INITIALIZE_NAMESERVERS); - if (!dnsbase) - { - MESA_handle_runtime_log(logger, RLOG_LV_FATAL, MODULE_NAME, "create dns base failed!"); - promise_failed(p, FUTURE_ERROR_EXCEPTION, "create dns base failed!"); - return; - } - struct evhttp_connection* connection = evhttp_connection_base_new(evbase, dnsbase, host, port); - if (!connection) - { - MESA_handle_runtime_log(logger, RLOG_LV_FATAL, MODULE_NAME, "create connection failed!"); - promise_failed(p, FUTURE_ERROR_EXCEPTION, "create connection failed!"); - return; - } - evhttp_connection_set_closecb(connection, connection_close_cb, evbase); - //TODO: free - struct evhttp_request* request = evhttp_request_new(get_response_cb, ctx); - evhttp_request_set_header_cb(request, read_header_done_cb); - if(flag == CHUNK_CB) - { - evhttp_request_set_chunked_cb(request, read_chunk_cb); - } - evhttp_request_set_error_cb(request, request_error_cb); - evhttp_add_header(evhttp_request_get_output_headers(request), "Host", host); - switch(method) - { - case GET: - evhttp_make_request(connection, request, EVHTTP_REQ_GET, request_url); - break; - case POST: - evbuffer_add(request->output_buffer, data, data_len); - evhttp_make_request(connection, request, EVHTTP_REQ_POST, request_url); - break; - default: - promise_failed(p, FUTURE_ERROR_EXCEPTION, "method is invalid!"); - return; - } -} - -struct -tfe_rpc_response_result* tfe_rpc_release(void* result) -{ - struct tfe_rpc_response_result* response = (struct tfe_rpc_response_result*)result; - return response; -} - -/* -int main(int argc, char** argv){ - char* url = "http://localhost:80/download/test1.txt"; - void* logger = MESA_create_runtime_log_handle_new("tfe_rpc_logger"); - if(!logger){ - printf("create runtime log handle failed!\n"); - return -1; - } - int rtn = MESA_read_runtime_log_handle_conf(logger, "./conf/MESA_handle_logger.conf"); - if(rtn == -1){ - printf("read runtime log handle conf failed!\n"); - return -1; - } - MESA_handle_runtime_log(logger, RLOG_LV_INFO, MODULE_NAME, "test log!\n"); - struct event_base* base = event_base_new(); - if(!base){ - MESA_handle_runtime_log(logger, RLOG_LV_FATAL, MODULE_NAME, "create event base failed!\n"); - return -1; - } - tfe_rpc(url, GET, CHUNK_CB, base, logger, NULL); - event_base_dispatch(base); - return 0; -} -*/ - diff --git a/platform/test/test_key_keeper.cpp b/platform/test/test_key_keeper.cpp index 005a7d2..214fcbe 100644 --- a/platform/test/test_key_keeper.cpp +++ b/platform/test/test_key_keeper.cpp @@ -1,37 +1,58 @@ #include "key_keeper.h" #include "tfe_future.h" #include "ssl_utils.h" -#include "event2/event.h" +#include "tfe_rpc.h" + void ask_key_keeper_on_succ(void* result, void* user); void ask_key_keeper_on_fail(enum e_future_error error, const char * what, void * user); -int -main() +int main() { void* logger = NULL; + future_promise_library_init(); + struct event_base* evbase = event_base_new(); struct key_keeper * keeper = key_keeper_init("./conf/tfe.conf", "key_keeper", logger); struct promise* user = NULL; struct future* f = future_create("key_keeper", ask_key_keeper_on_succ, ask_key_keeper_on_fail, user); - struct event_base* evbase = NULL; X509* origin_cert = ssl_x509_load("./conf/origin_cert.pem"); + printf("-------------------------------\n"); int i = 0; - for(i = 0;i<10;i++){ - printf("-------------------------------\n"); - printf("call key_keeper_async_ask, i = %d\n", i); - key_keeper_async_ask(f, keeper, NULL, 0, origin_cert, 0, evbase); - } + printf("call key_keeper_async_ask, i = %d\n", i); + key_keeper_async_ask(f, keeper, NULL, 0, origin_cert, 0, evbase); + event_base_dispatch(evbase); + + + struct event_base* evbase1 = event_base_new(); + struct future* f1 = future_create("key_keeper", ask_key_keeper_on_succ, ask_key_keeper_on_fail, user); + key_keeper_async_ask(f1, keeper, NULL, 0, origin_cert, 0, evbase1); + event_base_dispatch(evbase1); } -void -ask_key_keeper_on_succ(void* result, void* user) +void ask_key_keeper_on_succ(void* result, void* user) { printf("call ask_key_keeper_on_succ\n"); + struct keyring* kyr = key_keeper_release_keyring(result); + X509* cert = kyr->cert; + EVP_PKEY* key = kyr->key; + STACK_OF(X509) * chain = kyr->chain; + if(cert) + { + printf("cert is not null\n"); + } + if(key) + { + printf("key is not null\n"); + } + if(chain) + { + printf("chain is not null\n"); + } + return; } -void -ask_key_keeper_on_fail(enum e_future_error error, const char * what, void * user) +void ask_key_keeper_on_fail(enum e_future_error error, const char * what, void * user) { printf("call ask_key_keeper_on_fail\n"); } diff --git a/platform/test/test_tfe_rpc.cpp b/platform/test/test_tfe_rpc.cpp index e257e44..5e770b5 100644 --- a/platform/test/test_tfe_rpc.cpp +++ b/platform/test/test_tfe_rpc.cpp @@ -3,9 +3,207 @@ #include "MESA/MESA_prof_load.h" #include "MESA/MESA_handle_logger.h" #include "string.h" +#include "cjson/cJSON.h" +#include "ssl_utils.h" +#include "key_keeper.h" -static void -tfe_rpc_on_succ(void* result, void* user) +struct keyring_private +{ + struct keyring head; + pthread_mutex_t mutex; + size_t references; +}; + +static struct keyring_private* keyring_new(void) +{ + struct keyring_private *kyr; + if (!(kyr = (struct keyring_private *)ALLOC(struct keyring_private, 1))) + { + return NULL; + } + if (pthread_mutex_init(&kyr->mutex, NULL)) { + free(kyr); + return NULL; + } + kyr->references = 1; + return kyr; +} + + +// Increment reference count. +static void keyring_ref_inc(struct keyring_private* kyr) +{ + pthread_mutex_lock(&kyr->mutex); + kyr->references++; + pthread_mutex_unlock(&kyr->mutex); +} + +/* + * Thread-safe setter functions; they copy the value (refcounts are inc'd). + */ +static void keyring_set_key(struct keyring_private* kyr, EVP_PKEY *key) +{ + pthread_mutex_lock(&kyr->mutex); + if ((kyr->head).key) + { + EVP_PKEY_free((kyr->head).key); + } + (kyr->head).key = key; + if (key) + { + ssl_key_refcount_inc((kyr->head).key); + } + pthread_mutex_unlock(&kyr->mutex); +} + +static void keyring_set_cert(struct keyring_private* kry, X509 *cert) +{ + pthread_mutex_lock(&kry->mutex); + if ((kry->head).cert) + { + X509_free((kry->head).cert); + } + (kry->head).cert = cert; + if (cert) + { + ssl_x509_refcount_inc((kry->head).cert); + } + pthread_mutex_unlock(&kry->mutex); +} + +static void keyring_set_chain(struct keyring_private* kyr, STACK_OF(X509) *chain) +{ + pthread_mutex_lock(&kyr->mutex); + if ((kyr->head).chain) + { + sk_X509_pop_free((kyr->head).chain, X509_free); + } + if (chain) + { + (kyr->head).chain = sk_X509_dup(chain); + int i = 0; + for (i = 0; i < sk_X509_num((kyr->head).chain); i++) + { + ssl_x509_refcount_inc(sk_X509_value((kyr->head).chain, i)); + } + } else + { + (kyr->head).chain = NULL; + } + pthread_mutex_unlock(&kyr->mutex); +} + +static X509* transform_cert_to_x509(const char* str) +{ + BIO *bio; + X509 *cert; + bio = BIO_new(BIO_s_mem()); + BIO_write(bio, (const void*)str, strnlen(str, TFE_STRING_MAX)); + cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); + return cert; +} + +static EVP_PKEY* transform_key_to_EVP(const char* str) +{ + BIO *mem; + mem = BIO_new_mem_buf(str, -1); + EVP_PKEY* key = PEM_read_bio_PrivateKey(mem, NULL, NULL, 0); + return key; +} + + +static void err_out(X509* cert, EVP_PKEY* key, STACK_OF(X509)* chain) +{ + if(cert) + { + X509_free(cert); + } + if(key) + { + EVP_PKEY_free(key); + } + if(chain) + { + sk_X509_pop_free(chain, X509_free); + } + return; +} + +static struct keyring* get_keyring_from_response(const char* data) +{ + X509* cert = NULL; + EVP_PKEY* key = NULL; + STACK_OF(X509)* chain = NULL; + if(data == NULL) + { + return NULL; + } + cJSON* data_json = cJSON_Parse(data); + if(data_json == NULL) + { + return NULL; + } + cJSON* cert_json = NULL; + cJSON* key_json = NULL; + cJSON* chain_json = NULL; + cert_json = cJSON_GetObjectItemCaseSensitive(data_json, "CERTIFICATE"); + key_json = cJSON_GetObjectItemCaseSensitive(data_json, "PRIVATE_KEY"); + chain_json = cJSON_GetObjectItemCaseSensitive(data_json, "CERTIFICATE_CHAIN"); + if (cert_json && cert_json->valuestring != NULL) + { + cert = transform_cert_to_x509(cert_json->valuestring); + } + if(cert == NULL) + { + err_out(cert, key, chain); + return NULL; + } + if (key_json && key_json->valuestring != NULL) + { + key = transform_key_to_EVP(key_json->valuestring); + } + if(key == NULL) + { + err_out(cert, key, chain); + return NULL; + } + if(chain_json == NULL) + { + err_out(cert, key, chain); + return NULL; + } + cJSON* chain_cert_json = NULL; + chain = sk_X509_new_null(); + cJSON_ArrayForEach(chain_cert_json, chain_json) + { + X509* chain_cert = NULL; + if (chain_cert_json && chain_cert_json->valuestring != NULL) + { + chain_cert = transform_cert_to_x509(chain_cert_json->valuestring); + } + if(chain_cert == NULL) + { + err_out(cert, key, chain); + return NULL; + } + if(chain_cert) + printf("push to chain\n"); + sk_X509_push(chain, chain_cert); + } + struct keyring_private* _kyr= keyring_new(); + printf("cert is %s", cert == NULL ? "null" : "not null\n"); + printf("key is %s", key == NULL ? "null" : "not null\n"); + printf("chain is %s", chain == NULL ? "null" : "not null\n"); + keyring_set_cert(_kyr, cert); + keyring_set_key(_kyr, key); + keyring_set_chain(_kyr, chain); + X509_free(cert); + EVP_PKEY_free(key); + sk_X509_pop_free(chain, X509_free); + return &(_kyr->head); +} + +static void tfe_rpc_on_succ(void* result, void* user) { struct tfe_rpc_response_result* response = tfe_rpc_release(result); int status_code = response->status_code; @@ -15,24 +213,28 @@ tfe_rpc_on_succ(void* result, void* user) *(data+len) = '\0'; printf("status_code is %d\n", status_code); printf("status_msg is %s\n", status_msg); - printf("data is %s\n", data); + //printf("data is %s\n", data); printf("len is %d\n", len); + struct keyring* kyr = get_keyring_from_response(data); + //add to hash table } -static void -tfe_rpc_on_fail(enum e_future_error err, const char * what, void * user){ +static void tfe_rpc_on_fail(enum e_future_error err, const char * what, void * user){ printf("err is %d\n", err); printf("what is %s\n", what); - printf("user is %s\n", user); + printf("user is %s\n", (char*)user); } + + int main() { char cert_store_host[TFE_STRING_MAX]; unsigned int cert_store_port; - const char* file_path = "./log/test_tfe_rpc.log",*host="localhost"; - void * logger = MESA_create_runtime_log_handle(file_path, RLOG_LV_INFO); + future_promise_library_init(); + //const char* file_path = "./log/test_tfe_rpc.log",*host="localhost"; + //void * logger = MESA_create_runtime_log_handle(file_path, RLOG_LV_INFO); const char* profile = "./conf/tfe.conf"; const char* section = "key_keeper"; int keyring_id = 0; @@ -40,12 +242,11 @@ int main() MESA_load_profile_uint_def(profile, section, "cert_store_port", &cert_store_port, 80); struct event_base* evbase = event_base_new(); struct future* f_tfe_rpc = future_create("tfe_rpc", tfe_rpc_on_succ, tfe_rpc_on_fail, NULL); - struct tfe_rpc* rpc = tfe_rpc_init(NULL, NULL, logger); char url[TFE_STRING_MAX]; - strncpy(cert_store_host, "www.baidu.com", TFE_STRING_MAX); - snprintf(url, TFE_STRING_MAX, "http://%s:%d/ca?host=%s&flag=1&valid=1&kering_id=%d", cert_store_host, cert_store_port, host, keyring_id); + char sni[TFE_STRING_MAX] = "www.baidu.com"; + snprintf(url, TFE_STRING_MAX, "http://%s:%d/ca?host=%s&flag=1&valid=1&kering_id=%d", cert_store_host, cert_store_port, sni, keyring_id); printf("url is %s\n", url); - tfe_rpc_async_ask(f_tfe_rpc, rpc, url, GET, DONE_CB, NULL, 0, evbase); - event_base_dispatch(evbase); + tfe_rpc_async_ask(f_tfe_rpc, url, GET, DONE_CB, NULL, 0, evbase); + event_base_dispatch(evbase); }