|
|
|
@ -1,18 +1,15 @@ |
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* node_conn_direct.c — handle-based ETCP connection layer |
|
|
|
* node_conn_direct.c — handle-based ETCP connection layer |
|
|
|
* |
|
|
|
* |
|
|
|
* Тонкая прослойка над ETCP: управляет подключениями по node_id. |
|
|
|
* Тонкая прослойка над ETCP: управляет прямыми подключениями по node_id. |
|
|
|
* Несколько handle'ов могут разделять одно ETCP_CONN. |
|
|
|
* Несколько handle'ов могут разделять одно ETCP_CONN. |
|
|
|
* Conn закрывается при закрытии последнего handle (с протоколом CLOSE/KEEP_ALIVE). |
|
|
|
* Conn закрывается при закрытии последнего handle (с протоколом CLOSE/KEEP_ALIVE). |
|
|
|
* Поддерживает REVERSE-подключение через etcp_router если задан group_id. |
|
|
|
|
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
#include "node_conn_direct.h" |
|
|
|
#include "node_conn_direct.h" |
|
|
|
#include "etcp_api.h" |
|
|
|
#include "etcp_api.h" |
|
|
|
#include "etcp.h" |
|
|
|
#include "etcp.h" |
|
|
|
#include "etcp_connections.h" |
|
|
|
#include "etcp_connections.h" |
|
|
|
#include "etcp_router.h" |
|
|
|
|
|
|
|
#include "conn_mgr.h" |
|
|
|
|
|
|
|
#include "secure_channel.h" |
|
|
|
#include "secure_channel.h" |
|
|
|
#include "utun_instance.h" |
|
|
|
#include "utun_instance.h" |
|
|
|
#include "topo_node.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 */ |
|
|
|
#define NCD_FIN_WAIT_TIMEOUT_TB 50000 /* 5 сек в 0.1ms */ |
|
|
|
|
|
|
|
|
|
|
|
/* ═══════════ внутренние структуры ═══════════ */ |
|
|
|
/* ═══════════ внутренние структуры ═══════════ */ |
|
|
|
|
|
|
|
|
|
|
|
struct ncd_entry { |
|
|
|
struct ncd_entry { |
|
|
|
uint64_t node_id; |
|
|
|
uint64_t node_id; |
|
|
|
uint64_t group_id; /* для REVERSE (0 = без REVERSE) */ |
|
|
|
|
|
|
|
struct ETCP_CONN* conn; |
|
|
|
struct ETCP_CONN* conn; |
|
|
|
struct UASYNC* ua; |
|
|
|
struct UASYNC* ua; |
|
|
|
int handle_count; |
|
|
|
int handle_count; |
|
|
|
@ -51,7 +42,6 @@ struct ncd_entry { |
|
|
|
|
|
|
|
|
|
|
|
void* connect_timer; /* однократный таймер первого подъёма */ |
|
|
|
void* connect_timer; /* однократный таймер первого подъёма */ |
|
|
|
void* fin_wait_timer; /* таймер ожидания ответа на CLOSE */ |
|
|
|
void* fin_wait_timer; /* таймер ожидания ответа на CLOSE */ |
|
|
|
void* reverse_poll_timer; /* таймер polling входящего conn при REVERSE */ |
|
|
|
|
|
|
|
uint8_t up : 1; /* текущий статус: 1=есть живой линк */ |
|
|
|
uint8_t up : 1; /* текущий статус: 1=есть живой линк */ |
|
|
|
uint8_t timed_out : 1; /* connect_timer уже сработал */ |
|
|
|
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; |
|
|
|
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) { |
|
|
|
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: |
|
|
|
case NCD_EVENT_UP: |
|
|
|
if (entry->up) return; |
|
|
|
if (entry->up) return; |
|
|
|
if (entry->connect_timer) { uasync_cancel_timeout(entry->ua, entry->connect_timer); entry->connect_timer = NULL; } |
|
|
|
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; |
|
|
|
entry->up = 1; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case NCD_EVENT_DOWN: |
|
|
|
case NCD_EVENT_DOWN: |
|
|
|
@ -316,16 +212,6 @@ static void ncd_connect_timeout_cb(void* arg) { |
|
|
|
entry->connect_timer = NULL; |
|
|
|
entry->connect_timer = NULL; |
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_NCD, "[ncd] connect timeout node=0x%016llx handles=%d", |
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_NCD, "[ncd] connect timeout node=0x%016llx handles=%d", |
|
|
|
(unsigned long long)entry->node_id, entry->handle_count); |
|
|
|
(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); |
|
|
|
ncd_event_dispatch(entry, NCD_EVENT_TIMEOUT); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -415,7 +301,7 @@ static void ncd_init_control_binding(struct UTUN_INSTANCE* inst) { |
|
|
|
|
|
|
|
|
|
|
|
/* ═══════════ API ═══════════ */ |
|
|
|
/* ═══════════ 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, |
|
|
|
ncd_callback cb, void* cb_arg, |
|
|
|
struct NODE_CONN_DIRECT** out_handle) { |
|
|
|
struct NODE_CONN_DIRECT** out_handle) { |
|
|
|
if (!inst || !out_handle) return NCD_ERR; |
|
|
|
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) */ |
|
|
|
/* 2. Ищем conn через instance_find_conn (входящее / созданное etcp_connect) */ |
|
|
|
struct ETCP_CONN* conn = instance_find_conn(inst, node_id); |
|
|
|
struct ETCP_CONN* conn = instance_find_conn(inst, node_id); |
|
|
|
if (conn) { |
|
|
|
if (conn && conn->state == 1) { |
|
|
|
/* снять fin_wait если был */ |
|
|
|
/* снять fin_wait если был */ |
|
|
|
if (conn->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); |
|
|
|
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)); |
|
|
|
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; } |
|
|
|
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); |
|
|
|
entry->up = (uint8_t)(conn->links_up ? 1 : 0); |
|
|
|
ncd_registry_add(entry); |
|
|
|
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); |
|
|
|
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; |
|
|
|
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); |
|
|
|
ncd_registry_add(entry); |
|
|
|
|
|
|
|
|
|
|
|
struct NODE_CONN_DIRECT* h = u_calloc(1, sizeof(*h)); |
|
|
|
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); |
|
|
|
int link_count = ncd_create_links(entry, ni); |
|
|
|
|
|
|
|
|
|
|
|
if (link_count == 0 && group_id != 0) { |
|
|
|
if (link_count == 0) |
|
|
|
struct TOPO_GROUP* grp = topo_groups_find(inst->topo_groups, group_id); |
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_NCD, "[ncd] no links created for node=0x%016llx", (unsigned long long)node_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); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
entry->connect_timer = uasync_set_timeout(inst->ua, (int)inst->etcp_connect_timeout_tb, entry, ncd_connect_timeout_cb, "ncd_connect"); |
|
|
|
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", |
|
|
|
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; |
|
|
|
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) { |
|
|
|
void node_conn_direct_close(struct NODE_CONN_DIRECT* h) { |
|
|
|
if (!h) return; |
|
|
|
if (!h) return; |
|
|
|
struct ncd_entry* entry = h->entry; |
|
|
|
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->handle_count <= 0) { |
|
|
|
if (entry->connect_timer) { uasync_cancel_timeout(entry->ua, entry->connect_timer); entry->connect_timer = NULL; } |
|
|
|
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) { |
|
|
|
if (conn && conn->state != 2) { |
|
|
|
/* устанавливаем fin_wait, отправляем CLOSE, ставим таймер */ |
|
|
|
/* устанавливаем fin_wait, отправляем CLOSE, ставим таймер */ |
|
|
|
conn->fin_wait = 1; |
|
|
|
conn->fin_wait = 1; |
|
|
|
@ -607,63 +609,6 @@ void node_conn_direct_close(struct NODE_CONN_DIRECT* h) { |
|
|
|
u_free(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) { |
|
|
|
struct ETCP_CONN* node_conn_direct_get_conn(struct NODE_CONN_DIRECT* h) { |
|
|
|
if (!h || !h->entry) return NULL; |
|
|
|
if (!h || !h->entry) return NULL; |
|
|
|
return h->entry->conn; |
|
|
|
return h->entry->conn; |
|
|
|
|