Browse Source

keepalive: убрать периодический keepalive в standby (обе стороны молчат, только фазовые анонсы + один ack)

proxy
evgeny 2 weeks ago
parent
commit
331c7849f0
  1. 36
      src/transport_layer/etcp_keepalive.c
  2. 14
      src/transport_layer/etcp_keepalive.h

36
src/transport_layer/etcp_keepalive.c

@ -124,6 +124,14 @@ static void keepalive_timer_cb(void* arg) {
link->keepalive_timer = NULL; link->keepalive_timer = NULL;
// Клиент в standby: ничего не делаем (recovery/dead-link/отправка) — только переарм.
// Фазу сигналят фазовые переходы (ka_phase_cb), NAT держит сам сон (sleep ≤ NAT-таймаут).
if (link->ka_sleeping && !link->is_server) {
link->keepalive_timer = uasync_set_timeout(link->etcp->instance->ua,
link->ka_period_ms * 10, link, keepalive_timer_cb, "link_keepalive");
return;
}
// Check if all links are down and start recovery if needed (client only) // Check if all links are down and start recovery if needed (client only)
if (link->is_server == 0 && etcp_all_links_down(link->etcp)) { if (link->is_server == 0 && etcp_all_links_down(link->etcp)) {
if (link->is_tcp) { if (link->is_tcp) {
@ -187,14 +195,10 @@ static void keepalive_timer_cb(void* arg) {
} }
link->pkt_sent_since_keepalive = 0; link->pkt_sent_since_keepalive = 0;
// Отправка keepalive (в спячке — с флагом и свежим дедлайном) // Отправка keepalive: в спячке НЕ шлём (ни клиент, ни сервер) — фазу сигналят фазовые переходы.
if (link->ka_sleeping) { if (!link->ka_sleeping) {
if (link->is_server) if (!link->is_server || link->recv_keepalive)
etcp_link_send_keepalive(link); /* echo: поля уже зеркальны из on_recv */ etcp_link_send_keepalive(link);
else
ka_send_sleep_keepalive(link); /* клиент: пересчитать тайминг и анонс */
} else if (!link->is_server || link->recv_keepalive) {
etcp_link_send_keepalive(link);
} }
restart_timer: restart_timer:
@ -272,11 +276,9 @@ static void ka_client_enter_sleep(struct ETCP_LINK* link) {
restart_keepalive_timer_ms(link, period); restart_keepalive_timer_ms(link, period);
} }
// Клиент: переанонс на входе в очередной цикл спячки (обновить дедлайн). // Клиент: переанонс на входе в очередной цикл спячки (обновить фазу, без ре-ack).
static void ka_client_reannounce(struct ETCP_LINK* link) { static void ka_client_reannounce(struct ETCP_LINK* link) {
if (!link->ka_sleeping) return; if (!link->ka_sleeping) return;
link->ka_sleep_acked = 0;
link->ka_sleep_announce_end_tb = get_time_tb() + (uint64_t)KA_SLEEP_ANNOUNCE_TIMEOUT_MS * 10;
ka_send_sleep_keepalive(link); ka_send_sleep_keepalive(link);
} }
@ -400,7 +402,9 @@ int etcp_keepalive_on_recv(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt,
uint16_t sleep_duration = (pkt->data_len >= 8) uint16_t sleep_duration = (pkt->data_len >= 8)
? (pkt->data[6] | ((uint16_t)pkt->data[7] << 8)) : 0; ? (pkt->data[6] | ((uint16_t)pkt->data[7] << 8)) : 0;
if (link->is_server) { if (link->is_server) {
/* Сервер: пир в спячке — зеркалим флаг/поля для эхо и ведём фазу троттлинга. */ /* Сервер: пир в спячке — зеркалим флаг/поля и ведём фазу троттлинга.
ack-эхо шлём только на анонсе (переход 0→1), дальше в спячке молчим. */
int was_sleeping = link->ka_sleeping;
link->ka_sleeping = 1; link->ka_sleeping = 1;
link->ka_sleep_period_ms = peer_period; link->ka_sleep_period_ms = peer_period;
link->ka_active_remaining = active_remaining; link->ka_active_remaining = active_remaining;
@ -412,11 +416,13 @@ int etcp_keepalive_on_recv(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt,
ka_server_set_phase(link->etcp, active_remaining == 0); ka_server_set_phase(link->etcp, active_remaining == 0);
ka_server_arm_phase(link->etcp); ka_server_arm_phase(link->etcp);
} }
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] server: peer sleeping (period=%dms active_rem=%d.%ds sleep_dur=%d.%ds), echo ack", DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] server: peer sleeping (period=%dms active_rem=%d.%ds sleep_dur=%d.%ds), echo=%s",
link->etcp->log_name, peer_period, link->etcp->log_name, peer_period,
(int)(active_remaining / 10), (int)(active_remaining % 10), (int)(active_remaining / 10), (int)(active_remaining % 10),
(int)(sleep_duration / 10), (int)(sleep_duration % 10)); (int)(sleep_duration / 10), (int)(sleep_duration % 10),
etcp_link_send_keepalive(link); was_sleeping ? "no" : "ack");
if (!was_sleeping)
etcp_link_send_keepalive(link);
restart_keepalive_timer_ms(link, peer_period); restart_keepalive_timer_ms(link, peer_period);
} else { } else {
/* Клиент: ack/эхо сервера — анонс завершён. */ /* Клиент: ack/эхо сервера — анонс завершён. */

14
src/transport_layer/etcp_keepalive.h

@ -17,16 +17,16 @@ extern "C" {
* *
* data[0] = ETCP_KEEPALIVE (0x08) * data[0] = ETCP_KEEPALIVE (0x08)
* data[1] = flags (bit0 = KA_FLAG_SLEEP — standby) * data[1] = flags (bit0 = KA_FLAG_SLEEP — standby)
* data[2..3] = ka_period_ms (LE 16-bit) — период keepalive в спячке, мс * data[2..3] = ka_period_ms (LE 16-bit) — база dead-link таймаута, мс
* data[4..5] = active_remaining (LE 16-bit, x0.1с) — до SLEEP-фазы (0 = уже спим) * data[4..5] = active_remaining (LE 16-bit, x0.1с) — до SLEEP-фазы (0 = уже спим)
* data[6..7] = sleep_duration (LE 16-bit, x0.1с) — длительность SLEEP-фазы * data[6..7] = sleep_duration (LE 16-bit, x0.1с) — длительность SLEEP-фазы
* *
* Клиент в standby шлёт ВСЕ keepalive с KA_FLAG_SLEEP. На входе в SLEEP-фазу — * В standby обе стороны НЕ шлют периодические keepalive: standby-время само
* active_remaining=0, sleep_duration=полная; на входе в ACTIVE-окно — * удерживает NAT (sleep ≤ NAT-таймаута). Keepalive шлёт только клиент, и только
* active_remaining=остаток окна; периодические — active_remaining=0, * на фазовых переходах duty-cycle: вход в SLEEP (active_remaining=0,
* sleep_duration=оставшийся сон. Сервер по этим полям ведёт фазу троттлинга * sleep_duration=полная) и вход в ACTIVE (active_remaining=остаток окна). Сервер
* (SLEEP-фаза → тормозим протоколы, ACTIVE-окно → обмен) и эхо-подтверждает * по этим полям ведёт фазу троттлинга (SLEEP-фаза → тормозим протоколы,
* флаг как есть. * ACTIVE-окно → обмен) и ack-эхом отвечает один раз на анонсе (переход флага 0→1).
* *
* Засыпание (клиент): анонс + ретраи KA_SLEEP_RETRY_MS до ack (эхо с флагом), * Засыпание (клиент): анонс + ретраи KA_SLEEP_RETRY_MS до ack (эхо с флагом),
* окно KA_SLEEP_ANNOUNCE_TIMEOUT_MS, после чего спит anyway. * окно KA_SLEEP_ANNOUNCE_TIMEOUT_MS, после чего спит anyway.

Loading…
Cancel
Save