|
|
|
|
@ -21,6 +21,7 @@
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#define RELAY_IO_BUF 65536 |
|
|
|
|
#define RELAY_WARN_CONNS 64 |
|
|
|
|
|
|
|
|
|
#ifdef _WIN32 |
|
|
|
|
#define RELAY_SHUT_WR SD_SEND |
|
|
|
|
@ -36,6 +37,9 @@ struct reality_relay {
|
|
|
|
|
void *dest_sid; |
|
|
|
|
int connecting; // 1 = ждём завершения connect() к dest
|
|
|
|
|
|
|
|
|
|
void *idle_timer; // handle таймера простоя (NULL если выключен)
|
|
|
|
|
int idle_timeout_tb; // время простоя в 0.1ms (0 = таймер выключен)
|
|
|
|
|
|
|
|
|
|
char host[256]; // dest hostname (для async DNS и логирования)
|
|
|
|
|
uint16_t port; // dest port
|
|
|
|
|
struct adns_query *dns_q; // pending async DNS query (NULL если нет)
|
|
|
|
|
@ -53,8 +57,11 @@ struct reality_relay {
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static struct reality_relay *g_relays = NULL; // активные релеи
|
|
|
|
|
static int g_relay_count = 0; // число активных релеев (для warn)
|
|
|
|
|
|
|
|
|
|
static void relay_free(struct reality_relay *r); |
|
|
|
|
static void relay_touch(struct reality_relay *r); |
|
|
|
|
static void relay_idle_timeout_cb(void *arg); |
|
|
|
|
static void relay_flush_c2d(struct reality_relay *r); |
|
|
|
|
static void relay_flush_d2c(struct reality_relay *r); |
|
|
|
|
static void relay_client_read_cb(socket_t sock, void *arg); |
|
|
|
|
@ -69,12 +76,14 @@ static void relay_free_cb(void *arg) {
|
|
|
|
|
static void relay_free(struct reality_relay *r) { |
|
|
|
|
if (!r || r->closed) return; |
|
|
|
|
r->closed = 1; |
|
|
|
|
g_relay_count--; |
|
|
|
|
{ // вынуть из реестра активных релеев
|
|
|
|
|
struct reality_relay **pp = &g_relays; |
|
|
|
|
while (*pp && *pp != r) pp = &(*pp)->next; |
|
|
|
|
if (*pp) *pp = r->next; |
|
|
|
|
r->next = NULL; |
|
|
|
|
} |
|
|
|
|
if (r->idle_timer) { uasync_cancel_timeout(r->ua, r->idle_timer); r->idle_timer = NULL; } |
|
|
|
|
if (r->dns_q) { adns_cancel(r->dns_q); r->dns_q = NULL; } |
|
|
|
|
if (r->client_sid) { uasync_remove_socket_t(r->ua, r->client_sock); r->client_sid = NULL; } |
|
|
|
|
if (r->dest_sid) { uasync_remove_socket_t(r->ua, r->dest_sock); r->dest_sid = NULL; } |
|
|
|
|
@ -86,6 +95,21 @@ static void relay_free(struct reality_relay *r) {
|
|
|
|
|
uasync_call_soon(r->ua, r, relay_free_cb); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Перезапустить таймер простоя: сброс на любую активность (чтение данных).
|
|
|
|
|
static void relay_touch(struct reality_relay *r) { |
|
|
|
|
if (r->idle_timeout_tb <= 0) return; |
|
|
|
|
if (r->idle_timer) { uasync_cancel_timeout(r->ua, r->idle_timer); r->idle_timer = NULL; } |
|
|
|
|
r->idle_timer = uasync_set_timeout(r->ua, r->idle_timeout_tb, r, relay_idle_timeout_cb, "relay_idle"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void relay_idle_timeout_cb(void *arg) { |
|
|
|
|
struct reality_relay *r = (struct reality_relay *)arg; |
|
|
|
|
r->idle_timer = NULL; // handle освобождён process_timeouts сразу после колбэка
|
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_REALITY, "reality_relay: idle timeout %ds c2d=%zu d2c=%zu — closing", |
|
|
|
|
r->idle_timeout_tb / 10000, r->bytes_c2d, r->bytes_d2c); |
|
|
|
|
relay_free(r); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void relay_flush_c2d(struct reality_relay *r) { |
|
|
|
|
if (!r->c2d) return; |
|
|
|
|
while (r->c2d_off < r->c2d_len) { |
|
|
|
|
@ -157,6 +181,7 @@ static void relay_client_read_cb(socket_t sock, void *arg) {
|
|
|
|
|
#endif |
|
|
|
|
r->c2d = buf; r->c2d_len = (size_t)n; r->c2d_off = 0; |
|
|
|
|
uasync_set_socket_read(r->ua, r->client_sid, 0); // backpressure
|
|
|
|
|
relay_touch(r); |
|
|
|
|
relay_flush_c2d(r); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -183,6 +208,7 @@ static void relay_dest_read_cb(socket_t sock, void *arg) {
|
|
|
|
|
} |
|
|
|
|
r->d2c = buf; r->d2c_len = (size_t)n; r->d2c_off = 0; |
|
|
|
|
uasync_set_socket_read(r->ua, r->dest_sid, 0); // backpressure
|
|
|
|
|
relay_touch(r); |
|
|
|
|
relay_flush_d2c(r); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -263,7 +289,8 @@ static void relay_dns_done_cb(const struct adns_result *res, void *arg) {
|
|
|
|
|
|
|
|
|
|
int reality_relay_start(struct UASYNC *ua, socket_t client_sock, |
|
|
|
|
const char *dest, |
|
|
|
|
const uint8_t *initial_data, size_t initial_len) { |
|
|
|
|
const uint8_t *initial_data, size_t initial_len, |
|
|
|
|
int idle_timeout_sec) { |
|
|
|
|
if (!ua || client_sock == SOCKET_INVALID || !dest || !dest[0]) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_REALITY, "reality_relay_start: invalid args"); |
|
|
|
|
return -1; |
|
|
|
|
@ -275,7 +302,12 @@ int reality_relay_start(struct UASYNC *ua, socket_t client_sock,
|
|
|
|
|
r->client_sock = client_sock; |
|
|
|
|
r->dest_sock = SOCKET_INVALID; |
|
|
|
|
r->connecting = 1; |
|
|
|
|
r->idle_timeout_tb = idle_timeout_sec > 0 ? idle_timeout_sec * 10000 : 0; |
|
|
|
|
r->next = g_relays; g_relays = r; |
|
|
|
|
g_relay_count++; |
|
|
|
|
if (g_relay_count > RELAY_WARN_CONNS) |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_REALITY, "reality_relay: %d concurrent relays (over %d) — возможен скан-флуд", g_relay_count, RELAY_WARN_CONNS); |
|
|
|
|
relay_touch(r); // таймер покрывает DNS + connect (застрявший connect тоже чистится)
|
|
|
|
|
|
|
|
|
|
// берём владение client_sock сразу (снимаем старую регистрацию) — до парсинга,
|
|
|
|
|
// чтобы любая ошибка ниже не оставила сокет зарегистрированным в uasync.
|
|
|
|
|
|