From ca1e522a38a8754d876f533e8b1e4c2052dd89a8 Mon Sep 17 00:00:00 2001 From: jeka Date: Thu, 19 Mar 2026 22:24:16 +0300 Subject: [PATCH] 1 --- src/control_server.c | 1 + src/etcp.c | 112 ++++++++++++++++++------------- src/etcp_connections.c | 7 ++ src/etcp_connections.h | 9 ++- tools/etcpmon/etcpmon_gui.c | 19 +++--- tools/etcpmon/etcpmon_protocol.h | 1 + 6 files changed, 92 insertions(+), 57 deletions(-) diff --git a/src/control_server.c b/src/control_server.c index 9053d79a..a576d35e 100644 --- a/src/control_server.c +++ b/src/control_server.c @@ -876,6 +876,7 @@ static void send_metrics(struct control_server* server, struct control_client* c link_info[i].bandwidth = link->bandwidth; link_info[i].nat_changes_count = link->nat_changes_count; link_info[i].rtt_last = link->rtt_last; + link_info[i].rtt_avg10 = link->rtt_avg10; link_info[i].tt_last = link->tt_last; link_info[i].init_timer_active = (link->init_timer != NULL) ? 1 : 0; link_info[i].keepalive_timer_active = (link->keepalive_timer != NULL) ? 1 : 0; diff --git a/src/etcp.c b/src/etcp.c index 08ffe3a0..d2145548 100644 --- a/src/etcp.c +++ b/src/etcp.c @@ -21,8 +21,8 @@ // Constants from spec (adjusted for completeness) #define MAX_INFLIGHT_BYTES 65536 // Initial window -#define RETRANS_K1 2.0f // RTT multiplier for retrans timeout -#define RETRANS_K2 1.5f // Jitter multiplier +#define RETRANS_K1 32 // RTT multiplier for retrans timeout +#define RETRANS_K2 32 // Jitter multiplier #define ACK_DELAY_TB 20 // ACK timer delay (2ms in 0.1ms units) #define BURST_DELAY_FACTOR 4 // Delay before burst #define BURST_SIZE 5 // Packets in burst (1 delayed + 4 burst) @@ -555,7 +555,9 @@ static void ack_timeout_check(struct ETCP_CONN* etcp) { DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); uint64_t now = get_time_tb(); - int64_t timeout = 1000;//(uint64_t)(etcp->rtt_avg_10 * RETRANS_K1) + (uint64_t)(etcp->jitter * RETRANS_K2); + int32_t timeout = (etcp->rtt_avg_10 * RETRANS_K1 + etcp->jitter * RETRANS_K2) / 16; + if (timeout<50) timeout=50; + if (timeout>10000) timeout=10000; DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "starting check, now=%llu, timeout=%llu, rtt_avg_10=%u, jitter=%u", (unsigned long long)now, (unsigned long long)timeout, etcp->rtt_avg_10, etcp->jitter); @@ -898,37 +900,6 @@ void etcp_ack_recv(struct ETCP_CONN* etcp, uint32_t seq, uint16_t ts, uint16_t d return; } - // Calculate RTT if timestamps are valid -/* if (ts != (uint16_t)-1 && dts != (uint16_t)-1) { - uint16_t rtt = timestamp_diff(ts, dts); - etcp->rtt_last = rtt; - - // Update RTT averages (exponential smoothing) - if (etcp->rtt_avg_10 == 0) { - etcp->rtt_avg_10 = rtt; - etcp->rtt_avg_100 = rtt; - } else { - // RTT average over 10 packets - etcp->rtt_avg_10 = (etcp->rtt_avg_10 * 9 + rtt) / 10; - // RTT average over 100 packets - etcp->rtt_avg_100 = (etcp->rtt_avg_100 * 99 + rtt) / 100; - } - - // Update jitter calculation (max - min of last 10 RTT samples) - etcp->rtt_history[etcp->rtt_history_idx] = rtt; - etcp->rtt_history_idx = (etcp->rtt_history_idx + 1) % 10; - - uint16_t rtt_min = UINT16_MAX, rtt_max = 0; - for (int i = 0; i < 10; i++) { - if (etcp->rtt_history[i] < rtt_min) rtt_min = etcp->rtt_history[i]; - if (etcp->rtt_history[i] > rtt_max) rtt_max = etcp->rtt_history[i]; - } - etcp->jitter = rtt_max - rtt_min; - -// DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] RTT updated - last=%u, avg_10=%u, avg_100=%u, jitter=%u", -// etcp->log_name, rtt, etcp->rtt_avg_10, etcp->rtt_avg_100, etcp->jitter); - } -*/ // Update connection statistics etcp->unacked_bytes -= acked_pkt->ll.len; etcp->bytes_sent_total += acked_pkt->ll.len; @@ -960,10 +931,6 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) { uint16_t len = pkt->data_len; uint16_t ts = pkt->timestamp; // Received timestamp - // Note: Assume packet starts with sections after timestamp (but timestamp is already extracted in connections?). - // Protocol.txt: timestamp is first 2B, then sections. - // But in conn_input, pkt->data is after timestamp? Assume data starts with first section. - while (len >= 1) { uint8_t type = data[0]; @@ -987,32 +954,83 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) { case ETCP_SECTION_TIMESTAMP: { uint16_t cur_ts=get_current_timestamp(); uint16_t ret_ts=data[1] | (data[2]<<8);// cur_ts=ret_ts = RTT - pkt->link->rtt_last=cur_ts-ret_ts; + uint16_t new_rtt=cur_ts-ret_ts; + pkt->link->rtt_last=new_rtt; + + uint8_t old_idx = pkt->link->rtt_history_index; + uint16_t old_val = pkt->link->rtt_history[old_idx]; + + pkt->link->rtt_history[old_idx] = new_rtt; + pkt->link->rtt_history_index = (old_idx + 1) % 10; + if (pkt->link->rtt_history_count < 10) pkt->link->rtt_history_count++; + + if (new_rtt >= pkt->link->rtt_max_val) { + pkt->link->rtt_max_val = new_rtt; + pkt->link->rtt_max_idx = old_idx; + } else if (old_val == pkt->link->rtt_max_val) { + pkt->link->rtt_max_idx = 255; + } + + uint8_t rtt_cnt = pkt->link->rtt_history_count; + if (rtt_cnt == 1) { + pkt->link->rtt_avg10 = new_rtt; + } else { + uint32_t sum = 0; + if (pkt->link->rtt_max_idx == 255) { + uint16_t max_val = 0; + uint8_t max_pos = 0; + for (uint8_t i = 0; i < rtt_cnt; i++) { + uint16_t v = pkt->link->rtt_history[i]; + sum += v; + if (v > max_val) { + max_val = v; + max_pos = i; + } + } + pkt->link->rtt_max_val = max_val; + pkt->link->rtt_max_idx = max_pos; + } else { + for (uint8_t i = 0; i < rtt_cnt; i++) { + sum += pkt->link->rtt_history[i]; + } + } + pkt->link->rtt_avg10 = (sum - pkt->link->rtt_max_val) / (rtt_cnt - 1); + } int recv_dt_tx1=data[3] | (data[4]<<8);// localtime удаленной стороны момента принятия пакета - timestamp этого пакета (на стороне отправителя, т.е. у нас) - int recv_dt_tx=recv_dt_tx1 - pkt->link->rtt_last/2; - int recv_dt_rx=cur_ts - pkt->link->rtt_last/2 - ts; - if (pkt->link->recv_dt_avg_rx==0) pkt->link->recv_dt_avg_rx=recv_dt_rx*256; - if (pkt->link->recv_dt_avg_tx==0) pkt->link->recv_dt_avg_tx=recv_dt_tx*256; - pkt->link->recv_dt_avg_rx +=(recv_dt_rx*256 - pkt->link->recv_dt_avg_rx)/256; - pkt->link->recv_dt_avg_tx +=(recv_dt_tx*256 - pkt->link->recv_dt_avg_tx)/256; - pkt->link->tt_last = recv_dt_tx1;// - pkt->link->recv_dt_avg_tx/256; - pkt->link->rt_last = cur_ts - ts - pkt->link->recv_dt_avg_tx/256; + int recv_dt_rx=cur_ts - pkt->link->rtt_last/2 - 1000 - ts; + int recv_dt_tx=recv_dt_tx1 - pkt->link->rtt_last/2 - 1000; + if (pkt->link->recv_dt_avg_rx==0) pkt->link->recv_dt_avg_rx=recv_dt_rx*65536; + if (pkt->link->recv_dt_avg_tx==0) pkt->link->recv_dt_avg_tx=recv_dt_tx*65536; + pkt->link->recv_dt_avg_rx +=((int32_t)(recv_dt_rx*65536 - pkt->link->recv_dt_avg_rx))/32; + pkt->link->recv_dt_avg_tx +=((int32_t)(recv_dt_tx*65536 - pkt->link->recv_dt_avg_tx))/32; + pkt->link->rt_last = cur_ts - ts - pkt->link->recv_dt_avg_rx/65536; + pkt->link->tt_last = recv_dt_tx1 - pkt->link->recv_dt_avg_tx/65536; //tts_correction += ((NOW - RTT/2 - TTS) - tts_correction)/16 (инициализируем сразу по 1 пакету) data+=5; len-=5; + int d_rtt=pkt->link->rtt_avg10 - pkt->link->rtt_last; + if (d_rtt<0) d_rtt=-d_rtt; + pkt->link->jitter +=((int32_t)(d_rtt*65536 - pkt->link->jitter))/32; + struct ETCP_LINK* c=etcp->links; int rtt_sum=0; + int rtt_a10_max=0; int tt_sum=0; + int j_sum=0; int cnt=0; while (c) { rtt_sum += c->rtt_last; + if (rtt_a10_max < c->rtt_avg10) rtt_a10_max = c->rtt_avg10; tt_sum += c->tt_last; + j_sum += c->jitter/32768; cnt++; c=c->next; } etcp->rtt_last=rtt_sum/cnt; + etcp->rtt_avg_10=rtt_a10_max; etcp->tt_last=tt_sum/cnt; + etcp->jitter=j_sum/cnt; break; } case ETCP_SECTION_PAYLOAD: { diff --git a/src/etcp_connections.c b/src/etcp_connections.c index aa401786..941bbbe6 100644 --- a/src/etcp_connections.c +++ b/src/etcp_connections.c @@ -566,6 +566,13 @@ struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn link->ip_port_hash = sockaddr_hash(remote_addr); link->last_recv_local_time = get_time_tb(); // Initialize to prevent immediate timeout + // RTT sliding window initialization + link->rtt_history_index = 0; + link->rtt_history_count = 0; + link->rtt_max_val = 0; + link->rtt_max_idx = 0; + // rtt_history[] is already zeroed by calloc + // insert_link(conn, link); if (insert_link(conn, link) < 0) { // откатываем то, что успели diff --git a/src/etcp_connections.h b/src/etcp_connections.h index b7ccd25d..49ccc4c8 100644 --- a/src/etcp_connections.h +++ b/src/etcp_connections.h @@ -97,7 +97,14 @@ struct ETCP_LINK { size_t total_encrypted; size_t total_decrypted; - uint16_t rtt_last; // round trip (время отправки + приёма) + uint16_t rtt_last; // round trip (время отправки + приёма) + uint16_t rtt_history[10]; // Circular buffer for last 10 RTT values + uint8_t rtt_history_count; // Number of valid entries in history (0-10) + uint8_t rtt_history_index; // Current write position in history buffer + uint32_t jitter; // Current jitter [>>16] x0.1 ms + uint16_t rtt_max_val; // Current max RTT in history + uint8_t rtt_max_idx; // Index of max (255 = needs recalc) + uint16_t rtt_avg10; // round trip average (excl. max) uint32_t recv_dt_avg_tx; // дельта времени для отправленных пакетов (относительное время отправки) x256 uint32_t recv_dt_avg_rx; // дельта времени для принятых пакетов (относительное время отправки) x256 diff --git a/tools/etcpmon/etcpmon_gui.c b/tools/etcpmon/etcpmon_gui.c index 28cbd57e..35e0c0f3 100644 --- a/tools/etcpmon/etcpmon_gui.c +++ b/tools/etcpmon/etcpmon_gui.c @@ -931,10 +931,10 @@ void etcpmon_gui_update_metrics(struct etcpmon_app* app, if (!app || !metrics) return; HWND hMain = app->hWndMain; /* ETCP Metrics — обновляем ТОЛЬКО при изменении */ - UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_RTT_LAST, "%u us", metrics->etcp.rtt_last * 100); - UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_RTT_AVG10, "%u us", metrics->etcp.rtt_avg_10 * 100); - UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_RTT_AVG100, "%u us", metrics->etcp.rtt_avg_100 * 100); - UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_JITTER, "%u us", metrics->etcp.jitter * 100); + UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_RTT_LAST, "%.1f ms", metrics->etcp.rtt_last/10.f); + UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_RTT_AVG10, "%.1f ms", metrics->etcp.rtt_avg_10/10.f); + UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_RTT_AVG100, "%.1f ms", metrics->etcp.rtt_avg_100/10.f); + UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_JITTER, "%.1f ms", metrics->etcp.jitter/10.f); UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_BYTES_SENT, "%llu", (unsigned long long)metrics->etcp.bytes_sent_total); UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_RETRANS, "%u", metrics->etcp.retrans_count); UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_ACKS, "%u", metrics->etcp.ack_count); @@ -1028,7 +1028,7 @@ void etcpmon_gui_update_metrics(struct etcpmon_app* app, snprintf(line1, sizeof(line1), "Link %u: Status=%s, EncErr=%u, DecErr=%u, " "SndErr=%u, RcvErr=%u, Enc=%llu, Dec=%llu, " - "BW=%u Kbps, NAT=%u, RTT=%u us, TT=%u us", + "BW=%u Kbps, NAT=%u,", links[i].local_link_id, links[i].status ? "UP" : "DOWN", links[i].encrypt_errors, @@ -1038,13 +1038,14 @@ void etcpmon_gui_update_metrics(struct etcpmon_app* app, (unsigned long long)links[i].total_encrypted, (unsigned long long)links[i].total_decrypted, links[i].bandwidth, - links[i].nat_changes_count, - links[i].rtt_last * 100, - links[i].tt_last * 100); + links[i].nat_changes_count); snprintf(line2, sizeof(line2), - " Timers: Init=%s, KA=%s, Shaper=%s | " + " RTT=%.1f ms, avg10=%.1f ms, TT=%.1f ms Timers: Init=%s, KA=%s, Shaper=%s | " "KAsent=%u, KArecv=%u", + (float)links[i].rtt_last/10.0f, + (float)links[i].rtt_avg10/10.0f, + (float)links[i].tt_last/10.f, links[i].init_timer_active ? "ON" : "OFF", links[i].keepalive_timer_active ? "ON" : "OFF", links[i].shaper_timer_active ? "ON" : "OFF", diff --git a/tools/etcpmon/etcpmon_protocol.h b/tools/etcpmon/etcpmon_protocol.h index f75a75dd..aba7bff3 100644 --- a/tools/etcpmon/etcpmon_protocol.h +++ b/tools/etcpmon/etcpmon_protocol.h @@ -180,6 +180,7 @@ struct etcpmon_link_metrics { uint32_t bandwidth; /* Configured bandwidth (Kbps) */ uint32_t nat_changes_count; /* NAT address changes */ uint32_t rtt_last; /* Last RTT (0.1ms units) */ + uint32_t rtt_avg10; /* avg RTT (0.1ms units) */ uint32_t tt_last; /* Last transmit time (0.1ms units) */ /* Timer flags (1 = active, 0 = NULL) */