You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

135 lines
3.7 KiB

// utun_node.cpp — embedded uTun node running in a dedicated thread
#include "utun_node.h"
#include <cinttypes>
// === C headers ===
extern "C" {
#include "utun_instance.h"
#include "etcp_router.h"
#include "etcp_api.h"
#include "etcp.h"
#include "config_parser.h"
#include "config_updater.h"
#include "control_server.h"
#include "secure_channel.h"
#include "../lib/u_async.h"
#include "../lib/ll_queue.h"
#include "../lib/memory_pool.h"
#include "../lib/debug_config.h"
#include "../lib/mem.h"
}
#define ETCP_RT_ID_CHAT 0x11
static thread_local UtunNode* g_currentNode = nullptr;
UtunNode::UtunNode(QObject* parent) : QObject(parent) {}
UtunNode::~UtunNode() {
stop();
}
bool UtunNode::start(const QString& configPath) {
if (m_running) return false;
m_configPath = configPath;
m_stop = false;
m_running = true;
m_thread = std::thread(&UtunNode::runLoop, this);
for (int i = 0; i < 50 && m_running && !m_instance; ++i)
std::this_thread::sleep_for(std::chrono::milliseconds(10));
if (!m_instance) {
m_stop = true;
if (m_thread.joinable()) m_thread.join();
m_running = false;
return false;
}
emit started();
return true;
}
void UtunNode::stop() {
if (!m_running) return;
m_stop = true;
if (m_thread.joinable()) m_thread.join();
m_running = false;
}
void UtunNode::send(uint64_t dstNodeId, const QByteArray& data) {
if (!m_instance) return;
struct ll_entry* entry = queue_entry_new(data.size());
if (!entry) return;
memcpy(entry->data, data.constData(), data.size());
etcp_route_send(m_instance, dstNodeId, entry, 0);
}
QString UtunNode::nodeIdHex() const {
if (!m_instance) return {};
char buf[32];
snprintf(buf, sizeof(buf), "%016" PRIx64, m_instance->node_id);
return QString(buf);
}
QString UtunNode::pubKeyHex() const {
if (!m_instance || !m_instance->config) return {};
return QString::fromLatin1(m_instance->config->global.my_public_key_hex, 64);
}
void UtunNode::recvCallback(struct ETCP_CONN* conn, struct ll_entry* entry) {
if (!g_currentNode || !entry) return;
uint64_t src = conn ? conn->peer_node_id : 0;
QByteArray data((const char*)entry->data, (int)(entry->len ? entry->len : 0));
QMetaObject::invokeMethod(g_currentNode, [=] {
emit g_currentNode->messageReceived(src, data);
}, Qt::QueuedConnection);
}
void UtunNode::runLoop() {
g_currentNode = this;
debug_config_init();
debug_set_level(DEBUG_LEVEL_ERROR);
debug_enable_function_name(0);
utun_instance_set_tun_init_enabled(0);
struct UASYNC* ua = uasync_create();
if (!ua) {
QMetaObject::invokeMethod(this, [this] { emit error("uasync_create failed"); });
g_currentNode = nullptr;
return;
}
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);
g_currentNode = nullptr;
return;
}
m_instance->test_user_ptr = this;
if (utun_instance_init(m_instance) != 0) {
QMetaObject::invokeMethod(this, [this] { emit error("utun_instance_init failed"); });
utun_instance_destroy(m_instance);
m_instance = nullptr;
uasync_destroy(ua, 0);
g_currentNode = nullptr;
return;
}
etcp_router_bind(m_instance, ETCP_RT_ID_CHAT, recvCallback);
while (!m_stop) {
uasync_poll(ua, 100);
}
etcp_router_bind(m_instance, ETCP_RT_ID_CHAT, nullptr);
utun_instance_destroy(m_instance);
m_instance = nullptr;
uasync_destroy(ua, 0);
g_currentNode = nullptr;
QMetaObject::invokeMethod(this, [this] { emit stopped(); });
}