node_conn_direct: add open_node variant, refactor internals

This commit is contained in:
evgeny committed 2026-08-01 09:45:32 +03:00
1 parent 153483fd96
commit eb2a8f6975
3 files changed
+252 -222

No files matched your search

+134 -189
View File
@@ -1,18 +1,15 @@
/*
* node_conn_direct.c — handle-based ETCP connection layer
*
* Тонкая прослойка над ETCP: управляет подключениями по node_id.
* Тонкая прослойка над ETCP: управляет прямыми подключениями по node_id.
* Несколько handle'ов могут разделять одно ETCP_CONN.
* Conn закрывается при закрытии последнего handle (с протоколом CLOSE/KEEP_ALIVE).
* Поддерживает REVERSE-подключение через etcp_router если задан group_id.
*/
#include "node_conn_direct.h"
#include "etcp_api.h"
#include "etcp.h"
#include "etcp_connections.h"
#include "etcp_router.h"
#include "conn_mgr.h"
#include "secure_channel.h"
#include "utun_instance.h"
#include "topo_node.h"
@@ -31,18 +28,12 @@
/* ═══════════ локальные константы ═══════════ */
#define CM_V6_LINK_LOCAL 0
#define CM_V6_LOCAL 1
#define CM_V6_DIRECT 2
#define CM_V6_OTHER 3
#define NCD_FIN_WAIT_TIMEOUT_TB 50000 /* 5 сек в 0.1ms */
/* ═══════════ внутренние структуры ═══════════ */
struct ncd_entry {
uint64_t node_id;
uint64_t group_id; /* для REVERSE (0 = без REVERSE) */
struct ETCP_CONN* conn;
struct UASYNC* ua;
int handle_count;
@@ -51,7 +42,6 @@ struct ncd_entry {
void* connect_timer; /* однократный таймер первого подъёма */
void* fin_wait_timer; /* таймер ожидания ответа на CLOSE */
void* reverse_poll_timer; /* таймер polling входящего conn при REVERSE */
uint8_t up : 1; /* текущий статус: 1=есть живой линк */
uint8_t timed_out : 1; /* connect_timer уже сработал */
@@ -158,99 +148,6 @@ static int ncd_create_links(struct ncd_entry* entry, struct TOPO_NODE* ni) {
return link_count;
}
/* ═══════════ REVERSE ═══════════ */
static uint8_t ncd_classify_v6_addr(const uint8_t addr[16]) {
if (addr[0] == 0xfe && (addr[1] & 0xc0) == 0x80) return CM_V6_LINK_LOCAL;
if (addr[0] == 0xfc || addr[0] == 0xfd) return CM_V6_LOCAL;
if (addr[0] == 0xff) return CM_V6_OTHER;
{ uint8_t zero[16] = {0}; if (memcmp(addr, zero, 16) == 0) return CM_V6_OTHER; }
{ uint8_t lb[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; if (memcmp(addr, lb, 16) == 0) return CM_V6_OTHER; }
return CM_V6_DIRECT;
}
static int ncd_has_direct_ip(const struct TOPO_NODE* node) {
if (!node) return 0;
for (const struct TOPO_ADDR4* a = node->v4_addrs; a; a = a->next) {
if (a->type == TOPO_ADDR_NAT || a->type == TOPO_ADDR_INTERFACE) {
for (const struct TOPO_SOCKMETA4* m = node->v4_sock_meta; m; m = m->next) {
if (m->id == a->socket_id && (m->config_type == CFG_SERVER_TYPE_PUBLIC || m->config_type == CFG_SERVER_TYPE_UNKNOWN
|| m->nat_type == NAT_VERIFIED_EIM || m->nat_type == NAT_VERIFIED_DIRECT))
return 1;
}
}
}
for (const struct TOPO_ADDR6* a6 = node->v6_addrs; a6; a6 = a6->next) {
if ((a6->type != TOPO_ADDR_NAT && a6->type != TOPO_ADDR_INTERFACE) || ncd_classify_v6_addr(a6->addr) != CM_V6_DIRECT) continue;
for (const struct TOPO_SOCKMETA6* m = node->v6_sock_meta; m; m = m->next)
if (m->id == a6->socket_id && (m->config_type == CFG_SERVER_TYPE_PUBLIC || m->config_type == CFG_SERVER_TYPE_UNKNOWN
|| m->nat_type == NAT_VERIFIED_EIM || m->nat_type == NAT_VERIFIED_DIRECT))
return 1;
}
return 0;
}
static void ncd_try_reverse(struct ncd_entry* entry, struct TOPO_NODE* local_node, struct TOPO_NODE* target_node) {
if (!local_node || !target_node) return;
int has_our = ncd_has_direct_ip(local_node);
int has_target = ncd_has_direct_ip(target_node);
if (!has_our || has_target) return;
uint8_t direct_count = 0;
struct { uint8_t type; uint8_t ip[4]; uint16_t port; uint8_t socket_id; } out_addrs[8];
for (const struct TOPO_ADDR4* a = local_node->v4_addrs; a && direct_count < 8; a = a->next) {
if (a->type != TOPO_ADDR_NAT && a->type != TOPO_ADDR_INTERFACE) continue;
for (const struct TOPO_SOCKMETA4* m = local_node->v4_sock_meta; m; m = m->next) {
if (m->id == a->socket_id && (m->config_type == CFG_SERVER_TYPE_PUBLIC || m->config_type == CFG_SERVER_TYPE_UNKNOWN
|| m->nat_type == NAT_VERIFIED_EIM || m->nat_type == NAT_VERIFIED_DIRECT)) {
out_addrs[direct_count].type = a->type; memcpy(out_addrs[direct_count].ip, a->addr, 4);
out_addrs[direct_count].port = htons(a->port); out_addrs[direct_count].socket_id = a->socket_id;
direct_count++; break;
}
}
}
if (direct_count == 0) return;
size_t pkt_size = CONN_MGR_DIRECT_REQ_HDR_SIZE + (size_t)direct_count * 8;
uint8_t* pkt = u_malloc(pkt_size);
if (!pkt) return;
struct CONN_MGR_DIRECT_REQ* req = (struct CONN_MGR_DIRECT_REQ*)pkt;
req->cmd = ETCP_RT_ID_CONN_MGR;
req->subcmd = CONN_MGR_SUBCMD_DIRECT_REQ;
req->request_id = 0;
req->addr_count = direct_count;
uint8_t* p = pkt + CONN_MGR_DIRECT_REQ_HDR_SIZE;
for (uint8_t i = 0; i < direct_count; i++) {
*p++ = out_addrs[i].type;
memcpy(p, out_addrs[i].ip, 4); p += 4;
memcpy(p, &out_addrs[i].port, 2); p += 2;
*p++ = out_addrs[i].socket_id;
}
struct ll_entry* qe = queue_entry_new(0);
if (!qe) { u_free(pkt); return; }
qe->dgram = pkt; qe->len = (uint16_t)pkt_size;
etcp_route_send(entry->conn->instance, entry->group_id, entry->node_id, qe, 1);
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] REVERSE: sent DIRECT_REQ to 0x%016llx with %u addrs",
(unsigned long long)entry->node_id, direct_count);
}
/* ═══════════ REVERSE polling: проверка incoming conn ═══════════ */
static void ncd_reverse_poll_cb(void* arg) {
struct ncd_entry* entry = (struct ncd_entry*)arg;
if (!entry || entry->up || entry->timed_out || entry->conn->fin_wait) return;
struct ETCP_CONN* incoming = instance_find_conn(entry->conn->instance, entry->node_id);
if (incoming && incoming->state == 1 && incoming->peer_node_id == entry->node_id) {
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] REVERSE: incoming conn found node=0x%016llx", (unsigned long long)entry->node_id);
struct ETCP_CONN* old_conn = entry->conn;
entry->conn = incoming;
ncd_event_dispatch(entry, NCD_EVENT_UP);
if (old_conn && old_conn != incoming) etcp_connection_close(old_conn);
} else {
entry->reverse_poll_timer = uasync_set_timeout(entry->ua, 1000, entry, ncd_reverse_poll_cb, "ncd_rev_poll");
}
}
/* ═══════════ единая диспетчеризация событий ═══════════ */
static void ncd_event_dispatch(struct ncd_entry* entry, enum ncd_event event) {
@@ -259,7 +156,6 @@ static void ncd_event_dispatch(struct ncd_entry* entry, enum ncd_event event) {
case NCD_EVENT_UP:
if (entry->up) return;
if (entry->connect_timer) { uasync_cancel_timeout(entry->ua, entry->connect_timer); entry->connect_timer = NULL; }
if (entry->reverse_poll_timer) { uasync_cancel_timeout(entry->ua, entry->reverse_poll_timer); entry->reverse_poll_timer = NULL; }
entry->up = 1;
break;
case NCD_EVENT_DOWN:
@@ -316,16 +212,6 @@ static void ncd_connect_timeout_cb(void* arg) {
entry->connect_timer = NULL;
DEBUG_WARN(DEBUG_CATEGORY_NCD, "[ncd] connect timeout node=0x%016llx handles=%d",
(unsigned long long)entry->node_id, entry->handle_count);
/* проверяем incoming conn (REVERSE) */
struct ETCP_CONN* incoming = instance_find_conn(entry->conn->instance, entry->node_id);
if (incoming && incoming->state == 1 && incoming->peer_node_id == entry->node_id) {
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] connect timeout but incoming found, UP");
struct ETCP_CONN* old_conn = entry->conn;
entry->conn = incoming;
ncd_event_dispatch(entry, NCD_EVENT_UP);
if (old_conn && old_conn != incoming) etcp_connection_close(old_conn);
return;
}
ncd_event_dispatch(entry, NCD_EVENT_TIMEOUT);
}
@@ -415,7 +301,7 @@ static void ncd_init_control_binding(struct UTUN_INSTANCE* inst) {
/* ═══════════ API ═══════════ */
int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id, uint64_t group_id,
int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id,
ncd_callback cb, void* cb_arg,
struct NODE_CONN_DIRECT** out_handle) {
if (!inst || !out_handle) return NCD_ERR;
@@ -448,7 +334,7 @@ int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id, uint64_t
/* 2. Ищем conn через instance_find_conn (входящее / созданное etcp_connect) */
struct ETCP_CONN* conn = instance_find_conn(inst, node_id);
if (conn) {
if (conn && conn->state == 1) {
/* снять fin_wait если был */
if (conn->fin_wait) {
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open REUSED clearing fin_wait (existing conn) node=0x%016llx", (unsigned long long)node_id);
@@ -456,7 +342,7 @@ int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id, uint64_t
}
entry = u_calloc(1, sizeof(*entry));
if (!entry) { DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] alloc entry failed node=0x%016llx", (unsigned long long)node_id); return NCD_ERR; }
entry->node_id = node_id; entry->group_id = group_id; entry->conn = conn; entry->ua = inst->ua;
entry->node_id = node_id; entry->conn = conn; entry->ua = inst->ua;
entry->up = (uint8_t)(conn->links_up ? 1 : 0);
ncd_registry_add(entry);
@@ -524,7 +410,7 @@ int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id, uint64_t
DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] alloc entry failed node=0x%016llx", (unsigned long long)node_id);
etcp_connection_close(conn); topo_node_registry_unref(inst->topo_groups, ni->node_id); return NCD_ERR;
}
entry->node_id = node_id; entry->group_id = group_id; entry->conn = conn; entry->ua = inst->ua; entry->up = 0;
entry->node_id = node_id; entry->conn = conn; entry->ua = inst->ua; entry->up = 0;
ncd_registry_add(entry);
struct NODE_CONN_DIRECT* h = u_calloc(1, sizeof(*h));
@@ -541,18 +427,8 @@ int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id, uint64_t
int link_count = ncd_create_links(entry, ni);
if (link_count == 0 && group_id != 0) {
struct TOPO_GROUP* grp = topo_groups_find(inst->topo_groups, group_id);
struct TOPO_GROUP_NODE* local_nq = grp ? grp->local_node : NULL;
struct TOPO_NODE* local_node = local_nq ? topo_node_registry_find(inst->topo_groups, local_nq->node_id) : NULL;
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] no links, trying REVERSE node=0x%016llx group=0x%016llx",
(unsigned long long)node_id, (unsigned long long)group_id);
ncd_try_reverse(entry, local_node, ni);
entry->reverse_poll_timer = uasync_set_timeout(inst->ua, 1000, entry, ncd_reverse_poll_cb, "ncd_rev_poll");
}
if (link_count == 0) {
DEBUG_WARN(DEBUG_CATEGORY_NCD, "[ncd] no links created for node=0x%016llx (will wait for incoming)", (unsigned long long)node_id);
}
if (link_count == 0)
DEBUG_WARN(DEBUG_CATEGORY_NCD, "[ncd] no links created for node=0x%016llx", (unsigned long long)node_id);
entry->connect_timer = uasync_set_timeout(inst->ua, (int)inst->etcp_connect_timeout_tb, entry, ncd_connect_timeout_cb, "ncd_connect");
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open NEW node=0x%016llx conn=%p links=%d handles=%d",
@@ -561,6 +437,133 @@ int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id, uint64_t
return NCD_NEW;
}
int node_conn_direct_open_node(struct UTUN_INSTANCE* inst, uint64_t node_id,
ncd_callback cb, void* cb_arg,
struct NODE_CONN_DIRECT** out_handle,
struct TOPO_NODE* ni) {
if (!inst || !out_handle || !ni) return NCD_ERR;
*out_handle = NULL;
ncd_init_control_binding(inst);
/* 1. Ищем в реестре — conn уже есть */
{ struct ncd_entry* entry = ncd_registry_find(node_id);
if (entry) {
if (entry->conn && entry->conn->fin_wait) {
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open_node REUSED clearing fin_wait node=0x%016llx", (unsigned long long)node_id);
entry->conn->fin_wait = 0; entry->conn->fin_wait_clear_cb = NULL; entry->conn->fin_wait_clear_arg = NULL;
if (entry->fin_wait_timer) { uasync_cancel_timeout(entry->ua, entry->fin_wait_timer); entry->fin_wait_timer = NULL; }
}
struct NODE_CONN_DIRECT* h = u_calloc(1, sizeof(*h));
if (!h) { DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] open_node alloc handle failed node=0x%016llx", (unsigned long long)node_id); return NCD_ERR; }
h->entry = entry; h->cb = cb; h->cb_arg = cb_arg;
h->next = entry->handles; entry->handles = h;
entry->handle_count++;
*out_handle = h;
if (entry->conn && entry->conn->state == 1 && entry->up) {
uasync_call_soon(inst->ua, h, ncd_deliver_up_cb);
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open_node REUSED (ready) node=0x%016llx handles=%d", (unsigned long long)node_id, entry->handle_count);
} else {
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open_node REUSED (pending) node=0x%016llx handles=%d", (unsigned long long)node_id, entry->handle_count);
}
return NCD_REUSED;
}}
/* 2. Ищем conn через instance_find_conn */
{ struct ETCP_CONN* conn = instance_find_conn(inst, node_id);
if (conn) {
if (conn->fin_wait) {
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open_node REUSED clearing fin_wait (existing conn) node=0x%016llx", (unsigned long long)node_id);
conn->fin_wait = 0; conn->fin_wait_clear_cb = NULL; conn->fin_wait_clear_arg = NULL;
}
struct ncd_entry* entry = u_calloc(1, sizeof(*entry));
if (!entry) { DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] open_node alloc entry failed node=0x%016llx", (unsigned long long)node_id); return NCD_ERR; }
entry->node_id = node_id; entry->conn = conn; entry->ua = inst->ua;
entry->up = (uint8_t)(conn->links_up ? 1 : 0);
ncd_registry_add(entry);
struct NODE_CONN_DIRECT* h = u_calloc(1, sizeof(*h));
if (!h) { DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] open_node alloc handle failed node=0x%016llx", (unsigned long long)node_id);
ncd_registry_remove(entry); u_free(entry); return NCD_ERR; }
h->entry = entry; h->cb = cb; h->cb_arg = cb_arg;
h->next = entry->handles; entry->handles = h;
entry->handle_count = 1;
*out_handle = h;
etcp_conn_add_cbk(conn, ncd_init_cb, entry, ETCP_CBK_EVENT_INIT);;
etcp_conn_add_cbk(conn, ncd_up_cb, entry, ETCP_CBK_EVENT_UP);;
etcp_conn_add_cbk(conn, ncd_down_cb, entry, ETCP_CBK_EVENT_DOWN);;
if (conn->state == 1 && entry->up) {
uasync_call_soon(inst->ua, h, ncd_deliver_up_cb);
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open_node REUSED new-entry (ready) node=0x%016llx conn=%p", (unsigned long long)node_id, (void*)conn);
} else {
entry->connect_timer = uasync_set_timeout(inst->ua, (int)inst->etcp_connect_timeout_tb, entry, ncd_connect_timeout_cb, "ncd_connect_node");
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open_node REUSED new-entry (pending) node=0x%016llx conn=%p", (unsigned long long)node_id, (void*)conn);
}
return NCD_REUSED;
}}
/* 3. Новое подключение — используем переданный ni (временный, не владеем) */
{ struct ETCP_CONN* conn = etcp_connection_create(inst, NULL);
if (!conn) {
DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] open_node etcp_connection_create failed node=0x%016llx", (unsigned long long)node_id);
return NCD_ERR;
}
conn->peer_node_id = node_id;
etcp_update_log_name(conn);
if (sc_init_ctx(&conn->crypto_ctx, &inst->my_keys) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] open_node sc_init_ctx failed node=0x%016llx", (unsigned long long)node_id);
etcp_connection_close(conn); return NCD_ERR;
}
if (sc_set_peer_public_key(&conn->crypto_ctx, ni->public_key, 0) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] open_node sc_set_peer_public_key failed node=0x%016llx", (unsigned long long)node_id);
etcp_connection_close(conn); return NCD_ERR;
}
if (conn->conn_queue && conn->conn_queue_entry) {
queue_remove_data(conn->conn_queue, conn->conn_queue_entry);
queue_entry_free(conn->conn_queue_entry);
}
{ struct ll_entry* qe = queue_entry_new(sizeof(struct conn_queue_entry));
if (qe) { struct conn_queue_entry* ce = (struct conn_queue_entry*)qe->data;
ce->peer_node_id = node_id; ce->conn = conn;
conn->conn_queue_entry = qe; conn->conn_queue = inst->connections;
queue_data_put_with_index(inst->connections, qe); }
}
struct ncd_entry* entry = u_calloc(1, sizeof(*entry));
if (!entry) {
DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] open_node alloc entry failed node=0x%016llx", (unsigned long long)node_id);
etcp_connection_close(conn); return NCD_ERR;
}
entry->node_id = node_id; entry->conn = conn; entry->ua = inst->ua; entry->up = 0;
ncd_registry_add(entry);
struct NODE_CONN_DIRECT* h = u_calloc(1, sizeof(*h));
if (!h) { DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] open_node alloc handle failed node=0x%016llx", (unsigned long long)node_id);
ncd_registry_remove(entry); u_free(entry); etcp_connection_close(conn); return NCD_ERR; }
h->entry = entry; h->cb = cb; h->cb_arg = cb_arg;
h->next = entry->handles; entry->handles = h;
entry->handle_count = 1;
*out_handle = h;
etcp_conn_add_cbk(conn, ncd_init_cb, entry, ETCP_CBK_EVENT_INIT);;
etcp_conn_add_cbk(conn, ncd_up_cb, entry, ETCP_CBK_EVENT_UP);;
etcp_conn_add_cbk(conn, ncd_down_cb, entry, ETCP_CBK_EVENT_DOWN);;
int link_count = ncd_create_links(entry, ni);
if (link_count == 0)
DEBUG_WARN(DEBUG_CATEGORY_NCD, "[ncd] open_node no links created for node=0x%016llx", (unsigned long long)node_id);
entry->connect_timer = uasync_set_timeout(inst->ua, (int)inst->etcp_connect_timeout_tb, entry, ncd_connect_timeout_cb, "ncd_connect_node");
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open_node NEW node=0x%016llx conn=%p links=%d handles=%d",
(unsigned long long)node_id, (void*)conn, link_count, entry->handle_count);
return NCD_NEW;
}
}
void node_conn_direct_close(struct NODE_CONN_DIRECT* h) {
if (!h) return;
struct ncd_entry* entry = h->entry;
@@ -578,7 +581,6 @@ void node_conn_direct_close(struct NODE_CONN_DIRECT* h) {
if (entry->handle_count <= 0) {
if (entry->connect_timer) { uasync_cancel_timeout(entry->ua, entry->connect_timer); entry->connect_timer = NULL; }
if (entry->reverse_poll_timer) { uasync_cancel_timeout(entry->ua, entry->reverse_poll_timer); entry->reverse_poll_timer = NULL; }
if (conn && conn->state != 2) {
/* устанавливаем fin_wait, отправляем CLOSE, ставим таймер */
conn->fin_wait = 1;
@@ -607,63 +609,6 @@ void node_conn_direct_close(struct NODE_CONN_DIRECT* h) {
u_free(h);
}
int node_conn_direct_adopt(struct UTUN_INSTANCE* inst, struct ETCP_CONN* conn,
ncd_callback cb, void* cb_arg,
struct NODE_CONN_DIRECT** out_handle) {
if (!inst || !conn || !out_handle) return NCD_ERR;
*out_handle = NULL;
ncd_init_control_binding(inst);
uint64_t node_id = conn->peer_node_id;
/* снять fin_wait если был */
if (conn->fin_wait) {
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] adopt clearing fin_wait node=0x%016llx", (unsigned long long)node_id);
conn->fin_wait = 0; conn->fin_wait_clear_cb = NULL; conn->fin_wait_clear_arg = NULL;
}
/* проверяем реестр */
struct ncd_entry* entry = ncd_registry_find(node_id);
if (entry) {
/* entry уже есть — просто добавляем handle */
if (entry->fin_wait_timer) { uasync_cancel_timeout(entry->ua, entry->fin_wait_timer); entry->fin_wait_timer = NULL; }
if (entry->conn != conn) {
if (entry->conn && entry->conn->state != 2) etcp_connection_close(entry->conn);
entry->conn = conn;
}
struct NODE_CONN_DIRECT* h = u_calloc(1, sizeof(*h));
if (!h) return NCD_ERR;
h->entry = entry; h->cb = cb; h->cb_arg = cb_arg;
h->next = entry->handles; entry->handles = h;
entry->handle_count++;
*out_handle = h;
if (conn->state == 1 && entry->up) uasync_call_soon(inst->ua, h, ncd_deliver_up_cb);
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] adopt REUSED node=0x%016llx handles=%d", (unsigned long long)node_id, entry->handle_count);
return NCD_REUSED;
}
entry = u_calloc(1, sizeof(*entry));
if (!entry) { DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] adopt alloc entry failed node=0x%016llx", (unsigned long long)node_id); return NCD_ERR; }
entry->node_id = node_id; entry->conn = conn; entry->ua = inst->ua;
entry->up = (uint8_t)(conn->links_up ? 1 : 0);
ncd_registry_add(entry);
struct NODE_CONN_DIRECT* h = u_calloc(1, sizeof(*h));
if (!h) { ncd_registry_remove(entry); u_free(entry); return NCD_ERR; }
h->entry = entry; h->cb = cb; h->cb_arg = cb_arg;
h->next = entry->handles; entry->handles = h;
entry->handle_count = 1;
*out_handle = h;
etcp_conn_add_cbk(conn, ncd_init_cb, entry, ETCP_CBK_EVENT_INIT);;
etcp_conn_add_cbk(conn, ncd_up_cb, entry, ETCP_CBK_EVENT_UP);;
etcp_conn_add_cbk(conn, ncd_down_cb, entry, ETCP_CBK_EVENT_DOWN);;
if (conn->state == 1 && entry->up) uasync_call_soon(inst->ua, h, ncd_deliver_up_cb);
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] adopt NEW node=0x%016llx conn=%p handles=%d", (unsigned long long)node_id, (void*)conn, entry->handle_count);
return NCD_REUSED;
}
struct ETCP_CONN* node_conn_direct_get_conn(struct NODE_CONN_DIRECT* h) {
if (!h || !h->entry) return NULL;
return h->entry->conn;
+6 -10
View File
@@ -5,6 +5,7 @@
struct UTUN_INSTANCE;
struct ETCP_CONN;
struct TOPO_NODE;
/* ─── Return codes ─── */
#define NCD_NEW 0
@@ -26,24 +27,19 @@ typedef void (*ncd_callback)(struct NODE_CONN_DIRECT* h, enum ncd_event event, v
/*
* Открыть handle к узлу по node_id.
* Node info — из node_registry, fallback SQLite.
* group_id — для REVERSE-подключения через etcp_route_send (0 = без REVERSE).
* cb — вызывается при каждом изменении статуса / таймауте.
* Если conn уже готов — cb(h, NCD_EVENT_UP) через uasync_call_soon (не синхронно).
*
* Возвращает NCD_NEW / NCD_REUSED / NCD_ERR.
*/
int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id, uint64_t group_id,
int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id,
ncd_callback cb, void* cb_arg,
struct NODE_CONN_DIRECT** out_handle);
/*
* Обернуть уже существующий ETCP_CONN в handle (crypto+links уже готовы).
* Не создаёт линки, не делает crypto, не ставит connect_timer.
* Возвращает NCD_REUSED / NCD_ERR.
*/
int node_conn_direct_adopt(struct UTUN_INSTANCE* inst, struct ETCP_CONN* conn,
ncd_callback cb, void* cb_arg,
struct NODE_CONN_DIRECT** out_handle);
int node_conn_direct_open_node(struct UTUN_INSTANCE* inst, uint64_t node_id,
ncd_callback cb, void* cb_arg,
struct NODE_CONN_DIRECT** out_handle,
struct TOPO_NODE* ni);
void node_conn_direct_close(struct NODE_CONN_DIRECT* h);