- topo_group_invite.c/h: invite/join через DIRECT + INVITE_INFO_REQ/RESP (из conn_mgr) - conn_mgr: conn_mgr_open_invite → conn_mgr_open, убран invite-режим (-480 строк) - topo_group_connect: подключение через node_conn_direct вместо conn_mgr - member_sync: _rebuild_all_trees сносит merkle_tree_hash канала и собирает заново из peers (чистка осиротевших листов) - member_sync: хеш блока A/B (update_sig/adm_tags) в док-комментариях - обновлены doc-файлы и тесты
166 lines
7.3 KiB
C
166 lines
7.3 KiB
C
/**
|
|
* @file test_invite_group_create.c
|
|
* @brief Full invite flow: topo_group_invite_join → B is member → TGI_EVENT_JOIN
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include "../lib/platform_compat.h"
|
|
#include "../lib/mem.h"
|
|
#include "../lib/debug_config.h"
|
|
#include "test_utils.h"
|
|
#ifndef _WIN32
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include "../src/transport_layer/etcp.h"
|
|
#include "../src/transport_layer/etcp_connections.h"
|
|
#include "../src/config_parser.h"
|
|
#include "../src/config_updater.h"
|
|
#include "../src/utun_instance.h"
|
|
#include "../src/routing_layer/topo_group.h"
|
|
#include "../src/routing_layer/topo_node.h"
|
|
#include "../src/routing_layer/topo_node_sqlite.h"
|
|
#include "../src/routing_layer/topo_group_invite.h"
|
|
|
|
#define TIMEOUT_TB 50000
|
|
#define POLL_MS 20
|
|
|
|
static void fail(const char* msg) { fprintf(stderr, "FAIL: %s\n", msg); fflush(stderr); exit(1); }
|
|
|
|
static void wf(const char* path, const char* fmt, ...) {
|
|
va_list ap; va_start(ap, fmt);
|
|
FILE* f = fopen(path, "w");
|
|
if (!f) { fail("fopen"); return; }
|
|
vfprintf(f, fmt, ap); fclose(f);
|
|
va_end(ap);
|
|
}
|
|
|
|
static char* ls(const char* p, const char* k) {
|
|
char b[1024]; FILE* f = fopen(p, "r"); if (!f) return NULL;
|
|
size_t n = fread(b, 1, sizeof(b) - 1, f); fclose(f); b[n] = 0;
|
|
char* x = strstr(b, k); if (!x) return NULL;
|
|
x += strlen(k) + 1; while (*x == ' ' || *x == '\t') x++;
|
|
char* r = u_strdup(x); char* e = r; while (*e && *e != '\n' && *e != '\r') e++; *e = 0;
|
|
return r;
|
|
}
|
|
|
|
static int result = 0;
|
|
|
|
static void ccb(uint64_t nid, uint64_t gid, int ev, void* arg) {
|
|
(void)gid; (void)arg;
|
|
fprintf(stderr, "CB: ev=%d node=0x%llx\n", ev, (unsigned long long)nid); fflush(stderr);
|
|
if (ev == TGI_EVENT_JOIN) result = 1;
|
|
if (ev == TGI_EVENT_TIMEOUT) result = 2;
|
|
}
|
|
|
|
static void to_cb(void* arg) { (void)arg; fprintf(stderr, "TIMEOUT\n"); fflush(stderr); result = 2; }
|
|
|
|
int main(void) {
|
|
debug_config_init();
|
|
debug_set_level(DEBUG_LEVEL_TRACE);
|
|
debug_enable_file_output("/tmp/test_inv_crash.log", 1);
|
|
utun_instance_set_tun_init_enabled(0);
|
|
|
|
char tdir[] = "/tmp/utin_XXXXXX";
|
|
if (test_mkdtemp(tdir) != 0) { fail("mkdtemp"); return 1; }
|
|
char ca[256], cb[256];
|
|
snprintf(ca, sizeof(ca), "%s/a.conf", tdir);
|
|
snprintf(cb, sizeof(cb), "%s/b.conf", tdir);
|
|
int porta = 52000 + (getpid() % 10000), portb = porta + 1;
|
|
|
|
wf(ca, "[global]\ntun_ip=10.94.0.1/24\ntun_ifname=tun89\ndb_path=%s\n[server: s1]\naddr=127.0.0.1:%d\ntype=public\n[allowed_keys]\nallow_all=1\n", tdir, porta);
|
|
wf(cb, "[global]\ntun_ip=10.94.0.2/24\ntun_ifname=tun88\ndb_path=%s\n[server: s1]\naddr=127.0.0.1:%d\ntype=public\n[allowed_keys]\nallow_all=1\n", tdir, portb);
|
|
config_ensure_keys_and_node_id(ca); config_ensure_keys_and_node_id(cb);
|
|
|
|
char* rva = ls(ca, "priv"); char* pua = ls(ca, "pub"); char* pub = ls(cb, "pub");
|
|
wf(ca, "[global]\nmy_private_key=%s\nmy_public_key=%s\ntun_ip=10.94.0.1/24\ntun_ifname=tun89\ndb_path=%s\n[server: s1]\naddr=127.0.0.1:%d\ntype=public\n[client: to_b]\nkeepalive=1\npeer_public_key=%s\nlink=s1:127.0.0.1:%d\n[allowed_keys]\nallow_all=1\n", rva, pua, tdir, porta, pub, portb);
|
|
char* rvb = ls(cb, "priv");
|
|
wf(cb, "[global]\nmy_private_key=%s\nmy_public_key=%s\ntun_ip=10.94.0.2/24\ntun_ifname=tun88\ndb_path=%s\n[server: s1]\naddr=127.0.0.1:%d\ntype=public\n[allowed_keys]\nallow_all=1\n", rvb, pub, tdir, portb);
|
|
u_free(rva); u_free(pua); u_free(pub); u_free(rvb);
|
|
|
|
struct UASYNC* ua = uasync_create();
|
|
struct UTUN_INSTANCE* a = utun_instance_create(ua, ca);
|
|
if (!a) { fail("create A"); goto clean; }
|
|
utun_instance_init(a);
|
|
|
|
/* ── Add a TCP socket (simulating Android STCP server) ── */
|
|
{
|
|
struct ETCP_SOCKET* ts = u_calloc(1, sizeof(*ts));
|
|
ts->instance = a;
|
|
ts->type = CFG_SERVER_TYPE_PUBLIC;
|
|
ts->sock_id = (uint8_t)a->next_socket_id++;
|
|
struct sockaddr_in sin; memset(&sin, 0, sizeof(sin));
|
|
sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
|
|
sin.sin_port = htons((uint16_t)55555);
|
|
memcpy(&ts->local_addr, &sin, sizeof(sin));
|
|
ts->interface_addr = ts->local_addr;
|
|
ts->next = a->etcp_sockets; a->etcp_sockets = ts;
|
|
fprintf(stderr, "Added TCP socket ts=%p next=%p\n", (void*)ts, (void*)ts->next); fflush(stderr);
|
|
}
|
|
fprintf(stderr, "etcp_sockets=%p\n", (void*)a->etcp_sockets); fflush(stderr);
|
|
|
|
/* Get B's node_id and pubkey from its instance */
|
|
struct UTUN_INSTANCE* b = utun_instance_create(ua, cb);
|
|
if (!b) { fail("create B"); a->running = 0; utun_instance_destroy(a); uasync_destroy(ua, 0); goto clean; }
|
|
utun_instance_init(b);
|
|
|
|
/* ── Set up B as member of group 0x7777777700000001 ── */
|
|
{
|
|
uint64_t gid = 0x7777777700000001ULL;
|
|
char ch_str[32]; snprintf(ch_str, sizeof(ch_str), "%llu", (unsigned long long)gid);
|
|
topo_groups_create_group(b->topo_groups, gid, TOPO_GROUP_TYPE_CHAT, ch_str);
|
|
const char* ch_name = "TestCh";
|
|
uint8_t sig_msg[256]; size_t slen = 0;
|
|
/* msg: ch_id\0 || name\0 || owner(8 LE) || x25519_pub(32) || ed_pub(32) */
|
|
size_t ch_id_len = strlen(ch_str) + 1; memcpy(sig_msg + slen, ch_str, ch_id_len); slen += ch_id_len;
|
|
size_t name_len = strlen(ch_name) + 1; memcpy(sig_msg + slen, ch_name, name_len); slen += name_len;
|
|
uint64_t owner = b->node_id; memcpy(sig_msg + slen, &owner, 8); slen += 8;
|
|
memcpy(sig_msg + slen, b->my_keys.public_key, 32); slen += 32;
|
|
memcpy(sig_msg + slen, b->my_ed25519_pubkey, 32); slen += 32;
|
|
uint8_t ch_sig[64];
|
|
sc_ed25519_sign(b->my_ed25519_privkey, sig_msg, slen, ch_sig);
|
|
topo_node_sqlite_channel_put(b->topo_sqlite_db, ch_str, ch_name, owner,
|
|
b->my_keys.public_key, NULL,
|
|
b->my_ed25519_pubkey, NULL, ch_sig);
|
|
fprintf(stderr, "B: channel setup gid=0x%016llX ch=%s name=%s\n",
|
|
(unsigned long long)gid, ch_str, ch_name); fflush(stderr);
|
|
}
|
|
|
|
uint64_t nid_b = b->node_id;
|
|
uint8_t pk_b[32]; memcpy(pk_b, b->my_keys.public_key, 32);
|
|
|
|
/* Build TOPO_NODE for invite */
|
|
struct TOPO_NODE* ni = u_calloc(1, sizeof(*ni));
|
|
ni->node_id = nid_b; memcpy(ni->public_key, pk_b, 32);
|
|
struct TOPO_ADDR4* a4 = u_calloc(1, sizeof(*a4));
|
|
uint8_t ip[4] = {127, 0, 0, 1}; memcpy(a4->addr, ip, 4);
|
|
a4->port = (uint16_t)portb; a4->type = TOPO_ADDR_NAT; a4->protocol = 1;
|
|
ni->v4_addrs = a4;
|
|
|
|
uint64_t gid = 0x7777777700000001ULL;
|
|
fprintf(stderr, "=== topo_group_invite_join gid=0x%016llX nid=0x%016llX ===\n",
|
|
(unsigned long long)gid, (unsigned long long)nid_b); fflush(stderr);
|
|
|
|
int r = topo_group_invite_join(a, gid, ni, nid_b, ccb, NULL);
|
|
fprintf(stderr, "topo_group_invite_join => %d\n", r); fflush(stderr);
|
|
|
|
void* tt = uasync_set_timeout(ua, TIMEOUT_TB, NULL, to_cb, "to");
|
|
int el = 0;
|
|
while (!result && el < TIMEOUT_TB + 5000) { uasync_poll(ua, POLL_MS); el += POLL_MS; }
|
|
if (tt) uasync_cancel_timeout(ua, tt);
|
|
|
|
a->running = 0; utun_instance_destroy(a);
|
|
b->running = 0; utun_instance_destroy(b);
|
|
uasync_destroy(ua, 0);
|
|
u_free(a4); u_free(ni);
|
|
|
|
fprintf(stderr, "=== DONE result=%d ===\n", result); fflush(stderr);
|
|
|
|
clean:
|
|
test_unlink(ca); test_unlink(cb); test_rmdir(tdir);
|
|
debug_disable_file_output();
|
|
return (result == 1) ? 0 : 1;
|
|
}
|