From a2861b057078700363e16fff8147707afb0fd253 Mon Sep 17 00:00:00 2001 From: evgeny Date: Fri, 23 Oct 2026 22:35:14 +0200 Subject: [PATCH] Keep cancelled links alive until their constructor returns --- src/transport_layer/etcp_connections.c | 36 +++++++++++++++++++------- src/transport_layer/etcp_connections.h | 1 + 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/transport_layer/etcp_connections.c b/src/transport_layer/etcp_connections.c index 30ed932e..e46aff55 100644 --- a/src/transport_layer/etcp_connections.c +++ b/src/transport_layer/etcp_connections.c @@ -117,25 +117,26 @@ static void socks_etcp_read_callback(socket_t sock, void* arg) { void tcp_server_on_link(struct stcp_link *link, struct ETCP_SOCKET *tcp_sock) { struct UTUN_INSTANCE *inst = tcp_sock->instance; const uint8_t *pubkey = stcp_link_get_peer_pubkey(link); - if (!pubkey) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: no peer pubkey"); return; } + if (!pubkey) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: no peer pubkey"); stcp_link_close(link); return; } uint64_t node_id = sc_derive_node_id_from_pubkey(pubkey); DEBUG_INFO(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: accepted TCP from peer=0x%016llx", (unsigned long long)node_id); struct ETCP_CONN *conn = instance_find_conn(inst, node_id); + int new_conn = conn == NULL; DEBUG_INFO(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: %s conn=%p peer=0x%016llx pubkey=%016llx", conn ? "existing" : "NEW", (void*)conn, (unsigned long long)node_id, (unsigned long long)wire_read64(pubkey)); if (!conn) { conn = etcp_connection_create(inst, NULL); - if (!conn) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: etcp_connection_create failed"); return; } + if (!conn) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: etcp_connection_create failed/cancelled"); stcp_link_close(link); return; } conn->peer_node_id = node_id; if (sc_init_ctx(&conn->crypto_ctx, &inst->my_keys) != SC_OK) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: sc_init_ctx failed"); - etcp_connection_close(conn); return; + etcp_connection_close(conn); stcp_link_close(link); return; } if (sc_set_peer_public_key(&conn->crypto_ctx, pubkey, SC_PEER_PUBKEY_BIN) != SC_OK) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: sc_set_peer_public_key failed"); - etcp_connection_close(conn); return; + etcp_connection_close(conn); stcp_link_close(link); return; } etcp_update_log_name(conn); { struct conn_queue_entry* ce = (struct conn_queue_entry*)conn->conn_queue_entry->data; ce->peer_node_id = node_id; queue_remove_data(conn->conn_queue, conn->conn_queue_entry); queue_data_put_with_index(conn->conn_queue, conn->conn_queue_entry); } @@ -145,7 +146,12 @@ void tcp_server_on_link(struct stcp_link *link, struct ETCP_SOCKET *tcp_sock) { const struct sockaddr_storage* ra = stcp_link_get_peer_addr(link); if (!ra) ra = stcp_link_get_remote_addr(link); struct ETCP_LINK *tlink = etcp_link_new(conn, tcp_sock, ra, 1); - if (!tlink) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: etcp_link_new failed"); return; } + if (!tlink) { + DEBUG_WARN(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: link creation failed/cancelled peer=%016llx", (unsigned long long)node_id); + stcp_link_close(link); + if (new_conn) etcp_connection_close(conn); + return; + } tlink->tcp_link = link; tlink->is_server = 1; @@ -346,6 +352,7 @@ void etcp_link_enter_init(struct ETCP_LINK* link) { int old_state = link->link_state; link->link_state = LINK_STATE_HANDSHAKE; // handshake etcp_fire_link_status_cbk(link, old_state, link->link_status); + if (!etcp_link_rx_alive(link->etcp, link)) return; if (link->is_server != 0) return; int reset = (link->etcp->got_initial_pkt == 0); etcp_link_send_init(link, reset, 0); @@ -1044,7 +1051,7 @@ struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn const struct sockaddr_storage* remote_addr, uint8_t is_server) { DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); if (!etcp) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "null etcp"); return NULL; } - if (etcp->state == 2) { DEBUG_WARN(DEBUG_CATEGORY_ETCP, "[%s] link_new on deleted conn", etcp->log_name); return NULL; } + if (etcp->state == 2 || etcp->close_requested) { DEBUG_WARN(DEBUG_CATEGORY_ETCP, "[%s] link_new on closing conn", etcp->log_name); return NULL; } int is_tcp = (conn == NULL) || conn->is_tcp; struct ETCP_LINK* link = u_calloc(1, sizeof(struct ETCP_LINK)); @@ -1150,11 +1157,23 @@ struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn DEBUG_INFO(DEBUG_CATEGORY_ETCP, "NEW link etcp=[%s] link=%p socket=%s id=%u server=%u mtu=%u tcp=%u DATA_MSS=%u cwnd=%u", etcp->log_name, link, conn ? conn->name : "tcp", link->local_link_id, link->is_server, link->mtu, link->is_tcp, etcp->normalizer->frag_size, link->inflight_lim_bytes); + link->constructing = 1; etcp_fire_link_status_cbk(link, -1, 0); - if (!is_tcp && is_server == 0) { + if (!link->closing && !etcp->close_requested && !is_tcp && is_server == 0) { etcp_link_enter_init(link); } + link->constructing = 0; + if (link->closing) { + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] link creation cancelled path=%u", etcp->log_name, link->local_link_id); + u_free(link->bbr); u_free(link); + return NULL; + } + if (etcp->close_requested) { + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] link creation stopped by connection close path=%u", etcp->log_name, link->local_link_id); + etcp_link_close(link); + return NULL; + } callring_put(CR_LINK_NEW, (uintptr_t)link, (uintptr_t)etcp); return link; @@ -1254,8 +1273,7 @@ void etcp_link_close(struct ETCP_LINK* link) { etcp_fire_link_status_cbk(link, old_state, old_status); if (!etcp->close_requested) etcp_on_link_down(etcp, NULL); callring_put(CR_LINK_CLOSE_FREE, (uintptr_t)link, 0); - u_free(link->bbr); - u_free(link); + if (!link->constructing) { u_free(link->bbr); u_free(link); } etcp->callbacks_running--; } diff --git a/src/transport_layer/etcp_connections.h b/src/transport_layer/etcp_connections.h index 287011dc..85c39472 100644 --- a/src/transport_layer/etcp_connections.h +++ b/src/transport_layer/etcp_connections.h @@ -232,6 +232,7 @@ struct ETCP_LINK { uint8_t is_server; // инициирует подключение клиент uint8_t initialized; // Флаг инициализации (1=подтверждено или получен request) uint8_t closing; // Close начат: повторный вход из callback игнорируется до окончательного free + uint8_t constructing; // Конструктор ещё владеет памятью: close отвязывает ресурсы, free выполняет конструктор uint8_t local_link_id; // id моего линка uint8_t remote_link_id; // id этого линка на peer (устанавливается в момент initialized) uint8_t remote_socket_id; // socket id peer