Browse Source
- новый модуль etcp_keepalive.c/h: keepalive-пакеты, таймер, адаптивный период, согласование при handshake вынесены из etcp_connections.c как есть - протокол KEEPALIVE_REQ/RESP (0x09/0x0A): мобильный узел при смене active mode шлёт желаемый режим; отвечающий считает max (standby при любом standby), не-мобильный применяет как есть; инициатор применяет согласованный режим после RESP - режимы: NORMAL (3с, адаптивный рост), STANDBY (30с, ka_pinned=1 без роста) - active mode как событие: utun_add/remove_activity_cbk; подписчики topo_group (nodeinfo) и etcp_keepalive (рассылка REQ всем линкам)topo_upd
13 changed files with 446 additions and 206 deletions
@ -1,28 +0,0 @@
|
||||
/* confdefs.h */ |
||||
#define PACKAGE_NAME "utun" |
||||
#define PACKAGE_TARNAME "utun" |
||||
#define PACKAGE_VERSION "2.0.0" |
||||
#define PACKAGE_STRING "utun 2.0.0" |
||||
#define PACKAGE_BUGREPORT "https://github.com/anomalyco/utun3/issues"
|
||||
#define PACKAGE_URL "" |
||||
#define PACKAGE "utun" |
||||
#define VERSION "2.0.0" |
||||
#define USE_OPENSSL 1 |
||||
#define HAVE_ARPA_INET_H 1 |
||||
#define HAVE_FCNTL_H 1 |
||||
#define HAVE_LIMITS_H 1 |
||||
#define HAVE_NETINET_IN_H 1 |
||||
#define HAVE_STDINT_H 1 |
||||
#define HAVE_STDLIB_H 1 |
||||
#define HAVE_STRING_H 1 |
||||
#define HAVE_SYS_IOCTL_H 1 |
||||
#define HAVE_SYS_SOCKET_H 1 |
||||
#define HAVE_UNISTD_H 1 |
||||
#define HAVE_MALLOC 1 |
||||
#define HAVE_GETTIMEOFDAY 1 |
||||
#define HAVE_MEMSET 1 |
||||
#define HAVE_SOCKET 1 |
||||
#define HAVE_STRCHR 1 |
||||
#define HAVE_STRDUP 1 |
||||
#define HAVE_STRERROR 1 |
||||
#define HAVE_STRSTR 1 |
||||
Binary file not shown.
@ -0,0 +1,296 @@
|
||||
#include "etcp_keepalive.h" |
||||
#include "etcp.h" |
||||
#include "etcp_api.h" |
||||
#include "stcp_link.h" |
||||
#include "topo_node.h" |
||||
#include "../lib/mem.h" |
||||
#include "../lib/u_async.h" |
||||
#include "../lib/debug_config.h" |
||||
#include "../lib/memory_pool.h" |
||||
|
||||
// forward declarations (static)
|
||||
static void keepalive_timer_cb(void* arg); |
||||
static int etcp_all_links_down(struct ETCP_CONN* etcp); |
||||
|
||||
// === перенесено из etcp_connections.c без изменений ===
|
||||
|
||||
// Вычислить keepalive по типу устройств: оба десктоп/сервер → min, иначе (есть mobile) → max
|
||||
uint16_t negotiate_keepalive(uint8_t my_type, uint16_t my_ka, |
||||
uint8_t peer_type, uint16_t peer_ka) { |
||||
int my_lp = (my_type == CLIENT_TYPE_MOBILE); |
||||
int peer_lp = (peer_type == CLIENT_TYPE_MOBILE); |
||||
uint16_t result = (my_lp || peer_lp) ? (my_ka > peer_ka ? my_ka : peer_ka) |
||||
: (my_ka < peer_ka ? my_ka : peer_ka); |
||||
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "negotiate: my=%d(type=%d) peer=%d(type=%d) → %d (rule=%s)", |
||||
my_ka, my_type, peer_ka, peer_type, result, |
||||
(my_lp || peer_lp) ? "max(low_power)" : "min(both_desktop)"); |
||||
return result; |
||||
} |
||||
|
||||
// Send empty keepalive packet (only timestamp, no sections)
|
||||
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); |
||||
if (!dgram) { |
||||
DEBUG_ERROR(DEBUG_CATEGORY_KEEPALIVE, "malloc failed"); |
||||
return; |
||||
} |
||||
|
||||
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->noencrypt_len = 0; |
||||
dgram->timestamp = get_current_timestamp(); |
||||
dgram->flag_up = link->is_tcp ? 1 : link->recv_keepalive; |
||||
|
||||
link->keepalive_sent_count++; |
||||
|
||||
etcp_encrypt_send(dgram); |
||||
u_free(dgram); |
||||
} |
||||
|
||||
// Check if all links for an ETCP_CONN are down
|
||||
// Returns 1 if all links are down or no links exist, 0 otherwise
|
||||
static int etcp_all_links_down(struct ETCP_CONN* etcp) { |
||||
if (!etcp || !etcp->links) return 1; |
||||
|
||||
struct ETCP_LINK* l = etcp->links; |
||||
while (l) { |
||||
if (l->link_status == 1) { |
||||
return 0; // At least one link is up
|
||||
} |
||||
l = l->next; |
||||
} |
||||
return 1; // All links are down
|
||||
} |
||||
|
||||
void start_keepalive_timer(struct ETCP_LINK* link) { |
||||
// Start keepalive timer
|
||||
if (link->init_timer) {// cancel init timer
|
||||
uasync_cancel_timeout(link->etcp->instance->ua, link->init_timer); |
||||
link->init_timer = NULL; |
||||
} |
||||
|
||||
if (link->keepalive_timer == NULL) { |
||||
DEBUG_DEBUG(DEBUG_CATEGORY_KEEPALIVE, "[%s] Keepalive timer started on link %p (interval=%d ms)", link->etcp->log_name, link, link->keepalive_interval); |
||||
link->keepalive_timer = uasync_set_timeout(link->etcp->instance->ua, link->keepalive_interval * 10, link, keepalive_timer_cb, "link_keepalive"); |
||||
} |
||||
} |
||||
|
||||
// Keepalive timer callback
|
||||
static void keepalive_timer_cb(void* arg) { |
||||
DEBUG_TRACE(DEBUG_CATEGORY_KEEPALIVE, ""); |
||||
struct ETCP_LINK* link = (struct ETCP_LINK*)arg; |
||||
if (!link || !link->etcp || !link->etcp->instance) { |
||||
DEBUG_ERROR(DEBUG_CATEGORY_KEEPALIVE, "KEEPALIVE NULL !!!!!!!!"); |
||||
return; |
||||
} |
||||
|
||||
link->keepalive_timer = NULL; |
||||
|
||||
// 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_tcp) { |
||||
if (link->tcp_link) { stcp_link_close(link->tcp_link); link->tcp_link = NULL; } |
||||
etcp_tcp_link_start_reconnect(link); |
||||
return; |
||||
} |
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] All links are down, starting recovery", link->etcp->log_name); |
||||
etcp_link_enter_reinit(link);// keepalive timr после reinit не нужен
|
||||
return; |
||||
} |
||||
|
||||
// Skip if link is not initialized
|
||||
if (!link->initialized) { |
||||
DEBUG_DEBUG(DEBUG_CATEGORY_KEEPALIVE, "[%s] Keepalive skipped - link not initialized", |
||||
link->etcp->log_name); |
||||
goto restart_timer; |
||||
} |
||||
|
||||
// Check keepalive timeout
|
||||
uint64_t now = get_time_tb(); |
||||
uint64_t timeout_units = (uint64_t)link->keepalive_timeout * 10; // ms -> 0.1ms units
|
||||
uint64_t elapsed = now - link->last_recv_local_time; |
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "[%s] ka_check: recv=%d elapsed=%llu timeout=%llu", |
||||
link->etcp->log_name, link->recv_keepalive, (unsigned long long)elapsed, (unsigned long long)timeout_units); |
||||
|
||||
if (elapsed > timeout_units) { |
||||
if (link->recv_keepalive != 0) { |
||||
link->recv_keepalive = 0; |
||||
int old_link_status = link->link_status; |
||||
link->link_status = 0; |
||||
etcp_fire_link_status_cbk(link, link->link_state, old_link_status); |
||||
etcp_on_link_down(link->etcp, link); |
||||
if (link->is_tcp && link->tcp_link) { stcp_link_close(link->tcp_link); link->tcp_link = NULL; } |
||||
if (old_link_status) { |
||||
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %d down: addr=%s ka=%d remote_ka=%d state=%d init=%d tmo: %llu>%llu els=%llums", link->etcp->log_name, link->local_link_id, sockaddr_storage_to_str(&link->remote_addr).str, link->recv_keepalive, link->remote_keepalive, link->link_state, link->initialized, (unsigned long long)timeout_units, (unsigned long long)elapsed, (unsigned long long)(elapsed/10)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Adaptive keepalive period (only if adaptive enabled)
|
||||
if (link->ka_pinned) |
||||
link->ka_period_ms = (uint16_t)link->keepalive_interval; |
||||
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 && |
||||
link->etcp->instance->config->global.keepalive_adaptive) { |
||||
uint32_t next = (uint32_t)link->ka_period_ms * 105 / 100 + 1; |
||||
link->ka_period_ms = next > KA_PERIOD_MAX_MS ? KA_PERIOD_MAX_MS : (uint16_t)next; |
||||
} |
||||
link->pkt_sent_since_keepalive = 0; |
||||
|
||||
// Send keepalive (server stops if link lost, client always sends)
|
||||
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) ===
|
||||
|
||||
static uint8_t mobile_desired_ka_mode(struct UTUN_INSTANCE* inst) { |
||||
return (inst->client_activity == CLIENT_ACTIVITY_ACTIVE) ? KA_MODE_NORMAL : KA_MODE_STANDBY; |
||||
} |
||||
|
||||
static void restart_keepalive_timer(struct ETCP_LINK* link) { |
||||
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, link->ka_period_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(link); |
||||
} |
||||
|
||||
static void etcp_keepalive_send_mode_pkt(struct ETCP_LINK* link, uint8_t code, uint8_t mode) { |
||||
if (!link || !link->etcp || !link->etcp->instance) return; |
||||
|
||||
struct ETCP_DGRAM* dgram = u_malloc(sizeof(struct ETCP_DGRAM) + 4); |
||||
if (!dgram) { |
||||
DEBUG_ERROR(DEBUG_CATEGORY_KEEPALIVE, "malloc failed"); |
||||
return; |
||||
} |
||||
|
||||
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; |
||||
|
||||
etcp_encrypt_send(dgram); |
||||
u_free(dgram); |
||||
} |
||||
|
||||
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"); |
||||
} |
||||
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); |
||||
} |
||||
|
||||
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; |
||||
if (!e_sock || !pkt || !link) return 0; |
||||
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++; |
||||
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); |
||||
memory_pool_free(e_sock->instance->pkt_pool, pkt); |
||||
return 1; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void etcp_keepalive_on_activity(struct UTUN_INSTANCE* inst, int active, void* arg) { |
||||
(void)active; (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++; } |
||||
} |
||||
} |
||||
} |
||||
|
||||
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_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"); |
||||
} |
||||
@ -0,0 +1,43 @@
|
||||
#ifndef ETCP_KEEPALIVE_H |
||||
#define ETCP_KEEPALIVE_H |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
// подмодуль ETCP: keepalive-пакеты, таймер, адаптивный период и протокол смены
|
||||
// keepalive-режима (standby/normal) при смене active mode у мобильных узлов.
|
||||
|
||||
#include "etcp_connections.h" |
||||
|
||||
// Типы кодограмм keepalive
|
||||
#define ETCP_KEEPALIVE_REQ 0x09 // запрос смены keepalive-режима (data[1] = режим)
|
||||
#define ETCP_KEEPALIVE_RESP 0x0A // ответ: согласованный режим (data[1] = режим)
|
||||
|
||||
// Режимы keepalive (мобильные узлы)
|
||||
#define KA_MODE_NORMAL 0 // активен: интервал 3с, адаптивный
|
||||
#define KA_MODE_STANDBY 1 // спит: интервал 30с, пиннится
|
||||
|
||||
#define KA_MOBILE_ACTIVE_MS 3000 |
||||
#define KA_MOBILE_STANDBY_MS 30000 |
||||
|
||||
// --- перенесены из etcp_connections.c (имена сохранены) ---
|
||||
uint16_t negotiate_keepalive(uint8_t my_type, uint16_t my_ka, |
||||
uint8_t peer_type, uint16_t peer_ka); |
||||
void etcp_link_send_keepalive(struct ETCP_LINK* link); |
||||
void start_keepalive_timer(struct ETCP_LINK* link); |
||||
|
||||
// --- новое ---
|
||||
// Обработка keepalive-пакетов (ETCP_KEEPALIVE/REQ/RESP) из etcp_packet_decrypted.
|
||||
// Возвращает 1 если пакет обработан (и освобождён), 0 — если это не keepalive.
|
||||
int etcp_keepalive_on_recv(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, |
||||
struct ETCP_LINK* link, size_t pkt_len); |
||||
|
||||
// Подписка на смену active mode (рассылка KEEPALIVE_REQ всем линкам).
|
||||
// Вызывается из init_connections.
|
||||
void etcp_keepalive_register(struct UTUN_INSTANCE* inst); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
#endif // ETCP_KEEPALIVE_H
|
||||
Loading…
Reference in new issue