|
|
|
|
@ -7,10 +7,17 @@
|
|
|
|
|
#include "../lib/u_async.h" |
|
|
|
|
#include "../lib/debug_config.h" |
|
|
|
|
#include "../lib/memory_pool.h" |
|
|
|
|
#ifdef UTUN_HAVE_STANDBY |
|
|
|
|
#include "standby.h" |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
// forward declarations (static)
|
|
|
|
|
static void keepalive_timer_cb(void* arg); |
|
|
|
|
static int etcp_all_links_down(struct ETCP_CONN* etcp); |
|
|
|
|
static void ka_send_sleep_keepalive(struct ETCP_LINK* link); |
|
|
|
|
static void ka_announce_retry_cb(void* arg); |
|
|
|
|
static void ka_client_enter_sleep(struct ETCP_LINK* link); |
|
|
|
|
static void ka_client_wake(struct ETCP_LINK* link); |
|
|
|
|
|
|
|
|
|
// === перенесено из etcp_connections.c без изменений ===
|
|
|
|
|
|
|
|
|
|
@ -27,12 +34,12 @@ uint16_t negotiate_keepalive(uint8_t my_type, uint16_t my_ka,
|
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Send empty keepalive packet (only timestamp, no sections)
|
|
|
|
|
// Send keepalive packet: code(0x08) + flags + ka_period_ms + [sleep_time]
|
|
|
|
|
void etcp_link_send_keepalive(struct ETCP_LINK* link) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_KEEPALIVE, ""); |
|
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
|
|
|
|
|
|
struct ETCP_DGRAM* dgram = u_malloc(sizeof(struct ETCP_DGRAM) + 4); |
|
|
|
|
struct ETCP_DGRAM* dgram = u_malloc(sizeof(struct ETCP_DGRAM) + 8); |
|
|
|
|
if (!dgram) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_KEEPALIVE, "malloc failed"); |
|
|
|
|
return; |
|
|
|
|
@ -40,9 +47,16 @@ void etcp_link_send_keepalive(struct ETCP_LINK* link) {
|
|
|
|
|
|
|
|
|
|
dgram->link = link; |
|
|
|
|
dgram->data[0] = ETCP_KEEPALIVE; |
|
|
|
|
dgram->data[1] = link->ka_period_ms & 0xFF; |
|
|
|
|
dgram->data[2] = link->ka_period_ms >> 8; |
|
|
|
|
dgram->data_len = 3; |
|
|
|
|
dgram->data[1] = link->ka_sleeping ? KA_FLAG_SLEEP : 0; |
|
|
|
|
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; |
|
|
|
|
} else { |
|
|
|
|
dgram->data_len = 4; |
|
|
|
|
} |
|
|
|
|
dgram->noencrypt_len = 0; |
|
|
|
|
dgram->timestamp = get_current_timestamp(); |
|
|
|
|
dgram->flag_up = link->is_tcp ? 1 : link->recv_keepalive; |
|
|
|
|
@ -88,6 +102,15 @@ void start_keepalive_timer(struct ETCP_LINK* link) {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void restart_keepalive_timer_ms(struct ETCP_LINK* link, uint16_t ms) { |
|
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
|
if (link->keepalive_timer) { |
|
|
|
|
uasync_cancel_timeout(link->etcp->instance->ua, link->keepalive_timer); |
|
|
|
|
link->keepalive_timer = NULL; |
|
|
|
|
} |
|
|
|
|
link->keepalive_timer = uasync_set_timeout(link->etcp->instance->ua, (uint32_t)ms * 10, link, keepalive_timer_cb, "link_keepalive"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Keepalive timer callback
|
|
|
|
|
static void keepalive_timer_cb(void* arg) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_KEEPALIVE, ""); |
|
|
|
|
@ -150,9 +173,19 @@ static void keepalive_timer_cb(void* arg) {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Adaptive keepalive period (only if adaptive enabled)
|
|
|
|
|
if (link->ka_pinned) |
|
|
|
|
link->ka_period_ms = (uint16_t)link->keepalive_interval; |
|
|
|
|
// Сервер: дедлайн спячки пира вышел — пир должен был проснуться/переанонсировать,
|
|
|
|
|
// выходим из спячки в обычный режим (базовый период, 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; |
|
|
|
|
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; |
|
|
|
|
else if (link->pkt_sent_since_keepalive) |
|
|
|
|
link->ka_period_ms = (uint16_t)link->keepalive_interval; |
|
|
|
|
else if (link->etcp->instance && link->etcp->instance->config && |
|
|
|
|
@ -162,94 +195,135 @@ static void keepalive_timer_cb(void* arg) {
|
|
|
|
|
} |
|
|
|
|
link->pkt_sent_since_keepalive = 0; |
|
|
|
|
|
|
|
|
|
// Send keepalive (server stops if link lost, client always sends)
|
|
|
|
|
if (!link->is_server || link->recv_keepalive) |
|
|
|
|
// Отправка keepalive (в спячке — с флагом и свежим дедлайном)
|
|
|
|
|
if (link->ka_sleeping) |
|
|
|
|
ka_send_sleep_keepalive(link); |
|
|
|
|
else if (!link->is_server || link->recv_keepalive) |
|
|
|
|
etcp_link_send_keepalive(link); |
|
|
|
|
|
|
|
|
|
restart_timer: |
|
|
|
|
link->keepalive_timer = uasync_set_timeout(link->etcp->instance->ua, link->ka_period_ms * 10, link, keepalive_timer_cb, "link_keepalive"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// === протокол смены keepalive-режима (standby/normal, p2p) ===
|
|
|
|
|
// === протокол спячки (sleep) на флагах keepalive-пакета ===
|
|
|
|
|
|
|
|
|
|
// Период keepalive в спячке (мс): из настройки standby_keepalive_ms (Android).
|
|
|
|
|
static uint16_t ka_sleep_period_ms(struct UTUN_INSTANCE* inst) { |
|
|
|
|
#ifdef UTUN_HAVE_STANDBY |
|
|
|
|
int ms = standby_get_keepalive_ms(); |
|
|
|
|
if (ms < 100) ms = 100; |
|
|
|
|
return (uint16_t)ms; |
|
|
|
|
#else |
|
|
|
|
(void)inst; |
|
|
|
|
return 30000; |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static uint8_t mobile_desired_ka_mode(struct UTUN_INSTANCE* inst) { |
|
|
|
|
return (inst->client_activity == CLIENT_ACTIVITY_ACTIVE) ? KA_MODE_NORMAL : KA_MODE_STANDBY; |
|
|
|
|
// Дедлайн пробуждения (x0.1с): остаток SLEEP либо остаток ACTIVE + полная SLEEP.
|
|
|
|
|
static uint16_t ka_wake_deadline_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; |
|
|
|
|
return v > 65535 ? 65535 : (uint16_t)v; |
|
|
|
|
#else |
|
|
|
|
return 0; |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void restart_keepalive_timer_ms(struct ETCP_LINK* link, uint16_t ms) { |
|
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
|
if (link->keepalive_timer) { |
|
|
|
|
uasync_cancel_timeout(link->etcp->instance->ua, link->keepalive_timer); |
|
|
|
|
link->keepalive_timer = NULL; |
|
|
|
|
// Отправить 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; |
|
|
|
|
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, |
|
|
|
|
KA_SLEEP_RETRY_MS * 10, link, ka_announce_retry_cb, "ka_sleep_announce"); |
|
|
|
|
} |
|
|
|
|
link->keepalive_timer = uasync_set_timeout(link->etcp->instance->ua, (uint32_t)ms * 10, link, keepalive_timer_cb, "link_keepalive"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void apply_link_ka_mode(struct ETCP_LINK* link, uint8_t mode) { |
|
|
|
|
uint16_t ms = (mode == KA_MODE_STANDBY) ? KA_MOBILE_STANDBY_MS : KA_MOBILE_ACTIVE_MS; |
|
|
|
|
link->keepalive_interval = ms; |
|
|
|
|
link->ka_period_ms = ms; |
|
|
|
|
link->keepalive_timeout = (uint32_t)ms * KA_TIMEOUT_MULT; |
|
|
|
|
link->ka_pinned = (mode == KA_MODE_STANDBY) ? 1 : 0; |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] keepalive mode applied: mode=%s interval=%dms timeout=%dms pinned=%d", |
|
|
|
|
link->etcp->log_name, mode == KA_MODE_STANDBY ? "standby" : "normal", |
|
|
|
|
ms, link->keepalive_timeout, link->ka_pinned); |
|
|
|
|
restart_keepalive_timer_ms(link, link->ka_period_ms); |
|
|
|
|
static void ka_announce_retry_cb(void* arg) { |
|
|
|
|
struct ETCP_LINK* link = (struct ETCP_LINK*)arg; |
|
|
|
|
link->ka_sleep_announce_timer = NULL; |
|
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
|
if (!link->ka_sleeping || link->ka_sleep_acked) return; // анонс завершён
|
|
|
|
|
if (get_time_tb() >= link->ka_sleep_announce_end_tb) return; // окно 4с вышло
|
|
|
|
|
ka_send_sleep_keepalive(link); // ретрай
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void etcp_keepalive_send_mode_pkt(struct ETCP_LINK* link, uint8_t code, uint8_t mode) { |
|
|
|
|
// Клиент: вход в спячку (анонс с ретраями).
|
|
|
|
|
static void ka_client_enter_sleep(struct ETCP_LINK* link) { |
|
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] keepalive %s send: mode=%s", |
|
|
|
|
link->etcp->log_name, |
|
|
|
|
code == ETCP_KEEPALIVE_REQ ? "REQ" : "RESP", |
|
|
|
|
mode == KA_MODE_STANDBY ? "standby" : "normal"); |
|
|
|
|
|
|
|
|
|
struct ETCP_DGRAM* dgram = u_malloc(sizeof(struct ETCP_DGRAM) + 4); |
|
|
|
|
if (!dgram) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_KEEPALIVE, "malloc failed"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
uint16_t period = ka_sleep_period_ms(link->etcp->instance); |
|
|
|
|
link->ka_sleeping = 1; |
|
|
|
|
link->ka_sleep_acked = 0; |
|
|
|
|
link->ka_sleep_period_ms = period; |
|
|
|
|
link->ka_period_ms = period; |
|
|
|
|
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; |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] client entering sleep (period=%dms)", link->etcp->log_name, period); |
|
|
|
|
ka_send_sleep_keepalive(link); |
|
|
|
|
restart_keepalive_timer_ms(link, period); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
dgram->link = link; |
|
|
|
|
dgram->data[0] = code; |
|
|
|
|
dgram->data[1] = mode; |
|
|
|
|
dgram->data_len = 2; |
|
|
|
|
dgram->noencrypt_len = 0; |
|
|
|
|
dgram->timestamp = get_current_timestamp(); |
|
|
|
|
dgram->flag_up = link->is_tcp ? 1 : link->recv_keepalive; |
|
|
|
|
// Клиент: переанонс на входе в очередной цикл спячки (обновить дедлайн).
|
|
|
|
|
static void ka_client_reannounce(struct ETCP_LINK* link) { |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
etcp_encrypt_send(dgram); |
|
|
|
|
u_free(dgram); |
|
|
|
|
// Клиент: пробуждение (форграунд) — обычный keepalive, возврат к базовому периоду.
|
|
|
|
|
static void ka_client_wake(struct ETCP_LINK* link) { |
|
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
|
if (!link->ka_sleeping) return; |
|
|
|
|
link->ka_sleeping = 0; |
|
|
|
|
link->ka_sleep_acked = 0; |
|
|
|
|
if (link->ka_sleep_announce_timer) { |
|
|
|
|
uasync_cancel_timeout(link->etcp->instance->ua, link->ka_sleep_announce_timer); |
|
|
|
|
link->ka_sleep_announce_timer = NULL; |
|
|
|
|
} |
|
|
|
|
link->ka_period_ms = (uint16_t)link->keepalive_interval; |
|
|
|
|
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)", |
|
|
|
|
link->etcp->log_name, link->keepalive_interval); |
|
|
|
|
etcp_link_send_keepalive(link); |
|
|
|
|
restart_keepalive_timer_ms(link, link->ka_period_ms); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void handle_keepalive_req(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, struct ETCP_LINK* link) { |
|
|
|
|
uint8_t req_mode = (pkt->data_len >= 2) ? pkt->data[1] : KA_MODE_NORMAL; |
|
|
|
|
uint8_t agreed; |
|
|
|
|
if (e_sock->instance->client_type == CLIENT_TYPE_MOBILE) { |
|
|
|
|
uint8_t my_mode = mobile_desired_ka_mode(e_sock->instance); |
|
|
|
|
agreed = (my_mode == KA_MODE_STANDBY || req_mode == KA_MODE_STANDBY) ? KA_MODE_STANDBY : KA_MODE_NORMAL; |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] keepalive REQ recv: req=%s my=%s -> agreed=%s", |
|
|
|
|
link->etcp->log_name, |
|
|
|
|
req_mode == KA_MODE_STANDBY ? "standby" : "normal", |
|
|
|
|
my_mode == KA_MODE_STANDBY ? "standby" : "normal", |
|
|
|
|
agreed == KA_MODE_STANDBY ? "standby" : "normal"); |
|
|
|
|
} else { |
|
|
|
|
agreed = req_mode; |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] keepalive REQ recv: req=%s (non-mobile) -> agreed=%s", |
|
|
|
|
link->etcp->log_name, |
|
|
|
|
req_mode == KA_MODE_STANDBY ? "standby" : "normal", |
|
|
|
|
agreed == KA_MODE_STANDBY ? "standby" : "normal"); |
|
|
|
|
typedef void (*ka_link_fn)(struct ETCP_LINK* link); |
|
|
|
|
|
|
|
|
|
static void ka_for_each_link(struct UTUN_INSTANCE* inst, ka_link_fn fn) { |
|
|
|
|
if (inst->connections) { |
|
|
|
|
for (struct ll_entry* e = inst->connections->head; e; e = e->next) { |
|
|
|
|
struct conn_queue_entry* ce = (struct conn_queue_entry*)e->data; |
|
|
|
|
if (!ce || !ce->conn) continue; |
|
|
|
|
for (struct ETCP_LINK* l = ce->conn->links; l; l = l->next) |
|
|
|
|
if (l->initialized) fn(l); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (inst->tcp_connections) { |
|
|
|
|
for (struct ll_entry* e = inst->tcp_connections->head; e; e = e->next) { |
|
|
|
|
struct tcp_conn_entry* te = (struct tcp_conn_entry*)e->data; |
|
|
|
|
if (!te || !te->etcp_conn) continue; |
|
|
|
|
for (struct ETCP_LINK* l = te->etcp_conn->links; l; l = l->next) |
|
|
|
|
if (l->initialized) fn(l); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
apply_link_ka_mode(link, agreed); |
|
|
|
|
etcp_keepalive_send_mode_pkt(link, ETCP_KEEPALIVE_RESP, agreed); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void handle_keepalive_resp(struct ETCP_DGRAM* pkt, struct ETCP_LINK* link) { |
|
|
|
|
uint8_t agreed = (pkt->data_len >= 2) ? pkt->data[1] : KA_MODE_NORMAL; |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] keepalive RESP recv: agreed=%s", |
|
|
|
|
link->etcp->log_name, agreed == KA_MODE_STANDBY ? "standby" : "normal"); |
|
|
|
|
apply_link_ka_mode(link, agreed); |
|
|
|
|
#ifdef UTUN_HAVE_STANDBY |
|
|
|
|
// Фаза duty-cycle: вошли в SLEEP → переанонсировать спячку (каждый цикл).
|
|
|
|
|
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; |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
int etcp_keepalive_on_recv(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, |
|
|
|
|
struct ETCP_LINK* link, size_t pkt_len) { |
|
|
|
|
@ -258,30 +332,52 @@ int etcp_keepalive_on_recv(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt,
|
|
|
|
|
uint8_t code = pkt->data[0]; |
|
|
|
|
|
|
|
|
|
if (code == ETCP_KEEPALIVE) { |
|
|
|
|
if (pkt->data_len >= 3) { |
|
|
|
|
uint16_t peer_period = pkt->data[1] | ((uint16_t)pkt->data[2] << 8); |
|
|
|
|
link->keepalive_timeout = (uint32_t)peer_period * KA_TIMEOUT_MULT; |
|
|
|
|
} |
|
|
|
|
link->keepalive_recv_count++; |
|
|
|
|
/* Сервер в standby синхронизируется с keepalive клиента: отвечает echo и
|
|
|
|
|
* пере-армит свой таймер на период+запас, чтобы собственная проба ушла |
|
|
|
|
* только если клиент опаздывает. */ |
|
|
|
|
if (link->is_server && link->ka_pinned) { |
|
|
|
|
etcp_link_send_keepalive(link); |
|
|
|
|
restart_keepalive_timer_ms(link, (uint16_t)(link->ka_period_ms + KA_SYNC_MARGIN_MS)); |
|
|
|
|
uint16_t peer_period = 0; |
|
|
|
|
if (pkt->data_len >= 4) |
|
|
|
|
peer_period = pkt->data[2] | ((uint16_t)pkt->data[3] << 8); |
|
|
|
|
else if (pkt->data_len >= 3) /* легаси-формат (без флагов) */ |
|
|
|
|
peer_period = pkt->data[1] | ((uint16_t)pkt->data[2] << 8); |
|
|
|
|
if (peer_period) link->keepalive_timeout = (uint32_t)peer_period * KA_TIMEOUT_MULT; |
|
|
|
|
|
|
|
|
|
uint8_t flags = (pkt->data_len >= 2) ? pkt->data[1] : 0; |
|
|
|
|
|
|
|
|
|
if (flags & KA_FLAG_SLEEP) { |
|
|
|
|
uint16_t sleep_time = (pkt->data_len >= 6) |
|
|
|
|
? (pkt->data[4] | ((uint16_t)pkt->data[5] << 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_period_ms = peer_period; |
|
|
|
|
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)); |
|
|
|
|
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 { |
|
|
|
|
/* Обычный keepalive (без флага). */ |
|
|
|
|
if (link->is_server && link->ka_sleeping) { |
|
|
|
|
/* Пир проснулся (форграунд) — вернуться в обычный режим. */ |
|
|
|
|
link->ka_sleeping = 0; |
|
|
|
|
link->ka_period_ms = (uint16_t)link->keepalive_interval; |
|
|
|
|
link->keepalive_timeout = (uint32_t)link->keepalive_interval * KA_TIMEOUT_MULT; |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] server: peer woke up, back to normal (interval=%dms)", |
|
|
|
|
link->etcp->log_name, link->keepalive_interval); |
|
|
|
|
restart_keepalive_timer_ms(link, link->ka_period_ms); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
memory_pool_free(e_sock->instance->pkt_pool, pkt); |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (code == ETCP_KEEPALIVE_REQ) { |
|
|
|
|
handle_keepalive_req(e_sock, pkt, link); |
|
|
|
|
memory_pool_free(e_sock->instance->pkt_pool, pkt); |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (code == ETCP_KEEPALIVE_RESP) { |
|
|
|
|
handle_keepalive_resp(pkt, link); |
|
|
|
|
link->keepalive_recv_count++; |
|
|
|
|
memory_pool_free(e_sock->instance->pkt_pool, pkt); |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
@ -290,36 +386,27 @@ 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) { |
|
|
|
|
(void)active; (void)arg; |
|
|
|
|
(void)arg; |
|
|
|
|
if (!inst || inst->client_type != CLIENT_TYPE_MOBILE) return; |
|
|
|
|
uint8_t mode = mobile_desired_ka_mode(inst); |
|
|
|
|
|
|
|
|
|
int sent = 0; |
|
|
|
|
if (inst->connections) { |
|
|
|
|
for (struct ll_entry* e = inst->connections->head; e; e = e->next) { |
|
|
|
|
struct conn_queue_entry* ce = (struct conn_queue_entry*)e->data; |
|
|
|
|
if (!ce || !ce->conn) continue; |
|
|
|
|
for (struct ETCP_LINK* l = ce->conn->links; l; l = l->next) { |
|
|
|
|
if (l->initialized) { etcp_keepalive_send_mode_pkt(l, ETCP_KEEPALIVE_REQ, mode); sent++; } |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (inst->tcp_connections) { |
|
|
|
|
for (struct ll_entry* e = inst->tcp_connections->head; e; e = e->next) { |
|
|
|
|
struct tcp_conn_entry* te = (struct tcp_conn_entry*)e->data; |
|
|
|
|
if (!te || !te->etcp_conn) continue; |
|
|
|
|
for (struct ETCP_LINK* l = te->etcp_conn->links; l; l = l->next) { |
|
|
|
|
if (l->initialized) { etcp_keepalive_send_mode_pkt(l, ETCP_KEEPALIVE_REQ, mode); sent++; } |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
ka_for_each_link(inst, active ? ka_client_wake : ka_client_enter_sleep); |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "keepalive activity change: mode=%s -> REQ sent to %d links (node=%016llx)", |
|
|
|
|
mode == KA_MODE_STANDBY ? "standby" : "normal", sent, (unsigned long long)inst->node_id); |
|
|
|
|
// Переанонс спячки на только что (пере)инициализированном линке (рестарт сервера).
|
|
|
|
|
void etcp_keepalive_announce_mode(struct ETCP_LINK* link) { |
|
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
|
struct UTUN_INSTANCE* inst = link->etcp->instance; |
|
|
|
|
if (inst->client_type != CLIENT_TYPE_MOBILE) return; |
|
|
|
|
if (!inst->standby_enabled) return; /* не в standby — обычный режим */ |
|
|
|
|
ka_client_enter_sleep(link); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void etcp_keepalive_register(struct UTUN_INSTANCE* inst) { |
|
|
|
|
if (!inst) return; |
|
|
|
|
utun_add_activity_cbk(inst, etcp_keepalive_on_activity, NULL); |
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_KEEPALIVE, "keepalive activity callback registered"); |
|
|
|
|
#ifdef UTUN_HAVE_STANDBY |
|
|
|
|
standby_set_phase_callback(ka_phase_cb, inst); |
|
|
|
|
#endif |
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_KEEPALIVE, "keepalive activity + phase callbacks registered"); |
|
|
|
|
} |
|
|
|
|
|