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

// 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;
}