From 034be69ac17c905e7c1ba0f6fc7e9e1000892c0a Mon Sep 17 00:00:00 2001 From: evgeny Date: Sun, 11 Oct 2026 23:36:15 +0200 Subject: [PATCH] Expire ETCP transports after 30 seconds continuously down --- src/transport_layer/etcp.c | 42 ++++++++++++++++++++++++++++++++++++++ src/transport_layer/etcp.h | 3 +++ 2 files changed, 45 insertions(+) diff --git a/src/transport_layer/etcp.c b/src/transport_layer/etcp.c index 6ce3005f..08570803 100644 --- a/src/transport_layer/etcp.c +++ b/src/transport_layer/etcp.c @@ -195,6 +195,42 @@ static uint16_t timestamp_diff(uint16_t t1, uint16_t t2) { static const char EMPTY_NAME[] = ""; // Create new ETCP connection +// Таймаут непрерывного DOWN удаляет транспорт независимо от внешних ссылок. +static void etcp_down_timeout_cb(void* arg) { + struct ETCP_CONN* conn = arg; + conn->down_timer = NULL; + if (conn->close_requested || conn->state == 2) return; + if (conn->links_up) { + DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "[%s] DOWN timeout ignored: transport is UP", conn->log_name); + return; + } + DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] DOWN timeout: deleting transport peer=%016llx refs=%d timeout_ms=%d", + conn->log_name, (unsigned long long)conn->peer_node_id, conn->ref_count, ETCP_DOWN_TIMEOUT_TB / 10); + etcp_connection_close(conn); +} + +// Повторный DOWN не продлевает ожидание; первое подключение тоже имеет конечный срок. +static int etcp_down_timer_start(struct ETCP_CONN* conn) { + if (conn->down_timer || conn->links_up || conn->close_requested || conn->state == 2) return 0; + conn->down_timer = uasync_set_timeout(conn->instance->ua, ETCP_DOWN_TIMEOUT_TB, conn, etcp_down_timeout_cb, "etcp_down"); + if (!conn->down_timer) { + DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "[%s] cannot schedule DOWN timeout", conn->log_name); + etcp_connection_close(conn); + return -1; + } + DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] DOWN timer started timeout_ms=%d refs=%d", + conn->log_name, ETCP_DOWN_TIMEOUT_TB / 10, conn->ref_count); + return 0; +} + +// UP и окончательное закрытие отменяют отложенное удаление. +static void etcp_down_timer_cancel(struct ETCP_CONN* conn) { + if (!conn->down_timer) return; + uasync_cancel_timeout(conn->instance->ua, conn->down_timer); conn->down_timer = NULL; + DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] DOWN timer cancelled up=%u closing=%u", + conn->log_name, conn->links_up, conn->close_requested); +} + struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance, char* name) { DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); if (!instance) return NULL; @@ -281,6 +317,8 @@ struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance, char* n return NULL; } + if (etcp_down_timer_start(etcp) < 0) return NULL; + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] connection initialized. ETCP=%p mtu=%d, next_tx_id=%u state=pending", etcp->log_name, etcp, etcp->mtu, etcp->next_tx_id); @@ -328,6 +366,7 @@ void etcp_cbk_fire(struct ETCP_CONN* conn, int event) { static void etcp_on_up(struct ETCP_CONN* etcp) { if (etcp->state == 2) return; // defensive: после DELETE UP не стреляет + etcp_down_timer_cancel(etcp); int total_links = 0; for (struct ETCP_LINK* l = etcp->links; l; l = l->next) total_links++; uint64_t elapsed_ms = (get_time_tb() - etcp->setup_start_tb) / 10; struct strbuf sb = strbuf_new(); int any = 0; @@ -428,6 +467,7 @@ void etcp_connection_close(struct ETCP_CONN* etcp) { callring_put(CR_CCLOSE_IN, (uintptr_t)etcp, 0); etcp->close_requested = 1; + etcp_down_timer_cancel(etcp); etcp_padding_stop(&etcp->padding); if (etcp->callbacks_running) { if (etcp->close_token) return; @@ -1073,6 +1113,8 @@ void etcp_on_link_down(struct ETCP_CONN* etcp, struct ETCP_LINK* down_link) { } int was_up = etcp->links_up; etcp->links_up = up; + if (!up) etcp_down_timer_start(etcp); + else etcp_down_timer_cancel(etcp); if (up == 0 && was_up != 0) { DEBUG_INFO(DEBUG_CATEGORY_ETCP, "All links fall down"); etcp_on_down(etcp, down_link); diff --git a/src/transport_layer/etcp.h b/src/transport_layer/etcp.h index 8338d482..e09f8bc4 100644 --- a/src/transport_layer/etcp.h +++ b/src/transport_layer/etcp.h @@ -187,6 +187,7 @@ struct ETCP_CONN { // Timers void* retrans_timer; // Retrans check timer void* ack_resp_timer; // ACK send timer + void* down_timer; // удаление после непрерывного DOWN, включая первоначальное ожидание // Bandwidth measurement state // uint8_t burst_in_progress; // Burst transmission flag - Not used @@ -245,6 +246,8 @@ struct ETCP_CONN { // Создать транспортный объект; жизненным циклом прикладного соединения управляет NCD. struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance, char* name); +#define ETCP_DOWN_TIMEOUT_TB 300000 /* 30 секунд в 0.1 ms */ + /** * @brief Закрыть соединение: фаза-1 detach + отложенная фаза-2 очистка. *