You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
381 lines
13 KiB
381 lines
13 KiB
// 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 <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <assert.h> |
|
#include <sys/socket.h> |
|
|
|
|
|
void packet_pool_free(struct memory_pool* pool, void* ptr); |
|
// Forward declarations |
|
#include <netinet/in.h> |
|
#include <arpa/inet.h> |
|
#include <unistd.h> |
|
#include <fcntl.h> |
|
#include <errno.h> |
|
|
|
#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; |
|
} |