From ab6773a3137ee061c182284557d19ae752fa8100 Mon Sep 17 00:00:00 2001 From: evgeny Date: Thu, 10 Sep 2026 21:20:26 +0300 Subject: [PATCH] =?UTF-8?q?etcp:=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=D0=B2=D1=8F=D0=B7=D0=BA=D0=B0/=D1=81=D0=B2=D0=BE=D0=BF?= =?UTF-8?q?=20remote=5Flink=5Fid=20=D0=BF=D1=80=D0=B8=20INIT=20=D1=81?= =?UTF-8?q?=D0=BE=20=D1=81=D0=BC=D0=B5=D0=BD=D1=91=D0=BD=D0=BD=D1=8B=D0=BC?= =?UTF-8?q?=20=D0=B0=D0=B4=D1=80=D0=B5=D1=81=D0=BE=D0=BC=20(NAT)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/transport_layer/etcp_connections.c | 47 ++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/transport_layer/etcp_connections.c b/src/transport_layer/etcp_connections.c index cf20f0fd..efff854a 100644 --- a/src/transport_layer/etcp_connections.c +++ b/src/transport_layer/etcp_connections.c @@ -402,6 +402,27 @@ struct ETCP_LINK* etcp_link_find_by_addr(struct ETCP_SOCKET* e_sock, struct sock return lqe->link; } +/* Перепривязывает UDP-линк на новый remote-адрес (пир сменил NAT-адрес, линк ещё down). + * Пере-индексирует линк в socket->links_queue под новым ключом. */ +static void etcp_link_update_remote_addr(struct ETCP_LINK* link, struct ETCP_SOCKET* e_sock, + const struct sockaddr_storage* new_addr) { + if (!link || !e_sock || !new_addr) return; + if (link->is_tcp) { + DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "[%s] update_remote_addr: TCP link skip", link->etcp->log_name); + return; + } + if (link->conn != e_sock) { + DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "[%s] update_remote_addr: link socket [%s] != recv socket [%s], skip", + link->etcp->log_name, link->conn ? link->conn->name : "-", e_sock->name); + return; + } + remove_link_from_queue(link); + memcpy(&link->remote_addr, new_addr, sizeof(struct sockaddr_storage)); + if (insert_link_queue(e_sock, link) < 0) + DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "[%s] update_remote_addr: re-index FAILED at %s", + link->etcp->log_name, sockaddr_storage_to_str(new_addr).str); +} + struct ETCP_LINK* etcp_link_find_by_remote_id(struct ETCP_CONN* conn, uint8_t remote_link_id) { DEBUG_TRACE(DEBUG_CATEGORY_CONNECTION, ""); if (!conn || remote_link_id == 0) return NULL; @@ -2115,6 +2136,32 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) { // Check if link already exists (for CHANNEL_INIT recovery) struct ETCP_LINK* existing_link = etcp_link_find_by_remote_id(conn, req->link_id); + + /* Правила 1+2: найден по id, линк down, адрес сменился */ + if (existing_link && existing_link->link_status == 0 + && !sockaddr_equal(&existing_link->remote_addr, &addr)) { + struct ETCP_LINK* L_addr = etcp_link_find_by_addr(e_sock, &addr, 0); + if (L_addr && L_addr != existing_link && L_addr->etcp == conn && L_addr->link_status == 0) { + /* Правило 2: своп remote_link_id, дальше работаем с L_addr */ + uint8_t id_old = existing_link->remote_link_id; + uint8_t id_swap = L_addr->remote_link_id; + existing_link->remote_link_id = id_swap; + L_addr->remote_link_id = id_old; + DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] swap remote_link_id: id=%u @ %s <-> id=%u @ %s", + conn->log_name, id_old, sockaddr_storage_to_str(&existing_link->remote_addr).str, + id_swap, sockaddr_storage_to_str(&L_addr->remote_addr).str); + existing_link = L_addr; + } else if (!L_addr) { + /* Правило 1: перепривязать адрес */ + etcp_link_update_remote_addr(existing_link, e_sock, &addr); + DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] remote addr updated: id=%u -> %s", + conn->log_name, existing_link->remote_link_id, sockaddr_storage_to_str(&addr).str); + } else { + DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "[%s] addr %s busy (up/foreign) — link id=%u left as-is", + conn->log_name, sockaddr_storage_to_str(&addr).str, existing_link->remote_link_id); + } + } + if (!existing_link) { existing_link = etcp_link_find_by_addr(e_sock, &addr, 0); if (existing_link && existing_link->etcp == conn) {