|
|
|
|
@ -34,7 +34,7 @@ uint16_t negotiate_keepalive(uint8_t my_type, uint16_t my_ka,
|
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Send keepalive packet: code(0x08) + flags + ka_period_ms + [sleep_time]
|
|
|
|
|
// Send keepalive packet: code(0x08) + flags + ka_period_ms + [active_remaining + sleep_duration]
|
|
|
|
|
void etcp_link_send_keepalive(struct ETCP_LINK* link) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_KEEPALIVE, ""); |
|
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
|
@ -51,9 +51,11 @@ void etcp_link_send_keepalive(struct ETCP_LINK* link) {
|
|
|
|
|
dgram->data[2] = link->ka_period_ms & 0xFF; |
|
|
|
|
dgram->data[3] = link->ka_period_ms >> 8; |
|
|
|
|
if (link->ka_sleeping) { |
|
|
|
|
dgram->data[4] = link->ka_sleep_time & 0xFF; |
|
|
|
|
dgram->data[5] = link->ka_sleep_time >> 8; |
|
|
|
|
dgram->data_len = 6; |
|
|
|
|
dgram->data[4] = link->ka_active_remaining & 0xFF; |
|
|
|
|
dgram->data[5] = link->ka_active_remaining >> 8; |
|
|
|
|
dgram->data[6] = link->ka_sleep_duration & 0xFF; |
|
|
|
|
dgram->data[7] = link->ka_sleep_duration >> 8; |
|
|
|
|
dgram->data_len = 8; |
|
|
|
|
} else { |
|
|
|
|
dgram->data_len = 4; |
|
|
|
|
} |
|
|
|
|
@ -173,20 +175,6 @@ static void keepalive_timer_cb(void* arg) {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Сервер: дедлайн спячки пира вышел — пир должен был проснуться/переанонсировать,
|
|
|
|
|
// выходим из спячки в обычный режим (базовый период, probe штатным keepalive).
|
|
|
|
|
if (link->is_server && link->ka_sleeping && now >= link->ka_sleep_deadline_tb) { |
|
|
|
|
link->ka_sleeping = 0; |
|
|
|
|
link->ka_period_ms = link->keepalive_interval; |
|
|
|
|
link->keepalive_timeout = (uint32_t)link->keepalive_interval * KA_TIMEOUT_MULT; |
|
|
|
|
if (link->etcp && link->etcp->peer_sleeping) { |
|
|
|
|
link->etcp->peer_sleeping = 0; |
|
|
|
|
utun_fire_peer_sleep_cbk(link->etcp->instance, link->etcp->peer_node_id, 0); |
|
|
|
|
} |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] server: sleep deadline expired, back to normal (interval=%dms)", |
|
|
|
|
link->etcp->log_name, link->keepalive_interval); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Период: спячка — фиксированный sleep-период; normal — адаптивный от базового.
|
|
|
|
|
if (link->ka_sleeping) |
|
|
|
|
link->ka_period_ms = link->ka_sleep_period_ms; |
|
|
|
|
@ -223,22 +211,32 @@ static uint16_t ka_sleep_period_ms(struct UTUN_INSTANCE* inst) {
|
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Дедлайн пробуждения (x0.1с): остаток SLEEP либо остаток ACTIVE + полная SLEEP.
|
|
|
|
|
static uint16_t ka_wake_deadline_01s(void) { |
|
|
|
|
// Сколько осталось до SLEEP-фазы (x0.1с): 0 = уже спим.
|
|
|
|
|
static uint16_t ka_active_remaining_01s(void) { |
|
|
|
|
#ifdef UTUN_HAVE_STANDBY |
|
|
|
|
int deadline_tb = standby_get_wake_deadline_tb(); |
|
|
|
|
uint32_t v = deadline_tb > 0 ? (uint32_t)(deadline_tb / 1000) : 0; |
|
|
|
|
uint32_t v = (uint32_t)(standby_get_active_remaining_tb() / 1000); |
|
|
|
|
return v > 65535 ? 65535 : (uint16_t)v; |
|
|
|
|
#else |
|
|
|
|
return 0; |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Отправить keepalive спячки (обновить дедлайн) + при необходимости заармить ретрай.
|
|
|
|
|
// Длительность SLEEP-фазы (x0.1с): в SLEEP — оставшийся сон, в ACTIVE — полная длительность.
|
|
|
|
|
static uint16_t ka_sleep_duration_01s(void) { |
|
|
|
|
#ifdef UTUN_HAVE_STANDBY |
|
|
|
|
int s = standby_get_sleep_tb(); |
|
|
|
|
uint32_t v = s > 0 ? (uint32_t)(s / 1000) |
|
|
|
|
: (uint32_t)(standby_get_sleep_duration_tb() / 1000); |
|
|
|
|
return v > 65535 ? 65535 : (uint16_t)v; |
|
|
|
|
#else |
|
|
|
|
return 0; |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Отправить keepalive спячки (обновить поля тайминга) + при необходимости заармить ретрай.
|
|
|
|
|
static void ka_send_sleep_keepalive(struct ETCP_LINK* link) { |
|
|
|
|
uint16_t sleep_time = ka_wake_deadline_01s(); |
|
|
|
|
if (sleep_time == 0) sleep_time = link->ka_sleep_period_ms / 100; |
|
|
|
|
link->ka_sleep_time = sleep_time; |
|
|
|
|
link->ka_active_remaining = ka_active_remaining_01s(); |
|
|
|
|
link->ka_sleep_duration = ka_sleep_duration_01s(); |
|
|
|
|
etcp_link_send_keepalive(link); |
|
|
|
|
if (!link->ka_sleep_acked && link->ka_sleep_announce_timer == NULL) { |
|
|
|
|
link->ka_sleep_announce_timer = uasync_set_timeout(link->etcp->instance->ua, |
|
|
|
|
@ -318,17 +316,58 @@ static void ka_for_each_link(struct UTUN_INSTANCE* inst, ka_link_fn fn) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef UTUN_HAVE_STANDBY |
|
|
|
|
// Фаза duty-cycle: вошли в SLEEP → переанонсировать спячку (каждый цикл).
|
|
|
|
|
// Клиент: вход в ACTIVE-окно — отправить keepalive с active_remaining>0 (флаг стоит).
|
|
|
|
|
static void ka_client_active_announce(struct ETCP_LINK* link) { |
|
|
|
|
if (!link->ka_sleeping) return; |
|
|
|
|
ka_send_sleep_keepalive(link); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Фаза duty-cycle: SLEEP → переанонс спячки; ACTIVE → анонс активности (флаг всегда стоит).
|
|
|
|
|
static void ka_phase_cb(int sleeping, void* arg) { |
|
|
|
|
struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)arg; |
|
|
|
|
if (!inst || inst->client_type != CLIENT_TYPE_MOBILE) return; |
|
|
|
|
if (!sleeping) return; |
|
|
|
|
if (sleeping) { |
|
|
|
|
ka_for_each_link(inst, ka_client_reannounce); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "keepalive: duty-cycle SLEEP phase, re-announce (node=%016llx)", |
|
|
|
|
(unsigned long long)inst->node_id); |
|
|
|
|
} else { |
|
|
|
|
ka_for_each_link(inst, ka_client_active_announce); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "keepalive: duty-cycle ACTIVE phase, announce (node=%016llx)", |
|
|
|
|
(unsigned long long)inst->node_id); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/* ── Сервер: машина фаз троттлинга (по active_remaining/sleep_duration) ── */ |
|
|
|
|
|
|
|
|
|
static void ka_server_arm_phase(struct ETCP_CONN* etcp); |
|
|
|
|
|
|
|
|
|
static void ka_server_set_phase(struct ETCP_CONN* etcp, int sleeping) { |
|
|
|
|
if (!etcp) return; |
|
|
|
|
if (etcp->peer_sleep_phase == (uint8_t)(sleeping ? 1 : 0)) return; |
|
|
|
|
etcp->peer_sleep_phase = sleeping ? 1 : 0; |
|
|
|
|
utun_fire_peer_sleep_cbk(etcp->instance, etcp->peer_node_id, sleeping); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void ka_server_phase_timer_cb(void* arg) { |
|
|
|
|
struct ETCP_CONN* etcp = (struct ETCP_CONN*)arg; |
|
|
|
|
etcp->peer_phase_timer = NULL; |
|
|
|
|
if (!etcp || etcp->state == 2) return; |
|
|
|
|
ka_server_set_phase(etcp, etcp->peer_sleep_phase ? 0 : 1); |
|
|
|
|
ka_server_arm_phase(etcp); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void ka_server_arm_phase(struct ETCP_CONN* etcp) { |
|
|
|
|
if (!etcp || !etcp->instance) return; |
|
|
|
|
uint16_t dur_01s = etcp->peer_sleep_phase ? etcp->peer_sleep_duration : etcp->peer_active_remaining; |
|
|
|
|
if (etcp->peer_phase_timer) { |
|
|
|
|
uasync_cancel_timeout(etcp->instance->ua, etcp->peer_phase_timer); |
|
|
|
|
etcp->peer_phase_timer = NULL; |
|
|
|
|
} |
|
|
|
|
etcp->peer_phase_timer = uasync_set_timeout(etcp->instance->ua, (int)((uint32_t)dur_01s * 1000), |
|
|
|
|
etcp, ka_server_phase_timer_cb, "peer_phase"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int etcp_keepalive_on_recv(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, |
|
|
|
|
struct ETCP_LINK* link, size_t pkt_len) { |
|
|
|
|
(void)pkt_len; |
|
|
|
|
@ -346,21 +385,27 @@ 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; |
|
|
|
|
|
|
|
|
|
if (flags & KA_FLAG_SLEEP) { |
|
|
|
|
uint16_t sleep_time = (pkt->data_len >= 6) |
|
|
|
|
uint16_t active_remaining = (pkt->data_len >= 6) |
|
|
|
|
? (pkt->data[4] | ((uint16_t)pkt->data[5] << 8)) : 0; |
|
|
|
|
uint16_t sleep_duration = (pkt->data_len >= 8) |
|
|
|
|
? (pkt->data[6] | ((uint16_t)pkt->data[7] << 8)) : 0; |
|
|
|
|
if (link->is_server) { |
|
|
|
|
/* Сервер: пир заснул — перейти в спячку и ответить ack-эхо. */ |
|
|
|
|
/* Сервер: пир в спячке — зеркалим флаг/поля для эхо и ведём фазу троттлинга. */ |
|
|
|
|
link->ka_sleeping = 1; |
|
|
|
|
link->ka_sleep_period_ms = peer_period; |
|
|
|
|
link->ka_sleep_time = sleep_time; |
|
|
|
|
link->ka_sleep_deadline_tb = get_time_tb() + (uint64_t)sleep_time * 1000; |
|
|
|
|
link->ka_active_remaining = active_remaining; |
|
|
|
|
link->ka_sleep_duration = sleep_duration; |
|
|
|
|
link->ka_period_ms = peer_period; |
|
|
|
|
if (link->etcp && !link->etcp->peer_sleeping) { |
|
|
|
|
link->etcp->peer_sleeping = 1; |
|
|
|
|
utun_fire_peer_sleep_cbk(link->etcp->instance, link->etcp->peer_node_id, 1); |
|
|
|
|
if (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 deadline=%us), echo ack", |
|
|
|
|
link->etcp->log_name, peer_period, (unsigned)(sleep_time / 10)); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] server: peer sleeping (period=%dms active_rem=%d.%ds sleep_dur=%d.%ds), echo ack", |
|
|
|
|
link->etcp->log_name, peer_period, |
|
|
|
|
(int)(active_remaining / 10), (int)(active_remaining % 10), |
|
|
|
|
(int)(sleep_duration / 10), (int)(sleep_duration % 10)); |
|
|
|
|
etcp_link_send_keepalive(link); |
|
|
|
|
restart_keepalive_timer_ms(link, peer_period); |
|
|
|
|
} else { |
|
|
|
|
@ -379,9 +424,12 @@ int etcp_keepalive_on_recv(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt,
|
|
|
|
|
link->ka_sleeping = 0; |
|
|
|
|
link->ka_period_ms = (uint16_t)link->keepalive_interval; |
|
|
|
|
link->keepalive_timeout = (uint32_t)link->keepalive_interval * KA_TIMEOUT_MULT; |
|
|
|
|
if (link->etcp && link->etcp->peer_sleeping) { |
|
|
|
|
link->etcp->peer_sleeping = 0; |
|
|
|
|
utun_fire_peer_sleep_cbk(link->etcp->instance, link->etcp->peer_node_id, 0); |
|
|
|
|
if (link->etcp) { |
|
|
|
|
if (link->etcp->peer_phase_timer) { |
|
|
|
|
uasync_cancel_timeout(link->etcp->instance->ua, link->etcp->peer_phase_timer); |
|
|
|
|
link->etcp->peer_phase_timer = NULL; |
|
|
|
|
} |
|
|
|
|
ka_server_set_phase(link->etcp, 0); |
|
|
|
|
} |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] server: peer woke up, back to normal (interval=%dms)", |
|
|
|
|
link->etcp->log_name, link->keepalive_interval); |
|
|
|
|
|