fix: block redundant conn reinit on cross-connect INIT (reset_done flag)
Problem: when two peers connect simultaneously, each incoming INIT_REQUEST(0x02) or INIT_RESPONSE(0x03) triggers etcp_conn_reinit unconditionally, causing endless UP/DOWN flapping loop. Fix: add reset_done flag to ETCP_CONN: - 0 at creation and after explicit reinit (reinit allowed) - set to 1 in etcp_conn_ready (connection stable, block reinit) Three call sites guarded with !conn->reset_done: - client: handle_init_response_client (INIT_RESPONSE 0x03) - server: existing link INIT_REQUEST processing - server: new link INIT_REQUEST processing send_reset logic preserved unconditionally — only etcp_conn_reinit itself is blocked when already stable.
This commit is contained in:
1 parent
2bf7dcc6f0
commit
abbb6de701
3 files changed
+13
-8
No files matched your search
+3
-1
@@ -215,6 +215,7 @@ struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance, char* n
|
||||
etcp->optimal_inflight=100000;
|
||||
etcp->initialized=0;
|
||||
etcp->links_up=0;
|
||||
etcp->reset_done=0;
|
||||
etcp->last_rr_link=NULL;
|
||||
etcp->name = u_strdup(name);
|
||||
// Initialize log_name with local node_id (peer will be updated later when known)
|
||||
@@ -503,7 +504,7 @@ void etcp_conn_reinit(struct ETCP_CONN* etcp) {// Если сбой в обме
|
||||
etcp->log_name, etcp->initialized, etcp->links_up, etcp->reinit_count, etcp->tx_state);
|
||||
|
||||
etcp->reinit_count++;
|
||||
|
||||
etcp->reset_done = 0;
|
||||
etcp->initialized = 0;// еще раз придёт conn_ready_callback
|
||||
|
||||
// Отменяем висящие NAT-ping'и для этого соединения
|
||||
@@ -530,6 +531,7 @@ void etcp_conn_ready(struct ETCP_CONN* conn) {
|
||||
if (!conn) return;
|
||||
|
||||
conn->initialized = 1;
|
||||
conn->reset_done = 1;
|
||||
// Если tx_state не установлен (первое подключение без reinit), установим его
|
||||
if (conn->tx_state == 0) {
|
||||
conn->tx_state = ETCP_TX_STATE_DATA_WAIT;
|
||||
|
||||
@@ -225,6 +225,7 @@ struct ETCP_CONN {
|
||||
uint32_t session_id; // случайный ID сессии (генерируется клиентом) для защиты от ложного reinit
|
||||
uint8_t tx_state; // 0 - n/a, 1 - data_wait (queues empty), 2 - link_wait (link busy)
|
||||
uint8_t links_up; // 0 - канал не готов для передачи, 1 - канал готов для передачи (хотя бы один линк не down)
|
||||
uint8_t reset_done; // 0 - рукопожатие не завершено (реинит разрешён), 1 - соединение стабильно (реинит заблокирован)
|
||||
|
||||
// Callback chains for ready/up/down notifications
|
||||
struct etcp_cbk_entry* ready_cbks; // цепочка callback'ов при готовности соединения
|
||||
|
||||
@@ -1473,7 +1473,7 @@ static int handle_init_response_client(struct ETCP_SOCKET* e_sock, struct ETCP_D
|
||||
link->init_timer = NULL;
|
||||
}
|
||||
|
||||
if (pkt_code == ETCP_INIT_RESPONSE) {
|
||||
if (pkt_code == ETCP_INIT_RESPONSE && !link->etcp->reset_done) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "[%s] REINIT from client: INIT_RESPONSE(0x03) received, reinit conn=%p",
|
||||
link->etcp->log_name, link->etcp);
|
||||
etcp_conn_reinit(link->etcp);
|
||||
@@ -1748,10 +1748,11 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
|
||||
// Check session_id: if same - no reinit, if different - client restarted, do reinit
|
||||
if (code == ETCP_INIT_REQUEST || conn->session_id != session_id || !conn->got_initial_pkt) {
|
||||
send_reset = 1; // Client explicitly requested reset, or new session, or server waiting for first packet
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "[%s] REINIT existing link: code=0x%02x sess=%08x→%08x got_init=%d initialized=%d links_up=%d",
|
||||
conn->log_name, code, conn->session_id, session_id, conn->got_initial_pkt, conn->initialized, conn->links_up);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "[%s] REINIT existing link: code=0x%02x sess=%08x→%08x got_init=%d initialized=%d links_up=%d reset_done=%d",
|
||||
conn->log_name, code, conn->session_id, session_id, conn->got_initial_pkt, conn->initialized, conn->links_up, conn->reset_done);
|
||||
conn->session_id = session_id;
|
||||
etcp_conn_reinit(conn);
|
||||
if (!conn->reset_done) etcp_conn_reinit(conn);
|
||||
else DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "[%s] REINIT skipped — reset_done=1", conn->log_name);
|
||||
} else {
|
||||
send_reset = 0; // Same session, no reinit needed
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_CONNECTION, "same session_id, skip reinit");
|
||||
@@ -1775,10 +1776,11 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
|
||||
// For new links: reset if client requested or session changed
|
||||
if (code == ETCP_INIT_REQUEST || conn->session_id != session_id || !conn->got_initial_pkt) {
|
||||
send_reset = 1;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "[%s] REINIT new link: code=0x%02x sess=%08x→%08x got_init=%d initialized=%d links_up=%d",
|
||||
conn->log_name, code, conn->session_id, session_id, conn->got_initial_pkt, conn->initialized, conn->links_up);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "[%s] REINIT new link: code=0x%02x sess=%08x→%08x got_init=%d initialized=%d links_up=%d reset_done=%d",
|
||||
conn->log_name, code, conn->session_id, session_id, conn->got_initial_pkt, conn->initialized, conn->links_up, conn->reset_done);
|
||||
conn->session_id = session_id;
|
||||
etcp_conn_reinit(conn);
|
||||
if (!conn->reset_done) etcp_conn_reinit(conn);
|
||||
else DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "[%s] REINIT skipped — reset_done=1", conn->log_name);
|
||||
}
|
||||
link->keepalive_interval=(req->keepalive[0]<<8) | req->keepalive[1];
|
||||
link->recovery_interval=((req->recovery[0]<<8) | req->recovery[1])*100;// timebase в link, timebase/100 в кодограмме
|
||||
|
||||
Reference in new issue
Block a user