Keep cancelled links alive until their constructor returns

This commit is contained in:
evgeny committed 2026-10-23 22:35:14 +02:00
1 parent a51c080407
commit a2861b0570
2 files changed
+28 -9

No files matched your search

+27 -9
View File
@@ -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--;
}
+1
View File
@@ -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