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>
|
|
|
|
|
#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-21 16:11:50 +08:00
|
|
|
|
2018-08-23 11:23:05 +08:00
|
|
|
static int signals[] = {SIGTERM, SIGQUIT, SIGHUP, SIGINT, SIGPIPE, SIGUSR1};
|
|
|
|
|
|
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
|
|
|
|
const char * module_name_pxy = "TFE_PXY";
|
|
|
|
|
extern struct tfe_instance * g_tfe_instance;
|
|
|
|
|
|
|
|
|
|
__thread int __currect_thread_id;
|
|
|
|
|
|
|
|
|
|
static void __dummy_event_handler(evutil_socket_t fd, short what, void * arg)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Thread entry point; runs the event loop of the event base.
|
|
|
|
|
* Does not exit until the libevent loop is broken explicitly.
|
|
|
|
|
*/
|
|
|
|
|
static void * __tfe_thrmgr_thread_entry(void * arg)
|
|
|
|
|
{
|
|
|
|
|
struct tfe_thread_ctx * ctx = (struct tfe_thread_ctx *) arg;
|
|
|
|
|
struct timeval timer_delay = {60, 0};
|
|
|
|
|
|
|
|
|
|
struct event * ev;
|
|
|
|
|
ev = event_new(ctx->evbase, -1, EV_PERSIST, __dummy_event_handler, NULL);
|
|
|
|
|
|
|
|
|
|
if (!ev) return (void *)NULL;
|
|
|
|
|
|
|
|
|
|
evtimer_add(ev, &timer_delay);
|
|
|
|
|
ctx->running = 1;
|
|
|
|
|
|
|
|
|
|
__currect_thread_id = ctx->thread_id;
|
|
|
|
|
event_base_dispatch(ctx->evbase);
|
|
|
|
|
event_free(ev);
|
|
|
|
|
|
|
|
|
|
return (void *)NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void proxy_signal_cb(evutil_socket_t fd, short what, void * arg)
|
|
|
|
|
{
|
|
|
|
|
tfe_proxy * ctx = (tfe_proxy *) arg;
|
|
|
|
|
switch (fd)
|
|
|
|
|
{
|
|
|
|
|
case SIGTERM:
|
|
|
|
|
case SIGQUIT:
|
|
|
|
|
case SIGINT:
|
|
|
|
|
case SIGHUP:
|
|
|
|
|
break;
|
|
|
|
|
case SIGUSR1:
|
|
|
|
|
break;
|
|
|
|
|
case SIGPIPE:
|
2018-08-23 11:23:05 +08:00
|
|
|
TFE_LOG_ERROR(ctx->main_logger, "Warning: Received SIGPIPE; ignoring.\n");
|
2018-08-21 16:11:50 +08:00
|
|
|
break;
|
|
|
|
|
default:
|
2018-08-23 11:23:05 +08:00
|
|
|
TFE_LOG_ERROR(ctx->main_logger, "Warning: Received unexpected signal %i\n", fd);
|
2018-08-21 16:11:50 +08:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void proxy_gc_cb(evutil_socket_t fd, short what, void * arg)
|
|
|
|
|
{
|
|
|
|
|
tfe_proxy * ctx = (tfe_proxy *) arg;
|
|
|
|
|
(void)fd;
|
|
|
|
|
(void)what;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned int select_work_thread(struct tfe_proxy * pxy)
|
|
|
|
|
{
|
|
|
|
|
unsigned int min_thread_id = 0;
|
|
|
|
|
size_t min_load = pxy->work_threads[min_thread_id].load;
|
|
|
|
|
|
|
|
|
|
for (unsigned thread_id = 1; thread_id < pxy->nr_work_threads; thread_id++)
|
|
|
|
|
{
|
|
|
|
|
if (min_load > pxy->work_threads[thread_id].load)
|
|
|
|
|
{
|
|
|
|
|
min_load = pxy->work_threads[thread_id].load;
|
|
|
|
|
min_thread_id = thread_id;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxy->work_threads[min_thread_id].load++;
|
|
|
|
|
return min_thread_id;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Callback for accept events on the socket listener bufferevent.
|
|
|
|
|
*/
|
2018-08-23 11:23:05 +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-23 11:23:05 +08:00
|
|
|
unsigned int worker_tid = select_work_thread(ctx);
|
|
|
|
|
tfe_thread_ctx * worker_thread_ctx = &ctx->work_threads[worker_tid];
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-27 21:10:45 +08:00
|
|
|
struct tfe_stream * stream = tfe_stream_create(ctx, worker_thread_ctx);
|
|
|
|
|
tfe_stream_init_by_fds(stream, para->session_type, para->downstream_fd, para->upstream_fd);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
2018-08-27 21:10:45 +08:00
|
|
|
return 0;
|
2018-08-21 16:11:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set up the core event loop.
|
|
|
|
|
* Socket clisock is the privsep client socket used for binding to ports.
|
|
|
|
|
* Returns ctx on success, or NULL on error.
|
|
|
|
|
*/
|
2018-08-23 11:23:05 +08:00
|
|
|
struct tfe_proxy * tfe_proxy_new(const char * profile)
|
2018-08-21 16:11:50 +08:00
|
|
|
{
|
|
|
|
|
struct tfe_proxy * proxy = ALLOC(struct tfe_proxy, 1);
|
|
|
|
|
assert(proxy != NULL);
|
|
|
|
|
|
|
|
|
|
struct timeval gc_delay = {60, 0};
|
|
|
|
|
|
|
|
|
|
/* adds locking, only required if accessed from separate threads */
|
|
|
|
|
evthread_use_pthreads();
|
|
|
|
|
event_enable_debug_mode();
|
|
|
|
|
|
|
|
|
|
proxy->evbase = event_base_new();
|
|
|
|
|
proxy->nr_modules = 2;
|
|
|
|
|
proxy->modules = ALLOC(struct tfe_plugin, proxy->nr_modules);
|
|
|
|
|
|
|
|
|
|
proxy->modules[0].proto = APP_PROTO_HTTP1;
|
|
|
|
|
proxy->modules[1].proto = APP_PROTO_HTTP2;
|
|
|
|
|
|
|
|
|
|
proxy->work_threads = ALLOC(struct tfe_thread_ctx, proxy->nr_work_threads);
|
2018-08-23 11:23:05 +08:00
|
|
|
proxy->io_mod = kni_acceptor_init(proxy, profile, NULL);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < proxy->nr_work_threads; i++)
|
|
|
|
|
{
|
|
|
|
|
proxy->work_threads[i].thread_id = i;
|
|
|
|
|
proxy->work_threads[i].evbase = event_base_new();
|
|
|
|
|
proxy->work_threads[i].nr_modules = proxy->nr_modules;
|
|
|
|
|
proxy->work_threads[i].modules = proxy->modules;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Todo: Not handle signal if have mutliple proxy instance.
|
|
|
|
|
for (size_t i = 0; i < (sizeof(signals) / sizeof(int)); i++)
|
|
|
|
|
{
|
|
|
|
|
proxy->sev[i] = evsignal_new(proxy->evbase, signals[i], proxy_signal_cb, proxy);
|
|
|
|
|
if (!proxy->sev[i]) goto error_out;
|
|
|
|
|
evsignal_add(proxy->sev[i], NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proxy->gcev = event_new(proxy->evbase, -1, EV_PERSIST, proxy_gc_cb, proxy);
|
2018-08-23 11:23:05 +08:00
|
|
|
if (!proxy->gcev) goto error_out;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
|
|
|
|
evtimer_add(proxy->gcev, &gc_delay);
|
|
|
|
|
return proxy;
|
|
|
|
|
|
|
|
|
|
error_out:
|
|
|
|
|
if (proxy->gcev)
|
|
|
|
|
{
|
|
|
|
|
event_free(proxy->gcev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < (sizeof(proxy->sev) / sizeof(proxy->sev[0])); i++)
|
|
|
|
|
{
|
|
|
|
|
if (proxy->sev[i])
|
|
|
|
|
{
|
|
|
|
|
event_free(proxy->sev[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (typeof(proxy->nr_work_threads) i = 0; i < proxy->nr_work_threads; i++)
|
|
|
|
|
{
|
|
|
|
|
proxy->work_threads[i].thread_id = i;
|
|
|
|
|
event_base_free(proxy->work_threads[i].evbase);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
event_base_free(proxy->evbase);
|
|
|
|
|
|
|
|
|
|
free(proxy);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Run the event loop. Returns when the event loop is cancelled by a signal
|
|
|
|
|
* or on failure.
|
|
|
|
|
*/
|
|
|
|
|
void tfe_proxy_run(struct tfe_proxy * proxy)
|
|
|
|
|
{
|
|
|
|
|
unsigned int thread_id;
|
|
|
|
|
for (thread_id = 0; thread_id < proxy->nr_work_threads; thread_id++)
|
|
|
|
|
{
|
|
|
|
|
if (pthread_create(&(proxy->work_threads[thread_id].thr), NULL,
|
|
|
|
|
__tfe_thrmgr_thread_entry, &(proxy->work_threads[thread_id])))
|
|
|
|
|
{
|
|
|
|
|
MESA_handle_runtime_log(proxy->main_logger, RLOG_LV_FATAL, proxy->name, "pthread_create failed.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (!proxy->work_threads[thread_id].running)
|
|
|
|
|
{
|
|
|
|
|
sched_yield();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
event_base_dispatch(proxy->evbase);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Break the loop of the proxy, causing the tfe_proxy_run to return.
|
|
|
|
|
*/
|
|
|
|
|
void proxy_loopbreak(tfe_proxy * ctx)
|
|
|
|
|
{
|
|
|
|
|
event_base_loopbreak(ctx->evbase);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Free the proxy data structures.
|
|
|
|
|
*/
|
|
|
|
|
void proxy_free(tfe_proxy * ctx)
|
|
|
|
|
{
|
|
|
|
|
|
2018-08-23 11:23:05 +08:00
|
|
|
}
|
2018-08-21 16:11:50 +08:00
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
const char* main_profile="./conf/tfe_main.conf";
|
|
|
|
|
|
|
|
|
|
tfe_proxy *proxy=NULL;
|
|
|
|
|
void* wcfg_handle=NULL;
|
|
|
|
|
|
|
|
|
|
//TODO: Initiate Local Cert Cache, Decryption Mirror, Field Stat, Logger and etc.
|
|
|
|
|
//NOTICE: Maat, Cert Store,Tango Cache are initiated in bussiness plugin.
|
|
|
|
|
|
2018-08-23 11:23:05 +08:00
|
|
|
proxy=tfe_proxy_new(main_profile);
|
2018-08-21 16:11:50 +08:00
|
|
|
tfe_proxy_run(proxy);
|
|
|
|
|
proxy_free(proxy);
|
|
|
|
|
}
|