// tests/test_etcp_connections_send.c - Test ETCP connections send/encrypt functions #include "etcp_connections.h" #include "etcp.h" #include "secure_channel.h" #include "memory_pool.h" #include "ll_queue.h" #include "crc32.h" #include #include #include #include #include void packet_pool_free(struct memory_pool* pool, void* ptr); // Forward declarations #include #include #include #include #include #define TEST_PORT 6001 #define TEST_MESSAGE "Hello ETCP Connection!" typedef struct { struct UTUN_INSTANCE* instance; struct ETCP_SOCKET* socket; struct ETCP_CONN* conn; int udp_fd; } test_context_t; // Helper: Create minimal UTUN instance test_context_t* create_test_context(void) { test_context_t* ctx = calloc(1, sizeof(test_context_t)); assert(ctx); // Create instance ctx->instance = calloc(1, sizeof(struct UTUN_INSTANCE)); assert(ctx->instance); // Create ETCP connection ctx->conn = etcp_connection_create(ctx->instance); assert(ctx->conn); // Create UDP socket ctx->udp_fd = socket(AF_INET, SOCK_DGRAM, 0); assert(ctx->udp_fd >= 0); // Bind to test port struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(TEST_PORT); addr.sin_addr.s_addr = INADDR_ANY; int ret = bind(ctx->udp_fd, (struct sockaddr*)&addr, sizeof(addr)); assert(ret == 0); // Create ETCP socket wrapper ctx->socket = calloc(1, sizeof(struct ETCP_SOCKET)); assert(ctx->socket); ctx->socket->instance = ctx->instance; ctx->socket->fd = ctx->udp_fd; memcpy(&ctx->socket->local_addr, &addr, sizeof(addr)); ctx->socket->max_channels = 8; ctx->socket->links = calloc(ctx->socket->max_channels, sizeof(struct ETCP_LINK*)); assert(ctx->socket->links); // Add to instance ctx->socket->next = ctx->instance->etcp_sockets; ctx->instance->etcp_sockets = ctx->socket; printf(" ✓ Test context created\n"); return ctx; } // Helper: Cleanup context void destroy_test_context(test_context_t* ctx) { if (!ctx) return; close(ctx->udp_fd); etcp_destroy(ctx->conn); free(ctx->socket->links); free(ctx->socket); free(ctx->instance); free(ctx); printf(" ✓ Test context destroyed\n"); } // Test 1: etcp_socket_add static int test_socket_add(void) { printf("\n=== Test 1: Socket Add ===\n"); struct UTUN_INSTANCE* instance = calloc(1, sizeof(struct UTUN_INSTANCE)); assert(instance); // Create test IP struct sockaddr_storage ip_addr; struct sockaddr_in* sin = (struct sockaddr_in*)&ip_addr; sin->sin_family = AF_INET; sin->sin_port = htons(7000); sin->sin_addr.s_addr = INADDR_ANY; // Add socket struct ETCP_SOCKET* sock = etcp_socket_add(instance, &ip_addr, 0, 0, 0); assert(sock != NULL); assert(sock->fd >= 0); assert(sock->instance == instance); printf(" ✓ Test PASSED\n")("Socket added successfully"); // Find in list struct ETCP_SOCKET* found = instance->etcp_sockets; assert(found == sock); printf(" ✓ Test PASSED\n")("Socket found in instance list"); etcp_socket_remove(sock); free(instance); printf(" ✓ Test PASSED\n")("Cleanup successful"); return 0; } // Test 2: etcp_socket_remove with active links static int test_socket_remove_with_links(void) { printf("\n=== Test 2: Socket Remove with Links ===\n"); test_context_t* ctx = create_test_context(); // Create a link struct sockaddr_storage remote_addr; struct sockaddr_in* sin = (struct sockaddr_in*)&remote_addr; sin->sin_family = AF_INET; sin->sin_port = htons(7001); inet_pton(AF_INET, "127.0.0.1", &sin->sin_addr); struct ETCP_LINK* link = etcp_link_new(ctx->conn, ctx->socket, &remote_addr, 0); assert(link != NULL); printf(" ✓ Test PASSED\n")("Link created"); // Remove socket (should close links) etcp_socket_remove(ctx->socket); // Verify socket removed from instance assert(ctx->instance->etcp_sockets == NULL); printf(" ✓ Test PASSED\n")("Socket removed from instance"); free(ctx->instance); free(ctx); return 0; } // Test 3: etcp_link_new basic static int test_link_new_basic(void) { printf("\n=== Test 3: Link New Basic ===\n"); test_context_t* ctx = create_test_context(); // Create remote address struct sockaddr_storage remote_addr; struct sockaddr_in* sin = (struct sockaddr_in*)&remote_addr; sin->sin_family = AF_INET; sin->sin_port = htons(7002); inet_pton(AF_INET, "127.0.0.1", &sin->sin_addr); // Create link struct ETCP_LINK* link = etcp_link_new(ctx->conn, ctx->socket, &remote_addr, 0); assert(link != NULL); assert(link->conn == ctx->socket); assert(link->etcp == ctx->conn); printf(" ✓ Test PASSED\n")("Link created with correct associations"); // Verify remote address copied struct sockaddr_in* remote_sin = (struct sockaddr_in*)&link->remote_addr; assert(remote_sin->sin_port == htons(7002)); printf(" ✓ Test PASSED\n")("Remote address copied correctly"); destroy_test_context(ctx); return 0; } // Test 4: etcp_link_find_by_addr static int test_link_find_by_addr(void) { printf("\n=== Test 4: Link Find by Address ===\n"); test_context_t* ctx = create_test_context(); // Create multiple links for (int i = 0; i < 5; i++) { struct sockaddr_storage addr; struct sockaddr_in* sin = (struct sockaddr_in*)&addr; sin->sin_family = AF_INET; sin->sin_port = htons(8000 + i); inet_pton(AF_INET, "127.0.0.1", &sin->sin_addr); struct ETCP_LINK* link = etcp_link_new(ctx->conn, ctx->socket, &addr, 0); assert(link != NULL); } printf(" ✓ Test PASSED\n")("5 links created"); // Find specific link struct sockaddr_storage search_addr; struct sockaddr_in* search_sin = (struct sockaddr_in*)&search_addr; search_sin->sin_family = AF_INET; search_sin->sin_port = htons(8002); inet_pton(AF_INET, "127.0.0.1", &search_sin->sin_addr); struct ETCP_LINK* found = etcp_link_find_by_addr(ctx->socket, &search_addr); assert(found != NULL); assert(((struct sockaddr_in*)&found->remote_addr)->sin_port == htons(8002)); printf(" ✓ Test PASSED\n")("Link found by address"); // Search for non-existent search_sin->sin_port = htons(9999); found = etcp_link_find_by_addr(ctx->socket, &search_addr); assert(found == NULL); printf(" ✓ Test PASSED\n")("Non-existent link returns NULL"); destroy_test_context(ctx); return 0; } // Test 5: etcp_encrypt_send basic static int test_encrypt_send_basic(void) { printf("\n=== Test 5: Encrypt Send Basic ===\n"); test_context_t* ctx = create_test_context(); // Create peer struct sockaddr_storage peer_addr; struct sockaddr_in* sin = (struct sockaddr_in*)&peer_addr; sin->sin_family = AF_INET; sin->sin_port = htons(9001); inet_pton(AF_INET, "127.0.0.1", &sin->sin_addr); struct ETCP_LINK* link = etcp_link_new(ctx->conn, ctx->socket, &peer_addr, 0); assert(link != NULL); printf(" ✓ Test PASSED\n")("Link to peer created"); // Set peer public key for encryption // Using dummy key for test uint8_t dummy_key[SC_PUBKEY_SIZE]; memset(dummy_key, 0xAA, SC_PUBKEY_SIZE); int ret = sc_set_peer_public_key(&ctx->conn->crypto_ctx, (const char*)dummy_key, 0); if (ret != SC_OK) { printf(" ⚠ Warning: sc_set_peer_public_key failed (expected for dummy key)\n"); } // Create datagram uint8_t buffer[1600]; struct ETCP_DGRAM* dgram = (struct ETCP_DGRAM*)buffer; dgram->link = link; dgram->noencrypt_len = 0; dgram->data_len = strlen(TEST_MESSAGE); memcpy(dgram->data, TEST_MESSAGE, dgram->data_len); // Send (will fail due to invalid key, but tests the path) int sent = etcp_encrypt_send(dgram); if (sent < 0) { printf(" ✓ Send path executed (encryption failed as expected with dummy key)\n"); } else { printf(" ✓ Send successful\n"); } destroy_test_context(ctx); return 0; } // Test 6: etcp_link_close basic static int test_link_close_basic(void) { printf("\n=== Test 6: Link Close Basic ===\n"); test_context_t* ctx = create_test_context(); // Create link struct sockaddr_storage addr1, addr2; struct sockaddr_in* sin1 = (struct sockaddr_in*)&addr1; sin1->sin_family = AF_INET; sin1->sin_port = htons(7001); inet_pton(AF_INET, "127.0.0.1", &sin1->sin_addr); struct sockaddr_in* sin2 = (struct sockaddr_in*)&addr2; sin2->sin_family = AF_INET; sin2->sin_port = htons(7002); inet_pton(AF_INET, "127.0.0.1", &sin2->sin_addr); struct ETCP_LINK* link1 = etcp_link_new(ctx->conn, ctx->socket, &addr1, 0); struct ETCP_LINK* link2 = etcp_link_new(ctx->conn, ctx->socket, &addr2, 0); assert(link1 != NULL && link2 != NULL); printf(" ✓ Test PASSED\n")("2 links created"); // Close one link etcp_link_close(link1); printf(" ✓ Test PASSED\n")("Link closed"); // Verify socket still has one link int count = 0; for (size_t i = 0; i < ctx->socket->num_channels; i++) { if (ctx->socket->links[i] != NULL) count++; } printf(" ℹ Socket has %d links after closing\n", count); destroy_test_context(ctx); return 0; } // Test 7: Memory pool free static int test_packet_pool_free(void) { printf("\n=== Test 7: Packet Pool Free ===\n"); // Create a memory pool struct memory_pool* pool = memory_pool_init(1600); assert(pool != NULL); printf(" ✓ Test PASSED\n")("Memory pool created"); // Allocate a packet struct ETCP_DGRAM* pkt = memory_pool_alloc(pool); assert(pkt != NULL); printf(" ✓ Test PASSED\n")("Packet allocated"); // Fill with test data pkt->link = NULL; pkt->data_len = 100; memcpy(pkt->data, "test data", 10); // Free the packet packet_pool_free(pool, pkt); printf(" ✓ Test PASSED\n")("Packet freed"); // Cleanup // Note: memory_pool_destroy not exposed, assuming cleanup via etcp_destroy return 0; } // Main test runner int main(void) { printf("╔═══════════════════════════════════════════════════════════════╗\n"); printf("║ ETCP Connections Send Operations Tests ║\n"); printf("╚═══════════════════════════════════════════════════════════════╝\n"); int tests_passed = 0; int total_tests = 0; struct test_case { const char* name; int (*func)(void); } test_cases[] = { {"Socket Add", test_socket_add}, {"Socket Remove with Links", test_socket_remove_with_links}, {"Link New Basic", test_link_new_basic}, {"Link Find by Address", test_link_find_by_addr}, {"Encrypt Send Basic", test_encrypt_send_basic}, {"Link Close Basic", test_link_close_basic}, {"Packet Pool Free", test_packet_pool_free}, {NULL, NULL} }; for (int i = 0; test_cases[i].func != NULL; i++) { total_tests++; printf("\n[TEST %d/%d] Running: %s\n", i + 1, 7, test_cases[i].name); if (test_cases[i].func() == 0) { tests_passed++; printf("[TEST %d/%d] ✓ PASSED\n", i + 1, 7); } else { printf("[TEST %d/%d] ✗ FAILED\n", i + 1, 7); } } printf("\n╔═══════════════════════════════════════════════════════════════╗\n"); printf("║ TEST SUMMARY ║\n"); printf("╠═══════════════════════════════════════════════════════════════╣\n"); printf("║ Tests Passed: %d / %d ║\n", tests_passed, total_tests); printf("║ Coverage: ETCP Connections Send Operations ║\n"); printf("╚═══════════════════════════════════════════════════════════════╝\n"); return 0; }