fix: memory pool alloc mismatch in tests, db_sync SEND_DATA buffer overflow
- test_etcp_router_reconnect, test_etcp_connect, test_stcp_traffic: replace u_calloc with memory_pool_alloc for TOPO_SOCKMETA4/TOPO_ADDR4 - db_sync.c: fix req[14] -> req[15] — SEND_DATA request header is 15 bytes (type:1 + from:4 + count:2 + vp:4 + want_from:4)
This commit is contained in:
1 parent
fe9be74e29
commit
d310bccf08
52 files changed
+1796
-585
No files matched your search
@@ -41,6 +41,7 @@ utun_CORE_SOURCES = \
|
||||
transport_layer/packet_dump.c \
|
||||
transport_layer/etcp_api.c \
|
||||
transport_layer/etcp_connect.c \
|
||||
transport_layer/node_conn_direct.c \
|
||||
control_server.c \
|
||||
firewall.c \
|
||||
eim_nat.c \
|
||||
@@ -112,6 +113,7 @@ libutun_a_SOURCES = \
|
||||
transport_layer/packet_dump.c \
|
||||
transport_layer/etcp_api.c \
|
||||
transport_layer/etcp_connect.c \
|
||||
transport_layer/node_conn_direct.c \
|
||||
control_server.c \
|
||||
firewall.c \
|
||||
eim_nat.c \
|
||||
|
||||
@@ -415,7 +415,7 @@ static void cs_start_channel_join(struct chat_sync* cs, uint64_t peer) {
|
||||
|
||||
/* ── Connection callbacks ── */
|
||||
|
||||
static void cs_on_conn_up(struct ETCP_CONN* conn, void* arg) {
|
||||
static void cs_on_conn_up(struct ETCP_CONN* conn, int event, void* arg) { (void)event;
|
||||
(void)arg;
|
||||
if (!conn || !g_cs) return;
|
||||
uint64_t peer = conn->peer_node_id;
|
||||
@@ -438,7 +438,7 @@ static void cs_on_conn_up(struct ETCP_CONN* conn, void* arg) {
|
||||
cs_on_peer_status_changed(peer, 1);
|
||||
}
|
||||
|
||||
static void cs_on_conn_down(struct ETCP_CONN* conn, void* arg) {
|
||||
static void cs_on_conn_down(struct ETCP_CONN* conn, int event, void* arg) { (void)event;
|
||||
(void)arg;
|
||||
if (!conn || !g_cs) return;
|
||||
uint64_t peer = conn->peer_node_id;
|
||||
@@ -467,8 +467,8 @@ static void cs_on_conn_down(struct ETCP_CONN* conn, void* arg) {
|
||||
|
||||
static void cs_on_conn_status(struct ETCP_CONN* conn, int status, void* arg) {
|
||||
switch (status) {
|
||||
case ETCP_CONN_STATUS_UP: cs_on_conn_up(conn, arg); break;
|
||||
case ETCP_CONN_STATUS_DOWN: cs_on_conn_down(conn, arg); break;
|
||||
case ETCP_CONN_STATUS_UP: cs_on_conn_up(conn, ETCP_CBK_EVENT_UP, arg); break;
|
||||
case ETCP_CONN_STATUS_DOWN: cs_on_conn_down(conn, ETCP_CBK_EVENT_DOWN, arg); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@@ -478,8 +478,8 @@ static void cs_on_new_conn(struct ETCP_CONN* conn, void* arg) {
|
||||
(void)arg;
|
||||
if (!conn) return;
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: new_conn conn=%p", CS_ID, (void*)conn);
|
||||
etcp_conn_add_up_cbk(conn, cs_on_conn_up, NULL);
|
||||
etcp_conn_add_down_cbk(conn, cs_on_conn_down, NULL);
|
||||
etcp_conn_add_cbk(conn, cs_on_conn_up, NULL, ETCP_CBK_EVENT_UP);
|
||||
etcp_conn_add_cbk(conn, cs_on_conn_down, NULL, ETCP_CBK_EVENT_DOWN);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+2
-2
@@ -1089,10 +1089,10 @@ static void db_handle_sync_done(struct DB_SYNC_INSTANCE* si, uint64_t src, const
|
||||
} else if (mc < pc) {
|
||||
// Request tail
|
||||
uint32_t vp_send = mc > 0 ? mc - 1 : (uint32_t)-1;
|
||||
uint8_t req[14]; req[0] = DB_MSG_SEND_DATA;
|
||||
uint8_t req[15]; req[0] = DB_MSG_SEND_DATA;
|
||||
memcpy(req + 1, &mc, 4); uint16_t z = 0; memcpy(req + 5, &z, 2);
|
||||
memcpy(req + 7, &vp_send, 4); memcpy(req + 11, &mc, 4);
|
||||
db_sync_send(si, src, req, 14);
|
||||
db_sync_send(si, src, req, 15);
|
||||
if (sp) sp->sync_state = 1;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← SYNC_DONE: mc=%u < pc=%u → request tail from=%u",
|
||||
SI_SHRT(si), (unsigned long long)(src >> 16), mc, pc, mc);
|
||||
|
||||
@@ -101,7 +101,7 @@ static void send_debug_config(struct control_server* server, struct control_clie
|
||||
static void send_error(struct control_client* client, uint8_t error_code, const char* msg, uint8_t seq_id);
|
||||
|
||||
static void control_server_send_node_list(struct control_server* server, struct control_client* client, uint8_t seq_id);
|
||||
static void send_single_node_info(struct control_server* server, struct control_client* client, struct TOPO_NODEQ* nq);
|
||||
static void send_single_node_info(struct control_server* server, struct control_client* client, struct TOPO_GROUP_NODE* nq);
|
||||
static int control_client_send(struct control_server* server, struct control_client* client, uint8_t* dgram, uint16_t len);
|
||||
|
||||
static struct ETCP_CONN* find_connection_by_peer_id(struct UTUN_INSTANCE* instance, uint64_t peer_id);
|
||||
@@ -1385,10 +1385,12 @@ static struct ETCP_CONN* find_connection_by_peer_id(struct UTUN_INSTANCE* instan
|
||||
* Node Info Helpers (send_single_node_info, send_node_list, notify_change)
|
||||
* ============================================================================ */
|
||||
|
||||
static void send_single_node_info(struct control_server* server, struct control_client* client, struct TOPO_NODEQ* nq) {
|
||||
if (!server || !nq || !nq->node) return;
|
||||
static void send_single_node_info(struct control_server* server, struct control_client* client, struct TOPO_GROUP_NODE* nq) {
|
||||
if (!server || !nq) return;
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(server->instance->topo_groups, nq->node_id);
|
||||
if (!ni) return;
|
||||
uint8_t buf[8192];
|
||||
int ser_len = topo_node_serialize(topo_groups_get_default(server->instance->topo_groups), nq, buf + 2, sizeof(buf) - 2, 0);
|
||||
int ser_len = topo_node_serialize(ni, nq, buf + 2, sizeof(buf) - 2, 0);
|
||||
if (ser_len < 0) { DEBUG_ERROR(DEBUG_CATEGORY_CONTROL, "Failed to serialize node info"); return; }
|
||||
buf[0] = CTRL_BGP_CMD; buf[1] = CTRL_BGP_SUBCMD;
|
||||
size_t data_size = 2 + (size_t)ser_len;
|
||||
@@ -1414,7 +1416,7 @@ static void control_server_send_node_list(struct control_server* server, struct
|
||||
/* Send all known remote nodes */
|
||||
struct ll_entry* e = group->nodes ? group->nodes->head : NULL;
|
||||
while (e) {
|
||||
struct TOPO_NODEQ* nq = (struct TOPO_NODEQ*)e;
|
||||
struct TOPO_GROUP_NODE* nq = (struct TOPO_GROUP_NODE*)e;
|
||||
send_single_node_info(server, client, nq);
|
||||
e = e->next;
|
||||
}
|
||||
@@ -1429,7 +1431,7 @@ static void control_server_send_node_list(struct control_server* server, struct
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONTROL, "Sent node list to client (seq=%d)", seq_id);
|
||||
}
|
||||
|
||||
void control_server_notify_node_change(struct control_server* server, struct TOPO_NODEQ* node) {
|
||||
void control_server_notify_node_change(struct control_server* server, struct TOPO_GROUP_NODE* node) {
|
||||
if (!server || !node) return;
|
||||
struct control_client* client = server->clients;
|
||||
while (client) {
|
||||
|
||||
@@ -19,7 +19,7 @@ extern "C" {
|
||||
/* Forward declarations */
|
||||
struct UTUN_INSTANCE;
|
||||
struct UASYNC;
|
||||
struct TOPO_NODEQ;
|
||||
struct TOPO_GROUP_NODE;
|
||||
struct ll_queue;
|
||||
|
||||
/* Forward declaration */
|
||||
@@ -117,7 +117,7 @@ void control_server_process_updates(struct control_server* server);
|
||||
*/
|
||||
uint32_t control_server_get_client_count(const struct control_server* server);
|
||||
|
||||
void control_server_notify_node_change(struct control_server* server, struct TOPO_NODEQ* node);
|
||||
void control_server_notify_node_change(struct control_server* server, struct TOPO_GROUP_NODE* node);
|
||||
void control_server_notify_node_removed(struct control_server* server, uint64_t node_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -802,8 +802,9 @@ static void md_on_bgp_node(struct TOPO_GROUP* group, uint64_t node_id, int event
|
||||
}
|
||||
|
||||
/* check if this node is a supernode */
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(group, node_id);
|
||||
if (!nq || !nq->node) return;
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(group, node_id);
|
||||
struct TOPO_NODE* ni = nq ? topo_node_registry_find(group->instance->topo_groups, nq->node_id) : NULL;
|
||||
if (!nq || !ni) return;
|
||||
|
||||
/* for CHAT groups, check node_type via DB */
|
||||
if (group->group_type == TOPO_GROUP_TYPE_CHAT && group->channel_id[0]) {
|
||||
|
||||
+3
-3
@@ -23,7 +23,7 @@ _Static_assert(sizeof(struct time_sync_msg) == 9, "time_sync_msg size mismatch")
|
||||
|
||||
#define TIME_SYNC_PKT_SIZE (1 + sizeof(struct time_sync_msg)) // cmd(1) + msg(9) = 10
|
||||
|
||||
static void ntp_node_on_conn_init(struct ETCP_CONN* conn, void* arg);
|
||||
static void ntp_node_on_conn_init(struct ETCP_CONN* conn, int event, void* arg);
|
||||
static void ntp_node_on_new_conn(struct ETCP_CONN* conn, void* arg);
|
||||
static void ntp_node_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry);
|
||||
|
||||
@@ -103,7 +103,7 @@ static void check_drift(uint64_t node_id, int64_t offset_delta_us) {
|
||||
}
|
||||
}
|
||||
|
||||
static void ntp_node_on_conn_init(struct ETCP_CONN* conn, void* arg) {
|
||||
static void ntp_node_on_conn_init(struct ETCP_CONN* conn, int event, void* arg) { (void)event;
|
||||
struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)arg;
|
||||
if (!inst || !conn) return;
|
||||
|
||||
@@ -117,7 +117,7 @@ static void ntp_node_on_new_conn(struct ETCP_CONN* conn, void* arg) {
|
||||
if (!conn) return;
|
||||
struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)arg;
|
||||
if (!inst) return;
|
||||
etcp_conn_add_init_cbk(conn, ntp_node_on_conn_init, inst);
|
||||
etcp_conn_add_cbk(conn, ntp_node_on_conn_init, inst, ETCP_CBK_EVENT_INIT);
|
||||
}
|
||||
|
||||
static void ntp_node_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
|
||||
|
||||
+187
-149
@@ -24,6 +24,7 @@
|
||||
#include "route_ping.h"
|
||||
#include "route_connectivity.h"
|
||||
#include "conn_mgr.h"
|
||||
#include "../transport_layer/node_conn_direct.h"
|
||||
|
||||
static struct CONN_MGR_ENTRY* cm_find_entry(struct CONN_MGR* mgr, uint64_t node_id);
|
||||
static void cm_start_phase_direct(struct CONN_MGR_ENTRY* entry);
|
||||
@@ -34,28 +35,40 @@ static void cm_idle_timer_cb(void* arg);
|
||||
static void cm_deliver_result(struct CONN_MGR_ENTRY* entry, int result);
|
||||
static void cm_bg_ping_timer_cb(void* arg);
|
||||
static int cm_nat_compatible(struct ETCP_SOCKET* our, uint8_t target_config_type, uint8_t target_nat_type);
|
||||
static uint16_t cm_get_node_min_rtt(struct TOPO_NODEQ* nq);
|
||||
static int cm_has_direct_ip(struct TOPO_NODEQ* nq);
|
||||
static int cm_has_local_addr(struct TOPO_NODEQ* nq);
|
||||
static uint16_t cm_get_node_min_rtt(struct TOPO_GROUP_NODE* nq);
|
||||
static int cm_has_direct_ip(struct CONN_MGR* mgr, struct TOPO_GROUP_NODE* nq);
|
||||
static int cm_has_local_addr(struct CONN_MGR* mgr, struct TOPO_GROUP_NODE* nq);
|
||||
static void cm_entry_destroy(struct CONN_MGR_ENTRY* entry);
|
||||
static void cm_exchange_probe_retry_cb(void* arg);
|
||||
static uint64_t cm_get_node_max_probe_time(struct TOPO_NODEQ* nq);
|
||||
static int cm_is_rtt_fresh(struct TOPO_NODEQ* nq, uint64_t now_tb);
|
||||
static uint64_t cm_get_node_max_probe_time(struct TOPO_GROUP_NODE* nq);
|
||||
static int cm_is_rtt_fresh(struct TOPO_GROUP_NODE* nq, uint64_t now_tb);
|
||||
static void cm_clear_nodeinfo(struct CONN_MGR* mgr, uint64_t node_id);
|
||||
|
||||
static struct CONN_MGR_HANDLE* cm_handle_new(struct CONN_MGR_ENTRY* entry,
|
||||
conn_mgr_connect_callback_t cb, void* cb_arg) {
|
||||
struct CONN_MGR_HANDLE* h = u_calloc(1, sizeof(*h));
|
||||
if (!h) return NULL;
|
||||
h->target_node_id = entry->node_id;
|
||||
h->conn_type = CONN_TYPE_NONE;
|
||||
h->result_cb = cb; h->result_arg = cb_arg;
|
||||
h->entry = entry;
|
||||
h->next = entry->handles; entry->handles = h;
|
||||
return h;
|
||||
}
|
||||
|
||||
static void conn_mgr_router_recv_handler(struct ETCP_CONN* conn, struct ll_entry* entry);
|
||||
static void cm_handle_direct_req(struct ETCP_CONN* conn, const uint8_t* data, size_t len);
|
||||
static void cm_handle_interm_exchange_req(struct ETCP_CONN* conn, struct CONN_MGR_INTERM_EXCHANGE_REQ* req);
|
||||
static void cm_handle_interm_exchange_resp(struct CONN_MGR* mgr, const uint8_t* data, size_t len);
|
||||
static void cm_handle_interm_selected(struct CONN_MGR* mgr, const uint8_t* data, size_t len);
|
||||
static void cm_handle_disconnect(struct CONN_MGR* mgr, uint64_t node_id);
|
||||
static void cm_direct_init_cb(struct ETCP_CONN* conn, void* arg);
|
||||
static void cm_reverse_init_cb(struct ETCP_CONN* conn, void* arg);
|
||||
static void cm_direct_init_cb(struct ETCP_CONN* conn, int event, void* arg);
|
||||
static void cm_reverse_init_cb(struct ETCP_CONN* conn, int event, void* arg);
|
||||
static void cm_reverse_timeout_cb(void* arg);
|
||||
static void cm_exchange_timeout_cb(void* arg);
|
||||
static void cm_candidate_ping_timer_cb(void* arg);
|
||||
|
||||
static void cm_invite_init_cb(struct ETCP_CONN* conn, void* arg);
|
||||
static void cm_invite_init_cb(struct ETCP_CONN* conn, int event, void* arg);
|
||||
static void cm_invite_overall_timeout(void* arg);
|
||||
static void cm_invite_fail(struct cm_invite_pending* inv, int result);
|
||||
static void cm_invite_cleanup(struct cm_invite_pending* inv);
|
||||
@@ -101,7 +114,7 @@ struct cm_invite_pending {
|
||||
void* overall_timer;
|
||||
conn_mgr_connect_callback_t cb;
|
||||
void* cb_arg;
|
||||
struct TOPO_NODEQ* temp_nq;
|
||||
struct TOPO_GROUP_NODE* temp_nq;
|
||||
};
|
||||
|
||||
struct CONN_MGR* conn_mgr_init(struct TOPO_GROUP* group) {
|
||||
@@ -191,23 +204,23 @@ static struct CONN_MGR_ENTRY* cm_find_entry(struct CONN_MGR* mgr, uint64_t node_
|
||||
}
|
||||
|
||||
static void cm_deliver_result(struct CONN_MGR_ENTRY* entry, int result) {
|
||||
struct cm_cb_node* node = entry->cb_list;
|
||||
entry->cb_list = NULL;
|
||||
int delivered = 0;
|
||||
while (node) {
|
||||
struct cm_cb_node* next = node->next;
|
||||
if (!node->cancelled) { node->cb(result, entry->node_id, node->arg); delivered++; }
|
||||
u_free(node);
|
||||
node = next;
|
||||
struct CONN_MGR_HANDLE* h = entry->handles;
|
||||
entry->handles = NULL;
|
||||
while (h) {
|
||||
struct CONN_MGR_HANDLE* next = h->next;
|
||||
if (h->result_cb) h->result_cb(result, entry->node_id, h->result_arg);
|
||||
h->nd_handle = NULL; h->entry = NULL;
|
||||
u_free(h);
|
||||
h = next;
|
||||
}
|
||||
if (delivered == 0 && entry->state == CONN_MGR_STATE_CONNECTING)
|
||||
if (entry->state == CONN_MGR_STATE_CONNECTING)
|
||||
cm_clear_nodeinfo(entry->mgr, entry->node_id);
|
||||
}
|
||||
|
||||
static void cm_update_nodeinfo(struct CONN_MGR_ENTRY* entry) {
|
||||
struct TOPO_GROUP* group = entry->mgr->group;
|
||||
if (!group) return;
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(group, entry->node_id);
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(group, entry->node_id);
|
||||
if (!nq) return;
|
||||
nq->conn_mgr_type = entry->conn_type;
|
||||
memcpy(nq->conn_mgr_intermediaries, entry->intermediaries, sizeof(entry->intermediaries));
|
||||
@@ -215,7 +228,7 @@ static void cm_update_nodeinfo(struct CONN_MGR_ENTRY* entry) {
|
||||
}
|
||||
|
||||
static void cm_clear_nodeinfo(struct CONN_MGR* mgr, uint64_t node_id) {
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(mgr->group, node_id);
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(mgr->group, node_id);
|
||||
if (!nq) return;
|
||||
nq->conn_mgr_type = CONN_TYPE_NONE;
|
||||
nq->conn_mgr_intermediariy_count = 0;
|
||||
@@ -224,7 +237,7 @@ static void cm_clear_nodeinfo(struct CONN_MGR* mgr, uint64_t node_id) {
|
||||
static void cm_cleanup_db_node(struct CONN_MGR_ENTRY* entry) {
|
||||
if (!entry->db_loaded) return;
|
||||
struct TOPO_GROUP* group = entry->mgr->group;
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(group, entry->node_id);
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(group, entry->node_id);
|
||||
if (!nq) return;
|
||||
if (nq->paths && queue_entry_count(nq->paths) > 0) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: db_node 0x%016llx got paths, keep in group", (unsigned long long)entry->node_id);
|
||||
@@ -232,48 +245,44 @@ static void cm_cleanup_db_node(struct CONN_MGR_ENTRY* entry) {
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: removing db_node 0x%016llx from group (no paths)", (unsigned long long)entry->node_id);
|
||||
queue_remove_data(group->nodes, &nq->ll);
|
||||
topo_node_free_lists(group, nq);
|
||||
topo_nodeq_free_group_fields(entry->mgr->instance->topo_groups, nq);
|
||||
queue_entry_free(&nq->ll);
|
||||
}
|
||||
|
||||
int conn_mgr_connect_node(struct CONN_MGR* mgr, uint64_t node_id, uint32_t idle_timeout_ms,
|
||||
struct CONN_MGR_HANDLE* conn_mgr_connect_node(struct CONN_MGR* mgr, uint64_t node_id, uint32_t idle_timeout_ms,
|
||||
conn_mgr_connect_callback_t cb, void* cb_arg) {
|
||||
if (!mgr) return CONN_MGR_ERR_INTERNAL;
|
||||
if (!mgr) { if (cb) cb(CONN_MGR_ERR_INTERNAL, node_id, cb_arg); return NULL; }
|
||||
struct TOPO_GROUP* group = mgr->group;
|
||||
if (!group) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "BGP not initialized"); return CONN_MGR_ERR_INTERNAL; }
|
||||
struct TOPO_NODEQ* target = topo_node_find_by_id(group, node_id);
|
||||
if (!group) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "BGP not initialized"); if (cb) cb(CONN_MGR_ERR_INTERNAL, node_id, cb_arg); return NULL; }
|
||||
struct TOPO_GROUP_NODE* target = topo_node_find_by_id(group, node_id);
|
||||
int loaded_from_db = 0;
|
||||
if (!target && mgr->instance->topo_sqlite_db && mgr->instance->topo_groups) {
|
||||
struct TOPO_NODE* ni = topo_node_sqlite_node_load(mgr->instance->topo_sqlite_db, mgr->instance->topo_groups, node_id);
|
||||
if (ni) {
|
||||
ni = topo_node_registry_acquire(mgr->instance->topo_groups, ni);
|
||||
struct ll_entry* qe = queue_entry_new(sizeof(struct TOPO_NODEQ));
|
||||
ni = topo_node_registry_store(mgr->instance->topo_groups, ni);
|
||||
struct ll_entry* qe = queue_entry_new(sizeof(struct TOPO_GROUP_NODE));
|
||||
if (qe) {
|
||||
target = (struct TOPO_NODEQ*)qe;
|
||||
target = (struct TOPO_GROUP_NODE*)qe;
|
||||
memset((uint8_t*)target + sizeof(struct ll_entry), 0, sizeof(*target) - sizeof(struct ll_entry));
|
||||
target->node = ni; target->hash_node_id = node_id;
|
||||
target->node_id = node_id;
|
||||
target->conn_mgr_type = CONN_TYPE_NONE;
|
||||
queue_data_put_with_index(group->nodes, &target->ll);
|
||||
loaded_from_db = 1;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: node 0x%016llx loaded from DB", (unsigned long long)node_id);
|
||||
} else { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "conn_mgr: failed to alloc TOPO_NODEQ for DB node 0x%016llx", (unsigned long long)node_id); }
|
||||
} else { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "conn_mgr: failed to alloc TOPO_GROUP_NODE for DB node 0x%016llx", (unsigned long long)node_id); }
|
||||
}
|
||||
}
|
||||
if (!target) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "node 0x%016llx not found", (unsigned long long)node_id); return CONN_MGR_ERR_NOT_FOUND; }
|
||||
if (!target) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "node 0x%016llx not found", (unsigned long long)node_id); return NULL; }
|
||||
struct CONN_MGR_ENTRY* entry = cm_find_entry(mgr, node_id);
|
||||
struct CONN_MGR_HANDLE* h = NULL;
|
||||
if (entry && entry->state == CONN_MGR_STATE_CONNECTED) {
|
||||
if (cb) {
|
||||
struct cm_cb_node* cn = u_calloc(1, sizeof(struct cm_cb_node));
|
||||
if (cn) { cn->cb = cb; cn->arg = cb_arg; entry->cb_list = cn; }
|
||||
cb(CONN_MGR_OK, node_id, cb_arg);
|
||||
}
|
||||
return CONN_MGR_OK;
|
||||
h = cm_handle_new(entry, cb, cb_arg);
|
||||
if (cb) cb(CONN_MGR_OK, node_id, cb_arg);
|
||||
return h;
|
||||
}
|
||||
if (entry && entry->state == CONN_MGR_STATE_CONNECTING) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "node 0x%016llx already connecting, adding cb", (unsigned long long)node_id);
|
||||
struct cm_cb_node* cn = u_calloc(1, sizeof(struct cm_cb_node));
|
||||
if (cn) { cn->cb = cb; cn->arg = cb_arg; cn->next = entry->cb_list; entry->cb_list = cn; }
|
||||
return CONN_MGR_OK;
|
||||
DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "node 0x%016llx already connecting, adding handle", (unsigned long long)node_id);
|
||||
return cm_handle_new(entry, cb, cb_arg);
|
||||
}
|
||||
struct ETCP_CONN* existing = topo_group_find_conn_for_node(group, node_id);
|
||||
if (!existing) existing = instance_find_conn(mgr->instance, node_id);
|
||||
@@ -282,23 +291,21 @@ int conn_mgr_connect_node(struct CONN_MGR* mgr, uint64_t node_id, uint32_t idle_
|
||||
while (l) { if (l->link_state == 3 && l->initialized) break; l = l->next; }
|
||||
if (l) {
|
||||
entry = cm_ensure_entry(mgr, node_id);
|
||||
if (!entry) return CONN_MGR_ERR_INTERNAL;
|
||||
if (!entry) { if (cb) cb(CONN_MGR_ERR_INTERNAL, node_id, cb_arg); return NULL; }
|
||||
entry->state = CONN_MGR_STATE_CONNECTED;
|
||||
entry->conn_type = CONN_TYPE_DIRECT;
|
||||
entry->idle_timeout_ms = idle_timeout_ms;
|
||||
entry->last_traffic_tb = get_time_tb();
|
||||
{ struct cm_cb_node* cn = u_calloc(1, sizeof(struct cm_cb_node));
|
||||
if (cn) { cn->cb = cb; cn->arg = cb_arg; entry->cb_list = cn; } }
|
||||
cm_update_nodeinfo(entry);
|
||||
h = cm_handle_new(entry, cb, cb_arg);
|
||||
cm_update_nodeinfo(entry);
|
||||
cm_deliver_result(entry, CONN_MGR_OK);
|
||||
return CONN_MGR_OK;
|
||||
return h;
|
||||
}
|
||||
}
|
||||
entry = cm_ensure_entry(mgr, node_id);
|
||||
if (!entry) return CONN_MGR_ERR_INTERNAL;
|
||||
if (!entry) { if (cb) cb(CONN_MGR_ERR_INTERNAL, node_id, cb_arg); return NULL; }
|
||||
entry->state = CONN_MGR_STATE_CONNECTING;
|
||||
{ struct cm_cb_node* cn = u_calloc(1, sizeof(struct cm_cb_node));
|
||||
if (cn) { cn->cb = cb; cn->arg = cb_arg; cn->next = entry->cb_list; entry->cb_list = cn; } }
|
||||
h = cm_handle_new(entry, cb, cb_arg);
|
||||
entry->idle_timeout_ms = idle_timeout_ms;
|
||||
entry->last_traffic_tb = get_time_tb();
|
||||
entry->local_scan_state = CM_TRY_NONE;
|
||||
@@ -307,12 +314,12 @@ int conn_mgr_connect_node(struct CONN_MGR* mgr, uint64_t node_id, uint32_t idle_
|
||||
entry->main.timer = NULL;
|
||||
entry->main.request_id = 0;
|
||||
entry->db_loaded = (uint8_t)loaded_from_db;
|
||||
int has_our_local = cm_has_local_addr(group->local_node);
|
||||
int has_target_local = cm_has_local_addr(target);
|
||||
int has_our_local = cm_has_local_addr(mgr, group->local_node);
|
||||
int has_target_local = cm_has_local_addr(mgr, target);
|
||||
if (has_our_local && has_target_local) { entry->local_scan_state = CM_TRY_PENDING; cm_start_local_scan(entry); }
|
||||
entry->main_connect_state = CM_TRY_PENDING;
|
||||
cm_start_phase_direct(entry);
|
||||
return CONN_MGR_OK;
|
||||
return h;
|
||||
}
|
||||
|
||||
int conn_mgr_disconnect_node(struct CONN_MGR* mgr, uint64_t node_id) {
|
||||
@@ -334,32 +341,46 @@ int conn_mgr_disconnect_node(struct CONN_MGR* mgr, uint64_t node_id) {
|
||||
}
|
||||
|
||||
int conn_mgr_cancel_callback(struct CONN_MGR* mgr, uint64_t node_id,
|
||||
conn_mgr_connect_callback_t cb, void* cb_arg) {
|
||||
struct CONN_MGR_HANDLE* h) {
|
||||
if (!mgr) return CONN_MGR_ERR_INTERNAL;
|
||||
struct CONN_MGR_ENTRY* entry = cm_find_entry(mgr, node_id);
|
||||
if (!entry) return CONN_MGR_ERR_NOT_FOUND;
|
||||
|
||||
int cb_count = 0;
|
||||
struct cm_cb_node* target = NULL;
|
||||
for (struct cm_cb_node* n = entry->cb_list; n; n = n->next) {
|
||||
cb_count++;
|
||||
if (n->cb == cb && n->arg == cb_arg) target = n;
|
||||
}
|
||||
if (!target) return CONN_MGR_ERR_NOT_FOUND;
|
||||
for (struct CONN_MGR_HANDLE* n = entry->handles; n; n = n->next) cb_count++;
|
||||
if (cb_count == 0) return CONN_MGR_ERR_NOT_FOUND;
|
||||
|
||||
if (cb_count == 1) {
|
||||
if (h) {
|
||||
struct CONN_MGR_HANDLE** pp = &entry->handles;
|
||||
while (*pp) { if (*pp == h) { *pp = h->next; break; } pp = &(*pp)->next; }
|
||||
h->nd_handle = NULL; h->entry = NULL; u_free(h);
|
||||
cb_count--;
|
||||
}
|
||||
|
||||
if (cb_count <= 1 || !h) {
|
||||
cm_entry_destroy(entry);
|
||||
u_free(target);
|
||||
entry->cb_list = NULL;
|
||||
cm_clear_nodeinfo(mgr, node_id);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: cancel connect to 0x%016llx (single cb)", (unsigned long long)node_id);
|
||||
} else {
|
||||
target->cancelled = 1;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: cancel cb for 0x%016llx (cbs=%d)", (unsigned long long)node_id, cb_count);
|
||||
struct CONN_MGR_HANDLE* rem = h ? entry->handles : NULL;
|
||||
while (rem) { struct CONN_MGR_HANDLE* nx = rem->next; rem->nd_handle = NULL; u_free(rem); rem = nx; }
|
||||
entry->handles = NULL;
|
||||
}
|
||||
return CONN_MGR_OK;
|
||||
}
|
||||
|
||||
void conn_mgr_release_handle(struct CONN_MGR_HANDLE* h) {
|
||||
if (!h) return;
|
||||
struct CONN_MGR_ENTRY* entry = h->entry;
|
||||
if (!entry) { u_free(h); return; }
|
||||
|
||||
struct CONN_MGR_HANDLE** pp = &entry->handles;
|
||||
while (*pp) { if (*pp == h) { *pp = h->next; break; } pp = &(*pp)->next; }
|
||||
|
||||
if (h->nd_handle) { node_conn_direct_close(h->nd_handle); h->nd_handle = NULL; }
|
||||
|
||||
if (!entry->handles) { cm_entry_destroy(entry); cm_clear_nodeinfo(entry->mgr, entry->node_id); }
|
||||
h->entry = NULL; u_free(h);
|
||||
}
|
||||
|
||||
int conn_mgr_set_idle_timeout(struct CONN_MGR* mgr, uint64_t node_id, uint32_t timeout_ms) {
|
||||
if (!mgr) return CONN_MGR_ERR_INTERNAL;
|
||||
struct CONN_MGR_ENTRY* entry = cm_find_entry(mgr, node_id);
|
||||
@@ -455,7 +476,7 @@ static int cm_nat_compatible(struct ETCP_SOCKET* our, uint8_t target_config_type
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint16_t cm_get_node_min_rtt(struct TOPO_NODEQ* nq) {
|
||||
static uint16_t cm_get_node_min_rtt(struct TOPO_GROUP_NODE* nq) {
|
||||
uint16_t rtt = 0xFFFF;
|
||||
if (nq->connectivity.interface_status == PROBE_RESULT_REACHABLE && nq->connectivity.interface_min_rtt < rtt)
|
||||
rtt = nq->connectivity.interface_min_rtt;
|
||||
@@ -466,14 +487,14 @@ static uint16_t cm_get_node_min_rtt(struct TOPO_NODEQ* nq) {
|
||||
return rtt;
|
||||
}
|
||||
|
||||
static uint64_t cm_get_node_max_probe_time(struct TOPO_NODEQ* nq) {
|
||||
static uint64_t cm_get_node_max_probe_time(struct TOPO_GROUP_NODE* nq) {
|
||||
uint64_t t = nq->connectivity.interface_probe_time;
|
||||
if (nq->connectivity.nat_probe_time > t) t = nq->connectivity.nat_probe_time;
|
||||
if (nq->connectivity.real_probe_time > t) t = nq->connectivity.real_probe_time;
|
||||
return t;
|
||||
}
|
||||
|
||||
static int cm_is_rtt_fresh(struct TOPO_NODEQ* nq, uint64_t now_tb) {
|
||||
static int cm_is_rtt_fresh(struct TOPO_GROUP_NODE* nq, uint64_t now_tb) {
|
||||
uint64_t last = cm_get_node_max_probe_time(nq);
|
||||
return (last > 0 && (now_tb - last) < (uint64_t)(CONN_MGR_CANDIDATE_CACHE_MS * 10));
|
||||
}
|
||||
@@ -497,20 +518,22 @@ static uint8_t cm_sock_v6_classify(const struct ETCP_SOCKET* s) {
|
||||
return cm_classify_v6_addr(((const struct sockaddr_in6*)&s->local_addr)->sin6_addr.s6_addr);
|
||||
}
|
||||
|
||||
static int cm_has_direct_ip(struct TOPO_NODEQ* nq) {
|
||||
if (!nq || !nq->node) return 0;
|
||||
for (const struct TOPO_ADDR4* a = nq->node->v4_addrs; a; a = a->next) {
|
||||
static int cm_has_direct_ip(struct CONN_MGR* mgr, struct TOPO_GROUP_NODE* nq) {
|
||||
if (!nq) return 0;
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(mgr->instance->topo_groups, nq->node_id);
|
||||
if (!ni) return 0;
|
||||
for (const struct TOPO_ADDR4* a = ni->v4_addrs; a; a = a->next) {
|
||||
if (a->type == TOPO_ADDR_NAT || a->type == TOPO_ADDR_INTERFACE) {
|
||||
for (const struct TOPO_SOCKMETA4* m = nq->node->v4_sock_meta; m; m = m->next) {
|
||||
for (const struct TOPO_SOCKMETA4* m = ni->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 = nq->node->v6_addrs; a6; a6 = a6->next) {
|
||||
for (const struct TOPO_ADDR6* a6 = ni->v6_addrs; a6; a6 = a6->next) {
|
||||
if ((a6->type != TOPO_ADDR_NAT && a6->type != TOPO_ADDR_INTERFACE) || cm_classify_v6_addr(a6->addr) != CM_V6_DIRECT) continue;
|
||||
for (const struct TOPO_SOCKMETA6* m = nq->node->v6_sock_meta; m; m = m->next)
|
||||
for (const struct TOPO_SOCKMETA6* m = ni->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;
|
||||
@@ -518,21 +541,23 @@ static int cm_has_direct_ip(struct TOPO_NODEQ* nq) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cm_has_local_addr(struct TOPO_NODEQ* nq) {
|
||||
if (!nq || !nq->node) return 0;
|
||||
for (const struct TOPO_ADDR4* a = nq->node->v4_addrs; a; a = a->next) {
|
||||
static int cm_has_local_addr(struct CONN_MGR* mgr, struct TOPO_GROUP_NODE* nq) {
|
||||
if (!nq) return 0;
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(mgr->instance->topo_groups, nq->node_id);
|
||||
if (!ni) return 0;
|
||||
for (const struct TOPO_ADDR4* a = ni->v4_addrs; a; a = a->next) {
|
||||
if (a->type == TOPO_ADDR_INTERFACE) {
|
||||
for (const struct TOPO_SOCKMETA4* m = nq->node->v4_sock_meta; m; m = m->next) {
|
||||
for (const struct TOPO_SOCKMETA4* m = ni->v4_sock_meta; m; m = m->next) {
|
||||
if (m->id == a->socket_id && (m->config_type == CFG_SERVER_TYPE_PRIVATE || m->config_type == CFG_SERVER_TYPE_LOCAL))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const struct TOPO_ADDR6* a6 = nq->node->v6_addrs; a6; a6 = a6->next) {
|
||||
for (const struct TOPO_ADDR6* a6 = ni->v6_addrs; a6; a6 = a6->next) {
|
||||
if (a6->type != TOPO_ADDR_INTERFACE) continue;
|
||||
uint8_t cls = cm_classify_v6_addr(a6->addr);
|
||||
if (cls != CM_V6_LINK_LOCAL && cls != CM_V6_LOCAL) continue;
|
||||
for (const struct TOPO_SOCKMETA6* m = nq->node->v6_sock_meta; m; m = m->next)
|
||||
for (const struct TOPO_SOCKMETA6* m = ni->v6_sock_meta; m; m = m->next)
|
||||
if (m->id == a6->socket_id && (m->config_type == CFG_SERVER_TYPE_PRIVATE || m->config_type == CFG_SERVER_TYPE_LOCAL))
|
||||
return 1;
|
||||
}
|
||||
@@ -553,11 +578,12 @@ struct cm_ping_ctx {
|
||||
|
||||
static void cm_start_local_scan(struct CONN_MGR_ENTRY* entry) {
|
||||
struct TOPO_GROUP* group = entry->mgr->group;
|
||||
struct TOPO_NODEQ* target = topo_node_find_by_id(group, entry->node_id);
|
||||
if (!target || !target->node) { entry->local_scan_state = CM_TRY_FAILED; return; }
|
||||
for (const struct TOPO_ADDR4* a = target->node->v4_addrs; a; a = a->next) {
|
||||
struct TOPO_GROUP_NODE* target = topo_node_find_by_id(group, entry->node_id);
|
||||
struct TOPO_NODE* ni = target ? topo_node_registry_find(entry->mgr->instance->topo_groups, target->node_id) : NULL;
|
||||
if (!target || !ni) { entry->local_scan_state = CM_TRY_FAILED; return; }
|
||||
for (const struct TOPO_ADDR4* a = ni->v4_addrs; a; a = a->next) {
|
||||
if (a->type != TOPO_ADDR_INTERFACE) continue;
|
||||
for (const struct TOPO_SOCKMETA4* m = target->node->v4_sock_meta; m; m = m->next) {
|
||||
for (const struct TOPO_SOCKMETA4* m = ni->v4_sock_meta; m; m = m->next) {
|
||||
if (m->id != a->socket_id || (m->config_type != CFG_SERVER_TYPE_PRIVATE && m->config_type != CFG_SERVER_TYPE_LOCAL)) continue;
|
||||
struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets;
|
||||
while (s) {
|
||||
@@ -567,7 +593,7 @@ static void cm_start_local_scan(struct CONN_MGR_ENTRY* entry) {
|
||||
struct sockaddr_storage sa; memset(&sa, 0, sizeof(sa)); memcpy(&sa, &sin, sizeof(sin));
|
||||
struct cm_ping_ctx* ctx = u_calloc(1, sizeof(struct cm_ping_ctx)); if (!ctx) continue;
|
||||
ctx->entry = entry; ctx->addr = sa; ctx->sock = s; ctx->phase = 0; ctx->attempt = 0;
|
||||
etcp_send_ping_to_socket(entry->mgr->instance, s, target->node->public_key, &sa, CONN_MGR_LOCAL_SCAN_TIMEOUT_MS, cm_ping_cb, ctx, NULL, 0, 0);
|
||||
etcp_send_ping_to_socket(entry->mgr->instance, s, ni->public_key, &sa, CONN_MGR_LOCAL_SCAN_TIMEOUT_MS, cm_ping_cb, ctx, NULL, 0, 0);
|
||||
return;
|
||||
}
|
||||
s = s->next;
|
||||
@@ -577,21 +603,22 @@ static void cm_start_local_scan(struct CONN_MGR_ENTRY* entry) {
|
||||
entry->local_scan_state = CM_TRY_FAILED;
|
||||
}
|
||||
|
||||
static struct ETCP_CONN* cm_get_or_create_conn(struct CONN_MGR_ENTRY* entry, const struct TOPO_NODEQ* target) {
|
||||
static struct ETCP_CONN* cm_get_or_create_conn(struct CONN_MGR_ENTRY* entry, const struct TOPO_GROUP_NODE* target) {
|
||||
struct ETCP_CONN* conn = topo_group_find_conn_for_node(entry->mgr->group, entry->node_id);
|
||||
if (!conn) conn = instance_find_conn(entry->mgr->instance, entry->node_id);
|
||||
if (conn) {
|
||||
if (conn->peer_node_id == entry->node_id) { struct etcp_cbk_entry* cbe = conn->init_cbks; while (cbe) { struct etcp_cbk_entry* n = cbe->next; u_free(cbe); cbe = n; } conn->init_cbks = NULL; etcp_conn_add_init_cbk(conn, cm_direct_init_cb, entry); return conn; }
|
||||
if (conn->peer_node_id == entry->node_id) { etcp_conn_remove_cbk(conn, cm_direct_init_cb, entry); etcp_conn_add_cbk(conn, cm_direct_init_cb, entry, ETCP_CBK_EVENT_INIT); return conn; }
|
||||
DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "conn_mgr: existing conn peer_id mismatch 0x%016llx != 0x%016llx, ignoring",
|
||||
(unsigned long long)conn->peer_node_id, (unsigned long long)entry->node_id);
|
||||
}
|
||||
conn = etcp_connection_create(entry->mgr->instance, NULL);
|
||||
if (!conn) return NULL;
|
||||
sc_init_ctx(&conn->crypto_ctx, &entry->mgr->instance->my_keys);
|
||||
sc_set_peer_public_key(&conn->crypto_ctx, target->node->public_key, 0);
|
||||
{ struct TOPO_NODE* tni = topo_node_registry_find(entry->mgr->instance->topo_groups, target->node_id);
|
||||
sc_set_peer_public_key(&conn->crypto_ctx, tni ? tni->public_key : NULL, 0); }
|
||||
conn->peer_node_id = entry->node_id;
|
||||
etcp_update_log_name(conn);
|
||||
etcp_conn_add_init_cbk(conn, cm_direct_init_cb, entry);
|
||||
etcp_conn_add_cbk(conn, cm_direct_init_cb, entry, ETCP_CBK_EVENT_INIT);
|
||||
return conn;
|
||||
}
|
||||
|
||||
@@ -606,8 +633,9 @@ static void cm_add_v6_link(struct ETCP_CONN* conn, const uint8_t addr[16], uint1
|
||||
static void cm_start_phase_direct(struct CONN_MGR_ENTRY* entry) {
|
||||
if (entry->main_connect_state == CM_TRY_OK || entry->local_scan_state == CM_TRY_OK) return;
|
||||
struct TOPO_GROUP* group = entry->mgr->group;
|
||||
struct TOPO_NODEQ* target = topo_node_find_by_id(group, entry->node_id);
|
||||
if (!target || !target->node) { cm_deliver_result(entry, CONN_MGR_ERR_NOT_FOUND); return; }
|
||||
struct TOPO_GROUP_NODE* target = topo_node_find_by_id(group, entry->node_id);
|
||||
struct TOPO_NODE* ni = target ? topo_node_registry_find(entry->mgr->instance->topo_groups, target->node_id) : NULL;
|
||||
if (!target || !ni) { cm_deliver_result(entry, CONN_MGR_ERR_NOT_FOUND); return; }
|
||||
|
||||
struct ETCP_CONN* conn = cm_get_or_create_conn(entry, target);
|
||||
if (!conn) { cm_deliver_result(entry, CONN_MGR_ERR_INTERNAL); return; }
|
||||
@@ -616,7 +644,7 @@ static void cm_start_phase_direct(struct CONN_MGR_ENTRY* entry) {
|
||||
const char* timer_name = entry->db_loaded ? "conn_mgr_db_direct" : "conn_mgr_direct";
|
||||
|
||||
if (entry->db_loaded) {
|
||||
for (const struct TOPO_ADDR4* a = target->node->v4_addrs; a; a = a->next) {
|
||||
for (const struct TOPO_ADDR4* a = ni->v4_addrs; a; a = a->next) {
|
||||
if (!(a->protocol & TOPO_PROTO_UDP)) continue;
|
||||
struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets;
|
||||
while (s) {
|
||||
@@ -629,7 +657,7 @@ static void cm_start_phase_direct(struct CONN_MGR_ENTRY* entry) {
|
||||
s = s->next;
|
||||
}
|
||||
}
|
||||
for (const struct TOPO_ADDR6* a6 = target->node->v6_addrs; a6; a6 = a6->next) {
|
||||
for (const struct TOPO_ADDR6* a6 = ni->v6_addrs; a6; a6 = a6->next) {
|
||||
if (!(a6->protocol & TOPO_PROTO_UDP)) continue;
|
||||
uint8_t tclass = cm_classify_v6_addr(a6->addr); if (tclass == CM_V6_OTHER) continue;
|
||||
struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets;
|
||||
@@ -647,9 +675,9 @@ static void cm_start_phase_direct(struct CONN_MGR_ENTRY* entry) {
|
||||
|
||||
uint8_t priority_order[] = { TOPO_ADDR_NAT, TOPO_ADDR_INTERFACE };
|
||||
for (int pri = 0; pri < 2; pri++) {
|
||||
for (const struct TOPO_ADDR4* a = target->node->v4_addrs; a; a = a->next) {
|
||||
for (const struct TOPO_ADDR4* a = ni->v4_addrs; a; a = a->next) {
|
||||
if (a->type != priority_order[pri]) continue;
|
||||
for (const struct TOPO_SOCKMETA4* m = target->node->v4_sock_meta; m; m = m->next) {
|
||||
for (const struct TOPO_SOCKMETA4* m = ni->v4_sock_meta; m; m = m->next) {
|
||||
if (m->id != a->socket_id) continue;
|
||||
struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets;
|
||||
while (s) {
|
||||
@@ -663,7 +691,7 @@ static void cm_start_phase_direct(struct CONN_MGR_ENTRY* entry) {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const struct TOPO_ADDR6* a6 = target->node->v6_addrs; a6; a6 = a6->next) {
|
||||
for (const struct TOPO_ADDR6* a6 = ni->v6_addrs; a6; a6 = a6->next) {
|
||||
if (a6->type != priority_order[pri]) continue;
|
||||
uint8_t tclass = cm_classify_v6_addr(a6->addr); if (tclass == CM_V6_OTHER) continue;
|
||||
struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets;
|
||||
@@ -676,8 +704,8 @@ static void cm_start_phase_direct(struct CONN_MGR_ENTRY* entry) {
|
||||
return;
|
||||
}
|
||||
etcp_connection_close(conn);
|
||||
int has_our = cm_has_direct_ip(group->local_node);
|
||||
int has_target = cm_has_direct_ip(target);
|
||||
int has_our = cm_has_direct_ip(entry->mgr, group->local_node);
|
||||
int has_target = cm_has_direct_ip(entry->mgr, target);
|
||||
if (has_our && !has_target) { cm_start_phase_reverse(entry); return; }
|
||||
cm_start_phase_indirect(entry);
|
||||
}
|
||||
@@ -692,9 +720,9 @@ static void cm_direct_timeout_cb(void* arg) {
|
||||
return;
|
||||
}
|
||||
struct TOPO_GROUP* group = entry->mgr->group;
|
||||
struct TOPO_NODEQ* target = topo_node_find_by_id(group, entry->node_id);
|
||||
int has_our = cm_has_direct_ip(group->local_node);
|
||||
int has_target = target ? cm_has_direct_ip(target) : 0;
|
||||
struct TOPO_GROUP_NODE* target = topo_node_find_by_id(group, entry->node_id);
|
||||
int has_our = cm_has_direct_ip(entry->mgr, group->local_node);
|
||||
int has_target = target ? cm_has_direct_ip(entry->mgr, target) : 0;
|
||||
if (entry->local_scan_state != CM_TRY_OK) {
|
||||
if (has_our && !has_target) { cm_start_phase_reverse(entry); return; }
|
||||
cm_start_phase_indirect(entry);
|
||||
@@ -704,7 +732,7 @@ static void cm_direct_timeout_cb(void* arg) {
|
||||
cm_deliver_result(entry, CONN_MGR_ERR_UNREACHABLE);
|
||||
}
|
||||
|
||||
static void cm_direct_init_cb(struct ETCP_CONN* conn, void* arg) {
|
||||
static void cm_direct_init_cb(struct ETCP_CONN* conn, int event, void* arg) { (void)event;
|
||||
struct CONN_MGR_ENTRY* entry = (struct CONN_MGR_ENTRY*)arg;
|
||||
if (!conn || conn->peer_node_id != entry->node_id) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "conn_mgr: direct ready cb peer mismatch conn=%p peer=0x%llx entry=0x%llx",
|
||||
@@ -739,8 +767,10 @@ static void cm_ping_cb(int success, uint16_t rtt, void* arg, uint64_t nonce,
|
||||
}
|
||||
ctx->attempt++;
|
||||
if (ctx->attempt < CONN_MGR_LOCAL_SCAN_ATTEMPTS && ctx->phase == 0) {
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(entry->mgr->group, entry->node_id);
|
||||
struct TOPO_NODE* pub_ni = nq ? topo_node_registry_find(entry->mgr->instance->topo_groups, nq->node_id) : NULL;
|
||||
etcp_send_ping_to_socket(entry->mgr->instance, ctx->sock,
|
||||
topo_node_find_by_id(entry->mgr->group, entry->node_id)->node->public_key,
|
||||
pub_ni ? pub_ni->public_key : NULL,
|
||||
&ctx->addr, CONN_MGR_LOCAL_SCAN_TIMEOUT_MS, cm_ping_cb, ctx, NULL, 0, 0);
|
||||
return;
|
||||
}
|
||||
@@ -752,15 +782,16 @@ static void cm_ping_cb(int success, uint16_t rtt, void* arg, uint64_t nonce,
|
||||
|
||||
static void cm_start_phase_reverse(struct CONN_MGR_ENTRY* entry) {
|
||||
struct TOPO_GROUP* group = entry->mgr->group;
|
||||
struct TOPO_NODEQ* local = group->local_node;
|
||||
if (!local || !local->node) { cm_deliver_result(entry, CONN_MGR_ERR_INTERNAL); return; }
|
||||
struct TOPO_GROUP_NODE* local = group->local_node;
|
||||
struct TOPO_NODE* lni = local ? topo_node_registry_find(entry->mgr->instance->topo_groups, local->node_id) : NULL;
|
||||
if (!local || !lni) { cm_deliver_result(entry, CONN_MGR_ERR_INTERNAL); return; }
|
||||
uint32_t req_id = ++entry->mgr->next_request_id;
|
||||
entry->main.request_id = req_id; entry->main.phase = 2;
|
||||
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) {
|
||||
for (const struct TOPO_ADDR4* a = lni->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) {
|
||||
for (const struct TOPO_SOCKMETA4* m = lni->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);
|
||||
@@ -808,7 +839,7 @@ static void cm_reverse_timeout_cb(void* arg) {
|
||||
cm_start_phase_indirect(entry);
|
||||
}
|
||||
|
||||
static void cm_reverse_init_cb(struct ETCP_CONN* conn, void* arg) {
|
||||
static void cm_reverse_init_cb(struct ETCP_CONN* conn, int event, void* arg) { (void)event;
|
||||
struct cm_reverse_pending* rp = (struct cm_reverse_pending*)arg;
|
||||
struct CONN_MGR_ENTRY* entry = rp->entry;
|
||||
if (!conn || conn->peer_node_id != entry->node_id) { u_free(rp); return; }
|
||||
@@ -886,7 +917,7 @@ static void cm_compute_intermediaries(struct CONN_MGR_ENTRY* entry, struct CONN_
|
||||
}
|
||||
for (uint8_t i = 0; i < resp->my_count && count < 8; i++) {
|
||||
uint64_t id = resp->my_candidates[i].node_id;
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(entry->mgr->group, id);
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(entry->mgr->group, id);
|
||||
uint16_t our_rtt = nq ? cm_get_node_min_rtt(nq) : 0;
|
||||
if (our_rtt == 0xFFFF) our_rtt = 0;
|
||||
all[count].node_id = id;
|
||||
@@ -912,7 +943,7 @@ static void cm_compute_intermediaries(struct CONN_MGR_ENTRY* entry, struct CONN_
|
||||
for (uint8_t i = 0; i < sel; i++) {
|
||||
pkt.selected[i].node_id = all[i].node_id;
|
||||
pkt.selected[i].rtt = 0;
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(entry->mgr->group, all[i].node_id);
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(entry->mgr->group, all[i].node_id);
|
||||
if (nq) pkt.selected[i].rtt = cm_get_node_min_rtt(nq);
|
||||
}
|
||||
struct ll_entry* qe = queue_entry_new(0);
|
||||
@@ -933,7 +964,7 @@ static void cm_exchange_probe_retry_cb(void* arg) {
|
||||
uint8_t need_probe = 0;
|
||||
uint64_t now_tb = get_time_tb();
|
||||
for (uint8_t i = 0; i < ep->cached_resp.my_count && i < 4; i++) {
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(mgr->group, ep->cached_resp.my_candidates[i].node_id);
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(mgr->group, ep->cached_resp.my_candidates[i].node_id);
|
||||
if (!nq || !cm_is_rtt_fresh(nq, now_tb)) { need_probe++; break; }
|
||||
}
|
||||
if (need_probe == 0) {
|
||||
@@ -963,7 +994,7 @@ static void cm_handle_interm_exchange_resp(struct CONN_MGR* mgr, const uint8_t*
|
||||
uint8_t need_probe = 0;
|
||||
uint64_t now_tb = get_time_tb();
|
||||
for (uint8_t i = 0; i < ep->cached_resp.my_count && i < 4; i++) {
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(mgr->group, ep->cached_resp.my_candidates[i].node_id);
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(mgr->group, ep->cached_resp.my_candidates[i].node_id);
|
||||
if (!nq || !cm_is_rtt_fresh(nq, now_tb)) { need_probe++; route_connectivity_probe_node(mgr->instance, nq); }
|
||||
}
|
||||
if (need_probe == 0) { ep->probes_done = 1; cm_compute_intermediaries(ep->entry, &ep->cached_resp);
|
||||
@@ -1059,12 +1090,13 @@ static void cm_handle_direct_req(struct ETCP_CONN* conn, const uint8_t* data, si
|
||||
memset(&sa, 0, sizeof(sa)); memcpy(&sa, &sin, sizeof(sin));
|
||||
struct ETCP_CONN* new_conn = etcp_connection_create(conn->instance, NULL);
|
||||
if (new_conn) {
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(mgr->group, src_node_id);
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(mgr->group, src_node_id);
|
||||
if (nq) { sc_init_ctx(&new_conn->crypto_ctx, &conn->instance->my_keys);
|
||||
sc_set_peer_public_key(&new_conn->crypto_ctx, nq->node->public_key, 0); }
|
||||
{ struct TOPO_NODE* dni = topo_node_registry_find(mgr->instance->topo_groups, nq->node_id);
|
||||
sc_set_peer_public_key(&new_conn->crypto_ctx, dni ? dni->public_key : NULL, 0); } }
|
||||
struct cm_reverse_pending* rp = u_calloc(1, sizeof(struct cm_reverse_pending));
|
||||
if (rp) { rp->request_id = req->request_id; rp->entry = NULL; rp->next = mgr->reverse_pending;
|
||||
etcp_conn_add_init_cbk(new_conn, cm_reverse_init_cb, rp); mgr->reverse_pending = rp; }
|
||||
etcp_conn_add_cbk(new_conn, cm_reverse_init_cb, rp, ETCP_CBK_EVENT_INIT); mgr->reverse_pending = rp; }
|
||||
etcp_link_new(new_conn, s, &sa, 0);
|
||||
}
|
||||
break;
|
||||
@@ -1081,7 +1113,7 @@ static void cm_handle_interm_exchange_req(struct ETCP_CONN* conn,
|
||||
uint64_t now_tb = get_time_tb();
|
||||
for (uint8_t i = 0; i < req->candidate_count && i < 4; i++) {
|
||||
uint64_t cand_id = req->candidates[i].node_id;
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(mgr->group, cand_id);
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(mgr->group, cand_id);
|
||||
if (nq && cm_is_rtt_fresh(nq, now_tb)) continue;
|
||||
route_connectivity_probe_node(mgr->instance, nq);
|
||||
}
|
||||
@@ -1096,7 +1128,7 @@ static void cm_handle_interm_exchange_req(struct ETCP_CONN* conn,
|
||||
resp.your_count = req->candidate_count > 4 ? 4 : req->candidate_count;
|
||||
for (uint8_t i = 0; i < resp.your_count; i++) {
|
||||
resp.your_candidates[i].node_id = req->candidates[i].node_id;
|
||||
struct TOPO_NODEQ* nq2 = topo_node_find_by_id(mgr->group, req->candidates[i].node_id);
|
||||
struct TOPO_GROUP_NODE* nq2 = topo_node_find_by_id(mgr->group, req->candidates[i].node_id);
|
||||
uint16_t rtt = nq2 ? cm_get_node_min_rtt(nq2) : 0;
|
||||
resp.your_candidates[i].rtt = rtt;
|
||||
}
|
||||
@@ -1154,8 +1186,9 @@ static void cm_bg_ping_timer_cb(void* arg) {
|
||||
e = group->nodes->head;
|
||||
while (e && cursor < mgr->bg_ping_cursor) { cursor++; e = e->next; }
|
||||
if (e) {
|
||||
struct TOPO_NODEQ* nq = (struct TOPO_NODEQ*)e;
|
||||
uint64_t node_id = nq->node->node_id;
|
||||
struct TOPO_GROUP_NODE* nq = (struct TOPO_GROUP_NODE*)e;
|
||||
struct TOPO_NODE* bg_ni = topo_node_registry_find(mgr->instance->topo_groups, nq->node_id);
|
||||
uint64_t node_id = nq->node_id;
|
||||
if (node_id != mgr->instance->node_id) {
|
||||
struct ETCP_CONN* dconn = topo_group_find_conn_for_node(group, node_id);
|
||||
int has_active = 0;
|
||||
@@ -1163,9 +1196,9 @@ static void cm_bg_ping_timer_cb(void* arg) {
|
||||
struct ETCP_LINK* l = dconn->links;
|
||||
while (l) { if (l->initialized && l->link_status) { has_active = 1; break; } l = l->next; }
|
||||
}
|
||||
if (!has_active) {
|
||||
if (!has_active && bg_ni) {
|
||||
int sent_v4 = 0;
|
||||
for (const struct TOPO_ADDR4* a = nq->node->v4_addrs; a; a = a->next) {
|
||||
for (const struct TOPO_ADDR4* a = bg_ni->v4_addrs; a; a = a->next) {
|
||||
if (a->type != TOPO_ADDR_NAT && a->type != TOPO_ADDR_INTERFACE) continue;
|
||||
struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET;
|
||||
memcpy(&sin.sin_addr.s_addr, a->addr, 4); sin.sin_port = htons(a->port);
|
||||
@@ -1173,12 +1206,12 @@ static void cm_bg_ping_timer_cb(void* arg) {
|
||||
struct ETCP_SOCKET* s = mgr->instance->etcp_sockets;
|
||||
while (s) { if (s->local_addr.ss_family == AF_INET) break; s = s->next; }
|
||||
if (!s) break;
|
||||
etcp_send_ping_to_socket(mgr->instance, s, nq->node->public_key, &sa,
|
||||
etcp_send_ping_to_socket(mgr->instance, s, bg_ni->public_key, &sa,
|
||||
CONN_PROBE_TIMEOUT_MS, cm_bg_ping_noop_cb, NULL, NULL, 0, 0);
|
||||
sent_v4 = 1; break;
|
||||
}
|
||||
if (!sent_v4) {
|
||||
for (const struct TOPO_ADDR6* a6 = nq->node->v6_addrs; a6; a6 = a6->next) {
|
||||
for (const struct TOPO_ADDR6* a6 = bg_ni->v6_addrs; a6; a6 = a6->next) {
|
||||
if (a6->type != TOPO_ADDR_NAT && a6->type != TOPO_ADDR_INTERFACE) continue;
|
||||
struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6;
|
||||
memcpy(&sin6.sin6_addr, a6->addr, 16); sin6.sin6_port = htons(a6->port);
|
||||
@@ -1186,7 +1219,7 @@ static void cm_bg_ping_timer_cb(void* arg) {
|
||||
struct ETCP_SOCKET* s = mgr->instance->etcp_sockets;
|
||||
while (s) { if (s->local_addr.ss_family == AF_INET6) break; s = s->next; }
|
||||
if (!s) break;
|
||||
etcp_send_ping_to_socket(mgr->instance, s, nq->node->public_key, &sa,
|
||||
etcp_send_ping_to_socket(mgr->instance, s, bg_ni->public_key, &sa,
|
||||
CONN_PROBE_TIMEOUT_MS, cm_bg_ping_noop_cb, NULL, NULL, 0, 0);
|
||||
break;
|
||||
}
|
||||
@@ -1203,7 +1236,7 @@ static void cm_candidate_ping_timer_cb(void* arg) {
|
||||
uint64_t now_tb = get_time_tb();
|
||||
for (uint8_t i = 0; i < mgr->best_candidate_count; i++) {
|
||||
uint64_t cand_id = mgr->best_candidates[i].node_id;
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(mgr->group, cand_id);
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(mgr->group, cand_id);
|
||||
if (!nq) {
|
||||
memmove(&mgr->best_candidates[i], &mgr->best_candidates[i+1], (mgr->best_candidate_count - i - 1) * sizeof(mgr->best_candidates[0]));
|
||||
mgr->best_candidate_count--; i--; continue;
|
||||
@@ -1220,8 +1253,10 @@ static void cm_candidate_ping_timer_cb(void* arg) {
|
||||
struct ETCP_LINK* l = dconn->links;
|
||||
while (l) { if (l->initialized && l->link_status) { has_active = 1; break; } l = l->next; }
|
||||
}
|
||||
if (has_active)
|
||||
etcp_send_ping(mgr->instance, nq->node->public_key, &dconn->links->remote_addr, CONN_PROBE_TIMEOUT_MS, NULL, NULL, NULL, 0);
|
||||
if (has_active) {
|
||||
struct TOPO_NODE* cp_ni = topo_node_registry_find(mgr->instance->topo_groups, nq->node_id);
|
||||
if (cp_ni) etcp_send_ping(mgr->instance, cp_ni->public_key, &dconn->links->remote_addr, CONN_PROBE_TIMEOUT_MS, NULL, NULL, NULL, 0);
|
||||
}
|
||||
else
|
||||
route_connectivity_probe_node(mgr->instance, nq);
|
||||
}
|
||||
@@ -1278,8 +1313,8 @@ static void cm_handle_invite_info_req(struct CONN_MGR* mgr, struct ETCP_CONN* co
|
||||
struct TOPO_GROUP* group = topo_groups_find(mgr->instance->topo_groups, req->group_id);
|
||||
struct TOPO_GROUP* src_group = group ? group : mgr->group;
|
||||
const uint8_t* ed_pubkey = src_group->ed25519_public_key;
|
||||
const char* node_name = (src_group->local_node && src_group->local_node->node)
|
||||
? src_group->local_node->node->node_name : NULL;
|
||||
struct TOPO_NODE* ln = (src_group->local_node) ? topo_node_registry_find(src_group->instance->topo_groups, src_group->local_node->node_id) : NULL;
|
||||
const char* node_name = ln ? ln->node_name : NULL;
|
||||
size_t name_len = node_name ? strlen(node_name) : 0;
|
||||
if (name_len > 255) name_len = 255;
|
||||
|
||||
@@ -1335,13 +1370,16 @@ static void cm_handle_invite_info_resp(struct CONN_MGR* mgr, const uint8_t* data
|
||||
|
||||
if (inv->group_id != 0 && !resp->is_member) { cm_invite_fail(inv, CONN_MGR_ERR_NOT_MEMBER); return; }
|
||||
|
||||
struct TOPO_NODEQ* nq = inv->temp_nq;
|
||||
if (nq && nq->node) {
|
||||
memcpy(nq->node->ed25519_public_key, resp->ed25519_pubkey, SC_PUBKEY_SIZE);
|
||||
if (nq->node->node_name) { u_free(nq->node->node_name); nq->node->node_name = NULL; }
|
||||
if (resp->node_name_len) { nq->node->node_name = u_strdup((const char*)resp->node_name); }
|
||||
struct TOPO_GROUP_NODE* nq = inv->temp_nq;
|
||||
if (nq) {
|
||||
struct TOPO_NODE* inv_ni = topo_node_registry_find(inv->mgr->instance->topo_groups, nq->node_id);
|
||||
if (inv_ni) {
|
||||
memcpy(inv_ni->ed25519_public_key, resp->ed25519_pubkey, SC_PUBKEY_SIZE);
|
||||
if (inv_ni->node_name) { u_free(inv_ni->node_name); inv_ni->node_name = NULL; }
|
||||
if (resp->node_name_len) { inv_ni->node_name = u_strdup((const char*)resp->node_name); }
|
||||
}
|
||||
sqlite3* db = inv->mgr->instance->topo_sqlite_db;
|
||||
if (db) topo_node_sqlite_node_put(db, nq, (time_t)(get_time_tb() / 10000));
|
||||
if (db) topo_node_sqlite_node_put(db, inv->mgr->instance->topo_groups, nq, (time_t)(get_time_tb() / 10000));
|
||||
}
|
||||
|
||||
if (inv->overall_timer) { uasync_cancel_timeout(inv->mgr->instance->ua, inv->overall_timer); inv->overall_timer = NULL; }
|
||||
@@ -1349,7 +1387,7 @@ static void cm_handle_invite_info_resp(struct CONN_MGR* mgr, const uint8_t* data
|
||||
cm_invite_cleanup(inv);
|
||||
}
|
||||
|
||||
static void cm_invite_init_cb(struct ETCP_CONN* conn, void* arg) {
|
||||
static void cm_invite_init_cb(struct ETCP_CONN* conn, int event, void* arg) { (void)event;
|
||||
struct cm_invite_pending* inv = (struct cm_invite_pending*)arg;
|
||||
if (inv->state != CM_INVITE_CONNECTING) return;
|
||||
if (!conn || conn->peer_node_id != inv->node_id) {
|
||||
@@ -1399,7 +1437,7 @@ static void cm_tcp_ready_cb(struct stcp_link* link, void* arg) {
|
||||
|
||||
inv->conn = etcp;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: TCP invite ready node=0x%016llx", (unsigned long long)inv->node_id);
|
||||
cm_invite_init_cb(etcp, inv);
|
||||
cm_invite_init_cb(etcp, ETCP_CBK_EVENT_INIT, inv);
|
||||
}
|
||||
|
||||
static void cm_tcp_close_cb(struct stcp_link* link, int err, void* arg) {
|
||||
@@ -1424,7 +1462,7 @@ static void cm_invite_fail(struct cm_invite_pending* inv, int result) {
|
||||
if (inv->temp_nq) {
|
||||
struct TOPO_GROUP* group = mgr->group;
|
||||
queue_remove_data(group->nodes, &inv->temp_nq->ll);
|
||||
topo_node_free_lists(group, inv->temp_nq);
|
||||
topo_nodeq_free_group_fields(mgr->instance->topo_groups, inv->temp_nq);
|
||||
queue_entry_free(&inv->temp_nq->ll); inv->temp_nq = NULL;
|
||||
}
|
||||
struct cm_invite_pending** pp = &mgr->invite_list;
|
||||
@@ -1454,7 +1492,7 @@ int conn_mgr_connect_from_invite(struct CONN_MGR* mgr, struct TOPO_NODE* ni,
|
||||
|
||||
struct TOPO_NODE* group_ni = u_calloc(1, sizeof(struct TOPO_NODE));
|
||||
if (!group_ni) { if (cb) cb(CONN_MGR_ERR_INTERNAL, node_id, cb_arg); return CONN_MGR_ERR_INTERNAL; }
|
||||
group_ni->node_id = node_id; group_ni->ver = 1;
|
||||
group_ni->node_id = node_id; group_ni->ver = 1; group_ni->group_id = mgr->group->group_id;
|
||||
memcpy(group_ni->public_key, ni->public_key, SC_PUBKEY_SIZE);
|
||||
for (const struct TOPO_ADDR4* src = ni->v4_addrs; src; src = src->next) {
|
||||
struct TOPO_ADDR4* a4 = memory_pool_alloc(groups->v4_addr_pool);
|
||||
@@ -1472,17 +1510,17 @@ int conn_mgr_connect_from_invite(struct CONN_MGR* mgr, struct TOPO_NODE* ni,
|
||||
}
|
||||
if (!group_ni->v4_addrs && !group_ni->v6_addrs) { u_free(group_ni); if (cb) cb(CONN_MGR_ERR_NO_ADDRESSES, node_id, cb_arg); return CONN_MGR_ERR_NO_ADDRESSES; }
|
||||
|
||||
group_ni = topo_node_registry_acquire(groups, group_ni); /* group_ni now owned by registry (ref=1) */
|
||||
group_ni = topo_node_registry_store(groups, group_ni); /* group_ni now owned by registry (ref=1) */
|
||||
if (!group_ni) { if (cb) cb(CONN_MGR_ERR_INTERNAL, node_id, cb_arg); return CONN_MGR_ERR_INTERNAL; }
|
||||
|
||||
struct ll_entry* qe = queue_entry_new(sizeof(struct TOPO_NODEQ));
|
||||
if (!qe) { topo_node_registry_release(groups, group_ni); if (cb) cb(CONN_MGR_ERR_INTERNAL, node_id, cb_arg); return CONN_MGR_ERR_INTERNAL; }
|
||||
struct TOPO_NODEQ* nq = (struct TOPO_NODEQ*)qe;
|
||||
struct ll_entry* qe = queue_entry_new(sizeof(struct TOPO_GROUP_NODE));
|
||||
if (!qe) { topo_node_registry_unref(groups, group_ni->node_id); if (cb) cb(CONN_MGR_ERR_INTERNAL, node_id, cb_arg); return CONN_MGR_ERR_INTERNAL; }
|
||||
struct TOPO_GROUP_NODE* nq = (struct TOPO_GROUP_NODE*)qe;
|
||||
memset((uint8_t*)nq + sizeof(struct ll_entry), 0, sizeof(*nq) - sizeof(struct ll_entry));
|
||||
nq->node = group_ni; nq->hash_node_id = node_id;
|
||||
nq->node_id = node_id;
|
||||
|
||||
struct cm_invite_pending* inv = u_calloc(1, sizeof(struct cm_invite_pending));
|
||||
if (!inv) { queue_entry_free(qe); topo_node_registry_release(groups, group_ni); if (cb) cb(CONN_MGR_ERR_INTERNAL, node_id, cb_arg); return CONN_MGR_ERR_INTERNAL; }
|
||||
if (!inv) { queue_entry_free(qe); topo_node_registry_unref(groups, group_ni->node_id); if (cb) cb(CONN_MGR_ERR_INTERNAL, node_id, cb_arg); return CONN_MGR_ERR_INTERNAL; }
|
||||
inv->mgr = mgr; inv->node_id = node_id; inv->group_id = group_id;
|
||||
inv->timeout_ms = timeout_ms; inv->state = CM_INVITE_CONNECTING;
|
||||
inv->temp_nq = nq; inv->cb = cb; inv->cb_arg = cb_arg;
|
||||
@@ -1505,7 +1543,7 @@ int conn_mgr_connect_from_invite(struct CONN_MGR* mgr, struct TOPO_NODE* ni,
|
||||
if (!udp_conn) {
|
||||
udp_conn = etcp_connection_create(mgr->instance, NULL);
|
||||
if (udp_conn) {
|
||||
etcp_conn_add_init_cbk(udp_conn, cm_invite_init_cb, inv);
|
||||
etcp_conn_add_cbk(udp_conn, cm_invite_init_cb, inv, ETCP_CBK_EVENT_INIT);
|
||||
sc_init_ctx(&udp_conn->crypto_ctx, &mgr->instance->my_keys);
|
||||
sc_set_peer_public_key(&udp_conn->crypto_ctx, group_ni->public_key, 0);
|
||||
}
|
||||
@@ -1526,7 +1564,7 @@ int conn_mgr_connect_from_invite(struct CONN_MGR* mgr, struct TOPO_NODE* ni,
|
||||
if (!udp_conn) {
|
||||
udp_conn = etcp_connection_create(mgr->instance, NULL);
|
||||
if (udp_conn) {
|
||||
etcp_conn_add_init_cbk(udp_conn, cm_invite_init_cb, inv);
|
||||
etcp_conn_add_cbk(udp_conn, cm_invite_init_cb, inv, ETCP_CBK_EVENT_INIT);
|
||||
sc_init_ctx(&udp_conn->crypto_ctx, &mgr->instance->my_keys);
|
||||
sc_set_peer_public_key(&udp_conn->crypto_ctx, group_ni->public_key, 0);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ extern "C" {
|
||||
|
||||
struct UTUN_INSTANCE;
|
||||
struct ETCP_CONN;
|
||||
struct TOPO_NODEQ;
|
||||
struct TOPO_GROUP_NODE;
|
||||
struct TOPO_GROUP;
|
||||
|
||||
/**
|
||||
@@ -120,6 +120,10 @@ enum CM_TRY_STATE {
|
||||
#define CONN_MGR_SUBCMD_INTERM_EXCHANGE_RESP 0x04 ///< Ответ с нашими кандидатами + замеры RTT до кандидатов инициатора
|
||||
#define CONN_MGR_SUBCMD_INTERM_SELECTED 0x05 ///< Выбранные посредники (финальный шаг INDIRECT-фазы)
|
||||
#define CONN_MGR_SUBCMD_DISCONNECT 0x06 ///< Уведомление о разрыве соединения
|
||||
#define CONN_MGR_SUBCMD_BRIDGE_REQUEST 0x10 ///< A→X: запрос моста к B (payload: target_node_id)
|
||||
#define CONN_MGR_SUBCMD_BRIDGE_RESPONSE 0x11 ///< X→A: ответ с session_id
|
||||
#define CONN_MGR_SUBCMD_BRIDGE_CLOSE 0x12 ///< A→X: закрыть мост (payload: session_id + target_node_id)
|
||||
#define CONN_MGR_SUBCMD_BRIDGE_CLOSED 0x13 ///< X→A: мост закрыт (payload: session_id)
|
||||
#define CONN_MGR_SUBCMD_INVITE_INFO_REQ 0x0A ///< Запрос проверки членства в группе при invite-подключении
|
||||
#define CONN_MGR_SUBCMD_INVITE_INFO_RESP 0x0B ///< Ответ с членством, ed25519_pubkey, именем узла
|
||||
/** @} */
|
||||
@@ -221,6 +225,37 @@ struct CONN_MGR_DISCONNECT {
|
||||
uint64_t node_id; ///< Идентификатор ноды, с которой разрываем соединение
|
||||
};
|
||||
|
||||
struct CONN_MGR_BRIDGE_REQUEST {
|
||||
uint8_t cmd; ///< ETCP_RT_ID_CONN_MGR
|
||||
uint8_t subcmd; ///< CONN_MGR_SUBCMD_BRIDGE_REQUEST
|
||||
uint64_t target_node_id; ///< К какой ноде нужен мост
|
||||
};
|
||||
|
||||
struct CONN_MGR_BRIDGE_RESPONSE {
|
||||
uint8_t cmd; ///< ETCP_RT_ID_CONN_MGR
|
||||
uint8_t subcmd; ///< CONN_MGR_SUBCMD_BRIDGE_RESPONSE
|
||||
uint64_t session_id; ///< ID bridge-сессии
|
||||
uint64_t target_node_id; ///< Эхо target_node_id
|
||||
};
|
||||
|
||||
struct CONN_MGR_BRIDGE_CLOSE {
|
||||
uint8_t cmd; ///< ETCP_RT_ID_CONN_MGR
|
||||
uint8_t subcmd; ///< CONN_MGR_SUBCMD_BRIDGE_CLOSE
|
||||
uint64_t session_id; ///< ID bridge-сессии
|
||||
uint64_t target_node_id; ///< ID цели
|
||||
};
|
||||
|
||||
struct CONN_MGR_BRIDGE_CLOSED {
|
||||
uint8_t cmd; ///< ETCP_RT_ID_CONN_MGR
|
||||
uint8_t subcmd; ///< CONN_MGR_SUBCMD_BRIDGE_CLOSED
|
||||
uint64_t session_id; ///< ID bridge-сессии
|
||||
};
|
||||
|
||||
#define CONN_MGR_BRIDGE_REQUEST_SIZE sizeof(struct CONN_MGR_BRIDGE_REQUEST)
|
||||
#define CONN_MGR_BRIDGE_RESPONSE_SIZE sizeof(struct CONN_MGR_BRIDGE_RESPONSE)
|
||||
#define CONN_MGR_BRIDGE_CLOSE_SIZE sizeof(struct CONN_MGR_BRIDGE_CLOSE)
|
||||
#define CONN_MGR_BRIDGE_CLOSED_SIZE sizeof(struct CONN_MGR_BRIDGE_CLOSED)
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/**
|
||||
@@ -276,18 +311,36 @@ struct CONN_MGR_INVITE_INFO_RESP {
|
||||
*/
|
||||
typedef void (*conn_mgr_connect_callback_t)(int result, uint64_t node_id, void* arg);
|
||||
|
||||
/* forward declaration для handle */
|
||||
struct NODE_CONN_DIRECT;
|
||||
|
||||
/**
|
||||
* @struct cm_cb_node
|
||||
* @brief Узел связного списка callback'ов для одной ноды.
|
||||
*
|
||||
* Позволяет регистрировать несколько callback'ов на одно подключение.
|
||||
* Новые callback'и добавляются в начало списка.
|
||||
* @struct CONN_MGR_HANDLE
|
||||
* @brief Универсальный handle подключения (один на каждый conn_mgr_connect_node).
|
||||
*/
|
||||
struct cm_cb_node {
|
||||
conn_mgr_connect_callback_t cb; ///< Функция-callback
|
||||
void* arg; ///< Пользовательский аргумент
|
||||
struct cm_cb_node* next; ///< Следующий callback в списке
|
||||
uint8_t cancelled; ///< 1 = callback помечен как недействительный
|
||||
struct CONN_MGR_HANDLE {
|
||||
uint64_t target_node_id;
|
||||
uint8_t conn_type;
|
||||
uint64_t intermediary_node_id;
|
||||
uint64_t bridge_session_id;
|
||||
struct NODE_CONN_DIRECT* nd_handle;
|
||||
conn_mgr_connect_callback_t result_cb;
|
||||
void* result_arg;
|
||||
struct CONN_MGR_HANDLE* next;
|
||||
struct CONN_MGR_ENTRY* entry;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct cm_bridge_session
|
||||
* @brief Bridge-сессия на посреднике X (INDIRECT-прокси).
|
||||
*/
|
||||
struct cm_bridge_session {
|
||||
uint64_t session_id;
|
||||
uint64_t initiator_id;
|
||||
uint64_t target_id;
|
||||
struct CONN_MGR_HANDLE* handle_to_target;
|
||||
struct CONN_MGR_HANDLE* handle_to_initiator;
|
||||
struct cm_bridge_session* next;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -305,7 +358,7 @@ struct CONN_MGR_ENTRY {
|
||||
uint64_t last_traffic_tb; ///< Время последнего трафика (tb) для idle-проверки
|
||||
void* idle_timer; ///< Хендл таймера idle-проверки
|
||||
|
||||
struct cm_cb_node* cb_list; ///< Связный список callback'ов результата
|
||||
struct CONN_MGR_HANDLE* handles; ///< Связный список handle'ов (один на conn_mgr_connect_node)
|
||||
|
||||
uint64_t intermediaries[CONN_MGR_MAX_INTERMEDIARIES]; ///< Выбранные посредники (node_id)
|
||||
uint8_t intermediariy_count; ///< Количество выбранных посредников
|
||||
@@ -356,6 +409,8 @@ struct CONN_MGR {
|
||||
struct cm_reverse_pending* reverse_pending; ///< Связный список ожидающих REVERSE-подключений
|
||||
struct cm_exchange_pending* exchange_pending; ///< Связный список ожидающих INDIRECT-обменов
|
||||
struct cm_invite_pending* invite_list; ///< Связный список ожидающих invite-подключений
|
||||
struct cm_bridge_session* bridge_sessions; ///< Связный список активных bridge-сессий (на посреднике X)
|
||||
uint64_t next_bridge_session_id; ///< Счётчик session_id для новых bridge-сессий
|
||||
};
|
||||
|
||||
/* ==================== Жизненный цикл ==================== */
|
||||
@@ -383,46 +438,32 @@ void conn_mgr_destroy(struct CONN_MGR* mgr);
|
||||
|
||||
/**
|
||||
* @brief Запускает асинхронное подключение к ноде.
|
||||
* @param mgr менеджер
|
||||
* @param node_id идентификатор целевой ноды
|
||||
* @param idle_timeout_ms таймаут неактивности (мс), 0 = без таймаута
|
||||
* @param cb callback результата (CONN_MGR_OK, CONN_MGR_ERR_TIMEOUT, CONN_MGR_ERR_UNREACHABLE и т.д.)
|
||||
* @param cb_arg пользовательский аргумент для callback
|
||||
* @return CONN_MGR_OK если процесс запущен, CONN_MGR_ERR_* при ошибке
|
||||
*
|
||||
* @note Если нода уже подключена — сразу вызывает callback с CONN_MGR_OK и возвращает CONN_MGR_OK.
|
||||
* @note Если нода в процессе подключения — добавляет callback в список ожидания.
|
||||
* @note Автоматически определяет наличие BGP-соединения (уже существующий ETCP-линк).
|
||||
* @return CONN_MGR_HANDLE* при успехе, NULL при ошибке (cb вызван с CONN_MGR_ERR_*)
|
||||
*/
|
||||
int conn_mgr_connect_node(struct CONN_MGR* mgr, uint64_t node_id,
|
||||
struct CONN_MGR_HANDLE* conn_mgr_connect_node(struct CONN_MGR* mgr, uint64_t node_id,
|
||||
uint32_t idle_timeout_ms,
|
||||
conn_mgr_connect_callback_t cb, void* cb_arg);
|
||||
|
||||
/**
|
||||
* @brief Освобождает ОДИН handle (не разрывает соединение если есть другие handles).
|
||||
*/
|
||||
void conn_mgr_release_handle(struct CONN_MGR_HANDLE* h);
|
||||
|
||||
/**
|
||||
* @brief Разрывает подключение к ноде.
|
||||
* @param mgr менеджер
|
||||
* @param node_id идентификатор ноды
|
||||
* @return CONN_MGR_OK или CONN_MGR_ERR_NOT_FOUND
|
||||
*
|
||||
* Отправляет DISCONNECT-пакет целевой ноде, сбрасывает conn_mgr_type в NODEINFO_Q,
|
||||
* уничтожает запись entry.
|
||||
* Отправляет DISCONNECT-пакет целевой ноде (через etcp_router).
|
||||
* Для INDIRECT — также отправляет BRIDGE_CLOSE каждому посреднику.
|
||||
* Закрывает все handles, чистит entry.
|
||||
*/
|
||||
int conn_mgr_disconnect_node(struct CONN_MGR* mgr, uint64_t node_id);
|
||||
|
||||
/**
|
||||
* @brief Отменяет ожидающий callback подключения к ноде.
|
||||
* @param mgr менеджер
|
||||
* @param node_id идентификатор ноды
|
||||
* @param cb callback для отмены
|
||||
* @param cb_arg аргумент callback для точного сопоставления
|
||||
* @return CONN_MGR_OK или CONN_MGR_ERR_NOT_FOUND/INTERNAL
|
||||
*
|
||||
* Если callback единственный в списке — полностью отменяет попытку подключения
|
||||
* (уничтожает entry, таймеры, pending-структуры). Если есть другие callback'и —
|
||||
* только помечает этот callback как cancelled, он будет пропущен при доставке.
|
||||
* @brief Отменяет ожидающий handle подключения к ноде.
|
||||
* Если handle единственный — полностью отменяет подключение.
|
||||
* Если h == NULL — отменяет все handles для node_id.
|
||||
*/
|
||||
int conn_mgr_cancel_callback(struct CONN_MGR* mgr, uint64_t node_id,
|
||||
conn_mgr_connect_callback_t cb, void* cb_arg);
|
||||
struct CONN_MGR_HANDLE* h);
|
||||
|
||||
/* ==================== Управление idle-таймаутом ==================== */
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ static int router_send_one_flags(struct ETCP_ROUTER_CONN* rconn, const uint8_t*
|
||||
struct ETCP_CONN* conn = NULL;
|
||||
struct TOPO_GROUP* group = topo_groups_find(inst->topo_groups, rconn->group_id);
|
||||
if (group) {
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(group, rconn->remote_node_id);
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(group, rconn->remote_node_id);
|
||||
if (nq && nq->conn_mgr_type == CONN_TYPE_INDIRECT && nq->conn_mgr_intermediariy_count > 0) {
|
||||
for (uint8_t i = 0; i < nq->conn_mgr_intermediariy_count; i++) {
|
||||
conn = topo_group_find_conn_for_node(group, nq->conn_mgr_intermediaries[i]);
|
||||
@@ -434,7 +434,7 @@ static void router_retransmit_one(struct ETCP_ROUTER_CONN* rconn, struct ROUTER_
|
||||
struct ETCP_CONN* conn = NULL;
|
||||
struct TOPO_GROUP* group = topo_groups_find(inst->topo_groups, rconn->group_id);
|
||||
if (group) {
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(group, rconn->remote_node_id);
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(group, rconn->remote_node_id);
|
||||
if (nq && nq->conn_mgr_type == CONN_TYPE_INDIRECT && nq->conn_mgr_intermediariy_count > 0) {
|
||||
for (uint8_t i = 0; i < nq->conn_mgr_intermediariy_count; i++) {
|
||||
conn = topo_group_find_conn_for_node(group, nq->conn_mgr_intermediaries[i]);
|
||||
@@ -802,22 +802,24 @@ static int router_verify_signature(struct UTUN_INSTANCE* inst, struct ll_entry*
|
||||
size_t actual_payload = *pl_len - SC_SIGN_SIZE;
|
||||
uint8_t* sig = (uint8_t*)entry->dgram + SVC_ROUTE_HDR_SIZE + actual_payload;
|
||||
struct TOPO_GROUP* group = topo_groups_find(inst->topo_groups, hdr->group_id);
|
||||
struct TOPO_NODEQ* nq = group ? topo_node_find_by_id(group, hdr->src_node_id) : NULL;
|
||||
struct TOPO_GROUP_NODE* nq = group ? topo_node_find_by_id(group, hdr->src_node_id) : NULL;
|
||||
if (!nq) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router: SIGNED packet from unknown node %016llx — dropping",
|
||||
(unsigned long long)hdr->src_node_id);
|
||||
free_entry(entry); return -1;
|
||||
}
|
||||
struct TOPO_NODE* sni = topo_node_registry_find(inst->topo_groups, nq->node_id);
|
||||
if (!sni) { free_entry(entry); return -1; }
|
||||
{
|
||||
uint8_t zero[SC_PUBKEY_SIZE] = {0};
|
||||
if (memcmp(nq->node->ed25519_public_key, zero, SC_PUBKEY_SIZE) == 0) {
|
||||
if (memcmp(sni->ed25519_public_key, zero, SC_PUBKEY_SIZE) == 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router: no Ed25519 pubkey for node %016llx — dropping",
|
||||
(unsigned long long)hdr->src_node_id);
|
||||
free_entry(entry); return -1;
|
||||
}
|
||||
}
|
||||
struct sc_stream_sign_state vfy_state;
|
||||
if (sc_stream_sign_verify_init(&vfy_state, nq->node->ed25519_public_key) != SC_OK) {
|
||||
if (sc_stream_sign_verify_init(&vfy_state, sni->ed25519_public_key) != SC_OK) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router: sign_verify_init failed for node %016llx",
|
||||
(unsigned long long)hdr->src_node_id);
|
||||
free_entry(entry); return -1;
|
||||
|
||||
@@ -128,9 +128,11 @@ static void nat_detection_handle_nat_info(struct NAT_DETECTION* nd, struct TOPO_
|
||||
else if (info->nat_type == NAT_TYPE_DIRECT) verified_type = NAT_VERIFIED_DIRECT;
|
||||
else verified_type = NAT_VERIFIED_UNKNOWN;
|
||||
|
||||
if (group && group->local_node && group->local_node->node) {
|
||||
if (group && group->local_node) {
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(group->instance->topo_groups, group->local_node->node_id);
|
||||
if (!ni) return;
|
||||
int data_changed = 0;
|
||||
struct TOPO_SOCKMETA4* sm = group->local_node->node->v4_sock_meta;
|
||||
struct TOPO_SOCKMETA4* sm = ni->v4_sock_meta;
|
||||
while (sm) {
|
||||
if (sm->id == socket_id) {
|
||||
if (sm->nat_type != verified_type) { sm->nat_type = verified_type; data_changed = 1; }
|
||||
@@ -164,23 +166,23 @@ static void nat_detection_handle_nat_info(struct NAT_DETECTION* nd, struct TOPO_
|
||||
}
|
||||
|
||||
if (data_changed) {
|
||||
int prev_v4a = topo_list_count((struct _topo_head*)group->local_node->node->v4_addrs);
|
||||
int prev_v4a = topo_list_count((struct _topo_head*)ni->v4_addrs);
|
||||
topo_group_update_my_nodeinfo(group->instance, group);
|
||||
if (topo_list_count((struct _topo_head*)group->local_node->node->v4_addrs) != prev_v4a) {
|
||||
if (topo_list_count((struct _topo_head*)ni->v4_addrs) != prev_v4a) {
|
||||
group->local_node->dirty = 1;
|
||||
group->local_node->node->ver = (group->local_node->node->ver % 255) + 1;
|
||||
group->local_node->last_ver = group->local_node->node->ver;
|
||||
ni->ver = (ni->ver % 255) + 1;
|
||||
group->local_node->last_ver = ni->ver;
|
||||
}
|
||||
if (topo_list_count((struct _topo_head*)group->local_node->node->v4_addrs) == prev_v4a) {
|
||||
struct TOPO_ADDR4* a = group->local_node->node->v4_addrs;
|
||||
if (topo_list_count((struct _topo_head*)ni->v4_addrs) == prev_v4a) {
|
||||
struct TOPO_ADDR4* a = ni->v4_addrs;
|
||||
while (a) {
|
||||
if (a->type == TOPO_ADDR_INTERFACE && a->socket_id == socket_id) {
|
||||
uint32_t a_ip; memcpy(&a_ip, a->addr, 4);
|
||||
if (a_ip == nat_ip && a->port == nat_port) {
|
||||
a->type = TOPO_ADDR_NAT; a->socket_id = socket_id | 1;
|
||||
group->local_node->dirty = 1;
|
||||
group->local_node->node->ver = (group->local_node->node->ver % 255) + 1;
|
||||
group->local_node->last_ver = group->local_node->node->ver;
|
||||
ni->ver = (ni->ver % 255) + 1;
|
||||
group->local_node->last_ver = ni->ver;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT_INFO matched interface addr, updated entry type to NAT sock=%d", socket_id);
|
||||
}
|
||||
break;
|
||||
@@ -243,13 +245,13 @@ static void nat_detection_handle_nat_check_req(struct NAT_DETECTION* nd, struct
|
||||
|
||||
static void nat_detection_trigger_checks(struct NAT_DETECTION* nd);
|
||||
|
||||
static void nat_detection_on_conn_up(struct ETCP_CONN* conn, void* arg) {
|
||||
static void nat_detection_on_conn_up(struct ETCP_CONN* conn, int event, void* arg) { (void)event;
|
||||
struct NAT_DETECTION* nd = (struct NAT_DETECTION*)arg;
|
||||
if (!nd) return;
|
||||
nat_detection_trigger_checks(nd);
|
||||
}
|
||||
|
||||
static void nat_detection_on_conn_down(struct ETCP_CONN* conn, void* arg) {
|
||||
static void nat_detection_on_conn_down(struct ETCP_CONN* conn, int event, void* arg) { (void)event;
|
||||
struct NAT_DETECTION* nd = (struct NAT_DETECTION*)arg;
|
||||
if (!nd || !conn) return;
|
||||
route_ping_cancel_for_conn(nd, conn);
|
||||
@@ -264,8 +266,8 @@ static void nat_detection_new_conn_cbk(struct ETCP_CONN* conn, void* arg) {
|
||||
if (!conn || !conn->instance) return;
|
||||
struct NAT_DETECTION* nd = (struct NAT_DETECTION*)arg;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "NAT detection set callbacks: %s", conn->log_name);
|
||||
etcp_conn_add_up_cbk(conn, nat_detection_on_conn_up, nd);
|
||||
etcp_conn_add_down_cbk(conn, nat_detection_on_conn_down, nd);
|
||||
etcp_conn_add_cbk(conn, nat_detection_on_conn_up, nd, ETCP_CBK_EVENT_UP);
|
||||
etcp_conn_add_cbk(conn, nat_detection_on_conn_down, nd, ETCP_CBK_EVENT_DOWN);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ void route6_table_destroy(struct ROUTE6_TABLE *table) {
|
||||
u_free(table);
|
||||
}
|
||||
|
||||
bool route6_insert(struct ROUTE6_TABLE *table, struct TOPO_NODEQ *node) {
|
||||
bool route6_insert(struct ROUTE6_TABLE *table, struct TOPO_GROUP_NODE *node) {
|
||||
if (!table || !node || !node->subnets || !node->subnets->v6_subnets) return false;
|
||||
for (const struct TOPO_SUBNET6* s = node->subnets->v6_subnets; s; s = s->next) {
|
||||
struct ll_entry *entry = queue_entry_new(ROUTE6_DATA_SIZE);
|
||||
@@ -72,7 +72,7 @@ bool route6_insert(struct ROUTE6_TABLE *table, struct TOPO_NODEQ *node) {
|
||||
make_key6(rd->key, s->addr);
|
||||
make_mask6(rd->mask, s->prefix_length);
|
||||
rd->v_node_info = node;
|
||||
rd->node_id = node->node->node_id;
|
||||
rd->node_id = node->node_id;
|
||||
rd->prefix_length = s->prefix_length;
|
||||
struct radix_node *rn = rn_addroute(rd->key, rd->mask, &table->rnh->rh, rd->rn_nodes);
|
||||
if (!rn) { queue_entry_free(entry); continue; }
|
||||
@@ -81,9 +81,9 @@ bool route6_insert(struct ROUTE6_TABLE *table, struct TOPO_NODEQ *node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void route6_delete(struct ROUTE6_TABLE *table, struct TOPO_NODEQ *node) {
|
||||
void route6_delete(struct ROUTE6_TABLE *table, struct TOPO_GROUP_NODE *node) {
|
||||
if (!table || !node) return;
|
||||
uint64_t node_id = node->node->node_id;
|
||||
uint64_t node_id = node->node_id;
|
||||
struct ll_entry *entry = queue_find_data_by_index(table->queue, &node_id);
|
||||
while (entry) {
|
||||
struct ROUTE6_DATA *rd = (struct ROUTE6_DATA *)entry->data;
|
||||
|
||||
@@ -48,7 +48,7 @@ FDxx/8 - опциональные ipv6 подсети узлов /64 (если
|
||||
|
||||
struct ROUTE6_DATA {
|
||||
struct radix_node rn_nodes[2]; // scratch-буфер для rn_addroute
|
||||
struct TOPO_NODEQ *v_node_info; // узел-владелец
|
||||
struct TOPO_GROUP_NODE *v_node_info; // узел-владелец
|
||||
uint64_t node_id; // ключ для hash-поиска в ll_queue
|
||||
uint8_t prefix_length; // 0..128
|
||||
uint8_t key[17]; // sockaddr-like: {len=17, addr[16]}
|
||||
@@ -66,8 +66,8 @@ struct ROUTE6_TABLE {
|
||||
|
||||
struct ROUTE6_TABLE *route6_table_create(struct UASYNC *ua);
|
||||
void route6_table_destroy(struct ROUTE6_TABLE *table);
|
||||
bool route6_insert(struct ROUTE6_TABLE *table, struct TOPO_NODEQ *node);
|
||||
void route6_delete(struct ROUTE6_TABLE *table, struct TOPO_NODEQ *node);
|
||||
bool route6_insert(struct ROUTE6_TABLE *table, struct TOPO_GROUP_NODE *node);
|
||||
void route6_delete(struct ROUTE6_TABLE *table, struct TOPO_GROUP_NODE *node);
|
||||
const struct ROUTE6_DATA *route6_lookup(struct ROUTE6_TABLE *table, const uint8_t addr[16]);
|
||||
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
struct conn_probe_ctx {
|
||||
struct conn_probe_ctx* next; /* linked list in nq->connectivity.probe_list */
|
||||
struct UTUN_INSTANCE* instance;
|
||||
struct TOPO_NODEQ* nq;
|
||||
struct TOPO_GROUP_NODE* nq;
|
||||
uint8_t addr_type; // ADDR_TYPE_*
|
||||
struct sockaddr_storage target_addr;
|
||||
uint8_t peer_pubkey[SC_PUBKEY_SIZE];
|
||||
@@ -279,10 +279,10 @@ static void conn_probe_finish(struct conn_probe_ctx* ctx, int ok) {
|
||||
if (c->pending_count == 0) {
|
||||
c->probe_status = PROBE_STATUS_DONE;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "connectivity probe DONE for node %016llx: intf=%d nat=%d real=%d",
|
||||
(unsigned long long)ctx->nq->node->node_id,
|
||||
(unsigned long long)ctx->nq->node_id,
|
||||
c->interface_status, c->nat_status, c->real_status);
|
||||
if (ctx->instance && ctx->instance->topo_sqlite_db)
|
||||
topo_node_sqlite_nodeinfo_updated(ctx->instance->topo_sqlite_db, ctx->nq->node->node_id);
|
||||
topo_node_sqlite_nodeinfo_updated(ctx->instance->topo_sqlite_db, ctx->nq->node_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,11 +291,13 @@ static void conn_probe_finish(struct conn_probe_ctx* ctx, int ok) {
|
||||
|
||||
// ---- public API ----
|
||||
|
||||
void route_connectivity_probe_node(struct UTUN_INSTANCE* instance, struct TOPO_NODEQ* nq) {
|
||||
void route_connectivity_probe_node(struct UTUN_INSTANCE* instance, struct TOPO_GROUP_NODE* nq) {
|
||||
if (!instance || !nq) return;
|
||||
if (nq->node->node_id == instance->node_id) return; // не пингуем себя
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(instance->topo_groups, nq->node_id);
|
||||
if (!ni) return;
|
||||
if (nq->node_id == instance->node_id) return; // не пингуем себя
|
||||
if (nq->connectivity.probe_status == PROBE_STATUS_IN_PROGRESS) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "probe already in progress for node %016llx", (unsigned long long)nq->node->node_id);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "probe already in progress for node %016llx", (unsigned long long)nq->node_id);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -312,9 +314,9 @@ void route_connectivity_probe_node(struct UTUN_INSTANCE* instance, struct TOPO_N
|
||||
int pend = 0;
|
||||
|
||||
// ---- IPv4 addresses ----
|
||||
if (nq->node && nq->node->v4_addrs) {
|
||||
if (ni->v4_addrs) {
|
||||
uint32_t seen_ips[16]; uint16_t seen_ports[16]; int seen_count = 0;
|
||||
for (const struct TOPO_ADDR4* a = nq->node->v4_addrs; a; a = a->next) {
|
||||
for (const struct TOPO_ADDR4* a = ni->v4_addrs; a; a = a->next) {
|
||||
uint32_t ip; memcpy(&ip, a->addr, 4); uint16_t port = a->port;
|
||||
if (ip == 0 || port == 0) continue;
|
||||
int dup = 0; for (int j = 0; j < seen_count; j++) { if (seen_ips[j] == ip && seen_ports[j] == port) { dup = 1; break; } }
|
||||
@@ -331,7 +333,7 @@ void route_connectivity_probe_node(struct UTUN_INSTANCE* instance, struct TOPO_N
|
||||
|
||||
struct conn_probe_ctx* ctx = u_calloc(1, sizeof(struct conn_probe_ctx)); if (!ctx) continue;
|
||||
ctx->instance = instance; ctx->nq = nq; ctx->addr_type = a->type; ctx->target_addr = target;
|
||||
memcpy(ctx->peer_pubkey, nq->node->public_key, SC_PUBKEY_SIZE);
|
||||
memcpy(ctx->peer_pubkey, ni->public_key, SC_PUBKEY_SIZE);
|
||||
memcpy(ctx->candidate_sockets, candidates, cand_count * sizeof(struct ETCP_SOCKET*));
|
||||
ctx->candidate_count = cand_count; ctx->candidate_index = 0; ctx->count_total = CONN_PROBE_COUNT; ctx->timeout_ms = CONN_PROBE_TIMEOUT_MS; ctx->best_across_sockets = 65535;
|
||||
ctx->next = (struct conn_probe_ctx*)nq->connectivity.probe_list; nq->connectivity.probe_list = ctx; pend++;
|
||||
@@ -340,9 +342,9 @@ void route_connectivity_probe_node(struct UTUN_INSTANCE* instance, struct TOPO_N
|
||||
}
|
||||
|
||||
// ---- IPv6 addresses ----
|
||||
if (nq->node && nq->node->v6_addrs) {
|
||||
if (ni->v6_addrs) {
|
||||
uint8_t seen_ip6s[16][16]; uint16_t seen_ports6[16]; int seen6_count = 0;
|
||||
for (const struct TOPO_ADDR6* a6 = nq->node->v6_addrs; a6; a6 = a6->next) {
|
||||
for (const struct TOPO_ADDR6* a6 = ni->v6_addrs; a6; a6 = a6->next) {
|
||||
if (a6->port == 0) continue;
|
||||
int zero = 1; for (int z = 0; z < 16; z++) if (a6->addr[z] != 0) { zero = 0; break; } if (zero) continue;
|
||||
int dup = 0; for (int j = 0; j < seen6_count; j++) { if (memcmp(seen_ip6s[j], a6->addr, 16) == 0 && seen_ports6[j] == a6->port) { dup = 1; break; } }
|
||||
@@ -360,7 +362,7 @@ void route_connectivity_probe_node(struct UTUN_INSTANCE* instance, struct TOPO_N
|
||||
|
||||
struct conn_probe_ctx* ctx = u_calloc(1, sizeof(struct conn_probe_ctx)); if (!ctx) continue;
|
||||
ctx->instance = instance; ctx->nq = nq; ctx->addr_type = a6->type; ctx->target_addr = target;
|
||||
memcpy(ctx->peer_pubkey, nq->node->public_key, SC_PUBKEY_SIZE);
|
||||
memcpy(ctx->peer_pubkey, ni->public_key, SC_PUBKEY_SIZE);
|
||||
memcpy(ctx->candidate_sockets, candidates, cand_count * sizeof(struct ETCP_SOCKET*));
|
||||
ctx->candidate_count = cand_count; ctx->candidate_index = 0; ctx->count_total = CONN_PROBE_COUNT; ctx->timeout_ms = CONN_PROBE_TIMEOUT_MS; ctx->best_across_sockets = 65535;
|
||||
ctx->next = (struct conn_probe_ctx*)nq->connectivity.probe_list; nq->connectivity.probe_list = ctx; pend++;
|
||||
@@ -370,24 +372,24 @@ void route_connectivity_probe_node(struct UTUN_INSTANCE* instance, struct TOPO_N
|
||||
|
||||
if (pend == 0) {
|
||||
nq->connectivity.probe_status = PROBE_STATUS_DONE;
|
||||
if (!nq->node->v4_addrs && !nq->node->v6_addrs) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "no addresses to probe for node %016llx", (unsigned long long)nq->node->node_id);
|
||||
if (!ni->v4_addrs && !ni->v6_addrs) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "no addresses to probe for node %016llx", (unsigned long long)ni->node_id);
|
||||
}
|
||||
} else {
|
||||
nq->connectivity.pending_count = pend;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "connectivity probe started for node %016llx: %d series pending",
|
||||
(unsigned long long)nq->node->node_id, pend);
|
||||
(unsigned long long)ni->node_id, pend);
|
||||
}
|
||||
}
|
||||
|
||||
void route_connectivity_cancel_node(struct UTUN_INSTANCE* instance, struct TOPO_NODEQ* nq) {
|
||||
void route_connectivity_cancel_node(struct UTUN_INSTANCE* instance, struct TOPO_GROUP_NODE* nq) {
|
||||
if (!instance || !nq) return;
|
||||
nq->connectivity.probe_status = PROBE_STATUS_NONE;
|
||||
nq->connectivity.pending_count = 0;
|
||||
struct conn_probe_ctx* ctx = (struct conn_probe_ctx*)nq->connectivity.probe_list;
|
||||
while (ctx) { ctx->nq = NULL; ctx = ctx->next; }
|
||||
nq->connectivity.probe_list = NULL;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "connectivity probe cancelled for node %016llx", (unsigned long long)nq->node->node_id);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "connectivity probe cancelled for node %016llx", (unsigned long long)nq->node_id);
|
||||
}
|
||||
|
||||
void route_connectivity_cancel_all(struct UTUN_INSTANCE* instance) {
|
||||
@@ -396,7 +398,7 @@ void route_connectivity_cancel_all(struct UTUN_INSTANCE* instance) {
|
||||
int count = 0;
|
||||
struct ll_entry* e = group->nodes->head;
|
||||
while (e) {
|
||||
struct TOPO_NODEQ* nq = (struct TOPO_NODEQ*)e;
|
||||
struct TOPO_GROUP_NODE* nq = (struct TOPO_GROUP_NODE*)e;
|
||||
nq->connectivity.probe_status = PROBE_STATUS_NONE;
|
||||
nq->connectivity.pending_count = 0;
|
||||
e = e->next;
|
||||
|
||||
@@ -13,11 +13,11 @@ struct UTUN_INSTANCE;
|
||||
|
||||
// Запускает зондирование связности ко всем адресам удалённого узла
|
||||
void route_connectivity_probe_node(struct UTUN_INSTANCE* instance,
|
||||
struct TOPO_NODEQ* nq);
|
||||
struct TOPO_GROUP_NODE* nq);
|
||||
|
||||
// Отменяет все pending пробы для узла (при удалении / withdraw)
|
||||
void route_connectivity_cancel_node(struct UTUN_INSTANCE* instance,
|
||||
struct TOPO_NODEQ* nq);
|
||||
struct TOPO_GROUP_NODE* nq);
|
||||
|
||||
// Отменяет все pending пробы для всех узлов (при destroy)
|
||||
void route_connectivity_cancel_all(struct UTUN_INSTANCE* instance);
|
||||
|
||||
@@ -136,7 +136,7 @@ void route_table_destroy(struct ROUTE_TABLE *table) {
|
||||
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "count=%zu", table->count);
|
||||
|
||||
// v_node_info — внешний объект (TOPO_NODEQ), память им не управляем
|
||||
// v_node_info — внешний объект (TOPO_GROUP_NODE), память им не управляем
|
||||
u_free(table->dynamic_subnets);
|
||||
u_free(table->local_subnets);
|
||||
u_free(table->entries);
|
||||
@@ -145,7 +145,7 @@ void route_table_destroy(struct ROUTE_TABLE *table) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Routing table destroyed");
|
||||
}
|
||||
|
||||
bool route_insert(struct ROUTE_TABLE *table, struct TOPO_NODEQ *node) {
|
||||
bool route_insert(struct ROUTE_TABLE *table, struct TOPO_GROUP_NODE *node) {
|
||||
if (!table || !node) { DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "invalid arguments"); return false; }
|
||||
|
||||
if (!node->subnets || !node->subnets->v4_subnets) {
|
||||
@@ -184,13 +184,13 @@ bool route_insert(struct ROUTE_TABLE *table, struct TOPO_NODEQ *node) {
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "added %zu route(s) for node=%016llx",
|
||||
count, (unsigned long long)node->node->node_id);
|
||||
count, (unsigned long long)node->node_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
void route_delete(struct ROUTE_TABLE *table, struct TOPO_NODEQ *node) {
|
||||
void route_delete(struct ROUTE_TABLE *table, struct TOPO_GROUP_NODE *node) {
|
||||
if (!table || !node) return;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "removing all routes for node=%016llx", (unsigned long long)node->node->node_id);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "removing all routes for node=%016llx", (unsigned long long)node->node_id);
|
||||
size_t i = 0, removed = 0;
|
||||
while (i < table->count) {
|
||||
if (table->entries[i].v_node_info == node) {
|
||||
|
||||
@@ -15,7 +15,7 @@ extern "C" {
|
||||
struct ETCP_CONNECTIONS;
|
||||
struct ROUTE_TABLE;
|
||||
struct ROUTE_ENTRY;
|
||||
struct TOPO_NODEQ;
|
||||
struct TOPO_GROUP_NODE;
|
||||
|
||||
/**
|
||||
* @brief Флаги узла
|
||||
@@ -34,7 +34,7 @@ typedef enum {
|
||||
struct ROUTE_ENTRY {
|
||||
uint32_t network; // Сетевой адрес (big-endian)
|
||||
uint8_t prefix_length; // Длина префикса подсети
|
||||
struct TOPO_NODEQ* v_node_info; // узел владелец этих маршрутов. null если - локальный маршрут.
|
||||
struct TOPO_GROUP_NODE* v_node_info; // узел владелец этих маршрутов. null если - локальный маршрут.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -79,7 +79,7 @@ void route_table_destroy(struct ROUTE_TABLE *table);
|
||||
*
|
||||
* @return true если вставка/обновление успешно
|
||||
*/
|
||||
bool route_insert(struct ROUTE_TABLE *table, struct TOPO_NODEQ *node);
|
||||
bool route_insert(struct ROUTE_TABLE *table, struct TOPO_GROUP_NODE *node);
|
||||
|
||||
/**
|
||||
* @brief Удаляет все записи из таблицы маршрутизации для указанного узла
|
||||
@@ -87,7 +87,7 @@ bool route_insert(struct ROUTE_TABLE *table, struct TOPO_NODEQ *node);
|
||||
* @param table Указатель на таблицу маршрутизации
|
||||
* @param node узел, все маршруты которого нужно удалить
|
||||
*/
|
||||
void route_delete(struct ROUTE_TABLE *table, struct TOPO_NODEQ *node);
|
||||
void route_delete(struct ROUTE_TABLE *table, struct TOPO_GROUP_NODE *node);
|
||||
|
||||
/**
|
||||
* @brief Выполняет поиск маршрута для заданного IP-адреса
|
||||
|
||||
@@ -349,7 +349,7 @@ void route_ping_handle_req(struct NAT_DETECTION* nd, struct TOPO_GROUP* group,
|
||||
|
||||
{
|
||||
if (group) {
|
||||
struct TOPO_NODEQ* req_nq = topo_node_find_by_id(group, from_conn->peer_node_id);
|
||||
struct TOPO_GROUP_NODE* req_nq = topo_node_find_by_id(group, from_conn->peer_node_id);
|
||||
if (req_nq) req_nq->connectivity.ping_req_time = get_time_tb();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,13 +138,14 @@ void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry, uint64_t
|
||||
return;
|
||||
}
|
||||
|
||||
struct TOPO_NODEQ* nq = route->v_node_info;
|
||||
if (!nq || !nq->node || nq->hop_count == 0) {
|
||||
struct TOPO_GROUP_NODE* nq = route->v_node_info;
|
||||
struct TOPO_NODE* rni = nq ? topo_node_registry_find(instance->topo_groups, nq->node_id) : NULL;
|
||||
if (!nq || !rni || nq->hop_count == 0) {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "Local route to %s", ip_to_str(&addr, AF_INET).str);
|
||||
} else {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_pkt: sending %zu bytes to node %016llx dst=%s",
|
||||
ip_len, (unsigned long long)nq->node->node_id, ip_to_str(&addr, AF_INET).str);
|
||||
int send_err = etcp_route_send(instance, nq->node->group_id, nq->node->node_id, entry, 1);
|
||||
ip_len, (unsigned long long)nq->node_id, ip_to_str(&addr, AF_INET).str);
|
||||
int send_err = etcp_route_send(instance, rni->group_id, nq->node_id, entry, 1);
|
||||
if (send_err != 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_pkt: etcp_route_send failed: dst=%s err=%d",
|
||||
ip_to_str(&addr, AF_INET).str, send_err);
|
||||
|
||||
@@ -62,7 +62,7 @@ static void topo_group_send_table_complete(struct TOPO_GROUP* group, struct ETCP
|
||||
}
|
||||
|
||||
static void topo_group_add_to_senders(struct TOPO_GROUP* group, struct ETCP_CONN* conn);
|
||||
static bool topo_group_should_send_to(const struct TOPO_NODEQ* nq, uint64_t target_id);
|
||||
static bool topo_group_should_send_to(const struct TOPO_GROUP_NODE* nq, uint64_t target_id);
|
||||
static void topo_group_send_full_table(struct TOPO_GROUP* group, struct ETCP_CONN* conn);
|
||||
static void topo_group_handle_request_table(struct TOPO_GROUP* group, struct ETCP_CONN* conn);
|
||||
|
||||
@@ -173,6 +173,7 @@ static void topo_group_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP recv %s from %s len=%zu group=%016llx", group_subcmd_name(subcmd), from_conn->log_name, entry->len, (unsigned long long)pkt_group_id);
|
||||
if (subcmd == TOPO_SUBCMD_NODEINFO) { DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "BGP recv NODEINFO from=%s nid=%016llx ver=%d grp=%016llx", from_conn->log_name, (unsigned long long)((struct TOPOMSG_NODEINFO_PKT*)data)->node.node_id, ((struct TOPOMSG_NODEINFO_PKT*)data)->node.ver, (unsigned long long)((struct TOPOMSG_NODEINFO_PKT*)data)->node.group_id); }
|
||||
|
||||
if (subcmd == TOPO_SUBCMD_NODEINFO) { nodeinfo_dump_log(data, entry->len); topo_group_process_nodeinfo(group, from_conn, data, entry->len); }
|
||||
else if (subcmd == TOPO_SUBCMD_WITHDRAW) topo_group_process_withdraw(group, from_conn, data, entry->len);
|
||||
@@ -219,7 +220,7 @@ static struct TOPO_GROUP* topo_group_create(struct UTUN_INSTANCE* instance, uint
|
||||
sc_derive_ed25519_pubkey(instance->my_keys.private_key, group->ed25519_public_key);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Ed25519 pubkey derived from X25519 private key");
|
||||
|
||||
group->nodes = queue_new(instance->ua, BGP_NODES_HASH_SIZE, offsetof(struct TOPO_NODEQ, hash_node_id) - sizeof(struct ll_entry), 8, "group_nodes");
|
||||
group->nodes = queue_new(instance->ua, BGP_NODES_HASH_SIZE, offsetof(struct TOPO_GROUP_NODE, node_id) - sizeof(struct ll_entry), 8, "group_nodes");
|
||||
if (!group->nodes) { queue_entry_free(qe); DEBUG_ERROR(DEBUG_CATEGORY_BGP, "nodes queue creation failed"); return NULL; }
|
||||
|
||||
group->senders_list = queue_new(instance->ua, 0, 0, 0, "group_senders");
|
||||
@@ -245,7 +246,7 @@ static void topo_group_destroy(struct TOPO_GROUP* group) {
|
||||
while ((e = queue_data_get(group->senders_list)) != NULL) queue_entry_free(e);
|
||||
queue_free(group->senders_list);
|
||||
|
||||
if (group->local_node) { topo_node_free_lists(group, group->local_node); u_free(group->local_node); }
|
||||
if (group->local_node) { topo_nodeq_free_group_fields(group->instance->topo_groups, group->local_node); u_free(group->local_node); }
|
||||
|
||||
if (group->nodes) queue_free(group->nodes);
|
||||
group->conn_mgr = NULL; /* destroyed externally in utun_instance_destroy before etcp_router_destroy */
|
||||
@@ -334,7 +335,7 @@ void topo_groups_destroy(struct UTUN_INSTANCE* instance) {
|
||||
while ((re = queue_data_get(g->node_registry)) != NULL) {
|
||||
struct TOPO_NODE* node;
|
||||
memcpy(&node, re->data + 8, sizeof(node));
|
||||
topo_node_unref(node);
|
||||
topo_node_registry_unref(g, node->node_id);
|
||||
queue_entry_free(re);
|
||||
}
|
||||
queue_free(g->node_registry);
|
||||
@@ -404,7 +405,7 @@ void topo_group_new_conn(struct TOPO_GROUP* group, struct ETCP_CONN* conn) {
|
||||
|
||||
topo_recovery_cancel_for_node(group, conn->peer_node_id);
|
||||
|
||||
struct TOPO_NODEQ* peer_nq = topo_node_find_by_id(group, conn->peer_node_id);
|
||||
struct TOPO_GROUP_NODE* peer_nq = topo_node_find_by_id(group, conn->peer_node_id);
|
||||
topo_group_add_to_senders(group, conn);
|
||||
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "topo_group_new_conn: peer=%016llx group=%016llx type=%d ch=%s", (unsigned long long)conn->peer_node_id, (unsigned long long)group->group_id, group->group_type, group->channel_id);
|
||||
@@ -430,16 +431,16 @@ void topo_group_remove_conn(struct TOPO_GROUP* group, struct ETCP_CONN* conn) {
|
||||
struct ll_entry* node_entry = group->nodes ? group->nodes->head : NULL;
|
||||
while (node_entry) {
|
||||
struct ll_entry* next = node_entry->next;
|
||||
struct TOPO_NODEQ* nq = (struct TOPO_NODEQ*)node_entry;
|
||||
struct TOPO_GROUP_NODE* nq = (struct TOPO_GROUP_NODE*)node_entry;
|
||||
if (topo_group_remove_path(nq, conn) == 1) {
|
||||
uint64_t key = nq->hash_node_id;
|
||||
uint64_t key = nq->node_id;
|
||||
if (key != conn->peer_node_id) { topo_recovery_add_node(group, nq, conn->peer_node_id); cascaded++; }
|
||||
if (group->group_type != TOPO_GROUP_TYPE_CHAT && rt) route_delete(rt, nq);
|
||||
if (conn->instance && conn->instance->control_srv) control_server_notify_node_removed(conn->instance->control_srv, key);
|
||||
nq->dirty = 1;
|
||||
route_connectivity_cancel_node(conn->instance, nq);
|
||||
if (nq->paths) { queue_free(nq->paths); nq->paths = NULL; }
|
||||
topo_node_free_lists(group, nq);
|
||||
topo_nodeq_free_group_fields(group->instance->topo_groups, nq);
|
||||
struct ll_entry* entry = node_entry;
|
||||
if (entry) { queue_remove_data(group->nodes, entry); queue_entry_free(entry); }
|
||||
nodes_removed++;
|
||||
@@ -468,7 +469,9 @@ void topo_group_remove_conn(struct TOPO_GROUP* group, struct ETCP_CONN* conn) {
|
||||
|
||||
struct ETCP_CONN* topo_group_find_conn_for_node(struct TOPO_GROUP* group, uint64_t node_id) {
|
||||
if (!group) return NULL;
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(group, node_id);
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(group, node_id);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "find_conn_for_node %016llx: nq=%p paths=%p head=%p",
|
||||
(unsigned long long)node_id, (void*)nq, nq ? (void*)nq->paths : NULL, (nq && nq->paths) ? (void*)nq->paths->head : NULL);
|
||||
if (!nq || !nq->paths || !nq->paths->head) return NULL;
|
||||
struct ll_entry* e = nq->paths->head;
|
||||
struct TOPO_NODEPATH* best_live = NULL; uint8_t best_live_hops = 255;
|
||||
@@ -482,7 +485,7 @@ struct ETCP_CONN* topo_group_find_conn_for_node(struct TOPO_GROUP* group, uint64
|
||||
return best_live ? best_live->conn : (best_any ? best_any->conn : NULL);
|
||||
}
|
||||
|
||||
int topo_group_add_path(struct TOPO_NODEQ* nq, struct ETCP_CONN* conn, uint64_t* hop_list, uint8_t hop_count, uint16_t cumulative_rtt) {
|
||||
int topo_group_add_path(struct TOPO_GROUP_NODE* nq, struct ETCP_CONN* conn, uint64_t* hop_list, uint8_t hop_count, uint16_t cumulative_rtt) {
|
||||
if (!nq || !conn || hop_count > MAX_HOPS || !hop_list) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "add_path: invalid args"); return -1; }
|
||||
if (!nq->paths) { nq->paths = queue_new(conn->instance->ua, 0, 0, 0, "node_paths"); if (!nq->paths) return -1; }
|
||||
size_t path_size = sizeof(struct TOPO_NODEPATH) - sizeof(struct ll_entry) + hop_count * 8;
|
||||
@@ -494,7 +497,7 @@ int topo_group_add_path(struct TOPO_NODEQ* nq, struct ETCP_CONN* conn, uint64_t*
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int topo_group_remove_path_by_hop(struct TOPO_NODEQ* nq, uint64_t wd_source) {
|
||||
static int topo_group_remove_path_by_hop(struct TOPO_GROUP_NODE* nq, uint64_t wd_source) {
|
||||
if (!nq || !nq->paths) return 0;
|
||||
int removed = 0;
|
||||
struct ll_entry* e = nq->paths->head;
|
||||
@@ -509,7 +512,7 @@ static int topo_group_remove_path_by_hop(struct TOPO_NODEQ* nq, uint64_t wd_sour
|
||||
return removed;
|
||||
}
|
||||
|
||||
int topo_group_remove_path(struct TOPO_NODEQ* nq, struct ETCP_CONN* conn) {
|
||||
int topo_group_remove_path(struct TOPO_GROUP_NODE* nq, struct ETCP_CONN* conn) {
|
||||
if (!nq || !conn || !nq->paths) return -1;
|
||||
struct ll_entry* e = nq->paths->head;
|
||||
while (e) { struct TOPO_NODEPATH* path = (struct TOPO_NODEPATH*)e; if (path->conn == conn) { queue_remove_data(nq->paths, e); queue_entry_free(e); break; } e = e->next; }
|
||||
@@ -540,8 +543,8 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
|
||||
struct TOPOMSG_NODE* ni = &pkt->node;
|
||||
|
||||
if (ni->group_id != group->group_id) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "NODEINFO group_id mismatch from %s: expected=%016llx got=%016llx",
|
||||
from->log_name, (unsigned long long)group->group_id, (unsigned long long)ni->group_id);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "NODEINFO group_id mismatch from %s: expected=%016llx got=%016llx nid=%016llx",
|
||||
from->log_name, (unsigned long long)group->group_id, (unsigned long long)ni->group_id, (unsigned long long)ni->node_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -561,8 +564,10 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
|
||||
if (ni->hop_count >= MAX_HOPS) { DEBUG_WARN(DEBUG_CATEGORY_BGP, "NODEINFO from %s dropped: too many hops (%d)", from->log_name, ni->hop_count); return -1; }
|
||||
if (node_id == group->instance->node_id) return 0;
|
||||
|
||||
struct TOPO_NODEQ* nodeinfo1 = topo_node_find_by_id(group, node_id);
|
||||
struct TOPO_GROUP_NODE* nodeinfo1 = topo_node_find_by_id(group, node_id);
|
||||
uint8_t new_ver = ni->ver;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "process_nodeinfo: nid=%016llx ver=%d hops=%d nodeinfo1=%p from=%s",
|
||||
(unsigned long long)node_id, new_ver, ni->hop_count, (void*)nodeinfo1, from->log_name);
|
||||
|
||||
if (nodeinfo1 && (int8_t)(nodeinfo1->last_ver - new_ver) >= 0) {
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "NODEINFO skip (stale ver): node=%016llx cur_ver=%d new_ver=%d from=%s", (unsigned long long)node_id, nodeinfo1->last_ver, new_ver, from->log_name);
|
||||
@@ -585,7 +590,7 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
|
||||
struct ll_queue* paths = NULL;
|
||||
int is_new_node = 0;
|
||||
if (nodeinfo1) {
|
||||
topo_node_free_lists(group, nodeinfo1);
|
||||
topo_nodeq_free_group_fields(group->instance->topo_groups, nodeinfo1);
|
||||
paths = nodeinfo1->paths; nodeinfo1->paths = NULL;
|
||||
} else { is_new_node = 1; }
|
||||
|
||||
@@ -597,10 +602,12 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
|
||||
uint64_t* new_hop_list = NULL; uint8_t new_hop_count = 0;
|
||||
uint16_t incoming_cumulative_rtt = 0;
|
||||
if (topo_node_deserialize(group, ser_data, ser_len, &new_ni, &new_subnets, &new_tranzit, &new_tranzit_count, &new_hop_list, &new_hop_count, &incoming_cumulative_rtt) != 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "NODEINFO deserialize failed from %s", from->log_name);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "NODEINFO deserialize failed from %s nid=%016llx", from->log_name, (unsigned long long)node_id);
|
||||
if (nodeinfo1) { queue_remove_data(group->nodes, &nodeinfo1->ll); queue_free(paths); queue_entry_free(&nodeinfo1->ll); }
|
||||
return -1;
|
||||
}
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "NODEINFO deserialized: nid=%016llx new_ver=%d flags=0x%02x ed=%016llx",
|
||||
(unsigned long long)node_id, new_ni->ver, new_ni->flags, *(uint64_t*)new_ni->ed25519_public_key);
|
||||
|
||||
/* verify Ed25519 self-signature: Ed25519_pubkey must sign X25519_pubkey */
|
||||
{
|
||||
@@ -611,7 +618,7 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
|
||||
} else if (sc_ed25519_verify(new_ni->ed25519_public_key, new_ni->public_key, SC_PUBKEY_SIZE, new_ni->x25519_self_sig) != SC_OK) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "NODEINFO x25519_self_sig VERIFY FAIL node=%016llx ed_pubkey=%016llx... from=%s — rejecting as forgery",
|
||||
(unsigned long long)node_id, ekchk, from->log_name);
|
||||
topo_node_free_raw(group->instance->topo_groups, new_ni);
|
||||
topo_node_destroy(group->instance->topo_groups, new_ni);
|
||||
u_free(new_subnets); u_free(new_tranzit); u_free(new_hop_list);
|
||||
if (nodeinfo1) { queue_remove_data(group->nodes, &nodeinfo1->ll); queue_free(paths); queue_entry_free(&nodeinfo1->ll); }
|
||||
return -1;
|
||||
@@ -622,8 +629,13 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
|
||||
}
|
||||
|
||||
if (nodeinfo1) {
|
||||
nodeinfo1->node = topo_node_registry_acquire(group->instance->topo_groups, new_ni);
|
||||
nodeinfo1->hash_node_id = nodeinfo1->node ? nodeinfo1->node->node_id : 0;
|
||||
{ struct TOPO_NODE* stored = topo_node_registry_store(group->instance->topo_groups, new_ni);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "NODEINFO update: stored=%p new_ni=%p same=%d nid=%016llx",
|
||||
(void*)stored, (void*)new_ni, stored == new_ni, (unsigned long long)(stored ? stored->node_id : 0));
|
||||
if (stored != new_ni) new_ni = stored; }
|
||||
new_ni->group_id = group->group_id;
|
||||
new_ni->flags = pkt->node.flags;
|
||||
nodeinfo1->node_id = new_ni ? new_ni->node_id : 0;
|
||||
nodeinfo1->subnets = new_subnets;
|
||||
nodeinfo1->cumulative_rtt = incoming_cumulative_rtt;
|
||||
u_free(nodeinfo1->tranzit_data); nodeinfo1->tranzit_data = new_tranzit;
|
||||
@@ -631,12 +643,17 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
|
||||
u_free(nodeinfo1->hop_list); nodeinfo1->hop_list = new_hop_list;
|
||||
nodeinfo1->hop_count = new_hop_count;
|
||||
} else {
|
||||
struct ll_entry* qe = queue_entry_new(sizeof(struct TOPO_NODEQ));
|
||||
if (!qe) { topo_node_free_raw(group->instance->topo_groups, new_ni); u_free(new_tranzit); u_free(new_hop_list); u_free(new_subnets); return -1; }
|
||||
nodeinfo1 = (struct TOPO_NODEQ*)qe;
|
||||
struct ll_entry* qe = queue_entry_new(sizeof(struct TOPO_GROUP_NODE));
|
||||
if (!qe) { topo_node_destroy(group->instance->topo_groups, new_ni); u_free(new_tranzit); u_free(new_hop_list); u_free(new_subnets); return -1; }
|
||||
nodeinfo1 = (struct TOPO_GROUP_NODE*)qe;
|
||||
memset((uint8_t*)nodeinfo1 + sizeof(struct ll_entry), 0, sizeof(*nodeinfo1) - sizeof(struct ll_entry));
|
||||
nodeinfo1->node = topo_node_registry_acquire(group->instance->topo_groups, new_ni);
|
||||
nodeinfo1->hash_node_id = nodeinfo1->node ? nodeinfo1->node->node_id : 0;
|
||||
{ struct TOPO_NODE* stored = topo_node_registry_store(group->instance->topo_groups, new_ni);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "NODEINFO new: stored=%p new_ni=%p same=%d nid=%016llx",
|
||||
(void*)stored, (void*)new_ni, stored == new_ni, (unsigned long long)(stored ? stored->node_id : 0));
|
||||
if (stored != new_ni) new_ni = stored; }
|
||||
new_ni->group_id = group->group_id;
|
||||
new_ni->flags = pkt->node.flags;
|
||||
nodeinfo1->node_id = new_ni ? new_ni->node_id : 0;
|
||||
nodeinfo1->subnets = new_subnets;
|
||||
nodeinfo1->cumulative_rtt = incoming_cumulative_rtt;
|
||||
nodeinfo1->tranzit_data = new_tranzit; nodeinfo1->tranzit_count = new_tranzit_count;
|
||||
@@ -667,7 +684,7 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
|
||||
if (node_id != group->instance->node_id) {
|
||||
sqlite3* sdb = group->instance->topo_sqlite_db;
|
||||
if (sdb) {
|
||||
topo_node_sqlite_node_put(sdb, nodeinfo1, ntp_time_get_seconds(group->instance));
|
||||
topo_node_sqlite_node_put(sdb, group->instance->topo_groups, nodeinfo1, ntp_time_get_seconds(group->instance));
|
||||
if (group->group_type == TOPO_GROUP_TYPE_CHAT && group->channel_id[0]) {
|
||||
topo_node_sqlite_member_put(sdb, group->channel_id, node_id, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "SQLite member_put: ch=%s node=%016llx", group->channel_id, (unsigned long long)node_id);
|
||||
@@ -708,8 +725,9 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
|
||||
if (!is_new_node) socks_changed = 1;
|
||||
|
||||
if (node_id != group->instance->node_id && (is_new_node || socks_changed)) {
|
||||
int v4a = topo_list_count((struct _topo_head*)nodeinfo1->node->v4_addrs);
|
||||
int v6a = topo_list_count((struct _topo_head*)nodeinfo1->node->v6_addrs);
|
||||
struct TOPO_NODE* tni = topo_node_registry_find(group->instance->topo_groups, nodeinfo1->node_id);
|
||||
int v4a = tni ? topo_list_count((struct _topo_head*)tni->v4_addrs) : 0;
|
||||
int v6a = tni ? topo_list_count((struct _topo_head*)tni->v6_addrs) : 0;
|
||||
if (v4a > 0 || v6a > 0) route_connectivity_probe_node(group->instance, nodeinfo1);
|
||||
}
|
||||
|
||||
@@ -721,7 +739,7 @@ int topo_group_process_withdraw(struct TOPO_GROUP* group, struct ETCP_CONN* send
|
||||
struct TOPOMSG_WITHDRAW_PKT* wp = (struct TOPOMSG_WITHDRAW_PKT*)data;
|
||||
uint64_t node_id = wp->node_id, wd_source = wp->wd_source;
|
||||
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(group, node_id);
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(group, node_id);
|
||||
if (!nq) { DEBUG_INFO(DEBUG_CATEGORY_BGP, "node not found"); return 0; }
|
||||
int ret = topo_group_remove_path_by_hop(nq, wd_source);
|
||||
if (ret == 1) {
|
||||
@@ -730,7 +748,7 @@ int topo_group_process_withdraw(struct TOPO_GROUP* group, struct ETCP_CONN* send
|
||||
nq->dirty = 1;
|
||||
route_connectivity_cancel_node(group->instance, nq);
|
||||
if (nq->paths) { queue_free(nq->paths); nq->paths = NULL; }
|
||||
topo_node_free_lists(group, nq);
|
||||
topo_nodeq_free_group_fields(group->instance->topo_groups, nq);
|
||||
struct ll_entry* entry = queue_find_data_by_index(group->nodes, &node_id);
|
||||
if (entry) { queue_remove_data(group->nodes, entry); queue_entry_free(entry); }
|
||||
topo_group_broadcast_withdraw(group, node_id, wd_source, sender);
|
||||
@@ -744,7 +762,7 @@ int topo_group_process_withdraw(struct TOPO_GROUP* group, struct ETCP_CONN* send
|
||||
return 0;
|
||||
}
|
||||
|
||||
void topo_group_send_nodeinfo(struct TOPO_GROUP* group, struct TOPO_NODEQ* node, struct ETCP_CONN* conn, uint16_t cumulative_rtt) {
|
||||
void topo_group_send_nodeinfo(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* node, struct ETCP_CONN* conn, uint16_t cumulative_rtt) {
|
||||
if (!group || !node || !conn) return;
|
||||
|
||||
size_t max_sz = sizeof(struct TOPOMSG_NODEINFO_PKT) + 4096;
|
||||
@@ -753,14 +771,17 @@ void topo_group_send_nodeinfo(struct TOPO_GROUP* group, struct TOPO_NODEQ* node,
|
||||
|
||||
p[0] = ETCP_ID_TOPO_ENTRY; p[1] = TOPO_SUBCMD_NODEINFO;
|
||||
|
||||
int ser_len = topo_node_serialize(group, node, p + 2, max_sz - 2, cumulative_rtt);
|
||||
if (ser_len < 0) { u_free(p); return; }
|
||||
struct TOPO_NODE* sni = topo_node_registry_find(group->instance->topo_groups, node->node_id);
|
||||
if (!sni) { DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "send_nodeinfo: node %016llx NOT in registry — skip forward to %s", (unsigned long long)node->node_id, conn->log_name); u_free(p); return; }
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "send_nodeinfo: node %016llx ver=%d grp=%016llx to conn=%s", (unsigned long long)node->node_id, sni->ver, (unsigned long long)sni->group_id, conn->log_name);
|
||||
int ser_len = topo_node_serialize(sni, node, p + 2, max_sz - 2, cumulative_rtt);
|
||||
if (ser_len < 0) { DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "send_nodeinfo: serialize failed for node %016llx", (unsigned long long)node->node_id); u_free(p); return; }
|
||||
|
||||
struct ll_entry* e = queue_entry_new(0);
|
||||
if (!e) { u_free(p); return; }
|
||||
e->dgram = p; e->len = (size_t)ser_len + 2;
|
||||
|
||||
if (etcp_send(conn, e) != 0) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "etcp_send NODEINFO failed"); u_free(p); queue_entry_free(e); }
|
||||
if (etcp_send(conn, e) != 0) { DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "send_nodeinfo: etcp_send FAILED for node %016llx to %s", (unsigned long long)node->node_id, conn->log_name); u_free(p); queue_entry_free(e); }
|
||||
}
|
||||
|
||||
static void topo_group_add_to_senders(struct TOPO_GROUP* group, struct ETCP_CONN* conn) {
|
||||
@@ -774,9 +795,9 @@ static void topo_group_add_to_senders(struct TOPO_GROUP* group, struct ETCP_CONN
|
||||
}
|
||||
}
|
||||
|
||||
static bool topo_group_should_send_to(const struct TOPO_NODEQ* nq, uint64_t target_id) {
|
||||
if (!nq || !nq->node || !nq->paths) return false;
|
||||
if (target_id == nq->node->node_id) return false;
|
||||
static bool topo_group_should_send_to(const struct TOPO_GROUP_NODE* nq, uint64_t target_id) {
|
||||
if (!nq || !nq->paths) return false;
|
||||
if (target_id == nq->node_id) return false;
|
||||
struct ll_entry* e = nq->paths->head;
|
||||
while (e) {
|
||||
struct TOPO_NODEPATH* path = (struct TOPO_NODEPATH*)e;
|
||||
@@ -793,7 +814,7 @@ static void topo_group_send_full_table(struct TOPO_GROUP* group, struct ETCP_CON
|
||||
uint64_t target = conn->peer_node_id;
|
||||
struct ll_entry* e = group->nodes ? group->nodes->head : NULL;
|
||||
while (e) {
|
||||
struct TOPO_NODEQ* nq = (struct TOPO_NODEQ*)e;
|
||||
struct TOPO_GROUP_NODE* nq = (struct TOPO_GROUP_NODE*)e;
|
||||
if (nq->hop_count == 0) { e = e->next; continue; }
|
||||
if (!nq->paths) { DEBUG_WARN(DEBUG_CATEGORY_BGP, "node has no paths"); e = e->next; continue; }
|
||||
if (topo_group_should_send_to(nq, target)) topo_group_send_nodeinfo(group, nq, conn, (uint16_t)((uint32_t)conn->rtt_last + nq->cumulative_rtt));
|
||||
|
||||
@@ -148,7 +148,7 @@ struct TOPO_GROUP {
|
||||
struct UTUN_INSTANCE* instance;
|
||||
struct ll_queue* senders_list;
|
||||
struct ll_queue* nodes;
|
||||
struct TOPO_NODEQ* local_node;
|
||||
struct TOPO_GROUP_NODE* local_node;
|
||||
uint8_t ed25519_public_key[SC_PUBKEY_SIZE];
|
||||
char channel_id[64]; // channel_id для групп типа CHAT
|
||||
struct CONN_MGR* conn_mgr; // менеджер соединений для этой группы
|
||||
@@ -245,7 +245,7 @@ int topo_group_process_withdraw(struct TOPO_GROUP* group, struct ETCP_CONN* send
|
||||
/**
|
||||
* @brief Отправляет NODEINFO пакет одному conn (всегда local_node).
|
||||
*/
|
||||
void topo_group_send_nodeinfo(struct TOPO_GROUP* group, struct TOPO_NODEQ* node, struct ETCP_CONN* conn, uint16_t cumulative_rtt);
|
||||
void topo_group_send_nodeinfo(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* node, struct ETCP_CONN* conn, uint16_t cumulative_rtt);
|
||||
|
||||
/**
|
||||
* @brief Отправляет WITHDRAW для node_id (вызывает broadcast_withdraw).
|
||||
@@ -268,14 +268,14 @@ struct ETCP_CONN* topo_group_find_conn_for_node(struct TOPO_GROUP* group, uint64
|
||||
*
|
||||
* @return 0 при успехе
|
||||
*/
|
||||
int topo_group_add_path(struct TOPO_NODEQ* nq, struct ETCP_CONN* conn, uint64_t* hop_list, uint8_t hop_count, uint16_t cumulative_rtt);
|
||||
int topo_group_add_path(struct TOPO_GROUP_NODE* nq, struct ETCP_CONN* conn, uint64_t* hop_list, uint8_t hop_count, uint16_t cumulative_rtt);
|
||||
|
||||
/**
|
||||
* @brief Удаляет conn из paths узла.
|
||||
*
|
||||
* @return 1 если путей не осталось (unreachable)
|
||||
*/
|
||||
int topo_group_remove_path(struct TOPO_NODEQ* nq, struct ETCP_CONN* conn);
|
||||
int topo_group_remove_path(struct TOPO_GROUP_NODE* nq, struct ETCP_CONN* conn);
|
||||
|
||||
void topo_groups_set_node_updated_cb(struct TOPO_GROUPS* groups, topo_node_updated_fn fn);
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ void topo_group_connect_on_down(struct TOPO_GROUP* group, struct ETCP_CONN* conn
|
||||
}
|
||||
|
||||
/* есть ли indirect-пути в nodeinfo? */
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(group, peer);
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(group, peer);
|
||||
if (nq && nq->paths) {
|
||||
struct ll_entry* pe = nq->paths->head;
|
||||
while (pe) {
|
||||
@@ -216,7 +216,7 @@ static void tgc_phase1_timeout(void* arg) {
|
||||
uint8_t status; uint8_t conn_type;
|
||||
conn_mgr_get_status(gc->group->conn_mgr, ids[i], &status, &conn_type);
|
||||
if (status != CONN_MGR_STATE_CONNECTED) {
|
||||
conn_mgr_cancel_callback(gc->group->conn_mgr, ids[i], tgc_phase1_result, gc);
|
||||
conn_mgr_cancel_callback(gc->group->conn_mgr, ids[i], NULL);
|
||||
topo_node_sqlite_set_connected(db, gc->group->channel_id, ids[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,17 @@
|
||||
|
||||
void topo_node_ref(struct TOPO_NODE* ni) {
|
||||
if (!ni) return;
|
||||
ni->ref_count++;
|
||||
ni->group_ref_count++;
|
||||
}
|
||||
|
||||
void topo_node_registry_ref(struct TOPO_GROUPS* groups, uint64_t node_id) {
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(groups, node_id);
|
||||
if (ni) ni->group_ref_count++;
|
||||
}
|
||||
|
||||
void topo_node_unref(struct TOPO_NODE* ni) {
|
||||
if (!ni) return;
|
||||
if (--ni->ref_count == 0) {
|
||||
if (--ni->group_ref_count == 0) {
|
||||
u_free(ni->node_name);
|
||||
u_free(ni);
|
||||
}
|
||||
@@ -60,21 +65,25 @@ void topo_node_free_raw(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni) {
|
||||
u_free(ni);
|
||||
}
|
||||
|
||||
void topo_node_free_lists(struct TOPO_GROUP* group, struct TOPO_NODEQ* nq) {
|
||||
if (!group || !nq) return;
|
||||
if (nq->node) {
|
||||
free_v4_sock_list(group->instance->topo_groups->v4_sock_meta_pool, nq->node->v4_sock_meta);
|
||||
free_v4_addr_list(group->instance->topo_groups->v4_addr_pool, nq->node->v4_addrs);
|
||||
free_v6_sock_list(group->instance->topo_groups->v6_sock_meta_pool, nq->node->v6_sock_meta);
|
||||
free_v6_addr_list(group->instance->topo_groups->v6_addr_pool, nq->node->v6_addrs);
|
||||
nq->node->v4_sock_meta = NULL; nq->node->v4_addrs = NULL;
|
||||
nq->node->v6_sock_meta = NULL; nq->node->v6_addrs = NULL;
|
||||
topo_node_registry_release(group->instance->topo_groups, nq->node);
|
||||
nq->node = NULL;
|
||||
void topo_node_destroy(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni) {
|
||||
topo_node_free_raw(groups, ni);
|
||||
}
|
||||
|
||||
void topo_nodeq_free_group_fields(struct TOPO_GROUPS* groups, struct TOPO_GROUP_NODE* nq) {
|
||||
if (!groups || !nq) return;
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(groups, nq->node_id);
|
||||
if (ni) {
|
||||
free_v4_sock_list(groups->v4_sock_meta_pool, ni->v4_sock_meta);
|
||||
free_v4_addr_list(groups->v4_addr_pool, ni->v4_addrs);
|
||||
free_v6_sock_list(groups->v6_sock_meta_pool, ni->v6_sock_meta);
|
||||
free_v6_addr_list(groups->v6_addr_pool, ni->v6_addrs);
|
||||
ni->v4_sock_meta = NULL; ni->v4_addrs = NULL;
|
||||
ni->v6_sock_meta = NULL; ni->v6_addrs = NULL;
|
||||
topo_node_registry_unref(groups, nq->node_id);
|
||||
}
|
||||
if (nq->subnets) {
|
||||
free_v4_sub_list(group->instance->topo_groups->v4_subnet_pool, nq->subnets->v4_subnets);
|
||||
free_v6_sub_list(group->instance->topo_groups->v6_subnet_pool, nq->subnets->v6_subnets);
|
||||
free_v4_sub_list(groups->v4_subnet_pool, nq->subnets->v4_subnets);
|
||||
free_v6_sub_list(groups->v6_subnet_pool, nq->subnets->v6_subnets);
|
||||
u_free(nq->subnets);
|
||||
nq->subnets = NULL;
|
||||
}
|
||||
@@ -84,7 +93,7 @@ void topo_node_free_lists(struct TOPO_GROUP* group, struct TOPO_NODEQ* nq) {
|
||||
|
||||
// ===== глобальный реестр TOPO_NODE =====
|
||||
|
||||
static struct TOPO_NODE* node_registry_find(struct TOPO_GROUPS* groups, uint64_t node_id) {
|
||||
struct TOPO_NODE* topo_node_registry_find(struct TOPO_GROUPS* groups, uint64_t node_id) {
|
||||
if (!groups || !groups->node_registry) return NULL;
|
||||
struct ll_entry* e = queue_find_data_by_index(groups->node_registry, &node_id);
|
||||
if (!e) return NULL;
|
||||
@@ -93,9 +102,9 @@ static struct TOPO_NODE* node_registry_find(struct TOPO_GROUPS* groups, uint64_t
|
||||
return node;
|
||||
}
|
||||
|
||||
struct TOPO_NODE* topo_node_registry_acquire(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni) {
|
||||
struct TOPO_NODE* topo_node_registry_store(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni) {
|
||||
if (!groups || !ni) return NULL;
|
||||
struct TOPO_NODE* existing = node_registry_find(groups, ni->node_id);
|
||||
struct TOPO_NODE* existing = topo_node_registry_find(groups, ni->node_id);
|
||||
if (existing) {
|
||||
topo_node_ref(existing);
|
||||
topo_node_free_raw(groups, ni);
|
||||
@@ -113,10 +122,11 @@ struct TOPO_NODE* topo_node_registry_acquire(struct TOPO_GROUPS* groups, struct
|
||||
return ni;
|
||||
}
|
||||
|
||||
void topo_node_registry_release(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni) {
|
||||
if (!groups || !ni) return;
|
||||
uint64_t node_id = ni->node_id;
|
||||
uint32_t prev_ref = ni->ref_count;
|
||||
void topo_node_registry_unref(struct TOPO_GROUPS* groups, uint64_t node_id) {
|
||||
if (!groups) return;
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(groups, node_id);
|
||||
if (!ni) return;
|
||||
uint32_t prev_ref = ni->group_ref_count;
|
||||
topo_node_unref(ni);
|
||||
if (prev_ref == 1) {
|
||||
struct ll_entry* e = groups->node_registry ? queue_find_data_by_index(groups->node_registry, &node_id) : NULL;
|
||||
@@ -139,9 +149,8 @@ int topo_node_dyn_size(const struct TOPOMSG_NODE* msg) {
|
||||
+ msg->hop_count * 8;
|
||||
}
|
||||
|
||||
int topo_node_serialize(struct TOPO_GROUP* group, struct TOPO_NODEQ* nq, uint8_t* out, size_t out_max, uint16_t cumulative_rtt) {
|
||||
if (!group || !nq || !nq->node || !out) return -1;
|
||||
struct TOPO_NODE* ni = nq->node;
|
||||
int topo_node_serialize(struct TOPO_NODE* ni, struct TOPO_GROUP_NODE* nq, uint8_t* out, size_t out_max, uint16_t cumulative_rtt) {
|
||||
if (!ni || !nq || !out) return -1;
|
||||
|
||||
struct TOPOMSG_NODE msg;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
@@ -224,7 +233,7 @@ int topo_node_deserialize(struct TOPO_GROUP* group, const uint8_t* data, size_t
|
||||
|
||||
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE));
|
||||
if (!ni) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "alloc TOPO_NODE failed"); return -1; }
|
||||
ni->ref_count = 0;
|
||||
ni->group_ref_count = 0;
|
||||
ni->flags = msg->flags;
|
||||
ni->group_id = msg->group_id;
|
||||
ni->node_id = msg->node_id;
|
||||
@@ -316,11 +325,11 @@ int topo_node_deserialize(struct TOPO_GROUP* group, const uint8_t* data, size_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct TOPO_NODEQ* topo_node_find_by_id(struct TOPO_GROUP* group, uint64_t node_id) {
|
||||
struct TOPO_GROUP_NODE* topo_node_find_by_id(struct TOPO_GROUP* group, uint64_t node_id) {
|
||||
if (!group || !group->nodes) return NULL;
|
||||
uint64_t key = node_id;
|
||||
struct ll_entry* e = queue_find_data_by_index(group->nodes, &key);
|
||||
return e ? (struct TOPO_NODEQ*)e : NULL;
|
||||
return e ? (struct TOPO_GROUP_NODE*)e : NULL;
|
||||
}
|
||||
|
||||
int topo_node_ping_request_cbk(struct TOPO_GROUPS* groups, uint64_t node_id) {
|
||||
@@ -329,7 +338,7 @@ int topo_node_ping_request_cbk(struct TOPO_GROUPS* groups, uint64_t node_id) {
|
||||
struct ll_entry* ge = groups->group_list->head;
|
||||
while (ge) {
|
||||
struct TOPO_GROUP* g = (struct TOPO_GROUP*)ge;
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(g, node_id);
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(g, node_id);
|
||||
if (nq) {
|
||||
struct TOPO_CONNECTIVITY* c = &nq->connectivity;
|
||||
if (c->last_ping_time == 0 || (now - c->last_ping_time) > PING_TTL_TB) {
|
||||
@@ -354,7 +363,7 @@ void topo_node_ping_update_rtt(struct TOPO_GROUPS* groups, uint64_t node_id, uin
|
||||
struct ll_entry* ge = groups->group_list->head;
|
||||
while (ge) {
|
||||
struct TOPO_GROUP* g = (struct TOPO_GROUP*)ge;
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(g, node_id);
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(g, node_id);
|
||||
if (nq) {
|
||||
nq->connectivity.last_ping_time = now;
|
||||
if (nq->connectivity.interface_min_rtt == 0 || rtt < nq->connectivity.interface_min_rtt)
|
||||
@@ -402,8 +411,8 @@ void topo_node_dump_all(struct TOPO_GROUP* group) {
|
||||
int idx = 0;
|
||||
struct ll_entry* e = group->nodes->head;
|
||||
while (e) {
|
||||
struct TOPO_NODEQ* nq = (struct TOPO_NODEQ*)e;
|
||||
struct TOPO_NODE* ni = nq->node;
|
||||
struct TOPO_GROUP_NODE* nq = (struct TOPO_GROUP_NODE*)e;
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(group->instance->topo_groups, nq->node_id);
|
||||
if (!ni) { e = e->next; continue; }
|
||||
int is_local = (group->local_node == nq);
|
||||
const char* name_s = ni->node_name ? ni->node_name : "";
|
||||
@@ -498,8 +507,8 @@ int topo_node_format_all(struct TOPO_GROUP* group, char* buf, size_t buf_size) {
|
||||
int idx = 0;
|
||||
struct ll_entry* e = group->nodes->head;
|
||||
while (e && (size_t)pos < buf_size) {
|
||||
struct TOPO_NODEQ* nq = (struct TOPO_NODEQ*)e;
|
||||
struct TOPO_NODE* ni = nq->node;
|
||||
struct TOPO_GROUP_NODE* nq = (struct TOPO_GROUP_NODE*)e;
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(group->instance->topo_groups, nq->node_id);
|
||||
if (!ni) { e = e->next; continue; }
|
||||
int is_local = (group->local_node == nq);
|
||||
const char* name_s = ni->node_name ? ni->node_name : "";
|
||||
@@ -620,9 +629,10 @@ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GR
|
||||
}
|
||||
|
||||
int changed = 1; uint8_t old_ver = 0;
|
||||
if (group->local_node && group->local_node->node) {
|
||||
struct TOPO_NODE* oni = group->local_node->node;
|
||||
old_ver = oni->ver;
|
||||
if (group->local_node) {
|
||||
struct TOPO_NODE* oni = topo_node_registry_find(instance->topo_groups, group->local_node->node_id);
|
||||
if (oni) {
|
||||
old_ver = oni->ver;
|
||||
changed = (vc != (group->local_node->subnets ? topo_list_count((struct _topo_head*)group->local_node->subnets->v4_subnets) : 0))
|
||||
|| (sock_count != topo_list_count((struct _topo_head*)oni->v4_sock_meta))
|
||||
|| (addr_count != topo_list_count((struct _topo_head*)oni->v4_addrs))
|
||||
@@ -643,23 +653,24 @@ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GR
|
||||
}
|
||||
if (group->local_node && group->instance && group->instance->topo_groups)
|
||||
if (memcmp(oni->ed25519_public_key, group->ed25519_public_key, SC_PUBKEY_SIZE) != 0) changed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
if (group->local_node) {
|
||||
if (instance->rt) route_delete(instance->rt, group->local_node);
|
||||
topo_node_free_lists(group, group->local_node);
|
||||
topo_nodeq_free_group_fields(instance->topo_groups, group->local_node);
|
||||
u_free(group->local_node);
|
||||
group->local_node = NULL;
|
||||
}
|
||||
|
||||
group->local_node = u_calloc(1, sizeof(struct TOPO_NODEQ));
|
||||
group->local_node = u_calloc(1, sizeof(struct TOPO_GROUP_NODE));
|
||||
if (!group->local_node) return -1;
|
||||
struct TOPO_NODEQ* lq = group->local_node;
|
||||
struct TOPO_GROUP_NODE* lq = group->local_node;
|
||||
|
||||
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE));
|
||||
if (!ni) { u_free(lq); group->local_node = NULL; return -1; }
|
||||
ni->ref_count = 0;
|
||||
ni->group_ref_count = 0;
|
||||
ni->flags = (group->group_type == TOPO_GROUP_TYPE_CHAT) ? 0 : TOPO_FLAG_SEND_SUBNETS;
|
||||
ni->group_id = group->group_id;
|
||||
ni->node_id = instance->node_id;
|
||||
@@ -670,8 +681,8 @@ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GR
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Ed25519 self-sign FAILED for my node=%016llx", (unsigned long long)ni->node_id);
|
||||
if (name_len) { ni->node_name = u_malloc(name_len + 1); if (ni->node_name) { memcpy(ni->node_name, instance->name, name_len); ni->node_name[name_len] = 0; } }
|
||||
|
||||
lq->node = topo_node_registry_acquire(instance->topo_groups, ni);
|
||||
lq->hash_node_id = ni->node_id;
|
||||
topo_node_registry_store(instance->topo_groups, ni);
|
||||
lq->node_id = ni->node_id;
|
||||
lq->hop_count = 0;
|
||||
lq->dirty = 1;
|
||||
lq->last_ver = ni->ver;
|
||||
@@ -757,7 +768,8 @@ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GR
|
||||
if (group->group_type != TOPO_GROUP_TYPE_CHAT && instance->rt && !route_insert(instance->rt, lq))
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "failed to insert local routes");
|
||||
} else {
|
||||
group->local_node->last_ver = group->local_node->node->ver;
|
||||
struct TOPO_NODE* lni = topo_node_registry_find(instance->topo_groups, group->local_node->node_id);
|
||||
if (lni) group->local_node->last_ver = lni->ver;
|
||||
}
|
||||
return vc;
|
||||
}
|
||||
@@ -124,9 +124,10 @@ static uint8_t collect_socket_ids(struct TOPO_NODE* ni, uint8_t* sock_ids) {
|
||||
return count;
|
||||
}
|
||||
|
||||
int topo_node_sqlite_node_put(sqlite3* db, struct TOPO_NODEQ* nq, time_t now_sec) {
|
||||
if (!db || !nq || !nq->node) return -1;
|
||||
struct TOPO_NODE* ni = nq->node;
|
||||
int topo_node_sqlite_node_put(sqlite3* db, struct TOPO_GROUPS* groups, struct TOPO_GROUP_NODE* nq, time_t now_sec) {
|
||||
if (!db || !nq) return -1;
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(groups, nq->node_id);
|
||||
if (!ni) return -1;
|
||||
|
||||
sqlite3_exec(db, "BEGIN", NULL, NULL, NULL);
|
||||
|
||||
@@ -760,7 +761,7 @@ struct TOPO_NODE* topo_node_sqlite_node_load(sqlite3* db, struct TOPO_GROUPS* gr
|
||||
|
||||
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE));
|
||||
if (!ni) { u_free(name); return NULL; }
|
||||
ni->node_id = node_id; ni->ver = 1; ni->ref_count = 0;
|
||||
ni->node_id = node_id; ni->ver = 1; ni->group_ref_count = 0;
|
||||
memcpy(ni->public_key, pubkey, 32); memcpy(ni->ed25519_public_key, ed_pubkey, 32);
|
||||
ni->node_name = name;
|
||||
ni->v4_addrs = v4_head;
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <time.h>
|
||||
|
||||
struct TOPO_NODEQ;
|
||||
struct TOPO_GROUPS;
|
||||
#include "topo_node.h"
|
||||
|
||||
#define PEERS_JOIN_SIG_SIZE 64
|
||||
#define PEERS_JOIN_TS_SIZE 8
|
||||
@@ -18,7 +16,7 @@ struct TOPO_GROUPS;
|
||||
|
||||
int topo_node_sqlite_init(sqlite3* db);
|
||||
|
||||
int topo_node_sqlite_node_put(sqlite3* db, struct TOPO_NODEQ* nq, time_t now_sec);
|
||||
int topo_node_sqlite_node_put(sqlite3* db, struct TOPO_GROUPS* groups, struct TOPO_GROUP_NODE* nq, time_t now_sec);
|
||||
|
||||
int topo_node_sqlite_channel_put(sqlite3* db, const char* channel_id,
|
||||
const char* name, uint64_t owner_node_id,
|
||||
|
||||
@@ -44,11 +44,13 @@ static void topo_recovery_ctx_free(struct TOPO_RECOVERY_CTX* ctx) {
|
||||
}
|
||||
|
||||
/* Аналог cm_has_direct_ip: есть ли адреса с прямым доступом (PUBLIC/UNKNOWN/EIM/DIRECT) */
|
||||
static int node_has_direct_ip(const struct TOPO_NODEQ* nq) {
|
||||
if (!nq || !nq->node) return 0;
|
||||
for (const struct TOPO_ADDR4* a = nq->node->v4_addrs; a; a = a->next) {
|
||||
static int node_has_direct_ip(struct TOPO_GROUP* group, const struct TOPO_GROUP_NODE* nq) {
|
||||
if (!nq) return 0;
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(group->instance->topo_groups, nq->node_id);
|
||||
if (!ni) return 0;
|
||||
for (const struct TOPO_ADDR4* a = ni->v4_addrs; a; a = a->next) {
|
||||
if (a->type != TOPO_ADDR_NAT && a->type != TOPO_ADDR_INTERFACE) continue;
|
||||
for (const struct TOPO_SOCKMETA4* m = nq->node->v4_sock_meta; m; m = m->next) {
|
||||
for (const struct TOPO_SOCKMETA4* m = ni->v4_sock_meta; m; m = m->next) {
|
||||
if (m->id != a->socket_id) continue;
|
||||
if (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)
|
||||
@@ -59,7 +61,7 @@ static int node_has_direct_ip(const struct TOPO_NODEQ* nq) {
|
||||
}
|
||||
|
||||
/* Минимальный RTT из данных connectivity-проб (interface/nat/real). 0xFFFF если неизвестен */
|
||||
static uint16_t node_get_min_rtt(const struct TOPO_NODEQ* nq) {
|
||||
static uint16_t node_get_min_rtt(const struct TOPO_GROUP_NODE* nq) {
|
||||
uint16_t rtt = 0xFFFF;
|
||||
if (nq->connectivity.interface_status == PROBE_RESULT_REACHABLE && nq->connectivity.interface_min_rtt < rtt)
|
||||
rtt = nq->connectivity.interface_min_rtt;
|
||||
@@ -74,10 +76,10 @@ static uint16_t node_get_min_rtt(const struct TOPO_NODEQ* nq) {
|
||||
* hop_list = [...узлы пути...], последний элемент = failed_peer (форвардил NODEINFO нам).
|
||||
* next_hop = элемент перед failed_peer (hop_list[hop_count-2]).
|
||||
* Если failed_peer не найден в конце — fallback: node_id сам себе next_hop. */
|
||||
static uint64_t find_next_hop(const struct TOPO_NODEQ* nq, uint64_t failed_peer) {
|
||||
static uint64_t find_next_hop(const struct TOPO_GROUP_NODE* nq, uint64_t failed_peer) {
|
||||
if (nq->hop_count >= 2 && nq->hop_list && nq->hop_list[nq->hop_count - 1] == failed_peer)
|
||||
return nq->hop_list[nq->hop_count - 2];
|
||||
return nq->hash_node_id;
|
||||
return nq->node_id;
|
||||
}
|
||||
|
||||
/* Ищет незапущенный (started==0) контекст по next_hop_id */
|
||||
@@ -117,7 +119,10 @@ static void topo_recovery_timeout_cb(void* arg) {
|
||||
ctx->connect_timer = NULL;
|
||||
uint64_t node_id = ctx->current_node_id;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "recovery: next=%016llx timeout connecting to %016llx", (unsigned long long)ctx->next_hop_id, (unsigned long long)node_id);
|
||||
conn_mgr_cancel_callback(ctx->group->conn_mgr, node_id, topo_recovery_callback, ctx);
|
||||
if (ctx->current_handle) {
|
||||
conn_mgr_cancel_callback(ctx->group->conn_mgr, node_id, ctx->current_handle);
|
||||
ctx->current_handle = NULL;
|
||||
}
|
||||
int list = ctx->current_list;
|
||||
for (size_t i = 0; i < ctx->count[list]; i++)
|
||||
if (ctx->nodes[list][i].node_id == node_id) { ctx->nodes[list][i] = ctx->nodes[list][ctx->count[list] - 1]; ctx->count[list]--; break; }
|
||||
@@ -156,9 +161,9 @@ static void topo_recovery_try_next(struct TOPO_RECOVERY_CTX* ctx) {
|
||||
(unsigned long long)ctx->next_hop_id, (unsigned long long)node_id, best->min_rtt,
|
||||
ctx->current_list == 0 ? "direct" : "indirect", best->is_next_hop ? "[next_hop]" : "");
|
||||
ctx->current_node_id = node_id;
|
||||
int rc = conn_mgr_connect_node(ctx->group->conn_mgr, node_id, 0, topo_recovery_callback, ctx);
|
||||
if (rc != CONN_MGR_OK) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_BGP, "recovery: conn_mgr_connect_node %016llx returned %d", (unsigned long long)node_id, rc);
|
||||
ctx->current_handle = conn_mgr_connect_node(ctx->group->conn_mgr, node_id, 0, topo_recovery_callback, ctx);
|
||||
if (!ctx->current_handle) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_BGP, "recovery: conn_mgr_connect_node %016llx failed", (unsigned long long)node_id);
|
||||
*best = ctx->nodes[ctx->current_list][ctx->count[ctx->current_list] - 1]; ctx->count[ctx->current_list]--;
|
||||
ctx->current_node_id = 0;
|
||||
continue;
|
||||
@@ -174,9 +179,11 @@ static void topo_recovery_try_next(struct TOPO_RECOVERY_CTX* ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
void topo_recovery_add_node(struct TOPO_GROUP* group, struct TOPO_NODEQ* nq, uint64_t failed_peer) {
|
||||
if (!group || !nq || !nq->node) return;
|
||||
uint64_t node_id = nq->hash_node_id;
|
||||
void topo_recovery_add_node(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* nq, uint64_t failed_peer) {
|
||||
if (!group || !nq) return;
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(group->instance->topo_groups, nq->node_id);
|
||||
if (!ni) return;
|
||||
uint64_t node_id = nq->node_id;
|
||||
uint64_t next_hop = find_next_hop(nq, failed_peer);
|
||||
|
||||
struct TOPO_RECOVERY_CTX* ctx = topo_recovery_find_by_next_hop(group, next_hop);
|
||||
@@ -187,7 +194,7 @@ void topo_recovery_add_node(struct TOPO_GROUP* group, struct TOPO_NODEQ* nq, uin
|
||||
group->recovery_list = ctx;
|
||||
}
|
||||
|
||||
int list = node_has_direct_ip(nq) ? 0 : 1;
|
||||
int list = node_has_direct_ip(group, nq) ? 0 : 1;
|
||||
uint16_t rtt = node_get_min_rtt(nq);
|
||||
|
||||
if (ctx->count[list] >= ctx->capacity[list]) {
|
||||
@@ -244,8 +251,8 @@ void topo_recovery_cancel_for_node(struct TOPO_GROUP* group, uint64_t node_id) {
|
||||
if (found) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "recovery: cancel next=%016llx (node %016llx came up)",
|
||||
(unsigned long long)ctx->next_hop_id, (unsigned long long)node_id);
|
||||
if (ctx->current_node_id != 0)
|
||||
conn_mgr_cancel_callback(group->conn_mgr, ctx->current_node_id, topo_recovery_callback, ctx);
|
||||
if (ctx->current_node_id != 0 && ctx->current_handle)
|
||||
conn_mgr_cancel_callback(group->conn_mgr, ctx->current_node_id, ctx->current_handle);
|
||||
if (ctx->connect_timer) { uasync_cancel_timeout(group->instance->ua, ctx->connect_timer); ctx->connect_timer = NULL; }
|
||||
*pp = ctx->next;
|
||||
topo_recovery_ctx_free(ctx);
|
||||
@@ -260,8 +267,8 @@ void topo_recovery_cancel_all(struct TOPO_GROUP* group) {
|
||||
struct TOPO_RECOVERY_CTX* ctx = group->recovery_list;
|
||||
while (ctx) {
|
||||
struct TOPO_RECOVERY_CTX* next = ctx->next;
|
||||
if (ctx->current_node_id != 0)
|
||||
conn_mgr_cancel_callback(group->conn_mgr, ctx->current_node_id, topo_recovery_callback, ctx);
|
||||
if (ctx->current_node_id != 0 && ctx->current_handle)
|
||||
conn_mgr_cancel_callback(group->conn_mgr, ctx->current_node_id, ctx->current_handle);
|
||||
if (ctx->connect_timer) { uasync_cancel_timeout(group->instance->ua, ctx->connect_timer); ctx->connect_timer = NULL; }
|
||||
topo_recovery_ctx_free(ctx);
|
||||
ctx = next;
|
||||
|
||||
@@ -29,7 +29,7 @@ extern "C" {
|
||||
#include <stddef.h>
|
||||
|
||||
struct TOPO_GROUP;
|
||||
struct TOPO_NODEQ;
|
||||
struct TOPO_GROUP_NODE;
|
||||
|
||||
#define TOPO_RECOVERY_CONNECT_TIMEOUT_MS 2000
|
||||
|
||||
@@ -49,6 +49,7 @@ struct TOPO_RECOVERY_CTX {
|
||||
size_t capacity[2]; /* выделенная ёмкость */
|
||||
int current_list; /* 0=direct, 1=indirect */
|
||||
uint64_t current_node_id; /* node_id в текущей попытке, 0=нет активной */
|
||||
struct CONN_MGR_HANDLE* current_handle; /* handle текущей попытки conn_mgr_connect_node */
|
||||
void* connect_timer; /* внешний таймер 2с (uasync) */
|
||||
uint8_t started; /* 0=сбор узлов (add_node), 1=перебор запущен */
|
||||
};
|
||||
@@ -58,7 +59,7 @@ struct TOPO_RECOVERY_CTX {
|
||||
* Вызывается из topo_group_remove_conn ДО topo_node_free_lists (нужен hop_list).
|
||||
* @param failed_peer node_id отвалившегося пира (conn->peer_node_id)
|
||||
*/
|
||||
void topo_recovery_add_node(struct TOPO_GROUP* group, struct TOPO_NODEQ* nq, uint64_t failed_peer);
|
||||
void topo_recovery_add_node(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* nq, uint64_t failed_peer);
|
||||
|
||||
/**
|
||||
* Запускает перебор узлов для всех pending-контекстов.
|
||||
|
||||
+20
-18
@@ -276,8 +276,8 @@ struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance, char* n
|
||||
|
||||
// Вызываем callback для нового соединения если установлен
|
||||
if (instance) {
|
||||
struct etcp_cbk_entry* cbe = instance->new_conn_cbks;
|
||||
while (cbe) { struct etcp_cbk_entry* n = cbe->next; cbe->fn(etcp, cbe->arg); cbe = n; }
|
||||
struct etcp_inst_cbk_entry* cbe = instance->new_conn_cbks;
|
||||
while (cbe) { struct etcp_inst_cbk_entry* n = cbe->next; cbe->fn(etcp, cbe->arg); cbe = n; }
|
||||
}
|
||||
etcp_fire_conn_status(etcp, ETCP_CONN_STATUS_NEW);
|
||||
|
||||
@@ -294,6 +294,17 @@ static void etcp_fire_conn_status(struct ETCP_CONN* etcp, int status) {
|
||||
while (cbe) { struct etcp_status_cbk_entry* n = cbe->next; cbe->fn(etcp, status, cbe->arg); cbe = n; }
|
||||
}
|
||||
|
||||
void etcp_cbk_fire(struct ETCP_CONN* conn, int event) {
|
||||
if (!conn) return;
|
||||
static const char* names[] = { "INIT", "REINIT", "UP", "DOWN", "NODE_CHANGED" };
|
||||
int idx = 0, e = event; while (e >>= 1) idx++;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] callback event: %s", conn->log_name, (idx >= 0 && idx < (int)(sizeof(names)/sizeof(names[0]))) ? names[idx] : "?");
|
||||
conn->callbacks_running = 1;
|
||||
struct etcp_cbk_entry* cbe = conn->cbks;
|
||||
while (cbe) { struct etcp_cbk_entry* n = cbe->next; if (cbe->event_mask & event) cbe->fn(conn, event, cbe->arg); cbe = n; }
|
||||
conn->callbacks_running = 0;
|
||||
}
|
||||
|
||||
static void etcp_on_up(struct ETCP_CONN* etcp) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] Connection UP (links_up=%d initialized=%d)", etcp->log_name, etcp->links_up, etcp->initialized);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "CRYPTO_ON_UP_BEFORE: log=%s seskey=%02x%02x%02x%02x peer_pub=%02x%02x%02x%02x",
|
||||
@@ -302,11 +313,8 @@ static void etcp_on_up(struct ETCP_CONN* etcp) {
|
||||
etcp->crypto_ctx.session_key[2], etcp->crypto_ctx.session_key[3],
|
||||
etcp->crypto_ctx.peer_public_key[0], etcp->crypto_ctx.peer_public_key[1],
|
||||
etcp->crypto_ctx.peer_public_key[2], etcp->crypto_ctx.peer_public_key[3]);
|
||||
etcp->callbacks_running = 1;
|
||||
struct etcp_cbk_entry* cbe = etcp->up_cbks;
|
||||
while (cbe) { struct etcp_cbk_entry* n = cbe->next; cbe->fn(etcp, cbe->arg); cbe = n; }
|
||||
etcp_cbk_fire(etcp, ETCP_CBK_EVENT_UP);
|
||||
etcp_fire_conn_status(etcp, ETCP_CONN_STATUS_UP);
|
||||
etcp->callbacks_running = 0;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "CRYPTO_ON_UP_AFTER: log=%s seskey=%02x%02x%02x%02x peer_pub=%02x%02x%02x%02x",
|
||||
etcp->log_name,
|
||||
etcp->crypto_ctx.session_key[0], etcp->crypto_ctx.session_key[1],
|
||||
@@ -317,11 +325,8 @@ static void etcp_on_up(struct ETCP_CONN* etcp) {
|
||||
|
||||
static void etcp_on_down(struct ETCP_CONN* etcp) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] Connection DOWN (links_up=%d)", etcp->log_name, etcp->links_up);
|
||||
etcp->callbacks_running = 1;
|
||||
struct etcp_cbk_entry* cbe = etcp->down_cbks;
|
||||
while (cbe) { struct etcp_cbk_entry* n = cbe->next; cbe->fn(etcp, cbe->arg); cbe = n; }
|
||||
etcp_cbk_fire(etcp, ETCP_CBK_EVENT_DOWN);
|
||||
etcp_fire_conn_status(etcp, ETCP_CONN_STATUS_DOWN);
|
||||
etcp->callbacks_running = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -345,11 +350,8 @@ static void etcp_connection_free_resources(struct ETCP_CONN* etcp) {
|
||||
drain_and_free_queue(&etcp->recv_q);
|
||||
drain_and_free_queue(&etcp->ack_q);
|
||||
|
||||
// Free callback chains
|
||||
{ struct etcp_cbk_entry* cbe = etcp->init_cbks; while (cbe) { struct etcp_cbk_entry* n = cbe->next; u_free(cbe); cbe = n; } etcp->init_cbks = NULL; }
|
||||
{ struct etcp_cbk_entry* cbe = etcp->up_cbks; while (cbe) { struct etcp_cbk_entry* n = cbe->next; u_free(cbe); cbe = n; } etcp->up_cbks = NULL; }
|
||||
{ struct etcp_cbk_entry* cbe = etcp->down_cbks; while (cbe) { struct etcp_cbk_entry* n = cbe->next; u_free(cbe); cbe = n; } etcp->down_cbks = NULL; }
|
||||
{ struct etcp_cbk_entry* cbe = etcp->node_changed_cbks; while (cbe) { struct etcp_cbk_entry* n = cbe->next; u_free(cbe); cbe = n; } etcp->node_changed_cbks = NULL; }
|
||||
// Free callback chain
|
||||
{ struct etcp_cbk_entry* cbe = etcp->cbks; while (cbe) { struct etcp_cbk_entry* n = cbe->next; u_free(cbe); cbe = n; } etcp->cbks = NULL; }
|
||||
|
||||
if (etcp->inflight_pool) { memory_pool_destroy(etcp->inflight_pool); etcp->inflight_pool = NULL; }
|
||||
if (etcp->io_pool) { memory_pool_destroy(etcp->io_pool); etcp->io_pool = NULL; }
|
||||
@@ -574,6 +576,7 @@ void etcp_conn_reinit(struct ETCP_CONN* etcp) {// Если сбой в обме
|
||||
etcp->log_name, etcp->initialized, etcp->links_up, etcp->reinit_count, etcp->tx_state);
|
||||
|
||||
etcp->reinit_count++;
|
||||
etcp->reinit_pending = 1;
|
||||
etcp->reset_done = 0;
|
||||
etcp->initialized = 0;// еще раз придёт conn_ready_callback
|
||||
|
||||
@@ -652,10 +655,9 @@ void etcp_conn_queue_set_ready(struct ETCP_CONN* conn) {
|
||||
|
||||
etcp_metrics_start_timer(conn);
|
||||
|
||||
conn->callbacks_running = 1;
|
||||
{ struct etcp_cbk_entry* cbe = conn->init_cbks; while (cbe) { struct etcp_cbk_entry* n = cbe->next; cbe->fn(conn, cbe->arg); cbe = n; } }
|
||||
etcp_cbk_fire(conn, ETCP_CBK_EVENT_INIT);
|
||||
if (conn->reinit_pending) { conn->reinit_pending = 0; etcp_cbk_fire(conn, ETCP_CBK_EVENT_REINIT); }
|
||||
if (conn->links_up) etcp_on_up(conn);
|
||||
conn->callbacks_running = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,12 +20,7 @@ struct stcp_link; // forward declaration
|
||||
// Forward declarations
|
||||
struct UTUN_INSTANCE;
|
||||
struct ETCP_CONN;
|
||||
typedef void (*etcp_on_conn_ready)(struct ETCP_CONN* conn, void* arg);
|
||||
struct etcp_cbk_entry {
|
||||
etcp_on_conn_ready fn;
|
||||
void* arg;
|
||||
struct etcp_cbk_entry* next;
|
||||
};
|
||||
struct etcp_cbk_entry; // defined in etcp_api.h
|
||||
struct UASYNC;
|
||||
|
||||
uint16_t get_current_timestamp(void);
|
||||
@@ -236,13 +231,15 @@ struct ETCP_CONN {
|
||||
uint8_t reset_done; // 0 - рукопожатие не завершено (реинит разрешён), 1 - соединение стабильно (реинит заблокирован)
|
||||
uint8_t callbacks_running; // 1 - внутри итерации колбэк-цепочек, etcp_connection_close запрещён
|
||||
|
||||
// Callback chains for ready/up/down notifications
|
||||
struct etcp_cbk_entry* init_cbks; // цепочка callback'ов при инициализации соединения
|
||||
struct etcp_cbk_entry* up_cbks; // цепочка callback'ов при поднятии канала
|
||||
struct etcp_cbk_entry* down_cbks; // цепочка callback'ов при падении канала
|
||||
struct etcp_cbk_entry* node_changed_cbks; // цепочка callback'ов при смене pubkey узла (peer_id совпал, ключ изменился)
|
||||
// Unified callback chain with event mask (init/reinit/up/down/node_changed)
|
||||
struct etcp_cbk_entry* cbks;
|
||||
uint8_t reinit_pending; // 1 = reinit в процессе, ждём завершения
|
||||
void (*bgp_ready_cbk)(struct ETCP_CONN* conn); // вызывается когда BGP готов (завершён или пропущен)
|
||||
|
||||
uint8_t fin_wait : 1; // close-pending: ожидаем подтверждение закрытия от remote
|
||||
void (*fin_wait_clear_cb)(struct ETCP_CONN* conn, void* arg); // вызывается при сбросе fin_wait
|
||||
void* fin_wait_clear_arg;
|
||||
|
||||
uint32_t cnt_ack_hit_inf; // счетчик удлений из inflight
|
||||
uint32_t cnt_ack_hit_sndq; // счетчик удалений inflight пакетов из sndq
|
||||
uint32_t cnt_ack_miss; // счетчик не найденных ack
|
||||
|
||||
@@ -12,11 +12,12 @@
|
||||
|
||||
#define DEBUG_CATEGORY_ETCP_API DEBUG_CATEGORY_ETCP
|
||||
|
||||
static void etcp_cbk_add_to_chain(struct etcp_cbk_entry** head, etcp_cbk_fn fn, void* arg) {
|
||||
// Per-connection unified callback chain helpers
|
||||
static void etcp_cbk_add_to_chain(struct etcp_cbk_entry** head, etcp_cbk_fn fn, void* arg, int event_mask) {
|
||||
if (!head || !fn) return;
|
||||
struct etcp_cbk_entry* e = u_malloc(sizeof(struct etcp_cbk_entry));
|
||||
if (!e) return;
|
||||
e->fn = fn; e->arg = arg; e->next = *head;
|
||||
e->fn = fn; e->arg = arg; e->event_mask = event_mask; e->next = *head;
|
||||
*head = e;
|
||||
}
|
||||
static void etcp_cbk_remove_from_chain(struct etcp_cbk_entry** head, etcp_cbk_fn fn, void* arg) {
|
||||
@@ -31,17 +32,35 @@ static void etcp_cbk_remove_from_chain(struct etcp_cbk_entry** head, etcp_cbk_fn
|
||||
}
|
||||
}
|
||||
|
||||
void etcp_conn_add_init_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg) { if (conn) etcp_cbk_add_to_chain(&conn->init_cbks, fn, arg); }
|
||||
void etcp_conn_remove_init_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg) { if (conn) etcp_cbk_remove_from_chain(&conn->init_cbks, fn, arg); }
|
||||
void etcp_conn_add_up_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg) { if (conn) etcp_cbk_add_to_chain(&conn->up_cbks, fn, arg); }
|
||||
void etcp_conn_remove_up_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg) { if (conn) etcp_cbk_remove_from_chain(&conn->up_cbks, fn, arg); }
|
||||
void etcp_conn_add_down_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg) { if (conn) etcp_cbk_add_to_chain(&conn->down_cbks, fn, arg); }
|
||||
void etcp_conn_remove_down_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg) { if (conn) etcp_cbk_remove_from_chain(&conn->down_cbks, fn, arg); }
|
||||
void etcp_conn_node_changed(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg) { if (conn && fn) fn(conn, arg); }
|
||||
void etcp_conn_add_node_changed_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg) { if (conn) etcp_cbk_add_to_chain(&conn->node_changed_cbks, fn, arg); }
|
||||
void etcp_conn_remove_node_changed_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg) { if (conn) etcp_cbk_remove_from_chain(&conn->node_changed_cbks, fn, arg); }
|
||||
void etcp_add_new_conn_cbk(struct UTUN_INSTANCE* inst, etcp_cbk_fn fn, void* arg) { if (inst) etcp_cbk_add_to_chain(&inst->new_conn_cbks, fn, arg); }
|
||||
void etcp_remove_new_conn_cbk(struct UTUN_INSTANCE* inst, etcp_cbk_fn fn, void* arg) { if (inst) etcp_cbk_remove_from_chain(&inst->new_conn_cbks, fn, arg); }
|
||||
void etcp_conn_add_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg, int event_mask) { if (conn) etcp_cbk_add_to_chain(&conn->cbks, fn, arg, event_mask); }
|
||||
void etcp_conn_remove_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg) { if (conn) etcp_cbk_remove_from_chain(&conn->cbks, fn, arg); }
|
||||
void etcp_conn_update_cbk_mask(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg, int event_mask) {
|
||||
if (!conn || !fn) return;
|
||||
struct etcp_cbk_entry* p = conn->cbks;
|
||||
while (p) { if (p->fn == fn && p->arg == arg) { p->event_mask = event_mask; return; } p = p->next; }
|
||||
}
|
||||
|
||||
// Instance-level callback chain helpers
|
||||
static void etcp_inst_cbk_add_chain(struct etcp_inst_cbk_entry** head, etcp_inst_cbk_fn fn, void* arg) {
|
||||
if (!head || !fn) return;
|
||||
struct etcp_inst_cbk_entry* e = u_malloc(sizeof(struct etcp_inst_cbk_entry));
|
||||
if (!e) return;
|
||||
e->fn = fn; e->arg = arg; e->next = *head;
|
||||
*head = e;
|
||||
}
|
||||
static void etcp_inst_cbk_remove_chain(struct etcp_inst_cbk_entry** head, etcp_inst_cbk_fn fn, void* arg) {
|
||||
if (!head || !fn) return;
|
||||
struct etcp_inst_cbk_entry** p = head;
|
||||
while (*p) {
|
||||
if ((*p)->fn == fn && (*p)->arg == arg) {
|
||||
struct etcp_inst_cbk_entry* rm = *p;
|
||||
*p = rm->next; u_free(rm); return;
|
||||
}
|
||||
p = &(*p)->next;
|
||||
}
|
||||
}
|
||||
void etcp_add_new_conn_cbk(struct UTUN_INSTANCE* inst, etcp_inst_cbk_fn fn, void* arg) { if (inst) etcp_inst_cbk_add_chain(&inst->new_conn_cbks, fn, arg); }
|
||||
void etcp_remove_new_conn_cbk(struct UTUN_INSTANCE* inst, etcp_inst_cbk_fn fn, void* arg) { if (inst) etcp_inst_cbk_remove_chain(&inst->new_conn_cbks, fn, arg); }
|
||||
|
||||
static void etcp_status_cbk_add_chain(struct etcp_status_cbk_entry** head, etcp_conn_status_fn fn, void* arg) {
|
||||
if (!head || !fn) return;
|
||||
|
||||
@@ -44,6 +44,7 @@ extern "C" {
|
||||
#define ETCP_RT_ID_MEDIA_DELIVERY 0x07 // распространение медиа (аудио/видео стриминг)
|
||||
|
||||
#define ETCP_RT_ID_CONN_MGR 0x11 // Connection Manager — management connections
|
||||
#define ETCP_RT_ID_NCD_CONTROL 0x12 // node_conn_direct — CLOSE / KEEP_ALIVE control
|
||||
|
||||
// Connection status events (instance-level callback)
|
||||
#define ETCP_CONN_STATUS_NEW 0 // соединение создано
|
||||
@@ -95,8 +96,41 @@ typedef void (*etcp_recv_fn)(struct ETCP_CONN* conn, struct ll_entry* entry);
|
||||
// Forward declaration
|
||||
struct ETCP_CONN;
|
||||
struct UTUN_INSTANCE;
|
||||
struct TOPO_NODEQ;
|
||||
typedef void (*etcp_cbk_fn)(struct ETCP_CONN* conn, void* arg);
|
||||
struct TOPO_GROUP_NODE;
|
||||
|
||||
// Per-connection callback event types (bitmask)
|
||||
#define ETCP_CBK_EVENT_INIT (1 << 0)
|
||||
#define ETCP_CBK_EVENT_REINIT (1 << 1)
|
||||
#define ETCP_CBK_EVENT_UP (1 << 2)
|
||||
#define ETCP_CBK_EVENT_DOWN (1 << 3)
|
||||
#define ETCP_CBK_EVENT_NODE_CHANGED (1 << 4)
|
||||
|
||||
typedef void (*etcp_cbk_fn)(struct ETCP_CONN* conn, int event, void* arg);
|
||||
struct etcp_cbk_entry {
|
||||
etcp_cbk_fn fn;
|
||||
void* arg;
|
||||
int event_mask;
|
||||
struct etcp_cbk_entry* next;
|
||||
};
|
||||
|
||||
void etcp_cbk_fire(struct ETCP_CONN* conn, int event);
|
||||
|
||||
// Instance-level callback types (separate from per-connection etcp_cbk_fn in etcp.h)
|
||||
typedef void (*etcp_inst_cbk_fn)(struct ETCP_CONN* conn, void* arg);
|
||||
struct etcp_inst_cbk_entry {
|
||||
etcp_inst_cbk_fn fn;
|
||||
void* arg;
|
||||
struct etcp_inst_cbk_entry* next;
|
||||
};
|
||||
|
||||
// ---- Per-connection unified callback API ----
|
||||
void etcp_conn_add_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg, int event_mask);
|
||||
void etcp_conn_remove_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg);
|
||||
void etcp_conn_update_cbk_mask(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg, int event_mask);
|
||||
|
||||
// ---- Instance-level callbacks ----
|
||||
void etcp_add_new_conn_cbk(struct UTUN_INSTANCE* inst, etcp_inst_cbk_fn fn, void* arg);
|
||||
void etcp_remove_new_conn_cbk(struct UTUN_INSTANCE* inst, etcp_inst_cbk_fn fn, void* arg);
|
||||
|
||||
// ---- Background connection initialization ----
|
||||
#define ETCP_CONNECT_EARLY 1
|
||||
@@ -105,7 +139,7 @@ typedef void (*etcp_cbk_fn)(struct ETCP_CONN* conn, void* arg);
|
||||
|
||||
typedef void (*etcp_connect_callback_t)(void* arg, struct ETCP_CONN* conn, int type);
|
||||
|
||||
int etcp_connect(struct UTUN_INSTANCE* instance, struct TOPO_NODEQ* node,
|
||||
int etcp_connect(struct UTUN_INSTANCE* instance, struct TOPO_GROUP_NODE* node,
|
||||
etcp_connect_callback_t cb, void* arg, uint8_t flags);
|
||||
|
||||
/**
|
||||
@@ -151,18 +185,6 @@ int etcp_bind(struct UTUN_INSTANCE* inst, uint8_t id, etcp_recv_fn callback);
|
||||
*/
|
||||
int etcp_unbind(struct UTUN_INSTANCE* inst, uint8_t id);
|
||||
|
||||
void etcp_conn_add_init_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg);
|
||||
void etcp_conn_remove_init_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg);
|
||||
void etcp_conn_add_up_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg);
|
||||
void etcp_conn_remove_up_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg);
|
||||
void etcp_conn_add_down_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg);
|
||||
void etcp_conn_remove_down_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg);
|
||||
void etcp_conn_node_changed(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg);
|
||||
void etcp_conn_add_node_changed_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg);
|
||||
void etcp_conn_remove_node_changed_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg);
|
||||
void etcp_add_new_conn_cbk(struct UTUN_INSTANCE* inst, etcp_cbk_fn fn, void* arg);
|
||||
void etcp_remove_new_conn_cbk(struct UTUN_INSTANCE* inst, etcp_cbk_fn fn, void* arg);
|
||||
|
||||
void etcp_add_conn_status_cbk(struct UTUN_INSTANCE* inst, etcp_conn_status_fn fn, void* arg);
|
||||
void etcp_remove_conn_status_cbk(struct UTUN_INSTANCE* inst, etcp_conn_status_fn fn, void* arg);
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ struct ETCP_CONNECT {
|
||||
};
|
||||
static void tcp_link_ready_cb(struct stcp_link* link, void* arg);
|
||||
static void tcp_link_close_cb(struct stcp_link* link, int err, void* arg);
|
||||
static void connect_init_cb(struct ETCP_CONN* conn, void* arg);
|
||||
static void connect_init_cb(struct ETCP_CONN* conn, int event, void* arg);
|
||||
|
||||
static struct ETCP_CONNECT* connect_find(struct UTUN_INSTANCE* inst, uint64_t node_id) {
|
||||
struct ETCP_CONNECT* ctx = inst->pending_connects;
|
||||
@@ -69,9 +69,14 @@ static void connect_cancel(struct ETCP_CONNECT* ctx) {
|
||||
u_free(ctx);
|
||||
}
|
||||
|
||||
static void connect_create_links_v4(struct ETCP_CONNECT* ctx, struct TOPO_NODEQ* node) {
|
||||
if (!node || !node->node) return;
|
||||
for (const struct TOPO_ADDR4* a = node->node->v4_addrs; a; a = a->next) {
|
||||
static void connect_create_links_v4(struct ETCP_CONNECT* ctx, struct TOPO_GROUP_NODE* node) {
|
||||
if (!node) return;
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(ctx->instance->topo_groups, node->node_id);
|
||||
if (!ni) { DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "[etcp_connect] links_v4: ni NOT in registry for node=%016llx", (unsigned long long)node->node_id); return; }
|
||||
int addr_count = 0, sock_count = 0, link_count = 0;
|
||||
{ struct ETCP_SOCKET* s = ctx->instance->etcp_sockets; while (s) { sock_count++; s = s->next; } }
|
||||
for (const struct TOPO_ADDR4* a = ni->v4_addrs; a; a = a->next) {
|
||||
addr_count++;
|
||||
if (a->port == 0) continue;
|
||||
{ int zero = 1; for (int j = 0; j < 4; j++) if (a->addr[j] != 0) { zero = 0; break; } if (zero) continue; }
|
||||
struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET;
|
||||
@@ -79,21 +84,25 @@ static void connect_create_links_v4(struct ETCP_CONNECT* ctx, struct TOPO_NODEQ*
|
||||
struct sockaddr_storage sa; memcpy(&sa, &sin, sizeof(sin));
|
||||
if (!(a->protocol & TOPO_PROTO_TCP)) {
|
||||
struct ETCP_SOCKET* s = ctx->instance->etcp_sockets;
|
||||
while (s) { if (s->local_addr.ss_family == AF_INET) etcp_link_new(ctx->conn, s, &sa, 0); s = s->next; }
|
||||
while (s) { if (s->local_addr.ss_family == AF_INET && etcp_link_new(ctx->conn, s, &sa, 0)) link_count++; s = s->next; }
|
||||
}
|
||||
if ((a->protocol & TOPO_PROTO_TCP) && !ctx->tcp_link) {
|
||||
struct stcp_link_config tcp_cfg = {.ua = ctx->instance->ua, .my_keys = &ctx->instance->my_keys, .inst = ctx->instance,
|
||||
.peer_pubkey = ctx->conn->crypto_ctx.peer_public_key, .peer_pubkey_mode = 0,
|
||||
.remote_addr = &sa, .remote_port = a->port};
|
||||
ctx->tcp_link = stcp_link_connect(&tcp_cfg);
|
||||
if (ctx->tcp_link) { ctx->conn->transport_link = (void*)ctx->tcp_link; stcp_link_set_on_ready(ctx->tcp_link, tcp_link_ready_cb, ctx); stcp_link_set_on_close(ctx->tcp_link, tcp_link_close_cb, ctx); }
|
||||
if (ctx->tcp_link) { ctx->conn->transport_link = (void*)ctx->tcp_link; stcp_link_set_on_ready(ctx->tcp_link, tcp_link_ready_cb, ctx); stcp_link_set_on_close(ctx->tcp_link, tcp_link_close_cb, ctx); link_count++; }
|
||||
}
|
||||
}
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "[etcp_connect] links_v4: addrs=%d socks=%d links=%d for node=%016llx",
|
||||
addr_count, sock_count, link_count, (unsigned long long)node->node_id);
|
||||
}
|
||||
|
||||
static void connect_create_links_v6(struct ETCP_CONNECT* ctx, struct TOPO_NODEQ* node) {
|
||||
if (!node || !node->node) return;
|
||||
for (const struct TOPO_ADDR6* a = node->node->v6_addrs; a; a = a->next) {
|
||||
static void connect_create_links_v6(struct ETCP_CONNECT* ctx, struct TOPO_GROUP_NODE* node) {
|
||||
if (!node) return;
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(ctx->instance->topo_groups, node->node_id);
|
||||
if (!ni) return;
|
||||
for (const struct TOPO_ADDR6* a = ni->v6_addrs; a; a = a->next) {
|
||||
if (a->port == 0) continue;
|
||||
int zero = 1; for (int j = 0; j < 16; j++) if (a->addr[j] != 0) { zero = 0; break; } if (zero) continue;
|
||||
struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6;
|
||||
@@ -122,7 +131,7 @@ static void tcp_link_ready_cb(struct stcp_link* link, void* arg) {
|
||||
if (!ctx || ctx->done || ctx->tcp_ready) return;
|
||||
ctx->tcp_ready = 1;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] TCP link ready for node 0x%016llx", (unsigned long long)ctx->node_id);
|
||||
connect_init_cb(ctx->conn, ctx);
|
||||
connect_init_cb(ctx->conn, ETCP_CBK_EVENT_INIT, ctx);
|
||||
}
|
||||
|
||||
static void tcp_link_close_cb(struct stcp_link* link, int err, void* arg) {
|
||||
@@ -135,6 +144,8 @@ static void tcp_link_close_cb(struct stcp_link* link, int err, void* arg) {
|
||||
|
||||
static void connect_bgp_ready_cb(struct ETCP_CONN* conn) {
|
||||
struct ETCP_CONNECT* ctx = connect_find(conn->instance, conn->peer_node_id);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "[etcp_connect] bgp_ready_cb: node=%016llx ctx=%p ctx_done=%d ra=%d",
|
||||
(unsigned long long)conn->peer_node_id, (void*)ctx, ctx ? ctx->done : -1, conn->routing_exchange_active);
|
||||
if (!ctx || ctx->done) return;
|
||||
connect_deliver(ctx, ETCP_CONNECT_BGP_READY, 1);
|
||||
}
|
||||
@@ -174,12 +185,12 @@ static void connect_settle_timeout_cb(void* arg) {
|
||||
(unsigned long long)ctx->node_id);
|
||||
stcp_link_close(ctx->tcp_link); ctx->tcp_link = NULL;
|
||||
}
|
||||
etcp_conn_remove_init_cbk(ctx->conn, connect_init_cb, ctx);
|
||||
etcp_conn_remove_cbk(ctx->conn, connect_init_cb, ctx);
|
||||
connect_deliver(ctx, ETCP_CONNECT_LATE, 1);
|
||||
connect_cancel(ctx);
|
||||
}
|
||||
|
||||
static void connect_init_cb(struct ETCP_CONN* conn, void* arg) {
|
||||
static void connect_init_cb(struct ETCP_CONN* conn, int event, void* arg) { (void)event;
|
||||
struct ETCP_CONNECT* ctx = (struct ETCP_CONNECT*)arg;
|
||||
if (!ctx || ctx->done) return;
|
||||
|
||||
@@ -222,25 +233,30 @@ static void connect_init_cb(struct ETCP_CONN* conn, void* arg) {
|
||||
connect_settle_timeout_cb, "etcp_connect_settle");
|
||||
}
|
||||
|
||||
int etcp_connect(struct UTUN_INSTANCE* inst, struct TOPO_NODEQ* node,
|
||||
int etcp_connect(struct UTUN_INSTANCE* inst, struct TOPO_GROUP_NODE* node,
|
||||
etcp_connect_callback_t cb, void* arg, uint8_t flags) {
|
||||
if (!inst || !node || !cb) return -1;
|
||||
|
||||
uint64_t node_id = node->node->node_id;
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(inst->topo_groups, node->node_id);
|
||||
if (!ni) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] node not in registry"); return -1; }
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "[etcp_connect] registry OK node=%016llx pub=%016llx v4addrs=%p v4socks=%p",
|
||||
(unsigned long long)node->node_id, *(uint64_t*)ni->public_key, (void*)ni->v4_addrs, (void*)ni->v4_sock_meta);
|
||||
|
||||
uint64_t node_id = ni->node_id;
|
||||
if (node_id == 0) {
|
||||
if (!node->node->public_key) {
|
||||
if (!ni->public_key) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] node_id=0 and public_key is NULL");
|
||||
return -1;
|
||||
}
|
||||
int zero = 1;
|
||||
for (int i = 0; i < SC_PUBKEY_SIZE; i++)
|
||||
if (node->node->public_key[i]) { zero = 0; break; }
|
||||
if (ni->public_key[i]) { zero = 0; break; }
|
||||
if (zero) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] node_id=0 and public_key is all zeros");
|
||||
return -1;
|
||||
}
|
||||
node_id = sc_derive_node_id_from_pubkey(node->node->public_key);
|
||||
node->node->node_id = node_id;
|
||||
node_id = sc_derive_node_id_from_pubkey(ni->public_key);
|
||||
ni->node_id = node_id;
|
||||
}
|
||||
|
||||
struct ETCP_CONN* conn = instance_find_conn(inst, node_id);
|
||||
@@ -281,7 +297,7 @@ int etcp_connect(struct UTUN_INSTANCE* inst, struct TOPO_NODEQ* node,
|
||||
struct etcp_connect_cb_node* cn = u_calloc(1, sizeof(struct etcp_connect_cb_node));
|
||||
if (!cn) { u_free(ctx); return -1; }
|
||||
cn->cb = cb; cn->arg = arg; cn->flags = flags; ctx->cb_list = cn;
|
||||
etcp_conn_add_init_cbk(conn, connect_init_cb, ctx);
|
||||
etcp_conn_add_cbk(conn, connect_init_cb, ctx, ETCP_CBK_EVENT_INIT);
|
||||
conn->bgp_ready_cbk = connect_bgp_ready_cb;
|
||||
ctx->initial_timer = uasync_set_timeout(inst->ua, (int)inst->etcp_connect_timeout_tb, ctx,
|
||||
connect_initial_timeout_cb, "etcp_connect_init");
|
||||
@@ -348,7 +364,7 @@ int etcp_connect(struct UTUN_INSTANCE* inst, struct TOPO_NODEQ* node,
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] sc_init_ctx failed for node 0x%016llx", (unsigned long long)node_id);
|
||||
etcp_connection_close(conn); cb(arg, NULL, 0); return -1;
|
||||
}
|
||||
if (sc_set_peer_public_key(&conn->crypto_ctx, node->node->public_key, 0) != SC_OK) {
|
||||
if (sc_set_peer_public_key(&conn->crypto_ctx, ni->public_key, 0) != SC_OK) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] sc_set_peer_public_key failed for node 0x%016llx", (unsigned long long)node_id);
|
||||
etcp_connection_close(conn); cb(arg, NULL, 0); return -1;
|
||||
}
|
||||
@@ -366,15 +382,16 @@ int etcp_connect(struct UTUN_INSTANCE* inst, struct TOPO_NODEQ* node,
|
||||
cn->cb = cb; cn->arg = arg; cn->flags = flags; ctx->cb_list = cn;
|
||||
}
|
||||
|
||||
etcp_conn_add_init_cbk(conn, connect_init_cb, ctx);
|
||||
etcp_conn_add_cbk(conn, connect_init_cb, ctx, ETCP_CBK_EVENT_INIT);
|
||||
conn->bgp_ready_cbk = connect_bgp_ready_cb;
|
||||
|
||||
connect_create_links_v4(ctx, node);
|
||||
connect_create_links_v6(ctx, node);
|
||||
|
||||
if (!conn->links && !conn->transport_link) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] no links created for node 0x%016llx",
|
||||
(unsigned long long)node_id);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] no links created for node 0x%016llx (links=%p tcp=%p sock_count=%d)",
|
||||
(unsigned long long)node_id, (void*)conn->links, (void*)ctx->tcp_link,
|
||||
({ int sc = 0; struct ETCP_SOCKET* ss = inst->etcp_sockets; while (ss) { sc++; ss = ss->next; } sc; }));
|
||||
if (ctx->tcp_link) { stcp_link_close(ctx->tcp_link); ctx->tcp_link = NULL; }
|
||||
connect_deliver(ctx, 0, 1);
|
||||
etcp_connection_close(conn); u_free(ctx); return -1;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
struct UTUN_INSTANCE;
|
||||
struct ETCP_CONN;
|
||||
struct TOPO_NODEQ;
|
||||
struct TOPO_GROUP_NODE;
|
||||
typedef void (*etcp_connect_callback_t)(void* arg, struct ETCP_CONN* conn, int type);
|
||||
|
||||
/**
|
||||
@@ -18,7 +18,7 @@ typedef void (*etcp_connect_callback_t)(void* arg, struct ETCP_CONN* conn, int t
|
||||
* фаз установки соединения.
|
||||
*
|
||||
* @param inst UTUN_INSTANCE
|
||||
* @param node узел-адресат (TOPO_NODEQ). Из node->node берутся:
|
||||
* @param node узел-адресат (TOPO_GROUP_NODE). Из node->node берутся:
|
||||
* - node_id — идентификатор узла (0 = вычислить из pubkey)
|
||||
* - public_key — X25519 pubkey (32 байта)
|
||||
* - v4_addrs / v6_addrs — адреса для создания линков
|
||||
@@ -115,7 +115,7 @@ typedef void (*etcp_connect_callback_t)(void* arg, struct ETCP_CONN* conn, int t
|
||||
* connect_settle_timeout_cb (settle-таймер):
|
||||
* ├─ Закрывает неинициализированные линки (!link->initialized)
|
||||
* ├─ Закрывает TCP-линк если !tcp_ready
|
||||
* ├─ Убирает connect_init_cb из conn->init_cbks
|
||||
* ├─ Убирает connect_init_cb из conn->cbks
|
||||
* └─ connect_deliver(ctx, ETCP_CONNECT_LATE) → ctx освобождается
|
||||
*
|
||||
* connect_bgp_ready_cb (вызывается при routing_exchange_active >= 3):
|
||||
@@ -164,7 +164,7 @@ typedef void (*etcp_connect_callback_t)(void* arg, struct ETCP_CONN* conn, int t
|
||||
*
|
||||
* ============================================================================
|
||||
*/
|
||||
int etcp_connect(struct UTUN_INSTANCE* instance, struct TOPO_NODEQ* node,
|
||||
int etcp_connect(struct UTUN_INSTANCE* instance, struct TOPO_GROUP_NODE* node,
|
||||
etcp_connect_callback_t cb, void* arg, uint8_t flags);
|
||||
|
||||
/*
|
||||
|
||||
@@ -35,9 +35,9 @@ static void tcp_server_on_link(struct stcp_link *link, void *arg) {
|
||||
if (!conn) return;
|
||||
conn->transport_link = link;
|
||||
snprintf(conn->log_name, sizeof(conn->log_name), "tcp-[%p]", (void*)link);
|
||||
struct etcp_cbk_entry* cbe = inst->new_conn_cbks;
|
||||
while (cbe) { struct etcp_cbk_entry* n = cbe->next; cbe->fn(conn, cbe->arg); cbe = n; }
|
||||
{ struct etcp_cbk_entry* rcb = conn->init_cbks; while (rcb) { struct etcp_cbk_entry* n = rcb->next; rcb->fn(conn, rcb->arg); rcb = n; } }
|
||||
struct etcp_inst_cbk_entry* cbe = inst->new_conn_cbks;
|
||||
while (cbe) { struct etcp_inst_cbk_entry* n = cbe->next; cbe->fn(conn, cbe->arg); cbe = n; }
|
||||
etcp_cbk_fire(conn, ETCP_CBK_EVENT_INIT);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "TCP server new conn=%p total=%d pending=%d",
|
||||
(void*)conn,
|
||||
queue_entry_count(inst->connections),
|
||||
@@ -197,6 +197,7 @@ static void etcp_link_init_timer_cbk(void* arg) {
|
||||
|
||||
if (link->link_state == 3 && link->initialized) { DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "[%s] init_timer: SUPPRESSED state=%d init=%d link_status=%d recv_ka=%d remote_ka=%d links_up=%d", link->etcp->log_name, link->link_state, link->initialized, link->link_status, link->recv_keepalive, link->remote_keepalive, link->etcp->links_up); return; }
|
||||
if (link->etcp->links_up > 0) { DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "[%s] init_timer: SUPPRESSED (links_up=%d > 0)", link->etcp->log_name, link->etcp->links_up); return; }
|
||||
if (link->etcp->fin_wait) { DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] init_timer: SUPPRESSED (fin_wait)", link->etcp->log_name); return; }
|
||||
if (link->etcp->got_initial_pkt == 0) etcp_link_send_init(link,1,0);
|
||||
else etcp_link_send_init(link,0,0);
|
||||
}
|
||||
@@ -1383,7 +1384,9 @@ static void send_init_response(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pk
|
||||
if (g) {
|
||||
topo_group_update_my_nodeinfo(g->instance, g);
|
||||
if (g->local_node && g->senders_list) {
|
||||
g->local_node->node->ver = (g->local_node->node->ver % 255) + 1;
|
||||
struct TOPO_NODE* vni = topo_node_registry_find(g->instance->topo_groups, g->local_node->node_id);
|
||||
if (vni) vni->ver = (vni->ver % 255) + 1;
|
||||
g->local_node->dirty = 1;
|
||||
g->local_node->dirty = 1;
|
||||
struct ll_entry* se = g->senders_list->head;
|
||||
while (se) {
|
||||
@@ -1817,13 +1820,18 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
|
||||
*(uint64_t*)conn->crypto_ctx.peer_public_key, *(uint64_t*)sc.peer_public_key);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "peer key mismatch for node %016llx, firing node_changed callbacks", (unsigned long long)peer_id);
|
||||
conn->callbacks_running = 1;
|
||||
struct etcp_cbk_entry* cbe = conn->node_changed_cbks;
|
||||
while (cbe) { struct etcp_cbk_entry* n = cbe->next; cbe->fn(conn, cbe->arg); cbe = n; }
|
||||
etcp_cbk_fire(conn, ETCP_CBK_EVENT_NODE_CHANGED);
|
||||
conn->callbacks_running = 0;
|
||||
goto ec_fr;
|
||||
}// коллизия - peer id совпал а ключи разные.
|
||||
}
|
||||
|
||||
if (conn->fin_wait) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] received INIT during fin_wait, clearing", conn->log_name);
|
||||
conn->fin_wait = 0;
|
||||
if (conn->fin_wait_clear_cb) { conn->fin_wait_clear_cb(conn, conn->fin_wait_clear_arg); conn->fin_wait_clear_cb = NULL; conn->fin_wait_clear_arg = NULL; }
|
||||
}
|
||||
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "INIT conn=%s new_conn=%d peer=0x%016llx state=%d links_up=%d links=%p", conn->log_name, new_conn, (unsigned long long)peer_id, conn->state, conn->links_up, (void*)conn->links);
|
||||
|
||||
// Check if link already exists (for CHANNEL_INIT recovery)
|
||||
@@ -1836,8 +1844,7 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "[%s] link address match but pubkey mismatch, firing node_changed", conn->log_name);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "pubkey mismatch on reused link for node %016llx", (unsigned long long)peer_id);
|
||||
conn->callbacks_running = 1;
|
||||
struct etcp_cbk_entry* cbe = conn->node_changed_cbks;
|
||||
while (cbe) { struct etcp_cbk_entry* n = cbe->next; cbe->fn(conn, cbe->arg); cbe = n; }
|
||||
etcp_cbk_fire(conn, ETCP_CBK_EVENT_NODE_CHANGED);
|
||||
conn->callbacks_running = 0;
|
||||
errorcode = 67;
|
||||
goto ec_fr;
|
||||
@@ -1851,8 +1858,7 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "link address conflict for node %016llx, firing node_changed callbacks on %s",
|
||||
(unsigned long long)peer_id, old_conn->log_name);
|
||||
old_conn->callbacks_running = 1;
|
||||
struct etcp_cbk_entry* cbe = old_conn->node_changed_cbks;
|
||||
while (cbe) { struct etcp_cbk_entry* n = cbe->next; cbe->fn(old_conn, cbe->arg); cbe = n; }
|
||||
etcp_cbk_fire(old_conn, ETCP_CBK_EVENT_NODE_CHANGED);
|
||||
old_conn->callbacks_running = 0;
|
||||
errorcode = 67;
|
||||
goto ec_fr;
|
||||
|
||||
@@ -0,0 +1,670 @@
|
||||
/*
|
||||
* node_conn_direct.c — handle-based ETCP connection layer
|
||||
*
|
||||
* Тонкая прослойка над 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"
|
||||
#include "topo_node_sqlite.h"
|
||||
#include "topo_group.h"
|
||||
#include "config_parser.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include "../lib/mem.h"
|
||||
#include "../lib/u_async.h"
|
||||
#include "../lib/ll_queue.h"
|
||||
#include "../lib/socket_compat.h"
|
||||
#include "../lib/platform_compat.h"
|
||||
#include <string.h>
|
||||
|
||||
#define DEBUG_CATEGORY_NCD DEBUG_CATEGORY_ETCP
|
||||
|
||||
/* ═══════════ локальные константы ═══════════ */
|
||||
|
||||
#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;
|
||||
|
||||
struct NODE_CONN_DIRECT* handles; /* связный список всех handle'ов */
|
||||
|
||||
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 уже сработал */
|
||||
|
||||
struct ncd_entry* next; /* цепочка статического реестра */
|
||||
};
|
||||
|
||||
struct NODE_CONN_DIRECT {
|
||||
struct ncd_entry* entry;
|
||||
ncd_callback cb;
|
||||
void* cb_arg;
|
||||
struct NODE_CONN_DIRECT* next;
|
||||
};
|
||||
|
||||
static struct ncd_entry* g_ncd_registry;
|
||||
static uint8_t g_ncd_control_bound; /* 1 = etcp_bind(ETCP_RT_ID_NCD_CONTROL) уже сделан */
|
||||
|
||||
/* ─── forward declarations ─── */
|
||||
static void ncd_event_dispatch(struct ncd_entry* entry, enum ncd_event event);
|
||||
static void ncd_connect_timeout_cb(void* arg);
|
||||
static void ncd_deliver_up_cb(void* arg);
|
||||
|
||||
/* ═══════════ реестр ═══════════ */
|
||||
|
||||
static struct ncd_entry* ncd_registry_find(uint64_t node_id) {
|
||||
struct ncd_entry* e = g_ncd_registry;
|
||||
while (e) { if (e->node_id == node_id) return e; e = e->next; }
|
||||
return NULL;
|
||||
}
|
||||
static void ncd_registry_add(struct ncd_entry* entry) {
|
||||
entry->next = g_ncd_registry; g_ncd_registry = entry;
|
||||
}
|
||||
static void ncd_registry_remove(struct ncd_entry* entry) {
|
||||
struct ncd_entry** pp = &g_ncd_registry;
|
||||
while (*pp) { if (*pp == entry) { *pp = entry->next; return; } pp = &(*pp)->next; }
|
||||
}
|
||||
|
||||
/* ═══════════ поиск узла ═══════════ */
|
||||
|
||||
static struct TOPO_NODE* ncd_lookup_node(struct UTUN_INSTANCE* inst, uint64_t node_id) {
|
||||
if (inst->topo_groups && inst->topo_groups->node_registry) {
|
||||
struct ll_entry* e = queue_find_data_by_index(inst->topo_groups->node_registry, (const uint8_t*)&node_id);
|
||||
if (e) {
|
||||
struct TOPO_NODE* node;
|
||||
memcpy(&node, e->data + 8, sizeof(node));
|
||||
if (node) { topo_node_registry_ref(inst->topo_groups, node_id); return node; }
|
||||
}
|
||||
}
|
||||
if (inst->topo_sqlite_db && inst->topo_groups) {
|
||||
struct TOPO_NODE* ni = topo_node_sqlite_node_load(inst->topo_sqlite_db, inst->topo_groups, node_id);
|
||||
if (ni) return topo_node_registry_store(inst->topo_groups, ni);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ═══════════ создание линков (round‑robin, все сокеты кроме PRIVATE) ═══════════ */
|
||||
|
||||
static int ncd_create_links(struct ncd_entry* entry, struct TOPO_NODE* ni) {
|
||||
struct ETCP_CONN* conn = entry->conn;
|
||||
struct UTUN_INSTANCE* inst = conn->instance;
|
||||
int link_count = 0;
|
||||
|
||||
/* ---- IPv4 ---- */
|
||||
{
|
||||
struct ETCP_SOCKET* socks[64]; int sock_count = 0;
|
||||
for (struct ETCP_SOCKET* s = inst->etcp_sockets; s; s = s->next)
|
||||
if (s->local_addr.ss_family == AF_INET && s->type != CFG_SERVER_TYPE_PRIVATE)
|
||||
socks[sock_count++] = s;
|
||||
|
||||
if (sock_count > 0) {
|
||||
int rr = 0;
|
||||
for (const struct TOPO_ADDR4* a = ni->v4_addrs; a; a = a->next) {
|
||||
if (a->port == 0 || !(a->protocol & TOPO_PROTO_UDP)) continue;
|
||||
int zero = 1; for (int j = 0; j < 4; j++) if (a->addr[j] != 0) { zero = 0; break; }
|
||||
if (zero) continue;
|
||||
struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET;
|
||||
memcpy(&sin.sin_addr.s_addr, a->addr, 4); sin.sin_port = htons(a->port);
|
||||
struct sockaddr_storage sa; memcpy(&sa, &sin, sizeof(sin));
|
||||
if (etcp_link_new(conn, socks[rr++ % sock_count], &sa, 0)) link_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- IPv6 ---- */
|
||||
{
|
||||
struct ETCP_SOCKET* socks[64]; int sock_count = 0;
|
||||
for (struct ETCP_SOCKET* s = inst->etcp_sockets; s; s = s->next)
|
||||
if (s->local_addr.ss_family == AF_INET6 && s->type != CFG_SERVER_TYPE_PRIVATE)
|
||||
socks[sock_count++] = s;
|
||||
|
||||
if (sock_count > 0) {
|
||||
int rr = 0;
|
||||
for (const struct TOPO_ADDR6* a = ni->v6_addrs; a; a = a->next) {
|
||||
if (a->port == 0 || !(a->protocol & TOPO_PROTO_UDP)) continue;
|
||||
int zero = 1; for (int j = 0; j < 16; j++) if (a->addr[j] != 0) { zero = 0; break; }
|
||||
if (zero) continue;
|
||||
struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6;
|
||||
memcpy(&sin6.sin6_addr, a->addr, 16); sin6.sin6_port = htons(a->port);
|
||||
struct sockaddr_storage sa; memcpy(&sa, &sin6, sizeof(sin6));
|
||||
if (etcp_link_new(conn, socks[rr++ % sock_count], &sa, 0)) 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) {
|
||||
if (!entry) return;
|
||||
switch (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:
|
||||
if (!entry->up) return;
|
||||
entry->up = 0;
|
||||
break;
|
||||
case NCD_EVENT_TIMEOUT:
|
||||
if (entry->timed_out) return;
|
||||
entry->timed_out = 1;
|
||||
entry->connect_timer = NULL;
|
||||
break;
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] event=%d node=0x%016llx handles=%d",
|
||||
(int)event, (unsigned long long)entry->node_id, entry->handle_count);
|
||||
struct NODE_CONN_DIRECT* h = entry->handles;
|
||||
while (h) { struct NODE_CONN_DIRECT* next = h->next; if (h->cb) h->cb(h, event, h->cb_arg); h = next; }
|
||||
}
|
||||
|
||||
/* ═══════════ ETCP коллбэки (прокидывают в ncd_event_dispatch) ═══════════ */
|
||||
|
||||
static void ncd_init_cb(struct ETCP_CONN* conn, int event, void* arg) { (void)event;
|
||||
struct ncd_entry* entry = (struct ncd_entry*)arg;
|
||||
if (!entry || entry->timed_out || conn->fin_wait) return;
|
||||
ncd_event_dispatch(entry, NCD_EVENT_UP);
|
||||
}
|
||||
static void ncd_up_cb(struct ETCP_CONN* conn, int event, void* arg) { (void)event;
|
||||
struct ncd_entry* entry = (struct ncd_entry*)arg;
|
||||
if (!entry || conn->fin_wait) return;
|
||||
ncd_event_dispatch(entry, NCD_EVENT_UP);
|
||||
}
|
||||
static void ncd_down_cb(struct ETCP_CONN* conn, int event, void* arg) { (void)event;
|
||||
struct ncd_entry* entry = (struct ncd_entry*)arg;
|
||||
if (!entry) return;
|
||||
if (conn->fin_wait && entry->handle_count <= 0) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] DOWN during fin_wait, cleaning up node=0x%016llx", (unsigned long long)entry->node_id);
|
||||
conn->fin_wait = 0; conn->fin_wait_clear_cb = NULL; 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; }
|
||||
etcp_conn_remove_cbk(conn, ncd_init_cb, entry);;
|
||||
etcp_conn_remove_cbk(conn, ncd_up_cb, entry);;
|
||||
etcp_conn_remove_cbk(conn, ncd_down_cb, entry);;
|
||||
etcp_connection_close(conn);
|
||||
ncd_registry_remove(entry);
|
||||
u_free(entry);
|
||||
return;
|
||||
}
|
||||
ncd_event_dispatch(entry, NCD_EVENT_DOWN);
|
||||
}
|
||||
|
||||
/* ═══════════ таймер подключения ═══════════ */
|
||||
|
||||
static void ncd_connect_timeout_cb(void* arg) {
|
||||
struct ncd_entry* entry = (struct ncd_entry*)arg;
|
||||
if (!entry || entry->timed_out) return;
|
||||
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);
|
||||
}
|
||||
|
||||
/* ═══════════ асинхронная доставка UP ═══════════ */
|
||||
|
||||
static void ncd_deliver_up_cb(void* arg) {
|
||||
struct NODE_CONN_DIRECT* h = (struct NODE_CONN_DIRECT*)arg;
|
||||
if (h->cb) h->cb(h, NCD_EVENT_UP, h->cb_arg);
|
||||
}
|
||||
|
||||
/* ═══════════ FIN_WAIT ═══════════ */
|
||||
|
||||
static void ncd_fin_wait_cancelled(struct ETCP_CONN* conn, void* arg) {
|
||||
struct ncd_entry* entry = (struct ncd_entry*)arg;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] fin_wait cancelled node=0x%016llx", (unsigned long long)entry->node_id);
|
||||
if (entry->fin_wait_timer) { uasync_cancel_timeout(entry->ua, entry->fin_wait_timer); entry->fin_wait_timer = NULL; }
|
||||
}
|
||||
|
||||
static void ncd_fin_wait_timeout_cb(void* arg) {
|
||||
struct ncd_entry* entry = (struct ncd_entry*)arg;
|
||||
if (!entry || !entry->conn) return;
|
||||
entry->fin_wait_timer = NULL;
|
||||
if (!entry->conn->fin_wait) return;
|
||||
DEBUG_WARN(DEBUG_CATEGORY_NCD, "[ncd] fin_wait timeout, force close node=0x%016llx", (unsigned long long)entry->node_id);
|
||||
entry->conn->fin_wait = 0; entry->conn->fin_wait_clear_cb = NULL; entry->conn->fin_wait_clear_arg = NULL;
|
||||
etcp_conn_remove_cbk(entry->conn, ncd_init_cb, entry);
|
||||
etcp_conn_remove_cbk(entry->conn, ncd_up_cb, entry);
|
||||
etcp_conn_remove_cbk(entry->conn, ncd_down_cb, entry);
|
||||
etcp_connection_close(entry->conn);
|
||||
ncd_registry_remove(entry);
|
||||
u_free(entry);
|
||||
}
|
||||
|
||||
/* ═══════════ приём CLOSE / KEEP_ALIVE ═══════════ */
|
||||
|
||||
static void ncd_recv_control_handler(struct ETCP_CONN* conn, struct ll_entry* e) {
|
||||
if (!conn || !e || e->len < NCD_CONTROL_MSG_SIZE) {
|
||||
if (e) { queue_dgram_free(e); queue_entry_free(e); }
|
||||
return;
|
||||
}
|
||||
struct ncd_control_msg* msg = (struct ncd_control_msg*)e->dgram;
|
||||
uint64_t sender_id = msg->node_id;
|
||||
struct ncd_entry* entry = ncd_registry_find(sender_id);
|
||||
|
||||
switch (msg->subcmd) {
|
||||
case NCD_SUBCMD_CLOSE:
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] recv CLOSE from 0x%016llx", (unsigned long long)sender_id);
|
||||
if (!entry) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] no entry for CLOSE sender 0x%016llx, closing conn", (unsigned long long)sender_id);
|
||||
if (conn) etcp_connection_close(conn);
|
||||
break;
|
||||
}
|
||||
if (entry->handle_count > 0) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] refusing CLOSE, still have %d handles for 0x%016llx",
|
||||
entry->handle_count, (unsigned long long)sender_id);
|
||||
{ struct ncd_control_msg resp; resp.cmd = ETCP_RT_ID_NCD_CONTROL; resp.subcmd = NCD_SUBCMD_KEEP_ALIVE;
|
||||
resp.node_id = conn->instance->node_id;
|
||||
struct ll_entry* qe = queue_entry_new(0);
|
||||
if (qe) { qe->dgram = u_malloc(sizeof(resp)); memcpy(qe->dgram, &resp, sizeof(resp)); qe->len = sizeof(resp);
|
||||
etcp_send(conn, qe); }
|
||||
}
|
||||
} else {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] closing conn for CLOSE from 0x%016llx", (unsigned long long)sender_id);
|
||||
if (conn) etcp_connection_close(conn);
|
||||
}
|
||||
break;
|
||||
case NCD_SUBCMD_KEEP_ALIVE:
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] recv KEEP_ALIVE from 0x%016llx", (unsigned long long)sender_id);
|
||||
if (entry && entry->conn->fin_wait) {
|
||||
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; }
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] KEEP_ALIVE: fin_wait cleared, conn stays alive");
|
||||
}
|
||||
break;
|
||||
}
|
||||
queue_dgram_free(e); queue_entry_free(e);
|
||||
}
|
||||
|
||||
/* ═══════════ инициализация глобального обработчика ═══════════ */
|
||||
|
||||
static void ncd_init_control_binding(struct UTUN_INSTANCE* inst) {
|
||||
if (g_ncd_control_bound) return;
|
||||
etcp_bind(inst, ETCP_RT_ID_NCD_CONTROL, ncd_recv_control_handler);
|
||||
g_ncd_control_bound = 1;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] bound ETCP_RT_ID_NCD_CONTROL handler");
|
||||
}
|
||||
|
||||
/* ═══════════ API ═══════════ */
|
||||
|
||||
int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id, uint64_t group_id,
|
||||
ncd_callback cb, void* cb_arg,
|
||||
struct NODE_CONN_DIRECT** out_handle) {
|
||||
if (!inst || !out_handle) return NCD_ERR;
|
||||
*out_handle = NULL;
|
||||
ncd_init_control_binding(inst);
|
||||
|
||||
/* 1. Ищем в реестре — conn уже есть */
|
||||
struct ncd_entry* entry = ncd_registry_find(node_id);
|
||||
if (entry) {
|
||||
/* снять fin_wait если был */
|
||||
if (entry->conn && entry->conn->fin_wait) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open 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] 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 REUSED (ready) node=0x%016llx handles=%d", (unsigned long long)node_id, entry->handle_count);
|
||||
} else {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open REUSED (pending) node=0x%016llx handles=%d", (unsigned long long)node_id, entry->handle_count);
|
||||
}
|
||||
return NCD_REUSED;
|
||||
}
|
||||
|
||||
/* 2. Ищем conn через instance_find_conn (входящее / созданное etcp_connect) */
|
||||
struct ETCP_CONN* conn = instance_find_conn(inst, node_id);
|
||||
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);
|
||||
conn->fin_wait = 0; conn->fin_wait_clear_cb = NULL; conn->fin_wait_clear_arg = NULL;
|
||||
}
|
||||
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->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] 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 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");
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open REUSED new-entry (pending) node=0x%016llx conn=%p", (unsigned long long)node_id, (void*)conn);
|
||||
}
|
||||
return NCD_REUSED;
|
||||
}
|
||||
|
||||
/* 3. Новое подключение */
|
||||
struct TOPO_NODE* ni = ncd_lookup_node(inst, node_id);
|
||||
if (!ni) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] node not found id=0x%016llx", (unsigned long long)node_id);
|
||||
return NCD_ERR;
|
||||
}
|
||||
|
||||
conn = etcp_connection_create(inst, NULL);
|
||||
if (!conn) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] etcp_connection_create failed node=0x%016llx", (unsigned long long)node_id);
|
||||
topo_node_registry_unref(inst->topo_groups, ni->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] sc_init_ctx 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;
|
||||
}
|
||||
if (sc_set_peer_public_key(&conn->crypto_ctx, ni->public_key, 0) != SC_OK) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] sc_set_peer_public_key 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;
|
||||
}
|
||||
|
||||
/* Подключаем conn в inst->connections с индексом по node_id */
|
||||
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); }
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
ncd_registry_add(entry);
|
||||
|
||||
struct NODE_CONN_DIRECT* h = u_calloc(1, sizeof(*h));
|
||||
if (!h) { DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] alloc handle failed node=0x%016llx", (unsigned long long)node_id);
|
||||
ncd_registry_remove(entry); u_free(entry); etcp_connection_close(conn); topo_node_registry_unref(inst->topo_groups, ni->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 = 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 && 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);
|
||||
}
|
||||
|
||||
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",
|
||||
(unsigned long long)node_id, (void*)conn, link_count, entry->handle_count);
|
||||
topo_node_registry_unref(inst->topo_groups, ni->node_id);
|
||||
return NCD_NEW;
|
||||
}
|
||||
|
||||
void node_conn_direct_close(struct NODE_CONN_DIRECT* h) {
|
||||
if (!h) return;
|
||||
struct ncd_entry* entry = h->entry;
|
||||
if (!entry) { u_free(h); return; }
|
||||
|
||||
uint64_t node_id = entry->node_id;
|
||||
struct ETCP_CONN* conn = entry->conn;
|
||||
|
||||
/* Удаляем handle из списка */
|
||||
struct NODE_CONN_DIRECT** pp = &entry->handles;
|
||||
while (*pp) { if (*pp == h) { *pp = h->next; break; } pp = &(*pp)->next; }
|
||||
entry->handle_count--;
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] close node=0x%016llx remaining=%d", (unsigned long long)node_id, entry->handle_count);
|
||||
|
||||
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;
|
||||
conn->fin_wait_clear_cb = ncd_fin_wait_cancelled;
|
||||
conn->fin_wait_clear_arg = entry;
|
||||
{ struct ncd_control_msg msg; msg.cmd = ETCP_RT_ID_NCD_CONTROL; msg.subcmd = NCD_SUBCMD_CLOSE;
|
||||
msg.node_id = conn->instance->node_id;
|
||||
struct ll_entry* qe = queue_entry_new(0);
|
||||
if (qe) { qe->dgram = u_malloc(sizeof(msg)); memcpy(qe->dgram, &msg, sizeof(msg)); qe->len = sizeof(msg);
|
||||
etcp_send(conn, qe);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] sent CLOSE to 0x%016llx", (unsigned long long)node_id); }
|
||||
}
|
||||
entry->fin_wait_timer = uasync_set_timeout(entry->ua, NCD_FIN_WAIT_TIMEOUT_TB, entry, ncd_fin_wait_timeout_cb, "ncd_fin_wait");
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] fin_wait started node=0x%016llx", (unsigned long long)node_id);
|
||||
} else {
|
||||
etcp_conn_remove_cbk(conn, ncd_init_cb, entry);;
|
||||
etcp_conn_remove_cbk(conn, ncd_up_cb, entry);;
|
||||
etcp_conn_remove_cbk(conn, ncd_down_cb, entry);;
|
||||
if (conn) etcp_connection_close(conn);
|
||||
ncd_registry_remove(entry);
|
||||
u_free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
h->entry = NULL;
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#ifndef NODE_CONN_DIRECT_H
|
||||
#define NODE_CONN_DIRECT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct UTUN_INSTANCE;
|
||||
struct ETCP_CONN;
|
||||
|
||||
/* ─── Return codes ─── */
|
||||
#define NCD_NEW 0
|
||||
#define NCD_REUSED 1
|
||||
#define NCD_ERR -1
|
||||
|
||||
/* ─── Opaque handle ─── */
|
||||
struct NODE_CONN_DIRECT;
|
||||
|
||||
/* ─── Callback events (единый callback на handle) ─── */
|
||||
enum ncd_event {
|
||||
NCD_EVENT_UP = 0,
|
||||
NCD_EVENT_DOWN = 1,
|
||||
NCD_EVENT_TIMEOUT = 2,
|
||||
};
|
||||
|
||||
typedef void (*ncd_callback)(struct NODE_CONN_DIRECT* h, enum ncd_event event, void* arg);
|
||||
|
||||
/*
|
||||
* Открыть 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,
|
||||
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);
|
||||
|
||||
void node_conn_direct_close(struct NODE_CONN_DIRECT* h);
|
||||
|
||||
struct ETCP_CONN* node_conn_direct_get_conn(struct NODE_CONN_DIRECT* h);
|
||||
|
||||
/* ─── Протокол CLOSE / KEEP_ALIVE (ETCP_RT_ID_NCD_CONTROL = 0x12) ─── */
|
||||
|
||||
#define NCD_SUBCMD_CLOSE 0x01
|
||||
#define NCD_SUBCMD_KEEP_ALIVE 0x02
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct ncd_control_msg {
|
||||
uint8_t cmd; /* ETCP_RT_ID_NCD_CONTROL */
|
||||
uint8_t subcmd; /* NCD_SUBCMD_CLOSE / KEEP_ALIVE */
|
||||
uint64_t node_id; /* node_id отправителя */
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
#define NCD_CONTROL_MSG_SIZE sizeof(struct ncd_control_msg)
|
||||
|
||||
#endif
|
||||
+1
-1
@@ -114,7 +114,7 @@ struct UTUN_INSTANCE {
|
||||
struct ll_queue* tcp_connections; // indexed by node_id, data=tcp_conn_entry [TCP-only]
|
||||
|
||||
// Callback chain for new ETCP connections
|
||||
struct etcp_cbk_entry* new_conn_cbks;
|
||||
struct etcp_inst_cbk_entry* new_conn_cbks;
|
||||
struct etcp_status_cbk_entry* conn_status_cbks; // instance-level: NEW/UP/DOWN/DELETE
|
||||
void* test_user_ptr; // Generic user pointer (used by tests)
|
||||
|
||||
|
||||
Reference in new issue
Block a user