224 lines
8.9 KiB
C
224 lines
8.9 KiB
C
#include "cli_parse.h"
|
|
#include "server_kcp_hub.h"
|
|
#include "server_udp_relay.h"
|
|
|
|
static void kcpserver_usage(FILE *out) {
|
|
fprintf(out, "usage: kcpserver [-mode hub|relay] [-listen addr] [-bind-device dev]\n");
|
|
fprintf(out, " [-latency-log path] [-kcp-ts-debug-log path]\n");
|
|
fprintf(out, " [-kcp-session-stats-log path] [-kcp-session-stats-interval 100ms]\n");
|
|
fprintf(out, " [-relay-remote addr] [-relay-listen addr] [-relay-peer addr]\n");
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
const char *mode = "hub";
|
|
const char *listen_addr = ":9002";
|
|
const char *bind_device = "";
|
|
const char *latency_log_path = "";
|
|
const char *packet_log_path = "";
|
|
const char *stats_log_path = "";
|
|
const char *stats_interval_raw = "";
|
|
const char *relay_listen_alias = "";
|
|
const char *relay_remote_addr = "";
|
|
const char *relay_peer_alias = "";
|
|
int stats_interval_ms = KCP_DEFAULT_STATS_INTERVAL_MS;
|
|
int i;
|
|
int rc = 1;
|
|
|
|
latency_logger_t *latency_logger = NULL;
|
|
kcp_packet_debug_logger_t *packet_logger = NULL;
|
|
kcp_session_stats_logger_t *stats_logger = NULL;
|
|
kcp_listener_t *listener = NULL;
|
|
kcp_hub_t *hub = NULL;
|
|
udp_relay_t *relay = NULL;
|
|
|
|
for (i = 1; i < argc; ++i) {
|
|
const char *value = NULL;
|
|
int handled;
|
|
|
|
if ((handled = cli_parse_value_flag(argc, argv, &i, argv[i], "-mode", &value)) < 0) {
|
|
fprintf(stderr, "kcpserver: flag -mode requires a value\n");
|
|
return 1;
|
|
} else if (handled) {
|
|
mode = value;
|
|
continue;
|
|
}
|
|
if ((handled = cli_parse_value_flag(argc, argv, &i, argv[i], "-listen", &value)) < 0) {
|
|
fprintf(stderr, "kcpserver: flag -listen requires a value\n");
|
|
return 1;
|
|
} else if (handled) {
|
|
listen_addr = value;
|
|
continue;
|
|
}
|
|
if ((handled = cli_parse_value_flag(argc, argv, &i, argv[i], "-bind-device", &value)) < 0) {
|
|
fprintf(stderr, "kcpserver: flag -bind-device requires a value\n");
|
|
return 1;
|
|
} else if (handled) {
|
|
bind_device = value;
|
|
continue;
|
|
}
|
|
if ((handled = cli_parse_value_flag(argc, argv, &i, argv[i], "-latency-log", &value)) < 0) {
|
|
fprintf(stderr, "kcpserver: flag -latency-log requires a value\n");
|
|
return 1;
|
|
} else if (handled) {
|
|
latency_log_path = value;
|
|
continue;
|
|
}
|
|
if ((handled = cli_parse_value_flag(argc, argv, &i, argv[i], "-kcp-ts-debug-log", &value)) < 0) {
|
|
fprintf(stderr, "kcpserver: flag -kcp-ts-debug-log requires a value\n");
|
|
return 1;
|
|
} else if (handled) {
|
|
packet_log_path = value;
|
|
continue;
|
|
}
|
|
if ((handled = cli_parse_value_flag(argc, argv, &i, argv[i], "-kcp-session-stats-log", &value)) < 0) {
|
|
fprintf(stderr, "kcpserver: flag -kcp-session-stats-log requires a value\n");
|
|
return 1;
|
|
} else if (handled) {
|
|
stats_log_path = value;
|
|
continue;
|
|
}
|
|
if ((handled = cli_parse_value_flag(argc, argv, &i, argv[i], "-kcp-session-stats-interval", &value)) < 0) {
|
|
fprintf(stderr, "kcpserver: flag -kcp-session-stats-interval requires a value\n");
|
|
return 1;
|
|
} else if (handled) {
|
|
stats_interval_raw = value;
|
|
continue;
|
|
}
|
|
if ((handled = cli_parse_value_flag(argc, argv, &i, argv[i], "-relay-listen", &value)) < 0) {
|
|
fprintf(stderr, "kcpserver: flag -relay-listen requires a value\n");
|
|
return 1;
|
|
} else if (handled) {
|
|
relay_listen_alias = value;
|
|
continue;
|
|
}
|
|
if ((handled = cli_parse_value_flag(argc, argv, &i, argv[i], "-relay-remote", &value)) < 0) {
|
|
fprintf(stderr, "kcpserver: flag -relay-remote requires a value\n");
|
|
return 1;
|
|
} else if (handled) {
|
|
relay_remote_addr = value;
|
|
continue;
|
|
}
|
|
if ((handled = cli_parse_value_flag(argc, argv, &i, argv[i], "-relay-peer", &value)) < 0) {
|
|
fprintf(stderr, "kcpserver: flag -relay-peer requires a value\n");
|
|
return 1;
|
|
} else if (handled) {
|
|
relay_peer_alias = value;
|
|
continue;
|
|
}
|
|
if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
|
|
kcpserver_usage(stdout);
|
|
return 0;
|
|
}
|
|
fprintf(stderr, "kcpserver: unknown argument %s\n", argv[i]);
|
|
kcpserver_usage(stderr);
|
|
return 1;
|
|
}
|
|
|
|
if (kcp_session_stats_parse_interval_ms(stats_interval_raw, &stats_interval_ms) != 0) {
|
|
fprintf(stderr, "kcpserver: invalid -kcp-session-stats-interval value %s\n", stats_interval_raw);
|
|
return 1;
|
|
}
|
|
|
|
if (relay_peer_alias[0] != '\0' && relay_remote_addr[0] != '\0' && strcmp(relay_peer_alias, relay_remote_addr) != 0) {
|
|
fprintf(stderr, "kcpserver: flags -relay-remote and -relay-peer must match when both are set\n");
|
|
return 1;
|
|
}
|
|
if (relay_remote_addr[0] == '\0' && relay_peer_alias[0] != '\0') {
|
|
relay_remote_addr = relay_peer_alias;
|
|
}
|
|
if (relay_peer_alias[0] != '\0') {
|
|
fprintf(stderr, "warning: flag -relay-peer is deprecated; use -relay-remote instead\n");
|
|
}
|
|
if (relay_listen_alias[0] != '\0') {
|
|
if (strcmp(mode, "relay") != 0) {
|
|
fprintf(stderr, "kcpserver: flag -relay-listen may only be used in relay mode\n");
|
|
return 1;
|
|
}
|
|
if (listen_addr[0] != '\0' && strcmp(listen_addr, ":9002") != 0 && strcmp(listen_addr, relay_listen_alias) != 0) {
|
|
fprintf(stderr, "kcpserver: flags -listen and -relay-listen must match when both are set in relay mode\n");
|
|
return 1;
|
|
}
|
|
listen_addr = relay_listen_alias;
|
|
fprintf(stderr, "warning: flag -relay-listen is deprecated; use -listen with -mode=relay instead\n");
|
|
}
|
|
|
|
if (strcmp(mode, "hub") == 0) {
|
|
if (relay_remote_addr[0] != '\0') {
|
|
fprintf(stderr, "kcpserver: flag -relay-remote may only be used in relay mode\n");
|
|
return 1;
|
|
}
|
|
if (latency_log_path[0] != '\0') {
|
|
latency_logger = latencylog_open_jsonl(latency_log_path);
|
|
if (latency_logger == NULL) {
|
|
fprintf(stderr, "kcpserver: open latency logger %s failed\n", latency_log_path);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
if (packet_log_path[0] != '\0') {
|
|
packet_logger = kcp_packet_debug_open_jsonl(packet_log_path);
|
|
if (packet_logger == NULL) {
|
|
fprintf(stderr, "kcpserver: open packet debug logger %s failed\n", packet_log_path);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
if (stats_log_path[0] != '\0') {
|
|
stats_logger = kcp_session_stats_open_jsonl(stats_log_path);
|
|
if (stats_logger == NULL) {
|
|
fprintf(stderr, "kcpserver: open session stats logger %s failed\n", stats_log_path);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
listener = kcp_listener_listen(listen_addr, bind_device, packet_logger, OMNI_NODE_ROLE_SERVER, "hub");
|
|
if (listener == NULL) {
|
|
fprintf(stderr, "kcpserver: listen on %s failed\n", listen_addr);
|
|
goto cleanup;
|
|
}
|
|
hub = kcp_hub_new(latency_logger, stats_logger, stats_interval_ms);
|
|
if (hub == NULL) {
|
|
fprintf(stderr, "kcpserver: create hub failed\n");
|
|
goto cleanup;
|
|
}
|
|
fprintf(stderr, "kcp hub listening on %s\n", listen_addr);
|
|
if (kcp_hub_serve_listener(hub, listener) != 0) {
|
|
fprintf(stderr, "kcpserver: serve listener failed\n");
|
|
goto cleanup;
|
|
}
|
|
rc = 0;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (strcmp(mode, "relay") == 0) {
|
|
if (bind_device[0] != '\0') {
|
|
fprintf(stderr, "kcpserver: flag -bind-device is not supported in relay mode\n");
|
|
return 1;
|
|
}
|
|
if (relay_remote_addr[0] == '\0') {
|
|
fprintf(stderr, "kcpserver: flag -relay-remote is required in relay mode\n");
|
|
return 1;
|
|
}
|
|
relay = udp_relay_open(listen_addr, relay_remote_addr);
|
|
if (relay == NULL) {
|
|
fprintf(stderr, "kcpserver: open udp relay %s -> %s failed\n", listen_addr, relay_remote_addr);
|
|
goto cleanup;
|
|
}
|
|
fprintf(stderr, "udp relay listening on %s and forwarding to %s\n", listen_addr, relay_remote_addr);
|
|
if (udp_relay_serve(relay) != 0) {
|
|
fprintf(stderr, "kcpserver: udp relay stopped with error\n");
|
|
goto cleanup;
|
|
}
|
|
rc = 0;
|
|
goto cleanup;
|
|
}
|
|
|
|
fprintf(stderr, "kcpserver: unsupported -mode=%s; want hub or relay\n", mode);
|
|
|
|
cleanup:
|
|
udp_relay_free(relay);
|
|
kcp_hub_free(hub);
|
|
kcp_listener_free(listener);
|
|
kcp_session_stats_close(stats_logger);
|
|
kcp_packet_debug_close(packet_logger);
|
|
latencylog_close(latency_logger);
|
|
return rc;
|
|
}
|