From 08c42e62ef09eb2978c0a6542a713d5a1308ba60 Mon Sep 17 00:00:00 2001 From: evgeny Date: Fri, 23 Oct 2026 00:02:57 +0200 Subject: [PATCH] Reproduce ACK starvation behind the reverse-direction DATA pacer --- tests/test_etcp_windows.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/test_etcp_windows.c b/tests/test_etcp_windows.c index ce5abf93..423e3555 100644 --- a/tests/test_etcp_windows.c +++ b/tests/test_etcp_windows.c @@ -307,6 +307,22 @@ static void immediate_send(void) { ack_all(); teardown(); } +/* Подтверждения входящего потока не должны ждать pacing собственного исходящего DATA. */ +static void ack_without_data_pacing(void) { + setup(); b->link_status = 0; a->bandwidth = 1; + a->shaper_timer = uasync_set_timeout(ua, 1000, a, shaper_ready, "test_shaper"); CHECK(a->shaper_timer); + void* timer = a->shaper_timer; + uint64_t load = a->shaper_load_time_tb, fraction = a->shaper_sub_nanotime; + struct ACK_PACKET* confirmation = (struct ACK_PACKET*)queue_entry_new_from_pool(inst.ack_pool); CHECK(confirmation); + confirmation->seq = 777; + CHECK(queue_data_put_with_index(conn->ack_q, &confirmation->ll) == 0); + enqueue(100); uasync_drain_immediate(ua); + CHECK(sends == 1 && conn->input_send_q->count == 1 && !conn->ack_q->count); + CHECK(a->shaper_timer == timer && a->shaper_load_time_tb == load && a->shaper_sub_nanotime == fraction); + uasync_cancel_timeout(ua, timer); a->shaper_timer = NULL; + etcp_conn_wake_sender(conn); wait_sends(2); ack_all(); teardown(); +} + int main(void) { debug_config_init(); debug_set_level(DEBUG_LEVEL_ERROR); if (getenv("UTUN_TEST_DEBUG")) debug_set_category_level(DEBUG_CATEGORY_ETCP, DEBUG_LEVEL_DEBUG); @@ -314,7 +330,7 @@ int main(void) { size_t baseline = u_get_allocated_count(); void (*cases[])(void) = {selection, boundaries_ack_burst, late_ack_and_migration, lost_ack_and_shrink, grow_and_session, allocation_and_send_failure, removed_link_and_bbr, pacing_reset_close, initial_readiness, - config_limits, timer_failure, immediate_send}; + config_limits, timer_failure, immediate_send, ack_without_data_pacing}; for (unsigned i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { cases[i](); CHECK(u_get_allocated_count() == baseline); DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "PASS ETCP window scenario %u", i);