From d453e73ddba52f93a26d476ccf0e517011ff2f06 Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 8 Aug 2026 07:31:38 +0300 Subject: [PATCH] etcp: TCP links skip remote keepalive gating; chatgui: show interface names in member detail, fix destructor callbacks --- src/transport_layer/etcp_connections.c | 9 ++--- tools/chatgui/src/accountlist.cpp | 50 +++++++++++++++++++++++--- tools/chatgui/src/accountlist.h | 2 ++ tools/chatgui/src/mainwindow.cpp | 11 ++++++ 4 files changed, 62 insertions(+), 10 deletions(-) diff --git a/src/transport_layer/etcp_connections.c b/src/transport_layer/etcp_connections.c index ebcc3eef..21534c7d 100644 --- a/src/transport_layer/etcp_connections.c +++ b/src/transport_layer/etcp_connections.c @@ -62,9 +62,6 @@ void tcp_server_on_link(struct stcp_link *link, void *arg) { etcp_update_log_name(conn); { struct conn_queue_entry* ce = (struct conn_queue_entry*)conn->conn_queue_entry->data; ce->peer_node_id = node_id; queue_remove_data(conn->conn_queue, conn->conn_queue_entry); queue_data_put_with_index(conn->conn_queue, conn->conn_queue_entry); } DEBUG_INFO(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: new ETCP_CONN peer=0x%016llx", (unsigned long long)node_id); - } else { - struct ETCP_LINK* nl = conn->links; - while (nl) { struct ETCP_LINK* nx = nl->next; if (nl->is_tcp) etcp_link_close(nl); nl = nx; } } struct ETCP_LINK *tlink = etcp_link_new(conn, NULL, NULL, 1); @@ -306,7 +303,7 @@ static void etcp_link_send_keepalive(struct ETCP_LINK* link) { dgram->data_len = 3; dgram->noencrypt_len = 0; dgram->timestamp = get_current_timestamp(); - dgram->flag_up = link->recv_keepalive; + dgram->flag_up = link->is_tcp ? 1 : link->recv_keepalive; link->keepalive_sent_count++; @@ -1153,7 +1150,7 @@ static int etcp_tcp_send(struct ETCP_DGRAM* dgram) { struct ETCP_LINK *link = dgram->link; if (!link->tcp_link || !stcp_link_is_ready(link->tcp_link)) return -1; link->pkt_sent_since_keepalive = 1; - dgram->flag_up = link->recv_keepalive; + dgram->flag_up = 1; int rc; if (link->send_hook) rc = (int)link->send_hook(0, dgram->data, dgram->data_len, NULL, 0, link, link->send_hook_ctx); else if (link->tcp_link) rc = stcp_link_send(link->tcp_link, dgram->data, dgram->data_len) == 0 ? (int)dgram->data_len : -1; @@ -2238,7 +2235,7 @@ process_decrypted: } int was_up = link->link_status; - link->link_status = link->remote_keepalive && link->recv_keepalive; + link->link_status = link->is_tcp ? link->recv_keepalive : (link->remote_keepalive && link->recv_keepalive); if (link->link_status != was_up) etcp_fire_link_status_cbk(link, link->link_state, was_up); if (link->link_status && !was_up && link->initialized) { diff --git a/tools/chatgui/src/accountlist.cpp b/tools/chatgui/src/accountlist.cpp index 4753e48d..3061627a 100644 --- a/tools/chatgui/src/accountlist.cpp +++ b/tools/chatgui/src/accountlist.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "../../../lib/platform_compat.h" extern "C" { @@ -174,7 +175,7 @@ void AccountList::showMemberDetail(quint64 nodeId) { sqlite3_stmt* na = nullptr; sqlite3_prepare_v2(d, - "SELECT family, protocol, address, port FROM node_addresses WHERE node_id=? ORDER BY family, port", + "SELECT family, protocol, address, port, socket_id FROM node_addresses WHERE node_id=?", -1, &na, nullptr); if (na) { sqlite3_bind_int64(na, 1, (sqlite3_int64)nodeId); @@ -185,12 +186,46 @@ void AccountList::showMemberDetail(quint64 nodeId) { const void* adr = sqlite3_column_blob(na, 2); int sz = sqlite3_column_bytes(na, 2); if (adr && sz > 0) a.addr = QByteArray((const char*)adr, sz); - a.port = sqlite3_column_int(na, 3); + a.port = sqlite3_column_int(na, 3); + a.socket_id = sqlite3_column_int(na, 4); if (!a.addr.isEmpty()) m_detailAddrs.append(a); } sqlite3_finalize(na); } + /* resolve interface names from live sockets and sort */ + if (m_inst) { + for (auto& a : m_detailAddrs) { + if (a.protocol == 1) { + for (struct ETCP_SOCKET* s = m_inst->etcp_sockets; s; s = s->next) { + if ((int)s->sock_id == a.socket_id) { + QString name = QString::fromLatin1(s->name); + int idx = name.lastIndexOf("_v"); + if (idx > 3) a.ifname = name.mid(3, idx - 3); + break; + } + } + } else if (a.protocol == 2) { + for (struct TCP_SOCKET* ts = m_inst->tcp_sockets; ts; ts = ts->next) { + if ((int)ts->sock_id == a.socket_id) { + QString name = QString::fromLatin1(ts->name); + int idx = name.lastIndexOf("_v"); + if (idx > 3) a.ifname = name.mid(3, idx - 3); + break; + } + } + } + } + } + + std::sort(m_detailAddrs.begin(), m_detailAddrs.end(), + [](const DetailAddress& a, const DetailAddress& b) { + if (a.ifname != b.ifname) return a.ifname < b.ifname; + if (a.addr != b.addr) return a.addr < b.addr; + if (a.protocol != b.protocol) return a.protocol < b.protocol; + return a.port < b.port; + }); + m_detailTimer->start(); m_linkTimer->start(); updateDetailDisplay(); @@ -292,8 +327,15 @@ void AccountList::updateDetailDisplay() { if (linkCount > 0) prefix = QString("[%1] ").arg(linkCount); } - lines.append(QString("%1● %3:%4:%5") - .arg(prefix, linkColor, proto, addrStr(a.addr.constData(), a.family)).arg(a.port)); + if (!a.ifname.isEmpty()) { + lines.append(QString("%1● %3 %4") + .arg(prefix, linkColor, proto, a.ifname)); + lines.append(QString("  %1:%2") + .arg(addrStr(a.addr.constData(), a.family)).arg(a.port)); + } else { + lines.append(QString("%1● %3:%4:%5") + .arg(prefix, linkColor, proto, addrStr(a.addr.constData(), a.family)).arg(a.port)); + } } /* Show ETCP links that are not in DB (non-self) */ diff --git a/tools/chatgui/src/accountlist.h b/tools/chatgui/src/accountlist.h index 28de93ee..95334edd 100644 --- a/tools/chatgui/src/accountlist.h +++ b/tools/chatgui/src/accountlist.h @@ -17,6 +17,8 @@ struct DetailAddress { int protocol; QByteArray addr; int port; + int socket_id; + QString ifname; }; class AccountList : public QWidget { diff --git a/tools/chatgui/src/mainwindow.cpp b/tools/chatgui/src/mainwindow.cpp index 85c2b144..5b2b3ba2 100644 --- a/tools/chatgui/src/mainwindow.cpp +++ b/tools/chatgui/src/mainwindow.cpp @@ -104,6 +104,17 @@ MainWindow::MainWindow(QWidget *parent, DbManager* db, const QString& cfgPath, } MainWindow::~MainWindow() { + s_mainWindow = nullptr; + m_autoPlayTimer->stop(); + gui_bridge_set_msg_received_cb(nullptr); + gui_bridge_set_channel_updated_cb(nullptr); + gui_bridge_set_members_changed_cb(nullptr); + gui_bridge_set_my_node_id_cb(nullptr); + gui_bridge_set_auto_connect_status_cb(nullptr); + gui_bridge_set_channel_peers_online_cb(nullptr); + gui_bridge_set_db_ready_cb(nullptr); + gui_bridge_set_attachment_downloaded_cb(nullptr); + QCoreApplication::processEvents(QEventLoop::AllEvents); if (m_recorder) { m_recorder->shutdown(); m_recorder = nullptr; } SoundManager::instance()->shutdown(); DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "MainWindow: ~MainWindow — saving channel state");