diff --git a/src/transport_layer/etcp_keepalive.c b/src/transport_layer/etcp_keepalive.c index a02ba4c0..f597aec9 100644 --- a/src/transport_layer/etcp_keepalive.c +++ b/src/transport_layer/etcp_keepalive.c @@ -133,7 +133,6 @@ static void keepalive_timer_cb(void* arg) { * (topo_recovery → ncd_revive_entry) — link может быть освобождён. */ struct ETCP_CONN *etcp = link->etcp; int is_tcp = link->is_tcp; - struct stcp_link *tcp_link = link->tcp_link; int local_link_id = link->local_link_id; struct sockaddr_storage raddr = link->remote_addr; uint8_t remote_ka = link->remote_keepalive; @@ -144,7 +143,7 @@ static void keepalive_timer_cb(void* arg) { int alive = 0; for (struct ETCP_LINK *x = etcp->links; x; x = x->next) if (x == link) { alive = 1; break; } if (!alive) return; - if (is_tcp && tcp_link) stcp_link_close(tcp_link); + if (is_tcp && link->tcp_link) { stcp_link_close(link->tcp_link); link->tcp_link = NULL; } if (old_link_status) { DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %d down: addr=%s ka=%d remote_ka=%d state=%d init=%d tmo: %llu>%llu els=%llums", etcp->log_name, local_link_id, sockaddr_storage_to_str(&raddr).str, 0, remote_ka, link_state, initialized, (unsigned long long)timeout_units, (unsigned long long)elapsed, (unsigned long long)(elapsed/10)); } diff --git a/src/transport_layer/stcp_link.c b/src/transport_layer/stcp_link.c index 9d1c94fa..66311d2d 100644 --- a/src/transport_layer/stcp_link.c +++ b/src/transport_layer/stcp_link.c @@ -282,6 +282,7 @@ static void stcp_link_close_impl(void *arg) { stcp_conn_do_close(conn, 0); link->conn = NULL; } + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_link_close_impl: link=%p cli=%p conn=%p conn_pre_closed=%d", (void*)link, (void*)link->cli, (void*)link->conn, link->conn_pre_closed); u_free(link); } @@ -289,6 +290,9 @@ void stcp_link_close(struct stcp_link *link) { if (!link) return; if (link->closing) return; link->closing = 1; + /* Обрыв вперёд-ссылки родителя: после отложенного free (close_impl) + * etcp_link->tcp_link не должен остаться висячим. */ + if (link->etcp_link && link->etcp_link->tcp_link == link) link->etcp_link->tcp_link = NULL; link->etcp_conn = NULL; link->etcp_link = NULL; /* Явный teardown гасит «внезапное» уведомление: отложенный stcp_link_close_impl @@ -296,6 +300,7 @@ void stcp_link_close(struct stcp_link *link) { * on_close_cb с уже освобождённым ETCP_LINK. */ link->on_close_cb = NULL; link->close_arg = NULL; + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_link_close: link=%p closing=%d", (void*)link, link->closing); if (link->cli) { struct stcp_conn *c = stcp_client_get_conn(link->cli);