topo_group: асимметричный старт BGP (JOIN_GROUP) + вынос group_id/flags из TOPO_NODE
- UTUN: BGP инициирует только сторона-клиент ([client]) и явные etcp_connect; сервер добавляет пира по JOIN_GROUP (фикс обратного маршрута: сервер не создавал узел клиента из-за дедупа senders_list) - topo_group_new_conn: conn_add_path до дедупа; handle_request_table без add_to_senders - TOPO_NODE: убраны group_id/flags (shared-реестр), передаются в topo_node_serialize - routing/control_server: явный TOPO_GROUP_UTUN - CHAT: гейт по peers_* (get_member_channels) + пассивное add/remove в member_sync - tests: тесты адаптированы (route_ping ждёт registry+v4_addrs) - chatgui-android: voice_recorder_init в utun_bridge_voice_start (idempotent)
This commit is contained in:
1 parent
7b73d99b5b
commit
656da48e35
20 files changed
+236
-46
No files matched your search
@@ -497,6 +497,16 @@ int member_sync_apply_record(struct UTUN_INSTANCE* inst, const char* ch_id,
|
||||
if (rc == 0) changed = 0; /* запись была no-op (данные идентичны) */
|
||||
}
|
||||
|
||||
/* ── пассивное добавление: если узел уже подключён напрямую — добавить в CHAT-группу ── */
|
||||
if (changed && inst->topo_groups) {
|
||||
uint64_t gid = strtoull(ch_id, NULL, 10);
|
||||
struct TOPO_GROUP* g = topo_groups_find(inst->topo_groups, gid);
|
||||
if (g && g->group_type == TOPO_GROUP_TYPE_CHAT) {
|
||||
struct ETCP_CONN* c = instance_find_conn(inst, m->node_id);
|
||||
if (c) topo_group_new_conn(g, c);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: apply_record ch=%s nid=0x%016llx → changed=%d stale=%d",
|
||||
MS_ID, ch_id, (unsigned long long)m->node_id, changed, stale);
|
||||
return (changed ? MS_APPLY_CHANGED : 0) | (stale ? MS_APPLY_STALE : 0);
|
||||
@@ -608,6 +618,15 @@ int member_sync_verify_and_purge(struct UTUN_INSTANCE* inst, const char* ch_id)
|
||||
MS_ID, (unsigned long long)nid, ch_id);
|
||||
topo_node_sqlite_member_del(db, ch_id, nid);
|
||||
merkle_sync_recompute_path(inst, ch_id, nid);
|
||||
/* пассивное удаление: если узел подключён напрямую — убрать из CHAT-группы */
|
||||
if (inst->topo_groups) {
|
||||
uint64_t gid = strtoull(ch_id, NULL, 10);
|
||||
struct TOPO_GROUP* g = topo_groups_find(inst->topo_groups, gid);
|
||||
if (g && g->group_type == TOPO_GROUP_TYPE_CHAT) {
|
||||
struct ETCP_CONN* c = instance_find_conn(inst, nid);
|
||||
if (c) topo_group_remove_conn(g, c);
|
||||
}
|
||||
}
|
||||
purged++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1569,4 +1569,15 @@ int update_config_keys(const char *filename, const char *priv_key, const char *p
|
||||
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_peer_in_clients(const struct utun_config* config, const uint8_t* pubkey) {
|
||||
if (!config || !pubkey) return 0;
|
||||
uint8_t pk_bin[SC_PUBKEY_SIZE];
|
||||
for (const struct CFG_CLIENT* cli = config->clients; cli; cli = cli->next) {
|
||||
if (!cli->peer_public_key_hex[0]) continue;
|
||||
if (hex_to_binary(cli->peer_public_key_hex, pk_bin, SC_PUBKEY_SIZE) != 0) continue;
|
||||
if (memcmp(pk_bin, pubkey, SC_PUBKEY_SIZE) == 0) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -228,6 +228,9 @@ void print_config(const struct utun_config *config);
|
||||
void print_chatserver_invite_link(const struct utun_config *config, const struct CFG_SERVER *servers);
|
||||
int update_config_keys(const char *filename, const char *priv_key, const char *pub_key);
|
||||
|
||||
/* Узел (по pubkey, 32 байта) присутствует в списке [client] конфига? 1=да, 0=нет. */
|
||||
int config_peer_in_clients(const struct utun_config* config, const uint8_t* pubkey);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1390,7 +1390,7 @@ static void send_single_node_info(struct control_server* server, struct control_
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(server->instance->topo_groups, nq->node_id);
|
||||
if (!ni) return;
|
||||
uint8_t buf[8192];
|
||||
int ser_len = topo_node_serialize(ni, nq, buf + 2, sizeof(buf) - 2, 0);
|
||||
int ser_len = topo_node_serialize(ni, nq, TOPO_GROUP_UTUN, TOPO_FLAG_SEND_SUBNETS, buf + 2, sizeof(buf) - 2, 0);
|
||||
if (ser_len < 0) { DEBUG_ERROR(DEBUG_CATEGORY_CONTROL, "Failed to serialize node info"); return; }
|
||||
buf[0] = CTRL_BGP_CMD; buf[1] = CTRL_BGP_SUBCMD;
|
||||
size_t data_size = 2 + (size_t)ser_len;
|
||||
|
||||
@@ -61,6 +61,11 @@ static void md_mkdir_parent(const char* filepath) {
|
||||
|
||||
static int md_dl_send(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst, const uint8_t* data, size_t len) {
|
||||
if (!inst || !inst->topo_groups || !inst->connections) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "%s: md_dl_send: no routing (inst=%p topo=%p conn=%p)", MDL_ID, (void*)inst, (void*)(inst ? inst->topo_groups : NULL), (void*)(inst ? inst->connections : NULL)); return -1; }
|
||||
{ struct TOPO_GROUP* grp = topo_groups_find(inst->topo_groups, group_id);
|
||||
struct ETCP_CONN* gc = grp ? topo_group_find_conn_for_node(grp, dst) : NULL;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "%s: md_dl_send group=0x%016llx dst=0x%016llx grp=%p conn_in_group=%p",
|
||||
MDL_ID, (unsigned long long)group_id, (unsigned long long)dst, (void*)grp, (void*)gc);
|
||||
}
|
||||
struct ll_entry* e = queue_entry_new(0);
|
||||
if (!e) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "%s: queue_entry_new failed for send to 0x%016llx", MDL_ID, (unsigned long long)dst); return -1; }
|
||||
e->dgram = u_malloc(len + 1);
|
||||
|
||||
@@ -145,7 +145,7 @@ void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry, uint64_t
|
||||
} else {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_pkt: sending %zu bytes to node %016llx dst=%s",
|
||||
ip_len, (unsigned long long)nq->node_id, ip_to_str(&addr, AF_INET).str);
|
||||
int send_err = etcp_route_send(instance, rni->group_id, nq->node_id, entry, 1);
|
||||
int send_err = etcp_route_send(instance, TOPO_GROUP_UTUN, nq->node_id, entry, 1);
|
||||
if (send_err != 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_pkt: etcp_route_send failed: dst=%s err=%d",
|
||||
ip_to_str(&addr, AF_INET).str, send_err);
|
||||
|
||||
+114
-23
@@ -48,6 +48,20 @@ 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); }
|
||||
}
|
||||
|
||||
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);
|
||||
struct TOPOMSG_JOIN_GROUP* req = u_calloc(1, sizeof(struct TOPOMSG_JOIN_GROUP));
|
||||
if (!req) return;
|
||||
req->cmd = ETCP_ID_TOPO_ENTRY;
|
||||
req->subcmd = TOPO_SUBCMD_JOIN_GROUP;
|
||||
req->group_id = group->group_id;
|
||||
struct ll_entry* e = queue_entry_new(0);
|
||||
if (!e) { u_free(req); return; }
|
||||
e->dgram = (uint8_t*)req; e->len = sizeof(struct TOPOMSG_JOIN_GROUP);
|
||||
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));
|
||||
@@ -65,6 +79,7 @@ static void topo_group_add_to_senders(struct TOPO_GROUP* group, struct ETCP_CONN
|
||||
static bool topo_group_should_send_to(const struct TOPO_GROUP_NODE* nq, uint64_t target_id);
|
||||
static void topo_group_send_full_table(struct TOPO_GROUP* group, struct ETCP_CONN* conn);
|
||||
static void topo_group_handle_request_table(struct TOPO_GROUP* group, struct ETCP_CONN* conn);
|
||||
static void topo_group_handle_join_group(struct TOPO_GROUP* group, struct ETCP_CONN* conn);
|
||||
|
||||
static void nodeinfo_dump_log(const uint8_t* data, size_t len) {
|
||||
if (!data || len < sizeof(struct TOPOMSG_NODEINFO_PKT)) return;
|
||||
@@ -114,6 +129,7 @@ static const char* group_subcmd_name(uint8_t subcmd) {
|
||||
case TOPO_SUBCMD_WITHDRAW: return "WITHDRAW";
|
||||
case TOPO_SUBCMD_TABLE_COMPLETE: return "TABLE_COMPLETE";
|
||||
case TOPO_SUBCMD_ERR_GROUP_MISMATCH: return "ERR_GROUP_MISMATCH";
|
||||
case TOPO_SUBCMD_JOIN_GROUP: return "JOIN_GROUP";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
@@ -164,6 +180,8 @@ static void topo_group_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
|
||||
pkt_group_id = ((struct TOPOMSG_TABLE_REQ*)data)->group_id;
|
||||
} else if (subcmd == TOPO_SUBCMD_ERR_GROUP_MISMATCH && entry->len >= sizeof(struct TOPOMSG_ERR_GROUP_MISMATCH)) {
|
||||
pkt_group_id = ((struct TOPOMSG_ERR_GROUP_MISMATCH*)data)->group_id;
|
||||
} else if (subcmd == TOPO_SUBCMD_JOIN_GROUP && entry->len >= sizeof(struct TOPOMSG_JOIN_GROUP)) {
|
||||
pkt_group_id = ((struct TOPOMSG_JOIN_GROUP*)data)->group_id;
|
||||
}
|
||||
|
||||
struct TOPO_GROUP* group = topo_groups_find(instance->topo_groups, pkt_group_id);
|
||||
@@ -177,6 +195,7 @@ static void topo_group_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
|
||||
if (subcmd == TOPO_SUBCMD_NODEINFO) { nodeinfo_dump_log(data, entry->len); topo_group_process_nodeinfo(group, from_conn, data, entry->len); }
|
||||
else if (subcmd == TOPO_SUBCMD_WITHDRAW) topo_group_process_withdraw(group, from_conn, data, entry->len);
|
||||
else if (subcmd == TOPO_SUBCMD_REQUEST_TABLE) topo_group_handle_request_table(group, from_conn);
|
||||
else if (subcmd == TOPO_SUBCMD_JOIN_GROUP) topo_group_handle_join_group(group, from_conn);
|
||||
else if (subcmd == TOPO_SUBCMD_TABLE_COMPLETE) { etcp_set_routing_exchange_state(from_conn, 3); DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP sync complete with %s: %d nodes grp=%016llx", from_conn->log_name, queue_entry_count(group->nodes), (unsigned long long)group->group_id); }
|
||||
else if (subcmd == TOPO_SUBCMD_ERR_GROUP_MISMATCH) {
|
||||
if (entry->len >= sizeof(struct TOPOMSG_ERR_GROUP_MISMATCH)) {
|
||||
@@ -194,14 +213,77 @@ static void topo_group_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
|
||||
// Init / Destroy / New / Remove conn
|
||||
// ============================================================================
|
||||
|
||||
/* Создать TOPO_GROUP_NODE (если нет) + прямой путь через conn (hop=1). Без BGP.
|
||||
Используется из topo_group_new_conn (add + init BGP) и из приёма TABLE_REQ (входящий запросил BGP). */
|
||||
static void topo_group_conn_add_path(struct TOPO_GROUP* group, struct ETCP_CONN* conn, uint64_t node_id) {
|
||||
if (!group || !conn || !node_id || node_id == group->instance->node_id) return;
|
||||
|
||||
/* узел в реестре — иначе загрузить из БД (nodes + node_addresses), чтобы форвардинг мог сериализовать */
|
||||
{ struct TOPO_GROUPS* groups = group->instance->topo_groups;
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(groups, node_id);
|
||||
if (!ni) {
|
||||
sqlite3* db = group->instance->topo_sqlite_db;
|
||||
ni = db ? topo_node_sqlite_node_load(db, groups, node_id) : NULL;
|
||||
if (ni) ni = topo_node_registry_store(groups, ni);
|
||||
}
|
||||
}
|
||||
|
||||
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(group, node_id);
|
||||
if (nq && nq->paths) {
|
||||
struct ll_entry* pe = nq->paths->head;
|
||||
while (pe) { if (((struct TOPO_NODEPATH*)pe)->conn == conn) return; pe = pe->next; }
|
||||
}
|
||||
if (!nq) {
|
||||
struct ll_entry* qe = queue_entry_new(sizeof(struct TOPO_GROUP_NODE));
|
||||
if (!qe) return;
|
||||
nq = (struct TOPO_GROUP_NODE*)qe;
|
||||
memset((uint8_t*)nq + sizeof(struct ll_entry), 0, sizeof(*nq) - sizeof(struct ll_entry));
|
||||
nq->node_id = node_id;
|
||||
queue_data_put_with_index(group->nodes, &nq->ll);
|
||||
}
|
||||
uint64_t hop[1] = { node_id };
|
||||
topo_group_add_path(nq, conn, hop, 1, 0);
|
||||
nq->conn_presence |= NCONN_DIRECT;
|
||||
nq->conn_up |= NCONN_DIRECT;
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "conn_add_path: node=0x%016llx grp=%016llx ch=%s conn=%s",
|
||||
(unsigned long long)node_id, (unsigned long long)group->group_id, group->channel_id, conn->log_name);
|
||||
}
|
||||
|
||||
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;
|
||||
struct ll_entry* fe = groups->group_list->head;
|
||||
while (fe) { struct TOPO_GROUP* g = (struct TOPO_GROUP*)fe; fe = fe->next;
|
||||
if (status == ETCP_CONN_STATUS_UP) topo_group_new_conn(g, conn);
|
||||
if (status == ETCP_CONN_STATUS_DOWN) topo_group_remove_conn(g, conn);
|
||||
if (status == ETCP_CONN_STATUS_DELETE) topo_group_remove_conn(g, conn);
|
||||
|
||||
if (status == ETCP_CONN_STATUS_UP && conn->peer_node_id) {
|
||||
/* non-CHAT (UTUN): узлы из конфига (clients) + явные подключения (etcp_connect). */
|
||||
int explicit_conn = conn->bgp_ready_cbk != NULL;
|
||||
struct ll_entry* fe = groups->group_list->head;
|
||||
while (fe) {
|
||||
struct TOPO_GROUP* g = (struct TOPO_GROUP*)fe; fe = fe->next;
|
||||
if (g->group_type != TOPO_GROUP_TYPE_CHAT) {
|
||||
int is_client = conn->instance->config && config_peer_in_clients(conn->instance->config, conn->crypto_ctx.peer_public_key);
|
||||
if (is_client || explicit_conn) {
|
||||
topo_group_new_conn(g, conn); /* добавить + инициировать BGP */
|
||||
topo_group_send_join_group(g, conn); /* запросить членство у пира */
|
||||
}
|
||||
}
|
||||
}
|
||||
/* CHAT: только члены каналов (peers_* в БД). */
|
||||
sqlite3* db = conn->instance ? conn->instance->topo_sqlite_db : NULL;
|
||||
uint64_t* chs = NULL; int chn = 0;
|
||||
if (db && topo_node_sqlite_get_member_channels(db, conn->peer_node_id, &chs, &chn) == 0 && chn > 0) {
|
||||
for (int i = 0; i < chn; i++) {
|
||||
struct TOPO_GROUP* cg = topo_groups_find(groups, chs[i]);
|
||||
if (cg && cg->group_type == TOPO_GROUP_TYPE_CHAT)
|
||||
topo_group_new_conn(cg, conn);
|
||||
}
|
||||
}
|
||||
u_free(chs);
|
||||
} else if (status == ETCP_CONN_STATUS_DOWN || status == ETCP_CONN_STATUS_DELETE) {
|
||||
struct ll_entry* fe = groups->group_list->head;
|
||||
while (fe) { struct TOPO_GROUP* g = (struct TOPO_GROUP*)fe; fe = fe->next;
|
||||
topo_group_remove_conn(g, conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,9 +549,21 @@ void topo_group_new_conn(struct TOPO_GROUP* group, struct ETCP_CONN* conn) {
|
||||
if (!conn->instance) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "conn->instance is NULL"); return; }
|
||||
if (!conn->instance->rt) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "conn->instance->rt is NULL"); return; }
|
||||
|
||||
topo_recovery_cancel_for_node(group, conn->peer_node_id);
|
||||
|
||||
/* создать узел + прямой путь (сразу, не дожидаясь NODEINFO; дедуп внутри по conn).
|
||||
Делаем ДО проверки senders_list: conn может уже быть в senders_list (через handle_request_table),
|
||||
но узел ещё не создан (входящий JOIN_GROUP). */
|
||||
topo_group_conn_add_path(group, conn, conn->peer_node_id);
|
||||
{ struct TOPO_GROUP_NODE* peer_nq = topo_node_find_by_id(group, conn->peer_node_id);
|
||||
if (peer_nq) {
|
||||
peer_nq->connectivity.last_ping_time = get_time_tb();
|
||||
if (conn->instance->topo_sqlite_db) topo_node_sqlite_nodeinfo_updated(conn->instance->topo_sqlite_db, conn->peer_node_id);
|
||||
}
|
||||
}
|
||||
|
||||
/* дедуп: тот же conn стреляет ETCP_CONN_STATUS_UP дважды (UDP-линк, затем TCP-линк).
|
||||
* Если conn уже в senders_list — повторно не обрабатываем, иначе active_conn_count
|
||||
* задваивается и переподключение никогда не стартует. */
|
||||
* Если conn уже в senders_list — не слать повторно TABLE_REQ и не задваивать active_conn_count. */
|
||||
{ struct ll_entry* se = group->senders_list ? group->senders_list->head : NULL;
|
||||
while (se) {
|
||||
if (((struct TOPO_GROUP_CONN_ITEM*)se->data)->conn == conn) {
|
||||
@@ -480,15 +574,6 @@ void topo_group_new_conn(struct TOPO_GROUP* group, struct ETCP_CONN* conn) {
|
||||
}
|
||||
}
|
||||
|
||||
topo_recovery_cancel_for_node(group, conn->peer_node_id);
|
||||
|
||||
struct TOPO_GROUP_NODE* peer_nq = topo_node_find_by_id(group, conn->peer_node_id);
|
||||
if (peer_nq) {
|
||||
peer_nq->connectivity.last_ping_time = get_time_tb();
|
||||
peer_nq->conn_presence |= NCONN_DIRECT;
|
||||
peer_nq->conn_up |= NCONN_DIRECT;
|
||||
if (conn->instance->topo_sqlite_db) topo_node_sqlite_nodeinfo_updated(conn->instance->topo_sqlite_db, conn->peer_node_id);
|
||||
}
|
||||
topo_group_add_to_senders(group, conn);
|
||||
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "topo_group_new_conn: peer=%016llx group=%016llx type=%d ch=%s", (unsigned long long)conn->peer_node_id, (unsigned long long)group->group_id, group->group_type, group->channel_id);
|
||||
@@ -740,8 +825,6 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
|
||||
if (nodeinfo1) {
|
||||
{ struct TOPO_NODE* stored = topo_node_registry_store(group->instance->topo_groups, new_ni);
|
||||
if (stored != new_ni) new_ni = stored; }
|
||||
new_ni->group_id = group->group_id;
|
||||
new_ni->flags = pkt->node.flags;
|
||||
nodeinfo1->node_id = new_ni ? new_ni->node_id : 0;
|
||||
nodeinfo1->subnets = new_subnets;
|
||||
} else {
|
||||
@@ -751,8 +834,6 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
|
||||
memset((uint8_t*)nodeinfo1 + sizeof(struct ll_entry), 0, sizeof(*nodeinfo1) - sizeof(struct ll_entry));
|
||||
{ struct TOPO_NODE* stored = topo_node_registry_store(group->instance->topo_groups, new_ni);
|
||||
if (stored != new_ni) new_ni = stored; }
|
||||
new_ni->group_id = group->group_id;
|
||||
new_ni->flags = pkt->node.flags;
|
||||
nodeinfo1->node_id = new_ni ? new_ni->node_id : 0;
|
||||
nodeinfo1->subnets = new_subnets;
|
||||
nodeinfo1->connectivity.probe_status = PROBE_STATUS_NONE;
|
||||
@@ -888,8 +969,9 @@ void topo_group_send_nodeinfo(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE*
|
||||
u_free(p);
|
||||
return;
|
||||
}
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "send_nodeinfo: node %016llx ver=%d grp=%016llx to conn=%s", (unsigned long long)node->node_id, sni->ver, (unsigned long long)sni->group_id, conn->log_name);
|
||||
int ser_len = topo_node_serialize(sni, node, p + 2, max_sz - 2, cumulative_rtt);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "send_nodeinfo: node %016llx ver=%d grp=%016llx to conn=%s", (unsigned long long)node->node_id, sni->ver, (unsigned long long)group->group_id, conn->log_name);
|
||||
uint8_t sflags = (group->group_type == TOPO_GROUP_TYPE_CHAT) ? 0 : TOPO_FLAG_SEND_SUBNETS;
|
||||
int ser_len = topo_node_serialize(sni, node, group->group_id, sflags, p + 2, max_sz - 2, cumulative_rtt);
|
||||
if (ser_len < 0) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "send_nodeinfo: serialize failed for node %016llx", (unsigned long long)node->node_id); u_free(p); return; }
|
||||
|
||||
struct ll_entry* e = queue_entry_new(0);
|
||||
@@ -941,10 +1023,19 @@ static void topo_group_handle_request_table(struct TOPO_GROUP* group, struct ETC
|
||||
if (!group || !conn) return;
|
||||
topo_group_send_nodeinfo(group, group->local_node, conn, 0);
|
||||
topo_group_send_full_table(group, conn);
|
||||
topo_group_add_to_senders(group, conn);
|
||||
/* senders_list заполняется только через topo_group_new_conn (add + BGP);
|
||||
здесь не добавляем, иначе new_conn (на JOIN_GROUP) упирается в дедуп и не шлёт TABLE_REQ обратно. */
|
||||
topo_group_send_table_complete(group, conn);
|
||||
}
|
||||
|
||||
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);
|
||||
/* входящий запросил членство: для non-CHAT (UTUN) — добавить запросившего узла + инициировать BGP обратно */
|
||||
if (group->group_type != TOPO_GROUP_TYPE_CHAT)
|
||||
topo_group_new_conn(group, conn);
|
||||
}
|
||||
|
||||
/* ── BGP node event callbacks ── */
|
||||
|
||||
void topo_group_add_node_cbk(struct TOPO_GROUP* group, topo_node_event_fn fn, void* arg) {
|
||||
|
||||
@@ -96,6 +96,7 @@ void topo_fire_nodeinfo_cbk(struct UTUN_INSTANCE* instance, struct TOPO_GROUP* g
|
||||
#define TOPO_SUBCMD_WITHDRAW 0x06 // узел стал недоступен
|
||||
#define TOPO_SUBCMD_TABLE_COMPLETE 0x0B // завершение начальной синхронизации таблицы
|
||||
#define TOPO_SUBCMD_ERR_GROUP_MISMATCH 0x0C // ошибка несоответствия типа группы
|
||||
#define TOPO_SUBCMD_JOIN_GROUP 0x0D // запрос членства в группе
|
||||
|
||||
#define MAX_HOPS 16
|
||||
#define BGP_NODES_HASH_SIZE 256
|
||||
@@ -129,6 +130,15 @@ struct TOPOMSG_TABLE_REQ {
|
||||
uint64_t group_id; // идентификатор группы
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* @brief Пакет запроса членства в группе (отправитель просит добавить его в группу)
|
||||
*/
|
||||
struct TOPOMSG_JOIN_GROUP {
|
||||
uint8_t cmd;
|
||||
uint8_t subcmd;
|
||||
uint64_t group_id; // идентификатор группы
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* @brief Пакет ошибки несоответствия типа группы
|
||||
*/
|
||||
|
||||
@@ -436,7 +436,7 @@ int topo_group_invite_join(struct UTUN_INSTANCE* inst, uint64_t group_id,
|
||||
/* 2. Копировать ni в group_ni */
|
||||
struct TOPO_GROUPS* groups = inst->topo_groups;
|
||||
struct TOPO_NODE* gni = u_calloc(1, sizeof(*gni)); if (!gni) return -1;
|
||||
gni->node_id = nid; gni->ver = 1; gni->group_id = group_id; memcpy(gni->public_key, ni->public_key, SC_PUBKEY_SIZE);
|
||||
gni->node_id = nid; gni->ver = 1; memcpy(gni->public_key, ni->public_key, SC_PUBKEY_SIZE);
|
||||
for (const struct TOPO_ADDR4* src = ni->v4_addrs; src; src = src->next) {
|
||||
struct TOPO_ADDR4* a4 = memory_pool_alloc(groups->v4_addr_pool); if (!a4) continue;
|
||||
memset(a4, 0, sizeof(*a4)); memcpy(a4->addr, src->addr, 4); a4->port = src->port;
|
||||
|
||||
@@ -259,13 +259,15 @@ int topo_node_dyn_size(const struct TOPOMSG_NODE* msg) {
|
||||
+ msg->hop_count * 8;
|
||||
}
|
||||
|
||||
int topo_node_serialize(struct TOPO_NODE* ni, struct TOPO_GROUP_NODE* nq, uint8_t* out, size_t out_max, uint16_t cumulative_rtt) {
|
||||
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) {
|
||||
if (!ni || !nq || !out) return -1;
|
||||
|
||||
struct TOPOMSG_NODE msg;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.flags = ni->flags;
|
||||
msg.group_id = ni->group_id;
|
||||
msg.flags = flags;
|
||||
msg.group_id = group_id;
|
||||
msg.node_id = ni->node_id;
|
||||
msg.ver = ni->ver;
|
||||
memcpy(msg.public_key, ni->public_key, SC_PUBKEY_SIZE);
|
||||
@@ -339,8 +341,6 @@ int topo_node_deserialize(struct TOPO_GROUP* group, const uint8_t* data, size_t
|
||||
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE));
|
||||
if (!ni) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "alloc TOPO_NODE failed"); return -1; }
|
||||
ni->group_ref_count = 0;
|
||||
ni->flags = msg->flags;
|
||||
ni->group_id = msg->group_id;
|
||||
ni->node_id = msg->node_id;
|
||||
ni->ver = msg->ver;
|
||||
memcpy(ni->public_key, msg->public_key, SC_PUBKEY_SIZE);
|
||||
@@ -551,7 +551,7 @@ void topo_node_dump_all(struct TOPO_GROUP* group) {
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "--- Node #%d: id=%016llx name=\"%s\" ver=%u grp=%llu%s ---",
|
||||
idx, (unsigned long long)ni->node_id, name_s, ni->ver,
|
||||
(unsigned long long)ni->group_id, is_local ? " [LOCAL]" : "");
|
||||
(unsigned long long)group->group_id, is_local ? " [LOCAL]" : "");
|
||||
|
||||
log_dump(DEBUG_LEVEL_INFO, DEBUG_CATEGORY_BGP, " pubkey ", ni->public_key, SC_PUBKEY_SIZE);
|
||||
log_dump(DEBUG_LEVEL_INFO, DEBUG_CATEGORY_BGP, " ed25519", ni->ed25519_public_key, SC_PUBKEY_SIZE);
|
||||
@@ -642,7 +642,7 @@ int topo_node_format_all(struct TOPO_GROUP* group, char* buf, size_t buf_size) {
|
||||
|
||||
FMT_ADD("--- Node #%d: id=%016llx name=\"%s\" ver=%u grp=%llu%s ---\n",
|
||||
idx, (unsigned long long)ni->node_id, name_s, ni->ver,
|
||||
(unsigned long long)ni->group_id, is_local ? " [LOCAL]" : "");
|
||||
(unsigned long long)group->group_id, is_local ? " [LOCAL]" : "");
|
||||
|
||||
FMT_ADD(" pubkey: "); for (int k = 0; k < SC_PUBKEY_SIZE; k++) FMT_ADD("%02x", ni->public_key[k]); FMT_ADD("\n");
|
||||
FMT_ADD(" ed25519: "); for (int k = 0; k < SC_PUBKEY_SIZE; k++) FMT_ADD("%02x", ni->ed25519_public_key[k]); FMT_ADD("\n");
|
||||
@@ -797,8 +797,6 @@ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GR
|
||||
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE));
|
||||
if (!ni) { u_free(lq); group->local_node = NULL; return -1; }
|
||||
ni->group_ref_count = 0;
|
||||
ni->flags = (group->group_type == TOPO_GROUP_TYPE_CHAT) ? 0 : TOPO_FLAG_SEND_SUBNETS;
|
||||
ni->group_id = group->group_id;
|
||||
ni->node_id = instance->node_id;
|
||||
ni->ver = (old_ver % 255) + 1;
|
||||
ni->client_type = instance->client_type;
|
||||
|
||||
@@ -139,7 +139,7 @@ static inline int topo_list_count(struct _topo_head* head) { int n = 0; while (h
|
||||
struct TOPO_NODE {
|
||||
struct ll_entry ll;
|
||||
uint32_t group_ref_count;
|
||||
uint8_t flags; uint64_t group_id, node_id; uint8_t ver;
|
||||
uint64_t node_id; uint8_t ver;
|
||||
uint8_t public_key[SC_PUBKEY_SIZE], ed25519_public_key[SC_PUBKEY_SIZE];
|
||||
uint8_t x25519_self_sig[64];
|
||||
uint8_t client_type; // CLIENT_TYPE_SERVER/DESKTOP/MOBILE
|
||||
@@ -191,7 +191,9 @@ struct TOPO_GROUP_NODE* topo_node_find_by_id(struct TOPO_GROUP* group, uint64_t
|
||||
void topo_nodeq_free_group_fields(struct TOPO_GROUPS* groups, struct TOPO_GROUP_NODE* nq);
|
||||
|
||||
int topo_node_dyn_size(const struct TOPOMSG_NODE* msg);
|
||||
int topo_node_serialize(struct TOPO_NODE* ni, struct TOPO_GROUP_NODE* nq, uint8_t* out, size_t out_max, uint16_t cumulative_rtt);
|
||||
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);
|
||||
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);
|
||||
|
||||
@@ -37,7 +37,7 @@ topo_group_update_my_nodeinfo(instance, group);
|
||||
```c
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(groups, nq->node_id);
|
||||
uint8_t buf[4096];
|
||||
int len = topo_node_serialize(ni, nq, buf, sizeof(buf), cumulative_rtt);
|
||||
int len = topo_node_serialize(ni, nq, group_id, flags, buf, sizeof(buf), cumulative_rtt);
|
||||
```
|
||||
Запаковывает `TOPO_NODE` + per-group данные (`TOPO_GROUP_NODE`) в буфер: заголовок
|
||||
`TOPOMSG_NODE`, затем имя узла, v4/v6 sock_meta, v4/v6 адреса, подсети (если
|
||||
@@ -143,7 +143,7 @@ topo_node_format_all(group, buf, size); // в строку
|
||||
|
||||
**Сериализация:**
|
||||
- `topo_node_dyn_size(msg)` — размер динамической части по счётчикам заголовка.
|
||||
- `topo_node_serialize(ni, nq, out, out_max, cumulative_rtt)` — сериализовать `TOPO_NODE` + per-group в буфер.
|
||||
- `topo_node_serialize(ni, nq, group_id, flags, out, out_max, cumulative_rtt)` — сериализовать `TOPO_NODE` + per-group в буфер.
|
||||
- `topo_node_deserialize(group, data, len, &out_ni, &out_subnets, &out_hop_list, &out_hop_count, &out_cumulative_rtt)` — восстановить из wire-формата.
|
||||
|
||||
**Пути:**
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "../lib/json_flat.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define PEERS_JOIN_SIG_SIZE 64
|
||||
#define PEERS_JOIN_TS_SIZE 8
|
||||
@@ -168,6 +169,46 @@ int topo_node_sqlite_member_exists(sqlite3* db, uint64_t node_id) {
|
||||
return found;
|
||||
}
|
||||
|
||||
int topo_node_sqlite_get_member_channels(sqlite3* db, uint64_t node_id,
|
||||
uint64_t** out_ch_ids, int* out_count) {
|
||||
if (!db || !out_ch_ids || !out_count) return -1;
|
||||
*out_ch_ids = NULL; *out_count = 0;
|
||||
|
||||
sqlite3_stmt* s = NULL;
|
||||
if (sqlite3_prepare_v2(db,
|
||||
"SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'peers\\_%' ESCAPE '\\'",
|
||||
-1, &s, NULL) != SQLITE_OK) return -1;
|
||||
|
||||
uint64_t* ids = NULL; int count = 0, cap = 0;
|
||||
char sql[256];
|
||||
while (sqlite3_step(s) == SQLITE_ROW) {
|
||||
const char* tbl = (const char*)sqlite3_column_text(s, 0);
|
||||
if (!tbl || strncmp(tbl, "peers_", 6) != 0) continue;
|
||||
snprintf(sql, sizeof(sql), "SELECT 1 FROM \"%s\" WHERE node_id=?", tbl);
|
||||
sqlite3_stmt* m = NULL;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &m, NULL) == SQLITE_OK) {
|
||||
sqlite3_bind_int64(m, 1, (sqlite3_int64)node_id);
|
||||
int is_member = (sqlite3_step(m) == SQLITE_ROW);
|
||||
sqlite3_finalize(m);
|
||||
if (is_member) {
|
||||
uint64_t ch = strtoull(tbl + 6, NULL, 10);
|
||||
if (ch != 0) {
|
||||
if (count == cap) {
|
||||
cap = cap ? cap * 2 : 8;
|
||||
uint64_t* tmp = u_realloc(ids, (size_t)cap * sizeof(uint64_t));
|
||||
if (!tmp) { u_free(ids); sqlite3_finalize(s); return -1; }
|
||||
ids = tmp;
|
||||
}
|
||||
ids[count++] = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(s);
|
||||
*out_ch_ids = ids; *out_count = count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int topo_node_sqlite_init(sqlite3* db) {
|
||||
if (!db) return -1;
|
||||
|
||||
|
||||
@@ -23,6 +23,10 @@ int topo_node_sqlite_addrs_put(sqlite3* db, uint64_t node_id, struct TOPO_NODE*
|
||||
/* Есть ли у узла запись мембера хотя бы в одной peers_<ch> (реальный мембер с ключами). */
|
||||
int topo_node_sqlite_member_exists(sqlite3* db, uint64_t node_id);
|
||||
|
||||
/* Список channel_id (uint64) всех peers_<ch>, где узел является членом. 0=ок. */
|
||||
int topo_node_sqlite_get_member_channels(sqlite3* db, uint64_t node_id,
|
||||
uint64_t** out_ch_ids, int* out_count);
|
||||
|
||||
int topo_node_sqlite_channel_put(sqlite3* db, const char* channel_id,
|
||||
const char* name, uint64_t owner_node_id,
|
||||
const uint8_t* x25519_pub, const uint8_t* x25519_priv,
|
||||
|
||||
Reference in new issue
Block a user