topo: remember REQUEST_TABLE for not-yet-created groups, fulfill on create

При REQUEST_TABLE для ещё не созданной группы (CHAT-канал не загружен) пир
дропал запрос, и проситель навсегда не узнавал таблицу — односторонняя
видимость (звонок android→linux падал «peer offline»). Теперь запрос
запоминается в pending_table_reqs[32] и выполняется при создании группы
(topo_group_fulfill_table_reqs → handle_request_table).

Попутно: test_chat_join_e2e — критерий успеха через CHAT_EVT_CONNECT_RESULT
(JOIN_READY) вместо senders_list; doxygen-комментарии в etcp_api.h.
This commit is contained in:
evgeny committed 2026-09-18 23:36:45 +03:00
1 parent 8bfb456161
commit 6d3ad965ee
5 files changed
+221 -19

No files matched your search

+39
View File
@@ -102,6 +102,42 @@ 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);
/* Запоминает REQUEST_TABLE для группы, которой у нас ещё нет (CHAT-канал не загружен). */
static void topo_group_remember_table_req(struct TOPO_GROUPS* g, uint64_t node_id, uint64_t group_id) {
if (!g) return;
for (int i = 0; i < g->pending_table_req_count; i++)
if (g->pending_table_reqs[i].node_id == node_id && g->pending_table_reqs[i].group_id == group_id) return;
if (g->pending_table_req_count >= TOPO_MAX_PENDING_TABLE_REQS) {
memmove(g->pending_table_reqs, g->pending_table_reqs + 1,
(TOPO_MAX_PENDING_TABLE_REQS - 1) * sizeof(g->pending_table_reqs[0]));
g->pending_table_req_count = TOPO_MAX_PENDING_TABLE_REQS - 1;
}
g->pending_table_reqs[g->pending_table_req_count].node_id = node_id;
g->pending_table_reqs[g->pending_table_req_count].group_id = group_id;
g->pending_table_req_count++;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "remembered table request node=%016llx grp=%016llx (group not created yet)",
(unsigned long long)node_id, (unsigned long long)group_id);
}
/* Когда группа создана — отвечаем тем, кто просил её таблицу раньше. */
static void topo_group_fulfill_table_reqs(struct TOPO_GROUPS* g, uint64_t group_id) {
if (!g) return;
struct TOPO_GROUP* group = topo_groups_find(g, group_id);
if (!group) return;
int w = 0;
for (int i = 0; i < g->pending_table_req_count; i++) {
struct topo_pending_table_req* req = &g->pending_table_reqs[i];
if (req->group_id != group_id) { g->pending_table_reqs[w++] = *req; continue; }
struct ETCP_CONN* conn = instance_find_conn(g->instance, req->node_id);
if (conn && conn->links_up) {
DEBUG_INFO(DEBUG_CATEGORY_BGP, "fulfilling remembered table request node=%016llx grp=%016llx",
(unsigned long long)req->node_id, (unsigned long long)group_id);
topo_group_handle_request_table(group, conn);
}
}
g->pending_table_req_count = w;
}
/* Краткий 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;
@@ -219,6 +255,8 @@ static void topo_group_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
struct TOPO_GROUP* group = topo_groups_find(instance->topo_groups, pkt_group_id);
if (!group) {
if (subcmd == TOPO_SUBCMD_REQUEST_TABLE)
topo_group_remember_table_req(instance->topo_groups, from_conn->peer_node_id, pkt_group_id);
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "BGP recv %s from %s: group %016llx not found, dropping", group_subcmd_name(subcmd), from_conn->log_name, (unsigned long long)pkt_group_id);
queue_dgram_free(entry); queue_entry_free(entry); return;
}
@@ -580,6 +618,7 @@ struct TOPO_GROUP* topo_groups_create_group(struct TOPO_GROUPS* g, uint64_t grou
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Group created: group_id=%016llx type=%u ch_id=%s", (unsigned long long)group_id, group_type, group->channel_id);
if (group_type == TOPO_GROUP_TYPE_CHAT && chat_setting_get_int(group->instance, "group_autoconnect", 1)) topo_group_connect_init(group);
topo_group_fulfill_table_reqs(g, group_id);
return group;
}
+11
View File
@@ -195,6 +195,15 @@ struct TOPO_GROUP {
struct topo_node_cbk_entry* node_cbks; // цепочка подписчиков на события узлов
};
/* Отложенный REQUEST_TABLE: пир запросил таблицу группы, которой у нас ещё нет.
* Запоминаем (node_id, group_id) и отвечаем, когда группа будет создана. */
#define TOPO_MAX_PENDING_TABLE_REQS 32
struct topo_pending_table_req {
uint64_t node_id; /* кто запросил таблицу */
uint64_t group_id; /* какую группу */
};
/**
* @brief Контейнер всех групп топологии экземпляра
*/
@@ -209,6 +218,8 @@ struct TOPO_GROUPS {
struct memory_pool* v4_subnet_pool;
struct memory_pool* v6_subnet_pool;
topo_node_updated_fn node_updated_cb; /* optional — set by chatgui's member_sync */
struct topo_pending_table_req pending_table_reqs[TOPO_MAX_PENDING_TABLE_REQS];
int pending_table_req_count;
};
/**