fix: 程序断掉后超时清理连接

This commit is contained in:
Mock
2026-04-10 13:21:24 +08:00
parent 6cedf859db
commit 6f727dbe57

View File

@@ -4,6 +4,7 @@
#include <unistd.h>
#define UDP_RELAY_BUF_SIZE (64U * 1024U)
#define UDP_RELAY_ROUTE_TIMEOUT_MS 30000U
struct udp_relay {
int downstream_fd;
@@ -15,6 +16,7 @@ struct udp_relay {
struct sockaddr_storage client_addr;
socklen_t client_addr_len;
int has_client;
uint32_t client_last_seen_ms;
struct udp_relay_route *routes;
pthread_mutex_t lock;
pthread_mutex_t log_mu;
@@ -35,8 +37,17 @@ typedef struct udp_relay_route {
uint32_t conv;
struct sockaddr_storage client_addr;
socklen_t client_addr_len;
uint32_t last_seen_ms;
} udp_relay_route_t;
static uint32_t udp_relay_now_ms(void) {
return omni_now_millis32();
}
static uint32_t udp_relay_elapsed_ms(uint32_t now_ms, uint32_t then_ms) {
return now_ms - then_ms;
}
static void udp_relay_parse_kcp_summary(const uint8_t *packet, size_t len, int *has_conv, uint32_t *conv, size_t *segment_count) {
size_t offset = 0;
size_t count = 0;
@@ -144,22 +155,61 @@ static void udp_relay_record_client(udp_relay_t *relay, const struct sockaddr_st
memcpy(&relay->client_addr, addr, sizeof(*addr));
relay->client_addr_len = addr_len;
relay->has_client = 1;
relay->client_last_seen_ms = udp_relay_now_ms();
pthread_mutex_unlock(&relay->lock);
}
static void udp_relay_prune_routes_locked(udp_relay_t *relay, uint32_t now_ms) {
udp_relay_route_t *prev = NULL;
udp_relay_route_t *route;
if (relay == NULL) {
return;
}
route = relay->routes;
while (route != NULL) {
udp_relay_route_t *next = route->next;
if (udp_relay_elapsed_ms(now_ms, route->last_seen_ms) >= UDP_RELAY_ROUTE_TIMEOUT_MS) {
if (prev == NULL) {
relay->routes = next;
} else {
prev->next = next;
}
free(route);
route = next;
continue;
}
prev = route;
route = next;
}
if (relay->has_client && udp_relay_elapsed_ms(now_ms, relay->client_last_seen_ms) >= UDP_RELAY_ROUTE_TIMEOUT_MS) {
relay->has_client = 0;
relay->client_addr_len = 0;
memset(&relay->client_addr, 0, sizeof(relay->client_addr));
}
}
static int udp_relay_record_route(udp_relay_t *relay, uint32_t conv, const struct sockaddr_storage *addr, socklen_t addr_len) {
udp_relay_route_t *route;
uint32_t now_ms;
if (relay == NULL || addr == NULL || addr_len == 0) {
errno = EINVAL;
return -1;
}
now_ms = udp_relay_now_ms();
pthread_mutex_lock(&relay->lock);
udp_relay_prune_routes_locked(relay, now_ms);
for (route = relay->routes; route != NULL; route = route->next) {
if (route->conv == conv) {
memcpy(&route->client_addr, addr, sizeof(*addr));
route->client_addr_len = addr_len;
route->last_seen_ms = now_ms;
pthread_mutex_unlock(&relay->lock);
return 0;
}
@@ -173,6 +223,7 @@ static int udp_relay_record_route(udp_relay_t *relay, uint32_t conv, const struc
route->conv = conv;
memcpy(&route->client_addr, addr, sizeof(*addr));
route->client_addr_len = addr_len;
route->last_seen_ms = now_ms;
route->next = relay->routes;
relay->routes = route;
pthread_mutex_unlock(&relay->lock);
@@ -181,8 +232,11 @@ static int udp_relay_record_route(udp_relay_t *relay, uint32_t conv, const struc
static int udp_relay_copy_client(udp_relay_t *relay, struct sockaddr_storage *addr, socklen_t *addr_len) {
int has_client;
uint32_t now_ms;
now_ms = udp_relay_now_ms();
pthread_mutex_lock(&relay->lock);
udp_relay_prune_routes_locked(relay, now_ms);
has_client = relay->has_client;
if (has_client) {
memcpy(addr, &relay->client_addr, sizeof(*addr));
@@ -194,8 +248,11 @@ static int udp_relay_copy_client(udp_relay_t *relay, struct sockaddr_storage *ad
static int udp_relay_copy_route(udp_relay_t *relay, uint32_t conv, struct sockaddr_storage *addr, socklen_t *addr_len) {
udp_relay_route_t *route;
uint32_t now_ms;
now_ms = udp_relay_now_ms();
pthread_mutex_lock(&relay->lock);
udp_relay_prune_routes_locked(relay, now_ms);
for (route = relay->routes; route != NULL; route = route->next) {
if (route->conv == conv) {
memcpy(addr, &route->client_addr, sizeof(*addr));
@@ -305,8 +362,11 @@ static void *udp_relay_forward_upstream_to_downstream(void *arg) {
udp_relay_print_packet(relay, "relay_upstream_rx", relay->upstream_local_addr, &relay->upstream_addr, relay->upstream_addr_len, buffer, (size_t) n);
udp_relay_parse_kcp_summary(buffer, (size_t) n, &has_conv, &conv, NULL);
if ((has_conv && !udp_relay_copy_route(relay, conv, &client_addr, &client_addr_len)) &&
!udp_relay_copy_client(relay, &client_addr, &client_addr_len)) {
if (has_conv && !udp_relay_copy_route(relay, conv, &client_addr, &client_addr_len)) {
udp_relay_print_packet(relay, "relay_upstream_drop_unknown_conv", relay->upstream_local_addr, &relay->upstream_addr, relay->upstream_addr_len, buffer, (size_t) n);
continue;
}
if (!has_conv && !udp_relay_copy_client(relay, &client_addr, &client_addr_len)) {
udp_relay_print_packet(relay, "relay_upstream_drop_no_client", relay->upstream_local_addr, &relay->upstream_addr, relay->upstream_addr_len, buffer, (size_t) n);
continue;
}