refactor: STCP connections as ETCP links (is_tcp)
- Add is_tcp, tcp_link, tcp_reconnect_* fields to ETCP_LINK - Remove transport_link from ETCP_CONN, add tcp_link_count - stcp_link: replace embedded etcp_conn with pointer; add etcp_link backpointer - stcp_link: link_rx_cb routes ETCP data to etcp_conn_input - stcp_link: call on_close_cb in close - New TCP functions: etcp_link_enter_ready_tcp, etcp_tcp_link_start_connect, etcp_tcp_link_start_reconnect, tcp_link_close_cb, etcp_tcp_send - etcp_link_new: handle NULL conn for TCP links; skip enter_init for TCP - etcp_link_close: close stcp_link for TCP - etcp_encrypt_send: redirect TCP to etcp_tcp_send (skips AES-CCM) - tcp_server_on_link: create ETCP_LINK(is_tcp=1) + enter_ready_tcp - etcp_connect: TCP addrs -> etcp_tcp_link_start_connect - Remove ctx->tcp_link/tcp_ready - test_stcp_traffic: find stcp_link via links->is_tcp instead of transport_link - 66/68 tests pass; 2 STCP tests expected to fail (integration not complete)
This commit is contained in:
1 parent
937af4c26a
commit
d773f1724a
1705 files changed
+187
-1082154
No files matched your search
@@ -1,234 +0,0 @@
|
||||
// nodespage.cpp — Nodes table + dump in settings
|
||||
#include "nodespage.h"
|
||||
#include "../db/db_manager.h"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QDateTime>
|
||||
#include <QFont>
|
||||
#include <cstring>
|
||||
|
||||
#include "../../../lib/platform_compat.h"
|
||||
|
||||
static QString hex16(uint64_t v) {
|
||||
return QString("%1").arg(v, 16, 16, QChar('0')).toUpper();
|
||||
}
|
||||
|
||||
QString NodesPage::shortenKey(const QByteArray& key) {
|
||||
if (key.size() < 8) return key.toHex(' ').toUpper();
|
||||
return key.left(4).toHex(' ').toUpper() + ".." + key.right(4).toHex(' ').toUpper();
|
||||
}
|
||||
|
||||
QString NodesPage::addrStr(const void* addr, int family) {
|
||||
if (family == 4) {
|
||||
const uint8_t* a = (const uint8_t*)addr;
|
||||
return QString("%1.%2.%3.%4").arg(a[0]).arg(a[1]).arg(a[2]).arg(a[3]);
|
||||
}
|
||||
if (family == 6) {
|
||||
const uint16_t* a = (const uint16_t*)addr;
|
||||
return QString("%1:%2:%3:%4:%5:%6:%7:%8")
|
||||
.arg(ntohs(a[0]), 0, 16).arg(ntohs(a[1]), 0, 16)
|
||||
.arg(ntohs(a[2]), 0, 16).arg(ntohs(a[3]), 0, 16)
|
||||
.arg(ntohs(a[4]), 0, 16).arg(ntohs(a[5]), 0, 16)
|
||||
.arg(ntohs(a[6]), 0, 16).arg(ntohs(a[7]), 0, 16);
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
QString NodesPage::protoStr(int protocol) {
|
||||
switch (protocol) {
|
||||
case 1: return "UDP";
|
||||
case 2: return "TCP";
|
||||
case 3: return "UDP+TCP";
|
||||
default: return QString::number(protocol);
|
||||
}
|
||||
}
|
||||
|
||||
static QString addrTypeStr(int t) {
|
||||
switch (t) { case 0: return "NETIF"; case 1: return "DIRECT"; case 2: return "NAT_EIM"; case 3: return "NAT_STRICT"; default: return QString("?%1").arg(t); }
|
||||
}
|
||||
|
||||
NodesPage::NodesPage(DbManager* db, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, m_db(db)
|
||||
{
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
layout->setSpacing(8);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
auto* title = new QLabel("Known Nodes", this);
|
||||
title->setStyleSheet("font-weight: bold; font-size: 13px;");
|
||||
layout->addWidget(title);
|
||||
|
||||
m_table = new QTableWidget(0, 6, this);
|
||||
m_table->setHorizontalHeaderLabels({"Node ID", "Name", "Online", "x25519", "ed25519", "Addrs"});
|
||||
m_table->horizontalHeader()->setStretchLastSection(true);
|
||||
m_table->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
m_table->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_table->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
m_table->verticalHeader()->setVisible(false);
|
||||
m_table->setFont(QFont("monospace", 9));
|
||||
m_table->setStyleSheet(
|
||||
"QTableWidget { border: 1px solid palette(mid); border-radius: 4px;"
|
||||
" gridline-color: palette(midlight); background: palette(base); }"
|
||||
"QHeaderView::section { background: palette(window); padding: 4px;"
|
||||
" font-weight: bold; font-size: 9px; }");
|
||||
layout->addWidget(m_table, 2);
|
||||
|
||||
auto* dumpLabel = new QLabel("Details", this);
|
||||
dumpLabel->setStyleSheet("font-weight: bold; font-size: 12px; margin-top: 8px;");
|
||||
layout->addWidget(dumpLabel);
|
||||
|
||||
m_dumpText = new QPlainTextEdit(this);
|
||||
m_dumpText->setReadOnly(true);
|
||||
m_dumpText->setFont(QFont("monospace", 10));
|
||||
m_dumpText->setStyleSheet(
|
||||
"QPlainTextEdit { border: 1px solid palette(mid); border-radius: 4px;"
|
||||
" padding: 8px; background: palette(base); }");
|
||||
m_dumpText->setPlaceholderText("Click Refresh to load nodes");
|
||||
layout->addWidget(m_dumpText, 3);
|
||||
|
||||
auto* btnLayout = new QHBoxLayout();
|
||||
btnLayout->addStretch();
|
||||
m_refreshBtn = new QPushButton("Refresh", this);
|
||||
m_refreshBtn->setFixedWidth(90);
|
||||
m_refreshBtn->setStyleSheet(
|
||||
"QPushButton { border: 1px solid palette(mid); border-radius: 4px;"
|
||||
" padding: 6px 16px; font-size: 13px; background: palette(button); }"
|
||||
"QPushButton:hover { background: palette(light); }");
|
||||
connect(m_refreshBtn, &QPushButton::clicked, this, &NodesPage::onRefreshClicked);
|
||||
btnLayout->addWidget(m_refreshBtn);
|
||||
layout->addLayout(btnLayout);
|
||||
}
|
||||
|
||||
void NodesPage::onRefreshClicked() { refreshNodes(); }
|
||||
|
||||
void NodesPage::refreshNodes() {
|
||||
if (!m_db || !m_db->m_db) {
|
||||
m_table->setRowCount(0);
|
||||
m_dumpText->setPlainText(QString("Database not connected (m_db=%1, m_db->m_db=%2)")
|
||||
.arg((quintptr)m_db, 0, 16).arg(m_db ? (quintptr)m_db->m_db : 0, 0, 16));
|
||||
qWarning("NodesPage::refreshNodes: DB not ready m_db=%p m_db->m_db=%p", (void*)m_db, m_db ? (void*)m_db->m_db : nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
sqlite3* d = m_db->m_db;
|
||||
|
||||
/* ── table ── */
|
||||
m_table->setRowCount(0);
|
||||
|
||||
sqlite3_stmt* st = nullptr;
|
||||
if (sqlite3_prepare_v2(d,
|
||||
"SELECT node_id, name, online, x25519_pubkey, ed25519_pubkey,"
|
||||
" last_seen_at, created_at FROM nodes ORDER BY node_id",
|
||||
-1, &st, nullptr) != SQLITE_OK) return;
|
||||
|
||||
int row = 0;
|
||||
while (sqlite3_step(st) == SQLITE_ROW) {
|
||||
m_table->insertRow(row);
|
||||
quint64 nid = (quint64)sqlite3_column_int64(st, 0);
|
||||
|
||||
auto setCell = [&](int col, const QString& v) {
|
||||
m_table->setItem(row, col, new QTableWidgetItem(v));
|
||||
};
|
||||
|
||||
setCell(0, hex16(nid));
|
||||
setCell(1, DbManager::colText(st, 1));
|
||||
setCell(2, sqlite3_column_int(st, 2) ? "yes" : "no");
|
||||
|
||||
QByteArray x25 = DbManager::colBlob(st, 3);
|
||||
QByteArray ed = DbManager::colBlob(st, 4);
|
||||
setCell(3, x25.isEmpty() ? "-" : shortenKey(x25));
|
||||
setCell(4, ed.isEmpty() ? "-" : shortenKey(ed));
|
||||
|
||||
sqlite3_stmt* ac = nullptr;
|
||||
sqlite3_prepare_v2(d, "SELECT COUNT(*) FROM node_addresses WHERE node_id=?", -1, &ac, nullptr);
|
||||
if (ac) {
|
||||
sqlite3_bind_int64(ac, 1, (sqlite3_int64)nid);
|
||||
setCell(5, sqlite3_step(ac) == SQLITE_ROW
|
||||
? QString::number(sqlite3_column_int(ac, 0))
|
||||
: "0");
|
||||
sqlite3_finalize(ac);
|
||||
} else {
|
||||
setCell(5, "0");
|
||||
}
|
||||
row++;
|
||||
}
|
||||
sqlite3_finalize(st);
|
||||
m_table->resizeColumnsToContents();
|
||||
|
||||
/* ── text dump ── */
|
||||
QString dump;
|
||||
|
||||
st = nullptr;
|
||||
sqlite3_prepare_v2(d,
|
||||
"SELECT node_id, name, online, x25519_pubkey, ed25519_pubkey,"
|
||||
" last_seen_at, created_at FROM nodes ORDER BY node_id",
|
||||
-1, &st, nullptr);
|
||||
if (!st) { m_dumpText->setPlainText("Query error"); return; }
|
||||
|
||||
int nodeCount = 0;
|
||||
while (sqlite3_step(st) == SQLITE_ROW) {
|
||||
if (nodeCount > 0) dump += "\n";
|
||||
nodeCount++;
|
||||
|
||||
quint64 nid = (quint64)sqlite3_column_int64(st, 0);
|
||||
QString name = DbManager::colText(st, 1);
|
||||
int online = sqlite3_column_int(st, 2);
|
||||
QByteArray x25 = DbManager::colBlob(st, 3);
|
||||
QByteArray ed = DbManager::colBlob(st, 4);
|
||||
qint64 last_seen = sqlite3_column_int64(st, 5);
|
||||
qint64 created = sqlite3_column_int64(st, 6);
|
||||
|
||||
dump += QString("Node: %1").arg(hex16(nid));
|
||||
if (!name.isEmpty()) dump += QString(" (%1)").arg(name);
|
||||
dump += QString(" id=0x%1\n").arg(nid, 16, 16, QChar('0'));
|
||||
dump += QString(" online: %1\n").arg(online ? "yes" : "no");
|
||||
dump += QString(" x25519: %1\n").arg(x25.isEmpty() ? "-" : shortenKey(x25));
|
||||
dump += QString(" ed25519: %1\n").arg(ed.isEmpty() ? "-" : shortenKey(ed));
|
||||
if (last_seen > 0)
|
||||
dump += QString(" last_seen: %1\n").arg(QDateTime::fromSecsSinceEpoch(last_seen).toString("yyyy-MM-dd hh:mm:ss"));
|
||||
if (created > 0)
|
||||
dump += QString(" created: %1\n").arg(QDateTime::fromSecsSinceEpoch(created).toString("yyyy-MM-dd hh:mm:ss"));
|
||||
|
||||
sqlite3_stmt* na = nullptr;
|
||||
sqlite3_prepare_v2(d,
|
||||
"SELECT family, protocol, address, port, rtt, addr_type"
|
||||
" FROM node_addresses WHERE node_id=? ORDER BY family, port",
|
||||
-1, &na, nullptr);
|
||||
if (na) {
|
||||
sqlite3_bind_int64(na, 1, (sqlite3_int64)nid);
|
||||
int ac = 0;
|
||||
while (sqlite3_step(na) == SQLITE_ROW) {
|
||||
if (ac == 0) dump += " addresses:\n";
|
||||
int family = sqlite3_column_int(na, 0);
|
||||
int proto = sqlite3_column_int(na, 1);
|
||||
const void* addr = sqlite3_column_blob(na, 2);
|
||||
int addrSz = sqlite3_column_bytes(na, 2);
|
||||
int port = sqlite3_column_int(na, 3);
|
||||
int rtt = sqlite3_column_int(na, 4);
|
||||
int addrType = sqlite3_column_int(na, 5);
|
||||
|
||||
if (addr && addrSz > 0) {
|
||||
dump += QString(" %1:%2 %3 %4 rtt=%5ms\n")
|
||||
.arg(addrStr(addr, family))
|
||||
.arg(port)
|
||||
.arg(protoStr(proto))
|
||||
.arg(addrTypeStr(addrType))
|
||||
.arg(rtt > 0 ? QString::number(rtt / 10) : "-");
|
||||
}
|
||||
ac++;
|
||||
}
|
||||
if (ac == 0) dump += " addresses: none\n";
|
||||
sqlite3_finalize(na);
|
||||
} else {
|
||||
dump += " addresses: none\n";
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(st);
|
||||
|
||||
if (nodeCount == 0) dump = "No nodes found.";
|
||||
m_dumpText->setPlainText(dump);
|
||||
}
|
||||
Reference in new issue
Block a user