From 636e41cfca230e872f94b6be6f8c61ffbaf72845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B4=94=E4=B8=80=E9=B8=A3?= Date: Tue, 4 Sep 2018 15:47:41 +0800 Subject: [PATCH] add feature-key-keeper --- platform/CMakeLists.txt | 41 +- platform/include/internal/key_keeper.h | 42 +- platform/include/internal/tfe_rpc.h | 35 ++ platform/src/key_keeper.cpp | 608 ++++++++++++++++++------- platform/src/tfe_rpc.cpp | 258 +++++++++++ platform/test/test_key_keeper.cpp | 37 ++ platform/test/test_tfe_rpc.cpp | 50 ++ 7 files changed, 904 insertions(+), 167 deletions(-) create mode 100644 platform/include/internal/tfe_rpc.h create mode 100644 platform/src/tfe_rpc.cpp create mode 100644 platform/test/test_key_keeper.cpp create mode 100644 platform/test/test_tfe_rpc.cpp diff --git a/platform/CMakeLists.txt b/platform/CMakeLists.txt index f2e4df2..8dda336 100644 --- a/platform/CMakeLists.txt +++ b/platform/CMakeLists.txt @@ -1,5 +1,4 @@ -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) +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) target_include_directories(tfe PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include/external) target_include_directories(tfe PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include/internal) @@ -17,3 +16,41 @@ target_link_libraries(tfe pthread dl MESA_field_stat) 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) + +target_include_directories(test_key_keeper PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include/internal) + +target_link_libraries(test_key_keeper common) +target_link_libraries(test_key_keeper pthread dl + openssl-ssl-static + openssl-crypto-static + pthread libevent-static + libevent-static-openssl + libevent-static-pthreads + MESA_handle_logger + MESA_prof_load + 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) + +target_include_directories(test_tfe_rpc PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include/internal) + +target_link_libraries(test_tfe_rpc common) +target_link_libraries(test_tfe_rpc pthread dl + openssl-ssl-static + openssl-crypto-static + pthread libevent-static + libevent-static-openssl + libevent-static-pthreads + MESA_handle_logger + MESA_prof_load + MESA_htable wiredcfg + MESA_field_stat) + +install(TARGETS test_tfe_rpc RUNTIME DESTINATION ./) diff --git a/platform/include/internal/key_keeper.h b/platform/include/internal/key_keeper.h index fbed3c0..4211a73 100644 --- a/platform/include/internal/key_keeper.h +++ b/platform/include/internal/key_keeper.h @@ -1,8 +1,10 @@ #pragma once - -#include +#include "ssl_utils.h" #include -#include +#include "tfe_future.h" +#include "tfe_utils.h" +#include "MESA/MESA_htable.h" +#include "event2/event.h" struct keyring { @@ -10,11 +12,41 @@ struct keyring X509 *cert; STACK_OF(X509) * chain; }; -struct key_keeper; + +struct key_keeper +{ + unsigned int mode; + char cert_store_host[TFE_STRING_MAX]; + unsigned int cert_store_port; + MESA_htable_handle htable; + void* logger; +}; + struct key_keeper * key_keeper_init(const char * profile, const char* section, void* logger); + struct key_keeper * key_keeper_destroy(struct key_keeper *keeper); struct keyring* key_keeper_release_cert(future_result_t* result); + +struct keyring* key_keeper_keyring_new(void); + +struct keyring* key_keeper_keyring_new3(EVP_PKEY *key, X509 *cert, STACK_OF(X509) *chain); + void key_keeper_free_keyring(struct keyring* cert); + void key_keeper_async_ask(struct future * f, struct key_keeper * keeper, int keyring_id, - X509 * origin_cert, int is_cert_valid, struct event_base * evbase); + X509 * origin_cert, int is_cert_valid, struct event_base * evbase); + +void key_keeper_keyring_refcount_inc(struct keyring* ring); + +void key_keeper_keyring_set_cert(struct keyring* ring, X509 *cert); + +void key_keeper_keyring_set_key(struct keyring* ring, EVP_PKEY *key); + +void key_keeper_keyring_set_chain(struct keyring* ring, STACK_OF(X509) *chain); + +static void key_keeper_free_serialized(); + +static void key_keeper_verify_cb(); + + diff --git a/platform/include/internal/tfe_rpc.h b/platform/include/internal/tfe_rpc.h new file mode 100644 index 0000000..d009d63 --- /dev/null +++ b/platform/include/internal/tfe_rpc.h @@ -0,0 +1,35 @@ +#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 ca53aa1..59f00b1 100644 --- a/platform/src/key_keeper.cpp +++ b/platform/src/key_keeper.cpp @@ -1,67 +1,472 @@ -#include +#include "key_keeper.h" #include -#include - -struct key_keeper -{ +#include +#include +#include +#include "MESA/MESA_prof_load.h" +#include "tfe_rpc.h" +#include "event2/http.h" +#define HTABLE_MAX_KEY_LEN 256 +#define KEYRING_EXSITED 0 +#define KEYRING_NOT_EXSITED -1 +enum KEY_KEEPER_MODE{ + NORMAL = 0, + DEBUG, }; -struct key_keeper_private + +struct keyring_private { struct keyring head; pthread_mutex_t mutex; size_t references; }; -#if 0 +struct key_keeper_promise_ctx +{ + void* logger; + MESA_htable_handle htable; + const uchar* key; + unsigned int key_len; +}; + +static const uchar* get_key_by_cert(X509* cert, int keyring_id, unsigned int* len); + +static long htable_search_cb(void * data, const uchar * key, uint size, void * user_arg); + +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 struct keyring* generate_x509_cert(X509* origin_cert, int keyring_id, const char* filename); + +static void tfe_rpc_on_succ(void* result, void* user); + +static void tfe_rpc_on_fail(enum e_future_error err, const char * what, void * user); + +static void ctx_destory_cb(struct promise* p); + +static X509* get_cert_from_response(const char* data, int len, void* logger); + +static EVP_PKEY* get_key_from_response(const char* data, int len, void* logger); + +static STACK_OF(X509)* get_chain_from_response(const char* data, int len, void* logger); /* * Certificate, including private key and keyring chain. */ - -cert_t * -cert_new(void) +struct keyring* +key_keeper_keyring_new(void) { - cert_t *c; - - if (!(c = (cert_t *)malloc(sizeof(cert_t)))) - return NULL; - memset(c, 0, sizeof(cert_t)); - if (pthread_mutex_init(&c->mutex, NULL)) { - free(c); + struct keyring_private *keyring; + if (!(keyring = (struct keyring_private *)ALLOC(struct keyring_private, 1))) + { return NULL; } - c->references = 1; - return c; + if (pthread_mutex_init(&keyring->mutex, NULL)) { + free(keyring); + return NULL; + } + keyring->references = 1; + return &(keyring->head); } /* * Passed OpenSSL objects are owned by cert_t; refcount will not be * incremented, stack will not be duplicated. */ -cert_t * -cert_new3(EVP_PKEY *key, X509 *crt, STACK_OF(X509) *chain) +struct keyring* +key_keeper_keyring_new3(EVP_PKEY *key, X509 *cert, STACK_OF(X509) *chain) { - cert_t *c; - - if (!(c = (cert_t *)malloc(sizeof(cert_t)))) - return NULL; - if (pthread_mutex_init(&c->mutex, NULL)) { - free(c); + struct keyring_private* keyring; + if (!(keyring = (struct keyring_private *)ALLOC(struct keyring_private, 1))) + { return NULL; } - c->key = key; - c->crt = crt; - c->chain = chain; - c->references = 1; - return c; + if (pthread_mutex_init(&keyring->mutex, NULL)) { + free(keyring); + return NULL; + } + keyring->references = 1; + (keyring->head).key = key; + (keyring->head).cert = cert; + (keyring->head).chain = chain; + if(key) + { + ssl_key_refcount_inc(key); + } + if(cert) + { + ssl_x509_refcount_inc(cert); + } + if(chain){ + int i = 0; + for (i = 0; i < sk_X509_num(chain); i++) + { + ssl_x509_refcount_inc(sk_X509_value(chain, i)); + } + } + return &(keyring->head); +} + +// Increment reference count. +void +key_keeper_keyring_refcount_inc(struct keyring* ring) +{ + struct keyring_private* keyring = (struct keyring_private*)ring; + pthread_mutex_lock(&keyring->mutex); + keyring->references++; + pthread_mutex_unlock(&keyring->mutex); } +/* + * Thread-safe setter functions; they copy the value (refcounts are inc'd). + */ +void +key_keeper_keyring_set_key(struct keyring* ring, EVP_PKEY *key) +{ + struct keyring_private* keyring = (struct keyring_private*)ring; + pthread_mutex_lock(&keyring->mutex); + if ((keyring->head).key) + { + EVP_PKEY_free((keyring->head).key); + } + (keyring->head).key = key; + if (key) + { + ssl_key_refcount_inc((keyring->head).key); + } + pthread_mutex_unlock(&keyring->mutex); +} + +void +key_keeper_keyring_set_cert(struct keyring* ring, X509 *cert) +{ + struct keyring_private* keyring = (struct keyring_private*)ring; + pthread_mutex_lock(&keyring->mutex); + if ((keyring->head).cert) + { + X509_free((keyring->head).cert); + } + (keyring->head).cert = cert; + if (cert) + { + ssl_x509_refcount_inc((keyring->head).cert); + } + pthread_mutex_unlock(&keyring->mutex); +} + +void +key_keeper_keyring_set_chain(struct keyring* ring, STACK_OF(X509) *chain) +{ + struct keyring_private* keyring = (struct keyring_private*)ring; + pthread_mutex_lock(&keyring->mutex); + if ((keyring->head).chain) + { + sk_X509_pop_free((keyring->head).chain, X509_free); + } + if (chain) + { + (keyring->head).chain = sk_X509_dup(chain); + int i = 0; + for (i = 0; i < sk_X509_num((keyring->head).chain); i++) + { + ssl_x509_refcount_inc(sk_X509_value((keyring->head).chain, i)); + } + } else + { + (keyring->head).chain = NULL; + } + pthread_mutex_unlock(&keyring->mutex); +} + +/* + * Free keyring including internal objects. + */ +void +key_keeper_free_keyring(struct keyring *ring) +{ + struct keyring_private* keyring = (struct keyring_private*)ring; + pthread_mutex_lock(&keyring->mutex); + keyring->references--; + if (keyring->references) + { + pthread_mutex_unlock(&keyring->mutex); + return; + } + pthread_mutex_unlock(&keyring->mutex); + pthread_mutex_destroy(&keyring->mutex); + if ((keyring->head).key) + { + EVP_PKEY_free((keyring->head).key); + } + if ((keyring->head).cert) + { + X509_free((keyring->head).cert); + } + if ((keyring->head).chain) + { + sk_X509_pop_free((keyring->head).chain, X509_free); + } + free(keyring); +} + +static void key_keeper_free_serialized() +{ + return; +} + +static void key_keeper_verify_cb() +{ + return; +} + +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; +} + +//return void ?? +struct key_keeper * +key_keeper_destroy(struct key_keeper *keeper) +{ + free(keeper); + keeper = NULL; + return keeper; +} + +struct keyring* +key_keeper_release_cert(future_result_t* result) +{ + return (struct keyring*)result; +} + +static struct keyring* +generate_x509_cert(X509* origin_cert, int keyring_id, const char* filename) +{ + X509* ca = ssl_x509_load(filename); + EVP_PKEY* cakey = ssl_key_load(filename); + EVP_PKEY* forge_key = ssl_key_genrsa(1024); + X509* forge_cert = ssl_x509_forge(ca, cakey, origin_cert, forge_key, NULL, NULL); + STACK_OF(X509)* chain = sk_X509_new_null(); + sk_X509_push(chain, ca); + sk_X509_push(chain, forge_cert); + struct keyring* ring= key_keeper_keyring_new(); + key_keeper_keyring_set_key(ring, forge_key); + key_keeper_keyring_set_cert(ring, forge_cert); + key_keeper_keyring_set_chain(ring, chain); + return ring; +} + +static void +tfe_rpc_on_succ(void* result, void* user) +{ + struct promise * p = (struct promise *) user; + struct key_keeper_promise_ctx* ctx = (struct key_keeper_promise_ctx*)promise_get_ctx(p); + void* logger = ctx->logger; + 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; + int len = response->len; + if(status_code == HTTP_OK) + { + struct keyring* ring= key_keeper_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); + key_keeper_keyring_set_key(ring, forge_key); + key_keeper_keyring_set_cert(ring, forge_cert); + key_keeper_keyring_set_chain(ring, chain); + promise_success(p, (void*)ring); + int ret = MESA_htable_add(htable, key, key_len, (void*)ring); + assert(ret >= 0); + } + else + { + promise_failed(p, FUTURE_ERROR_EXCEPTION, status_msg); + } +} + + +static void +tfe_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 void ctx_destory_cb(struct promise* p) +{ + +} + +//TODO: cert_not_valid +void key_keeper_async_ask(struct future * f, struct key_keeper * keeper, 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); + 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, htable_search_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", tfe_rpc_on_succ, tfe_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* ring = generate_x509_cert(origin_cert, keyring_id, filename); + if(ring) + { + int ret = MESA_htable_add(ctx->htable, ctx->key, ctx->key_len, (void*)ring); + assert(ret >= 0); + printf("key %s is added to hash table\n", ctx->key); + promise_success(p, (void*)ring); + } + else + { + promise_failed(p, FUTURE_ERROR_EXCEPTION, "generate X509 cert failed"); + } + break; + } + } + return; +} + +static long +htable_search_cb(void * data, const uchar * key, uint size, void * user_arg) +{ + //data is (struct keyring*) + if(data == NULL) + { + return KEYRING_NOT_EXSITED; + } + else + { + struct promise* p = (struct promise*)user_arg; + promise_success(p, data); + return KEYRING_EXSITED; + } +} + +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))); + assert(ret == 0); + return ret; +} + +static MESA_htable_handle +create_hash_table(unsigned int slot_size, unsigned int expire_seconds) +{ + int ret = 0; + unsigned max_num = slot_size * 4; + MESA_htable_handle htable = MESA_htable_born(); + ret = __wrapper_MESA_htable_set_opt(htable, MHO_SCREEN_PRINT_CTRL, 0); + ret = __wrapper_MESA_htable_set_opt(htable, MHO_THREAD_SAFE, 1); + ret = __wrapper_MESA_htable_set_opt(htable, MHO_MUTEX_NUM, 16); + ret = __wrapper_MESA_htable_set_opt(htable, MHO_HASH_SLOT_SIZE, slot_size); + ret = __wrapper_MESA_htable_set_opt(htable, MHO_HASH_MAX_ELEMENT_NUM, max_num); + ret = __wrapper_MESA_htable_set_opt(htable, MHO_EXPIRE_TIME, expire_seconds); + ret = __wrapper_MESA_htable_set_opt(htable, MHO_ELIMIMINATE_TYPE, + HASH_ELIMINATE_ALGO_FIFO); + //TODO: how to do overide? + //ret = __wrapper_MESA_htable_set_opt(htable, MHO_CBFUN_DATA_FREE, + // (void *)key_keeper_free_serialized); + //ret = __wrapper_MESA_htable_set_opt(htable, MHO_CBFUN_DATA_EXPIRE_NOTIFY, + // (void *)key_keeper_verify_cb); + ret = MESA_htable_mature(htable); + assert(ret == 0); + return htable; +} + +//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) +{ + +} + + +static STACK_OF(X509)* +get_chain_from_response(const char* data, int len, void* logger) +{ + +} /* * Passed OpenSSL objects are copied by cert_t; crt/key refcount will be * incremented, stack will be duplicated. - */ -cert_t * -cert_new3_copy(EVP_PKEY *key, X509 *crt, STACK_OF(X509) *chain) + * / +cert_t *cert_new3_copy(EVP_PKEY *key, X509 *crt, STACK_OF(X509) *chain) { cert_t *c; @@ -82,12 +487,12 @@ cert_new3_copy(EVP_PKEY *key, X509 *crt, STACK_OF(X509) *chain) c->references = 1; return c; } +*/ /* * Load cert_t from file. - */ -cert_t * -cert_new_load(const char *filename) + * / +cert_t *cert_new_load(const char *filename) { cert_t *c; @@ -115,100 +520,14 @@ cert_new_load(const char *filename) c->references = 1; return c; } +*/ /* - * Increment reference count. - */ -void -cert_refcount_inc(cert_t *c) -{ - pthread_mutex_lock(&c->mutex); - c->references++; - pthread_mutex_unlock(&c->mutex); -} - -/* - * Thread-safe setter functions; they copy the value (refcounts are inc'd). - */ -void -cert_set_key(cert_t *c, EVP_PKEY *key) -{ - pthread_mutex_lock(&c->mutex); - if (c->key) { - EVP_PKEY_free(c->key); - } - c->key = key; - if (c->key) { - ssl_key_refcount_inc(c->key); - } - pthread_mutex_unlock(&c->mutex); -} -void -cert_set_crt(cert_t *c, X509 *crt) -{ - pthread_mutex_lock(&c->mutex); - if (c->crt) { - X509_free(c->crt); - } - c->crt = crt; - if (c->crt) { - ssl_x509_refcount_inc(c->crt); - } - pthread_mutex_unlock(&c->mutex); -} -void -cert_set_chain(cert_t *c, STACK_OF(X509) *chain) -{ - pthread_mutex_lock(&c->mutex); - if (c->chain) { - sk_X509_pop_free(c->chain, X509_free); - } - if (chain) { - c->chain = sk_X509_dup(chain); - for (int i = 0; i < sk_X509_num(c->chain); i++) { - ssl_x509_refcount_inc(sk_X509_value(c->chain, i)); - } - } else { - c->chain = NULL; - } - pthread_mutex_unlock(&c->mutex); -} - -/* - * Free keyring including internal objects. - */ -void -cert_free(cert_t *c) -{ - pthread_mutex_lock(&c->mutex); - c->references--; - if (c->references) { - pthread_mutex_unlock(&c->mutex); - return; - } - pthread_mutex_unlock(&c->mutex); - pthread_mutex_destroy(&c->mutex); - if (c->key) { - EVP_PKEY_free(c->key); - } - if (c->crt) { - X509_free(c->crt); - } - if (c->chain) { - sk_X509_pop_free(c->chain, X509_free); - } - free(c); -} - -struct key_keeper* key_keeper_init(const char* profile) -{ - -} - -void cert_mgr_async_get(struct future* future, struct key_keeper* mgr, int keyring_id, X509* origin_cert, struct event_base* evbase) +void key_keeper_async_ask(struct future * f, struct key_keeper * keeper, int keyring_id, + X509 * origin_cert, int is_cert_valid, struct event_base * evbase) { X509* orig_cert=SSL_get_peer_certificate(origssl); - //todo: need implement + //todo: need implement cert_t * keyring = NULL; if (opts->tgcrtdir) { @@ -315,36 +634,5 @@ void cert_mgr_async_get(struct future* future, struct key_keeper* mgr, int keyri return keyring; } -void cert_manager_free(cert_t * keyring) -{ - cert_free(keyring); - return; -} -#endif +*/ - -struct key_keeper * key_keeper_init(const char * profile, const char* section, void* logger) -{ - return NULL; -} - -struct key_keeper * key_keeper_destroy(struct key_keeper *keeper) -{ - return NULL; -} - -struct keyring* key_keeper_release_cert(future_result_t* result) -{ - return NULL; -} - -void key_keeper_free_keyring(struct keyring* cert) -{ - return; -} - -void key_keeper_async_ask(struct future * f, struct key_keeper * keeper, int keyring_id, - X509 * origin_cert, int is_cert_valid, struct event_base * evbase) -{ - return; -} diff --git a/platform/src/tfe_rpc.cpp b/platform/src/tfe_rpc.cpp new file mode 100644 index 0000000..3648697 --- /dev/null +++ b/platform/src/tfe_rpc.cpp @@ -0,0 +1,258 @@ +#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) + { + GET: + evhttp_make_request(connection, request, EVHTTP_REQ_GET, request_url); + break; + 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 new file mode 100644 index 0000000..f3116e2 --- /dev/null +++ b/platform/test/test_key_keeper.cpp @@ -0,0 +1,37 @@ +#include "key_keeper.h" +#include "tfe_future.h" +#include "ssl_utils.h" +#include "event2/event.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() +{ + void* logger = NULL; + 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"); + 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, 0, origin_cert, 0, evbase); + } +} + +void +ask_key_keeper_on_succ(void* result, void* user) +{ + printf("call ask_key_keeper_on_succ\n"); +} + +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 new file mode 100644 index 0000000..b4b7279 --- /dev/null +++ b/platform/test/test_tfe_rpc.cpp @@ -0,0 +1,50 @@ +#include "tfe_rpc.h" +#include "tfe_utils.h" +#include "MESA/MESA_prof_load.h" +#include "MESA/MESA_handle_logger.h" +#include "string.h" + +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; + const char* status_msg = response->status_msg; + char* data = (char*)response->data; + int len = response->len; + *(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("len is %d\n", len); +} + + +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); +} + +int main() +{ + char cert_store_host[TFE_STRING_MAX]; + unsigned int cert_store_port; + const char* file_path = "./log/test_tfe_rpc.log"; + 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; + MESA_load_profile_string_def(profile, section, "cert_store_host", cert_store_host, sizeof(cert_store_host), "xxxxx"); + 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); + 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); +}