diff --git a/tools/chatgui/src/main.cpp b/tools/chatgui/src/main.cpp index 10fbec40..3674860c 100644 --- a/tools/chatgui/src/main.cpp +++ b/tools/chatgui/src/main.cpp @@ -9,13 +9,14 @@ #include "mainwindow.h" #include "../db/db_manager.h" #include "../transport/node_config.h" +#include "../transport/utun_node.h" #ifdef _WIN32 -extern "C" void utun_node_signal_shutdown(void); +static UtunNode* g_ctrl_node = nullptr; static BOOL WINAPI console_ctrl_handler(DWORD dwCtrlType) { if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { - utun_node_signal_shutdown(); + if (g_ctrl_node) g_ctrl_node->requestStop(); return TRUE; } return FALSE; @@ -92,6 +93,7 @@ int main(int argc, char *argv[]) { w.show(); #ifdef _WIN32 + g_ctrl_node = w.utunNode(); SetConsoleCtrlHandler(console_ctrl_handler, TRUE); #endif diff --git a/tools/chatgui/src/mainwindow.cpp b/tools/chatgui/src/mainwindow.cpp index 65002eee..be215956 100644 --- a/tools/chatgui/src/mainwindow.cpp +++ b/tools/chatgui/src/mainwindow.cpp @@ -120,10 +120,11 @@ void MainWindow::setupNode() { connect(m_node, &UtunNode::started, this, []() { qDebug("UtunNode started"); }); - connect(m_node, &UtunNode::stopped, this, []() { + connect(m_node, &UtunNode::stopped, this, [this]() { qDebug("UtunNode stopped"); + if (m_node) m_node->finalize(); + qApp->quit(); }); - connect(m_node, &UtunNode::stopped, qApp, &QApplication::quit); if (!m_cfgDebugFile.isEmpty()) m_node->setDebugFile(m_cfgDebugFile); @@ -255,7 +256,9 @@ void MainWindow::setupTray() { }); QAction *quitAction = m_trayMenu->addAction("Quit"); - connect(quitAction, &QAction::triggered, qApp, &QApplication::quit); + connect(quitAction, &QAction::triggered, this, [this]() { + if (m_node) m_node->requestStop(); + }); m_trayIcon->setContextMenu(m_trayMenu); diff --git a/tools/chatgui/src/mainwindow.h b/tools/chatgui/src/mainwindow.h index 814f3a2b..adab944b 100644 --- a/tools/chatgui/src/mainwindow.h +++ b/tools/chatgui/src/mainwindow.h @@ -36,6 +36,7 @@ public: void onAutoConnectStatus(uint8_t status, uint16_t total, uint16_t totalNodes, uint16_t connected); void onChannelPeersOnline(const char* ch_id, int ch_id_len, uint16_t online); void reloadChannels(); + UtunNode* utunNode() const { return m_node; } private: void setupUi(); diff --git a/tools/chatgui/transport/utun_node.cpp b/tools/chatgui/transport/utun_node.cpp index 778607c2..94493577 100644 --- a/tools/chatgui/transport/utun_node.cpp +++ b/tools/chatgui/transport/utun_node.cpp @@ -35,18 +35,9 @@ extern "C" { static thread_local UtunNode* g_currentNode = nullptr; -static volatile sig_atomic_t g_shutdown = 0; -static struct UASYNC* g_signal_ua = nullptr; - static void signal_handler(int sig) { (void)sig; - g_shutdown = 1; - if (g_signal_ua) uasync_wakeup(g_signal_ua); -} - -extern "C" void utun_node_signal_shutdown(void) { - g_shutdown = 1; - if (g_signal_ua) uasync_wakeup(g_signal_ua); + if (g_currentNode) g_currentNode->requestStop(); } UtunNode::UtunNode(QObject* parent) : QObject(parent) {} @@ -92,13 +83,32 @@ void UtunNode::setDebugCategories(const QString& categories) { m_debugCategories = categories; } +void UtunNode::requestStop() { + m_stop = true; + if (m_ua) uasync_wakeup(m_ua); +} + void UtunNode::stop() { if (!m_running) return; - m_stop = true; + requestStop(); if (m_thread.joinable()) m_thread.join(); + finalize(); m_running = false; } +void UtunNode::finalize() { + if (!m_instance) return; + DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "finalize: cleanup start"); + etcp_router_bind(m_instance, ETCP_RT_ID_CHAT, nullptr); + chat_sync_destroy(m_instance); + chat_core_destroy(m_instance); + utun_instance_destroy(m_instance); + m_instance = nullptr; + uasync_destroy(m_ua, 0); + m_ua = nullptr; + DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "finalize: cleanup done"); +} + void UtunNode::send(uint64_t dstNodeId, const QByteArray& data) { if (!m_instance) return; struct ll_entry* entry = queue_entry_new(data.size()); @@ -273,11 +283,13 @@ void UtunNode::runLoop() { g_currentNode = nullptr; return; } + m_ua = ua; m_instance = utun_instance_create(ua, m_configPath.toUtf8().constData()); if (!m_instance) { QMetaObject::invokeMethod(this, [this] { emit error("utun_instance_create failed"); }); uasync_destroy(ua, 0); + m_ua = nullptr; g_currentNode = nullptr; return; } @@ -319,6 +331,7 @@ void UtunNode::runLoop() { utun_instance_destroy(m_instance); m_instance = nullptr; uasync_destroy(ua, 0); + m_ua = nullptr; g_currentNode = nullptr; return; } @@ -336,31 +349,18 @@ void UtunNode::runLoop() { DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "chat_core + chat_sync initialized"); DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "utun_node: entering poll loop"); - g_signal_ua = ua; signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); - while (!m_stop && !g_shutdown) { + while (!m_stop) { uasync_poll(ua, 100); } - DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "runLoop: poll exit m_stop=%d g_shutdown=%d", (int)m_stop, (int)g_shutdown); + DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "runLoop: poll exit m_stop=%d", (int)m_stop); signal(SIGINT, SIG_DFL); signal(SIGTERM, SIG_DFL); - g_signal_ua = nullptr; - etcp_router_bind(m_instance, ETCP_RT_ID_CHAT, nullptr); - DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "runLoop: etcp_router_unbind done"); - chat_sync_destroy(m_instance); - DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "runLoop: chat_sync_destroy done"); - chat_core_destroy(m_instance); - DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "runLoop: chat_core_destroy done"); - utun_instance_destroy(m_instance); - DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "runLoop: utun_instance_destroy done"); - m_instance = nullptr; - uasync_destroy(ua, 0); - DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "runLoop: uasync_destroy done, emitting stopped"); - g_currentNode = nullptr; + DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "runLoop: emitting stopped"); QMetaObject::invokeMethod(this, [this] { emit stopped(); }); } diff --git a/tools/chatgui/transport/utun_node.h b/tools/chatgui/transport/utun_node.h index 28ab6b1a..1e44b447 100644 --- a/tools/chatgui/transport/utun_node.h +++ b/tools/chatgui/transport/utun_node.h @@ -21,8 +21,10 @@ public: ~UtunNode(); bool start(const QString& configPath); + void requestStop(); void stop(); bool isRunning() const { return m_running; } + void finalize(); void setDebugFile(const QString& path); void setDbPath(const QString& path); @@ -49,6 +51,7 @@ private: static void recvCallback(struct ETCP_CONN* conn, struct ll_entry* entry); UTUN_INSTANCE* m_instance = nullptr; + struct UASYNC* m_ua = nullptr; std::thread m_thread; std::atomic m_running{false}; std::atomic m_stop{false};