- Fixed incorrect init_connections() call in test_etcp_simple_traffic.c (was calling server_instance instead of client_instance) - Fixed double free in timeout_heap_pop() when handling deleted elements - Enhanced NULL pointer safety in uasync_print_resources() by removing complex heap manipulation - Added debug logging to timeout_heap_pop() for better error tracking Test results: test_etcp_simple_traffic now passes without double free errors
190 lines
6.8 KiB
C
Executable File
190 lines
6.8 KiB
C
Executable File
#include "test_virtual_tun.h"
|
|
#include "../lib/debug_config.h"
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
|
|
#ifndef DEBUG_CATEGORY_TEST
|
|
#define DEBUG_CATEGORY_TEST (1 << 30)
|
|
#endif
|
|
|
|
// Create virtual TUN with bidirectional pipes
|
|
struct virtual_tun* virtual_tun_create(const char* ifname) {
|
|
if (!ifname) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "NULL interface name provided");
|
|
return NULL;
|
|
}
|
|
|
|
struct virtual_tun* vtun = calloc(1, sizeof(struct virtual_tun));
|
|
if (!vtun) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to allocate virtual TUN");
|
|
return NULL;
|
|
}
|
|
|
|
// Copy interface name
|
|
strncpy(vtun->ifname, ifname, sizeof(vtun->ifname) - 1);
|
|
vtun->ifname[sizeof(vtun->ifname) - 1] = '\0';
|
|
vtun->enabled = true;
|
|
|
|
// Create pipes for bidirectional communication
|
|
// read_pipe: [0] = read end, [1] = write end (for packets from network)
|
|
// write_pipe: [0] = read end, [1] = write end (for packets to network)
|
|
if (pipe(vtun->read_pipe) < 0) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to create read pipe: %s", strerror(errno));
|
|
free(vtun);
|
|
return NULL;
|
|
}
|
|
|
|
if (pipe(vtun->write_pipe) < 0) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to create write pipe: %s", strerror(errno));
|
|
close(vtun->read_pipe[0]);
|
|
close(vtun->read_pipe[1]);
|
|
free(vtun);
|
|
return NULL;
|
|
}
|
|
|
|
// Set non-blocking mode on pipe ends
|
|
for (int i = 0; i < 2; i++) {
|
|
int flags = fcntl(vtun->read_pipe[i], F_GETFL, 0);
|
|
if (flags == -1 || fcntl(vtun->read_pipe[i], F_SETFL, flags | O_NONBLOCK) < 0) {
|
|
DEBUG_WARN(DEBUG_CATEGORY_TEST, "Failed to set non-blocking on read pipe[%d]: %s", i, strerror(errno));
|
|
}
|
|
|
|
flags = fcntl(vtun->write_pipe[i], F_GETFL, 0);
|
|
if (flags == -1 || fcntl(vtun->write_pipe[i], F_SETFL, flags | O_NONBLOCK) < 0) {
|
|
DEBUG_WARN(DEBUG_CATEGORY_TEST, "Failed to set non-blocking on write pipe[%d]: %s", i, strerror(errno));
|
|
}
|
|
}
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_TEST, "Virtual TUN created: %s (read_fd=%d, write_fd=%d)",
|
|
vtun->ifname, vtun->read_pipe[0], vtun->write_pipe[1]);
|
|
|
|
return vtun;
|
|
}
|
|
|
|
// Cleanup virtual TUN
|
|
void virtual_tun_destroy(struct virtual_tun* vtun) {
|
|
if (!vtun) return;
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_TEST, "Destroying virtual TUN: %s (stats: sent=%zu packets/%zu bytes, recv=%zu packets/%zu bytes)",
|
|
vtun->ifname, vtun->stats.packets_sent, vtun->stats.bytes_sent,
|
|
vtun->stats.packets_received, vtun->stats.bytes_received);
|
|
|
|
// Close all pipe file descriptors
|
|
if (vtun->read_pipe[0] >= 0) close(vtun->read_pipe[0]);
|
|
if (vtun->read_pipe[1] >= 0) close(vtun->read_pipe[1]);
|
|
if (vtun->write_pipe[0] >= 0) close(vtun->write_pipe[0]);
|
|
if (vtun->write_pipe[1] >= 0) close(vtun->write_pipe[1]);
|
|
|
|
free(vtun);
|
|
}
|
|
|
|
// Get file descriptor for reading (simulates TUN device read)
|
|
int virtual_tun_get_read_fd(struct virtual_tun* vtun) {
|
|
if (!vtun || !vtun->enabled) return -1;
|
|
return vtun->read_pipe[0]; // Read end of read pipe
|
|
}
|
|
|
|
// Get file descriptor for writing (simulates TUN device write)
|
|
int virtual_tun_get_write_fd(struct virtual_tun* vtun) {
|
|
if (!vtun || !vtun->enabled) return -1;
|
|
return vtun->write_pipe[1]; // Write end of write pipe
|
|
}
|
|
|
|
// Inject packet into virtual TUN (simulates packet from network)
|
|
int virtual_tun_inject_packet(struct virtual_tun* vtun, const uint8_t* packet, size_t len) {
|
|
if (!vtun || !vtun->enabled || !packet || len == 0) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Invalid parameters for packet injection");
|
|
return -1;
|
|
}
|
|
|
|
if (len > VIRTUAL_TUN_MAX_PACKET_SIZE) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Packet too large: %zu > %d", len, VIRTUAL_TUN_MAX_PACKET_SIZE);
|
|
return -1;
|
|
}
|
|
|
|
// Write packet to read pipe (simulates packet arriving from network)
|
|
ssize_t written = write(vtun->read_pipe[1], packet, len);
|
|
if (written < 0) {
|
|
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to inject packet: %s", strerror(errno));
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
vtun->stats.packets_received++;
|
|
vtun->stats.bytes_received += written;
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_TEST, "Injected packet into %s: %zu bytes", vtun->ifname, written);
|
|
return 0;
|
|
}
|
|
|
|
// Read packet from virtual TUN (captures packets going to network)
|
|
ssize_t virtual_tun_read_packet(struct virtual_tun* vtun, uint8_t* buffer, size_t max_len) {
|
|
if (!vtun || !vtun->enabled || !buffer || max_len == 0) {
|
|
return -1;
|
|
}
|
|
|
|
// Read from write pipe (captures packets going to network)
|
|
ssize_t bytes_read = read(vtun->write_pipe[0], buffer, max_len);
|
|
if (bytes_read < 0) {
|
|
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to read packet: %s", strerror(errno));
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
if (bytes_read > 0) {
|
|
vtun->stats.packets_sent++;
|
|
vtun->stats.bytes_sent += bytes_read;
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_TEST, "Read packet from %s: %zu bytes", vtun->ifname, bytes_read);
|
|
}
|
|
|
|
return bytes_read;
|
|
}
|
|
|
|
// Write packet to virtual TUN (sends packet to network)
|
|
ssize_t virtual_tun_write_packet(struct virtual_tun* vtun, const uint8_t* packet, size_t len) {
|
|
if (!vtun || !vtun->enabled || !packet || len == 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (len > VIRTUAL_TUN_MAX_PACKET_SIZE) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Packet too large: %zu > %d", len, VIRTUAL_TUN_MAX_PACKET_SIZE);
|
|
return -1;
|
|
}
|
|
|
|
// Write packet to write pipe (sends to network)
|
|
ssize_t written = write(vtun->write_pipe[1], packet, len);
|
|
if (written < 0) {
|
|
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to write packet: %s", strerror(errno));
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_TEST, "Wrote packet to %s: %zu bytes", vtun->ifname, written);
|
|
return written;
|
|
}
|
|
|
|
// Get virtual TUN statistics
|
|
void virtual_tun_get_stats(struct virtual_tun* vtun, size_t* packets_sent, size_t* packets_received,
|
|
size_t* bytes_sent, size_t* bytes_received) {
|
|
if (!vtun) return;
|
|
|
|
if (packets_sent) *packets_sent = vtun->stats.packets_sent;
|
|
if (packets_received) *packets_received = vtun->stats.packets_received;
|
|
if (bytes_sent) *bytes_sent = vtun->stats.bytes_sent;
|
|
if (bytes_received) *bytes_received = vtun->stats.bytes_received;
|
|
}
|
|
|
|
// Reset virtual TUN statistics
|
|
void virtual_tun_reset_stats(struct virtual_tun* vtun) {
|
|
if (!vtun) return;
|
|
|
|
memset(&vtun->stats, 0, sizeof(vtun->stats));
|
|
DEBUG_INFO(DEBUG_CATEGORY_TEST, "Reset statistics for virtual TUN: %s", vtun->ifname);
|
|
} |