fix: 当前的 relay 实现原来只记了一个“最后发包的下游客户端地址”
This commit is contained in:
@@ -15,6 +15,7 @@ struct udp_relay {
|
||||
struct sockaddr_storage client_addr;
|
||||
socklen_t client_addr_len;
|
||||
int has_client;
|
||||
struct udp_relay_route *routes;
|
||||
pthread_mutex_t lock;
|
||||
pthread_mutex_t log_mu;
|
||||
pthread_mutex_t state_mu;
|
||||
@@ -29,6 +30,13 @@ struct udp_relay {
|
||||
int closed;
|
||||
};
|
||||
|
||||
typedef struct udp_relay_route {
|
||||
struct udp_relay_route *next;
|
||||
uint32_t conv;
|
||||
struct sockaddr_storage client_addr;
|
||||
socklen_t client_addr_len;
|
||||
} udp_relay_route_t;
|
||||
|
||||
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;
|
||||
@@ -139,6 +147,38 @@ static void udp_relay_record_client(udp_relay_t *relay, const struct sockaddr_st
|
||||
pthread_mutex_unlock(&relay->lock);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (relay == NULL || addr == NULL || addr_len == 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&relay->lock);
|
||||
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;
|
||||
pthread_mutex_unlock(&relay->lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
route = (udp_relay_route_t *) calloc(1, sizeof(*route));
|
||||
if (route == NULL) {
|
||||
pthread_mutex_unlock(&relay->lock);
|
||||
return -1;
|
||||
}
|
||||
route->conv = conv;
|
||||
memcpy(&route->client_addr, addr, sizeof(*addr));
|
||||
route->client_addr_len = addr_len;
|
||||
route->next = relay->routes;
|
||||
relay->routes = route;
|
||||
pthread_mutex_unlock(&relay->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int udp_relay_copy_client(udp_relay_t *relay, struct sockaddr_storage *addr, socklen_t *addr_len) {
|
||||
int has_client;
|
||||
|
||||
@@ -152,6 +192,42 @@ static int udp_relay_copy_client(udp_relay_t *relay, struct sockaddr_storage *ad
|
||||
return has_client;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
pthread_mutex_lock(&relay->lock);
|
||||
for (route = relay->routes; route != NULL; route = route->next) {
|
||||
if (route->conv == conv) {
|
||||
memcpy(addr, &route->client_addr, sizeof(*addr));
|
||||
*addr_len = route->client_addr_len;
|
||||
pthread_mutex_unlock(&relay->lock);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&relay->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void udp_relay_clear_routes(udp_relay_t *relay) {
|
||||
udp_relay_route_t *route;
|
||||
udp_relay_route_t *next;
|
||||
|
||||
if (relay == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&relay->lock);
|
||||
route = relay->routes;
|
||||
relay->routes = NULL;
|
||||
pthread_mutex_unlock(&relay->lock);
|
||||
|
||||
while (route != NULL) {
|
||||
next = route->next;
|
||||
free(route);
|
||||
route = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void *udp_relay_forward_downstream_to_upstream(void *arg) {
|
||||
udp_relay_t *relay = (udp_relay_t *) arg;
|
||||
uint8_t buffer[UDP_RELAY_BUF_SIZE];
|
||||
@@ -160,6 +236,8 @@ static void *udp_relay_forward_downstream_to_upstream(void *arg) {
|
||||
struct sockaddr_storage source;
|
||||
socklen_t source_len = sizeof(source);
|
||||
ssize_t n = recvfrom(relay->downstream_fd, buffer, sizeof(buffer), 0, (struct sockaddr *) &source, &source_len);
|
||||
int has_conv = 0;
|
||||
uint32_t conv = 0;
|
||||
|
||||
if (n < 0) {
|
||||
int errnum = errno;
|
||||
@@ -175,6 +253,10 @@ static void *udp_relay_forward_downstream_to_upstream(void *arg) {
|
||||
}
|
||||
|
||||
udp_relay_record_client(relay, &source, source_len);
|
||||
udp_relay_parse_kcp_summary(buffer, (size_t) n, &has_conv, &conv, NULL);
|
||||
if (has_conv) {
|
||||
(void) udp_relay_record_route(relay, conv, &source, source_len);
|
||||
}
|
||||
udp_relay_print_packet(relay, "relay_downstream_rx", relay->downstream_local_addr, &source, source_len, buffer, (size_t) n);
|
||||
for (;;) {
|
||||
if (send(relay->upstream_fd, buffer, (size_t) n, 0) >= 0) {
|
||||
@@ -205,6 +287,8 @@ static void *udp_relay_forward_upstream_to_downstream(void *arg) {
|
||||
struct sockaddr_storage client_addr;
|
||||
socklen_t client_addr_len = 0;
|
||||
ssize_t n = recv(relay->upstream_fd, buffer, sizeof(buffer), 0);
|
||||
int has_conv = 0;
|
||||
uint32_t conv = 0;
|
||||
|
||||
if (n < 0) {
|
||||
int errnum = errno;
|
||||
@@ -220,7 +304,9 @@ 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);
|
||||
if (!udp_relay_copy_client(relay, &client_addr, &client_addr_len)) {
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
@@ -409,6 +495,7 @@ void udp_relay_free(udp_relay_t *relay) {
|
||||
}
|
||||
udp_relay_close(relay);
|
||||
udp_relay_join_threads(relay);
|
||||
udp_relay_clear_routes(relay);
|
||||
pthread_mutex_destroy(&relay->lock);
|
||||
pthread_mutex_destroy(&relay->log_mu);
|
||||
pthread_cond_destroy(&relay->state_cond);
|
||||
|
||||
Reference in New Issue
Block a user