From 11ab897fe5c220bf2fec897c55523100a7a9963d Mon Sep 17 00:00:00 2001 From: Evgeny Date: Sun, 26 Jul 2026 08:57:02 +0300 Subject: [PATCH] chatgui: fix RTT display 10x overstatement (DB stores 0.1ms, displayed as ms); remove unused rtt_avg_100 --- src/control_server.c | 1 - src/transport_layer/etcp.c | 3 - src/transport_layer/etcp.h | 1 - src/transport_layer/etcp_dump.c | 4 +- task.txt | 79 +++++++++++++++++++++++++++ tools/chatgui/src/accountlist.cpp | 2 +- tools/chatgui/src/memberlistmodel.cpp | 2 +- tools/chatgui/src/nodespage.cpp | 2 +- tools/chatgui/transport/chat_status.c | 2 +- tools/chatgui/transport/chat_sync.c | 8 --- tools/etcpmon/etcpmon_gui.c | 3 - tools/etcpmon/etcpmon_protocol.h | 1 - 12 files changed, 85 insertions(+), 23 deletions(-) create mode 100644 task.txt diff --git a/src/control_server.c b/src/control_server.c index be5a858a..a06368b8 100644 --- a/src/control_server.c +++ b/src/control_server.c @@ -1064,7 +1064,6 @@ static void send_metrics(struct control_server* server, struct control_client* c rsp->etcp.peer_node_id = conn->peer_node_id; rsp->etcp.rtt_last = conn->rtt_last; rsp->etcp.rtt_avg_10 = conn->rtt_avg_10; - rsp->etcp.rtt_avg_100 = conn->rtt_avg_100; rsp->etcp.jitter = conn->jitter; rsp->etcp.bytes_sent_total = conn->bytes_sent_total; rsp->etcp.retrans_count = conn->retransmissions_count; diff --git a/src/transport_layer/etcp.c b/src/transport_layer/etcp.c index 161f4769..c28949b2 100644 --- a/src/transport_layer/etcp.c +++ b/src/transport_layer/etcp.c @@ -240,7 +240,6 @@ struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance, char* n etcp->mtu = ETCP_RFC791_MIN_MTU; // Default MTU per RFC 791 etcp->next_tx_id = 1; etcp->rtt_avg_10 = 10; // Initial guess (1ms) - etcp->rtt_avg_100 = 10; etcp->rtt_history_idx = 0; memset(etcp->rtt_history, 0, sizeof(etcp->rtt_history)); @@ -451,7 +450,6 @@ void etcp_conn_reset(struct ETCP_CONN* etcp) { etcp->unacked_bytes = 0; etcp->rtt_last = 0; etcp->rtt_avg_10 = 0; - etcp->rtt_avg_100 = 0; etcp->jitter = 0; etcp->last_rtt_cb_time = 0; etcp->bytes_sent_total = 0; @@ -856,7 +854,6 @@ void etcp_stats(struct ETCP_CONN* etcp) { DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] RTT metrics:", etcp->log_name); DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] rtt_last: %u (0.1ms)", etcp->log_name, etcp->rtt_last); DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] rtt_avg_10: %u (0.1ms)", etcp->log_name, etcp->rtt_avg_10); - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] rtt_avg_100: %u (0.1ms)", etcp->log_name, etcp->rtt_avg_100); DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] jitter: %u (0.1ms)", etcp->log_name, etcp->jitter); // Counters diff --git a/src/transport_layer/etcp.h b/src/transport_layer/etcp.h index cda281c1..3fafbe1c 100644 --- a/src/transport_layer/etcp.h +++ b/src/transport_layer/etcp.h @@ -197,7 +197,6 @@ struct ETCP_CONN { uint16_t tt_last;// transmission time (время пакета до меня) // uint16_t rxt_last;// recv relative time (бустро регаирует на изменение задержки rx и медленно на изменение задержки tx) uint16_t rtt_avg_10; - uint16_t rtt_avg_100; uint16_t jitter; uint64_t last_rtt_cb_time; // время последнего вызова ping_update_rtt (0.1ms) uint32_t bytes_sent_total; diff --git a/src/transport_layer/etcp_dump.c b/src/transport_layer/etcp_dump.c index d3f1249d..411722f2 100644 --- a/src/transport_layer/etcp_dump.c +++ b/src/transport_layer/etcp_dump.c @@ -65,8 +65,8 @@ void etcp_dump_conn_state(struct ETCP_CONN* conn) { conn->next_tx_id, conn->last_rx_id, conn->last_delivered_id, conn->rx_ack_till); /* --- RTT --- */ - DUMP_LINE("RTT: last=%u avg10=%u avg100=%u jitter=%u", - conn->rtt_last, conn->rtt_avg_10, conn->rtt_avg_100, conn->jitter); + DUMP_LINE("RTT: last=%u avg10=%u jitter=%u", + conn->rtt_last, conn->rtt_avg_10, conn->jitter); /* --- STATS --- */ DUMP_LINE("STATS: bytes_sent=%u retrans=%u reinit=%u reset=%u ack_pkts=%u", diff --git a/task.txt b/task.txt new file mode 100644 index 00000000..aabca001 --- /dev/null +++ b/task.txt @@ -0,0 +1,79 @@ +## Текущая задача: отладка merkle sync в chatgui + +### Контекст + +Две инстанции chatgui обмениваются мемберами (участниками) каналов через merkle sync. +Одна на Linux (node `41eab6811e3ff67b`), вторая на Windows (node `32a3a1ee5625ceb9`). + +### Что уже исправлено (vetka topo_upd) + +1. **`conn_mgr.c:276`** — убрано требование `links_up` при поиске существующего коннекта. + Раньше второй `conn_mgr_connect_node` (для второй группы/канала) не находил первый коннект + потому что тот был в handshake (links_up=0) и создавал дублирующий линк → два init-таймера + → два потока INIT-пакетов → бесконечный цикл реинициализации ETCP. + +2. **`etcp_connections.c:insert_link_queue`** — детект коллизии адреса: если адрес уже занят + ДРУГИМ коннектом → жирная ошибка + return -1 (вместо молчаливой замены). + +3. **`etcp.c:etcp_conn_set_peer_node_id`** — детект коллизии peer_id: если key уже занят + другим коннектом → жирная ошибка + return (не переиндексировать). + +4. **`merkle_sync.c`** — исправлен формат сообщений: + - Отправитель клал type ПЕРЕД ch_len+ns: `[svc][TYPE][ch_len][ns]...` + - Получатель (`_recv_cb`) ожидал `[svc][ch_len][ns][TYPE]...` (как у chat_sync) + - Переставлены байты в `_send_hashes`, `_send_batch`, MSG_REQUEST builder + - Результат: handle_hashes/handle_request/handle_batch начали реально получать сообщения + +5. **`merkle_sync.c`** — `_handle_batch` теперь вызывает `_session_done(s, MT_OK)` после + обработки всех терминальных бакетов. До этого сессия никогда не завершалась, + таймер истекал → retry → к тому моменту соединение уже отваливалось. + +### Текущее состояние + +Merkle sync обменивается сообщениями и завершает сессии (`session SYNCED` в логах). +Но данные мемберов не совпадают: Linux имеет 3 мембера в канале, Windows — 2. + +### Найденная проблема (исследуется) + +В логах `handle_batch` показывает `len=7` для обоих каналов с обеих сторон. +Это означает что в BATCH-сообщении данные мемберов = всего 2 байта (count=0). + +При этом `merkle_tree_hash` показывает НЕнулевой bitmap (00008000) → `update_bucket_hash` +находит мемберов в бакете. Но `get_items` для того же бакета возвращает 0 записей. + +**Гипотеза:** `update_bucket_hash` и `get_items` используют разную логику фильтрации +для одного и того же level/prefix → SQL запрос в `get_items` не находит мемберов. + +Файлы: `tools/chatgui/transport/member_sync.c` функции `_member_update_bucket_hash` и `_member_get_items`. + +### Данные из БД (Linux) + +Канал 17611191138590969914: 3 мембера +- 4749809422690154107 (0x41eab6811e3ff67b — Linux self) +- 3648938168119840441 (0x32a3a1ee5625ceb9 — Windows peer) +- 5749221071098079620 (0x4fc9561a7dfde984 — третий узел) + +Канал 10175004475814804132: 2 мембера +- 3648938168119840441 (0x32a3a1ee5625ceb9) +- 4749809422690154107 (0x41eab6811e3ff67b) + +Merkle tree для канала 176111...: +``` +level=1 prefix=0x4000000000000000 member_count=1 hash=F612B771... +level=2 prefix=0x41E0000000000000 member_count=1 hash=F612B771... +level=3 prefix=0x41EA000000000000 member_count=1 hash=F612B771... +level=4 prefix=0x41EAB00000000000 member_count=1 hash=F612B771... +level=5 prefix=0x41EAB68000000000 member_count=1 hash=F612B771... +``` + +### Логи + +Linux: `/home/vnc1/proj/utun3/tools/chatgui/build/chatgui.log` +Windows: `/home/vnc1/proj/utun3/tools/chatgui/build/chatgui2.log` + +Конфиг: `db_sync=debug` включён. + +### БД + +Linux: `/home/vnc1/proj/utun3/tools/chatgui/build/chat_data/chats.db` +Windows: `C:/ARM/_uTun/utun2/tools/chatgui/build/chat_data/chats.db` (доступа нет) diff --git a/tools/chatgui/src/accountlist.cpp b/tools/chatgui/src/accountlist.cpp index 97584d1a..4fccfb3d 100644 --- a/tools/chatgui/src/accountlist.cpp +++ b/tools/chatgui/src/accountlist.cpp @@ -156,7 +156,7 @@ void AccountList::showMemberDetail(quint64 nodeId) { .arg(port) .arg(protoStr(proto)) .arg(addrTypeStr(addrType)) - .arg(rtt > 0 ? QString::number(rtt) : "-"); + .arg(rtt > 0 ? QString::number(rtt / 10) : "-"); ac++; } if (ac == 0) text += " addresses: none\n"; diff --git a/tools/chatgui/src/memberlistmodel.cpp b/tools/chatgui/src/memberlistmodel.cpp index 94c6f0bd..fd247638 100644 --- a/tools/chatgui/src/memberlistmodel.cpp +++ b/tools/chatgui/src/memberlistmodel.cpp @@ -22,7 +22,7 @@ QVariant MemberListModel::data(const QModelIndex& index, int role) const { if (role == Qt::DecorationRole) return QVariant::fromValue(QIcon(it->avatar)); if (role == Qt::UserRole + 1) { QString sub; - if (it->rtt >= 0) sub += QString("rtt=%1ms").arg(it->rtt); + if (it->rtt >= 0) sub += QString("rtt=%1ms").arg(it->rtt / 10); if (it->natType >= 0) { static const char* nat[] = {"NET","DIR","EIM","STR"}; const char* nt = (it->natType <= 3) ? nat[it->natType] : "?"; diff --git a/tools/chatgui/src/nodespage.cpp b/tools/chatgui/src/nodespage.cpp index c0d753d4..06a6d2ee 100644 --- a/tools/chatgui/src/nodespage.cpp +++ b/tools/chatgui/src/nodespage.cpp @@ -217,7 +217,7 @@ void NodesPage::refreshNodes() { .arg(port) .arg(protoStr(proto)) .arg(addrTypeStr(addrType)) - .arg(rtt > 0 ? QString::number(rtt) : "-"); + .arg(rtt > 0 ? QString::number(rtt / 10) : "-"); } ac++; } diff --git a/tools/chatgui/transport/chat_status.c b/tools/chatgui/transport/chat_status.c index 62d6fd08..d68e8c62 100644 --- a/tools/chatgui/transport/chat_status.c +++ b/tools/chatgui/transport/chat_status.c @@ -97,7 +97,7 @@ static void chat_core_collect_status(void) { struct ETCP_LINK* link = conn->links; while (link) { char rtt_str[32]; rtt_str[0] = '\0'; - if (link->rtt_last > 0) snprintf(rtt_str, sizeof(rtt_str), " / rtt=%ums", link->rtt_last); + if (link->rtt_last > 0) snprintf(rtt_str, sizeof(rtt_str), " / rtt=%ums", link->rtt_last / 10); off += snprintf(buf + off, sizeof(buf) - off, " LINK#%d: %s /NAT=%s%s\n", link_idx, link->link_status ? "UP" : "DOWN", diff --git a/tools/chatgui/transport/chat_sync.c b/tools/chatgui/transport/chat_sync.c index 7ecb13cb..d292a89a 100644 --- a/tools/chatgui/transport/chat_sync.c +++ b/tools/chatgui/transport/chat_sync.c @@ -427,14 +427,6 @@ static void cs_on_conn_down(struct ETCP_CONN* conn, void* arg) { cs_on_peer_status_changed(peer, 0); - uint16_t rtt = conn->rtt_avg_100; - if (rtt > 0 && peer != 0 && g_cs->inst->topo_sqlite_db) { - sqlite3* db = g_cs->inst->topo_sqlite_db; - sqlite3_stmt* st = NULL; - sqlite3_prepare_v2(db, "UPDATE node_addresses SET rtt=? WHERE node_id=?", -1, &st, NULL); - if (st) { sqlite3_bind_int(st, 1, (int)rtt); sqlite3_bind_int64(st, 2, (sqlite3_int64)peer); sqlite3_step(st); sqlite3_finalize(st); } - DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: conn_down saved rtt=%u for node %016llx", CS_ID, rtt, (unsigned long long)peer); - } cs_cancel_proto_timers(g_cs); if (g_cs->pending_invite_node_id == peer) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: conn down while waiting invite resp peer=%016llx, timers cancelled, state kept for retry on reconnect", diff --git a/tools/etcpmon/etcpmon_gui.c b/tools/etcpmon/etcpmon_gui.c index 697d225a..a8f15a88 100644 --- a/tools/etcpmon/etcpmon_gui.c +++ b/tools/etcpmon/etcpmon_gui.c @@ -873,8 +873,6 @@ static void CreateTooltips(struct etcpmon_app* app) "etcp.rtt_last / ETCP Connection\r\nRound-trip time of the last packet (RTT), units 0.1 ms"); AddTooltip(app->hToolTip, app->hEditEtcpRttAvg10, "etcp.rtt_avg_10 / ETCP Connection\r\nAverage RTT over last 10 packets, units 0.1 ms"); - AddTooltip(app->hToolTip, app->hEditEtcpRttAvg100, - "etcp.rtt_avg_100 / ETCP Connection\r\nAverage RTT over last 100 packets, units 0.1 ms"); AddTooltip(app->hToolTip, app->hEditEtcpJitter, "etcp.jitter / ETCP Connection\r\nRTT spread (max - min), units 0.1 ms"); AddTooltip(app->hToolTip, app->hEditEtcpBytesSent, @@ -1624,7 +1622,6 @@ void etcpmon_gui_update_metrics(struct etcpmon_app* app, /* ETCP Metrics — обновляем ТОЛЬКО при изменении */ 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); diff --git a/tools/etcpmon/etcpmon_protocol.h b/tools/etcpmon/etcpmon_protocol.h index ecf8409c..7d2abfb2 100644 --- a/tools/etcpmon/etcpmon_protocol.h +++ b/tools/etcpmon/etcpmon_protocol.h @@ -152,7 +152,6 @@ struct etcpmon_etcp_metrics { uint64_t peer_node_id; /* Connection identifier */ uint32_t rtt_last; /* Last RTT (0.1ms units) */ uint32_t rtt_avg_10; /* Average RTT over 10 packets */ - uint32_t rtt_avg_100; /* Average RTT over 100 packets */ uint32_t jitter; /* Jitter (max-min RTT) */ uint64_t bytes_sent_total; /* Total bytes sent */ uint32_t retrans_count; /* Retransmission count */