diff --git a/src/transport_layer/etcp_keepalive.c b/src/transport_layer/etcp_keepalive.c index ed97bfb2..ff42f9b2 100644 --- a/src/transport_layer/etcp_keepalive.c +++ b/src/transport_layer/etcp_keepalive.c @@ -159,8 +159,14 @@ void etcp_keepalive_watch_rx(struct ETCP_LINK* link) { sleep_ms += (uint64_t)link->keepalive_interval * KA_TIMEOUT_MULT; if (sleep_ms > timeout_ms) timeout_ms = sleep_ms; } + uint64_t previous_deadline = link->rx_deadline_tb; link->rx_deadline_tb = link->last_recv_local_time + timeout_ms * 10; - if (link->rx_timeout_timer) return; + if (link->rx_timeout_timer && link->rx_deadline_tb >= previous_deadline) return; + if (link->rx_timeout_timer) { + uasync_cancel_timeout(link->etcp->instance->ua, link->rx_timeout_timer); link->rx_timeout_timer = NULL; + DEBUG_DEBUG(DEBUG_CATEGORY_KEEPALIVE, "[%s] RX deadline shortened link=%u timeout_ms=%llu", + link->etcp->log_name, link->local_link_id, (unsigned long long)timeout_ms); + } uint64_t now = get_time_tb(); uint64_t remaining = link->rx_deadline_tb > now ? link->rx_deadline_tb - now : 1; int delay = remaining > INT_MAX ? INT_MAX : (int)remaining; diff --git a/tests/test_etcp_server_lifecycle.c b/tests/test_etcp_server_lifecycle.c index 474ed644..b4659d5b 100644 --- a/tests/test_etcp_server_lifecycle.c +++ b/tests/test_etcp_server_lifecycle.c @@ -143,7 +143,7 @@ static void check_silent_peer(int tcp) { static void check_sleep(void) { setup(); struct ETCP_CONN* conn = ready_conn(1); struct ETCP_LINK* link = conn->links; struct ETCP_DGRAM* pkt = memory_pool_alloc(inst.pkt_pool); CHECK(pkt); - memset(pkt, 0, sizeof(*pkt)); pkt->data_len = 8; pkt->data[0] = ETCP_KEEPALIVE; pkt->data[1] = KA_FLAG_SLEEP; + memset(pkt, 0, sizeof(*pkt) + 8); pkt->data_len = 8; pkt->data[0] = ETCP_KEEPALIVE; pkt->data[1] = KA_FLAG_SLEEP; pkt->data[2] = 0xe8; pkt->data[3] = 3; pkt->data[4] = 5; pkt->data[6] = 200; // 1 s period, 0.5 s ACTIVE, 20 s SLEEP CHECK(etcp_keepalive_on_recv(&sock, pkt, link, 11) == 1); CHECK(link->ka_peer_sleeping && !link->keepalive_timer && link->rx_timeout_timer); @@ -158,6 +158,23 @@ static void check_sleep(void) { teardown(); DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "PASS sleeping peer deadline, FIN_WAIT and disappearance"); } +/* Пробуждение сокращает RX timeout сразу, не оставляя таймер прежнего длинного сна. */ +static void check_wake_deadline(void) { + setup(); struct ETCP_CONN* conn = ready_conn(1); struct ETCP_LINK* link = conn->links; + struct ETCP_DGRAM* pkt = memory_pool_alloc(inst.pkt_pool); CHECK(pkt); + memset(pkt, 0, sizeof(*pkt) + 8); pkt->data_len = 8; pkt->data[0] = ETCP_KEEPALIVE; pkt->data[1] = KA_FLAG_SLEEP; + pkt->data[2] = 0xe8; pkt->data[3] = 3; pkt->data[6] = 200; + CHECK(etcp_keepalive_on_recv(&sock, pkt, link, 11) == 1); + test_clock_run_for(inst.ua, 10000); CHECK(conn->links_up && link->ka_peer_sleeping); + pkt = memory_pool_alloc(inst.pkt_pool); CHECK(pkt); memset(pkt, 0, sizeof(*pkt) + 4); + pkt->data_len = 4; pkt->data[0] = ETCP_KEEPALIVE; pkt->data[2] = 200; + link->last_recv_local_time = get_time_tb(); + CHECK(etcp_keepalive_on_recv(&sock, pkt, link, 7) == 1); CHECK(!link->ka_peer_sleeping); + test_clock_run_for(inst.ua, 10000); CHECK(conn->links_up); + test_clock_run_for(inst.ua, 20000); CHECK(!conn->links_up && conn->down_timer && !deleted); + teardown(); DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "PASS wake replaces long sleep deadline with normal timeout"); +} + /* Мягкое закрытие работает без NCD entry; KEEP_ALIVE сохраняет транспорт дольше прежних 5 секунд. */ static void check_graceful(void) { setup(); struct ETCP_CONN* conn = ready_conn(0); @@ -187,6 +204,7 @@ int main(void) { check_silent_peer(0); CHECK(u_get_allocated_count() == baseline); check_silent_peer(1); CHECK(u_get_allocated_count() == baseline); check_sleep(); CHECK(u_get_allocated_count() == baseline); + check_wake_deadline(); CHECK(u_get_allocated_count() == baseline); check_graceful(); CHECK(u_get_allocated_count() == baseline); test_clock_finish(); return 0; }