fix: memory pool alloc mismatch in tests, db_sync SEND_DATA buffer overflow
- test_etcp_router_reconnect, test_etcp_connect, test_stcp_traffic: replace u_calloc with memory_pool_alloc for TOPO_SOCKMETA4/TOPO_ADDR4 - db_sync.c: fix req[14] -> req[15] — SEND_DATA request header is 15 bytes (type:1 + from:4 + count:2 + vp:4 + want_from:4)
This commit is contained in:
1 parent
fe9be74e29
commit
d310bccf08
52 files changed
+1796
-585
No files matched your search
@@ -0,0 +1,251 @@
|
||||
/**
|
||||
* @file test_node_conn_direct.c
|
||||
* @brief Тест node_conn_direct с 2 инстансами.
|
||||
*
|
||||
* Фазы:
|
||||
* 1 — два open ДО eventloop → NCD_NEW + NCD_REUSED(pending)
|
||||
* 2 — poll → init_cb → NCD_EVENT_UP на обоих
|
||||
* 3 — open на ready conn → NCD_REUSED + async cb
|
||||
* 4 — ещё open → NCD_REUSED
|
||||
* 5 — close h3,h2 → conn жив
|
||||
* 6 — close h1,h0 (last) → conn закрыт (fin_wait → CLOSE → DOWN)
|
||||
* 7 — NCD_ERR unknown node
|
||||
* 8 — inject unreachable → NCD_NEW → TIMEOUT
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "../lib/platform_compat.h"
|
||||
#include "test_utils.h"
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "etcp.h"
|
||||
#include "etcp_connections.h"
|
||||
#include "node_conn_direct.h"
|
||||
#include "../src/config_parser.h"
|
||||
#include "../src/config_updater.h"
|
||||
#include "../src/utun_instance.h"
|
||||
#include "topo_group.h"
|
||||
#include "topo_node.h"
|
||||
#include "secure_channel.h"
|
||||
#include "../lib/u_async.h"
|
||||
#include "../lib/ll_queue.h"
|
||||
#include "../lib/memory_pool.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include "../lib/mem.h"
|
||||
|
||||
#define TIMEOUT_TB 600000
|
||||
#define SHORT_TO_TB 50000
|
||||
#define POLL_MS 5
|
||||
|
||||
static struct UTUN_INSTANCE *g_a = NULL, *g_b = NULL;
|
||||
static struct UASYNC *ua = NULL;
|
||||
static volatile int g_result = 0;
|
||||
static int g_phase = 0;
|
||||
static void *g_ttimer = NULL;
|
||||
|
||||
static char tdir[] = "/tmp/utun_ncd_XXXXXX";
|
||||
static char ca[256], cb[256];
|
||||
static int pa = 0, pb = 0;
|
||||
static uint64_t nid_b = 0;
|
||||
static uint8_t pubkey_b[SC_PUBKEY_SIZE];
|
||||
|
||||
static struct NODE_CONN_DIRECT *gh[4];
|
||||
static volatile int g_up[4], g_down[4], g_tout[4];
|
||||
|
||||
static void ncd_cb(struct NODE_CONN_DIRECT* h, enum ncd_event event, void* arg) {
|
||||
int idx = (int)(intptr_t)arg;
|
||||
if (event == NCD_EVENT_UP) g_up[idx]++;
|
||||
else if (event == NCD_EVENT_DOWN) g_down[idx]++;
|
||||
else if (event == NCD_EVENT_TIMEOUT) g_tout[idx]++;
|
||||
fprintf(stderr, " cb[%d]: event=%d (up=%d down=%d tout=%d)\n", idx, (int)event, g_up[idx], g_down[idx], g_tout[idx]); fflush(stderr);
|
||||
}
|
||||
|
||||
static void to_cb(void* arg) { (void)arg; fprintf(stderr, "GLOBAL TIMEOUT phase=%d\n", g_phase); g_result = 2; }
|
||||
|
||||
static int wf(const char* p, const char* f, ...) { va_list ap; FILE* fp = fopen(p, "w"); if (!fp) return -1; va_start(ap, f); vfprintf(fp, f, ap); va_end(ap); fclose(fp); return 0; }
|
||||
static void fail(const char* msg) { fprintf(stderr, "FAIL[%d]: %s\n", g_phase, msg); fflush(stderr); g_result = 2; }
|
||||
|
||||
static void t1(void* arg); static void t2(void* arg); static void t3(void* arg);
|
||||
static void t4(void* arg); static void t5(void* arg); static void t6(void* arg);
|
||||
static void t7(void* arg); static void t8(void* arg); static void t9(void* arg);
|
||||
static void t_done(void* arg);
|
||||
|
||||
static void t1(void* arg) {
|
||||
(void)arg; g_phase = 1;
|
||||
fprintf(stderr, "\n=== P1: two opens before poll ===\n"); fflush(stderr);
|
||||
g_a->etcp_connect_timeout_tb = TIMEOUT_TB;
|
||||
|
||||
int r = node_conn_direct_open(g_a, nid_b, 0, ncd_cb, (void*)0, &gh[0]);
|
||||
fprintf(stderr, " open#0 → %s\n", r == NCD_NEW ? "NCD_NEW" : r == NCD_REUSED ? "NCD_REUSED" : "ERR");
|
||||
if (r != NCD_NEW) { fail("expected NCD_NEW"); return; }
|
||||
|
||||
r = node_conn_direct_open(g_a, nid_b, 0, ncd_cb, (void*)1, &gh[1]);
|
||||
fprintf(stderr, " open#1 → %s\n", r == NCD_NEW ? "NCD_NEW" : r == NCD_REUSED ? "NCD_REUSED" : "ERR");
|
||||
if (r != NCD_REUSED) { fail("expected NCD_REUSED"); return; }
|
||||
|
||||
uasync_call_soon(ua, NULL, t2);
|
||||
}
|
||||
|
||||
static void t2(void* arg) {
|
||||
(void)arg; g_phase = 2;
|
||||
if (g_up[0] > 0 && g_up[1] > 0) {
|
||||
if (node_conn_direct_get_conn(gh[0]) == NULL) { fail("get_conn h0 NULL"); return; }
|
||||
if (node_conn_direct_get_conn(gh[1]) == NULL) { fail("get_conn h1 NULL"); return; }
|
||||
fprintf(stderr, "\n=== P2: both up, get_conn OK ===\n"); fflush(stderr);
|
||||
uasync_call_soon(ua, NULL, t3); return;
|
||||
}
|
||||
uasync_set_timeout(ua, POLL_MS, NULL, (timeout_callback_t)t2, "t2");
|
||||
}
|
||||
|
||||
static void t3(void* arg) {
|
||||
(void)arg; g_phase = 3;
|
||||
fprintf(stderr, "\n=== P3: open on ready conn ===\n"); fflush(stderr);
|
||||
int r = node_conn_direct_open(g_a, nid_b, 0, ncd_cb, (void*)2, &gh[2]);
|
||||
fprintf(stderr, " open#2 → %s\n", r == NCD_REUSED ? "NCD_REUSED" : "?");
|
||||
if (r != NCD_REUSED) { fail("expected NCD_REUSED"); return; }
|
||||
uasync_call_soon(ua, NULL, t4);
|
||||
}
|
||||
|
||||
static void t4(void* arg) {
|
||||
(void)arg; g_phase = 4;
|
||||
if (g_up[2] == 0) { uasync_set_timeout(ua, POLL_MS, NULL, (timeout_callback_t)t4, "t4"); return; }
|
||||
fprintf(stderr, "\n=== P4: async cb OK, open h3 ===\n"); fflush(stderr);
|
||||
int r = node_conn_direct_open(g_a, nid_b, 0, ncd_cb, (void*)3, &gh[3]);
|
||||
fprintf(stderr, " open#3 → %s\n", r == NCD_REUSED ? "NCD_REUSED" : "?");
|
||||
if (r != NCD_REUSED) { fail("expected NCD_REUSED"); return; }
|
||||
uasync_call_soon(ua, NULL, t5);
|
||||
}
|
||||
|
||||
static void t5(void* arg) {
|
||||
(void)arg; g_phase = 5;
|
||||
if (g_up[3] == 0) { uasync_set_timeout(ua, POLL_MS, NULL, (timeout_callback_t)t5, "t5"); return; }
|
||||
fprintf(stderr, "\n=== P5: close h3, h2 → conn stays ===\n"); fflush(stderr);
|
||||
node_conn_direct_close(gh[3]); gh[3] = NULL;
|
||||
if (node_conn_direct_get_conn(gh[2]) == NULL) { fail("conn died after h3 close"); return; }
|
||||
node_conn_direct_close(gh[2]); gh[2] = NULL;
|
||||
if (node_conn_direct_get_conn(gh[1]) == NULL) { fail("conn died after h2 close"); return; }
|
||||
fprintf(stderr, " OK\n"); fflush(stderr);
|
||||
uasync_call_soon(ua, NULL, t6);
|
||||
}
|
||||
|
||||
static void t6(void* arg) {
|
||||
(void)arg; g_phase = 6;
|
||||
fprintf(stderr, "\n=== P6: close last → conn closed ===\n"); fflush(stderr);
|
||||
node_conn_direct_close(gh[1]); gh[1] = NULL;
|
||||
if (node_conn_direct_get_conn(gh[0]) == NULL) { fail("conn died before last handle"); return; }
|
||||
node_conn_direct_close(gh[0]); gh[0] = NULL;
|
||||
fprintf(stderr, " OK\n"); fflush(stderr);
|
||||
uasync_set_timeout(ua, 200, NULL, (timeout_callback_t)t7, "t6d");
|
||||
}
|
||||
|
||||
static void t7(void* arg) {
|
||||
(void)arg; g_phase = 7;
|
||||
fprintf(stderr, "\n=== P7: NCD_ERR unknown node ===\n"); fflush(stderr);
|
||||
struct NODE_CONN_DIRECT* hx = NULL;
|
||||
int r = node_conn_direct_open(g_a, 0xDEADBEEF00000001ULL, 0, ncd_cb, (void*)99, &hx);
|
||||
fprintf(stderr, " open(unknown) → %s\n", r == NCD_ERR ? "NCD_ERR" : "?");
|
||||
if (r != NCD_ERR) { fail("expected NCD_ERR"); return; }
|
||||
if (hx != NULL) { fail("handle not NULL"); return; }
|
||||
fprintf(stderr, " OK\n"); fflush(stderr);
|
||||
uasync_call_soon(ua, NULL, t8);
|
||||
}
|
||||
|
||||
static void t8(void* arg) {
|
||||
(void)arg; g_phase = 8;
|
||||
fprintf(stderr, "\n=== P8: unreachable node → timeout ===\n"); fflush(stderr);
|
||||
|
||||
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE));
|
||||
if (!ni) { fail("alloc ni"); return; }
|
||||
uint64_t fake_id = 0xF000000000000001ULL;
|
||||
ni->group_ref_count = 0; ni->node_id = fake_id; ni->ver = 0;
|
||||
memcpy(ni->public_key, pubkey_b, SC_PUBKEY_SIZE);
|
||||
|
||||
struct TOPO_SOCKMETA4* sm = memory_pool_alloc(g_a->topo_groups->v4_sock_meta_pool);
|
||||
if (sm) { sm->id = 0; sm->config_type = CFG_SERVER_TYPE_PUBLIC; sm->nat_type = NAT_TYPE_UNKNOWN; sm->next = ni->v4_sock_meta; ni->v4_sock_meta = sm; }
|
||||
|
||||
struct TOPO_ADDR4* addr = memory_pool_alloc(g_a->topo_groups->v4_addr_pool);
|
||||
if (addr) { addr->addr[0]=127; addr->addr[1]=0; addr->addr[2]=0; addr->addr[3]=1; addr->port=1; addr->type=TOPO_ADDR_INTERFACE; addr->socket_id=0; addr->protocol=TOPO_PROTO_UDP; addr->next=ni->v4_addrs; ni->v4_addrs=addr; }
|
||||
|
||||
if (!topo_node_registry_store(g_a->topo_groups, ni)) { fail("registry acquire"); return; }
|
||||
|
||||
memset((void*)g_up, 0, sizeof(g_up));
|
||||
memset((void*)g_tout, 0, sizeof(g_tout));
|
||||
g_a->etcp_connect_timeout_tb = SHORT_TO_TB;
|
||||
|
||||
int r = node_conn_direct_open(g_a, fake_id, 0, ncd_cb, (void*)0, &gh[0]);
|
||||
fprintf(stderr, " open(unreachable) → %s\n", r == NCD_NEW ? "NCD_NEW" : "?");
|
||||
if (r != NCD_NEW) { fail("expected NCD_NEW"); return; }
|
||||
|
||||
uasync_call_soon(ua, NULL, t9);
|
||||
}
|
||||
|
||||
static void t9(void* arg) {
|
||||
(void)arg; g_phase = 9;
|
||||
if (g_tout[0] == 0) { uasync_set_timeout(ua, POLL_MS, NULL, (timeout_callback_t)t9, "t9"); return; }
|
||||
if (g_up[0] > 0) { fail("up fired, expected only timeout"); return; }
|
||||
fprintf(stderr, "\n=== P9: timeout_cb fired, no up ===\n"); fflush(stderr);
|
||||
node_conn_direct_close(gh[0]); gh[0] = NULL;
|
||||
uasync_call_soon(ua, NULL, t_done);
|
||||
}
|
||||
|
||||
static void t_done(void* arg) {
|
||||
(void)arg; g_phase = 99;
|
||||
fprintf(stderr, "\n=== ALL PASSED ===\n"); fflush(stderr);
|
||||
g_result = 1;
|
||||
}
|
||||
|
||||
static int inject_node(struct UTUN_INSTANCE* inst, uint64_t nid, const uint8_t pk[SC_PUBKEY_SIZE], uint16_t port) {
|
||||
if (!inst->topo_groups) return -1;
|
||||
struct TOPO_NODE* ni = u_calloc(1, sizeof(*ni));
|
||||
if (!ni) return -1;
|
||||
ni->group_ref_count = 0; ni->node_id = nid; ni->ver = 0;
|
||||
memcpy(ni->public_key, pk, SC_PUBKEY_SIZE);
|
||||
struct TOPO_SOCKMETA4* sm = memory_pool_alloc(inst->topo_groups->v4_sock_meta_pool);
|
||||
if (sm) { sm->id = 0; sm->config_type = CFG_SERVER_TYPE_PUBLIC; sm->nat_type = NAT_TYPE_UNKNOWN; sm->next = ni->v4_sock_meta; ni->v4_sock_meta = sm; }
|
||||
struct TOPO_ADDR4* addr = memory_pool_alloc(inst->topo_groups->v4_addr_pool);
|
||||
if (addr) { addr->addr[0]=127; addr->addr[1]=0; addr->addr[2]=0; addr->addr[3]=1; addr->port=port; addr->type=TOPO_ADDR_INTERFACE; addr->socket_id=0; addr->protocol=TOPO_PROTO_UDP; addr->next=ni->v4_addrs; ni->v4_addrs=addr; }
|
||||
if (!topo_node_registry_store(inst->topo_groups, ni)) { u_free(ni); return -1; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup(void) {
|
||||
test_mkdtemp(tdir);
|
||||
int base = 49000 + (getpid() % 10000); pa = base; pb = base + 1;
|
||||
snprintf(ca, sizeof(ca), "%s/a.conf", tdir); snprintf(cb, sizeof(cb), "%s/b.conf", tdir);
|
||||
wf(ca, "[global]\ntun_ip=10.97.0.1/24\ntun_ifname=tun95\n[server: s1]\naddr=127.0.0.1:%d\ntype=public\n[allowed_keys]\nallow_all=1\n", pa);
|
||||
wf(cb, "[global]\ntun_ip=10.97.0.2/24\ntun_ifname=tun94\n[server: s1]\naddr=127.0.0.1:%d\ntype=public\n[allowed_keys]\nallow_all=1\n", pb);
|
||||
config_ensure_keys_and_node_id(ca); config_ensure_keys_and_node_id(cb);
|
||||
return 0;
|
||||
}
|
||||
static void cleanup(void) { test_unlink(ca); test_unlink(cb); test_rmdir(tdir); }
|
||||
|
||||
int main(void) {
|
||||
debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN);
|
||||
utun_instance_set_tun_init_enabled(0);
|
||||
if (setup() != 0) return 1;
|
||||
ua = uasync_create();
|
||||
g_a = utun_instance_create(ua, ca); g_b = utun_instance_create(ua, cb);
|
||||
if (!g_a || !g_b) { g_result = 2; goto done; }
|
||||
nid_b = g_b->node_id; memcpy(pubkey_b, g_b->my_keys.public_key, SC_PUBKEY_SIZE);
|
||||
fprintf(stderr, "B: 0x%016llx port=%d\n", (unsigned long long)nid_b, pb); fflush(stderr);
|
||||
utun_instance_init(g_a); utun_instance_init(g_b);
|
||||
if (inject_node(g_a, nid_b, pubkey_b, pb) != 0) { fail("inject_node"); goto done; }
|
||||
fprintf(stderr, "injected B into A registry\n"); fflush(stderr);
|
||||
uasync_call_soon(ua, NULL, t1);
|
||||
g_ttimer = uasync_set_timeout(ua, TIMEOUT_TB, NULL, to_cb, "to");
|
||||
{ uint64_t st = get_time_tb(); while (!g_result && (int)(get_time_tb() - st) < TIMEOUT_TB + 50000) uasync_poll(ua, POLL_MS); }
|
||||
if (g_result == 0) g_result = 2;
|
||||
done:
|
||||
if (g_ttimer && ua) uasync_cancel_timeout(ua, g_ttimer);
|
||||
for (int i = 0; i < 4; i++) if (gh[i]) node_conn_direct_close(gh[i]);
|
||||
if (g_a) { g_a->running = 0; utun_instance_destroy(g_a); }
|
||||
if (g_b) { g_b->running = 0; utun_instance_destroy(g_b); }
|
||||
if (ua) uasync_destroy(ua, 0);
|
||||
cleanup();
|
||||
fprintf(stderr, "\n%s\n", g_result == 1 ? "=== TEST PASSED ===" : "=== TEST FAILED ==="); fflush(stderr);
|
||||
return (g_result == 1) ? 0 : 1;
|
||||
}
|
||||
Reference in new issue
Block a user