Files
OmniSocketGo/cmd/kcpserver.c

254 lines
10 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, " [-telemetry-peer peer-id] [-telemetry-interval 500ms]\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 *telemetry_peer_id = "";
const char *telemetry_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 telemetry_interval_ms = 500;
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], "-telemetry-peer", &value)) < 0) {
fprintf(stderr, "kcpserver: flag -telemetry-peer requires a value\n");
return 1;
} else if (handled) {
telemetry_peer_id = value;
continue;
}
if ((handled = cli_parse_value_flag(argc, argv, &i, argv[i], "-telemetry-interval", &value)) < 0) {
fprintf(stderr, "kcpserver: flag -telemetry-interval requires a value\n");
return 1;
} else if (handled) {
telemetry_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 (omni_parse_duration_ms(telemetry_interval_raw, 500, &telemetry_interval_ms) != 0) {
fprintf(stderr, "kcpserver: invalid -telemetry-interval value %s\n", telemetry_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;
}
if (telemetry_peer_id[0] != '\0' && kcp_hub_set_telemetry(hub, telemetry_peer_id, telemetry_interval_ms) != 0) {
fprintf(stderr, "kcpserver: configure telemetry peer %s failed\n", telemetry_peer_id);
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 (telemetry_peer_id[0] != '\0') {
fprintf(stderr, "kcpserver: flag -telemetry-peer may only be used in hub mode\n");
return 1;
}
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;
}