fix: 程序断掉后超时清理连接
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define UDP_RELAY_BUF_SIZE (64U * 1024U)
|
#define UDP_RELAY_BUF_SIZE (64U * 1024U)
|
||||||
|
#define UDP_RELAY_ROUTE_TIMEOUT_MS 30000U
|
||||||
|
|
||||||
struct udp_relay {
|
struct udp_relay {
|
||||||
int downstream_fd;
|
int downstream_fd;
|
||||||
@@ -15,6 +16,7 @@ struct udp_relay {
|
|||||||
struct sockaddr_storage client_addr;
|
struct sockaddr_storage client_addr;
|
||||||
socklen_t client_addr_len;
|
socklen_t client_addr_len;
|
||||||
int has_client;
|
int has_client;
|
||||||
|
uint32_t client_last_seen_ms;
|
||||||
struct udp_relay_route *routes;
|
struct udp_relay_route *routes;
|
||||||
pthread_mutex_t lock;
|
pthread_mutex_t lock;
|
||||||
pthread_mutex_t log_mu;
|
pthread_mutex_t log_mu;
|
||||||
@@ -35,8 +37,17 @@ typedef struct udp_relay_route {
|
|||||||
uint32_t conv;
|
uint32_t conv;
|
||||||
struct sockaddr_storage client_addr;
|
struct sockaddr_storage client_addr;
|
||||||
socklen_t client_addr_len;
|
socklen_t client_addr_len;
|
||||||
|
uint32_t last_seen_ms;
|
||||||
} udp_relay_route_t;
|
} 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) {
|
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 offset = 0;
|
||||||
size_t count = 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));
|
memcpy(&relay->client_addr, addr, sizeof(*addr));
|
||||||
relay->client_addr_len = addr_len;
|
relay->client_addr_len = addr_len;
|
||||||
relay->has_client = 1;
|
relay->has_client = 1;
|
||||||
|
relay->client_last_seen_ms = udp_relay_now_ms();
|
||||||
pthread_mutex_unlock(&relay->lock);
|
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) {
|
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;
|
udp_relay_route_t *route;
|
||||||
|
uint32_t now_ms;
|
||||||
|
|
||||||
if (relay == NULL || addr == NULL || addr_len == 0) {
|
if (relay == NULL || addr == NULL || addr_len == 0) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
now_ms = udp_relay_now_ms();
|
||||||
pthread_mutex_lock(&relay->lock);
|
pthread_mutex_lock(&relay->lock);
|
||||||
|
udp_relay_prune_routes_locked(relay, now_ms);
|
||||||
for (route = relay->routes; route != NULL; route = route->next) {
|
for (route = relay->routes; route != NULL; route = route->next) {
|
||||||
if (route->conv == conv) {
|
if (route->conv == conv) {
|
||||||
memcpy(&route->client_addr, addr, sizeof(*addr));
|
memcpy(&route->client_addr, addr, sizeof(*addr));
|
||||||
route->client_addr_len = addr_len;
|
route->client_addr_len = addr_len;
|
||||||
|
route->last_seen_ms = now_ms;
|
||||||
pthread_mutex_unlock(&relay->lock);
|
pthread_mutex_unlock(&relay->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -173,6 +223,7 @@ static int udp_relay_record_route(udp_relay_t *relay, uint32_t conv, const struc
|
|||||||
route->conv = conv;
|
route->conv = conv;
|
||||||
memcpy(&route->client_addr, addr, sizeof(*addr));
|
memcpy(&route->client_addr, addr, sizeof(*addr));
|
||||||
route->client_addr_len = addr_len;
|
route->client_addr_len = addr_len;
|
||||||
|
route->last_seen_ms = now_ms;
|
||||||
route->next = relay->routes;
|
route->next = relay->routes;
|
||||||
relay->routes = route;
|
relay->routes = route;
|
||||||
pthread_mutex_unlock(&relay->lock);
|
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) {
|
static int udp_relay_copy_client(udp_relay_t *relay, struct sockaddr_storage *addr, socklen_t *addr_len) {
|
||||||
int has_client;
|
int has_client;
|
||||||
|
uint32_t now_ms;
|
||||||
|
|
||||||
|
now_ms = udp_relay_now_ms();
|
||||||
pthread_mutex_lock(&relay->lock);
|
pthread_mutex_lock(&relay->lock);
|
||||||
|
udp_relay_prune_routes_locked(relay, now_ms);
|
||||||
has_client = relay->has_client;
|
has_client = relay->has_client;
|
||||||
if (has_client) {
|
if (has_client) {
|
||||||
memcpy(addr, &relay->client_addr, sizeof(*addr));
|
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) {
|
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;
|
udp_relay_route_t *route;
|
||||||
|
uint32_t now_ms;
|
||||||
|
|
||||||
|
now_ms = udp_relay_now_ms();
|
||||||
pthread_mutex_lock(&relay->lock);
|
pthread_mutex_lock(&relay->lock);
|
||||||
|
udp_relay_prune_routes_locked(relay, now_ms);
|
||||||
for (route = relay->routes; route != NULL; route = route->next) {
|
for (route = relay->routes; route != NULL; route = route->next) {
|
||||||
if (route->conv == conv) {
|
if (route->conv == conv) {
|
||||||
memcpy(addr, &route->client_addr, sizeof(*addr));
|
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_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);
|
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)) &&
|
if (has_conv && !udp_relay_copy_route(relay, conv, &client_addr, &client_addr_len)) {
|
||||||
!udp_relay_copy_client(relay, &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);
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user