add feature-key-keeper

This commit is contained in:
崔一鸣
2018-09-04 15:47:41 +08:00
parent b87a9db3dc
commit 636e41cfca
7 changed files with 904 additions and 167 deletions

View File

@@ -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 ./)

View File

@@ -1,8 +1,10 @@
#pragma once
#include <openssl/ssl.h>
#include "ssl_utils.h"
#include <pthread.h>
#include <tfe_future.h>
#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);
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();

View File

@@ -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);

View File

@@ -1,67 +1,472 @@
#include <key_keeper.h>
#include "key_keeper.h"
#include <string.h>
#include <ssl_utils.h>
struct key_keeper
{
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#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,97 +520,11 @@ 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
@@ -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;
}

258
platform/src/tfe_rpc.cpp Normal file
View File

@@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sys/queue.h>
#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;
}
*/

View File

@@ -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");
}

View File

@@ -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);
}