From e7fc69bb1d739317c46f70b0df07f57400f9f434 Mon Sep 17 00:00:00 2001 From: evgeny Date: Thu, 17 Sep 2026 17:30:05 +0300 Subject: [PATCH] =?UTF-8?q?topo:=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D0=B0=D1=80=D0=B8=D0=B8=20=D0=BA=20=D1=84=D1=83=D0=BD?= =?UTF-8?q?=D0=BA=D1=86=D0=B8=D1=8F=D0=BC=20topo=5Fnode/topo=5Fgroup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit conn_mgr: src node_id вместо conn->peer_node_id, препенд ETCP_RT_ID_CONN_MGR к dgram, bind CONN_MGR после etcp_router_init call: guard CALL_ST_CONNECTING при accept --- src/call/call.c | 4 +-- src/routing_layer/conn_mgr_core.c | 19 ++++++------ src/routing_layer/conn_mgr_indirect.c | 10 +++---- src/routing_layer/conn_mgr_priv.h | 4 +-- src/routing_layer/topo_group.c | 43 +++++++++++++++++++++++++++ src/routing_layer/topo_node.c | 29 ++++++++++++++++++ src/utun_instance.c | 5 +++- 7 files changed, 95 insertions(+), 19 deletions(-) diff --git a/src/call/call.c b/src/call/call.c index 4607f4a8..16dcc83d 100644 --- a/src/call/call.c +++ b/src/call/call.c @@ -472,7 +472,7 @@ static void call_handle_accept(struct call_ctx* ctx, uint64_t from, const uint8_ if (n < 9) return; uint64_t call_id; memcpy(&call_id, b + 1, 8); struct call_session* s = call_session_find(ctx, call_id); - if (!s || s->role != CALL_ROLE_CALLER || s->state == CALL_ST_ENDED) return; + if (!s || s->role != CALL_ROLE_CALLER || s->state == CALL_ST_ENDED || s->state == CALL_ST_CONNECTING) return; DEBUG_INFO(DEBUG_CATEGORY_CALL, "%s: ACCEPT id=%016llx -> conn_mgr_open", CALL_ID, (unsigned long long)call_id); s->state = CALL_ST_CONNECTING; @@ -796,7 +796,7 @@ void call_accept(struct UTUN_INSTANCE* inst, uint64_t call_id) { struct call_ctx* ctx = call_of(inst); if (!ctx || !ctx->initialized) return; struct call_session* s = call_session_find(ctx, call_id); - if (!s || s->role != CALL_ROLE_CALLEE || s->state == CALL_ST_ENDED) return; + if (!s || s->role != CALL_ROLE_CALLEE || s->state == CALL_ST_ENDED || s->state == CALL_ST_CONNECTING) return; DEBUG_INFO(DEBUG_CATEGORY_CALL, "%s: call_accept id=%016llx -> ACCEPT + conn_mgr_open", CALL_ID, (unsigned long long)call_id); diff --git a/src/routing_layer/conn_mgr_core.c b/src/routing_layer/conn_mgr_core.c index fbae4570..b1f30c86 100644 --- a/src/routing_layer/conn_mgr_core.c +++ b/src/routing_layer/conn_mgr_core.c @@ -439,7 +439,7 @@ void conn_mgr_close(struct CONN_MGR_HANDLE* h) { struct CM_DISCONNECT pkt; memset(&pkt, 0, sizeof(pkt)); pkt.cmd = ETCP_RT_ID_CONN_MGR; pkt.subcmd = CM_SUBCMD_DISCONNECT; pkt.node_id = entry->node_id; struct ll_entry* qe = queue_entry_new(0); - if (qe) { qe->dgram = u_malloc(sizeof(pkt)); memcpy(qe->dgram, &pkt, sizeof(pkt)); qe->len = sizeof(pkt); + if (qe) { qe->dgram = u_malloc(1+sizeof(pkt)); qe->dgram[0] = ETCP_RT_ID_CONN_MGR; memcpy(qe->dgram+1, &pkt, sizeof(pkt)); qe->len = (uint16_t)(1+sizeof(pkt)); etcp_route_send(entry->mgr->instance, entry->mgr->group->group_id, entry->node_id, qe, 1, 0); } /* NCD CLOSE — транспортный уровень (отправит CLOSE/KEEP_ALIVE через node_conn_direct) */ } @@ -684,7 +684,8 @@ void cm_start_phase_reverse(struct CONN_MGR_ENTRY* entry) { for (uint8_t i=0;idgram=pkt; qe->len=(uint16_t)sz; etcp_route_send(entry->mgr->instance, group->group_id, entry->node_id, qe, 1, 0); + qe->dgram=u_malloc(1+sz); qe->dgram[0]=ETCP_RT_ID_CONN_MGR; memcpy(qe->dgram+1,pkt,sz); u_free(pkt); qe->len=(uint16_t)(1+sz); + etcp_route_send(entry->mgr->instance, group->group_id, entry->node_id, qe, 1, 0); struct cm_reverse_pending* rp = u_calloc(1, sizeof(*rp)); if (rp) { rp->request_id=req_id; rp->entry=entry; rp->next=entry->mgr->reverse_pending; entry->mgr->reverse_pending=rp; } entry->main.timer = uasync_set_timeout(entry->mgr->instance->ua, CONN_MGR_CONNECT_REVERSE_TIMEOUT_MS*10, @@ -698,13 +699,12 @@ void cm_start_phase_reverse(struct CONN_MGR_ENTRY* entry) { /* Принимающая сторона REVERSE: получили DIRECT_REQ от инициатора — открываем * NCD-соединение к нему, добавляем линки по адресам из запроса. При INIT * вызывается cm_reverse_init_cb. */ -void cm_handle_direct_req(struct ETCP_CONN* conn, struct CONN_MGR* mgr, const uint8_t* data, size_t len) { +void cm_handle_direct_req(uint64_t src, struct CONN_MGR* mgr, const uint8_t* data, size_t len) { if (!mgr) return; struct CM_DIRECT_REQ* req = (struct CM_DIRECT_REQ*)data; if (len < CM_DIRECT_REQ_H_SIZE + (size_t)req->addr_count * 8) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "conn_mgr: DIRECT_REQ too short"); return; } DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: got DIRECT_REQ from 0x%016llx with %u addrs", - (unsigned long long)conn->peer_node_id, req->addr_count); - uint64_t src = conn->peer_node_id; + (unsigned long long)src, req->addr_count); struct TOPO_NODE* src_ni = topo_node_registry_find(mgr->instance->topo_groups, src); if (!src_ni) return; struct TOPO_NODE nbuf; memset(&nbuf,0,sizeof(nbuf)); nbuf.node_id=src; memcpy(nbuf.public_key,src_ni->public_key,SC_PUBKEY_SIZE); struct NODE_CONN_DIRECT* ncd_h = NULL; @@ -717,7 +717,7 @@ void cm_handle_direct_req(struct ETCP_CONN* conn, struct CONN_MGR* mgr, const ui uint8_t* p = (uint8_t*)data + CM_DIRECT_REQ_H_SIZE; for (uint8_t i=0;iaddr_count;i++) { uint8_t type=*p++; (void)type; uint8_t ip[4]; memcpy(ip,p,4);p+=4; uint16_t port; memcpy(&port,p,2);p+=2; uint8_t sid=*p++; (void)sid; - struct ETCP_SOCKET* s = conn->instance->etcp_sockets; + struct ETCP_SOCKET* s = mgr->instance->etcp_sockets; while (s) { if ((s->type==CFG_SERVER_TYPE_PUBLIC||s->type==CFG_SERVER_TYPE_UNKNOWN)&&s->local_addr.ss_family==AF_INET) { cm_add_v4_link(newc, ip, port, s); break; } s=s->next; } } @@ -741,13 +741,14 @@ void conn_mgr_router_recv_handler(struct ETCP_CONN* conn, struct ll_entry* entry uint8_t* d = entry->dgram + ROUTER_SVC_PAYLOAD_OFF; size_t len = entry->len - ROUTER_SVC_PAYLOAD_OFF; uint8_t sub = d[1]; /* conn_mgr — per-group: резолвим группу из заголовка доставки, а не instance->conn_mgr */ uint64_t group_id; memcpy(&group_id, entry->dgram + ROUTER_SVC_GROUP_OFF, 8); + uint64_t src; memcpy(&src, entry->dgram + ROUTER_SVC_SRC_OFF, 8); struct TOPO_GROUP* grp = topo_groups_find(conn->instance->topo_groups, group_id); struct CONN_MGR* mgr = grp ? grp->conn_mgr : conn->instance->conn_mgr; - if (mgr) { struct CONN_MGR_ENTRY* e = cm_find_entry(mgr, conn->peer_node_id); if (e && e->state == CONN_MGR_STATE_CONNECTED) e->last_traffic_tb = get_time_tb(); } + if (mgr) { struct CONN_MGR_ENTRY* e = cm_find_entry(mgr, src); if (e && e->state == CONN_MGR_STATE_CONNECTED) e->last_traffic_tb = get_time_tb(); } switch (sub) { - case CM_SUBCMD_DIRECT_REQ: cm_handle_direct_req(conn, mgr, d, len); break; + case CM_SUBCMD_DIRECT_REQ: cm_handle_direct_req(src, mgr, d, len); break; case CM_SUBCMD_DIRECT_RESP: break; - case CM_SUBCMD_INTERM_EXCHANGE_REQ: if (len >= CM_EXCHANGE_REQ_SIZE) cm_handle_interm_exchange_req(conn, mgr, (struct CM_EXCHANGE_REQ*)d); break; + case CM_SUBCMD_INTERM_EXCHANGE_REQ: if (len >= CM_EXCHANGE_REQ_SIZE) cm_handle_interm_exchange_req(src, mgr, (struct CM_EXCHANGE_REQ*)d); break; case CM_SUBCMD_INTERM_EXCHANGE_RESP: if (mgr) cm_handle_interm_exchange_resp(mgr, d, len); break; case CM_SUBCMD_INTERM_SELECTED: if (mgr) cm_handle_interm_selected(mgr, d, len); break; case CM_SUBCMD_DISCONNECT: if (len >= CM_DISCONNECT_SIZE && mgr) cm_handle_disconnect(mgr, ((struct CM_DISCONNECT*)d)->node_id); break; diff --git a/src/routing_layer/conn_mgr_indirect.c b/src/routing_layer/conn_mgr_indirect.c index 7e9ea6e3..f0bee25a 100644 --- a/src/routing_layer/conn_mgr_indirect.c +++ b/src/routing_layer/conn_mgr_indirect.c @@ -25,7 +25,7 @@ void cm_start_phase_indirect(struct CONN_MGR_ENTRY* entry) { req.candidate_count = mgr->best_candidate_count > 4 ? 4 : mgr->best_candidate_count; for (uint8_t i=0;ibest_candidates[i]; struct ll_entry* qe = queue_entry_new(0); if (!qe) return; - qe->dgram=u_malloc(sizeof(req)); memcpy(qe->dgram,&req,sizeof(req)); qe->len=sizeof(req); + qe->dgram=u_malloc(1+sizeof(req)); qe->dgram[0]=ETCP_RT_ID_CONN_MGR; memcpy(qe->dgram+1,&req,sizeof(req)); qe->len=(uint16_t)(1+sizeof(req)); etcp_route_send(mgr->instance, mgr->group->group_id, entry->node_id, qe, 1, 0); entry->main.timer = uasync_set_timeout(mgr->instance->ua, CONN_MGR_INTERM_EXCHANGE_TIMEOUT_MS*10, entry, cm_exchange_timeout_cb, "conn_mgr_interm_exch"); struct cm_exchange_pending* ep = u_calloc(1,sizeof(*ep)); @@ -67,7 +67,7 @@ void cm_compute_intermediaries(struct CONN_MGR_ENTRY* entry, struct CM_EXCHANGE_ for(uint8_t i=0;imgr->group,all[i].nid); if(nq)pkt.selected[i].rtt=topo_get_chain_rtt(nq);} struct ll_entry* qe=queue_entry_new(0); - if(qe){qe->dgram=u_malloc(sizeof(pkt));memcpy(qe->dgram,&pkt,sizeof(pkt));qe->len=sizeof(pkt);etcp_route_send(entry->mgr->instance,entry->mgr->group->group_id,entry->node_id,qe,1,0);} + if(qe){qe->dgram=u_malloc(1+sizeof(pkt));qe->dgram[0]=ETCP_RT_ID_CONN_MGR;memcpy(qe->dgram+1,&pkt,sizeof(pkt));qe->len=(uint16_t)(1+sizeof(pkt));etcp_route_send(entry->mgr->instance,entry->mgr->group->group_id,entry->node_id,qe,1,0);} entry->conn_type=CONN_TYPE_INDIRECT; entry->state=CONN_MGR_STATE_CONNECTED; DEBUG_INFO(DEBUG_CATEGORY_GENERAL,"conn_mgr: indirect OK for 0x%016llx via %u intermediaries",(unsigned long long)entry->node_id,sel); cm_update_nodeinfo(entry); cm_deliver_event(entry,CONN_EVENT_UP); @@ -121,7 +121,7 @@ void cm_handle_interm_selected(struct CONN_MGR* mgr, const uint8_t* data, size_t /* Цель получила EXCHANGE_REQ: измеряет RTT до кандидатов инициатора (если * замеры протухли — запускает probe), отправляет EXCHANGE_RESP со СВОИМИ * кандидатами + замерами RTT до кандидатов инициатора. */ -void cm_handle_interm_exchange_req(struct ETCP_CONN* conn, struct CONN_MGR* mgr, struct CM_EXCHANGE_REQ* req) { +void cm_handle_interm_exchange_req(uint64_t src, struct CONN_MGR* mgr, struct CM_EXCHANGE_REQ* req) { if (!mgr) return; uint64_t now=get_time_tb(); for(uint8_t i=0;icandidate_count&&i<4;i++){ @@ -140,6 +140,6 @@ void cm_handle_interm_exchange_req(struct ETCP_CONN* conn, struct CONN_MGR* mgr, } size_t sz=offsetof(struct CM_EXCHANGE_RESP,your_candidates)+(size_t)resp.your_count*sizeof(struct CONN_MGR_CANDIDATE); struct ll_entry* qe=queue_entry_new(0); - if(qe){qe->dgram=u_malloc(sz);memcpy(qe->dgram,&resp,sz);qe->len=(uint16_t)sz;etcp_route_send(mgr->instance,mgr->group->group_id,conn->peer_node_id,qe,1,0);} - DEBUG_INFO(DEBUG_CATEGORY_GENERAL,"conn_mgr: sent EXCHANGE_RESP to 0x%016llx my=%u your=%u",(unsigned long long)conn->peer_node_id,resp.my_count,resp.your_count); + if(qe){qe->dgram=u_malloc(1+sz);qe->dgram[0]=ETCP_RT_ID_CONN_MGR;memcpy(qe->dgram+1,&resp,sz);qe->len=(uint16_t)(1+sz);etcp_route_send(mgr->instance,mgr->group->group_id,src,qe,1,0);} + DEBUG_INFO(DEBUG_CATEGORY_GENERAL,"conn_mgr: sent EXCHANGE_RESP to 0x%016llx my=%u your=%u",(unsigned long long)src,resp.my_count,resp.your_count); } diff --git a/src/routing_layer/conn_mgr_priv.h b/src/routing_layer/conn_mgr_priv.h index 8705879a..0150f3d5 100644 --- a/src/routing_layer/conn_mgr_priv.h +++ b/src/routing_layer/conn_mgr_priv.h @@ -142,7 +142,7 @@ void cm_start_phase_direct(struct CONN_MGR_ENTRY* entry); void cm_start_phase_reverse(struct CONN_MGR_ENTRY* entry); void cm_start_phase_indirect(struct CONN_MGR_ENTRY* entry); void cm_start_local_scan(struct CONN_MGR_ENTRY* entry); -void cm_handle_direct_req(struct ETCP_CONN* conn, struct CONN_MGR* mgr, const uint8_t* data, size_t len); +void cm_handle_direct_req(uint64_t src, struct CONN_MGR* mgr, const uint8_t* data, size_t len); void cm_handle_disconnect(struct CONN_MGR* mgr, uint64_t node_id); void cm_reverse_init_cb(struct ETCP_CONN* conn, int event, void* arg); void cm_reverse_timeout_cb(void* arg); @@ -163,7 +163,7 @@ uint8_t cm_sock_v6_classify(const struct ETCP_SOCKET* s); void cm_exchange_timeout_cb(void* arg); void cm_compute_intermediaries(struct CONN_MGR_ENTRY* entry, struct CM_EXCHANGE_RESP* resp); void cm_exchange_probe_retry_cb(void* arg); -void cm_handle_interm_exchange_req(struct ETCP_CONN* conn, struct CONN_MGR* mgr, struct CM_EXCHANGE_REQ* req); +void cm_handle_interm_exchange_req(uint64_t src, struct CONN_MGR* mgr, struct CM_EXCHANGE_REQ* req); void cm_handle_interm_exchange_resp(struct CONN_MGR* mgr, const uint8_t* data, size_t len); void cm_handle_interm_selected(struct CONN_MGR* mgr, const uint8_t* data, size_t len); diff --git a/src/routing_layer/topo_group.c b/src/routing_layer/topo_group.c index 8c800c6d..1ddb7cc6 100644 --- a/src/routing_layer/topo_group.c +++ b/src/routing_layer/topo_group.c @@ -36,6 +36,7 @@ // Вспомогательные функции // ============================================================================ +/* Шлёт пиру запрос полной таблицы узлов группы (REQUEST_TABLE). */ static void topo_group_send_table_request(struct TOPO_GROUP* group, struct ETCP_CONN* conn) { if (!group || !conn) return; DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "Sending table request to %s grp=%016llx", conn->log_name, (unsigned long long)group->group_id); @@ -50,6 +51,7 @@ static void topo_group_send_table_request(struct TOPO_GROUP* group, struct ETCP_ if (etcp_send(conn, e) != 0) { u_free(req); queue_entry_free(e); } } +/* Запрашивает у пира членство в группе (JOIN_GROUP). */ static void topo_group_send_join_group(struct TOPO_GROUP* group, struct ETCP_CONN* conn) { if (!group || !conn) return; DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "Sending join group request to %s grp=%016llx", conn->log_name, (unsigned long long)group->group_id); @@ -64,6 +66,7 @@ static void topo_group_send_join_group(struct TOPO_GROUP* group, struct ETCP_CON if (etcp_send(conn, e) != 0) { u_free(req); queue_entry_free(e); } } +/* Шлёт пиру RESYNC — просьбу заново анонсировать свои группы. */ static void topo_group_send_resync(struct ETCP_CONN* conn) { if (!conn) return; DEBUG_INFO(DEBUG_CATEGORY_BGP, "Sending RESYNC to %s", conn->log_name); @@ -77,6 +80,7 @@ static void topo_group_send_resync(struct ETCP_CONN* conn) { if (etcp_send(conn, e) != 0) { u_free(req); queue_entry_free(e); } } +/* Сигнализирует пиру об окончании начальной синхронизации таблицы. */ static void topo_group_send_table_complete(struct TOPO_GROUP* group, struct ETCP_CONN* conn) { if (!group || !conn) return; struct TOPOMSG_TABLE_REQ* req = u_calloc(1, sizeof(struct TOPOMSG_TABLE_REQ)); @@ -98,6 +102,7 @@ static void topo_group_handle_join_group(struct TOPO_GROUP* group, struct ETCP_C static void topo_group_send_resync(struct ETCP_CONN* conn); static void topo_group_handle_resync(struct UTUN_INSTANCE* instance, struct ETCP_CONN* conn); +/* Краткий DEBUG-дамп принятого NODEINFO (id/ver/счётчики/hops). */ static void nodeinfo_dump_log(const uint8_t* data, size_t len) { if (!data || len < sizeof(struct TOPOMSG_NODEINFO_PKT)) return; struct TOPOMSG_NODEINFO_PKT* pkt = (struct TOPOMSG_NODEINFO_PKT*)data; @@ -107,6 +112,7 @@ static void nodeinfo_dump_log(const uint8_t* data, size_t len) { ni->local_v4_sockets, ni->local_v4_addrs, ni->hop_count); } +/* Форматирует NODEINFO в читаемую строку для лога (имя, подсети, адреса). */ static char* nodeinfo_format(const uint8_t* data, size_t len) { if (!data || len < sizeof(struct TOPOMSG_NODEINFO_PKT)) return NULL; struct TOPOMSG_NODEINFO_PKT* pkt = (struct TOPOMSG_NODEINFO_PKT*)data; @@ -139,6 +145,7 @@ static char* nodeinfo_format(const uint8_t* data, size_t len) { return buf; } +/* Читаемое имя sub-команды BGP для логов. */ static const char* group_subcmd_name(uint8_t subcmd) { switch (subcmd) { case TOPO_SUBCMD_NODEINFO: return "NODEINFO"; @@ -157,6 +164,7 @@ static const char* group_subcmd_name(uint8_t subcmd) { // Broadcast / Withdraw // ============================================================================ +/* Рассылает WITHDRAW всем BGP-пирам (кроме exclude) об удалении узла. */ static void topo_group_broadcast_withdraw(struct TOPO_GROUP* group, uint64_t node_id, uint64_t wd_source, struct ETCP_CONN* exclude) { if (!group) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "group is NULL"); return; } struct TOPOMSG_WITHDRAW_PKT* pkt = u_calloc(1, sizeof(struct TOPOMSG_WITHDRAW_PKT)); @@ -180,6 +188,7 @@ static void topo_group_broadcast_withdraw(struct TOPO_GROUP* group, uint64_t nod // Приём пакетов // ============================================================================ +/* Приёмник BGP-пакетов от ETCP: диспетчер по subcmd (NODEINFO/WITHDRAW/...). */ static void topo_group_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry* entry) { if (!from_conn || !entry || entry->len < 2) { if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } return; } struct UTUN_INSTANCE* instance = from_conn->instance; @@ -237,6 +246,7 @@ static void topo_group_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry* // Init / Destroy / New / Remove conn // ============================================================================ +/* Callback статуса ETCP-соединения: UP — добавить пира в группы; DOWN — удалить. */ static void topo_group_conn_status(struct ETCP_CONN* conn, int status, void* arg) { struct TOPO_GROUPS* groups = (struct TOPO_GROUPS*)arg; if (!conn || !groups) return; @@ -279,6 +289,7 @@ static void topo_group_conn_status(struct ETCP_CONN* conn, int status, void* arg } } +/* Создаёт группу: очереди nodes/senders, local_node, conn_mgr, broadcast. */ static struct TOPO_GROUP* topo_group_create(struct UTUN_INSTANCE* instance, uint64_t group_id, uint8_t group_type) { if (!instance) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "instance is NULL"); return NULL; } DEBUG_INFO(DEBUG_CATEGORY_BGP, "group_id=%016llx node_id=%016llx", (unsigned long long)group_id, (unsigned long long)instance->node_id); @@ -311,6 +322,7 @@ static struct TOPO_GROUP* topo_group_create(struct UTUN_INSTANCE* instance, uint return group; } +/* Полностью разрушает группу: recovery, connect, broadcast, conn_mgr, узлы. */ static void topo_group_destroy(struct TOPO_GROUP* group) { if (!group) return; DEBUG_INFO(DEBUG_CATEGORY_SYS, "[GRP_DESTROY] 0 enter grp=%p id=0x%016llx rec_list=%p connect=%p", @@ -356,6 +368,7 @@ static void topo_group_destroy(struct TOPO_GROUP* group) { DEBUG_INFO(DEBUG_CATEGORY_SYS, "[GRP_DESTROY] 5 done"); } +/* Удаляет группу из контейнера (кроме UTUN-группы по умолчанию). */ void topo_groups_remove_group(struct TOPO_GROUPS* g, uint64_t group_id) { if (!g || !g->group_list || group_id == TOPO_GROUP_UTUN) return; struct TOPO_GROUP* group = topo_groups_find(g, group_id); @@ -374,6 +387,7 @@ void topo_groups_remove_group(struct TOPO_GROUPS* g, uint64_t group_id) { queue_entry_free(&group->ll); } +/* Инициализация контейнера групп: реестр, пулы, SQLite, default-группа, подписки. */ struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance) { if (!instance) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "instance is NULL"); return NULL; } DEBUG_INFO(DEBUG_CATEGORY_BGP, "node_id=%016llx", (unsigned long long)instance->node_id); @@ -442,6 +456,7 @@ struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance) { return g; } +/* Callback смены active/standby: обновляет свой nodeinfo и рассылает его пирам. */ void topo_group_on_activity_change(struct UTUN_INSTANCE* instance, int active, void* arg) { (void)active; (void)arg; if (!instance || !instance->topo_groups || !instance->topo_groups->group_list) return; @@ -461,6 +476,7 @@ void topo_group_on_activity_change(struct UTUN_INSTANCE* instance, int active, v } } +/* Полный teardown контейнера: отписки, уничтожение групп, реестра, пулов. */ void topo_groups_destroy(struct UTUN_INSTANCE* instance) { if (!instance) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "instance is NULL"); return; } if (!instance->topo_groups) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "topo_groups is NULL"); return; } @@ -515,16 +531,19 @@ void topo_groups_destroy(struct UTUN_INSTANCE* instance) { DEBUG_INFO(DEBUG_CATEGORY_SYS, "[TOPO_DESTROY] 9 done"); } +/* Возвращает UTUN-группу по умолчанию (group_id=TOPO_GROUP_UTUN). */ struct TOPO_GROUP* topo_groups_get_default(struct TOPO_GROUPS* g) { return topo_groups_find(g, TOPO_GROUP_UTUN); } +/* Ищет группу по group_id (NULL, если нет). */ struct TOPO_GROUP* topo_groups_find(struct TOPO_GROUPS* g, uint64_t group_id) { if (!g || !g->group_list) return NULL; struct ll_entry* e = queue_find_data_by_index(g->group_list, &group_id); return e ? (struct TOPO_GROUP*)e : NULL; } +/* Создаёт и регистрирует новую группу; добавляет существующие conn, для CHAT — автоподключение. */ struct TOPO_GROUP* topo_groups_create_group(struct TOPO_GROUPS* g, uint64_t group_id, uint8_t group_type, const char* channel_id) { if (!g || !g->instance) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid args"); return NULL; } if (topo_groups_find(g, group_id)) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "group_id=%016llx already exists", (unsigned long long)group_id); return NULL; } @@ -564,15 +583,18 @@ struct TOPO_GROUP* topo_groups_create_group(struct TOPO_GROUPS* g, uint64_t grou return group; } +/* Разрешить/запретить NAT-проверку локальных подсетей (делегат в nat_detection). */ void topo_group_set_nat_check_local(struct TOPO_GROUP* group, int allow) { if (!group || !group->instance || !group->instance->nat_det) return; nat_detection_set_allow_local(group->instance->nat_det, allow); } +/* Устанавливает колбэк сохранения узла в БД (используется chatgui/member_sync). */ void topo_groups_set_node_updated_cb(struct TOPO_GROUPS* groups, topo_node_updated_fn fn) { if (groups) groups->node_updated_cb = fn; } +/* Добавляет пира в группу при UP: дедуп, добавление в senders, запрос таблицы. */ void topo_group_new_conn(struct TOPO_GROUP* group, struct ETCP_CONN* conn) { if (!group || !conn) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid args"); return; } if (!conn->instance) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "conn->instance is NULL"); return; } @@ -626,6 +648,7 @@ void topo_group_new_conn(struct TOPO_GROUP* group, struct ETCP_CONN* conn) { topo_group_connect_on_up(group, conn); } +/* Обрабатывает DOWN пира: чистит пути, каскадно удаляет узлы, шлёт withdraw. */ void topo_group_remove_conn(struct TOPO_GROUP* group, struct ETCP_CONN* conn) { if (!group || !conn) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid args"); return; } if (!conn->instance) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid instance"); return; } @@ -712,6 +735,7 @@ void topo_group_remove_conn(struct TOPO_GROUP* group, struct ETCP_CONN* conn) { // NODEINFO BASED IMPLEMENTATION // ============================================================================ +/* Ищет лучшее ETCP-соединение до узла (мин. hop_count среди живых путей). */ struct ETCP_CONN* topo_group_find_conn_for_node(struct TOPO_GROUP* group, uint64_t node_id) { if (!group) return NULL; struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(group, node_id); @@ -728,6 +752,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); } +/* Добавляет путь (conn + hop_list + rtt) в paths узла. */ 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; } @@ -740,6 +765,7 @@ int topo_group_add_path(struct TOPO_GROUP_NODE* nq, struct ETCP_CONN* conn, uint return 0; } +/* Удаляет пути, содержащие wd_source в hop_list; 1 — если путей не осталось. */ 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; @@ -755,6 +781,7 @@ static int topo_group_remove_path_by_hop(struct TOPO_GROUP_NODE* nq, uint64_t wd return removed; } +/* Удаляет путь через конкретный conn; 1 — если путей не осталось. */ 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; @@ -766,6 +793,7 @@ int topo_group_remove_path(struct TOPO_GROUP_NODE* nq, struct ETCP_CONN* conn) { // ===== NODEINFO process ===== +/* Шлёт пиру ошибку несоответствия типа группы (ERR_GROUP_MISMATCH). */ static void topo_group_send_err_group_mismatch(struct TOPO_GROUP* group, struct ETCP_CONN* conn, uint8_t expected_type, uint8_t received_flags) { if (!group || !conn) return; struct TOPOMSG_ERR_GROUP_MISMATCH* pkt = u_calloc(1, sizeof(struct TOPOMSG_ERR_GROUP_MISMATCH)); @@ -779,6 +807,7 @@ static void topo_group_send_err_group_mismatch(struct TOPO_GROUP* group, struct if (etcp_send(conn, e) != 0) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "etcp_send ERR_GROUP_MISMATCH failed"); u_free(pkt); queue_entry_free(e); } } +/* Обрабатывает NODEINFO: проверка подписи/версии, обновление узла, пути, роутинг, форвард. */ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from, const uint8_t* data, size_t len) { if (!group || !from || len < sizeof(struct TOPOMSG_NODEINFO_PKT)) return -1; @@ -986,6 +1015,7 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from return 0; } +/* Обрабатывает WITHDRAW: удаляет узел/пути, чистит роутинг, форвардит withdraw. */ int topo_group_process_withdraw(struct TOPO_GROUP* group, struct ETCP_CONN* sender, const uint8_t* data, size_t len) { if (!group || len < sizeof(struct TOPOMSG_WITHDRAW_PKT)) return -1; struct TOPOMSG_WITHDRAW_PKT* wp = (struct TOPOMSG_WITHDRAW_PKT*)data; @@ -1017,6 +1047,7 @@ int topo_group_process_withdraw(struct TOPO_GROUP* group, struct ETCP_CONN* send return 0; } +/* Сериализует и шлёт NODEINFO узла конкретному пиру. */ 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; @@ -1051,6 +1082,7 @@ void topo_group_send_nodeinfo(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* if (etcp_send(conn, e) != 0) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "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); } } +/* Добавляет conn в senders_list (дедуп), если его там ещё нет. */ static void topo_group_add_to_senders(struct TOPO_GROUP* group, struct ETCP_CONN* conn) { if (!group || !conn || !group->senders_list) return; bool already = false; @@ -1067,6 +1099,7 @@ static void topo_group_add_to_senders(struct TOPO_GROUP* group, struct ETCP_CONN } } +/* Решает, надо ли слать узел пиру (не шлём, если пир уже есть в hop_list пути). */ 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; @@ -1081,6 +1114,7 @@ static bool topo_group_should_send_to(const struct TOPO_GROUP_NODE* nq, uint64_t return false; } +/* Шлёт пиру полную таблицу узлов группы (все узлы, кроме достижимых через него). */ static void topo_group_send_full_table(struct TOPO_GROUP* group, struct ETCP_CONN* conn) { if (!group || !conn) return; uint64_t target = conn->peer_node_id; @@ -1094,6 +1128,7 @@ static void topo_group_send_full_table(struct TOPO_GROUP* group, struct ETCP_CON } } +/* Обрабатывает REQUEST_TABLE: шлёт свой nodeinfo + полную таблицу + TABLE_COMPLETE. */ static void topo_group_handle_request_table(struct TOPO_GROUP* group, struct ETCP_CONN* conn) { if (!group || !conn) return; topo_group_send_nodeinfo(group, group->local_node, conn, 0); @@ -1103,6 +1138,7 @@ static void topo_group_handle_request_table(struct TOPO_GROUP* group, struct ETC topo_group_send_table_complete(group, conn); } +/* Обрабатывает JOIN_GROUP: для UTUN — добавить запросившего и инициировать BGP обратно. */ static void topo_group_handle_join_group(struct TOPO_GROUP* group, struct ETCP_CONN* conn) { if (!group || !conn) return; DEBUG_INFO(DEBUG_CATEGORY_BGP, "handle_join_group: from %s grp=%016llx type=%d", conn->log_name, (unsigned long long)group->group_id, group->group_type); @@ -1111,6 +1147,7 @@ static void topo_group_handle_join_group(struct TOPO_GROUP* group, struct ETCP_C topo_group_new_conn(group, conn); } +/* Обрабатывает RESYNC: если мы VPN-клиент пира — заново шлём JOIN_GROUP по группам. */ static void topo_group_handle_resync(struct UTUN_INSTANCE* instance, struct ETCP_CONN* conn) { if (!instance || !conn || !conn->instance || !instance->topo_groups) return; /* общий сигнал от пассивной стороны: рестартуем обмен, если мы для этого пира VPN-клиент */ @@ -1127,6 +1164,7 @@ static void topo_group_handle_resync(struct UTUN_INSTANCE* instance, struct ETCP /* ── BGP node event callbacks ── */ +/* Регистрирует подписчика на события узлов группы (NEW/UPDATE/REMOVE). */ void topo_group_add_node_cbk(struct TOPO_GROUP* group, topo_node_event_fn fn, void* arg) { if (!group || !fn) return; struct topo_node_cbk_entry* e = u_malloc(sizeof(*e)); @@ -1136,6 +1174,7 @@ void topo_group_add_node_cbk(struct TOPO_GROUP* group, topo_node_event_fn fn, vo group->node_cbks = e; } +/* Снимает подписчика событий узлов группы. */ void topo_group_remove_node_cbk(struct TOPO_GROUP* group, topo_node_event_fn fn, void* arg) { if (!group || !fn) return; struct topo_node_cbk_entry** p = &group->node_cbks; @@ -1151,6 +1190,7 @@ void topo_group_remove_node_cbk(struct TOPO_GROUP* group, topo_node_event_fn fn, /* ── Global nodeinfo callbacks (instance-level, any node change) ── */ +/* Регистрирует глобальный колбэк изменения nodeinfo (уровень инстанса). */ void utun_add_nodeinfo_cbk(struct UTUN_INSTANCE* instance, nodeinfo_cbk_fn fn, void* arg) { if (!instance || !fn) return; struct nodeinfo_cbk_entry* e = u_malloc(sizeof(*e)); @@ -1160,6 +1200,7 @@ void utun_add_nodeinfo_cbk(struct UTUN_INSTANCE* instance, nodeinfo_cbk_fn fn, v instance->nodeinfo_cbks = e; } +/* Снимает глобальный колбэк nodeinfo. */ void utun_remove_nodeinfo_cbk(struct UTUN_INSTANCE* instance, nodeinfo_cbk_fn fn, void* arg) { if (!instance || !fn) return; struct nodeinfo_cbk_entry** p = &instance->nodeinfo_cbks; @@ -1173,12 +1214,14 @@ void utun_remove_nodeinfo_cbk(struct UTUN_INSTANCE* instance, nodeinfo_cbk_fn fn } } +/* Вызывает все глобальные nodeinfo-колбэки для узла. */ void topo_fire_nodeinfo_cbk(struct UTUN_INSTANCE* instance, struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* node) { if (!instance || !group || !node) return; struct nodeinfo_cbk_entry* c = instance->nodeinfo_cbks; while (c) { c->fn(group, node, c->arg); c = c->next; } } +/* Публичная рассылка WITHDRAW об удалении узла. */ void topo_group_send_withdraw(struct TOPO_GROUP* group, uint64_t node_id) { if (!group) return; DEBUG_INFO(DEBUG_CATEGORY_BGP, "node=%016llx", (unsigned long long)node_id); diff --git a/src/routing_layer/topo_node.c b/src/routing_layer/topo_node.c index 6c604c98..a63e5acd 100644 --- a/src/routing_layer/topo_node.c +++ b/src/routing_layer/topo_node.c @@ -18,16 +18,19 @@ #include "../lib/u_async.h" #include "../ntp_time.h" +/* Инкремент refcount узла: держит TOPO_NODE живым, пока на него ссылаются группы. */ void topo_node_ref(struct TOPO_NODE* ni) { if (!ni) return; ni->group_ref_count++; } +/* Инкремент refcount узла в глобальном реестре по node_id (взял ссылку через реестр). */ 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++; } +/* Декремент refcount; при обнулении освобождает имя узла и сам TOPO_NODE. */ void topo_node_unref(struct TOPO_NODE* ni) { if (!ni) return; if (--ni->group_ref_count == 0) { @@ -36,6 +39,7 @@ void topo_node_unref(struct TOPO_NODE* ni) { } } +/* Освобождают односвязные списки структур узла (sock_meta/адреса/подсети v4,v6) из memory_pool. */ static void free_v4_sock_list(struct memory_pool* pool, struct TOPO_SOCKMETA4* head) { while (head) { struct TOPO_SOCKMETA4* next = head->next; memory_pool_free(pool, head); head = next; } } @@ -54,10 +58,12 @@ static void free_v4_sub_list(struct memory_pool* pool, struct TOPO_SUBNET4* head static void free_v6_sub_list(struct memory_pool* pool, struct TOPO_SUBNET6* head) { while (head) { struct TOPO_SUBNET6* next = head->next; memory_pool_free(pool, head); head = next; } } +/* Освобождает список reality-сокетов узла (выделялся u_calloc). */ static void free_reality_sock_list(struct TOPO_REALITY_SOCK* head) { while (head) { struct TOPO_REALITY_SOCK* next = head->next; u_free(head); head = next; } } +/* Ищет reality-параметры сокета узла по socket_id (NULL, если сокет без reality). */ const struct TOPO_REALITY_SOCK* topo_node_find_reality_sock(const struct TOPO_NODE* ni, uint8_t socket_id) { if (!ni) return NULL; for (const struct TOPO_REALITY_SOCK* r = ni->reality_socks; r; r = r->next) @@ -65,6 +71,7 @@ const struct TOPO_REALITY_SOCK* topo_node_find_reality_sock(const struct TOPO_NO return NULL; } +/* Копирует reality-параметры узла в link->reality и поднимает флаг reality_set. */ void topo_node_apply_reality(struct ETCP_LINK* link, const struct TOPO_REALITY_SOCK* rs) { if (!link || !rs) return; memcpy(link->reality.server_static_pubkey, rs->server_pubkey, REALITY_AUTH_KEY_SIZE); @@ -147,6 +154,7 @@ static void topo_node_identity_free(struct TOPO_GROUPS* groups, struct TOPO_NODE ni->reality_socks = NULL; } +/* Полностью освобождает TOPO_NODE со всеми списками и именем (без учёта refcount). */ void topo_node_free_raw(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni) { if (!ni) return; if (groups) { @@ -160,10 +168,12 @@ void topo_node_free_raw(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni) { u_free(ni); } +/* Публичная обёртка free_raw — уничтожение узла глобального реестра. */ void topo_node_destroy(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni) { topo_node_free_raw(groups, ni); } +/* Освобождает per-group поля TOPO_GROUP_NODE: unref идентичности в реестре + подсети, сброс handle. */ void topo_nodeq_free_group_fields(struct TOPO_GROUPS* groups, struct TOPO_GROUP_NODE* nq) { if (!groups || !nq) return; topo_node_registry_unref(groups, nq->node_id); @@ -178,6 +188,7 @@ void topo_nodeq_free_group_fields(struct TOPO_GROUPS* groups, struct TOPO_GROUP_ // ===== глобальный реестр TOPO_NODE ===== +/* Ищет TOPO_NODE в глобальном реестре по node_id (NULL, если узла нет). */ 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); @@ -194,6 +205,7 @@ static int topo_node_is_full_identity(const struct TOPO_NODE* ni) { return 0; } +/* Кладёт узел в реестр; если он уже есть — обновляет идентичность/адреса и возвращает существующий. */ struct TOPO_NODE* topo_node_registry_store(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni) { if (!groups || !ni) return NULL; struct TOPO_NODE* existing = topo_node_registry_find(groups, ni->node_id); @@ -242,6 +254,7 @@ struct TOPO_NODE* topo_node_registry_store(struct TOPO_GROUPS* groups, struct TO return ni; } +/* Снимает ссылку группы на узел; при последней — чистит идентичность и удаляет запись из реестра. */ 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); @@ -258,6 +271,7 @@ void topo_node_registry_unref(struct TOPO_GROUPS* groups, uint64_t node_id) { // ===== serialization ===== +/* Собирает канонический буфер для Ed25519-подписи узла (id, ver, pubkey, имя, тип, адреса). */ int topo_node_build_sig_msg(struct TOPO_NODE* ni, uint8_t* buf, size_t buf_size) { if (!ni || !buf || buf_size < 64 + 9) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "build_sig_msg: invalid args"); return -1; } size_t off = 0; @@ -311,6 +325,7 @@ int topo_node_build_sig_msg(struct TOPO_NODE* ni, uint8_t* buf, size_t buf_size) return (int)off; } +/* Подписывает свой узел Ed25519: build_sig_msg + sc_ed25519_sign → ni->x25519_self_sig. */ void topo_node_sign_self(struct UTUN_INSTANCE* instance, struct TOPO_NODE* ni) { if (!instance || !ni) return; uint8_t sig_msg[TOPO_SIG_MSG_MAX_SIZE]; @@ -319,6 +334,7 @@ void topo_node_sign_self(struct UTUN_INSTANCE* instance, struct TOPO_NODE* ni) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Ed25519 self-sign FAILED for node=%016llx", (unsigned long long)ni->node_id); } +/* Вычисляет суммарный размер динамической части NODEINFO по счётчикам заголовка. */ int topo_node_dyn_size(const struct TOPOMSG_NODE* msg) { return msg->node_name_len + msg->local_v4_sockets * sizeof(struct TOPOMSG_SOCKMETA4) @@ -332,6 +348,7 @@ int topo_node_dyn_size(const struct TOPOMSG_NODE* msg) { + msg->hop_count * 8; } +/* Сериализует узел в wire-формат NODEINFO (заголовок + имя + адреса + подсети + hop_list). */ int topo_node_serialize(struct TOPO_NODE* ni, struct TOPO_GROUP_NODE* nq, uint64_t group_id, uint8_t flags, uint8_t* out, size_t out_max, uint16_t cumulative_rtt) { @@ -412,6 +429,7 @@ int topo_node_serialize(struct TOPO_NODE* ni, struct TOPO_GROUP_NODE* nq, // ===== deserialization ===== +/* Разбирает wire-формат NODEINFO в TOPO_NODE + подсети/hop_list/cumulative_rtt (память через пулы). */ int topo_node_deserialize(struct TOPO_GROUP* group, const uint8_t* data, size_t len, struct TOPO_NODE** out_ni, struct TOPO_NODESUBNETS** out_subnets, uint64_t** out_hop_list, uint8_t* out_hop_count, uint16_t* out_cumulative_rtt) { @@ -531,6 +549,7 @@ int topo_node_deserialize(struct TOPO_GROUP* group, const uint8_t* data, size_t return 0; } +/* Ищет per-group узел TOPO_GROUP_NODE в группе по node_id (NULL, если нет). */ 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; @@ -538,6 +557,7 @@ struct TOPO_GROUP_NODE* topo_node_find_by_id(struct TOPO_GROUP* group, uint64_t return e ? (struct TOPO_GROUP_NODE*)e : NULL; } +/* Решает, нужен ли ping узлу: да, если в любой группе last_ping старше PING_TTL_TB. */ int topo_node_ping_request_cbk(struct TOPO_GROUPS* groups, uint64_t node_id) { if (!groups || !groups->group_list) return 0; uint64_t now = get_time_tb(); @@ -560,6 +580,7 @@ int topo_node_ping_request_cbk(struct TOPO_GROUPS* groups, uint64_t node_id) { return 0; } +/* Обновляет RTT/last_ping узла во всех группах, пишет RTT в БД и уведомляет подписчиков. */ void topo_node_ping_update_rtt(struct TOPO_GROUPS* groups, uint64_t node_id, uint16_t rtt) { if (!groups || !groups->group_list) { DEBUG_WARN(DEBUG_CATEGORY_BGP, "ping_update_rtt: no groups, node=%016llx rtt=%u", (unsigned long long)node_id, (unsigned)rtt); @@ -588,6 +609,7 @@ void topo_node_ping_update_rtt(struct TOPO_GROUPS* groups, uint64_t node_id, uin } } +/* Суммарный RTT цепочки до узла: минимальный (rtt_last + cumulative_rtt) среди живых путей. */ uint16_t topo_get_chain_rtt(struct TOPO_GROUP_NODE* nq) { if (!nq || !nq->paths || !nq->paths->head) { return 0xFFFF; @@ -606,6 +628,7 @@ uint16_t topo_get_chain_rtt(struct TOPO_GROUP_NODE* nq) { // ===== dump / format ===== +/* Есть ли у узла непустая диагностика связности (статусы/таймстемпы проб). */ static int is_node_connectivity_active(struct TOPO_CONNECTIVITY* c) { return c->probe_status != PROBE_STATUS_NONE || c->interface_status != PROBE_RESULT_UNKNOWN @@ -616,6 +639,7 @@ static int is_node_connectivity_active(struct TOPO_CONNECTIVITY* c) { || c->last_ping_time != 0; } +/* Читаемое имя статуса/результата пробы и типа conn_mgr для дампа. */ static const char* probe_status_str(uint8_t s) { switch (s) { case 0: return "NONE"; case 1: return "IN_PROGRESS"; case 2: return "DONE"; default: return "?"; } } @@ -626,6 +650,7 @@ static const char* conn_mgr_type_str(uint8_t t) { switch (t) { case 1: return "DIRECT"; case 2: return "REVERSE"; case 3: return "INDIRECT"; default: return "NONE"; } } +/* Выводит в лог полный дамп узлов группы (адреса, пути, связность, conn_mgr). */ void topo_node_dump_all(struct TOPO_GROUP* group) { if (!group || !group->nodes) return; @@ -713,6 +738,7 @@ void topo_node_dump_all(struct TOPO_GROUP* group) { } } +/* То же, что dump_all, но в строковый буфер (для control-сервера). */ int topo_node_format_all(struct TOPO_GROUP* group, char* buf, size_t buf_size) { if (!group || !group->nodes || !buf || buf_size == 0) return 0; int pos = 0; @@ -804,6 +830,7 @@ int topo_node_format_all(struct TOPO_GROUP* group, char* buf, size_t buf_size) { // ===== update my nodeinfo ===== +/* Пересоздаёт local_node группы при изменении имени/подсетей/ключей, инкрементируя версию. */ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GROUP* group) { if (!instance || !group) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid args"); return -1; } size_t name_len = 0; @@ -897,6 +924,7 @@ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GR return vc; } +/* Пересобирает списки адресов своего узла из ETCP-сокетов; при изменении — подпись, БД, рассылка. */ int topo_node_update_my_addresses(struct UTUN_INSTANCE* instance) { if (!instance || !instance->topo_groups) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid args"); return -1; } struct TOPO_GROUP* default_group = topo_groups_get_default(instance->topo_groups); @@ -1065,6 +1093,7 @@ int topo_node_update_my_addresses(struct UTUN_INSTANCE* instance) { return changed ? 1 : 0; } +/* Callback изменения сокета (адрес/статус) — инициирует пересборку адресов своего узла. */ void topo_node_on_socket_changed(struct ETCP_SOCKET* sock, int event, void* arg) { (void)arg; if (!sock || !sock->instance) return; diff --git a/src/utun_instance.c b/src/utun_instance.c index 751ed51f..48985a1e 100644 --- a/src/utun_instance.c +++ b/src/utun_instance.c @@ -221,7 +221,6 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Failed to initialize BGP module"); } else { DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP module initialized"); - etcp_router_bind(instance, ETCP_RT_ID_CONN_MGR, conn_mgr_router_recv_handler); topo_group_invite_init(instance); struct TOPO_GROUP* g = topo_groups_get_default(instance->topo_groups); if (instance->rt && g && g->local_node) { @@ -255,6 +254,10 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u return -1; } + // Bind CONN_MGR handler AFTER etcp_router_init (init затирает router_bindings) + if (g_topo_group_enabled && instance->topo_groups) + etcp_router_bind(instance, ETCP_RT_ID_CONN_MGR, conn_mgr_router_recv_handler); + // Bind DATA handler via etcp_router (after etcp_router_init) if (routing_bind(instance) != 0) { DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to bind DATA via etcp_router");