Browse Source

topo: комментарии к функциям topo_node/topo_group

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
proxy
evgeny 2 weeks ago
parent
commit
e7fc69bb1d
  1. 4
      src/call/call.c
  2. 19
      src/routing_layer/conn_mgr_core.c
  3. 10
      src/routing_layer/conn_mgr_indirect.c
  4. 4
      src/routing_layer/conn_mgr_priv.h
  5. 43
      src/routing_layer/topo_group.c
  6. 29
      src/routing_layer/topo_node.c
  7. 5
      src/utun_instance.c

4
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);

19
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;i<dc;i++) { *p++=addrs[i].t; memcpy(p,addrs[i].ip,4);p+=4; memcpy(p,&addrs[i].port,2);p+=2; *p++=addrs[i].sid; }
struct ll_entry* qe = queue_entry_new(0);
if (!qe) { u_free(pkt); cm_deliver_event(entry, CONN_EVENT_TIMEOUT); return; }
qe->dgram=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;i<req->addr_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;

10
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;i<req.candidate_count;i++) req.candidates[i]=mgr->best_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;i<sel;i++){pkt.selected[i].node_id=all[i].nid;pkt.selected[i].rtt=0;
struct TOPO_GROUP_NODE* nq=topo_node_find_by_id(entry->mgr->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;i<req->candidate_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);
}

4
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);

43
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);

29
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;

5
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");

Loading…
Cancel
Save