diff --git a/tests/Makefile.am b/tests/Makefile.am index 7fbf8c1e..e5ddeb7b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1056,7 +1056,8 @@ test_etcp_multipath_LDFLAGS = $(test_clock_ldflags) -Wl,--wrap=etcp_dump_pkt_sec test_stcp_sigpipe_SOURCES = test_stcp_sigpipe.c test_stcp_sigpipe_LDADD = $(LIBUTUN) $(COMMON_LIBS) test_etcp_windows_LDADD = $(LIBUTUN) $(COMMON_LIBS) -test_etcp_windows_LDFLAGS = $(test_clock_ldflags) -Wl,--wrap=get_time_tb -Wl,--wrap=etcp_encrypt_send -Wl,--wrap=memory_pool_alloc_impl \ +test_etcp_windows_LDFLAGS = $(test_clock_ldflags) -Wl,--wrap=get_time_tb -Wl,--wrap=get_time_us \ + -Wl,--wrap=etcp_encrypt_send -Wl,--wrap=memory_pool_alloc_impl \ -Wl,--wrap=bbr_main -Wl,--wrap=uasync_set_timeout -Wl,--wrap=uasync_call_soon -Wl,--wrap=ll_alloc_lldgram \ -Wl,--wrap=u_malloc_impl -Wl,--wrap=u_calloc_impl -Wl,--wrap=u_realloc_impl -Wl,--wrap=random_bytes diff --git a/tests/test_etcp_windows.c b/tests/test_etcp_windows.c index 993df7f8..d7dec5b2 100644 --- a/tests/test_etcp_windows.c +++ b/tests/test_etcp_windows.c @@ -33,13 +33,21 @@ static uint32_t last_mss; static unsigned fail_rx_message_at, fail_tx_inflight, fail_normalizer_timer, fail_normalizer_waiter, fail_session_timer_at; static unsigned no_alloc, unexpected_alloc, fail_rng, session_sends, received, receive_action; static uint8_t received_values[8]; +static unsigned ack_clock_active, capture_ack_timer, fail_ack_timer; +static uint64_t ack_now_us; +static timeout_callback_t captured_ack_callback; +static void* captured_ack_arg; /* Фиксируем только TB на время синхронной проверки pacer; uasync при этих часах не опрашивается. */ uint64_t __real_get_time_tb(void); uint64_t __wrap_get_time_tb(void) { + if (ack_clock_active) return ack_now_us / 100; return pacer_clock_active ? pacer_now_tb : __real_get_time_tb(); } +uint64_t __real_get_time_us(void); +uint64_t __wrap_get_time_us(void) { return ack_clock_active ? ack_now_us : __real_get_time_us(); } + void* __real_uasync_call_soon(struct UASYNC*, void*, timeout_callback_t); void* __wrap_uasync_call_soon(struct UASYNC* loop, void* arg, timeout_callback_t callback) { if (fail_normalizer_timer && conn && arg == conn->normalizer) { fail_normalizer_timer--; return NULL; } @@ -52,6 +60,8 @@ void* __wrap_uasync_call_soon(struct UASYNC* loop, void* arg, timeout_callback_t void* __real_uasync_set_timeout(struct UASYNC*, int, void*, timeout_callback_t, const char*); void* __wrap_uasync_set_timeout(struct UASYNC* loop, int delay, void* arg, timeout_callback_t callback, const char* name) { + if (capture_ack_timer && !strcmp(name, "etcp_ack_resp")) { captured_ack_callback = callback; captured_ack_arg = arg; } + if (fail_ack_timer && !strcmp(name, "etcp_ack_resp")) { fail_ack_timer--; return NULL; } if (capture_shaper && name && !strcmp(name, "etcp_shaper")) { shaper_arm_count++; captured_shaper_delay = delay; captured_shaper_callback = callback; captured_shaper_arg = arg; @@ -152,6 +162,8 @@ static void setup(void) { fail_rx_message_at = fail_tx_inflight = fail_normalizer_timer = fail_normalizer_waiter = fail_session_timer_at = 0; no_alloc = unexpected_alloc = fail_rng = session_sends = received = receive_action = 0; memset(received_values, 0, sizeof(received_values)); + ack_clock_active = capture_ack_timer = fail_ack_timer = 0; + captured_ack_callback = NULL; captured_ack_arg = NULL; last_sent_link = NULL; last_sent_request = last_sent_payload = 0; ua = uasync_create(); CHECK(ua); inst.ua = ua; inst.node_id = 1; inst.config = &cfg; cfg.global.bbr_max_cwnd = INFLIGHT_LIM_MAX; @@ -175,6 +187,7 @@ static void setup(void) { } static void teardown(void) { + ack_clock_active = 0; check_accounting(); etcp_connection_close(conn); conn = NULL; uasync_poll(ua, 0); @@ -1124,6 +1137,21 @@ static void independent_attempt_acks(void) { check_accounting(); teardown(); } +/* Посторонний wake не снимает задержку ACK; точные границы проверяются без опроса uasync при ручных часах. */ +static void ack_absolute_deadline(void) { + setup(); conn->got_initial_pkt = 1; + ack_now_us = get_time_us(); ack_clock_active = capture_ack_timer = 1; + receive_fragment(a, 2, 1); CHECK(a->ack_q->count == 1 && conn->ack_resp_timer); + etcp_conn_wake_sender(conn); + struct ETCP_DGRAM* pkt = request(); + DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "ACK deadline: age_us=0 queued=%d sent_early=%u", a->ack_q->count, pkt != NULL); + CHECK(!pkt && a->ack_q->count == 1); + ack_now_us += 1999; CHECK(!request() && a->ack_q->count == 1); + ack_now_us++; pkt = request(); CHECK(pkt && pkt->link == a && pkt->data[1] == 1); + memory_pool_free(inst.pkt_pool, pkt); CHECK(!a->ack_q->count && !conn->ack_resp_timer); + teardown(); +} + static void receive_admission_and_path_acks(void) { setup(); conn->got_initial_pkt = 1; fail_rx_data = 1; receive_fragment(a, 2, 1); @@ -1545,7 +1573,7 @@ int main(void) { retry_waits_for_alternative, retry_alternative_lifecycle, send_queue_scan, send_queue_input_admission, retry_full_round_history, retry_history_slot_reuse, fast_stall_progress, stalled_retry_selection, input_admission_callbacks, - receive_admission_and_path_acks, peer_window_queries, pacing_continuity, pacing_data_units, attempt_memory_limits, + ack_absolute_deadline, receive_admission_and_path_acks, peer_window_queries, pacing_continuity, pacing_data_units, attempt_memory_limits, normalizer_rx_oom, normalizer_tx_oom, normalizer_callback_abort, reset_without_allocation, restart_allocation_failures, receiver_bandwidth_bounds, receiver_point_lifecycle, receiver_point_wire, receiver_point_truncated, compact_attempt_identity, compact_attempt_exhaustion, compact_sequence_exhaustion,