From 6d661360b11e40cb03c617c56b7b50e08c1739f7 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Mon, 1 Jun 2026 20:15:06 +0300 Subject: [PATCH] =?UTF-8?q?etcp:=20=D0=B0=D0=B4=D0=B0=D0=BF=D1=82=D0=B8?= =?UTF-8?q?=D0=B2=D0=BD=D1=8B=D0=B9=20keepalive=20=E2=80=94=20=D0=BE=D1=82?= =?UTF-8?q?=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D0=B0=D1=8F=20=D0=BA=D0=BE=D0=BC?= =?UTF-8?q?=D0=B0=D0=BD=D0=B4=D0=B0=20ETCP=5FKEEPALIVE=20=D1=81=20period?= =?UTF-8?q?=5Fms?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ETCP_KEEPALIVE=0x08, формат: [0x08][period_lo][period_hi] - link->ka_period_ms: 200ms при трафике, ×1.05+1 в idle, потолок 10s - keepalive_timeout = peer_period * KA_TIMEOUT_MULT(10) - приём KA обновляет keepalive_timeout адаптивно (2000ms→100000ms) - флаг recv_keepalive по-прежнему в flag_up для быстрого сигнала --- src/etcp_connections.c | 51 +++++++++++++++++++++++++----------------- src/etcp_connections.h | 7 ++++++ 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/etcp_connections.c b/src/etcp_connections.c index 6474294e..e8f5d84e 100644 --- a/src/etcp_connections.c +++ b/src/etcp_connections.c @@ -239,15 +239,16 @@ static void etcp_link_send_keepalive(struct ETCP_LINK* link) { } dgram->link = link; - dgram->data_len = 0; // Empty packet - only timestamp in header + 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(); - - DEBUG_DEBUG(DEBUG_CATEGORY_KEEPALIVE, "[%s] Sending keepalive on link %p (local_id=%d)", - link->etcp->log_name, link, link->local_link_id); + dgram->flag_up = link->recv_keepalive; link->keepalive_sent_count++; - + etcp_encrypt_send(dgram); u_free(dgram); } @@ -320,17 +321,21 @@ static void keepalive_timer_cb(void* arg) { } } - // Send keepalive only if no packets were sent since last tick - if (!link->pkt_sent_since_keepalive) { - if (link->is_server) { - if (link->recv_keepalive) etcp_link_send_keepalive(link);// сервер прекращает слать keepalive если линк потерян (ждём keepalive клиента) - } - else etcp_link_send_keepalive(link); - } + // Adaptive keepalive period + if (link->pkt_sent_since_keepalive) + link->ka_period_ms = KA_PERIOD_MIN_MS; // data flowing → reset to 200ms + else { + 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->keepalive_interval * 10, link, keepalive_timer_cb, "link_keepalive"); + link->keepalive_timer = uasync_set_timeout(link->etcp->instance->ua, link->ka_period_ms * 10, link, keepalive_timer_cb, "link_keepalive"); } static uint32_t sockaddr_hash(struct sockaddr_storage* addr) { @@ -781,6 +786,7 @@ struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn if (link->keepalive_interval < 10) link->keepalive_interval = 10; link->keepalive_sent_count = 0; link->keepalive_recv_count = 0; + link->ka_period_ms = KA_PERIOD_MIN_MS; link->inflight_lim_bytes = link->mtu * 4; // BBR init_cwnd (~4 packets) link->bandwidth = 10000; // начальная оценка 10 Mbps для шейпера link->burst_id = 0; @@ -1589,17 +1595,20 @@ process_decrypted: // Count decrypted bytes link->total_decrypted += pkt->data_len; - - // Count received keepalive packets (empty packets with no payload) - if (pkt->data_len == 0) { - link->keepalive_recv_count++; - DEBUG_DEBUG(DEBUG_CATEGORY_KEEPALIVE, "[%s] Received keepalive on link %p (local_id=%d)", - link->etcp->log_name, link, link->local_link_id); - } - + size_t offset = 0; uint8_t code = pkt->data[offset++]; + 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; // KA handled, nothing more to process + } + if (code == ETCP_INIT_RESPONSE || code == ETCP_INIT_RESPONSE_NOINIT) { if (pkt_len < 22) { errorcode = 46; DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "INIT_RESPONSE too short: pkt_len=%zu", pkt_len); goto ec_fr; } // ETCP_INIT_RESPONSE (0x03) - reset entire ETCP_CONN diff --git a/src/etcp_connections.h b/src/etcp_connections.h index e62de545..4bb68cf6 100644 --- a/src/etcp_connections.h +++ b/src/etcp_connections.h @@ -26,6 +26,12 @@ #define ETCP_INIT_RESPONSE_NOINIT 0x05 #define ETCP_PING 0x06 #define ETCP_PONG 0x07 +#define ETCP_KEEPALIVE 0x08 + +/* Адаптивный keepalive */ +#define KA_PERIOD_MIN_MS 200 +#define KA_PERIOD_MAX_MS 10000 +#define KA_TIMEOUT_MULT 10 /* timeout = period * mult */ #pragma pack(push, 1) @@ -194,6 +200,7 @@ struct ETCP_LINK { // Keepalive state void* keepalive_timer; // Таймер для отправки keepalive пакетов uint32_t keepalive_timeout; // таймаут (ms) + uint16_t ka_period_ms; // адаптивный период отправки keepalive (200→10000->200) uint8_t pkt_sent_since_keepalive; // Флаг: был ли отправлен пакет с последнего keepalive тика uint32_t keepalive_sent_count; // Счётчик отправленных keepalive uint32_t keepalive_recv_count; // Счётчик полученных keepalive