/* * Proxy engine, built around libevent 2.x. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int signals[] = {SIGTERM, SIGQUIT, SIGHUP, SIGINT, SIGPIPE, SIGUSR1}; 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: TFE_LOG_ERROR(ctx->main_logger, "Warning: Received SIGPIPE; ignoring.\n"); break; default: TFE_LOG_ERROR(ctx->main_logger, "Warning: Received unexpected signal %i\n", fd); 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. */ int tfe_proxy_fds_accept(struct tfe_proxy * ctx, const struct tfe_proxy_accept_para * para) { unsigned int worker_tid = select_work_thread(ctx); tfe_thread_ctx * worker_thread_ctx = &ctx->work_threads[worker_tid]; 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); return 0; } /* * 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. */ struct tfe_proxy * tfe_proxy_new(const char * profile) { 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); proxy->io_mod = kni_acceptor_init(proxy, profile, NULL); 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); if (!proxy->gcev) goto error_out; 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) { } 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. proxy=tfe_proxy_new(main_profile); tfe_proxy_run(proxy); proxy_free(proxy); }