diff --git a/src/transport_layer/etcp_api.c b/src/transport_layer/etcp_api.c index 656abf29..cc54c54b 100644 --- a/src/transport_layer/etcp_api.c +++ b/src/transport_layer/etcp_api.c @@ -131,6 +131,7 @@ void etcp_fire_link_status_cbk(struct ETCP_LINK* link, int old_state, int old_st 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++; + link->active_users++; inst->etcp_callbacks_depth++; struct etcp_link_status_cbk_entry* cbe = conn->instance->link_status_cbks; while (cbe) { @@ -144,7 +145,7 @@ void etcp_fire_link_status_cbk(struct ETCP_LINK* link, int old_state, int old_st } cbe = cbe->next; } - conn->callbacks_running--; + etcp_link_release(link); conn->callbacks_running--; inst->etcp_callbacks_depth--; etcp_instance_callbacks_collect(inst); } diff --git a/src/transport_layer/etcp_keepalive.c b/src/transport_layer/etcp_keepalive.c index 31b9c565..af60957a 100644 --- a/src/transport_layer/etcp_keepalive.c +++ b/src/transport_layer/etcp_keepalive.c @@ -298,30 +298,27 @@ static uint8_t ka_announce_max_calc(struct ETCP_LINK* link) { // Разрыв линка (мёртвый пир в спячке). Может освободить link — после вызова link не трогать. static void ka_link_down(struct ETCP_LINK* link) { - if (!link || !link->etcp) return; + if (!link || !link->etcp || link->closing || link->etcp->close_requested) return; + struct ETCP_CONN* etcp = link->etcp; + etcp->callbacks_running++; link->active_users++; if (link->rx_timeout_timer) { uasync_cancel_timeout(link->etcp->instance->ua, link->rx_timeout_timer); link->rx_timeout_timer = NULL; } link->recv_keepalive = 0; int old_link_status = link->link_status; link->link_status = 0; - etcp_fire_link_status_cbk(link, link->link_state, old_link_status); - struct ETCP_CONN* etcp = link->etcp; - int is_tcp = link->is_tcp; - int local_link_id = link->local_link_id; - struct sockaddr_storage raddr = link->remote_addr; - uint8_t remote_ka = link->remote_keepalive; - int link_state = link->link_state, initialized = link->initialized; - etcp_on_link_down(etcp, link); - if (etcp->state == 2) return; /* conn+link освобождены каскадом */ - 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 && 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 (peer unresponsive): addr=%s remote_ka=%d state=%d init=%d", - etcp->log_name, local_link_id, sockaddr_storage_to_str(&raddr).str, remote_ka, link_state, initialized); + DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %u down (peer unresponsive): addr=%s remote_ka=%u state=%u init=%u", + etcp->log_name, link->local_link_id, sockaddr_storage_to_str(&link->remote_addr).str, + link->remote_keepalive, link->link_state, link->initialized); } + etcp_fire_link_status_cbk(link, link->link_state, old_link_status); + if (!etcp_link_is_alive(etcp, link)) goto done; + etcp_on_link_down(etcp, link); + if (!etcp_link_is_alive(etcp, link)) goto done; + if (link->is_tcp && link->tcp_link) { stcp_link_close(link->tcp_link); link->tcp_link = NULL; } +done: + etcp_link_release(link); etcp->callbacks_running--; } // Отправить один анонс спячки с таймингом.