|
|
|
@ -12,6 +12,7 @@ |
|
|
|
// invalid неверный ключ: J отклонён, мембера J нет.
|
|
|
|
// invalid неверный ключ: J отклонён, мембера J нет.
|
|
|
|
|
|
|
|
|
|
|
|
#include "chat_core.h" |
|
|
|
#include "chat_core.h" |
|
|
|
|
|
|
|
#include "chat_core_priv.h" |
|
|
|
#include "chat_sync.h" |
|
|
|
#include "chat_sync.h" |
|
|
|
#include "chat_join.h" |
|
|
|
#include "chat_join.h" |
|
|
|
#include "chat_headless_control.h" |
|
|
|
#include "chat_headless_control.h" |
|
|
|
@ -432,6 +433,46 @@ out: |
|
|
|
|
|
|
|
|
|
|
|
/* ── child_main ── */ |
|
|
|
/* ── child_main ── */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Проверяем выбор на реальных мемберах канала; изменения производных полей откатываем до следующего poll. */ |
|
|
|
|
|
|
|
static int check_invite_priority(struct UTUN_INSTANCE* inst) { |
|
|
|
|
|
|
|
uint64_t channel_id = strtoull(g_sh.ch_id, NULL, 10), selected = 0; |
|
|
|
|
|
|
|
struct TOPO_GROUP* group = topo_groups_find(inst->topo_groups, channel_id); |
|
|
|
|
|
|
|
struct TOPO_GROUP_NODE* peer = topo_node_find_by_id(group, g_sh.nid[IDX_C]); |
|
|
|
|
|
|
|
if (!peer) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "test invite priority: missing peer"); return 0; } |
|
|
|
|
|
|
|
uint64_t deadline = get_time_tb() + 10000; |
|
|
|
|
|
|
|
while (!peer->conn_presence && get_time_tb() < deadline) poll_checked(inst); |
|
|
|
|
|
|
|
if (!peer->conn_presence) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "test invite priority: peer unreachable"); return 0; } |
|
|
|
|
|
|
|
char table[80], sql[256]; |
|
|
|
|
|
|
|
peers_table_name(g_sh.ch_id, table, sizeof(table)); |
|
|
|
|
|
|
|
sqlite3* db = inst->topo_sqlite_db; |
|
|
|
|
|
|
|
if (sqlite3_exec(db, "SAVEPOINT invite_priority", NULL, NULL, NULL) != SQLITE_OK) { |
|
|
|
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "test invite priority: savepoint failed: %s", sqlite3_errmsg(db)); return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
int ok = 0; |
|
|
|
|
|
|
|
uint8_t presence = peer->conn_presence; |
|
|
|
|
|
|
|
snprintf(sql, sizeof(sql), "UPDATE \"%s\" SET node_type=1", table); |
|
|
|
|
|
|
|
if (sqlite3_exec(db, sql, NULL, NULL, NULL) != SQLITE_OK) goto out; |
|
|
|
|
|
|
|
if (chat_invite_best_node(inst, channel_id, &selected) || selected != g_sh.nid[IDX_C]) goto out; |
|
|
|
|
|
|
|
snprintf(sql, sizeof(sql), "UPDATE \"%s\" SET node_type=4 WHERE node_id=%lld", table, (long long)inst->node_id); |
|
|
|
|
|
|
|
if (sqlite3_exec(db, sql, NULL, NULL, NULL) != SQLITE_OK) goto out; |
|
|
|
|
|
|
|
if (chat_invite_best_node(inst, channel_id, &selected) || selected != inst->node_id) goto out; |
|
|
|
|
|
|
|
snprintf(sql, sizeof(sql), "UPDATE \"%s\" SET node_type=1 WHERE node_id=%lld", table, (long long)inst->node_id); |
|
|
|
|
|
|
|
if (sqlite3_exec(db, sql, NULL, NULL, NULL) != SQLITE_OK) goto out; |
|
|
|
|
|
|
|
snprintf(sql, sizeof(sql), "UPDATE \"%s\" SET node_type=4 WHERE node_id=%lld", table, (long long)g_sh.nid[IDX_C]); |
|
|
|
|
|
|
|
if (sqlite3_exec(db, sql, NULL, NULL, NULL) != SQLITE_OK) goto out; |
|
|
|
|
|
|
|
if (chat_invite_best_node(inst, channel_id, &selected) || selected != g_sh.nid[IDX_C]) goto out; |
|
|
|
|
|
|
|
peer->conn_presence = 0; |
|
|
|
|
|
|
|
if (chat_invite_best_node(inst, channel_id, &selected) || selected != inst->node_id) goto out; |
|
|
|
|
|
|
|
ok = 1; |
|
|
|
|
|
|
|
out: |
|
|
|
|
|
|
|
peer->conn_presence = presence; |
|
|
|
|
|
|
|
if (sqlite3_exec(db, "ROLLBACK TO invite_priority; RELEASE invite_priority", NULL, NULL, NULL) != SQLITE_OK) ok = 0; |
|
|
|
|
|
|
|
if (!ok) DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "test invite priority failed: selected=%016llx err=%s", |
|
|
|
|
|
|
|
(unsigned long long)selected, sqlite3_errmsg(db)); |
|
|
|
|
|
|
|
else DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "test invite priority: regular, self-supernode, supernode, unreachable PASS"); |
|
|
|
|
|
|
|
return ok; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int child_main(const char* role, const char* dir, int invalid_key) { |
|
|
|
static int child_main(const char* role, const char* dir, int invalid_key) { |
|
|
|
struct UASYNC* ua = uasync_create(); |
|
|
|
struct UASYNC* ua = uasync_create(); |
|
|
|
if (!ua) { fprintf(stderr, "%s: uasync_create failed\n", role); return 1; } |
|
|
|
if (!ua) { fprintf(stderr, "%s: uasync_create failed\n", role); return 1; } |
|
|
|
@ -477,6 +518,7 @@ static int child_main(const char* role, const char* dir, int invalid_key) { |
|
|
|
if (!g_sh.degraded && !wait_bgp(inst, g_sh.nid[IDX_C], 8000)) { |
|
|
|
if (!g_sh.degraded && !wait_bgp(inst, g_sh.nid[IDX_C], 8000)) { |
|
|
|
fprintf(stderr, "A: no BGP to C\n"); goto out; |
|
|
|
fprintf(stderr, "A: no BGP to C\n"); goto out; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!g_sh.degraded && !check_invite_priority(inst)) goto out; |
|
|
|
|
|
|
|
|
|
|
|
uint64_t target = g_sh.degraded ? g_sh.nid[IDX_A] : g_sh.nid[IDX_C]; |
|
|
|
uint64_t target = g_sh.degraded ? g_sh.nid[IDX_A] : g_sh.nid[IDX_C]; |
|
|
|
struct invite_result result = {0}; |
|
|
|
struct invite_result result = {0}; |
|
|
|
|