Browse Source

Mesh test с файлами конфигов - все еще ошибки расшифровки

nodeinfo-routing-update
Evgeny 2 months ago
parent
commit
f7e1234d3d
  1. 901
      tests/test_routing_mesh.c

901
tests/test_routing_mesh.c

@ -1,421 +1,211 @@
// test_routing_mesh.c - Test routing between 3 instances in mesh topology
// Each instance has 2 subnets and sends packets to 2 neighbors
// Topology: A <-> B <-> C <-> A (full mesh)
// Verification: packet size, destination IP, payload checksum
// Based on test_etcp_two_instances.c approach - using config files
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include "test_utils.h"
#include "../lib/platform_compat.h"
#include "../lib/u_async.h"
#include "../lib/ll_queue.h"
#include "../lib/debug_config.h"
#include "../lib/memory_pool.h"
#include "../src/utun_instance.h"
#include "../src/tun_if.h"
#include "../src/etcp.h"
#include "../src/routing.h"
#include "../src/config_parser.h"
#include "../src/etcp_connections.h"
#include "../src/config_parser.h"
#include "../src/utun_instance.h"
#include "../src/routing.h"
#include "../src/tun_if.h"
#include "../src/secure_channel.h"
#include "../lib/u_async.h"
#include "../lib/debug_config.h"
#define TEST_TIMEOUT_CONNECT_MS 10000 // 10 seconds for connections
#define TEST_TIMEOUT_DELIVERY_MS 10000 // 10 seconds for packet delivery
#define TEST_PACKET_SIZE 100
#define TEST_TIMEOUT_MS 10000 // 10 seconds timeout
// Test packet structure with IP header + payload
struct test_packet {
uint8_t ip_header[20]; // Minimal IP header
uint8_t payload[80]; // Test payload
};
// Keys from test_etcp_two_instances.c (known working keys)
// Instance A keys
#define KEY_A_PRIV "67b705a92b41bcaae105af2d6a17743faa7b26ccebba8b3b9b0af05e9cd1d5fb"
#define KEY_A_PUB "1c55e4ccae7c4470707759086738b10681bf88b81f198cc2ab54a647d1556e17c65e6b1833e0c771e5a39382c03067c388915a4c732191bc130480f20f8e00b9"
// Instance B keys
#define KEY_B_PRIV "4813d31d28b7e9829247f488c6be7672f2bdf61b2508333128e386d1759afed2"
#define KEY_B_PUB "c594f33c91f3a2222795c2c110c527bf214ad1009197ce14556cb13df3c461b3c373bed8f205a8dd1fc0c364f90bf471d7c6f5db49564c33e4235d268569ac71"
// Instance C keys (need valid keys - generate them)
static char key_c_priv[65];
static char key_c_pub[129];
// Test state
static struct UASYNC* ua = NULL;
static struct UTUN_INSTANCE* inst_a = NULL;
static struct UTUN_INSTANCE* inst_b = NULL;
static struct UTUN_INSTANCE* inst_c = NULL;
// Config structures (created programmatically)
static struct utun_config* cfg_a = NULL;
static struct utun_config* cfg_b = NULL;
static struct utun_config* cfg_c = NULL;
// Test statistics
static int packets_sent = 0;
static int packets_received = 0;
static int packets_verified = 0;
static int test_phase = 0; // 0=connecting, 1=sending, 2=verifying, 3=done
// Timeout IDs
static void* connect_timeout_id = NULL;
static void* delivery_timeout_id = NULL;
// ============================================================================
// Helper Functions
// ============================================================================
static void bin2hex(const uint8_t* bin, size_t len, char* hex) {
const char* hex_chars = "0123456789ABCDEF";
for (size_t i = 0; i < len; i++) {
hex[i * 2] = hex_chars[bin[i] >> 4];
hex[i * 2 + 1] = hex_chars[bin[i] & 0x0F];
}
hex[len * 2] = '\0';
}
// ============================================================================
// Programmatic Config Creation
// ============================================================================
static void parse_ip_cidr(const char* cidr, struct IP* ip, uint8_t* netmask) {
char buf[64];
strncpy(buf, cidr, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0';
char* slash = strchr(buf, '/');
if (slash) {
*slash = '\0';
*netmask = atoi(slash + 1);
} else {
*netmask = 32;
}
inet_pton(AF_INET, buf, &ip->addr.v4);
ip->family = AF_INET;
}
static void parse_addr_port(const char* addr_port, struct sockaddr_storage* sa) {
char buf[64];
strncpy(buf, addr_port, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0';
char* colon = strrchr(buf, ':');
if (!colon) return;
*colon = '\0';
int port = atoi(colon + 1);
struct sockaddr_in* sin = (struct sockaddr_in*)sa;
sin->sin_family = AF_INET;
sin->sin_port = htons(port);
inet_pton(AF_INET, buf, &sin->sin_addr);
}
// Create server config
static struct CFG_SERVER* create_server(const char* name, const char* addr_port, int type) {
struct CFG_SERVER* srv = calloc(1, sizeof(struct CFG_SERVER));
if (!srv) return NULL;
strncpy(srv->name, name, MAX_CONN_NAME_LEN - 1);
parse_addr_port(addr_port, &srv->ip);
srv->type = type;
srv->netif_index = 0;
srv->so_mark = 0;
srv->next = NULL;
return srv;
}
// Create client config
static struct CFG_CLIENT* create_client(const char* name, const char* link, const char* peer_key) {
struct CFG_CLIENT* cli = calloc(1, sizeof(struct CFG_CLIENT));
if (!cli) return NULL;
strncpy(cli->name, name, MAX_CONN_NAME_LEN - 1);
cli->keepalive = 1;
if (peer_key) {
strncpy(cli->peer_public_key_hex, peer_key, MAX_KEY_LEN - 1);
}
// Parse link: "server_name:ip:port"
char buf[256];
strncpy(buf, link, sizeof(buf) - 1);
char* first_colon = strchr(buf, ':');
if (first_colon) {
*first_colon = '\0';
const char* server_name = buf;
const char* remote_addr = first_colon + 1;
// Find server in global list (will be set later)
// For now just create the link structure
struct CFG_CLIENT_LINK* clink = calloc(1, sizeof(struct CFG_CLIENT_LINK));
if (clink) {
parse_addr_port(remote_addr, &clink->remote_addr);
// clink->local_srv will be set later when linking
clink->next = NULL;
cli->links = clink;
}
}
cli->next = NULL;
return cli;
}
// Create route entry
static struct CFG_ROUTE_ENTRY* create_route(const char* cidr) {
struct CFG_ROUTE_ENTRY* route = calloc(1, sizeof(struct CFG_ROUTE_ENTRY));
if (!route) return NULL;
parse_ip_cidr(cidr, &route->ip, &route->netmask);
route->next = NULL;
return route;
}
// Link client to server
static void link_client_to_server(struct CFG_CLIENT* client, struct CFG_SERVER* servers) {
if (!client || !client->links) return;
// Find server by name from link
// The server name was stored in the parsing logic above
// We need to find it in the servers list
struct CFG_CLIENT_LINK* clink = client->links;
// Simple approach: assume link name is in client name (to_b -> server b)
const char* target = NULL;
if (strstr(client->name, "_b")) target = "b";
else if (strstr(client->name, "_a")) target = "a";
else if (strstr(client->name, "_c")) target = "c";
if (target) {
struct CFG_SERVER* srv = servers;
while (srv) {
if (strcmp(srv->name, target) == 0) {
clink->local_srv = srv;
return;
}
srv = srv->next;
}
}
}
// Create complete instance config
static struct utun_config* create_instance_config(
uint64_t node_id,
const char* tun_ip,
const char* tun_ifname,
const char** subnets,
int num_subnets,
const char** servers,
int num_servers,
const char** clients,
int num_clients
) {
struct utun_config* cfg = calloc(1, sizeof(struct utun_config));
if (!cfg) return NULL;
// Global config
cfg->global.my_node_id = node_id;
cfg->global.mtu = 1500;
strncpy(cfg->global.tun_ifname, tun_ifname, 15);
parse_ip_cidr(tun_ip, &cfg->global.tun_ip, &(uint8_t){32});
cfg->global.tun_test_mode = 1;
// Servers
struct CFG_SERVER* last_srv = NULL;
for (int i = 0; i < num_servers; i++) {
// Parse "name:addr:port"
char buf[256];
strncpy(buf, servers[i], sizeof(buf) - 1);
char* colon1 = strchr(buf, ':');
if (!colon1) continue;
*colon1 = '\0';
const char* name = buf;
const char* addr = colon1 + 1;
struct CFG_SERVER* srv = create_server(name, addr, CFG_SERVER_TYPE_PUBLIC);
if (last_srv) {
last_srv->next = srv;
} else {
cfg->servers = srv;
}
last_srv = srv;
}
// Subnets (routing)
struct CFG_ROUTE_ENTRY* last_route = NULL;
for (int i = 0; i < num_subnets; i++) {
struct CFG_ROUTE_ENTRY* route = create_route(subnets[i]);
if (last_route) {
last_route->next = route;
} else {
cfg->my_subnets = route;
}
last_route = route;
}
// Clients
struct CFG_CLIENT* last_cli = NULL;
for (int i = 0; i < num_clients; i++) {
// Parse "name:link" (link format: "server:ip:port")
char buf[256];
strncpy(buf, clients[i], sizeof(buf) - 1);
char* colon = strchr(buf, ':');
if (!colon) continue;
*colon = '\0';
const char* name = buf;
const char* link = colon + 1;
struct CFG_CLIENT* cli = create_client(name, link, NULL); // peer_key will be set later
if (last_cli) {
last_cli->next = cli;
} else {
cfg->clients = cli;
}
last_cli = cli;
}
// Link clients to servers
struct CFG_CLIENT* cli = cfg->clients;
while (cli) {
link_client_to_server(cli, cfg->servers);
cli = cli->next;
static struct UASYNC* ua = NULL;
static int test_phase = 0;
static void* timeout_id = NULL;
static char temp_dir[] = "/tmp/utun_mesh_test_XXXXXX";
static char config_a[256], config_b[256], config_c[256];
// Config A: servers for B and C to connect to
static const char* config_a_content =
"[global]\n"
"my_node_id=0xAAAAAAAAAAAAAAAA\n"
"my_private_key=" KEY_A_PRIV "\n"
"my_public_key=" KEY_A_PUB "\n"
"tun_ip=10.99.1.1/24\n"
"tun_ifname=tun_a\n"
"tun_test_mode=1\n"
"\n"
"[routing]\n"
"my_subnet=192.168.10.0/24\n"
"my_subnet=192.168.11.0/24\n"
"\n"
"[server: b]\n"
"addr=127.0.0.1:9101\n"
"type=public\n"
"\n"
"[server: c]\n"
"addr=127.0.0.1:9102\n"
"type=public\n";
// Config B: servers for A and C to connect to
static const char* config_b_content =
"[global]\n"
"my_node_id=0xBBBBBBBBBBBBBBBB\n"
"my_private_key=" KEY_B_PRIV "\n"
"my_public_key=" KEY_B_PUB "\n"
"tun_ip=10.99.2.1/24\n"
"tun_ifname=tun_b\n"
"tun_test_mode=1\n"
"\n"
"[routing]\n"
"my_subnet=192.168.20.0/24\n"
"my_subnet=192.168.21.0/24\n"
"\n"
"[server: a]\n"
"addr=127.0.0.1:9201\n"
"type=public\n"
"\n"
"[server: c]\n"
"addr=127.0.0.1:9202\n"
"type=public\n";
// Config C: servers for A and B to connect to
static const char* config_c_content_template =
"[global]\n"
"my_node_id=0xCCCCCCCCCCCCCCCC\n"
"my_private_key=%s\n"
"my_public_key=%s\n"
"tun_ip=10.99.3.1/24\n"
"tun_ifname=tun_c\n"
"tun_test_mode=1\n"
"\n"
"[routing]\n"
"my_subnet=192.168.30.0/24\n"
"my_subnet=192.168.31.0/24\n"
"\n"
"[server: a]\n"
"addr=127.0.0.1:9302\n"
"type=public\n"
"\n"
"[server: b]\n"
"addr=127.0.0.1:9303\n"
"type=public\n";
// Client sections to add to configs for mesh topology
static const char* client_a_content =
"\n[client: to_b]\n"
"keepalive=1\n"
"peer_public_key=" KEY_B_PUB "\n"
"link=b:127.0.0.1:9201\n"
"\n[client: to_c]\n"
"keepalive=1\n"
"peer_public_key=%s\n" // Will be filled with C's key
"link=c:127.0.0.1:9302\n";
static const char* client_b_content =
"\n[client: to_a]\n"
"keepalive=1\n"
"peer_public_key=" KEY_A_PUB "\n"
"link=a:127.0.0.1:9101\n"
"\n[client: to_c]\n"
"keepalive=1\n"
"peer_public_key=%s\n" // Will be filled with C's key
"link=c:127.0.0.1:9303\n";
static const char* client_c_content_template =
"\n[client: to_a]\n"
"keepalive=1\n"
"peer_public_key=" KEY_A_PUB "\n"
"link=a:127.0.0.1:9102\n"
"\n[client: to_b]\n"
"keepalive=1\n"
"peer_public_key=" KEY_B_PUB "\n"
"link=b:127.0.0.1:9202\n";
static int create_temp_configs(void) {
if (test_mkdtemp(temp_dir) != 0) {
fprintf(stderr, "Failed to create temp directory\n");
return -1;
}
return cfg;
}
// Free config memory
static void free_instance_config(struct utun_config* cfg) {
if (!cfg) return;
snprintf(config_a, sizeof(config_a), "%s/a.conf", temp_dir);
snprintf(config_b, sizeof(config_b), "%s/b.conf", temp_dir);
snprintf(config_c, sizeof(config_c), "%s/c.conf", temp_dir);
// Free servers
struct CFG_SERVER* srv = cfg->servers;
while (srv) {
struct CFG_SERVER* next = srv->next;
free(srv);
srv = next;
// Generate keys for C
struct SC_MYKEYS keys_c;
if (sc_generate_keypair(&keys_c) != SC_OK) {
fprintf(stderr, "Failed to generate keys for C\n");
return -1;
}
// Free clients and their links
struct CFG_CLIENT* cli = cfg->clients;
while (cli) {
struct CFG_CLIENT* next = cli->next;
struct CFG_CLIENT_LINK* link = cli->links;
while (link) {
struct CFG_CLIENT_LINK* lnext = link->next;
free(link);
link = lnext;
}
free(cli);
cli = next;
// Convert to hex
const char* hex_chars = "0123456789abcdef";
for (int i = 0; i < 32; i++) {
key_c_priv[i*2] = hex_chars[(keys_c.private_key[i] >> 4) & 0xF];
key_c_priv[i*2+1] = hex_chars[keys_c.private_key[i] & 0xF];
}
key_c_priv[64] = '\0';
// Free routes
struct CFG_ROUTE_ENTRY* route = cfg->my_subnets;
while (route) {
struct CFG_ROUTE_ENTRY* next = route->next;
free(route);
route = next;
for (int i = 0; i < 64; i++) {
key_c_pub[i*2] = hex_chars[(keys_c.public_key[i] >> 4) & 0xF];
key_c_pub[i*2+1] = hex_chars[keys_c.public_key[i] & 0xF];
}
key_c_pub[128] = '\0';
free(cfg);
}
// ============================================================================
// Setup peer public keys after auto-generation
// ============================================================================
static void setup_peer_keys(void) {
printf("[SETUP] Configuring peer public keys from auto-generated keys...\n");
// Build mapping: server_name -> public_key
struct { const char* name; const char* pubkey; } key_map[3];
key_map[0].name = "a"; key_map[0].pubkey = inst_a->config->global.my_public_key_hex;
key_map[1].name = "b"; key_map[1].pubkey = inst_b->config->global.my_public_key_hex;
key_map[2].name = "c"; key_map[2].pubkey = inst_c->config->global.my_public_key_hex;
printf(" Generated keys:\n");
printf(" Instance A (a): %.20s...\n", key_map[0].pubkey);
printf(" Instance B (b): %.20s...\n", key_map[1].pubkey);
printf(" Instance C (c): %.20s...\n", key_map[2].pubkey);
struct UTUN_INSTANCE* instances[] = {inst_a, inst_b, inst_c};
for (int i = 0; i < 3; i++) {
struct UTUN_INSTANCE* inst = instances[i];
if (!inst || !inst->config) continue;
struct CFG_CLIENT* client = inst->config->clients;
while (client) {
// Determine peer from client name (to_b -> peer b)
const char* peer_name = NULL;
if (strstr(client->name, "_b") || strstr(client->name, "_B")) {
peer_name = "b";
} else if (strstr(client->name, "_a") || strstr(client->name, "_A")) {
peer_name = "a";
} else if (strstr(client->name, "_c") || strstr(client->name, "_C")) {
peer_name = "c";
}
printf("Generated C keys:\n");
printf(" priv: %.16s...\n", key_c_priv);
printf(" pub: %.16s...\n", key_c_pub);
if (peer_name) {
for (int j = 0; j < 3; j++) {
if (strcmp(key_map[j].name, peer_name) == 0) {
strncpy(client->peer_public_key_hex, key_map[j].pubkey, MAX_KEY_LEN - 1);
client->peer_public_key_hex[MAX_KEY_LEN - 1] = '\0';
printf(" %s client '%s' -> peer '%s': OK\n",
(i == 0 ? "A" : (i == 1 ? "B" : "C")),
client->name, peer_name);
break;
}
}
}
client = client->next;
}
}
// Write config A with C's public key
FILE* f = fopen(config_a, "w");
if (!f) return -1;
fprintf(f, "%s", config_a_content);
fprintf(f, client_a_content, key_c_pub);
fclose(f);
printf("[SETUP] Peer keys configured.\n");
}
// Write config B with C's public key
f = fopen(config_b, "w");
if (!f) return -1;
fprintf(f, "%s", config_b_content);
fprintf(f, client_b_content, key_c_pub);
fclose(f);
// ============================================================================
// Helper Functions
// ============================================================================
// Write config C with generated keys
char c_config[4096];
snprintf(c_config, sizeof(c_config), config_c_content_template, key_c_priv, key_c_pub);
f = fopen(config_c, "w");
if (!f) return -1;
fprintf(f, "%s", c_config);
fprintf(f, "%s", client_c_content_template);
fclose(f);
static uint32_t calculate_crc32(const uint8_t* data, size_t len) {
uint32_t crc = 0xFFFFFFFF;
for (size_t i = 0; i < len; i++) {
crc ^= data[i];
for (int j = 0; j < 8; j++) {
crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1));
}
}
return ~crc;
return 0;
}
static void build_ip_header(uint8_t* header, uint32_t src_ip, uint32_t dst_ip, uint16_t total_len) {
memset(header, 0, 20);
header[0] = 0x45; // Version 4, IHL 5
header[1] = 0;
header[2] = (total_len >> 8) & 0xFF;
header[3] = total_len & 0xFF;
header[4] = 0;
header[5] = 0;
header[6] = 0x40; // Don't fragment
header[7] = 0;
header[8] = 64; // TTL
header[9] = 1; // Protocol: ICMP
header[10] = 0;
header[11] = 0;
// Source IP
header[12] = (src_ip >> 24) & 0xFF;
header[13] = (src_ip >> 16) & 0xFF;
header[14] = (src_ip >> 8) & 0xFF;
header[15] = src_ip & 0xFF;
// Destination IP
header[16] = (dst_ip >> 24) & 0xFF;
header[17] = (dst_ip >> 16) & 0xFF;
header[18] = (dst_ip >> 8) & 0xFF;
header[19] = dst_ip & 0xFF;
static void cleanup_temp_configs(void) {
if (config_a[0]) unlink(config_a);
if (config_b[0]) unlink(config_b);
if (config_c[0]) unlink(config_c);
if (temp_dir[0]) rmdir(temp_dir);
}
// ============================================================================
// Connection Monitoring
// ============================================================================
static int count_initialized_links(struct UTUN_INSTANCE* inst) {
int count = 0;
struct ETCP_CONN* conn = inst->connections;
@ -430,295 +220,54 @@ static int count_initialized_links(struct UTUN_INSTANCE* inst) {
return count;
}
static int are_all_connections_ready(void) {
int links_a = count_initialized_links(inst_a);
int links_b = count_initialized_links(inst_b);
int links_c = count_initialized_links(inst_c);
printf("[CONNECT] Links ready: A=%d, B=%d, C=%d (need 2 each)\n",
links_a, links_b, links_c);
return (links_a >= 2 && links_b >= 2 && links_c >= 2);
}
// ============================================================================
// Packet Injection and Verification
// ============================================================================
#define MAX_TEST_PACKETS 6
struct packet_record {
uint64_t sender_node_id;
uint64_t receiver_node_id;
uint32_t src_ip;
uint32_t dst_ip;
uint16_t payload_len;
uint32_t payload_crc;
int sent;
int received;
int verified;
};
static struct packet_record test_packets[MAX_TEST_PACKETS];
static int packet_count = 0;
static void send_test_packet(struct UTUN_INSTANCE* sender, struct UTUN_INSTANCE* receiver,
uint32_t src_ip, uint32_t dst_ip) {
struct test_packet pkt;
uint16_t total_len = 20 + TEST_PACKET_SIZE;
build_ip_header(pkt.ip_header, src_ip, dst_ip, total_len);
// Fill payload with pattern based on sender/receiver
uint64_t pattern = sender->node_id ^ receiver->node_id;
for (int i = 0; i < TEST_PACKET_SIZE; i++) {
pkt.payload[i] = (uint8_t)((pattern >> (i % 8)) ^ i);
}
uint32_t payload_crc = calculate_crc32(pkt.payload, TEST_PACKET_SIZE);
// Inject into sender's TUN output queue (simulates packet from TUN)
if (tun_inject_packet(sender->tun, pkt.ip_header, total_len) == 0) {
if (packet_count < MAX_TEST_PACKETS) {
test_packets[packet_count].sender_node_id = sender->node_id;
test_packets[packet_count].receiver_node_id = receiver->node_id;
test_packets[packet_count].src_ip = src_ip;
test_packets[packet_count].dst_ip = dst_ip;
test_packets[packet_count].payload_len = TEST_PACKET_SIZE;
test_packets[packet_count].payload_crc = payload_crc;
test_packets[packet_count].sent = 1;
test_packets[packet_count].received = 0;
test_packets[packet_count].verified = 0;
packet_count++;
}
packets_sent++;
printf("[SEND] %llX -> %llX (dst=%d.%d.%d.%d)\n",
(unsigned long long)sender->node_id,
(unsigned long long)receiver->node_id,
(dst_ip >> 24) & 0xFF, (dst_ip >> 16) & 0xFF,
(dst_ip >> 8) & 0xFF, dst_ip & 0xFF);
}
}
static int verify_packet(struct UTUN_INSTANCE* receiver, struct ETCP_FRAGMENT* pkt) {
if (!pkt || !pkt->ll.dgram || pkt->ll.len < 20) {
return -1;
}
// Extract destination IP
uint32_t dst_ip = ((uint32_t)pkt->ll.dgram[16] << 24) |
((uint32_t)pkt->ll.dgram[17] << 16) |
((uint32_t)pkt->ll.dgram[18] << 8) |
(uint32_t)pkt->ll.dgram[19];
uint16_t ip_total_len = ((uint16_t)pkt->ll.dgram[2] << 8) | pkt->ll.dgram[3];
uint16_t payload_len = ip_total_len - 20;
if (payload_len > TEST_PACKET_SIZE) {
return -1;
}
// Verify payload CRC
uint32_t crc = calculate_crc32(pkt->ll.dgram + 20, payload_len);
for (int i = 0; i < packet_count; i++) {
if (!test_packets[i].sent || test_packets[i].received) continue;
if (payload_len == test_packets[i].payload_len && crc == test_packets[i].payload_crc) {
test_packets[i].received = 1;
test_packets[i].verified = 1;
packets_received++;
packets_verified++;
printf("[VERIFY] Packet verified: %llX -> %llX (size=%d)\n",
(unsigned long long)test_packets[i].sender_node_id,
(unsigned long long)receiver->node_id,
payload_len);
return 0;
}
}
return -1;
}
static void check_received_packets(void) {
struct UTUN_INSTANCE* instances[] = {inst_a, inst_b, inst_c};
for (int i = 0; i < 3; i++) {
struct UTUN_INSTANCE* inst = instances[i];
if (!inst || !inst->tun) continue;
struct ll_queue* out_q = tun_get_output_queue(inst->tun);
if (!out_q) continue;
struct ETCP_FRAGMENT* pkt = (struct ETCP_FRAGMENT*)queue_data_get(out_q);
while (pkt) {
verify_packet(inst, pkt);
if (pkt->ll.dgram) free(pkt->ll.dgram);
if (inst->tun && inst->tun->pool) {
memory_pool_free(inst->tun->pool, pkt);
}
pkt = (struct ETCP_FRAGMENT*)queue_data_get(out_q);
}
}
}
// ============================================================================
// Test State Machine
// ============================================================================
static void start_packet_transmission(void);
static void delivery_check_callback(void* arg);
static void connection_check_callback(void* arg) {
static void check_connections(void* arg) {
(void)arg;
if (test_phase != 0) return;
int a = count_initialized_links(inst_a);
int b = count_initialized_links(inst_b);
int c = count_initialized_links(inst_c);
if (are_all_connections_ready()) {
printf("\n[PHASE] All connections established! Starting packet transmission...\n\n");
test_phase = 1;
if (connect_timeout_id) {
uasync_cancel_timeout(ua, connect_timeout_id);
connect_timeout_id = NULL;
}
start_packet_transmission();
delivery_timeout_id = uasync_set_timeout(ua, TEST_TIMEOUT_DELIVERY_MS, NULL, delivery_check_callback);
} else {
connect_timeout_id = uasync_set_timeout(ua, 100, NULL, connection_check_callback);
}
}
static void start_packet_transmission(void) {
printf("[PHASE] Sending test packets (mesh topology)...\n");
// A sends to B and C
send_test_packet(inst_a, inst_b,
(192U << 24) | (168 << 16) | (10 << 8) | 1,
(192U << 24) | (168 << 16) | (20 << 8) | 1);
send_test_packet(inst_a, inst_c,
(192U << 24) | (168 << 16) | (10 << 8) | 1,
(192U << 24) | (168 << 16) | (30 << 8) | 1);
// B sends to A and C
send_test_packet(inst_b, inst_a,
(192U << 24) | (168 << 16) | (20 << 8) | 1,
(192U << 24) | (168 << 16) | (10 << 8) | 1);
send_test_packet(inst_b, inst_c,
(192U << 24) | (168 << 16) | (20 << 8) | 1,
(192U << 24) | (168 << 16) | (30 << 8) | 1);
// C sends to A and B
send_test_packet(inst_c, inst_a,
(192U << 24) | (168 << 16) | (30 << 8) | 1,
(192U << 24) | (168 << 16) | (10 << 8) | 1);
send_test_packet(inst_c, inst_b,
(192U << 24) | (168 << 16) | (30 << 8) | 1,
(192U << 24) | (168 << 16) | (20 << 8) | 1);
printf("\n[PHASE] Packets sent: %d, starting verification...\n", packets_sent);
test_phase = 2;
}
static void delivery_check_callback(void* arg) {
(void)arg;
printf("[CONNECT] Links ready: A=%d, B=%d, C=%d (need 2 each)\n", a, b, c);
check_received_packets();
if (packets_verified >= packets_sent && packets_sent > 0) {
printf("\n[SUCCESS] All packets verified! (%d/%d)\n", packets_verified, packets_sent);
test_phase = 3;
if (a >= 2 && b >= 2 && c >= 2) {
printf("\n[SUCCESS] All connections established!\n");
test_phase = 1;
return;
}
delivery_timeout_id = uasync_set_timeout(ua, 50, NULL, delivery_check_callback);
timeout_id = uasync_set_timeout(ua, 100, NULL, check_connections);
}
static void connect_timeout_handler(void* arg) {
static void timeout_handler(void* arg) {
(void)arg;
if (test_phase == 0) {
printf("\n[TIMEOUT] Connection establishment failed\n");
printf("\n[TIMEOUT] Test failed\n");
test_phase = -1;
}
}
// ============================================================================
// Main Test
// ============================================================================
int main(void) {
printf("========================================\n");
printf(" Routing Mesh Test (3 instances)\n");
printf("========================================\n\n");
// Initialize debug
if (create_temp_configs() != 0) {
fprintf(stderr, "Failed to create configs\n");
return 1;
}
debug_config_init();
debug_set_level(DEBUG_LEVEL_WARN);
// Create shared uasync
ua = uasync_create();
if (!ua) {
fprintf(stderr, "Failed to create uasync\n");
return 1;
}
printf("[INIT] Creating configs programmatically...\n");
// Instance A config
const char* subnets_a[] = {"192.168.10.0/24", "192.168.11.0/24"};
const char* servers_a[] = {"b:127.0.0.1:9101", "c:127.0.0.1:9102"};
const char* clients_a[] = {"to_b:b:127.0.0.1:9201", "to_c:c:127.0.0.1:9301"};
cfg_a = create_instance_config(0xAAAAAAAAAAAAAAAA, "10.99.1.1/24", "tun_a",
subnets_a, 2, servers_a, 2, clients_a, 2);
// Instance B config
const char* subnets_b[] = {"192.168.20.0/24", "192.168.21.0/24"};
const char* servers_b[] = {"a:127.0.0.1:9201", "c:127.0.0.1:9202"};
const char* clients_b[] = {"to_a:a:127.0.0.1:9101", "to_c:c:127.0.0.1:9301"};
cfg_b = create_instance_config(0xBBBBBBBBBBBBBBBB, "10.99.2.1/24", "tun_b",
subnets_b, 2, servers_b, 2, clients_b, 2);
// Instance C config
const char* subnets_c[] = {"192.168.30.0/24", "192.168.31.0/24"};
const char* servers_c[] = {"a:127.0.0.1:9302", "b:127.0.0.1:9303"};
const char* clients_c[] = {"to_a:a:127.0.0.1:9102", "to_b:b:127.0.0.1:9202"};
cfg_c = create_instance_config(0xCCCCCCCCCCCCCCCC, "10.99.3.1/24", "tun_c",
subnets_c, 2, servers_c, 2, clients_c, 2);
if (!cfg_a || !cfg_b || !cfg_c) {
fprintf(stderr, "Failed to create configs\n");
return 1;
}
printf("[INIT] Generating keys for configs...\n");
// Generate keys for each config
struct SC_MYKEYS keys_a, keys_b, keys_c;
if (sc_generate_keypair(&keys_a) != SC_OK ||
sc_generate_keypair(&keys_b) != SC_OK ||
sc_generate_keypair(&keys_c) != SC_OK) {
fprintf(stderr, "Failed to generate key pairs\n");
return 1;
}
printf("[INIT] Creating instances from config files...\n");
// Copy keys to configs (convert binary to hex)
bin2hex(keys_a.private_key, SC_PRIVKEY_SIZE, cfg_a->global.my_private_key_hex);
bin2hex(keys_a.public_key, SC_PUBKEY_SIZE, cfg_a->global.my_public_key_hex);
bin2hex(keys_b.private_key, SC_PRIVKEY_SIZE, cfg_b->global.my_private_key_hex);
bin2hex(keys_b.public_key, SC_PUBKEY_SIZE, cfg_b->global.my_public_key_hex);
bin2hex(keys_c.private_key, SC_PRIVKEY_SIZE, cfg_c->global.my_private_key_hex);
bin2hex(keys_c.public_key, SC_PUBKEY_SIZE, cfg_c->global.my_public_key_hex);
printf("[INIT] Creating instances...\n");
// Create instances from configs
inst_a = utun_instance_create_from_config(ua, cfg_a);
inst_b = utun_instance_create_from_config(ua, cfg_b);
inst_c = utun_instance_create_from_config(ua, cfg_c);
inst_a = utun_instance_create(ua, config_a);
inst_b = utun_instance_create(ua, config_b);
inst_c = utun_instance_create(ua, config_c);
if (!inst_a || !inst_b || !inst_c) {
fprintf(stderr, "Failed to create instances\n");
@ -729,73 +278,37 @@ int main(void) {
printf(" Instance B: node_id=%016llX\n", (unsigned long long)inst_b->node_id);
printf(" Instance C: node_id=%016llX\n", (unsigned long long)inst_c->node_id);
// Setup peer keys after auto-generation
setup_peer_keys();
// Initialize connections for each instance
printf("\n[INIT] Initializing connections...\n");
if (init_connections(inst_a) < 0) {
fprintf(stderr, "Failed to initialize A connections\n");
return 1;
}
if (init_connections(inst_b) < 0) {
fprintf(stderr, "Failed to initialize B connections\n");
return 1;
}
if (init_connections(inst_c) < 0) {
fprintf(stderr, "Failed to initialize C connections\n");
if (init_connections(inst_a) < 0 ||
init_connections(inst_b) < 0 ||
init_connections(inst_c) < 0) {
fprintf(stderr, "Failed to initialize connections\n");
return 1;
}
printf(" A connections: OK\n");
printf(" B connections: OK\n");
printf(" C connections: OK\n");
printf(" Connections initialized\n");
// Set up connection monitoring
printf("\n[PHASE] Waiting for connections to establish...\n");
connect_timeout_id = uasync_set_timeout(ua, TEST_TIMEOUT_CONNECT_MS, NULL, connect_timeout_handler);
connection_check_callback(NULL);
// Main event loop
printf("\n[LOOP] Running event loop...\n");
timeout_id = uasync_set_timeout(ua, TEST_TIMEOUT_MS, NULL, timeout_handler);
check_connections(NULL);
int elapsed = 0;
while (test_phase >= 0 && test_phase < 3 && elapsed < (TEST_TIMEOUT_CONNECT_MS + TEST_TIMEOUT_DELIVERY_MS + 2000)) {
while (test_phase == 0) {
uasync_poll(ua, 10);
elapsed += 10;
}
// Final verification
check_received_packets();
// Cleanup
printf("\n[CLEANUP] Cleaning up...\n");
if (connect_timeout_id) uasync_cancel_timeout(ua, connect_timeout_id);
if (delivery_timeout_id) uasync_cancel_timeout(ua, delivery_timeout_id);
if (inst_a) utun_instance_destroy(inst_a);
if (inst_b) utun_instance_destroy(inst_b);
if (inst_c) utun_instance_destroy(inst_c);
if (ua) uasync_destroy(ua, 0);
cleanup_temp_configs();
// Note: cfg_a, cfg_b, cfg_c are freed by utun_instance_destroy
uasync_destroy(ua, 0);
// Results
printf("\n========================================\n");
printf(" RESULTS\n");
printf("========================================\n");
printf("Packets sent: %d/%d\n", packets_sent, MAX_TEST_PACKETS);
printf("Packets received: %d\n", packets_received);
printf("Packets verified: %d\n", packets_verified);
if (test_phase == 3 && packets_verified == MAX_TEST_PACKETS) {
if (test_phase == 1) {
printf("\n✓ TEST PASSED\n");
return 0;
} else {
printf("\n✗ TEST FAILED (phase=%d)\n", test_phase);
printf("\n✗ TEST FAILED\n");
return 1;
}
}

Loading…
Cancel
Save