tinyproxy.c
raw ยท 3221 bytes
#include <event2/event.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "klog.h"
#include "signal.h"
#include "file_conf.h"
#include "tcp_route.h"
static void usage(FILE *out, const char *prog)
{
fprintf(out,
"usage: %s [-c config-file]\n"
"\n"
"options:\n"
" -c FILE path to config file (default: tinyproxy.conf)\n"
" -v show the version\n"
" -h show this help\n",
prog);
}
int main(int argc, char **argv)
{
const char *conf_path = "tinyproxy.conf";
int opt;
while ((opt = getopt(argc, argv, "c:h:v")) != -1) {
switch (opt) {
case 'c':
if (optarg == NULL || optarg[0] == '\0') {
LOG_ERROR("missing config path after -c");
return 2;
}
conf_path = optarg;
break;
case 'h':
usage(stdout, argv[0]);
return 0;
case 'v':
fprintf(stdout, "tinyproxy v0.0.1\n");
return 0;
default:
usage(stderr, argv[0]);
return 2;
}
}
if (optind != argc) {
LOG_ERROR("unexpected argument", "argv", _LOGV(argv[optind]));
usage(stderr, argv[0]);
return 2;
}
struct route *routes = NULL;
size_t route_count = 0;
int rc = load_routes_from_file(conf_path, &routes, &route_count);
if (rc != 0) {
LOG_ERROR("failed to load config", "path", conf_path, "msg", _LOGV(strerror(-rc)));
return 1;
}
if (route_count == 0) {
LOG_ERROR("config has no routes", "path", _LOGV(conf_path));
free_routes(routes);
return 1;
}
struct listener_ctx **tcp_ctxs = calloc(route_count, sizeof(*tcp_ctxs));
if (tcp_ctxs == NULL) {
free_routes(routes);
return 1;
}
size_t tcp_ctx_count = 0;
struct event_base *base = event_base_new();
if (base == NULL) {
LOG_ERROR("event_base_new failed");
return 1;
}
struct signal_events signals;
if (setup_signal_handlers(base, &signals) != 0) {
LOG_ERROR("failed to setup signal handlers");
event_base_free(base);
free_routes(routes);
return 1;
}
struct worker w = {
.base = base,
.id = 0,
};
for (size_t i = 0; i < route_count; i++) {
const struct route *r = &routes[i];
switch (r->proto) {
case PROTO_TCP:
rc = start_tcp_route(&w, r, &tcp_ctxs[tcp_ctx_count]);
if (rc == 0) {
tcp_ctx_count++;
}
break;
case PROTO_UDP:
// rc = start_udp_route(r);
LOG_WARN("skipping udp route: Not implemented yet");
break;
default:
LOG_ERROR("route has unknown protocol", "line", _LOGV(r->line_no));
rc = -EINVAL;
break;
}
if (rc != 0) {
LOG_ERROR("failed to start route",
"line", _LOGV(r->line_no),
"listen_host", _LOGV(r->listen_port),
"listen_port", _LOGV(r->listen_host),
"upstream_host", _LOGV(r->upstream_host),
"upstream_port", _LOGV(r->upstream_port)
);
for (size_t j = 0; j < tcp_ctx_count; j++) {
free_tcp_route(tcp_ctxs[j]);
}
free(tcp_ctxs);
event_base_free(base);
free_routes(routes);
return 1;
}
}
rc = event_base_dispatch(base);
for (size_t i = 0; i < tcp_ctx_count; i++) {
free_tcp_route(tcp_ctxs[i]);
}
free_signal_handlers(&signals);
free(tcp_ctxs);
event_base_free(base);
free_routes(routes);
if (rc != 0) {
LOG_ERROR("event loop failed", "msg", _LOGV(strerror(-rc)));
return 1;
}
return 0;
}