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

+19 -16
View File
@@ -17,6 +17,7 @@
#include "invite_link.h"
#include "invite_build.h"
#include "member_sync.h"
#include "chat_event.h"
#include "../routing_layer/topo_node_sqlite.h"
#include "../routing_layer/topo_group.h"
#include "../routing_layer/topo_node.h"
@@ -235,21 +236,22 @@ static int wait_file(struct UTUN_INSTANCE* inst, const char* path, int max_iter)
return 0;
}
/* J получил JOIN_READY: cs_handle_join_ready вызвал topo_group_new_conn → senders_list непуст */
static int wait_group_started(struct UTUN_INSTANCE* inst, int max_iter) {
uint64_t gid = strtoull(g_sh.ch_id, NULL, 10);
for (int a = 0; a < max_iter; a++) {
struct TOPO_GROUP* g = topo_groups_find(inst->topo_groups, gid);
if (g && g->senders_list && g->senders_list->head) return 1;
uasync_poll(inst->ua, POLL_MS);
/* JOIN_READY (успех join) наблюдается через CHAT_EVT_CONNECT_RESULT(result=0):
* сигнал точный (в отличие от senders_list, заполняемого и ncd-подключением)
* и не зависит от того, успел ли connection-узел остаться в живых до синка мембера. */
static int g_j_join_ok = 0;
static void join_event_handler(struct UTUN_INSTANCE* inst, int type, const uint8_t* data, int len) {
(void)inst;
if (type == CHAT_EVT_CONNECT_RESULT && len >= 12) {
int r = 0; memcpy(&r, data + 8, 4);
if (r == 0) g_j_join_ok = 1;
}
{
struct TOPO_GROUP* g = topo_groups_find(inst->topo_groups, gid);
fprintf(stderr, " [join-ready-fail] self=0x%016llx group=%p senders_head=%p\n",
(unsigned long long)inst->node_id, (void*)g,
(void*)(g && g->senders_list ? g->senders_list->head : NULL));
}
return 0;
}
static int wait_join_result(struct UTUN_INSTANCE* inst, int max_iter) {
for (int a = 0; a < max_iter && !g_j_join_ok; a++) uasync_poll(inst->ua, POLL_MS);
return g_j_join_ok;
}
/* ── настройка канала и мемберов ── */
@@ -291,6 +293,7 @@ static int child_main(const char* role, const char* dir, int invalid_key) {
struct UTUN_INSTANCE* inst = utun_instance_create(ua, cfg);
if (!inst) { fprintf(stderr, "%s: create failed\n", role); uasync_destroy(ua, 0); return 1; }
utun_instance_init(inst);
chat_event_set_handler(inst, join_event_handler);
int rc = 1;
uint64_t ch_num = strtoull(g_sh.ch_id, NULL, 10);
@@ -397,8 +400,8 @@ static int child_main(const char* role, const char* dir, int invalid_key) {
rc = wait_not_member(inst, g_sh.nid[IDX_J], 200) ? 0 : 1;
if (rc) fprintf(stderr, "J: unexpectedly became member with wrong key\n");
} else {
/* критерий J по ТЗ: получил JOIN_READY (topo_group_new_conn → senders_list) */
if (!wait_group_started(inst, 8000)) {
/* критерий J по ТЗ: получил JOIN_READY (CHAT_EVT_CONNECT_RESULT result=0) */
if (!wait_join_result(inst, 8000)) {
fprintf(stderr, "J: no JOIN_READY\n"); goto out;
}
rc = 0;