2018-08-23 11:23:05 +08:00
|
|
|
/*
|
|
|
|
|
* Proxy engine, built around libevent 2.x.
|
|
|
|
|
*/
|
2018-08-21 16:11:50 +08:00
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
#include <sys/un.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <pthread.h>
|
|
|
|
|
|
|
|
|
|
#include <event2/event.h>
|
|
|
|
|
#include <event2/listener.h>
|
|
|
|
|
#include <event2/bufferevent.h>
|
|
|
|
|
#include <event2/bufferevent_ssl.h>
|
|
|
|
|
#include <event2/buffer.h>
|
|
|
|
|
#include <event2/thread.h>
|
|
|
|
|
|
|
|
|
|
#include <MESA/MESA_handle_logger.h>
|
|
|
|
|
#include <tfe_utils.h>
|
2018-09-02 15:46:39 +08:00
|
|
|
#include <tfe_future.h>
|
2018-08-21 16:11:50 +08:00
|
|
|
#include <tfe_stream.h>
|
2018-08-27 21:10:45 +08:00
|
|
|
#include <platform.h>
|
2018-08-23 11:23:05 +08:00
|
|
|
#include <proxy.h>
|
2018-08-27 21:10:45 +08:00
|
|
|
#include <kni_acceptor.h>
|
|
|
|
|
#include <tcp_stream.h>
|
2018-08-30 15:53:41 +08:00
|
|
|
#include <MESA/MESA_prof_load.h>
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
static int signals[] = {SIGTERM, SIGQUIT, SIGHUP, SIGPIPE, SIGUSR1};
|
2018-08-23 11:23:05 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
/* Global Resource */
|
|
|
|
|
void * g_default_logger = NULL;
|
|
|
|
|
struct tfe_proxy * g_default_proxy = NULL;
|
2018-08-23 11:23:05 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
/* Per thread resource */
|
|
|
|
|
thread_local unsigned int __currect_thread_id = 0;
|
|
|
|
|
thread_local void * __currect_default_logger = NULL;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
struct tfe_thread_ctx * tfe_proxy_thread_ctx_acquire(struct tfe_proxy * ctx)
|
|
|
|
|
{
|
|
|
|
|
unsigned int min_thread_id = 0;
|
|
|
|
|
unsigned int min_load = 0;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
for(unsigned int tid = 0; tid < ctx->nr_work_threads; tid++)
|
|
|
|
|
{
|
|
|
|
|
struct tfe_thread_ctx * thread_ctx = ctx->work_threads[tid];
|
|
|
|
|
min_thread_id = min_load > thread_ctx->load ? tid : min_thread_id;
|
|
|
|
|
min_load = min_load > thread_ctx->load ? thread_ctx->load : min_load;
|
|
|
|
|
}
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
ctx->work_threads[min_thread_id]->load++;
|
|
|
|
|
return ctx->work_threads[min_thread_id];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void tfe_proxy_thread_ctx_release(struct tfe_thread_ctx * thread_ctx)
|
2018-08-21 16:11:50 +08:00
|
|
|
{
|
2018-08-30 15:53:41 +08:00
|
|
|
thread_ctx->load--;
|
2018-08-21 16:11:50 +08:00
|
|
|
}
|
2018-08-30 15:53:41 +08:00
|
|
|
|
|
|
|
|
int tfe_proxy_fds_accept(struct tfe_proxy * ctx, const struct tfe_proxy_accept_para * para)
|
2018-08-21 16:11:50 +08:00
|
|
|
{
|
2018-08-30 15:53:41 +08:00
|
|
|
tfe_thread_ctx * worker_thread_ctx = tfe_proxy_thread_ctx_acquire(ctx);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
struct tfe_stream * stream = tfe_stream_create(ctx, worker_thread_ctx);
|
|
|
|
|
tfe_stream_option_set(stream, TFE_STREAM_OPT_SESSION_TYPE, ¶->session_type, sizeof(para->session_type));
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
/* FOR DEBUG */
|
|
|
|
|
if (para->passthrough || ctx->tcp_all_passthrough)
|
|
|
|
|
{
|
|
|
|
|
bool __true = true;
|
2018-09-03 10:30:47 +08:00
|
|
|
enum tfe_stream_proto __session_type = STREAM_PROTO_PLAIN;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
tfe_stream_option_set(stream, TFE_STREAM_OPT_PASSTHROUGH, &__true, sizeof(__true));
|
|
|
|
|
tfe_stream_option_set(stream, TFE_STREAM_OPT_SESSION_TYPE, &__session_type, sizeof(__session_type));
|
|
|
|
|
}
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
tfe_stream_init_by_fds(stream, para->downstream_fd, para->upstream_fd);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
TFE_LOG_DEBUG(ctx->logger, "%p, Fds(downstream = %d, upstream = %d, type = %d) accepted",
|
|
|
|
|
stream, para->downstream_fd, para->upstream_fd, para->session_type);
|
|
|
|
|
|
|
|
|
|
return 0;
|
2018-08-21 16:11:50 +08:00
|
|
|
}
|
|
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
void tfe_proxy_loopbreak(tfe_proxy * ctx)
|
|
|
|
|
{
|
|
|
|
|
event_base_loopbreak(ctx->evbase);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void tfe_proxy_free(tfe_proxy * ctx)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
static void __dummy_event_handler(evutil_socket_t fd, short what, void * arg)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
static void __signal_handler_cb(evutil_socket_t fd, short what, void * arg)
|
2018-08-21 16:11:50 +08:00
|
|
|
{
|
|
|
|
|
tfe_proxy * ctx = (tfe_proxy *) arg;
|
|
|
|
|
switch (fd)
|
|
|
|
|
{
|
|
|
|
|
case SIGTERM:
|
|
|
|
|
case SIGQUIT:
|
|
|
|
|
case SIGINT:
|
|
|
|
|
case SIGHUP:
|
|
|
|
|
break;
|
|
|
|
|
case SIGUSR1:
|
|
|
|
|
break;
|
|
|
|
|
case SIGPIPE:
|
2018-08-30 15:53:41 +08:00
|
|
|
TFE_LOG_ERROR(ctx->logger, "Warning: Received SIGPIPE; ignoring.\n");
|
2018-08-21 16:11:50 +08:00
|
|
|
break;
|
|
|
|
|
default:
|
2018-08-30 15:53:41 +08:00
|
|
|
TFE_LOG_ERROR(ctx->logger, "Warning: Received unexpected signal %i\n", fd);
|
2018-08-21 16:11:50 +08:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
static void __gc_handler_cb(evutil_socket_t fd, short what, void * arg)
|
2018-08-21 16:11:50 +08:00
|
|
|
{
|
|
|
|
|
tfe_proxy * ctx = (tfe_proxy *) arg;
|
|
|
|
|
(void)fd;
|
|
|
|
|
(void)what;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
static void * __thread_ctx_entry(void * arg)
|
2018-08-21 16:11:50 +08:00
|
|
|
{
|
2018-08-30 15:53:41 +08:00
|
|
|
struct tfe_thread_ctx * ctx = (struct tfe_thread_ctx *) arg;
|
|
|
|
|
struct timeval timer_delay = {60, 0};
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
struct event * ev = event_new(ctx->evbase, -1, EV_PERSIST, __dummy_event_handler, NULL);
|
|
|
|
|
if (unlikely(ev == NULL))
|
2018-08-21 16:11:50 +08:00
|
|
|
{
|
2018-08-30 15:53:41 +08:00
|
|
|
TFE_LOG_ERROR(g_default_logger, "Failed at creating dummy event for thread %u", ctx->thread_id);
|
|
|
|
|
exit(EXIT_FAILURE);
|
2018-08-21 16:11:50 +08:00
|
|
|
}
|
|
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
evtimer_add(ev, &timer_delay);
|
|
|
|
|
ctx->running = 1;
|
|
|
|
|
__currect_thread_id = ctx->thread_id;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
TFE_LOG_INFO(g_default_logger, "Thread %u is running...", ctx->thread_id);
|
|
|
|
|
event_base_dispatch(ctx->evbase);
|
|
|
|
|
event_free(ev);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
return (void *)NULL;
|
2018-08-21 16:11:50 +08:00
|
|
|
}
|
|
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
struct tfe_thread_ctx * __thread_ctx_create(struct tfe_proxy * proxy, unsigned int thread_id)
|
2018-08-21 16:11:50 +08:00
|
|
|
{
|
2018-08-30 15:53:41 +08:00
|
|
|
struct tfe_thread_ctx * __thread_ctx = ALLOC(struct tfe_thread_ctx, 1);
|
|
|
|
|
assert(__thread_ctx != NULL);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
__thread_ctx->thread_id = thread_id;
|
|
|
|
|
__thread_ctx->evbase = event_base_new();
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
int ret = pthread_create(&__thread_ctx->thr, NULL, __thread_ctx_entry, (void *)__thread_ctx);
|
|
|
|
|
if (unlikely(ret < 0))
|
2018-08-21 16:11:50 +08:00
|
|
|
{
|
2018-08-30 15:53:41 +08:00
|
|
|
TFE_LOG_ERROR(proxy->logger, "Failed at pthread_create() for thread %d: %s", strerror(errno));
|
|
|
|
|
goto __errout;
|
2018-08-21 16:11:50 +08:00
|
|
|
}
|
|
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
return __thread_ctx;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
__errout:
|
|
|
|
|
if (__thread_ctx != NULL && __thread_ctx->evbase != NULL) event_base_free(__thread_ctx->evbase);
|
|
|
|
|
if (__thread_ctx != NULL) free(__thread_ctx);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
int tfe_proxy_config(struct tfe_proxy * proxy, const char * profile)
|
|
|
|
|
{
|
|
|
|
|
MESA_load_profile_uint_def(profile, "main", "nr_worker_threads", &proxy->nr_work_threads, 1);
|
|
|
|
|
MESA_load_profile_uint_def(profile, "debug", "passthrough_all_tcp", &proxy->tcp_all_passthrough, 0);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2018-08-21 16:11:50 +08:00
|
|
|
|
|
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
#define CHECK_OR_EXIT(condition, fmt, ...) \
|
|
|
|
|
do { if(!(condition)) { TFE_LOG_ERROR(g_default_logger, fmt, ##__VA_ARGS__); exit(EXIT_FAILURE); } } while(0) \
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
const char* main_profile="./conf/tfe.conf";
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
g_default_logger = MESA_create_runtime_log_handle("log/tfe.log", RLOG_LV_DEBUG);
|
|
|
|
|
if (unlikely(g_default_logger == NULL))
|
2018-08-21 16:11:50 +08:00
|
|
|
{
|
2018-08-30 15:53:41 +08:00
|
|
|
TFE_LOG_ERROR(g_default_logger, "Failed at creating default logger: %s", "log/tfe.log");
|
|
|
|
|
exit(EXIT_FAILURE);
|
2018-08-21 16:11:50 +08:00
|
|
|
}
|
2018-09-02 15:46:39 +08:00
|
|
|
|
|
|
|
|
future_promise_library_init();
|
2018-08-30 15:53:41 +08:00
|
|
|
/* PROXY INSTANCE */
|
|
|
|
|
g_default_proxy = ALLOC(struct tfe_proxy, 1);
|
|
|
|
|
assert(g_default_proxy);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
/* CONFIG */
|
|
|
|
|
int ret = tfe_proxy_config(g_default_proxy, main_profile);
|
|
|
|
|
CHECK_OR_EXIT(ret == 0, "Failed at loading profile %s, Exit.", main_profile);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
/* LOGGER */
|
|
|
|
|
g_default_proxy->logger = g_default_logger;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
/* MAIN THREAD EVBASE */
|
|
|
|
|
g_default_proxy->evbase = event_base_new();
|
|
|
|
|
CHECK_OR_EXIT(g_default_proxy->evbase, "Failed at creating evbase for main thread. Exit.");
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
/* GC EVENT */
|
|
|
|
|
g_default_proxy->gcev = event_new(g_default_proxy->evbase, -1, EV_PERSIST, __gc_handler_cb, g_default_proxy);
|
|
|
|
|
CHECK_OR_EXIT(g_default_proxy->gcev, "Failed at creating GC event. Exit. ");
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-31 10:39:25 +08:00
|
|
|
/* SSL INIT */
|
|
|
|
|
g_default_proxy->ssl_mgr_handler = ssl_manager_init(main_profile, "ssl",
|
|
|
|
|
g_default_proxy->evbase, g_default_logger, NULL);
|
|
|
|
|
CHECK_OR_EXIT(g_default_proxy->ssl_mgr_handler, "Failed at init SSL manager. Exit.");
|
|
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
/* MODULE INIT */
|
|
|
|
|
g_default_proxy->kni_acceptor_handler = kni_acceptor_init(g_default_proxy, main_profile, g_default_logger);
|
|
|
|
|
CHECK_OR_EXIT(g_default_proxy->kni_acceptor_handler, "Failed at init KNI acceptor. Exit. ");
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
struct timeval gc_delay = {60, 0};
|
|
|
|
|
evtimer_add(g_default_proxy->gcev , &gc_delay);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
/* WORKER THREAD */
|
|
|
|
|
for(unsigned tid = 0; tid < g_default_proxy->nr_work_threads; tid++)
|
|
|
|
|
{
|
|
|
|
|
g_default_proxy->work_threads[tid] = __thread_ctx_create(g_default_proxy, tid);
|
|
|
|
|
CHECK_OR_EXIT(g_default_proxy->work_threads[tid], "Failed at creating thread %u", tid);
|
|
|
|
|
}
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
TFE_LOG_ERROR(g_default_logger, "Tango Frontend Engine initialized. ");
|
|
|
|
|
event_base_dispatch(g_default_proxy->evbase);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-30 15:53:41 +08:00
|
|
|
return 0;
|
2018-08-21 16:11:50 +08:00
|
|
|
}
|