diff --git a/src/transport_layer/etcp.c b/src/transport_layer/etcp.c index b2a3fd9e..9649f51c 100644 --- a/src/transport_layer/etcp.c +++ b/src/transport_layer/etcp.c @@ -4,6 +4,7 @@ #include "etcp_api.h" #include "etcp_session.h" #include "etcp_connect.h" +#include "node_conn_direct.h" #include "etcp_debug.h" #include "call_ring.h" #include "etcp_loadbalancer.h" @@ -195,7 +196,7 @@ static uint16_t timestamp_diff(uint16_t t1, uint16_t t2) { static const char EMPTY_NAME[] = ""; // Create new ETCP connection -// Таймаут непрерывного DOWN удаляет транспорт независимо от внешних ссылок. +// Таймаут DOWN удаляет только транспорт без локальных NCD владельцев. static void etcp_down_timeout_cb(void* arg) { struct ETCP_CONN* conn = arg; conn->down_timer = NULL; @@ -204,26 +205,37 @@ static void etcp_down_timeout_cb(void* arg) { DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "[%s] DOWN timeout ignored: transport is UP", conn->log_name); return; } + int handles = node_conn_direct_handle_count(conn); + if (handles) { + DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] DOWN timeout: retaining transport peer=%016llx handles=%d refs=%d", + conn->log_name, (unsigned long long)conn->peer_node_id, handles, conn->ref_count); + 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) { +int etcp_conn_schedule_down_close(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"); + uint64_t now = get_time_tb(); + if (!conn->down_deadline_tb) conn->down_deadline_tb = now + ETCP_DOWN_TIMEOUT_TB; + if (conn->down_deadline_tb <= now && node_conn_direct_handle_count(conn)) return 0; + int remaining = conn->down_deadline_tb > now ? (int)(conn->down_deadline_tb - now) : 1; + conn->down_timer = uasync_set_timeout(conn->instance->ua, remaining, conn, etcp_down_timeout_cb, "etcp_down"); if (!conn->down_timer) { DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "[%s] cannot schedule DOWN timeout", conn->log_name); 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); + DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] DOWN timer started remaining_tb=%d handles=%d refs=%d", + conn->log_name, remaining, node_conn_direct_handle_count(conn), conn->ref_count); return 0; } // UP и окончательное закрытие отменяют отложенное удаление. static void etcp_down_timer_cancel(struct ETCP_CONN* conn) { + conn->down_deadline_tb = 0; 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", @@ -316,7 +328,7 @@ struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance, char* n return NULL; } - if (etcp_down_timer_start(etcp) < 0) { etcp_connection_close(etcp); return NULL; } + if (etcp_conn_schedule_down_close(etcp) < 0) { etcp_connection_close(etcp); 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); @@ -1113,7 +1125,9 @@ 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) { - if (etcp_down_timer_start(etcp) < 0) { etcp_connection_close(etcp); return; } + if (etcp_conn_schedule_down_close(etcp) < 0 && !node_conn_direct_handle_count(etcp)) { + etcp_connection_close(etcp); return; + } } else etcp_down_timer_cancel(etcp); if (up == 0 && was_up != 0) { DEBUG_INFO(DEBUG_CATEGORY_ETCP, "All links fall down"); diff --git a/src/transport_layer/etcp.h b/src/transport_layer/etcp.h index e09f8bc4..6649a226 100644 --- a/src/transport_layer/etcp.h +++ b/src/transport_layer/etcp.h @@ -188,6 +188,7 @@ struct ETCP_CONN { void* retrans_timer; // Retrans check timer void* ack_resp_timer; // ACK send timer void* down_timer; // удаление после непрерывного DOWN, включая первоначальное ожидание + uint64_t down_deadline_tb; // сохраняется при наличии NCD handles после истечения таймера // Bandwidth measurement state // uint8_t burst_in_progress; // Burst transmission flag - Not used @@ -248,6 +249,9 @@ struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance, char* n #define ETCP_DOWN_TIMEOUT_TB 300000 /* 30 секунд в 0.1 ms */ +/* Поставить удаление DOWN без NCD handles с учётом уже прошедшего срока; -1 при отказе таймера. */ +int etcp_conn_schedule_down_close(struct ETCP_CONN* conn); + /** * @brief Закрыть соединение: фаза-1 detach + отложенная фаза-2 очистка. *