etcp: replace connections linked-list with indexed ll_queue, add state/ref_count lifecycle
- Remove ETCP_CONN.next linked-list, UTUN_INSTANCE.connections list/count
- Unified connections in single ll_queue indexed by peer_node_id (0=pending)
- struct conn_queue_entry { peer_node_id, conn* } for uniform queue data
- Connection lifecycle via etcp.c: create→pending, conn_ready→indexed, close→detach+deferred free
- Close split: phase1 detach from external world, phase2 deferred via uasync_call_soon
- etcp_conn_set_peer_node_id: reindex on ID change (WARN)
- etcp_conn_ref_take/free: blocking close until refcount returns to 0
- Remove chat_connections — use unified connections queue directly
- Update all iteration/search patterns across 40 files (src + tests + chatgui)
This commit is contained in:
1 parent
6902f5fd95
commit
a7ecee01f5
40 files changed
+650
-449
No files matched your search
+14
-16
@@ -885,10 +885,10 @@ static void send_conn_list(struct control_server* server, struct control_client*
|
||||
|
||||
/* Count connections */
|
||||
uint8_t count = 0;
|
||||
struct ETCP_CONN* conn = instance->connections;
|
||||
while (conn && count < ETCPMON_MAX_CONNECTIONS) {
|
||||
struct ll_entry* entry = instance->connections->head;
|
||||
while (entry && count < ETCPMON_MAX_CONNECTIONS) {
|
||||
count++;
|
||||
conn = conn->next;
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
/* Build response */
|
||||
@@ -909,12 +909,13 @@ static void send_conn_list(struct control_server* server, struct control_client*
|
||||
rsp->count = count;
|
||||
|
||||
struct etcpmon_conn_info* info = (struct etcpmon_conn_info*)(buffer + sizeof(*hdr) + sizeof(*rsp));
|
||||
conn = instance->connections;
|
||||
for (uint8_t i = 0; i < count && conn; i++) {
|
||||
info[i].peer_node_id = conn->peer_node_id;
|
||||
strncpy(info[i].name, conn->log_name, ETCPMON_MAX_CONN_NAME - 1);
|
||||
entry = instance->connections->head;
|
||||
for (uint8_t i = 0; i < count && entry; i++) {
|
||||
struct conn_queue_entry* ce = (struct conn_queue_entry*)entry->data;
|
||||
info[i].peer_node_id = ce->conn->peer_node_id;
|
||||
strncpy(info[i].name, ce->conn->log_name, ETCPMON_MAX_CONN_NAME - 1);
|
||||
info[i].name[ETCPMON_MAX_CONN_NAME - 1] = '\0';
|
||||
conn = conn->next;
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
/* Log and send response */
|
||||
@@ -1372,14 +1373,11 @@ static void send_debug_config(struct control_server* server, struct control_clie
|
||||
|
||||
static struct ETCP_CONN* find_connection_by_peer_id(struct UTUN_INSTANCE* instance,
|
||||
uint64_t peer_id) {
|
||||
struct ETCP_CONN* conn = instance->connections;
|
||||
while (conn) {
|
||||
if (conn->peer_node_id == peer_id) {
|
||||
return conn;
|
||||
}
|
||||
conn = conn->next;
|
||||
}
|
||||
return NULL;
|
||||
if (!instance || !instance->connections) return NULL;
|
||||
struct ll_entry* e = queue_find_data_by_index(instance->connections, (const uint8_t*)&peer_id);
|
||||
if (!e) return NULL;
|
||||
struct conn_queue_entry* ce = (struct conn_queue_entry*)e->data;
|
||||
return ce->conn;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
|
||||
+29
-18
@@ -488,9 +488,9 @@ static int db_sync_send_hash(struct DB_SYNC* db, uint64_t node_id,
|
||||
entry->len = plen + 9;
|
||||
|
||||
struct ETCP_CONN* conn = NULL;
|
||||
if (db->inst->chat_connections) {
|
||||
struct ll_entry* e = queue_find_data_by_index(db->inst->chat_connections, (const uint8_t*)&node_id);
|
||||
if (e) { struct { uint64_t node_id; struct ETCP_CONN* conn; }* ce = e->data; if (ce->conn->links_up) conn = ce->conn; }
|
||||
{
|
||||
struct ll_entry* e = queue_find_data_by_index(db->inst->connections, (const uint8_t*)&node_id);
|
||||
if (e) { struct conn_queue_entry* ce = (struct conn_queue_entry*)e->data; if (ce->conn->links_up) conn = ce->conn; }
|
||||
}
|
||||
if (!conn) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC,
|
||||
@@ -1430,11 +1430,16 @@ int db_sync_init(struct UTUN_INSTANCE* inst)
|
||||
etcp_set_new_conn_cbk(inst, db_sync_on_new_conn, NULL);
|
||||
|
||||
// Attach to existing connections
|
||||
struct ETCP_CONN* conn = inst->connections;
|
||||
while (conn) {
|
||||
etcp_conn_add_up_cbk(conn, db_sync_on_conn_up, NULL);
|
||||
etcp_conn_add_down_cbk(conn, db_sync_on_conn_down, NULL);
|
||||
conn = conn->next;
|
||||
{
|
||||
struct ll_entry* entry = inst->connections->head;
|
||||
while (entry) {
|
||||
struct conn_queue_entry* ce = (struct conn_queue_entry*)entry->data;
|
||||
if (ce && ce->conn) {
|
||||
etcp_conn_add_up_cbk(ce->conn, db_sync_on_conn_up, NULL);
|
||||
etcp_conn_add_down_cbk(ce->conn, db_sync_on_conn_down, NULL);
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (db->enabled)
|
||||
@@ -1474,11 +1479,16 @@ void db_sync_destroy(struct UTUN_INSTANCE* inst)
|
||||
}
|
||||
|
||||
// Detach from existing connections
|
||||
struct ETCP_CONN* conn = inst->connections;
|
||||
while (conn) {
|
||||
etcp_conn_remove_up_cbk(conn, db_sync_on_conn_up, NULL);
|
||||
etcp_conn_remove_down_cbk(conn, db_sync_on_conn_down, NULL);
|
||||
conn = conn->next;
|
||||
{
|
||||
struct ll_entry* entry = inst->connections->head;
|
||||
while (entry) {
|
||||
struct conn_queue_entry* ce = (struct conn_queue_entry*)entry->data;
|
||||
if (ce && ce->conn) {
|
||||
etcp_conn_remove_up_cbk(ce->conn, db_sync_on_conn_up, NULL);
|
||||
etcp_conn_remove_down_cbk(ce->conn, db_sync_on_conn_down, NULL);
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
|
||||
db_sqlite_close(db);
|
||||
@@ -1579,11 +1589,12 @@ struct DB_SYNC_INSTANCE* db_sync_instance_add(struct UTUN_INSTANCE* inst,
|
||||
|
||||
// Initiate sync with already connected peers
|
||||
{
|
||||
struct ETCP_CONN* conn = inst->connections;
|
||||
while (conn) {
|
||||
uint64_t pid = conn->peer_node_id;
|
||||
struct ll_entry* entry = inst->connections->head;
|
||||
while (entry) {
|
||||
struct conn_queue_entry* ce = (struct conn_queue_entry*)entry->data;
|
||||
uint64_t pid = ce->conn->peer_node_id;
|
||||
if (pid != 0 && pid != inst->node_id
|
||||
&& conn->links_up > 0 && conn->initialized)
|
||||
&& ce->conn->links_up > 0 && ce->conn->initialized)
|
||||
{
|
||||
struct SI_PEER* p = si_peer_add(si, pid);
|
||||
if (p && p->synced == 0) {
|
||||
@@ -1591,7 +1602,7 @@ struct DB_SYNC_INSTANCE* db_sync_instance_add(struct UTUN_INSTANCE* inst,
|
||||
db_sync_initiate_sync(si, pid);
|
||||
}
|
||||
}
|
||||
conn = conn->next;
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+151
-75
@@ -44,6 +44,7 @@ static void input_send_q_cb(struct ll_queue* q, void* arg);
|
||||
static void wait_ack_cb(struct ll_queue* q, void* arg);
|
||||
static void send_ack_req_cb(struct ll_queue* q, void* arg);
|
||||
static void etcp_conn_process_send_queue(struct ETCP_CONN* etcp);
|
||||
static void etcp_connection_free_deferred(void* arg);
|
||||
struct ETCP_DGRAM* etcp_request_pkt(struct ETCP_CONN* etcp);
|
||||
|
||||
static void clear_queue(struct ll_queue* q) {
|
||||
@@ -217,6 +218,7 @@ struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance, char* n
|
||||
etcp->links_up=0;
|
||||
etcp->reset_done=0;
|
||||
etcp->callbacks_running=0;
|
||||
etcp->ref_count=0;
|
||||
etcp->last_rr_link=NULL;
|
||||
etcp->name = u_strdup(name);
|
||||
// Initialize log_name with local node_id (peer will be updated later when known)
|
||||
@@ -256,7 +258,19 @@ struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance, char* n
|
||||
|
||||
etcp->link_ready_for_send_fn = etcp_link_ready_callback;
|
||||
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] connection initialized. ETCP=%p mtu=%d, next_tx_id=%u",
|
||||
// Add to instance's connections queue (peer_node_id=0 for pending, reindexed later)
|
||||
{
|
||||
struct ll_entry* qe = queue_entry_new(sizeof(struct conn_queue_entry));
|
||||
if (!qe) { etcp_connection_close(etcp); return NULL; }
|
||||
struct conn_queue_entry* ce = (struct conn_queue_entry*)qe->data;
|
||||
ce->peer_node_id = 0;
|
||||
ce->conn = etcp;
|
||||
etcp->conn_queue_entry = qe;
|
||||
etcp->conn_queue = instance->connections;
|
||||
queue_data_put_with_index(instance->connections, qe);
|
||||
}
|
||||
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] connection initialized. ETCP=%p mtu=%d, next_tx_id=%u state=pending",
|
||||
etcp->log_name, etcp, etcp->mtu, etcp->next_tx_id);
|
||||
|
||||
// Вызываем callback для нового соединения если установлен
|
||||
@@ -286,57 +300,15 @@ static void etcp_on_down(struct ETCP_CONN* etcp) {
|
||||
}
|
||||
|
||||
|
||||
// Close connection with NULL pointer safety (prevents double free)
|
||||
void etcp_connection_close(struct ETCP_CONN* etcp) {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "");
|
||||
// Phase 2 resources cleanup (callable both sync and async via call_soon)
|
||||
static void etcp_connection_free_resources(struct ETCP_CONN* etcp) {
|
||||
if (!etcp) return;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] freeing resources phase 2", etcp->log_name);
|
||||
|
||||
if (etcp->callbacks_running) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "[%s] FATAL: etcp_connection_close called from inside callback chain — SEGFAULTING to show backtrace",
|
||||
etcp->log_name);
|
||||
*(volatile int*)0 = 0;
|
||||
}
|
||||
|
||||
if (etcp->links_up!=0) {
|
||||
etcp->links_up=0;
|
||||
etcp_on_down(etcp);
|
||||
}
|
||||
|
||||
// Cancel active timers to prevent memory leaks
|
||||
if (etcp->retrans_timer) {
|
||||
uasync_cancel_timeout(etcp->instance->ua, etcp->retrans_timer);
|
||||
etcp->retrans_timer = NULL;
|
||||
}
|
||||
if (etcp->ack_resp_timer) {
|
||||
uasync_cancel_timeout(etcp->instance->ua, etcp->ack_resp_timer);
|
||||
etcp->ack_resp_timer = NULL;
|
||||
}
|
||||
etcp_metrics_stop_timer(etcp);
|
||||
|
||||
routing_del_conn(etcp);
|
||||
|
||||
// NOTE: topo_bgp_remove_conn is already called via down_cbk in etcp_on_down() above
|
||||
// DO NOT call it again here to avoid double-processing and ref_count corruption
|
||||
|
||||
// Очистить транзитные очереди (до pn_deinit/stcp_link_close — waiter'ы на normalizer->input/tx_queue)
|
||||
etcp_router_transit_queues_destroy(etcp);
|
||||
|
||||
// Deinitialize packet normalizer (this will call routing_del_conn)
|
||||
if (etcp->normalizer) {
|
||||
pn_deinit((struct PKTNORM*)etcp->normalizer);
|
||||
etcp->normalizer = NULL;
|
||||
}
|
||||
|
||||
// Clear links BEFORE draining queues: etcp_link_close calls
|
||||
// etcp_conn_on_inflight_lim_changed -> input_queue_try_resume
|
||||
// which accesses input_send_q, input_queue, input_wait_ack.
|
||||
// Close links
|
||||
if (etcp->links) {
|
||||
struct ETCP_LINK* link = etcp->links;
|
||||
while (link) {
|
||||
struct ETCP_LINK* next = link->next;
|
||||
etcp_link_close(link);
|
||||
link = next;
|
||||
}
|
||||
while (link) { struct ETCP_LINK* next = link->next; etcp_link_close(link); link = next; }
|
||||
etcp->links = NULL;
|
||||
}
|
||||
|
||||
@@ -350,35 +322,86 @@ void etcp_connection_close(struct ETCP_CONN* etcp) {
|
||||
|
||||
// Free callback chains
|
||||
{ struct etcp_cbk_entry* cbe = etcp->ready_cbks; while (cbe) { struct etcp_cbk_entry* n = cbe->next; u_free(cbe); cbe = n; } etcp->ready_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->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; }
|
||||
|
||||
// Free memory pools after all elements are returned
|
||||
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;
|
||||
}
|
||||
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; }
|
||||
|
||||
u_free(etcp->name);
|
||||
u_free(etcp);
|
||||
}
|
||||
|
||||
{ struct UTUN_INSTANCE* inst = etcp->instance;
|
||||
if (inst && inst->connections) {
|
||||
struct ETCP_CONN** pp = &inst->connections;
|
||||
while (*pp && *pp != etcp) pp = &(*pp)->next;
|
||||
if (*pp) { *pp = etcp->next; if (inst->connections_count) inst->connections_count--; }
|
||||
}
|
||||
static void etcp_connection_free_deferred(void* arg) {
|
||||
etcp_connection_free_resources((struct ETCP_CONN*)arg);
|
||||
}
|
||||
|
||||
// Close connection: phase 1 detach + deferred phase 2 cleanup
|
||||
void etcp_connection_close(struct ETCP_CONN* etcp) {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "");
|
||||
if (!etcp) return;
|
||||
if (etcp->state == 2) { DEBUG_WARN(DEBUG_CATEGORY_ETCP, "[%s] already deleted", etcp->log_name); return; }
|
||||
|
||||
if (etcp->callbacks_running) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "[%s] FATAL: etcp_connection_close called from inside callback chain — SEGFAULTING to show backtrace",
|
||||
etcp->log_name);
|
||||
*(volatile int*)0 = 0;
|
||||
}
|
||||
|
||||
// Clear next pointer to prevent dangling references
|
||||
etcp->next = NULL;
|
||||
// === PHASE 1: detach from external world ===
|
||||
|
||||
// TODO: Free rx_list, etc.
|
||||
u_free(etcp);
|
||||
if (etcp->links_up != 0) { etcp->links_up = 0; etcp_on_down(etcp); }
|
||||
|
||||
// Cancel active timers
|
||||
if (etcp->retrans_timer) { uasync_cancel_timeout(etcp->instance->ua, etcp->retrans_timer); etcp->retrans_timer = NULL; }
|
||||
if (etcp->ack_resp_timer) { uasync_cancel_timeout(etcp->instance->ua, etcp->ack_resp_timer); etcp->ack_resp_timer = NULL; }
|
||||
etcp_metrics_stop_timer(etcp);
|
||||
|
||||
routing_del_conn(etcp);
|
||||
etcp_router_transit_queues_destroy(etcp);
|
||||
|
||||
if (etcp->normalizer) { pn_deinit((struct PKTNORM*)etcp->normalizer); etcp->normalizer = NULL; }
|
||||
|
||||
// Close links (detach from socket scan queues)
|
||||
if (etcp->links) {
|
||||
struct ETCP_LINK* link = etcp->links;
|
||||
while (link) { struct ETCP_LINK* next = link->next; etcp_link_close(link); link = next; }
|
||||
etcp->links = NULL;
|
||||
}
|
||||
|
||||
// Remove from instance queue
|
||||
if (etcp->conn_queue && etcp->conn_queue_entry) {
|
||||
queue_remove_data(etcp->conn_queue, etcp->conn_queue_entry);
|
||||
queue_entry_free(etcp->conn_queue_entry);
|
||||
etcp->conn_queue_entry = NULL;
|
||||
etcp->conn_queue = NULL;
|
||||
}
|
||||
|
||||
etcp->state = 2; // deleted
|
||||
|
||||
// === PHASE 2: deferred resource cleanup (only if no outstanding refs) ===
|
||||
if (etcp->ref_count == 0)
|
||||
uasync_call_soon(etcp->instance->ua, etcp, etcp_connection_free_deferred);
|
||||
// else: cleanup deferred until last etcp_conn_ref_free()
|
||||
}
|
||||
|
||||
// Take a reference on connection. Returns -1 if already deleted (state==2).
|
||||
int etcp_conn_ref_take(struct ETCP_CONN* conn) {
|
||||
if (!conn) return -1;
|
||||
if (conn->state == 2) { DEBUG_WARN(DEBUG_CATEGORY_ETCP, "[%s] ref_take on deleted conn", conn->log_name); return -1; }
|
||||
conn->ref_count++;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] ref_take ref_count=%d", conn->log_name, conn->ref_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Release a reference. If last ref and conn is deleted, schedule deferred free.
|
||||
void etcp_conn_ref_free(struct ETCP_CONN* conn) {
|
||||
if (!conn) return;
|
||||
if (conn->ref_count <= 0) { DEBUG_WARN(DEBUG_CATEGORY_ETCP, "[%s] ref_free underflow ref_count=%d", conn->log_name, conn->ref_count); return; }
|
||||
conn->ref_count--;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] ref_free ref_count=%d state=%d", conn->log_name, conn->ref_count, conn->state);
|
||||
if (conn->ref_count == 0 && conn->state == 2)
|
||||
uasync_call_soon(conn->instance->ua, conn, etcp_connection_free_deferred);
|
||||
}
|
||||
|
||||
// Reset connection
|
||||
@@ -543,24 +566,77 @@ void etcp_conn_reinit(struct ETCP_CONN* etcp) {// Если сбой в обме
|
||||
// внутренняя функция. Вызывается один раз когда первый линк готов.
|
||||
void etcp_conn_ready(struct ETCP_CONN* conn) {
|
||||
if (!conn) return;
|
||||
if (conn->initialized) return; // already ready
|
||||
|
||||
conn->initialized = 1;
|
||||
conn->reset_done = 1;
|
||||
// Если tx_state не установлен (первое подключение без reinit), установим его
|
||||
if (conn->tx_state == 0) {
|
||||
conn->tx_state = ETCP_TX_STATE_DATA_WAIT;
|
||||
}
|
||||
if (conn->tx_state == 0) { conn->tx_state = ETCP_TX_STATE_DATA_WAIT; }
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] Connection ready", conn->log_name);
|
||||
|
||||
etcp_conn_queue_set_ready(conn);
|
||||
}
|
||||
|
||||
// Move from pending to indexed connections, fire ready callbacks
|
||||
void etcp_conn_queue_set_ready(struct ETCP_CONN* conn) {
|
||||
if (!conn || conn->state != 0) return;
|
||||
|
||||
// Reindex: remove old entry (key=0), add new entry with real peer_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) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[%s] failed to alloc queue entry for ready", conn->log_name); return; }
|
||||
struct conn_queue_entry* ce = (struct conn_queue_entry*)qe->data;
|
||||
ce->peer_node_id = conn->peer_node_id;
|
||||
ce->conn = conn;
|
||||
conn->conn_queue_entry = qe;
|
||||
conn->conn_queue = conn->instance->connections;
|
||||
conn->state = 1;
|
||||
queue_data_put_with_index(conn->instance->connections, qe);
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] moved to ready queue, state=%d peer_node_id=0x%llx",
|
||||
conn->log_name, conn->state, (unsigned long long)conn->peer_node_id);
|
||||
|
||||
etcp_metrics_start_timer(conn);
|
||||
|
||||
// Вызываем callback если установлен
|
||||
conn->callbacks_running = 1;
|
||||
{ struct etcp_cbk_entry* cbe = conn->ready_cbks; while (cbe) { struct etcp_cbk_entry* n = cbe->next; cbe->fn(conn, cbe->arg); cbe = n; } }
|
||||
if (conn->links_up) etcp_on_up(conn);
|
||||
conn->callbacks_running = 0;
|
||||
}
|
||||
|
||||
// Set peer_node_id, reindex if already in connections queue
|
||||
void etcp_conn_set_peer_node_id(struct ETCP_CONN* conn, uint64_t peer_node_id) {
|
||||
if (!conn) return;
|
||||
if (conn->state == 2) { DEBUG_WARN(DEBUG_CATEGORY_ETCP, "[%s] set_peer_node_id on deleted conn", conn->log_name); return; }
|
||||
|
||||
if (conn->peer_node_id == peer_node_id) return;
|
||||
|
||||
if (conn->state == 1 && conn->peer_node_id != 0) {
|
||||
// Already in indexed queue with old ID — reindex
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "[%s] peer_node_id changed 0x%llx -> 0x%llx, reindexing",
|
||||
conn->log_name, (unsigned long long)conn->peer_node_id, (unsigned long long)peer_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) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[%s] reindex alloc failed", conn->log_name); return; }
|
||||
struct conn_queue_entry* ce = (struct conn_queue_entry*)qe->data;
|
||||
ce->peer_node_id = peer_node_id;
|
||||
ce->conn = conn;
|
||||
conn->conn_queue_entry = qe;
|
||||
conn->conn_queue = conn->instance->connections;
|
||||
queue_data_put_with_index(conn->instance->connections, qe);
|
||||
}
|
||||
|
||||
conn->peer_node_id = peer_node_id;
|
||||
etcp_update_log_name(conn);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] peer_node_id set to 0x%llx", conn->log_name, (unsigned long long)peer_node_id);
|
||||
}
|
||||
|
||||
|
||||
// Update log_name when peer_node_id becomes known
|
||||
void etcp_update_log_name(struct ETCP_CONN* etcp) {
|
||||
|
||||
+32
-1
@@ -138,11 +138,19 @@ struct ACK_PACKET {
|
||||
|
||||
// ETCP connection structure (refactored)
|
||||
struct ETCP_CONN {
|
||||
struct ETCP_CONN* next;
|
||||
// State: 0=not ready, 1=ready (indexed in instance->connections), 2=deleted
|
||||
int state; // 0=pending, 1=ready, 2=deleted (phase 1 of close done)
|
||||
int ref_count; // External reference count. >0 blocks deferred resource free.
|
||||
// Take/free via etcp_conn_ref_take()/etcp_conn_ref_free().
|
||||
|
||||
int mtu;
|
||||
|
||||
struct UTUN_INSTANCE* instance;
|
||||
|
||||
// Queue entries in instance->connections or instance->pending_connections
|
||||
struct ll_entry* conn_queue_entry; // entry в очереди instance
|
||||
struct ll_queue* conn_queue; // указатель на очередь где лежим (pending или connections)
|
||||
|
||||
// Links (channels) - linked list
|
||||
struct ETCP_LINK* links;
|
||||
struct ETCP_LINK* last_rr_link; // последний линк, выбранный round-robin
|
||||
@@ -252,6 +260,29 @@ struct ETCP_CONN {
|
||||
// Functions
|
||||
struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance, char* name);
|
||||
void etcp_connection_close(struct ETCP_CONN* etcp);
|
||||
void etcp_conn_set_peer_node_id(struct ETCP_CONN* conn, uint64_t peer_node_id);
|
||||
void etcp_conn_queue_set_ready(struct ETCP_CONN* conn); // move pending->connections, fire ready cbks
|
||||
|
||||
/**
|
||||
* @brief Take a reference on the connection (blocks deferred resource free).
|
||||
* @param conn connection
|
||||
* @return 0 on success, -1 if conn is NULL or already in state 2 (deleted).
|
||||
*
|
||||
* Increments ref_count. While ref_count > 0, etcp_connection_close()
|
||||
* will detach but defer resource cleanup until all references are released.
|
||||
* Always pair with etcp_conn_ref_free().
|
||||
*/
|
||||
int etcp_conn_ref_take(struct ETCP_CONN* conn);
|
||||
|
||||
/**
|
||||
* @brief Release a reference. Triggers deferred resource free if last ref and state==2.
|
||||
* @param conn connection
|
||||
*
|
||||
* Decrements ref_count. If ref_count reaches 0 and the connection has been closed
|
||||
* (state == 2), schedules deferred resource cleanup via uasync_call_soon.
|
||||
* Safe to call on NULL.
|
||||
*/
|
||||
void etcp_conn_ref_free(struct ETCP_CONN* conn);
|
||||
|
||||
void etcp_conn_reset(struct ETCP_CONN* etcp);
|
||||
void etcp_links_reset(struct ETCP_CONN* etcp);
|
||||
|
||||
+18
-15
@@ -210,22 +210,26 @@ int etcp_connect(struct UTUN_INSTANCE* inst, struct TOPO_NODEQ* node,
|
||||
if (!inst || !node || !cb) return -1;
|
||||
uint64_t node_id = node->node->node_id;
|
||||
|
||||
struct ETCP_CONN* existing = inst->connections;
|
||||
while (existing) {
|
||||
if (existing->peer_node_id == node_id) {
|
||||
struct ETCP_LINK* l = existing->links;
|
||||
while (l) { if (l->link_state == 3) break; l = l->next; }
|
||||
if (l) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] node 0x%016llx already connected, delivering immediately",
|
||||
(unsigned long long)node_id);
|
||||
if (flags & ETCP_CONNECT_EARLY) cb(arg, existing, ETCP_CONNECT_EARLY);
|
||||
if (flags & ETCP_CONNECT_LATE) cb(arg, existing, ETCP_CONNECT_LATE);
|
||||
if ((flags & ETCP_CONNECT_BGP_READY) && existing->routing_exchange_active >= 3)
|
||||
cb(arg, existing, ETCP_CONNECT_BGP_READY);
|
||||
return 0;
|
||||
// Check if already connected via indexed queue
|
||||
{
|
||||
struct ll_entry* e = queue_find_data_by_index(inst->connections, (const uint8_t*)&node_id);
|
||||
if (e) {
|
||||
struct conn_queue_entry* ce = (struct conn_queue_entry*)e->data;
|
||||
struct ETCP_CONN* existing = ce->conn;
|
||||
if (existing && existing->peer_node_id == node_id) {
|
||||
struct ETCP_LINK* l = existing->links;
|
||||
while (l) { if (l->link_state == 3) break; l = l->next; }
|
||||
if (l) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] node 0x%016llx already connected, delivering immediately",
|
||||
(unsigned long long)node_id);
|
||||
if (flags & ETCP_CONNECT_EARLY) cb(arg, existing, ETCP_CONNECT_EARLY);
|
||||
if (flags & ETCP_CONNECT_LATE) cb(arg, existing, ETCP_CONNECT_LATE);
|
||||
if ((flags & ETCP_CONNECT_BGP_READY) && existing->routing_exchange_active >= 3)
|
||||
cb(arg, existing, ETCP_CONNECT_BGP_READY);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
existing = existing->next;
|
||||
}
|
||||
|
||||
struct ETCP_CONNECT* ctx = connect_find(inst, node_id);
|
||||
@@ -241,7 +245,6 @@ int etcp_connect(struct UTUN_INSTANCE* inst, struct TOPO_NODEQ* node,
|
||||
struct ETCP_CONN* conn = etcp_connection_create(inst, NULL);
|
||||
if (!conn) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] failed to create ETCP_CONN for node 0x%016llx",
|
||||
(unsigned long long)node_id); cb(arg, NULL, 0); return -1; }
|
||||
conn->next = inst->connections; inst->connections = conn; inst->connections_count++;
|
||||
if (sc_init_ctx(&conn->crypto_ctx, &inst->my_keys) != SC_OK) {
|
||||
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;
|
||||
|
||||
+20
-29
@@ -32,18 +32,17 @@
|
||||
// TCP server: on new incoming connection → create minimal ETCP_CONN
|
||||
static void tcp_server_on_link(struct stcp_link *link, void *arg) {
|
||||
struct UTUN_INSTANCE *inst = (struct UTUN_INSTANCE *)arg;
|
||||
struct ETCP_CONN *conn = u_calloc(1, sizeof(struct ETCP_CONN));
|
||||
struct ETCP_CONN *conn = etcp_connection_create(inst, NULL);
|
||||
if (!conn) return;
|
||||
conn->instance = inst;
|
||||
conn->transport_link = link;
|
||||
snprintf(conn->log_name, sizeof(conn->log_name), "tcp-[%p]", (void*)link);
|
||||
conn->next = inst->connections;
|
||||
inst->connections = conn;
|
||||
inst->connections_count++;
|
||||
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->ready_cbks; while (rcb) { struct etcp_cbk_entry* n = rcb->next; rcb->fn(conn, rcb->arg); rcb = n; } }
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "TCP server new conn=%p total=%d", (void*)conn, inst->connections_count);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "TCP server new conn=%p total=%d pending=%d",
|
||||
(void*)conn,
|
||||
queue_entry_count(inst->connections),
|
||||
queue_entry_count(inst->connections));
|
||||
}
|
||||
|
||||
// Forward declaration
|
||||
@@ -1464,8 +1463,7 @@ static int handle_init_response_client(struct ETCP_SOCKET* e_sock, struct ETCP_D
|
||||
|
||||
// DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Received INIT_RESPONSE from server_node_id=%llu, mtu=%d", (unsigned long long)server_node_id, link->mtu);
|
||||
|
||||
link->etcp->peer_node_id = server_node_id; // If not set
|
||||
etcp_update_log_name(link->etcp); // Update log_name with peer_node_id
|
||||
etcp_conn_set_peer_node_id(link->etcp, server_node_id);
|
||||
|
||||
link->initialized = 1;// получен init response (client)
|
||||
link->link_state = 3; // connected
|
||||
@@ -1678,11 +1676,11 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
|
||||
req->src_ipv4[0], req->src_ipv4[1], req->src_ipv4[2], req->src_ipv4[3],
|
||||
src_port, session_id, sockaddr_storage_to_str(&addr).str);
|
||||
|
||||
struct ETCP_CONN* conn=e_sock->instance->connections;
|
||||
while (conn) {// ищем есть ли подключение к этому пиру
|
||||
if (conn->peer_node_id==peer_id) break;
|
||||
conn=conn->next;
|
||||
}
|
||||
struct ETCP_CONN* conn = NULL;
|
||||
{
|
||||
struct ll_entry* e = queue_find_data_by_index(e_sock->instance->connections, (const uint8_t*)&peer_id);
|
||||
if (e) { struct conn_queue_entry* ce = (struct conn_queue_entry*)e->data; conn = ce->conn; }
|
||||
}
|
||||
|
||||
int new_conn=0;
|
||||
if (!conn || conn->peer_node_id!=peer_id) {// создаём новое подключение [new etcp]
|
||||
@@ -1690,14 +1688,11 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
|
||||
conn=etcp_connection_create(e_sock->instance,"");
|
||||
if (!conn) { errorcode=55; DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "failed to create connection"); goto ec_fr; }
|
||||
memcpy(&conn->crypto_ctx, &sc, sizeof(sc));
|
||||
conn->peer_node_id=peer_id;
|
||||
etcp_update_log_name(conn);
|
||||
etcp_conn_set_peer_node_id(conn, peer_id);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "New connection received on socket %s: log_name=%s peer_id=%lu peer:%s", e_sock->name, conn->log_name, (unsigned long)peer_id, sockaddr_storage_to_str(&addr).str);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "New connection from %s peer_id=%ld etcp=%p", ip_to_str(&addr, addr.ss_family).str, peer_id, conn);
|
||||
conn->next = e_sock->instance->connections;
|
||||
e_sock->instance->connections = conn;
|
||||
e_sock->instance->connections_count++;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Added incoming connection %p to instance, total count: %d", conn, e_sock->instance->connections_count);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "New connection from %s peer_id=%ld etcp=%p total=%d",
|
||||
ip_to_str(&addr, addr.ss_family).str, peer_id, conn,
|
||||
queue_entry_count(e_sock->instance->connections));
|
||||
}
|
||||
else {// check keys если существующее подключение
|
||||
if (memcmp(conn->crypto_ctx.peer_public_key, sc.peer_public_key, SC_PUBKEY_SIZE)) { errorcode=5; DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "peer key mismatch for node %016llx", (unsigned long long)peer_id); goto ec_fr; }// коллизия - peer id совпал а ключи разные.
|
||||
@@ -2065,8 +2060,8 @@ int init_connections(struct UTUN_INSTANCE* instance) {
|
||||
|
||||
// Initialize clients - create outgoing connections
|
||||
struct CFG_CLIENT* client = config->clients;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "init_connections called, instance=%p, config=%p, clients=%p, connections_count=%d",
|
||||
instance, config, config ? config->clients : NULL, instance ? instance->connections_count : -1);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "init_connections called, instance=%p, config=%p, clients=%p, total_conns=%d",
|
||||
instance, config, config ? config->clients : NULL, instance ? queue_entry_count(instance->connections) : -1);
|
||||
while (client) {
|
||||
// Check if client has required configuration
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Client %s - keepalive=%d, links=%p, peer_key_len=%zu",
|
||||
@@ -2196,22 +2191,18 @@ int init_connections(struct UTUN_INSTANCE* instance) {
|
||||
client_link = client_link->next;
|
||||
}
|
||||
|
||||
etcp_conn->next = instance->connections;
|
||||
instance->connections = etcp_conn;
|
||||
instance->connections_count++;
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Added connection %p to instance, total count: %d", etcp_conn, instance->connections_count);
|
||||
client = client->next;
|
||||
}
|
||||
|
||||
// If there are clients configured but no connections created, that's an error
|
||||
// If there are no clients (server-only mode), 0 connections is OK (server will accept incoming)
|
||||
if (instance->connections_count == 0 && config->clients != NULL) {
|
||||
int total_conns = queue_entry_count(instance->connections);
|
||||
if (total_conns == 0 && config->clients != NULL) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Clients configured but no connections initialized");
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Initialized %d connections", instance->connections_count);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Initialized %d connections", total_conns);
|
||||
// Return 1 if there was a partial socket initialization error
|
||||
if (socket_result == 1) return 1;
|
||||
return 0;
|
||||
|
||||
+9
-6
@@ -233,13 +233,16 @@ void etcp_dump_all_conns(struct UTUN_INSTANCE* instance) {
|
||||
}
|
||||
DUMP_HDR("=== DUMP ALL CONNS for instance node=0x%llx ===",
|
||||
(unsigned long long)instance->node_id);
|
||||
struct ETCP_CONN* conn = instance->connections;
|
||||
struct ll_entry* entry = instance->connections->head;
|
||||
int idx = 0;
|
||||
while (conn) {
|
||||
DUMP_HDR("--- CONN %d ---", idx);
|
||||
etcp_dump_conn_state(conn);
|
||||
conn = conn->next;
|
||||
idx++;
|
||||
while (entry) {
|
||||
struct conn_queue_entry* ce = (struct conn_queue_entry*)entry->data;
|
||||
if (ce && ce->conn) {
|
||||
DUMP_HDR("--- CONN %d ---", idx);
|
||||
etcp_dump_conn_state(ce->conn);
|
||||
idx++;
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
if (idx == 0) DUMP_HDR("--- NO CONNECTIONS ---");
|
||||
DUMP_HDR("=== END DUMP ALL ===");
|
||||
|
||||
+4
-3
@@ -152,9 +152,10 @@ void ntp_node_sync_peers(struct UTUN_INSTANCE* inst) {
|
||||
if (!inst || !ntp_time_is_synced(inst)) return;
|
||||
|
||||
int sent = 0;
|
||||
for (struct ETCP_CONN* conn = inst->connections; conn; conn = conn->next) {
|
||||
if (!conn->initialized || !conn->links_up) continue;
|
||||
if (send_time_sync(inst, conn->peer_node_id) == 0) sent++;
|
||||
for (struct ll_entry* entry = inst->connections->head; entry; entry = entry->next) {
|
||||
struct conn_queue_entry* ce = (struct conn_queue_entry*)entry->data;
|
||||
if (!ce->conn->initialized || !ce->conn->links_up) continue;
|
||||
if (send_time_sync(inst, ce->conn->peer_node_id) == 0) sent++;
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "NTP_node: broadcast TIME_SYNC to %d peers", sent);
|
||||
|
||||
+3
-3
@@ -366,8 +366,8 @@ void topo_group_new_conn(struct TOPO_GROUP* group, struct ETCP_CONN* conn) {
|
||||
topo_group_add_to_senders(group, conn);
|
||||
if (peer_nq && peer_nq->alien) { DEBUG_INFO(DEBUG_CATEGORY_BGP, "peer 0x%016llx is alien, skipping route exchange", (unsigned long long)conn->peer_node_id); return; }
|
||||
|
||||
struct ETCP_CONN* c = conn->instance->connections;
|
||||
while (c) { struct ETCP_LINK* l = c->links; while (l) { if (l->initialized && l->conn && l->nat_check_status < NAT_CHECK_IN_PROGRESS) topo_group_start_link_nat_check(group, l); l = l->next; } c = c->next; }
|
||||
struct ll_entry* entry = conn->instance->connections->head;
|
||||
while (entry) { struct conn_queue_entry* ce = (struct conn_queue_entry*)entry->data; struct ETCP_LINK* l = ce->conn->links; while (l) { if (l->initialized && l->conn && l->nat_check_status < NAT_CHECK_IN_PROGRESS) topo_group_start_link_nat_check(group, l); l = l->next; } entry = entry->next; }
|
||||
|
||||
topo_group_send_table_request(group, conn);
|
||||
}
|
||||
@@ -839,7 +839,7 @@ void topo_group_send_nat_check_req(struct ETCP_CONN* conn, uint8_t socket_id) {
|
||||
void topo_group_request_nat_check_all(struct TOPO_GROUP* group) {
|
||||
if (!group || !group->instance) return;
|
||||
int count = 0;
|
||||
struct ETCP_CONN* conn = group->instance->connections; while (conn) { struct ETCP_LINK* link = conn->links; while (link) { if (link->nat_check_status < NAT_CHECK_IN_PROGRESS) topo_group_start_link_nat_check(group, link); count++; link = link->next; } conn = conn->next; }
|
||||
struct ll_entry* entry = group->instance->connections->head; while (entry) { struct conn_queue_entry* ce = (struct conn_queue_entry*)entry->data; struct ETCP_LINK* link = ce->conn->links; while (link) { if (link->nat_check_status < NAT_CHECK_IN_PROGRESS) topo_group_start_link_nat_check(group, link); count++; link = link->next; } entry = entry->next; }
|
||||
}
|
||||
|
||||
void topo_group_send_withdraw(struct TOPO_GROUP* group, uint64_t node_id) {
|
||||
|
||||
+27
-22
@@ -106,6 +106,9 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to create networks queue");
|
||||
return -1;
|
||||
}
|
||||
// Initialize connection queue
|
||||
instance->connections = queue_new(ua, 256, 0, 8, "connections");
|
||||
if (!instance->connections) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create connections queue"); return -1; }
|
||||
struct CFG_NETWORK *net = config->networks;
|
||||
while (net) {
|
||||
struct ll_entry *entry = queue_entry_new(sizeof(struct NETWORK_ENTRY));
|
||||
@@ -397,17 +400,17 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
|
||||
instance->etcp_sockets = NULL;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] ETCP sockets cleanup complete");
|
||||
|
||||
// Safe cleanup of ETCP connections with NULL pointer checks
|
||||
struct ETCP_CONN* conn = instance->connections;
|
||||
while (conn) {
|
||||
struct ETCP_CONN* next = conn->next;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Closing connection %p", conn);
|
||||
if (conn) { // Дополнительная проверка на случай поврежденного списка
|
||||
etcp_connection_close(conn); // Закрыть соединение (с проверкой NULL внутри)
|
||||
// Cleanup ETCP connections (phase 1 detach + deferred phase 2 via call_soon)
|
||||
{
|
||||
struct ll_entry* entry = instance->connections->head;
|
||||
while (entry) {
|
||||
struct ll_entry* next = entry->next;
|
||||
struct conn_queue_entry* ce = (struct conn_queue_entry*)entry->data;
|
||||
if (ce && ce->conn) etcp_connection_close(ce->conn);
|
||||
entry = next;
|
||||
}
|
||||
conn = next;
|
||||
}
|
||||
instance->connections = NULL;
|
||||
queue_free(instance->connections); instance->connections = NULL;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] ETCP connections cleanup complete");
|
||||
|
||||
struct PING_CONTEXT* p = instance->pending_pings;
|
||||
@@ -578,7 +581,7 @@ int utun_instance_init(struct UTUN_INSTANCE *instance) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "Connections initialized successfully, count=%d", instance->connections_count);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "Connections initialized successfully, count=%d", queue_entry_count(instance->connections));
|
||||
|
||||
// Initialize control server if configured
|
||||
if (instance->config->global.control_sock.ss_family != 0) {
|
||||
@@ -654,16 +657,15 @@ void utun_instance_diagnose_leaks(struct UTUN_INSTANCE *instance, const char *ph
|
||||
}
|
||||
|
||||
// Подсчёт ETCP соединений
|
||||
struct ETCP_CONN *conn = instance->connections;
|
||||
while (conn) {
|
||||
report.etcp_connections_count++;
|
||||
// Подсчёт линков в соединениях
|
||||
struct ETCP_LINK *link = conn->links;
|
||||
while (link) {
|
||||
report.etcp_links_count++;
|
||||
link = link->next;
|
||||
{
|
||||
struct ll_entry* entry = instance->connections->head;
|
||||
while (entry) {
|
||||
struct conn_queue_entry* ce = (struct conn_queue_entry*)entry->data;
|
||||
report.etcp_connections_count++;
|
||||
struct ETCP_LINK *link = ce->conn->links;
|
||||
while (link) { report.etcp_links_count++; link = link->next; }
|
||||
entry = entry->next;
|
||||
}
|
||||
conn = conn->next;
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[LEAK DIAGNOSIS] Phase: %s", phase);
|
||||
@@ -788,9 +790,12 @@ struct UTUN_INSTANCE *utun_instance_reload(struct UTUN_INSTANCE *instance, struc
|
||||
// Clients [client:] and links (link=)
|
||||
for (struct CFG_CLIENT *nc = new_config->clients; nc; nc = nc->next) {
|
||||
struct ETCP_CONN *conn = NULL;
|
||||
for (struct ETCP_CONN *c = instance->connections; c; c = c->next) {
|
||||
if (strcmp(nc->name, c->name) == 0) {
|
||||
conn = c; break;
|
||||
{
|
||||
struct ll_entry* entry = instance->connections->head;
|
||||
while (entry) {
|
||||
struct conn_queue_entry* ce = (struct conn_queue_entry*)entry->data;
|
||||
if (strcmp(nc->name, ce->conn->name) == 0) { conn = ce->conn; break; }
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
if (!conn) {
|
||||
|
||||
+8
-4
@@ -52,6 +52,12 @@ struct NETWORK_ENTRY {
|
||||
char name[64];
|
||||
};
|
||||
|
||||
// Queue entry for instance->connections (indexed by peer_node_id)
|
||||
struct conn_queue_entry {
|
||||
uint64_t peer_node_id;
|
||||
struct ETCP_CONN* conn;
|
||||
};
|
||||
|
||||
// uTun instance configuration
|
||||
struct UTUN_INSTANCE {
|
||||
// Identification
|
||||
@@ -87,9 +93,8 @@ struct UTUN_INSTANCE {
|
||||
// State
|
||||
int running;
|
||||
|
||||
// Connections (список всех подключений для instance)
|
||||
struct ETCP_CONN* connections;// linked-list
|
||||
int connections_count; // Number of connections
|
||||
// Connections (очередь всех подключений для instance)
|
||||
struct ll_queue* connections; // indexed by peer_node_id (0=pending), data=conn_queue_entry
|
||||
|
||||
// Callback chain for new ETCP connections
|
||||
struct etcp_cbk_entry* new_conn_cbks;
|
||||
@@ -135,7 +140,6 @@ struct UTUN_INSTANCE {
|
||||
// etcp_router bindings и seq-connections (per-instance service routing)
|
||||
struct ETCP_ROUTER_BINDINGS router_bindings;
|
||||
struct ll_queue* router_conns;
|
||||
struct ll_queue* chat_connections; // chat P2P connections indexed by node_id
|
||||
struct CONN_MGR* conn_mgr; // Connection Manager (может быть NULL)
|
||||
struct DB_SYNC* db_sync; // Distributed DB sync (может быть NULL)
|
||||
|
||||
|
||||
Reference in new issue
Block a user