diff --git a/tests/Makefile.am b/tests/Makefile.am index d8ba450a..429d01de 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -4,6 +4,9 @@ check_PROGRAMS = test_etcp_crypto$(EXEEXT) \ test_crypto$(EXEEXT) \ test_etcp_two_instances$(EXEEXT) \ + test_etcp_traffic_flow$(EXEEXT) \ + test_etcp_simple_traffic$(EXEEXT) \ + test_etcp_minimal$(EXEEXT) \ test_ll_queue_pos$(EXEEXT) \ test_ll_queue_unified$(EXEEXT) @@ -25,6 +28,21 @@ test_etcp_two_instances_SOURCES = test_etcp_two_instances.c test_etcp_two_instances_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source test_etcp_two_instances_LDADD = $(top_builddir)/src/utun-config_parser.o $(top_builddir)/src/utun-config_updater.o $(top_builddir)/src/utun-crc32.o $(top_builddir)/src/utun-etcp.o $(top_builddir)/src/utun-etcp_connections.o $(top_builddir)/src/utun-etcp_loadbalancer.o $(top_builddir)/src/utun-secure_channel.o $(top_builddir)/src/utun-routing.o $(top_builddir)/src/utun-tun_if.o $(top_builddir)/src/utun-utun_instance.o $(top_builddir)/tinycrypt/lib/source/utun-aes_encrypt.o $(top_builddir)/tinycrypt/lib/source/utun-aes_decrypt.o $(top_builddir)/tinycrypt/lib/source/utun-ccm_mode.o $(top_builddir)/tinycrypt/lib/source/utun-cmac_mode.o $(top_builddir)/tinycrypt/lib/source/utun-ctr_mode.o $(top_builddir)/tinycrypt/lib/source/utun-ecc.o $(top_builddir)/tinycrypt/lib/source/utun-ecc_dh.o $(top_builddir)/tinycrypt/lib/source/utun-ecc_dsa.o $(top_builddir)/tinycrypt/lib/source/utun-sha256.o $(top_builddir)/tinycrypt/lib/source/utun-ecc_platform_specific.o $(top_builddir)/tinycrypt/lib/source/utun-utils.o $(top_builddir)/lib/libuasync.a -lpthread -lcrypto +# ETCP simple traffic test - TUN-less traffic analysis +test_etcp_simple_traffic_SOURCES = test_etcp_simple_traffic.c +test_etcp_simple_traffic_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source +test_etcp_simple_traffic_LDADD = $(top_builddir)/src/utun-config_parser.o $(top_builddir)/src/utun-config_updater.o $(top_builddir)/src/utun-crc32.o $(top_builddir)/src/utun-etcp.o $(top_builddir)/src/utun-etcp_connections.o $(top_builddir)/src/utun-etcp_loadbalancer.o $(top_builddir)/src/utun-secure_channel.o $(top_builddir)/src/utun-routing.o $(top_builddir)/src/utun-tun_if.o $(top_builddir)/src/utun-utun_instance.o $(top_builddir)/tinycrypt/lib/source/utun-aes_encrypt.o $(top_builddir)/tinycrypt/lib/source/utun-aes_decrypt.o $(top_builddir)/tinycrypt/lib/source/utun-ccm_mode.o $(top_builddir)/tinycrypt/lib/source/utun-cmac_mode.o $(top_builddir)/tinycrypt/lib/source/utun-ctr_mode.o $(top_builddir)/tinycrypt/lib/source/utun-ecc.o $(top_builddir)/tinycrypt/lib/source/utun-ecc_dh.o $(top_builddir)/tinycrypt/lib/source/utun-ecc_dsa.o $(top_builddir)/tinycrypt/lib/source/utun-sha256.o $(top_builddir)/tinycrypt/lib/source/utun-ecc_platform_specific.o $(top_builddir)/tinycrypt/lib/source/utun-utils.o $(top_builddir)/lib/libuasync.a -lpthread -lcrypto + +# ETCP minimal test - basic packet analysis +test_etcp_minimal_SOURCES = test_etcp_minimal.c +test_etcp_minimal_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source +test_etcp_minimal_LDADD = $(top_builddir)/src/utun-etcp.o $(top_builddir)/src/utun-etcp_connections.o $(top_builddir)/src/utun-etcp_loadbalancer.o $(top_builddir)/src/utun-secure_channel.o $(top_builddir)/src/utun-crc32.o $(top_builddir)/tinycrypt/lib/source/utun-aes_encrypt.o $(top_builddir)/tinycrypt/lib/source/utun-aes_decrypt.o $(top_builddir)/tinycrypt/lib/source/utun-ccm_mode.o $(top_builddir)/tinycrypt/lib/source/utun-cmac_mode.o $(top_builddir)/tinycrypt/lib/source/utun-ctr_mode.o $(top_builddir)/tinycrypt/lib/source/utun-ecc.o $(top_builddir)/tinycrypt/lib/source/utun-ecc_dh.o $(top_builddir)/tinycrypt/lib/source/utun-ecc_dsa.o $(top_builddir)/tinycrypt/lib/source/utun-sha256.o $(top_builddir)/tinycrypt/lib/source/utun-ecc_platform_specific.o $(top_builddir)/tinycrypt/lib/source/utun-utils.o $(top_builddir)/lib/libuasync.a -lpthread -lcrypto + +# ETCP traffic flow test - TUN-less traffic analysis +test_etcp_traffic_flow_SOURCES = test_etcp_traffic_flow.c +test_etcp_traffic_flow_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source +test_etcp_traffic_flow_LDADD = $(top_builddir)/src/utun-config_parser.o $(top_builddir)/src/utun-config_updater.o $(top_builddir)/src/utun-crc32.o $(top_builddir)/src/utun-etcp.o $(top_builddir)/src/utun-etcp_connections.o $(top_builddir)/src/utun-etcp_loadbalancer.o $(top_builddir)/src/utun-secure_channel.o $(top_builddir)/src/utun-routing.o $(top_builddir)/src/utun-tun_if.o $(top_builddir)/src/utun-utun_instance.o $(top_builddir)/tinycrypt/lib/source/utun-aes_encrypt.o $(top_builddir)/tinycrypt/lib/source/utun-aes_decrypt.o $(top_builddir)/tinycrypt/lib/source/utun-ccm_mode.o $(top_builddir)/tinycrypt/lib/source/utun-cmac_mode.o $(top_builddir)/tinycrypt/lib/source/utun-ctr_mode.o $(top_builddir)/tinycrypt/lib/source/utun-ecc.o $(top_builddir)/tinycrypt/lib/source/utun-ecc_dh.o $(top_builddir)/tinycrypt/lib/source/utun-ecc_dsa.o $(top_builddir)/tinycrypt/lib/source/utun-sha256.o $(top_builddir)/tinycrypt/lib/source/utun-ecc_platform_specific.o $(top_builddir)/tinycrypt/lib/source/utun-utils.o $(top_builddir)/lib/libuasync.a -lpthread -lcrypto + # LL queue position test test_ll_queue_pos_SOURCES = test_ll_queue_pos.c test_ll_queue_pos_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib diff --git a/tests/test_etcp_minimal b/tests/test_etcp_minimal new file mode 100755 index 00000000..10de869c Binary files /dev/null and b/tests/test_etcp_minimal differ diff --git a/tests/test_etcp_minimal.c b/tests/test_etcp_minimal.c new file mode 100644 index 00000000..d7838a46 --- /dev/null +++ b/tests/test_etcp_minimal.c @@ -0,0 +1,208 @@ +// test_etcp_minimal.c - Minimal ETCP traffic debugging test +// This is the most basic test to verify ETCP packet processing works + +#include "../src/etcp.h" +#include "../lib/debug_config.h" +#include +#include +#include + +// Test basic packet analysis +static void test_packet_analysis() { + printf("=== Testing Basic Packet Analysis ===\n"); + + // Simple test packet with one section + uint8_t test_packet[] = { + 0x00, // ETCP_SECTION_PAYLOAD + 0x00, 0x06, // Length: 6 bytes + 0x00, 0x01, // Packet ID: 1 + 0x48, 0x65, 0x6C, 0x6C, 0x6F // "Hello" + }; + + printf("Test packet: "); + for (int i = 0; i < sizeof(test_packet); i++) { + printf("%02X ", test_packet[i]); + } + printf("\n"); + + // Manual section parsing + if (sizeof(test_packet) >= 3) { + uint8_t section_type = test_packet[0]; + uint16_t section_len = (test_packet[1] << 8) | test_packet[2]; + + printf("Section type: 0x%02X\n", section_type); + printf("Section length: %u\n", section_len); + printf("Total packet size: %zu\n", sizeof(test_packet)); + + if (section_type == 0x00) { // PAYLOAD + printf("This is a PAYLOAD section\n"); + if (section_len >= 2 && section_len + 3 <= sizeof(test_packet)) { + uint16_t packet_id = (test_packet[3] << 8) | test_packet[4]; + printf("Packet ID: %u\n", packet_id); + printf("Payload size: %u bytes\n", section_len - 2); + + printf("Payload data: "); + for (int i = 0; i < section_len - 2; i++) { + printf("%02X ", test_packet[5 + i]); + } + printf("\n"); + + printf("Payload as text: "); + for (int i = 0; i < section_len - 2; i++) { + printf("%c", test_packet[5 + i]); + } + printf("\n"); + } + } + } +} + +// Test multiple sections +static void test_multi_section_packet() { + printf("\n=== Testing Multi-Section Packet ===\n"); + + // Packet with TIMESTAMP + ACK + PAYLOAD sections + uint8_t multi_packet[] = { + // TIMESTAMP section + 0x06, 0x00, 0x02, 0x12, 0x34, + // ACK section + 0x01, 0x00, 0x09, 0x02, 0x00, 0x01, 0x56, 0x78, 0x00, 0x02, 0x56, 0x79, + // PAYLOAD section + 0x00, 0x00, 0x08, 0x00, 0x03, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x21 // "Hello!" + }; + + printf("Multi-section packet: "); + for (int i = 0; i < sizeof(multi_packet); i++) { + printf("%02X ", multi_packet[i]); + } + printf("\n"); + + // Parse each section + int pos = 0; + int section_count = 0; + + while (pos < sizeof(multi_packet) - 2) { + if (pos + 3 > sizeof(multi_packet)) break; + + uint8_t section_type = multi_packet[pos]; + uint16_t section_len = (multi_packet[pos+1] << 8) | multi_packet[pos+2]; + + printf("\nSection %d at position %d:\n", section_count, pos); + printf(" Type: 0x%02X ", section_type); + + switch (section_type) { + case 0x00: printf("(PAYLOAD)"); break; + case 0x01: printf("(ACK)"); break; + case 0x06: printf("(TIMESTAMP)"); break; + default: printf("(UNKNOWN)"); break; + } + printf("\n"); + printf(" Length: %u bytes\n", section_len); + + if (pos + 3 + section_len > sizeof(multi_packet)) { + printf(" ERROR: Section extends beyond packet boundary\n"); + break; + } + + // Section-specific analysis + uint8_t* section_data = multi_packet + pos + 3; + + switch (section_type) { + case 0x00: { // PAYLOAD + if (section_len >= 2) { + uint16_t packet_id = (section_data[0] << 8) | section_data[1]; + printf(" Packet ID: %u\n", packet_id); + printf(" Payload: "); + for (int i = 2; i < section_len; i++) { + printf("%c", section_data[i]); + } + printf("\n"); + } + break; + } + case 0x01: { // ACK + if (section_len >= 1) { + uint8_t ack_count = section_data[0]; + printf(" ACK count: %u\n", ack_count); + for (int i = 0; i < ack_count && i*4+5 <= section_len; i++) { + uint16_t ack_id = (section_data[1+i*4] << 8) | section_data[2+i*4]; + uint16_t ack_ts = (section_data[3+i*4] << 8) | section_data[4+i*4]; + printf(" ACK[%d]: id=%u, ts=%u\n", i, ack_id, ack_ts); + } + } + break; + } + case 0x06: { // TIMESTAMP + if (section_len == 2) { + uint16_t ts = (section_data[0] << 8) | section_data[1]; + printf(" Timestamp: %u\n", ts); + } + break; + } + } + + pos += 3 + section_len; + section_count++; + } + + printf("\nTotal sections parsed: %d\n", section_count); +} + +// Test connection establishment packets +static void test_connection_packets() { + printf("\n=== Testing Connection Establishment Packets ===\n"); + + // INIT_REQUEST packet + uint8_t init_request[] = { + ETCP_INIT_REQUEST, // 0x02 + 0x00, 0x14, // 20 bytes + // Node ID + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + // MTU + 0x05, 0xDC, + // Keepalive + 0x00, 0x64, + // Fake public key (8 bytes) + 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22 + }; + + printf("INIT_REQUEST packet:\n"); + printf(" Node ID: 0x"); + for (int i = 0; i < 8; i++) printf("%02X", init_request[3+i]); + printf("\n"); + printf(" MTU: %u\n", (init_request[11] << 8) | init_request[12]); + printf(" Keepalive: %u\n", (init_request[13] << 8) | init_request[14]); + + // INIT_RESPONSE packet + uint8_t init_response[] = { + ETCP_INIT_RESPONSE, // 0x03 + 0x00, 0x0A, // 10 bytes + // Node ID + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + // MTU + 0x05, 0xDC + }; + + printf("\nINIT_RESPONSE packet:\n"); + printf(" Node ID: 0x"); + for (int i = 0; i < 8; i++) printf("%02X", init_response[3+i]); + printf("\n"); + printf(" MTU: %u\n", (init_response[11] << 8) | init_response[12]); +} + +int main() { + printf("=== Minimal ETCP Traffic Flow Debugging ===\n"); + + debug_config_init(); + debug_set_level(DEBUG_LEVEL_DEBUG); + debug_enable_category(DEBUG_CATEGORY_ETCP); + debug_enable_timestamp(1); + debug_enable_function_name(1); + + test_packet_analysis(); + test_multi_section_packet(); + test_connection_packets(); + + printf("\n=== Test completed ===\n"); + return 0; +} \ No newline at end of file diff --git a/tests/test_etcp_simple_traffic b/tests/test_etcp_simple_traffic new file mode 100755 index 00000000..010ec457 Binary files /dev/null and b/tests/test_etcp_simple_traffic differ diff --git a/tests/test_etcp_simple_traffic.c b/tests/test_etcp_simple_traffic.c new file mode 100644 index 00000000..7cc4d653 --- /dev/null +++ b/tests/test_etcp_simple_traffic.c @@ -0,0 +1,491 @@ +// test_etcp_simple_traffic.c - Simplified ETCP traffic flow debugging without sockets +// This test focuses purely on ETCP protocol traffic analysis using direct packet injection + +#include "../src/etcp.h" +#include "../src/etcp_connections.h" +#include "../src/etcp_loadbalancer.h" +#include "../lib/u_async.h" +#include "../lib/debug_config.h" +#include "../lib/memory_pool.h" +#include "../lib/ll_queue.h" +#include "../src/secure_channel.h" +#include "../src/crc32.h" +#include +#include +#include +#include +#include +#include +#include + +// Simplified traffic analysis - focus on ETCP protocol packets only +typedef struct { + uint64_t timestamp; + uint16_t packet_id; + uint8_t packet_type; + uint16_t data_len; + uint8_t data[1500]; // Copy of packet data for analysis +} packet_capture_t; + +typedef struct { + packet_capture_t captures[1000]; + size_t capture_count; + pthread_mutex_t lock; +} traffic_analyzer_t; + +// Test instance - simplified version without actual sockets +typedef struct { + struct UTUN_INSTANCE* instance; + struct ETCP_CONN* etcp_conn; + traffic_analyzer_t* analyzer; + uint64_t node_id; + int is_server; + int running; +} test_instance_t; + +// Global test state +static test_instance_t* server_instance = NULL; +static test_instance_t* client_instance = NULL; + +// Enhanced packet analysis function +static void analyze_etcp_packet(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len, const char* direction) { + if (!etcp || !data || len == 0) { + DEBUG_WARN(DEBUG_CATEGORY_ETCP, "analyze_etcp_packet: invalid parameters (etcp=%p, data=%p, len=%u)", + etcp, data, len); + return; + } + + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "PACKET %s: etcp=%p, len=%u, first_byte=0x%02x", + direction, etcp, len, data[0]); + + // Parse ETCP sections + uint16_t pos = 0; + int section_count = 0; + + while (pos < len) { + if (pos + 3 > len) { + DEBUG_WARN(DEBUG_CATEGORY_ETCP, "Invalid section header at pos %u (need 3 bytes, have %u)", + pos, len - pos); + break; + } + + uint8_t section_type = data[pos]; + uint16_t section_len = (data[pos+1] << 8) | data[pos+2]; + + DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "Section %d: type=0x%02x, len=%u at pos=%u", + section_count, section_type, section_len, pos); + + if (pos + 3 + section_len > len || section_len > 1500) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Section length %u exceeds packet boundary (pos=%u, total=%u) or max size", + section_len, pos, len); + break; + } + + // Analyze specific section types + uint8_t* section_data = data + pos + 3; + + switch (section_type) { + case ETCP_SECTION_PAYLOAD: { + if (section_len >= 2) { + uint16_t packet_id = (section_data[0] << 8) | section_data[1]; + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, " PAYLOAD: packet_id=%u, payload_len=%u", + packet_id, section_len - 2); + } + break; + } + case ETCP_SECTION_ACK: { + if (section_len >= 1) { + uint8_t ack_count = section_data[0]; + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, " ACK: count=%u", ack_count); + for (int i = 0; i < ack_count && i*4+5 <= section_len; i++) { + uint16_t ack_id = (section_data[1+i*4] << 8) | section_data[2+i*4]; + uint16_t ack_ts = (section_data[3+i*4] << 8) | section_data[4+i*4]; + DEBUG_TRACE(DEBUG_CATEGORY_ETCP, " ACK[%d]: id=%u, ts=%u", i, ack_id, ack_ts); + } + } + break; + } + case ETCP_SECTION_TIMESTAMP: { + if (section_len == 2) { + uint16_t ts = (section_data[0] << 8) | section_data[1]; + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, " TIMESTAMP: ts=%u", ts); + } + break; + } + case ETCP_INIT_REQUEST: { + if (section_len >= 76) { // node_id(8) + mtu(2) + keepalive(2) + pubkey(64) + uint64_t node_id = 0; + for (int i = 0; i < 8; i++) { + node_id = (node_id << 8) | section_data[i]; + } + uint16_t mtu = (section_data[8] << 8) | section_data[9]; + uint16_t keepalive = (section_data[10] << 8) | section_data[11]; + DEBUG_INFO(DEBUG_CATEGORY_ETCP, " INIT_REQUEST: node_id=%llu, mtu=%u, keepalive=%u", + (unsigned long long)node_id, mtu, keepalive); + } + break; + } + case ETCP_INIT_RESPONSE: { + if (section_len >= 10) { // node_id(8) + mtu(2) + uint64_t node_id = 0; + for (int i = 0; i < 8; i++) { + node_id = (node_id << 8) | section_data[i]; + } + uint16_t mtu = (section_data[8] << 8) | section_data[9]; + DEBUG_INFO(DEBUG_CATEGORY_ETCP, " INIT_RESPONSE: node_id=%llu, mtu=%u", + (unsigned long long)node_id, mtu); + } + break; + } + default: { + if (section_type >= ETCP_SECTION_RETRANS && section_type <= ETCP_SECTION_RETRANS + 0x1F) { + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, " RETRANS: base_id=%u", section_type - ETCP_SECTION_RETRANS); + // Parse retransmission requests + for (int i = 0; i < section_len; i += 2) { + if (i+1 < section_len) { + uint16_t req_id = (section_data[i] << 8) | section_data[i+1]; + DEBUG_TRACE(DEBUG_CATEGORY_ETCP, " RETRANS_REQ: id=%u", req_id); + } + } + } else { + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, " UNKNOWN: type=0x%02x, len=%u", section_type, section_len); + } + break; + } + } + + pos += 3 + section_len; + section_count++; + } + + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "Packet analysis complete: %d sections processed", section_count); +} + +// Simulate packet reception for analysis +static void simulate_packet_rx(test_instance_t* inst, uint8_t* data, uint16_t len) { + if (!inst || !inst->etcp_conn || !data) return; + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "SIMULATE RX: inst=%s, len=%u", + inst->is_server ? "server" : "client", len); + + // Analyze the packet first + analyze_etcp_packet(inst->etcp_conn, data, len, "SIM_RX"); + + // Create a mock ETCP_DGRAM for processing + struct ETCP_DGRAM mock_dgram; + memset(&mock_dgram, 0, sizeof(mock_dgram)); + mock_dgram.link = NULL; // Will be set by connection processing + mock_dgram.data_len = len > 1500 ? 1500 : len; + mock_dgram.timestamp = get_current_timestamp(); + if (mock_dgram.data_len > 0) { + memcpy(mock_dgram.data, data, mock_dgram.data_len); + } + + // Process through ETCP input + etcp_conn_input(&mock_dgram); +} + +// Simulate packet transmission for analysis +static void simulate_packet_tx(test_instance_t* inst) { + if (!inst || !inst->etcp_conn) return; + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "SIMULATE TX: inst=%s", + inst->is_server ? "server" : "client"); + + struct ETCP_DGRAM* dgram = etcp_request_pkt(inst->etcp_conn); + if (dgram) { + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "Generated packet: len=%u", dgram->data_len); + analyze_etcp_packet(inst->etcp_conn, dgram->data, dgram->data_len, "SIM_TX"); + + // In a real scenario, this would be sent over the network + // For now, we just analyze it and free it + DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "Would send %u bytes to peer", dgram->data_len); + } else { + DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "No packets available to send"); + } +} + +// Create simplified test instance +static test_instance_t* create_simple_instance(uint64_t node_id, int is_server) { + test_instance_t* inst = calloc(1, sizeof(test_instance_t)); + if (!inst) return NULL; + + inst->node_id = node_id; + inst->is_server = is_server; + inst->running = 1; + + // Create traffic analyzer + inst->analyzer = calloc(1, sizeof(traffic_analyzer_t)); + if (inst->analyzer) { + pthread_mutex_init(&inst->analyzer->lock, NULL); + } + + // Create UTUN instance directly without TUN device + inst->instance = calloc(1, sizeof(struct UTUN_INSTANCE)); + if (!inst->instance) { + free(inst->analyzer); + free(inst); + return NULL; + } + + // Initialize the instance manually + inst->instance->node_id = node_id; + inst->instance->running = 1; + inst->instance->log_fp = stderr; + + // Initialize crypto keys (hardcoded for test) + const char* priv_key_hex = "67b705a92b41bcaae105af2d6a17743faa7b26ccebba8b3b9b0af05e9cd1d5fb"; + const char* pub_key_hex = "1c55e4ccae7c4470707759086738b10681bf88b81f198cc2ab54a647d1556e17c65e6b1833e0c771e5a39382c03067c388915a4c732191bc130480f20f8e00b9"; + + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "Parsing crypto keys: priv_len=%zu, pub_len=%zu", + strlen(priv_key_hex), strlen(pub_key_hex)); + + // Parse keys + for (int i = 0; i < 32; i++) { + if (sscanf(&priv_key_hex[i*2], "%2hhx", &inst->instance->my_keys.private_key[i]) != 1) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to parse private key byte %d", i); + } + } + for (int i = 0; i < 64; i++) { + if (sscanf(&pub_key_hex[i*2], "%2hhx", &inst->instance->my_keys.public_key[i]) != 1) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to parse public key byte %d", i); + } + } + + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "Keys parsed successfully"); + + // Create uasync context + inst->instance->ua = uasync_create(); + if (!inst->instance->ua) { + free(inst->instance); + free(inst->analyzer); + free(inst); + return NULL; + } + uasync_init_instance(inst->instance->ua); + + // Create packet pool + inst->instance->pkt_pool = memory_pool_init(1600); // 1600 byte packets + if (!inst->instance->pkt_pool) { + uasync_destroy(inst->instance->ua); + free(inst->instance); + free(inst->analyzer); + free(inst); + return NULL; + } + + // Create ETCP connection + inst->etcp_conn = etcp_connection_create(inst->instance); + if (!inst->etcp_conn) { + memory_pool_destroy(inst->instance->pkt_pool); + uasync_destroy(inst->instance->ua); + free(inst->instance); + free(inst->analyzer); + free(inst); + return NULL; + } + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Created %s instance (node_id=%llu)", + is_server ? "server" : "client", (unsigned long long)node_id); + + return inst; +} + +// Cleanup simplified test instance +static void destroy_simple_instance(test_instance_t* inst) { + if (!inst) return; + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Destroying %s instance", inst->is_server ? "server" : "client"); + + if (inst->etcp_conn) { + etcp_connection_close(inst->etcp_conn); + } + + if (inst->instance) { + if (inst->instance->pkt_pool) { + memory_pool_destroy(inst->instance->pkt_pool); + } + if (inst->instance->ua) { + uasync_destroy(inst->instance->ua); + } + free(inst->instance); + } + + if (inst->analyzer) { + pthread_mutex_destroy(&inst->analyzer->lock); + free(inst->analyzer); + } + + free(inst); +} + +// Generate test packets manually +static void generate_test_packets(test_instance_t* inst, int count) { + if (!inst || !inst->etcp_conn) return; + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Generating %d test packets for %s instance", + count, inst->is_server ? "server" : "client"); + + for (int i = 0; i < count; i++) { + struct ll_entry* entry = queue_entry_new(100); // 100 byte packets + if (entry) { + // Fill with test data + uint8_t* data = (uint8_t*)ll_entry_data(entry); + for (int j = 0; j < 100; j++) { + data[j] = (uint8_t)((i+1) * 10 + j); // Pattern data + } + queue_entry_put(inst->etcp_conn->input_queue, entry); + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "Queued test packet %d for %s", + i+1, inst->is_server ? "server" : "client"); + } + } +} + +// Main test function +int main(int argc, char* argv[]) { + printf("=== ETCP Traffic Flow Debugging Test (Simplified) ===\n"); + + // Initialize debug system + debug_config_init(); + debug_set_level(DEBUG_LEVEL_DEBUG); + debug_enable_category(DEBUG_CATEGORY_ETCP); + debug_enable_timestamp(1); + debug_enable_function_name(1); + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Starting simplified ETCP traffic flow debugging test"); + + // Create server instance + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Creating server instance..."); + server_instance = create_simple_instance(0x1111111111111111ULL, 1); + if (!server_instance) { + fprintf(stderr, "Failed to create server instance\n"); + return 1; + } + + // Create client instance + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Creating client instance..."); + client_instance = create_simple_instance(0x2222222222222222ULL, 0); + if (!client_instance) { + fprintf(stderr, "Failed to create client instance\n"); + destroy_simple_instance(server_instance); + return 1; + } + + // Phase 1: Test basic packet generation and analysis + printf("\n=== Phase 1: Basic Packet Generation ===\n"); + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Generating test packets..."); + generate_test_packets(server_instance, 5); + generate_test_packets(client_instance, 5); + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Simulating packet transmission..."); + + // Let server generate some packets + for (int i = 0; i < 3; i++) { + simulate_packet_tx(server_instance); + usleep(10000); // 1ms delay + } + + // Let client generate some packets + for (int i = 0; i < 3; i++) { + simulate_packet_tx(client_instance); + usleep(10000); // 1ms delay + } + + // Phase 2: Test connection establishment simulation + printf("\n=== Phase 2: Connection Establishment Simulation ===\n"); + + // Simulate INIT_REQUEST from client - smaller version for testing + uint8_t init_request[] = { + ETCP_INIT_REQUEST, // Section type + 0x00, 0x14, // Section length (20 bytes) - smaller for test + // Node ID (8 bytes) + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + // MTU (2 bytes) + 0x05, 0xDC, // 1500 + // Keepalive (2 bytes) + 0x00, 0x64, // 100 + // Fake public key (8 bytes) - just for testing + 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22 + }; + // Total: 3 + 20 = 23 bytes + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Simulating INIT_REQUEST from client..."); + simulate_packet_rx(server_instance, init_request, sizeof(init_request)); + + // Simulate INIT_RESPONSE from server + uint8_t init_response[] = { + ETCP_INIT_RESPONSE, // Section type + 0x00, 0x0A, // Section length (10 bytes) + // Node ID (8 bytes) + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + // MTU (2 bytes) + 0x05, 0xDC // 1500 + }; + // Total: 3 + 10 = 13 bytes + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Simulating INIT_RESPONSE from server..."); + simulate_packet_rx(client_instance, init_response, sizeof(init_response)); + + // Phase 3: Test mixed traffic with ACKs and timestamps + printf("\n=== Phase 3: Mixed Traffic Simulation ===\n"); + + // Generate more traffic + generate_test_packets(server_instance, 3); + generate_test_packets(client_instance, 3); + + // Simulate some packets with multiple sections + uint8_t complex_packet[] = { + // TIMESTAMP section: 3 bytes header + 2 bytes data = 5 bytes + ETCP_SECTION_TIMESTAMP, 0x00, 0x02, 0x12, 0x34, + // ACK section with 2 ACKs: 3 bytes header + 1 byte count + 2*4 bytes = 12 bytes total + ETCP_SECTION_ACK, 0x00, 0x09, 0x02, 0x00, 0x01, 0x12, 0x34, 0x00, 0x02, 0x12, 0x35, + // PAYLOAD section: 3 bytes header + 2 bytes ID + 5 bytes data = 10 bytes total + ETCP_SECTION_PAYLOAD, 0x00, 0x08, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F // "Hello" + }; + // Total: 5 + 12 + 10 = 27 bytes + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Simulating complex packet with multiple sections..."); + simulate_packet_rx(server_instance, complex_packet, sizeof(complex_packet)); + + // Phase 4: Test retransmission requests + printf("\n=== Phase 4: Retransmission Testing ===\n"); + + uint8_t retrans_request[] = { + ETCP_SECTION_RETRANS + 0x02, // RETRANS section with base ID 2 + 0x00, 0x04, // Section length (4 bytes) + 0x00, 0x03, // Request retransmission of packet ID 3 + 0x00, 0x04 // Request retransmission of packet ID 4 + }; + // Total: 3 + 4 = 7 bytes + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Simulating retransmission request..."); + simulate_packet_rx(client_instance, retrans_request, sizeof(retrans_request)); + + // Final packet generation + printf("\n=== Final Phase: Additional Traffic ===\n"); + + // Generate final packets + for (int i = 0; i < 5; i++) { + simulate_packet_tx(server_instance); + simulate_packet_tx(client_instance); + usleep(5000); // 0.5ms delay + } + + // Print summary + printf("\n=== Traffic Analysis Summary ===\n"); + printf("Server instance: processed packets with detailed section analysis\n"); + printf("Client instance: processed packets with detailed section analysis\n"); + printf("Connection establishment: INIT handshake simulated\n"); + printf("Mixed traffic: ACK, TIMESTAMP, PAYLOAD sections processed\n"); + printf("Retransmission: RETRANS requests processed\n"); + + // Cleanup + destroy_simple_instance(server_instance); + destroy_simple_instance(client_instance); + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Test completed"); + printf("\n=== Test completed successfully ===\n"); + + return 0; +} \ No newline at end of file diff --git a/tests/test_etcp_traffic_flow b/tests/test_etcp_traffic_flow new file mode 100755 index 00000000..b4167bac Binary files /dev/null and b/tests/test_etcp_traffic_flow differ diff --git a/tests/test_etcp_traffic_flow.c b/tests/test_etcp_traffic_flow.c new file mode 100644 index 00000000..4c6dfcee --- /dev/null +++ b/tests/test_etcp_traffic_flow.c @@ -0,0 +1,544 @@ +// test_etcp_traffic_flow.c - TUN-less ETCP traffic flow debugging test +// This test bypasses TUN devices to focus on ETCP protocol traffic analysis + +#include "../src/etcp.h" +#include "../src/etcp_connections.h" +#include "../src/etcp_loadbalancer.h" +#include "../lib/u_async.h" +#include "../lib/debug_config.h" +#include "../lib/memory_pool.h" +#include "../lib/ll_queue.h" +#include "../src/secure_channel.h" +#include "../src/crc32.h" +#include "../src/config_parser.h" +#include "../src/utun_instance.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Traffic analysis structures +typedef struct { + uint64_t timestamp; + uint16_t packet_id; + uint8_t packet_type; + uint16_t src_port; + uint16_t dst_port; + uint16_t data_len; + uint8_t* data_copy; // Copy of packet data for analysis +} packet_capture_t; + +typedef struct { + packet_capture_t* captures; + size_t max_captures; + size_t capture_count; + pthread_mutex_t lock; +} traffic_analyzer_t; + +// Test instance configuration +typedef struct { + struct UTUN_INSTANCE* instance; + struct ETCP_CONN* etcp_conn; + struct ETCP_SOCKET* socket; + traffic_analyzer_t* analyzer; + uint16_t listen_port; + uint16_t peer_port; + uint64_t node_id; + int is_server; + pthread_t thread; + int running; +} test_instance_t; + +// Global test state +static test_instance_t* server_instance = NULL; +static test_instance_t* client_instance = NULL; +static int test_completed = 0; +static int connection_established = 0; + +// Traffic capture function +static void capture_packet(test_instance_t* inst, struct ETCP_DGRAM* dgram, const char* direction) { + if (!inst->analyzer || !dgram) return; + + pthread_mutex_lock(&inst->analyzer->lock); + + if (inst->analyzer->capture_count < inst->analyzer->max_captures) { + packet_capture_t* cap = &inst->analyzer->captures[inst->analyzer->capture_count++]; + cap->timestamp = get_current_timestamp() * 10; // Convert to 0.1ms units + cap->data_len = dgram->data_len; + cap->src_port = inst->listen_port; + cap->dst_port = inst->peer_port; + + // Copy packet data for analysis + if (dgram->data_len > 0 && dgram->data_len <= 1500) { + cap->data_copy = malloc(dgram->data_len); + if (cap->data_copy) { + memcpy(cap->data_copy, dgram->data, dgram->data_len); + } + } + + // Analyze packet type from first byte + if (dgram->data_len > 0) { + cap->packet_type = dgram->data[0]; + + // Try to extract packet ID if it's a payload packet + if (dgram->data_len >= 5 && dgram->data[0] == 0x00) { // ETCP_SECTION_PAYLOAD + cap->packet_id = (dgram->data[3] << 8) | dgram->data[4]; + } else { + cap->packet_id = 0xFFFF; // Not a payload packet + } + } + + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "CAPTURE %s: inst=%p type=0x%02x id=%u len=%u ts=%llu", + direction, inst, cap->packet_type, cap->packet_id, cap->data_len, + (unsigned long long)cap->timestamp); + } + + pthread_mutex_unlock(&inst->analyzer->lock); +} + +// Enhanced packet input function with traffic analysis +static void test_etcp_input_with_capture(struct ETCP_DGRAM* dgram) { + if (!dgram || !dgram->link || !dgram->link->etcp) return; + + test_instance_t* inst = NULL; + + // Determine which instance this packet belongs to + if (server_instance && dgram->link->etcp == server_instance->etcp_conn) { + inst = server_instance; + } else if (client_instance && dgram->link->etcp == client_instance->etcp_conn) { + inst = client_instance; + } + + if (inst) { + capture_packet(inst, dgram, "RX"); + } + + // Call original ETCP input function + etcp_conn_input(dgram); +} + +// Enhanced packet request function with traffic analysis +static struct ETCP_DGRAM* test_etcp_request_with_capture(struct ETCP_CONN* etcp) { + struct ETCP_DGRAM* dgram = etcp_request_pkt(etcp); + + if (dgram) { + test_instance_t* inst = NULL; + + // Determine which instance this packet belongs to + if (server_instance && etcp == server_instance->etcp_conn) { + inst = server_instance; + } else if (client_instance && etcp == client_instance->etcp_conn) { + inst = client_instance; + } + + if (inst) { + capture_packet(inst, dgram, "TX"); + } + } + + return dgram; +} + +// Traffic analysis report +static void print_traffic_analysis(test_instance_t* inst, const char* role) { + if (!inst || !inst->analyzer) return; + + pthread_mutex_lock(&inst->analyzer->lock); + + printf("\n=== %s Instance Traffic Analysis ===\n", role); + printf("Total packets captured: %zu\n", inst->analyzer->capture_count); + + // Count by packet type + int payload_count = 0; + int ack_count = 0; + int retrans_count = 0; + int timestamp_count = 0; + int init_count = 0; + int other_count = 0; + + for (size_t i = 0; i < inst->analyzer->capture_count; i++) { + packet_capture_t* cap = &inst->analyzer->captures[i]; + + switch (cap->packet_type) { + case 0x00: payload_count++; break; // ETCP_SECTION_PAYLOAD + case 0x01: ack_count++; break; // ETCP_SECTION_ACK + case 0x02: init_count++; break; // ETCP_INIT_REQUEST + case 0x03: init_count++; break; // ETCP_INIT_RESPONSE + case 0x04: init_count++; break; // ETCP_CHANNEL_INIT + case 0x05: init_count++; break; // ETCP_CHANNEL_RESPONSE + case 0x06: timestamp_count++; break; // ETCP_SECTION_TIMESTAMP + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F: + retrans_count++; break; // ETCP_SECTION_RETRANS variants + default: other_count++; break; + } + } + + printf("Packet breakdown:\n"); + printf(" Payload packets: %d\n", payload_count); + printf(" ACK packets: %d\n", ack_count); + printf(" Retransmission requests: %d\n", retrans_count); + printf(" Timestamp packets: %d\n", timestamp_count); + printf(" Initialization packets: %d\n", init_count); + printf(" Other packets: %d\n", other_count); + + // Show packet ID analysis for payload packets + printf("\nPayload packet IDs:\n"); + int last_id = -1; + int gap_count = 0; + + for (size_t i = 0; i < inst->analyzer->capture_count; i++) { + packet_capture_t* cap = &inst->analyzer->captures[i]; + if (cap->packet_type == 0x00 && cap->packet_id != 0xFFFF) { + printf(" ID: %u, Len: %u bytes\n", cap->packet_id, cap->data_len); + + if (last_id != -1 && cap->packet_id != last_id + 1) { + gap_count++; + } + last_id = cap->packet_id; + } + } + + if (gap_count > 0) { + printf(" WARNING: Found %d gaps in packet ID sequence!\n", gap_count); + } + + // Show timing analysis + if (inst->analyzer->capture_count > 1) { + uint64_t first_ts = inst->analyzer->captures[0].timestamp; + uint64_t last_ts = inst->analyzer->captures[inst->analyzer->capture_count-1].timestamp; + uint64_t duration = (last_ts > first_ts) ? (last_ts - first_ts) : 1; + + printf("\nTiming analysis:\n"); + printf(" Test duration: %llu time units (0.1ms each)\n", (unsigned long long)duration); + printf(" Average packet rate: %.2f packets/time unit\n", + (double)inst->analyzer->capture_count / (double)duration); + } + + pthread_mutex_unlock(&inst->analyzer->lock); +} + +// Test instance thread function +static void* test_instance_thread(void* arg) { + test_instance_t* inst = (test_instance_t*)arg; + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Starting %s instance thread (port %u)", + inst->is_server ? "server" : "client", inst->listen_port); + + // Main event loop + while (inst->running) { + uasync_poll(inst->instance->ua, 10); // 10 time units timeout + + // Process any pending ETCP packets + if (inst->etcp_conn) { + struct ETCP_DGRAM* dgram = test_etcp_request_with_capture(inst->etcp_conn); + if (dgram) { + // Send the packet through the socket + if (inst->socket && inst->socket->fd >= 0) { + struct sockaddr_in peer_addr; + memset(&peer_addr, 0, sizeof(peer_addr)); + peer_addr.sin_family = AF_INET; + peer_addr.sin_port = htons(inst->peer_port); + peer_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + + // Note: In real implementation, this would send through etcp_encrypt_send + DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "Would send packet to peer port %u (len=%u)", + inst->peer_port, dgram->data_len); + } + } + } + } + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "%s instance thread exiting", inst->is_server ? "server" : "client"); + return NULL; +} + +// Create test instance +static test_instance_t* create_test_instance(uint16_t listen_port, uint16_t peer_port, + uint64_t node_id, int is_server) { + test_instance_t* inst = calloc(1, sizeof(test_instance_t)); + if (!inst) return NULL; + + inst->listen_port = listen_port; + inst->peer_port = peer_port; + inst->node_id = node_id; + inst->is_server = is_server; + inst->running = 1; + + // Create traffic analyzer + inst->analyzer = calloc(1, sizeof(traffic_analyzer_t)); + if (inst->analyzer) { + inst->analyzer->max_captures = 1000; + inst->analyzer->captures = calloc(inst->analyzer->max_captures, sizeof(packet_capture_t)); + pthread_mutex_init(&inst->analyzer->lock, NULL); + } + + // Create UTUN instance directly without config file + inst->instance = calloc(1, sizeof(struct UTUN_INSTANCE)); + if (!inst->instance) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to allocate UTUN instance"); + free(inst->analyzer); + free(inst); + return NULL; + } + + // Initialize the instance manually + inst->instance->node_id = node_id; + inst->instance->running = 1; + inst->instance->log_fp = stderr; + + // Initialize crypto keys + const char* priv_key_hex = "67b705a92b41bcaae105af2d6a17743faa7b26ccebba8b3b9b0af05e9cd1d5fb"; + const char* pub_key_hex = "1c55e4ccae7c4470707759086738b10681bf88b81f198cc2ab54a647d1556e17c65e6b1833e0c771e5a39382c03067c388915a4c732191bc130480f20f8e00b9"; + + // Parse keys + for (int i = 0; i < 32; i++) { + sscanf(&priv_key_hex[i*2], "%2hhx", &inst->instance->my_keys.private_key[i]); + } + for (int i = 0; i < 64; i++) { + sscanf(&pub_key_hex[i*2], "%2hhx", &inst->instance->my_keys.public_key[i]); + } + + // Create uasync context + inst->instance->ua = uasync_create(); + if (!inst->instance->ua) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create uasync context"); + free(inst->instance); + free(inst->analyzer); + free(inst); + return NULL; + } + + // Initialize uasync instance + uasync_init_instance(inst->instance->ua); + + // Create packet pool + inst->instance->pkt_pool = memory_pool_init(1600); // 1600 byte packets + if (!inst->instance->pkt_pool) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create packet pool"); + uasync_destroy(inst->instance->ua); + free(inst->instance); + free(inst->analyzer); + free(inst); + return NULL; + } + if (!inst->instance) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create UTUN instance"); + free(inst->analyzer); + free(inst); + return NULL; + } + + // Create ETCP connection + inst->etcp_conn = etcp_connection_create(inst->instance); + if (!inst->etcp_conn) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create ETCP connection"); + utun_instance_destroy(inst->instance); + free(inst->analyzer); + free(inst); + return NULL; + } + + // Create ETCP socket (UDP socket for traffic) + int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (sock_fd < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create UDP socket"); + etcp_connection_close(inst->etcp_conn); + utun_instance_destroy(inst->instance); + free(inst->analyzer); + free(inst); + return NULL; + } + + struct sockaddr_in local_addr; + memset(&local_addr, 0, sizeof(local_addr)); + local_addr.sin_family = AF_INET; + local_addr.sin_port = htons(listen_port); + local_addr.sin_addr.s_addr = INADDR_ANY; + + if (bind(sock_fd, (struct sockaddr*)&local_addr, sizeof(local_addr)) < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to bind UDP socket to port %u", listen_port); + close(sock_fd); + etcp_connection_close(inst->etcp_conn); + utun_instance_destroy(inst->instance); + free(inst->analyzer); + free(inst); + return NULL; + } + + // Create socket structure + inst->socket = etcp_socket_add(inst->instance, (struct sockaddr_storage*)&local_addr, 0, 0, 0); + if (!inst->socket) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create ETCP socket"); + close(sock_fd); + etcp_connection_close(inst->etcp_conn); + utun_instance_destroy(inst->instance); + free(inst->analyzer); + free(inst); + return NULL; + } + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Created %s instance (listen=%u, peer=%u, node_id=%llu)", + is_server ? "server" : "client", listen_port, peer_port, + (unsigned long long)node_id); + + return inst; +} + +// Cleanup test instance +static void destroy_test_instance(test_instance_t* inst) { + if (!inst) return; + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Destroying %s instance", inst->is_server ? "server" : "client"); + + inst->running = 0; + + if (inst->thread) { + pthread_join(inst->thread, NULL); + } + + if (inst->etcp_conn) { + etcp_connection_close(inst->etcp_conn); + } + + if (inst->instance) { + if (inst->instance->pkt_pool) { + // Memory pool will be cleaned up with instance + } + if (inst->instance->ua) { + uasync_destroy(inst->instance->ua); + } + free(inst->instance); + } + + if (inst->analyzer) { + // Free captured packet data + for (size_t i = 0; i < inst->analyzer->capture_count; i++) { + if (inst->analyzer->captures[i].data_copy) { + free(inst->analyzer->captures[i].data_copy); + } + } + free(inst->analyzer->captures); + pthread_mutex_destroy(&inst->analyzer->lock); + free(inst->analyzer); + } + + free(inst); +} + +// Main test function +int main(int argc, char* argv[]) { + printf("=== ETCP Traffic Flow Debugging Test ===\n"); + + // Initialize debug system + debug_config_init(); + debug_set_level(DEBUG_LEVEL_DEBUG); + debug_enable_category(DEBUG_CATEGORY_ETCP); + debug_enable_timestamp(1); + debug_enable_function_name(1); + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Starting ETCP traffic flow debugging test"); + + // Create server instance - use dynamic high ports to avoid conflicts + uint16_t server_port = 30000 + (getpid() % 1000); // Dynamic port based on PID + uint16_t client_port = server_port + 1; + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Creating server instance on port %u...", server_port); + server_instance = create_test_instance(server_port, client_port, 0x1111111111111111ULL, 1); + if (!server_instance) { + fprintf(stderr, "Failed to create server instance on port %u\n", server_port); + return 1; + } + + // Create client instance + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Creating client instance on port %u...", client_port); + client_instance = create_test_instance(client_port, server_port, 0x2222222222222222ULL, 0); + if (!client_instance) { + fprintf(stderr, "Failed to create client instance\n"); + destroy_test_instance(server_instance); + return 1; + } + + // Start instance threads + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Starting instance threads..."); + pthread_create(&server_instance->thread, NULL, test_instance_thread, server_instance); + pthread_create(&client_instance->thread, NULL, test_instance_thread, client_instance); + + // Let instances run for a bit to establish connection + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Running test for 5 seconds..."); + sleep(5); + + // Initiate connection from client + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Initiating connection from client..."); + + // Create initial connection request + struct ETCP_LINK* client_link = etcp_link_new(client_instance->etcp_conn, client_instance->socket, + (struct sockaddr_storage*)&(struct sockaddr_in){ + .sin_family = AF_INET, + .sin_port = htons(9001), + .sin_addr.s_addr = inet_addr("127.0.0.1") + }, 0); + if (client_link) { + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Client link created successfully"); + + // Send initial packet to trigger connection + struct ETCP_DGRAM* init_dgram = test_etcp_request_with_capture(client_instance->etcp_conn); + if (init_dgram) { + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Initial connection packet requested"); + } + } + + // Run for another 5 seconds to see traffic flow + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Continuing test for 5 more seconds..."); + sleep(5); + + // Generate some test traffic + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Generating test traffic..."); + + // Create test packets and queue them + for (int i = 0; i < 10; i++) { + if (client_instance->etcp_conn) { + struct ll_entry* entry = queue_entry_new(100); // 100 byte packets + if (entry) { + // Fill with test data + uint8_t* data = (uint8_t*)ll_entry_data(entry); + for (int j = 0; j < 100; j++) { + data[j] = (uint8_t)(i * 10 + j); // Pattern data + } + queue_entry_put(client_instance->etcp_conn->input_queue, entry); + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "Queued test packet %d", i); + } + } + } + + // Run for final 5 seconds + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Final test phase - 5 seconds..."); + sleep(5); + + // Stop instances + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Stopping test instances..."); + server_instance->running = 0; + client_instance->running = 0; + + // Wait for threads to finish + pthread_join(server_instance->thread, NULL); + pthread_join(client_instance->thread, NULL); + + // Print traffic analysis + print_traffic_analysis(server_instance, "Server"); + print_traffic_analysis(client_instance, "Client"); + + // Cleanup + destroy_test_instance(server_instance); + destroy_test_instance(client_instance); + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Test completed"); + printf("\n=== Test completed ===\n"); + + return 0; +} \ No newline at end of file