fix: 当前 relay 很可能只记住了“一个下游 UDP 地址”
This commit is contained in:
@@ -5,6 +5,13 @@
|
|||||||
|
|
||||||
#define UDP_RELAY_BUF_SIZE (64U * 1024U)
|
#define UDP_RELAY_BUF_SIZE (64U * 1024U)
|
||||||
|
|
||||||
|
typedef struct udp_relay_client_entry {
|
||||||
|
struct udp_relay_client_entry *next;
|
||||||
|
uint32_t conv;
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
socklen_t addr_len;
|
||||||
|
} udp_relay_client_entry_t;
|
||||||
|
|
||||||
struct udp_relay {
|
struct udp_relay {
|
||||||
int downstream_fd;
|
int downstream_fd;
|
||||||
int upstream_fd;
|
int upstream_fd;
|
||||||
@@ -12,9 +19,10 @@ struct udp_relay {
|
|||||||
socklen_t upstream_addr_len;
|
socklen_t upstream_addr_len;
|
||||||
char downstream_local_addr[OMNI_MAX_ADDR_TEXT];
|
char downstream_local_addr[OMNI_MAX_ADDR_TEXT];
|
||||||
char upstream_local_addr[OMNI_MAX_ADDR_TEXT];
|
char upstream_local_addr[OMNI_MAX_ADDR_TEXT];
|
||||||
struct sockaddr_storage client_addr;
|
struct sockaddr_storage last_client_addr;
|
||||||
socklen_t client_addr_len;
|
socklen_t last_client_addr_len;
|
||||||
int has_client;
|
int has_last_client;
|
||||||
|
udp_relay_client_entry_t *clients;
|
||||||
pthread_mutex_t lock;
|
pthread_mutex_t lock;
|
||||||
pthread_mutex_t log_mu;
|
pthread_mutex_t log_mu;
|
||||||
pthread_mutex_t state_mu;
|
pthread_mutex_t state_mu;
|
||||||
@@ -131,22 +139,55 @@ static void udp_relay_note_result(udp_relay_t *relay, int rc, int errnum) {
|
|||||||
pthread_mutex_unlock(&relay->state_mu);
|
pthread_mutex_unlock(&relay->state_mu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void udp_relay_record_client(udp_relay_t *relay, const struct sockaddr_storage *addr, socklen_t addr_len) {
|
static udp_relay_client_entry_t *udp_relay_find_client_locked(udp_relay_t *relay, uint32_t conv) {
|
||||||
|
udp_relay_client_entry_t *entry;
|
||||||
|
|
||||||
|
for (entry = relay->clients; entry != NULL; entry = entry->next) {
|
||||||
|
if (entry->conv == conv) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void udp_relay_record_client(udp_relay_t *relay, int has_conv, uint32_t conv, const struct sockaddr_storage *addr, socklen_t addr_len) {
|
||||||
pthread_mutex_lock(&relay->lock);
|
pthread_mutex_lock(&relay->lock);
|
||||||
memcpy(&relay->client_addr, addr, sizeof(*addr));
|
memcpy(&relay->last_client_addr, addr, sizeof(*addr));
|
||||||
relay->client_addr_len = addr_len;
|
relay->last_client_addr_len = addr_len;
|
||||||
relay->has_client = 1;
|
relay->has_last_client = 1;
|
||||||
|
if (has_conv) {
|
||||||
|
udp_relay_client_entry_t *entry = udp_relay_find_client_locked(relay, conv);
|
||||||
|
if (entry == NULL) {
|
||||||
|
entry = (udp_relay_client_entry_t *) calloc(1, sizeof(*entry));
|
||||||
|
if (entry != NULL) {
|
||||||
|
entry->conv = conv;
|
||||||
|
entry->next = relay->clients;
|
||||||
|
relay->clients = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (entry != NULL) {
|
||||||
|
memcpy(&entry->addr, addr, sizeof(*addr));
|
||||||
|
entry->addr_len = addr_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
pthread_mutex_unlock(&relay->lock);
|
pthread_mutex_unlock(&relay->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
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, int has_conv, uint32_t conv, struct sockaddr_storage *addr, socklen_t *addr_len) {
|
||||||
int has_client;
|
int has_client = 0;
|
||||||
|
|
||||||
pthread_mutex_lock(&relay->lock);
|
pthread_mutex_lock(&relay->lock);
|
||||||
has_client = relay->has_client;
|
if (has_conv) {
|
||||||
if (has_client) {
|
udp_relay_client_entry_t *entry = udp_relay_find_client_locked(relay, conv);
|
||||||
memcpy(addr, &relay->client_addr, sizeof(*addr));
|
if (entry != NULL) {
|
||||||
*addr_len = relay->client_addr_len;
|
memcpy(addr, &entry->addr, sizeof(*addr));
|
||||||
|
*addr_len = entry->addr_len;
|
||||||
|
has_client = 1;
|
||||||
|
}
|
||||||
|
} else if (relay->has_last_client) {
|
||||||
|
memcpy(addr, &relay->last_client_addr, sizeof(*addr));
|
||||||
|
*addr_len = relay->last_client_addr_len;
|
||||||
|
has_client = 1;
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&relay->lock);
|
pthread_mutex_unlock(&relay->lock);
|
||||||
return has_client;
|
return has_client;
|
||||||
@@ -160,6 +201,8 @@ static void *udp_relay_forward_downstream_to_upstream(void *arg) {
|
|||||||
struct sockaddr_storage source;
|
struct sockaddr_storage source;
|
||||||
socklen_t source_len = sizeof(source);
|
socklen_t source_len = sizeof(source);
|
||||||
ssize_t n = recvfrom(relay->downstream_fd, buffer, sizeof(buffer), 0, (struct sockaddr *) &source, &source_len);
|
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) {
|
if (n < 0) {
|
||||||
int errnum = errno;
|
int errnum = errno;
|
||||||
@@ -174,7 +217,8 @@ static void *udp_relay_forward_downstream_to_upstream(void *arg) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
udp_relay_record_client(relay, &source, source_len);
|
udp_relay_parse_kcp_summary(buffer, (size_t) n, &has_conv, &conv, NULL);
|
||||||
|
udp_relay_record_client(relay, has_conv, conv, &source, source_len);
|
||||||
udp_relay_print_packet(relay, "relay_downstream_rx", relay->downstream_local_addr, &source, source_len, buffer, (size_t) n);
|
udp_relay_print_packet(relay, "relay_downstream_rx", relay->downstream_local_addr, &source, source_len, buffer, (size_t) n);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (send(relay->upstream_fd, buffer, (size_t) n, 0) >= 0) {
|
if (send(relay->upstream_fd, buffer, (size_t) n, 0) >= 0) {
|
||||||
@@ -205,6 +249,8 @@ static void *udp_relay_forward_upstream_to_downstream(void *arg) {
|
|||||||
struct sockaddr_storage client_addr;
|
struct sockaddr_storage client_addr;
|
||||||
socklen_t client_addr_len = 0;
|
socklen_t client_addr_len = 0;
|
||||||
ssize_t n = recv(relay->upstream_fd, buffer, sizeof(buffer), 0);
|
ssize_t n = recv(relay->upstream_fd, buffer, sizeof(buffer), 0);
|
||||||
|
int has_conv = 0;
|
||||||
|
uint32_t conv = 0;
|
||||||
|
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
int errnum = errno;
|
int errnum = errno;
|
||||||
@@ -220,7 +266,8 @@ 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);
|
||||||
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 (!udp_relay_copy_client(relay, has_conv, conv, &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;
|
||||||
}
|
}
|
||||||
@@ -404,11 +451,18 @@ int udp_relay_close(udp_relay_t *relay) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void udp_relay_free(udp_relay_t *relay) {
|
void udp_relay_free(udp_relay_t *relay) {
|
||||||
|
udp_relay_client_entry_t *entry;
|
||||||
|
udp_relay_client_entry_t *next;
|
||||||
|
|
||||||
if (relay == NULL) {
|
if (relay == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
udp_relay_close(relay);
|
udp_relay_close(relay);
|
||||||
udp_relay_join_threads(relay);
|
udp_relay_join_threads(relay);
|
||||||
|
for (entry = relay->clients; entry != NULL; entry = next) {
|
||||||
|
next = entry->next;
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
pthread_mutex_destroy(&relay->lock);
|
pthread_mutex_destroy(&relay->lock);
|
||||||
pthread_mutex_destroy(&relay->log_mu);
|
pthread_mutex_destroy(&relay->log_mu);
|
||||||
pthread_cond_destroy(&relay->state_cond);
|
pthread_cond_destroy(&relay->state_cond);
|
||||||
|
|||||||
Reference in New Issue
Block a user