|
|
|
@ -15,9 +15,10 @@ |
|
|
|
static void keepalive_timer_cb(void* arg); |
|
|
|
static void keepalive_timer_cb(void* arg); |
|
|
|
static int etcp_all_links_down(struct ETCP_CONN* etcp); |
|
|
|
static int etcp_all_links_down(struct ETCP_CONN* etcp); |
|
|
|
static void ka_send_sleep_keepalive(struct ETCP_LINK* link); |
|
|
|
static void ka_send_sleep_keepalive(struct ETCP_LINK* link); |
|
|
|
|
|
|
|
static void ka_send_sleep_ack(struct ETCP_LINK* link); |
|
|
|
static void ka_announce_retry_cb(void* arg); |
|
|
|
static void ka_announce_retry_cb(void* arg); |
|
|
|
static void ka_client_enter_sleep(struct ETCP_LINK* link); |
|
|
|
static void ka_enter_sleep(struct ETCP_LINK* link); |
|
|
|
static void ka_client_wake(struct ETCP_LINK* link); |
|
|
|
static void ka_wake(struct ETCP_LINK* link); |
|
|
|
|
|
|
|
|
|
|
|
// === перенесено из etcp_connections.c без изменений ===
|
|
|
|
// === перенесено из etcp_connections.c без изменений ===
|
|
|
|
|
|
|
|
|
|
|
|
@ -35,7 +36,7 @@ uint16_t negotiate_keepalive(uint8_t my_type, uint16_t my_ka, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Send keepalive packet: code(0x08) + flags + ka_period_ms + [active_remaining + sleep_duration]
|
|
|
|
// Send keepalive packet: code(0x08) + flags + ka_period_ms + [active_remaining + sleep_duration]
|
|
|
|
void etcp_link_send_keepalive(struct ETCP_LINK* link) { |
|
|
|
static void etcp_link_send_keepalive_ex(struct ETCP_LINK* link, uint8_t flags) { |
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_KEEPALIVE, ""); |
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_KEEPALIVE, ""); |
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
|
|
|
|
|
|
|
|
@ -47,10 +48,10 @@ void etcp_link_send_keepalive(struct ETCP_LINK* link) { |
|
|
|
|
|
|
|
|
|
|
|
dgram->link = link; |
|
|
|
dgram->link = link; |
|
|
|
dgram->data[0] = ETCP_KEEPALIVE; |
|
|
|
dgram->data[0] = ETCP_KEEPALIVE; |
|
|
|
dgram->data[1] = link->ka_sleeping ? KA_FLAG_SLEEP : 0; |
|
|
|
dgram->data[1] = flags; |
|
|
|
dgram->data[2] = link->ka_period_ms & 0xFF; |
|
|
|
dgram->data[2] = link->ka_period_ms & 0xFF; |
|
|
|
dgram->data[3] = link->ka_period_ms >> 8; |
|
|
|
dgram->data[3] = link->ka_period_ms >> 8; |
|
|
|
if (link->ka_sleeping) { |
|
|
|
if (flags & KA_FLAG_SLEEP) { |
|
|
|
dgram->data[4] = link->ka_active_remaining & 0xFF; |
|
|
|
dgram->data[4] = link->ka_active_remaining & 0xFF; |
|
|
|
dgram->data[5] = link->ka_active_remaining >> 8; |
|
|
|
dgram->data[5] = link->ka_active_remaining >> 8; |
|
|
|
dgram->data[6] = link->ka_sleep_duration & 0xFF; |
|
|
|
dgram->data[6] = link->ka_sleep_duration & 0xFF; |
|
|
|
@ -69,6 +70,11 @@ void etcp_link_send_keepalive(struct ETCP_LINK* link) { |
|
|
|
u_free(dgram); |
|
|
|
u_free(dgram); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Обычный keepalive (без sleep-флагов): «жив» / «проснулся».
|
|
|
|
|
|
|
|
void etcp_link_send_keepalive(struct ETCP_LINK* link) { |
|
|
|
|
|
|
|
etcp_link_send_keepalive_ex(link, 0); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Check if all links for an ETCP_CONN are down
|
|
|
|
// Check if all links for an ETCP_CONN are down
|
|
|
|
// Returns 1 if all links are down or no links exist, 0 otherwise
|
|
|
|
// Returns 1 if all links are down or no links exist, 0 otherwise
|
|
|
|
static int etcp_all_links_down(struct ETCP_CONN* etcp) { |
|
|
|
static int etcp_all_links_down(struct ETCP_CONN* etcp) { |
|
|
|
@ -124,9 +130,10 @@ 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-таймаут).
|
|
|
|
// никакого recovery/dead-link/отправки. Фазу сигналят фазовые переходы (ka_phase_cb),
|
|
|
|
if (link->ka_sleeping && !link->is_server) { |
|
|
|
// NAT держит сам сон (sleep ≤ NAT-таймаут).
|
|
|
|
|
|
|
|
if (link->ka_sleeping) { |
|
|
|
link->keepalive_timer = uasync_set_timeout(link->etcp->instance->ua, |
|
|
|
link->keepalive_timer = uasync_set_timeout(link->etcp->instance->ua, |
|
|
|
link->ka_period_ms * 10, link, keepalive_timer_cb, "link_keepalive"); |
|
|
|
link->ka_period_ms * 10, link, keepalive_timer_cb, "link_keepalive"); |
|
|
|
return; |
|
|
|
return; |
|
|
|
@ -241,17 +248,22 @@ static uint16_t ka_sleep_duration_01s(void) { |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Отправить keepalive спячки (обновить поля тайминга) + при необходимости заармить ретрай.
|
|
|
|
// Отправить анонс спячки (обновить поля тайминга) + при необходимости заармить ретрай.
|
|
|
|
static void ka_send_sleep_keepalive(struct ETCP_LINK* link) { |
|
|
|
static void ka_send_sleep_keepalive(struct ETCP_LINK* link) { |
|
|
|
link->ka_active_remaining = ka_active_remaining_01s(); |
|
|
|
link->ka_active_remaining = ka_active_remaining_01s(); |
|
|
|
link->ka_sleep_duration = ka_sleep_duration_01s(); |
|
|
|
link->ka_sleep_duration = ka_sleep_duration_01s(); |
|
|
|
etcp_link_send_keepalive(link); |
|
|
|
etcp_link_send_keepalive_ex(link, KA_FLAG_SLEEP); |
|
|
|
if (!link->ka_sleep_acked && link->ka_sleep_announce_timer == NULL) { |
|
|
|
if (!link->ka_sleep_acked && link->ka_sleep_announce_timer == NULL) { |
|
|
|
link->ka_sleep_announce_timer = uasync_set_timeout(link->etcp->instance->ua, |
|
|
|
link->ka_sleep_announce_timer = uasync_set_timeout(link->etcp->instance->ua, |
|
|
|
KA_SLEEP_RETRY_MS * 10, link, ka_announce_retry_cb, "ka_sleep_announce"); |
|
|
|
KA_SLEEP_RETRY_MS * 10, link, ka_announce_retry_cb, "ka_sleep_announce"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Ответ на анонс спячки пира: подтверждение доставки (без тайминга).
|
|
|
|
|
|
|
|
static void ka_send_sleep_ack(struct ETCP_LINK* link) { |
|
|
|
|
|
|
|
etcp_link_send_keepalive_ex(link, KA_FLAG_SLEEP_ACK); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void ka_announce_retry_cb(void* arg) { |
|
|
|
static void ka_announce_retry_cb(void* arg) { |
|
|
|
struct ETCP_LINK* link = (struct ETCP_LINK*)arg; |
|
|
|
struct ETCP_LINK* link = (struct ETCP_LINK*)arg; |
|
|
|
link->ka_sleep_announce_timer = NULL; |
|
|
|
link->ka_sleep_announce_timer = NULL; |
|
|
|
@ -261,8 +273,8 @@ static void ka_announce_retry_cb(void* arg) { |
|
|
|
ka_send_sleep_keepalive(link); // ретрай
|
|
|
|
ka_send_sleep_keepalive(link); // ретрай
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Клиент: вход в спячку (анонс с ретраями).
|
|
|
|
// Вход в спячку (анонс с ретраями) — моя сторона.
|
|
|
|
static void ka_client_enter_sleep(struct ETCP_LINK* link) { |
|
|
|
static void ka_enter_sleep(struct ETCP_LINK* link) { |
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
uint16_t period = ka_sleep_period_ms(link->etcp->instance); |
|
|
|
uint16_t period = ka_sleep_period_ms(link->etcp->instance); |
|
|
|
link->ka_sleeping = 1; |
|
|
|
link->ka_sleeping = 1; |
|
|
|
@ -271,19 +283,19 @@ static void ka_client_enter_sleep(struct ETCP_LINK* link) { |
|
|
|
link->ka_period_ms = period; |
|
|
|
link->ka_period_ms = period; |
|
|
|
link->keepalive_timeout = (uint32_t)period * KA_TIMEOUT_MULT; |
|
|
|
link->keepalive_timeout = (uint32_t)period * KA_TIMEOUT_MULT; |
|
|
|
link->ka_sleep_announce_end_tb = get_time_tb() + (uint64_t)KA_SLEEP_ANNOUNCE_TIMEOUT_MS * 10; |
|
|
|
link->ka_sleep_announce_end_tb = get_time_tb() + (uint64_t)KA_SLEEP_ANNOUNCE_TIMEOUT_MS * 10; |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] client entering sleep (period=%dms)", link->etcp->log_name, period); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] entering sleep (period=%dms)", link->etcp->log_name, period); |
|
|
|
ka_send_sleep_keepalive(link); |
|
|
|
ka_send_sleep_keepalive(link); |
|
|
|
restart_keepalive_timer_ms(link, period); |
|
|
|
restart_keepalive_timer_ms(link, period); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Клиент: переанонс на входе в очередной цикл спячки (обновить фазу, без ре-ack).
|
|
|
|
// Переанонс на входе в очередной цикл спячки (обновить фазу, без ре-ack).
|
|
|
|
static void ka_client_reannounce(struct ETCP_LINK* link) { |
|
|
|
static void ka_reannounce(struct ETCP_LINK* link) { |
|
|
|
if (!link->ka_sleeping) return; |
|
|
|
if (!link->ka_sleeping) return; |
|
|
|
ka_send_sleep_keepalive(link); |
|
|
|
ka_send_sleep_keepalive(link); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Клиент: пробуждение (форграунд) — обычный keepalive, возврат к базовому периоду.
|
|
|
|
// Пробуждение (форграунд) — обычный keepalive, возврат к базовому периоду.
|
|
|
|
static void ka_client_wake(struct ETCP_LINK* link) { |
|
|
|
static void ka_wake(struct ETCP_LINK* link) { |
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
if (!link->ka_sleeping) return; |
|
|
|
if (!link->ka_sleeping) return; |
|
|
|
link->ka_sleeping = 0; |
|
|
|
link->ka_sleeping = 0; |
|
|
|
@ -294,7 +306,7 @@ static void ka_client_wake(struct ETCP_LINK* link) { |
|
|
|
} |
|
|
|
} |
|
|
|
link->ka_period_ms = (uint16_t)link->keepalive_interval; |
|
|
|
link->ka_period_ms = (uint16_t)link->keepalive_interval; |
|
|
|
link->keepalive_timeout = (uint32_t)link->keepalive_interval * KA_TIMEOUT_MULT; |
|
|
|
link->keepalive_timeout = (uint32_t)link->keepalive_interval * KA_TIMEOUT_MULT; |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] client woke up, back to normal (interval=%dms)", |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] woke up, back to normal (interval=%dms)", |
|
|
|
link->etcp->log_name, link->keepalive_interval); |
|
|
|
link->etcp->log_name, link->keepalive_interval); |
|
|
|
etcp_link_send_keepalive(link); |
|
|
|
etcp_link_send_keepalive(link); |
|
|
|
restart_keepalive_timer_ms(link, link->ka_period_ms); |
|
|
|
restart_keepalive_timer_ms(link, link->ka_period_ms); |
|
|
|
@ -322,8 +334,8 @@ static void ka_for_each_link(struct UTUN_INSTANCE* inst, ka_link_fn fn) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#ifdef UTUN_HAVE_STANDBY |
|
|
|
#ifdef UTUN_HAVE_STANDBY |
|
|
|
// Клиент: вход в ACTIVE-окно — отправить keepalive с active_remaining>0 (флаг стоит).
|
|
|
|
// Вход в ACTIVE-окно — отправить keepalive с active_remaining>0 (флаг стоит).
|
|
|
|
static void ka_client_active_announce(struct ETCP_LINK* link) { |
|
|
|
static void ka_active_announce(struct ETCP_LINK* link) { |
|
|
|
if (!link->ka_sleeping) return; |
|
|
|
if (!link->ka_sleeping) return; |
|
|
|
ka_send_sleep_keepalive(link); |
|
|
|
ka_send_sleep_keepalive(link); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -333,37 +345,37 @@ static void ka_phase_cb(int sleeping, void* arg) { |
|
|
|
struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)arg; |
|
|
|
struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)arg; |
|
|
|
if (!inst || inst->client_type != CLIENT_TYPE_MOBILE) return; |
|
|
|
if (!inst || inst->client_type != CLIENT_TYPE_MOBILE) return; |
|
|
|
if (sleeping) { |
|
|
|
if (sleeping) { |
|
|
|
ka_for_each_link(inst, ka_client_reannounce); |
|
|
|
ka_for_each_link(inst, ka_reannounce); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "keepalive: duty-cycle SLEEP phase, re-announce (node=%016llx)", |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "keepalive: duty-cycle SLEEP phase, re-announce (node=%016llx)", |
|
|
|
(unsigned long long)inst->node_id); |
|
|
|
(unsigned long long)inst->node_id); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
ka_for_each_link(inst, ka_client_active_announce); |
|
|
|
ka_for_each_link(inst, ka_active_announce); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "keepalive: duty-cycle ACTIVE phase, announce (node=%016llx)", |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "keepalive: duty-cycle ACTIVE phase, announce (node=%016llx)", |
|
|
|
(unsigned long long)inst->node_id); |
|
|
|
(unsigned long long)inst->node_id); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
/* ── Сервер: машина фаз троттлинга (по active_remaining/sleep_duration) ── */ |
|
|
|
/* ── Пир: машина фаз троттлинга (по active_remaining/sleep_duration) ── */ |
|
|
|
|
|
|
|
|
|
|
|
static void ka_server_arm_phase(struct ETCP_CONN* etcp); |
|
|
|
static void ka_peer_arm_phase(struct ETCP_CONN* etcp); |
|
|
|
|
|
|
|
|
|
|
|
static void ka_server_set_phase(struct ETCP_CONN* etcp, int sleeping) { |
|
|
|
static void ka_peer_set_phase(struct ETCP_CONN* etcp, int sleeping) { |
|
|
|
if (!etcp) return; |
|
|
|
if (!etcp) return; |
|
|
|
if (etcp->peer_sleep_phase == (uint8_t)(sleeping ? 1 : 0)) return; |
|
|
|
if (etcp->peer_sleep_phase == (uint8_t)(sleeping ? 1 : 0)) return; |
|
|
|
etcp->peer_sleep_phase = sleeping ? 1 : 0; |
|
|
|
etcp->peer_sleep_phase = sleeping ? 1 : 0; |
|
|
|
utun_fire_peer_sleep_cbk(etcp->instance, etcp->peer_node_id, sleeping); |
|
|
|
utun_fire_peer_sleep_cbk(etcp->instance, etcp->peer_node_id, sleeping); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void ka_server_phase_timer_cb(void* arg) { |
|
|
|
static void ka_peer_phase_timer_cb(void* arg) { |
|
|
|
struct ETCP_CONN* etcp = (struct ETCP_CONN*)arg; |
|
|
|
struct ETCP_CONN* etcp = (struct ETCP_CONN*)arg; |
|
|
|
etcp->peer_phase_timer = NULL; |
|
|
|
etcp->peer_phase_timer = NULL; |
|
|
|
if (!etcp || etcp->state == 2) return; |
|
|
|
if (!etcp || etcp->state == 2) return; |
|
|
|
ka_server_set_phase(etcp, etcp->peer_sleep_phase ? 0 : 1); |
|
|
|
ka_peer_set_phase(etcp, etcp->peer_sleep_phase ? 0 : 1); |
|
|
|
ka_server_arm_phase(etcp); |
|
|
|
ka_peer_arm_phase(etcp); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void ka_server_arm_phase(struct ETCP_CONN* etcp) { |
|
|
|
static void ka_peer_arm_phase(struct ETCP_CONN* etcp) { |
|
|
|
if (!etcp || !etcp->instance) return; |
|
|
|
if (!etcp || !etcp->instance) return; |
|
|
|
uint16_t dur_01s = etcp->peer_sleep_phase ? etcp->peer_sleep_duration : etcp->peer_active_remaining; |
|
|
|
uint16_t dur_01s = etcp->peer_sleep_phase ? etcp->peer_sleep_duration : etcp->peer_active_remaining; |
|
|
|
if (etcp->peer_phase_timer) { |
|
|
|
if (etcp->peer_phase_timer) { |
|
|
|
@ -372,12 +384,12 @@ static void ka_server_arm_phase(struct ETCP_CONN* etcp) { |
|
|
|
} |
|
|
|
} |
|
|
|
/* гвард: нулевой тайминг (битый/legacy пакет) → не армать, иначе timer=0 даёт busy-loop */ |
|
|
|
/* гвард: нулевой тайминг (битый/legacy пакет) → не армать, иначе timer=0 даёт busy-loop */ |
|
|
|
if (dur_01s == 0) { |
|
|
|
if (dur_01s == 0) { |
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_KEEPALIVE, "[%s] server: zero phase duration (phase=%d), skip arming", |
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_KEEPALIVE, "[%s] peer: zero phase duration (phase=%d), skip arming", |
|
|
|
etcp->log_name, etcp->peer_sleep_phase); |
|
|
|
etcp->log_name, etcp->peer_sleep_phase); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
etcp->peer_phase_timer = uasync_set_timeout(etcp->instance->ua, (int)((uint32_t)dur_01s * 1000), |
|
|
|
etcp->peer_phase_timer = uasync_set_timeout(etcp->instance->ua, (int)((uint32_t)dur_01s * 1000), |
|
|
|
etcp, ka_server_phase_timer_cb, "peer_phase"); |
|
|
|
etcp, ka_peer_phase_timer_cb, "peer_phase"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int etcp_keepalive_on_recv(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, |
|
|
|
int etcp_keepalive_on_recv(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, |
|
|
|
@ -396,61 +408,52 @@ int etcp_keepalive_on_recv(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, |
|
|
|
|
|
|
|
|
|
|
|
uint8_t flags = (pkt->data_len >= 2) ? pkt->data[1] : 0; |
|
|
|
uint8_t flags = (pkt->data_len >= 2) ? pkt->data[1] : 0; |
|
|
|
|
|
|
|
|
|
|
|
if (flags & KA_FLAG_SLEEP) { |
|
|
|
if (flags & KA_FLAG_SLEEP_ACK) { |
|
|
|
|
|
|
|
/* Ответ на мой анонс сна — команда дошла, можно спать без ретраев. */ |
|
|
|
|
|
|
|
link->ka_sleep_acked = 1; |
|
|
|
|
|
|
|
if (link->ka_sleep_announce_timer) { |
|
|
|
|
|
|
|
uasync_cancel_timeout(e_sock->instance->ua, link->ka_sleep_announce_timer); |
|
|
|
|
|
|
|
link->ka_sleep_announce_timer = NULL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_KEEPALIVE, "[%s] sleep ack received", link->etcp->log_name); |
|
|
|
|
|
|
|
} else if (flags & KA_FLAG_SLEEP) { |
|
|
|
|
|
|
|
/* Пир объявил сон — заткнуться и вести фазу троттлинга по таймингу. */ |
|
|
|
uint16_t active_remaining = (pkt->data_len >= 6) |
|
|
|
uint16_t active_remaining = (pkt->data_len >= 6) |
|
|
|
? (pkt->data[4] | ((uint16_t)pkt->data[5] << 8)) : 0; |
|
|
|
? (pkt->data[4] | ((uint16_t)pkt->data[5] << 8)) : 0; |
|
|
|
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) { |
|
|
|
link->ka_sleeping = 1; |
|
|
|
/* Сервер: пир в спячке — зеркалим флаг/поля и ведём фазу троттлинга.
|
|
|
|
link->ka_sleep_period_ms = peer_period; |
|
|
|
ack-эхо шлём только на анонсе (переход 0→1), дальше в спячке молчим. */ |
|
|
|
link->ka_active_remaining = active_remaining; |
|
|
|
int was_sleeping = link->ka_sleeping; |
|
|
|
link->ka_sleep_duration = sleep_duration; |
|
|
|
link->ka_sleeping = 1; |
|
|
|
link->ka_period_ms = peer_period; |
|
|
|
link->ka_sleep_period_ms = peer_period; |
|
|
|
if (link->etcp) { |
|
|
|
link->ka_active_remaining = active_remaining; |
|
|
|
link->etcp->peer_active_remaining = active_remaining; |
|
|
|
link->ka_sleep_duration = sleep_duration; |
|
|
|
link->etcp->peer_sleep_duration = sleep_duration; |
|
|
|
link->ka_period_ms = peer_period; |
|
|
|
ka_peer_set_phase(link->etcp, active_remaining == 0); |
|
|
|
if (link->etcp) { |
|
|
|
ka_peer_arm_phase(link->etcp); |
|
|
|
link->etcp->peer_active_remaining = active_remaining; |
|
|
|
|
|
|
|
link->etcp->peer_sleep_duration = sleep_duration; |
|
|
|
|
|
|
|
ka_server_set_phase(link->etcp, active_remaining == 0); |
|
|
|
|
|
|
|
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=%s", |
|
|
|
|
|
|
|
link->etcp->log_name, peer_period, |
|
|
|
|
|
|
|
(int)(active_remaining / 10), (int)(active_remaining % 10), |
|
|
|
|
|
|
|
(int)(sleep_duration / 10), (int)(sleep_duration % 10), |
|
|
|
|
|
|
|
was_sleeping ? "no" : "ack"); |
|
|
|
|
|
|
|
if (!was_sleeping) |
|
|
|
|
|
|
|
etcp_link_send_keepalive(link); |
|
|
|
|
|
|
|
restart_keepalive_timer_ms(link, peer_period); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
/* Клиент: ack/эхо сервера — анонс завершён. */ |
|
|
|
|
|
|
|
link->ka_sleep_acked = 1; |
|
|
|
|
|
|
|
if (link->ka_sleep_announce_timer) { |
|
|
|
|
|
|
|
uasync_cancel_timeout(e_sock->instance->ua, link->ka_sleep_announce_timer); |
|
|
|
|
|
|
|
link->ka_sleep_announce_timer = NULL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_KEEPALIVE, "[%s] client: sleep ack received", link->etcp->log_name); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] peer sleeping (period=%dms active_rem=%d.%ds sleep_dur=%d.%ds)", |
|
|
|
/* Обычный keepalive (без флага). */ |
|
|
|
link->etcp->log_name, peer_period, |
|
|
|
if (link->is_server && link->ka_sleeping) { |
|
|
|
(int)(active_remaining / 10), (int)(active_remaining % 10), |
|
|
|
/* Пир проснулся (форграунд) — вернуться в обычный режим. */ |
|
|
|
(int)(sleep_duration / 10), (int)(sleep_duration % 10)); |
|
|
|
link->ka_sleeping = 0; |
|
|
|
ka_send_sleep_ack(link); |
|
|
|
link->ka_period_ms = (uint16_t)link->keepalive_interval; |
|
|
|
restart_keepalive_timer_ms(link, peer_period); |
|
|
|
link->keepalive_timeout = (uint32_t)link->keepalive_interval * KA_TIMEOUT_MULT; |
|
|
|
} else if (link->ka_sleeping) { |
|
|
|
if (link->etcp) { |
|
|
|
/* Обычный keepalive (без флагов): пир проснулся — вернуться в обычный режим. */ |
|
|
|
if (link->etcp->peer_phase_timer) { |
|
|
|
link->ka_sleeping = 0; |
|
|
|
uasync_cancel_timeout(link->etcp->instance->ua, link->etcp->peer_phase_timer); |
|
|
|
link->ka_period_ms = (uint16_t)link->keepalive_interval; |
|
|
|
link->etcp->peer_phase_timer = NULL; |
|
|
|
link->keepalive_timeout = (uint32_t)link->keepalive_interval * KA_TIMEOUT_MULT; |
|
|
|
} |
|
|
|
if (link->etcp) { |
|
|
|
ka_server_set_phase(link->etcp, 0); |
|
|
|
if (link->etcp->peer_phase_timer) { |
|
|
|
|
|
|
|
uasync_cancel_timeout(link->etcp->instance->ua, link->etcp->peer_phase_timer); |
|
|
|
|
|
|
|
link->etcp->peer_phase_timer = NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] server: peer woke up, back to normal (interval=%dms)", |
|
|
|
ka_peer_set_phase(link->etcp, 0); |
|
|
|
link->etcp->log_name, link->keepalive_interval); |
|
|
|
|
|
|
|
restart_keepalive_timer_ms(link, link->ka_period_ms); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] peer woke up, back to normal (interval=%dms)", |
|
|
|
|
|
|
|
link->etcp->log_name, link->keepalive_interval); |
|
|
|
|
|
|
|
restart_keepalive_timer_ms(link, link->ka_period_ms); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
link->keepalive_recv_count++; |
|
|
|
link->keepalive_recv_count++; |
|
|
|
@ -464,18 +467,18 @@ int etcp_keepalive_on_recv(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, |
|
|
|
static void etcp_keepalive_on_activity(struct UTUN_INSTANCE* inst, int active, void* arg) { |
|
|
|
static void etcp_keepalive_on_activity(struct UTUN_INSTANCE* inst, int active, void* arg) { |
|
|
|
(void)arg; |
|
|
|
(void)arg; |
|
|
|
if (!inst || inst->client_type != CLIENT_TYPE_MOBILE) return; |
|
|
|
if (!inst || inst->client_type != CLIENT_TYPE_MOBILE) return; |
|
|
|
ka_for_each_link(inst, active ? ka_client_wake : ka_client_enter_sleep); |
|
|
|
ka_for_each_link(inst, active ? ka_wake : ka_enter_sleep); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "keepalive activity change: %s -> applied to links (node=%016llx)", |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "keepalive activity change: %s -> applied to links (node=%016llx)", |
|
|
|
active ? "ACTIVE(wake)" : "STANDBY(sleep)", (unsigned long long)inst->node_id); |
|
|
|
active ? "ACTIVE(wake)" : "STANDBY(sleep)", (unsigned long long)inst->node_id); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Переанонс спячки на только что (пере)инициализированном линке (рестарт сервера).
|
|
|
|
// Переанонс спячки на только что (пере)инициализированном линке (рестарт пира).
|
|
|
|
void etcp_keepalive_announce_mode(struct ETCP_LINK* link) { |
|
|
|
void etcp_keepalive_announce_mode(struct ETCP_LINK* link) { |
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
struct UTUN_INSTANCE* inst = link->etcp->instance; |
|
|
|
struct UTUN_INSTANCE* inst = link->etcp->instance; |
|
|
|
if (inst->client_type != CLIENT_TYPE_MOBILE) return; |
|
|
|
if (inst->client_type != CLIENT_TYPE_MOBILE) return; |
|
|
|
if (!inst->standby_enabled) return; /* не в standby — обычный режим */ |
|
|
|
if (!inst->standby_enabled) return; /* не в standby — обычный режим */ |
|
|
|
ka_client_enter_sleep(link); |
|
|
|
ka_enter_sleep(link); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void etcp_keepalive_register(struct UTUN_INSTANCE* inst) { |
|
|
|
void etcp_keepalive_register(struct UTUN_INSTANCE* inst) { |
|
|
|
|