diff --git a/src/transport_layer/etcp.c b/src/transport_layer/etcp.c index 21a27dbe..aabb16ef 100644 --- a/src/transport_layer/etcp.c +++ b/src/transport_layer/etcp.c @@ -269,7 +269,12 @@ void etcp_fire_conn_status(struct ETCP_CONN* etcp, int status) { (status >= 0 && status < (int)(sizeof(names)/sizeof(names[0]))) ? names[status] : "?"); etcp->callbacks_running++; struct etcp_status_cbk_entry* cbe = etcp->instance->conn_status_cbks; - while (cbe) { struct etcp_status_cbk_entry* n = cbe->next; cbe->fn(etcp, status, cbe->arg); cbe = n; } + while (cbe) { + struct etcp_status_cbk_entry* n = cbe->next; + cbe->fn(etcp, status, cbe->arg); + if (etcp->close_requested && status != ETCP_CONN_STATUS_DOWN && status != ETCP_CONN_STATUS_DELETE) break; + cbe = n; + } etcp->callbacks_running--; } @@ -281,7 +286,12 @@ void etcp_cbk_fire(struct ETCP_CONN* conn, int event) { DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] callback event: %s", conn->log_name, (idx >= 0 && idx < (int)(sizeof(names)/sizeof(names[0]))) ? names[idx] : "?"); conn->callbacks_running++; struct etcp_cbk_entry* cbe = conn->cbks; - while (cbe) { struct etcp_cbk_entry* n = cbe->next; if (cbe->fn && (cbe->event_mask & event)) cbe->fn(conn, event, cbe->arg); cbe = n; } + while (cbe) { + struct etcp_cbk_entry* n = cbe->next; + if (cbe->fn && (cbe->event_mask & event)) cbe->fn(conn, event, cbe->arg); + if (conn->close_requested && event != ETCP_CBK_EVENT_DOWN && event != ETCP_CBK_EVENT_DELETE) break; + cbe = n; + } conn->callbacks_running--; if (!conn->callbacks_running) { struct etcp_cbk_entry** pp = &conn->cbks; @@ -293,7 +303,7 @@ void etcp_cbk_fire(struct ETCP_CONN* conn, int event) { } static void etcp_on_up(struct ETCP_CONN* etcp) { - if (etcp->state == 2) return; // defensive: после DELETE UP не стреляет + if (etcp->state == 2 || etcp->close_requested) return; etcp_down_timer_cancel(etcp); int total_links = 0; for (struct ETCP_LINK* l = etcp->links; l; l = l->next) total_links++; uint64_t elapsed_ms = (get_time_tb() - etcp->setup_start_tb) / 10; @@ -310,7 +320,7 @@ static void etcp_on_up(struct ETCP_CONN* etcp) { strbuf_free(&sb); (void)elapsed_ms; etcp_cbk_fire(etcp, ETCP_CBK_EVENT_UP); - etcp_fire_conn_status(etcp, ETCP_CONN_STATUS_UP); + if (!etcp->close_requested) etcp_fire_conn_status(etcp, ETCP_CONN_STATUS_UP); } static void etcp_on_down(struct ETCP_CONN* etcp, struct ETCP_LINK* down_link) { @@ -328,7 +338,7 @@ static void etcp_on_down(struct ETCP_CONN* etcp, struct ETCP_LINK* down_link) { DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Connection DOWN — closing, links: %s", etcp->log_name, any ? strbuf_str(&sb) : "(none)"); strbuf_free(&sb); etcp_cbk_fire(etcp, ETCP_CBK_EVENT_DOWN); - etcp_fire_conn_status(etcp, ETCP_CONN_STATUS_DOWN); + if (!etcp->close_requested) etcp_fire_conn_status(etcp, ETCP_CONN_STATUS_DOWN); } @@ -341,9 +351,7 @@ static void etcp_connection_free_resources(struct ETCP_CONN* etcp) { // Close links if (etcp->links) { - struct ETCP_LINK* link = etcp->links; - while (link) { struct ETCP_LINK* next = link->next; etcp_link_close(link); link = next; } - etcp->links = NULL; + while (etcp->links) etcp_link_close(etcp->links); } // Drain and free all queues @@ -443,9 +451,8 @@ void etcp_connection_close(struct ETCP_CONN* etcp) { // Close links (detach from socket scan queues) if (etcp->links) { - struct ETCP_LINK* link = etcp->links; - while (link) { struct ETCP_LINK* next = link->next; etcp_link_close(link); link = next; } - etcp->links = NULL; + /* Callback закрытия одного пути может удалить соседний: следующий берём заново. */ + while (etcp->links) etcp_link_close(etcp->links); } // Remove from instance queue @@ -582,7 +589,7 @@ void etcp_conn_apply_peer_reset_id(struct ETCP_CONN* conn, uint64_t peer_reset_i // внутренняя функция. Вызывается один раз когда первый линк готов. void etcp_conn_ready(struct ETCP_CONN* conn) { - if (!conn) return; + if (!conn || conn->close_requested) return; if (conn->state == 2) { DEBUG_WARN(DEBUG_CATEGORY_ETCP, "[%s] conn_ready on deleted conn", conn->log_name); return; } if (conn->initialized || conn->session_required) return; // ready or awaiting authenticated confirmation @@ -595,6 +602,7 @@ void etcp_conn_ready(struct ETCP_CONN* conn) { for (struct ETCP_LINK* link = conn->links; link; link = link->next) if (link->initialized && link->link_status) conn->links_up = 1; etcp_conn_queue_set_ready(conn); + if (conn->close_requested) return; // Реинит уже готового соединения (state!=0): etcp_conn_queue_set_ready не сработал // (ранний выход по state!=0), поэтому reinit_pending остаётся висеть и блокирует приём — @@ -602,6 +610,7 @@ void etcp_conn_ready(struct ETCP_CONN* conn) { if (conn->reinit_pending) { conn->reinit_pending = 0; etcp_cbk_fire(conn, ETCP_CBK_EVENT_REINIT); + if (conn->close_requested) return; etcp_fire_conn_status(conn, ETCP_CONN_STATUS_REINIT); } if (conn->normalizer && !conn->close_requested) queue_resume_callback(conn->normalizer->input); @@ -646,8 +655,12 @@ void etcp_conn_queue_set_ready(struct ETCP_CONN* conn) { conn->log_name, conn->state, (unsigned long long)conn->peer_node_id); etcp_cbk_fire(conn, ETCP_CBK_EVENT_INIT); - if (conn->reinit_pending) { conn->reinit_pending = 0; etcp_cbk_fire(conn, ETCP_CBK_EVENT_REINIT); - etcp_fire_conn_status(conn, ETCP_CONN_STATUS_REINIT); } + if (conn->close_requested) return; + if (conn->reinit_pending) { + conn->reinit_pending = 0; etcp_cbk_fire(conn, ETCP_CBK_EVENT_REINIT); + if (conn->close_requested) return; + etcp_fire_conn_status(conn, ETCP_CONN_STATUS_REINIT); + } if (conn->links_up) etcp_on_up(conn); } diff --git a/src/transport_layer/etcp_api.c b/src/transport_layer/etcp_api.c index 72cb0531..f09d2e4f 100644 --- a/src/transport_layer/etcp_api.c +++ b/src/transport_layer/etcp_api.c @@ -94,12 +94,14 @@ void etcp_remove_link_status_cbk(struct UTUN_INSTANCE* inst, etcp_link_status_cb void etcp_fire_link_status_cbk(struct ETCP_LINK* link, int old_state, int old_status) { if (!link || !link->etcp || !link->etcp->instance) return; struct ETCP_CONN* conn = link->etcp; + int closing_connection = conn->close_requested; int was_attached = 0; for (struct ETCP_LINK* current = conn->links; current; current = current->next) if (current == link) { was_attached = 1; break; } conn->callbacks_running++; struct etcp_link_status_cbk_entry* cbe = conn->instance->link_status_cbks; while (cbe) { cbe->fn(conn, link, old_state, old_status, cbe->arg); + if (!closing_connection && conn->close_requested) break; if (was_attached) { int attached = 0; for (struct ETCP_LINK* current = conn->links; current; current = current->next)