Browse Source

Shorten RX deadline immediately when a sleeping peer wakes

master
evgeny 13 hours ago
parent
commit
85b4af5b1d
  1. 8
      src/transport_layer/etcp_keepalive.c
  2. 20
      tests/test_etcp_server_lifecycle.c

8
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;

20
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;
}

Loading…
Cancel
Save