Browse Source

Simplify tun_if: unified init, write, close API with queue-based reads

- New struct tun_if with internal queue for incoming packets
- Single tun_init() does everything: create TUN, set MTU=1500, up, register in uasync
- tun_write() for outgoing packets
- tun_close() cleans up everything including queue
- Removed: tun_create, tun_set_ip, tun_set_up, tun_set_mtu, tun_read, tun_get_config
- Removed: utun_instance_register/unregister_sockets (now internal)
- Updated utun_instance to use new tun_if* pointer
- Updated test_etcp_two_instances for new API
nodeinfo-routing-update
Evgeny 2 months ago
parent
commit
5a7107b855
  1. 326
      src/tun_if.c
  2. 122
      src/tun_if.h
  3. 8
      src/utun.c
  4. 100
      src/utun_instance.c
  5. 5
      src/utun_instance.h
  6. BIN
      tests/bench_timeout_heap
  7. BIN
      tests/bench_uasync_timeouts
  8. BIN
      tests/test_config_debug
  9. BIN
      tests/test_crypto
  10. BIN
      tests/test_debug_categories
  11. BIN
      tests/test_ecc_encrypt
  12. BIN
      tests/test_etcp_100_packets
  13. BIN
      tests/test_etcp_crypto
  14. BIN
      tests/test_etcp_minimal
  15. BIN
      tests/test_etcp_simple_traffic
  16. BIN
      tests/test_etcp_two_instances
  17. 51
      tests/test_etcp_two_instances.c
  18. BIN
      tests/test_intensive_memory_pool
  19. BIN
      tests/test_ll_queue
  20. BIN
      tests/test_memory_pool_and_config
  21. BIN
      tests/test_packet_dump
  22. BIN
      tests/test_pkt_normalizer_etcp
  23. BIN
      tests/test_pkt_normalizer_standalone
  24. BIN
      tests/test_u_async_comprehensive
  25. BIN
      tests/test_u_async_performance

326
src/tun_if.c

@ -1,9 +1,12 @@
// tun_if.c - TUN interface management implementation
// tun_if.c - Simplified TUN interface management implementation
#define _POSIX_C_SOURCE 200809L
#include "tun_if.h"
#include "config_parser.h"
#include "etcp.h"
#include "../lib/debug_config.h"
#include "../lib/u_async.h"
#include "etcp_connections.h"
#include "../lib/ll_queue.h"
#include "../lib/memory_pool.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -46,7 +49,7 @@ static int parse_ip_mask(const char *ip_addr, struct in_addr *ip, struct in_addr
char ip_str[INET_ADDRSTRLEN];
char *slash = strchr(ip_addr, '/');
if (!slash) return -1; // Require /mask
if (!slash) return -1;
size_t ip_len = slash - ip_addr;
if (ip_len >= sizeof(ip_str)) return -1;
@ -97,46 +100,8 @@ static int create_tun_device(char *ifname, size_t ifname_len) {
return fd;
}
int tun_create(struct tun_config *config) {
if (!config) {
errno = EINVAL;
return -1;
}
// Create TUN device
int fd = create_tun_device(config->ifname, sizeof(config->ifname));
if (fd < 0) {
return -1;
}
config->fd = fd;
// Configure IP if specified
if (config->ip_addr[0] != '\0') {
if (tun_set_ip(config->ifname, config->ip_addr) < 0) {
close(fd);
return -1;
}
}
// Set MTU if specified
if (config->mtu > 0) {
if (tun_set_mtu(config->ifname, config->mtu) < 0) {
DEBUG_WARN(DEBUG_CATEGORY_TUN, "Failed to set MTU %d on %s: %s", config->mtu, config->ifname, strerror(errno));
}
}
// Bring interface up
if (tun_set_up(config->ifname) < 0) {
close(fd);
return -1;
}
config->is_up = 1;
return 0;
}
int tun_set_ip(const char *ifname, const char *ip_addr) {
// Set IP address on TUN interface
static int tun_set_ip(const char *ifname, const char *ip_addr) {
if (!ifname || !ip_addr) {
errno = EINVAL;
return -1;
@ -167,7 +132,8 @@ int tun_set_ip(const char *ifname, const char *ip_addr) {
return 0;
}
int tun_set_up(const char *ifname) {
// Bring TUN interface up
static int tun_set_up(const char *ifname) {
if (!ifname) {
errno = EINVAL;
return -1;
@ -186,7 +152,8 @@ int tun_set_up(const char *ifname) {
return 0;
}
int tun_set_mtu(const char *ifname, int mtu) {
// Set MTU on TUN interface
static int tun_set_mtu(const char *ifname, int mtu) {
if (!ifname || mtu <= 0) {
errno = EINVAL;
return -1;
@ -201,119 +168,228 @@ int tun_set_mtu(const char *ifname, int mtu) {
return 0;
}
ssize_t tun_read(int fd, uint8_t *buffer, size_t size) {
if (fd < 0 || !buffer || size == 0) {
errno = EINVAL;
return -1;
}
// Internal read callback - called by uasync when data available on TUN
static void tun_read_callback(int fd, void* user_arg) {
struct tun_if* tun = (struct tun_if*)user_arg;
uint8_t buffer[TUN_MAX_PACKET_SIZE];
ssize_t nread = read(fd, buffer, size);
// Read from TUN device
ssize_t nread = read(fd, buffer, sizeof(buffer));
if (nread < 0) {
perror("tun_read");
if (errno == EINTR) return;
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to read from TUN device %s: %s", tun->ifname, strerror(errno));
tun->read_errors++;
return;
}
return nread;
}
if (nread == 0) return;
ssize_t tun_write(int fd, const uint8_t *buffer, size_t size) {
if (fd < 0 || !buffer || size == 0) {
errno = EINVAL;
return -1;
// Allocate packet data
uint8_t* packet_data = malloc(nread);
if (!packet_data) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to allocate packet data (size=%zd)", nread);
tun->read_errors++;
return;
}
memcpy(packet_data, buffer, nread);
// Allocate ETCP_FRAGMENT from pool
struct ETCP_FRAGMENT* pkt = (struct ETCP_FRAGMENT*)queue_entry_new_from_pool(tun->pool);
if (!pkt) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to allocate ETCP_FRAGMENT from pool");
free(packet_data);
tun->read_errors++;
return;
}
ssize_t nwritten = write(fd, buffer, size);
if (nwritten < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to write to TUN device fd=%d: %s", fd, strerror(errno));
// Initialize fragment
pkt->seq = 0;
pkt->timestamp = 0;
pkt->ll.dgram = packet_data;
pkt->ll.len = nread;
// Add to input queue
if (queue_data_put(tun->input_queue, (struct ll_entry*)pkt, 0) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to add packet to input queue");
free(packet_data);
memory_pool_free(tun->pool, pkt);
tun->read_errors++;
return;
}
return nwritten;
// Update statistics
tun->bytes_read += nread;
tun->packets_read++;
DEBUG_DEBUG(DEBUG_CATEGORY_TUN, "Read %zd bytes from TUN %s", nread, tun->ifname);
}
void tun_close(struct tun_config *config) {
if (!config) return;
struct tun_if* tun_init(struct UASYNC* ua, struct utun_config* config) {
if (!ua || !config) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Invalid arguments: ua=%p, config=%p", ua, config);
return NULL;
}
if (config->fd >= 0) {
close(config->fd);
config->fd = -1;
// Allocate tun_if structure
struct tun_if* tun = calloc(1, sizeof(struct tun_if));
if (!tun) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to allocate tun_if");
return NULL;
}
config->is_up = 0;
}
tun->ua = ua;
tun->fd = -1;
int tun_get_config(const char *ifname, struct tun_config *config) {
if (!ifname || !config) {
errno = EINVAL;
return -1;
// Get interface name from config (or empty for auto)
const char* ifname = config->global.tun_ifname;
if (ifname && ifname[0] != '\0') {
strncpy(tun->ifname, ifname, sizeof(tun->ifname) - 1);
}
// TODO: Implement reading current interface configuration
// This would require ioctl SIOCGIFADDR, SIOCGIFNETMASK, etc.
// Create TUN device
tun->fd = create_tun_device(tun->ifname, sizeof(tun->ifname));
if (tun->fd < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to create TUN device");
free(tun);
return NULL;
}
memset(config, 0, sizeof(*config));
strncpy(config->ifname, ifname, sizeof(config->ifname) - 1);
config->fd = -1;
// Build IP address string from config
char ip_buffer[INET_ADDRSTRLEN];
char tun_ip_str[64];
if (config->global.tun_ip.family == AF_INET) {
inet_ntop(AF_INET, &config->global.tun_ip.addr.v4, ip_buffer, sizeof(ip_buffer));
} else {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Only IPv4 is supported for TUN");
close(tun->fd);
free(tun);
return NULL;
}
return 0;
}
#ifdef __linux__
snprintf(tun_ip_str, sizeof(tun_ip_str), "%s/32", ip_buffer);
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
snprintf(tun_ip_str, sizeof(tun_ip_str), "%s", ip_buffer);
#else
snprintf(tun_ip_str, sizeof(tun_ip_str), "%s/32", ip_buffer);
#endif
// Configure IP address
if (tun_set_ip(tun->ifname, tun_ip_str) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to set TUN IP: %s", tun_ip_str);
close(tun->fd);
free(tun);
return NULL;
}
// Set MTU to 1500 (default)
int mtu = config->global.mtu > 0 ? config->global.mtu : TUN_MTU_DEFAULT;
if (tun_set_mtu(tun->ifname, mtu) < 0) {
DEBUG_WARN(DEBUG_CATEGORY_TUN, "Failed to set MTU %d on %s: %s", mtu, tun->ifname, strerror(errno));
}
// Bring interface up
if (tun_set_up(tun->ifname) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to bring up TUN interface %s", tun->ifname);
close(tun->fd);
free(tun);
return NULL;
}
// Create memory pool for ETCP_FRAGMENT
tun->pool = memory_pool_init(sizeof(struct ETCP_FRAGMENT));
if (!tun->pool) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to create memory pool");
close(tun->fd);
free(tun);
return NULL;
}
// Create input queue
tun->input_queue = queue_new(ua, 0); // hash_size=0 - no ID lookup needed
if (!tun->input_queue) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to create input queue");
memory_pool_destroy(tun->pool);
close(tun->fd);
free(tun);
return NULL;
}
// Register TUN socket with uasync
tun->socket_id = uasync_add_socket(ua, tun->fd, tun_read_callback, NULL, NULL, tun);
if (!tun->socket_id) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to register TUN socket with uasync");
queue_free(tun->input_queue);
memory_pool_destroy(tun->pool);
close(tun->fd);
free(tun);
return NULL;
}
DEBUG_INFO(DEBUG_CATEGORY_TUN, "TUN interface initialized: %s (fd=%d, IP=%s, MTU=%d)",
tun->ifname, tun->fd, tun_ip_str, mtu);
// Extract destination IPv4 address from packet
static uint32_t get_dest_ip(const uint8_t *packet, size_t len) {
if (len < 20) return 0; // Minimum IPv4 header size
// Check IP version (first nibble)
uint8_t version = (packet[0] >> 4) & 0x0F;
if (version != 4) return 0;
// Destination IP is at offset 16
uint32_t dest_ip;
memcpy(&dest_ip, packet + 16, 4);
return dest_ip;
return tun;
}
// Callback for TUN device read events
void tun_read_callback(int fd, void* user_arg) {
struct UTUN_INSTANCE *instance = (struct UTUN_INSTANCE*)user_arg;
uint8_t buffer[MAX_PACKET_SIZE];
void tun_close(struct tun_if* tun) {
if (!tun) return;
// Read from TUN device
ssize_t nread = tun_read(fd, buffer, sizeof(buffer));
if (nread < 0) {
if (errno == EINTR) return;
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to read from TUN device %s: %s", instance->tun.ifname, strerror(errno));
return;
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Closing TUN interface: %s", tun->ifname);
// Unregister socket from uasync
if (tun->socket_id && tun->ua) {
uasync_remove_socket(tun->ua, tun->socket_id);
tun->socket_id = NULL;
}
// Drain and free all packets from input queue
if (tun->input_queue) {
struct ETCP_FRAGMENT* pkt;
while ((pkt = (struct ETCP_FRAGMENT*)queue_data_get(tun->input_queue)) != NULL) {
if (pkt->ll.dgram) {
free(pkt->ll.dgram);
}
memory_pool_free(tun->pool, pkt);
}
queue_free(tun->input_queue);
tun->input_queue = NULL;
}
if (nread > 0) {
// Route packet based on destination IP
uint32_t dest_ip = get_dest_ip(buffer, nread);
// ... (rest of the routing logic)
// Destroy memory pool
if (tun->pool) {
memory_pool_destroy(tun->pool);
tun->pool = NULL;
}
// Close file descriptor
if (tun->fd >= 0) {
close(tun->fd);
tun->fd = -1;
}
free(tun);
}
// Register sockets with uasync
int utun_instance_register_sockets(struct UTUN_INSTANCE *instance) {
if (!instance || !instance->ua || instance->tun.fd < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Invalid instance or TUN fd");
ssize_t tun_write(struct tun_if* tun, const uint8_t* buf, size_t len) {
if (!tun || tun->fd < 0 || !buf || len == 0) {
if (tun) tun->write_errors++;
errno = EINVAL;
return -1;
}
// Register TUN file descriptor
instance->tun_socket_id = uasync_add_socket(instance->ua, instance->tun.fd,
tun_read_callback, NULL, NULL, instance);
if (!instance->tun_socket_id) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to register TUN socket");
ssize_t nwritten = write(tun->fd, buf, len);
if (nwritten < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to write to TUN device %s: %s", tun->ifname, strerror(errno));
tun->write_errors++;
return -1;
}
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Registered TUN socket (fd=%d)", instance->tun.fd);
return 0;
}
tun->bytes_written += nwritten;
tun->packets_written++;
// Unregister sockets
void utun_instance_unregister_sockets(struct UTUN_INSTANCE *instance) {
if (!instance || !instance->ua) return;
DEBUG_DEBUG(DEBUG_CATEGORY_TUN, "Wrote %zd bytes to TUN %s", nwritten, tun->ifname);
if (instance->tun_socket_id) {
uasync_remove_socket(instance->ua, instance->tun_socket_id);
instance->tun_socket_id = NULL;
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Unregistered TUN socket: %s", instance->tun.ifname);
}
}
return nwritten;
}

122
src/tun_if.h

@ -1,102 +1,82 @@
// tun_if.h - TUN interface management for utun
// tun_if.h - Simplified TUN interface management for utun
#ifndef TUN_IF_H
#define TUN_IF_H
#include <stdint.h>
#include <stddef.h>
#include <sys/types.h>
// Forward declarations
struct UTUN_INSTANCE;
struct UASYNC;
struct utun_config;
struct ll_queue;
struct memory_pool;
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_PACKET_SIZE 1500
// TUN interface configuration
struct tun_config {
char ifname[16]; // Interface name (e.g., "tun12")
char ip_addr[64]; // IP address with mask (e.g., "10.0.0.1/24")
int mtu; // MTU size
int fd; // File descriptor
uint8_t is_up; // 1 if interface is up
#define TUN_MTU_DEFAULT 1500
#define TUN_MAX_PACKET_SIZE 1500
// TUN interface handle - opaque structure
struct tun_if {
char ifname[16]; // Interface name (e.g., "tun12")
int fd; // File descriptor
struct UASYNC* ua; // uasync instance
void* socket_id; // Socket ID from uasync_add_socket
struct memory_pool* pool; // Pool for ETCP_FRAGMENT structures
struct ll_queue* input_queue; // Queue for incoming packets (ETCP_FRAGMENT)
// Statistics
uint64_t bytes_read; // Bytes read from TUN
uint64_t bytes_written; // Bytes written to TUN
uint32_t packets_read; // Packets read from TUN
uint32_t packets_written; // Packets written to TUN
uint32_t read_errors; // Read errors
uint32_t write_errors; // Write errors
uint64_t bytes_read; // Bytes read from TUN
uint64_t bytes_written; // Bytes written to TUN
uint32_t packets_read; // Packets read from TUN
uint32_t packets_written; // Packets written to TUN
uint32_t read_errors; // Read errors
uint32_t write_errors; // Write errors
};
/**
* @brief Create and configure TUN interface
* @param config TUN configuration (ifname can be empty for auto)
* @return 0 on success, -1 on error
*/
int tun_create(struct tun_config *config);
/**
* @brief Configure IP address on TUN interface
* @param ifname Interface name
* @param ip_addr IP address with mask (e.g., "10.0.0.1/24")
* @return 0 on success, -1 on error
* @brief Initialize TUN interface
* Creates TUN device, sets MTU=1500, brings interface up,
* configures IP from config, registers read callback in uasync,
* creates memory pool and input queue for incoming packets.
* @param ua uasync instance for event handling
* @param config Configuration containing tun_ip and other settings
* @return Pointer to tun_if on success, NULL on error
*/
int tun_set_ip(const char *ifname, const char *ip_addr);
struct tun_if* tun_init(struct UASYNC* ua, struct utun_config* config);
/**
* @brief Bring TUN interface up
* @param ifname Interface name
* @return 0 on success, -1 on error
* @brief Close TUN interface and free resources
* Unregisters socket from uasync, closes fd, drains and frees
* all packets from input_queue, destroys pool and queue.
* @param tun TUN interface handle
*/
int tun_set_up(const char *ifname);
/**
* @brief Set MTU on TUN interface
* @param ifname Interface name
* @param mtu MTU value
* @return 0 on success, -1 on error
*/
int tun_set_mtu(const char *ifname, int mtu);
/**
* @brief Read packet from TUN interface
* @param fd TUN file descriptor
* @param buffer Buffer to store packet
* @param size Buffer size
* @return Number of bytes read, -1 on error
*/
ssize_t tun_read(int fd, uint8_t *buffer, size_t size);
void tun_close(struct tun_if* tun);
/**
* @brief Write packet to TUN interface
* @param fd TUN file descriptor
* @param buffer Packet data
* @param size Packet size
* @param tun TUN interface handle
* @param buf Packet data
* @param len Packet size
* @return Number of bytes written, -1 on error
*/
ssize_t tun_write(int fd, const uint8_t *buffer, size_t size);
/**
* @brief Close TUN interface
* @param config TUN configuration
*/
void tun_close(struct tun_config *config);
ssize_t tun_write(struct tun_if* tun, const uint8_t* buf, size_t len);
/**
* @brief Get current TUN configuration
* @param ifname Interface name
* @param config Output configuration
* @return 0 on success, -1 on error
* @brief Get input queue for reading packets
* User should call queue_data_get(tun->input_queue) to retrieve packets.
* Each packet is struct ETCP_FRAGMENT with:
* - ll.dgram: malloc'd packet data (user must free)
* - ll.len: packet length
* User must free dgram and return fragment to pool via memory_pool_free().
* @param tun TUN interface handle
* @return Pointer to input queue
*/
int tun_get_config(const char *ifname, struct tun_config *config);
int utun_instance_register_sockets(struct UTUN_INSTANCE *instance);
void utun_instance_unregister_sockets(struct UTUN_INSTANCE *instance);
// TUN callback function
void tun_read_callback(int fd, void* user_arg);
static inline struct ll_queue* tun_get_input_queue(struct tun_if* tun) {
return tun ? tun->input_queue : NULL;
}
#ifdef __cplusplus
}

8
src/utun.c

@ -292,12 +292,7 @@ int main(int argc, char *argv[]) {
return 1;
}
// Register sockets with uasync
if (utun_instance_register_sockets(instance) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to register sockets");
utun_instance_destroy(instance);
return 1;
}
// Note: TUN socket is registered in tun_init(), ETCP sockets in init_connections()
// Setup signal handlers
signal(SIGINT, signal_handler);
@ -324,7 +319,6 @@ int main(int argc, char *argv[]) {
// Cleanup
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Shutdown");
utun_instance_unregister_sockets(instance);
utun_instance_destroy(instance);
// Destroy uasync instance after instance is destroyed

100
src/utun_instance.c

@ -81,70 +81,17 @@ struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char *config
// Initialize TUN device only if enabled
if (g_tun_init_enabled) {
// Initialize TUN device
if (tun_create(&instance->tun) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to create TUN device");
instance->tun = tun_init(ua, instance->config);
if (!instance->tun) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to initialize TUN device");
free(instance);
return NULL;
}
// Configure TUN device IP (BSD: use config IP as-is, Linux/Win: IP/32)
char tun_ip_str[64];
char ip_buffer[64];
// Convert struct IP to string using inet_ntop
if (instance->config->global.tun_ip.family == AF_INET) {
inet_ntop(AF_INET, &instance->config->global.tun_ip.addr.v4, ip_buffer, sizeof(ip_buffer));
} else {
inet_ntop(AF_INET6, &instance->config->global.tun_ip.addr.v6, ip_buffer, sizeof(ip_buffer));
}
#ifdef __linux__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-truncation"
snprintf(tun_ip_str, sizeof(tun_ip_str), "%s/32", ip_buffer);
#pragma GCC diagnostic pop
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
// BSD systems: use config IP as-is, peer IP will be 192.0.2.1
snprintf(tun_ip_str, sizeof(tun_ip_str), "%s", ip_buffer);
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-truncation"
snprintf(tun_ip_str, sizeof(tun_ip_str), "%s/32", ip_buffer); // Default to /32
#pragma GCC diagnostic pop
#endif
if (tun_set_ip(instance->tun.ifname, tun_ip_str) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to set TUN IP: %s", tun_ip_str);
tun_close(&instance->tun);
free(instance);
return NULL;
}
// Set MTU (default 1500)
int mtu = instance->config->global.mtu > 0 ? instance->config->global.mtu : 1500;
if (tun_set_mtu(instance->tun.ifname, mtu) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to set TUN MTU: %d", mtu);
tun_close(&instance->tun);
free(instance);
return NULL;
}
if (tun_set_up(instance->tun.ifname) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to bring up TUN interface");
tun_close(&instance->tun);
free(instance);
return NULL;
}
DEBUG_INFO(DEBUG_CATEGORY_TUN, "TUN interface initialized: %s with IP %s",
instance->tun.ifname, tun_ip_str);
DEBUG_INFO(DEBUG_CATEGORY_TUN, "TUN interface initialized: %s", instance->tun->ifname);
} else {
// TUN initialization disabled - skip TUN setup
DEBUG_INFO(DEBUG_CATEGORY_TUN, "TUN initialization disabled - skipping TUN device setup");
// Initialize TUN structure with safe defaults
memset(&instance->tun, 0, sizeof(instance->tun));
instance->tun.fd = -1; // Invalid file descriptor to indicate no TUN device
instance->tun = NULL;
}
return instance;
@ -162,12 +109,6 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
// Stop running if not already
instance->running = 0;
// Unregister all sockets from uasync BEFORE destroying ETCP components
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Unregistering sockets from uasync");
utun_instance_unregister_sockets(instance);
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Socket unregistration complete");
// Cleanup ETCP sockets and connections FIRST (before destroying uasync)
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Cleaning up ETCP sockets and connections");
struct ETCP_SOCKET* sock = instance->etcp_sockets;
@ -194,9 +135,10 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] ETCP connections cleanup complete");
// Cleanup TUN
if (instance->tun.fd >= 0) {
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Closing TUN interface: %s", instance->tun.ifname);
tun_close(&instance->tun);
if (instance->tun) {
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Closing TUN interface: %s", instance->tun->ifname);
tun_close(instance->tun);
instance->tun = NULL;
}
// Cleanup config
@ -258,17 +200,7 @@ void utun_instance_stop(struct UTUN_INSTANCE *instance) {
int utun_instance_init(struct UTUN_INSTANCE *instance) {
if (!instance) return -1;
// Register TUN socket with uasync
if (instance->tun.fd >= 0) {
instance->tun_socket_id = uasync_add_socket(instance->ua, instance->tun.fd,
tun_read_callback, NULL, NULL, instance);
if (!instance->tun_socket_id) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to register TUN socket with uasync");
return -1;
}
DEBUG_INFO(DEBUG_CATEGORY_TUN, "TUN interface registered: %s (fd=%d)",
instance->tun.ifname, instance->tun.fd);
}
// Note: TUN socket is already registered in tun_init()
// Initialize connections
// Добавляем прямой вывод для отладки проблемы double free
@ -344,8 +276,8 @@ void utun_instance_diagnose_leaks(struct UTUN_INSTANCE *instance, const char *ph
printf("\n🔧 RESOURCE STATUS:\n");
printf(" Memory Pool: %s\n", instance->pkt_pool ? "ALLOCATED" : "NULL");
printf(" TUN Socket ID: %p\n", instance->tun_socket_id);
printf(" TUN FD: %d\n", instance->tun.fd);
printf(" TUN Interface: %s\n", instance->tun ? instance->tun->ifname : "NULL");
printf(" TUN FD: %d\n", instance->tun ? instance->tun->fd : -1);
printf(" Connections list: %p\n", instance->connections);
printf(" ETCP Sockets list: %p\n", instance->etcp_sockets);
@ -353,8 +285,8 @@ void utun_instance_diagnose_leaks(struct UTUN_INSTANCE *instance, const char *ph
if (instance->pkt_pool) {
printf(" ❌ Memory Pool not freed\n");
}
if (instance->tun_socket_id) {
printf(" ❌ TUN socket not unregistered from uasync\n");
if (instance->tun) {
printf(" ❌ TUN interface not closed\n");
}
if (report.etcp_sockets_count > 0) {
printf(" ❌ %d ETCP sockets still allocated\n", report.etcp_sockets_count);
@ -370,8 +302,8 @@ void utun_instance_diagnose_leaks(struct UTUN_INSTANCE *instance, const char *ph
if (instance->pkt_pool) {
printf(" → Call memory_pool_destroy() before freeing instance\n");
}
if (instance->tun_socket_id) {
printf(" → Call uasync_remove_socket() for TUN socket\n");
if (instance->tun) {
printf(" → Call tun_close() to close TUN interface\n");
}
if (report.etcp_sockets_count > 0) {
printf(" → Iterate and call etcp_socket_remove() for each socket\n");

5
src/utun_instance.h

@ -6,7 +6,6 @@
#include <stdio.h>
#include "../lib/memory_pool.h"
#include "secure_channel.h"
#include "tun_if.h"
// Forward declarations
struct utun_config;
@ -14,6 +13,7 @@ struct uasync_s;
struct routing_table;
struct ETCP_CONN;
struct ETCP_SOCKET;
struct tun_if;
// uTun instance configuration
struct UTUN_INSTANCE {
@ -21,8 +21,7 @@ struct UTUN_INSTANCE {
struct utun_config *config;
// TUN interface
struct tun_config tun;
void *tun_socket_id; // Socket ID from uasync_add_socket
struct tun_if* tun;
// Identification
uint64_t node_id;

BIN
tests/bench_timeout_heap

Binary file not shown.

BIN
tests/bench_uasync_timeouts

Binary file not shown.

BIN
tests/test_config_debug

Binary file not shown.

BIN
tests/test_crypto

Binary file not shown.

BIN
tests/test_debug_categories

Binary file not shown.

BIN
tests/test_ecc_encrypt

Binary file not shown.

BIN
tests/test_etcp_100_packets

Binary file not shown.

BIN
tests/test_etcp_crypto

Binary file not shown.

BIN
tests/test_etcp_minimal

Binary file not shown.

BIN
tests/test_etcp_simple_traffic

Binary file not shown.

BIN
tests/test_etcp_two_instances

Binary file not shown.

51
tests/test_etcp_two_instances.c

@ -144,23 +144,11 @@ int main() {
return 1;
}
// Check if TUN is disabled and handle accordingly
if (server_instance->tun.fd < 0) {
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Server TUN disabled - skipping TUN initialization");
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Server instance created successfully (node_id=%llx)", (unsigned long long)server_instance->node_id);
} else {
// Normal initialization for TUN-enabled mode
if (utun_instance_init(server_instance) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to initialize server instance");
utun_instance_destroy(server_instance);
return 1;
}
if (utun_instance_register_sockets(server_instance) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to register server sockets");
utun_instance_destroy(server_instance);
return 1;
}
// Initialize instance (TUN is initialized in utun_instance_create if enabled)
if (utun_instance_init(server_instance) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to initialize server instance");
utun_instance_destroy(server_instance);
return 1;
}
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Server instance ready (node_id=%llx)", (unsigned long long)server_instance->node_id);
@ -181,25 +169,12 @@ int main() {
return 1;
}
// Check if TUN is disabled and handle accordingly
if (client_instance->tun.fd < 0) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, " Client TUN disabled - skipping TUN initialization\n");
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "✅ Client instance created successfully (node_id=%llx)\n", (unsigned long long)client_instance->node_id);
} else {
// Normal initialization for TUN-enabled mode
if (utun_instance_init(client_instance) < 0) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Failed to initialize client instance\n");
utun_instance_destroy(server_instance);
utun_instance_destroy(client_instance);
return 1;
}
if (utun_instance_register_sockets(client_instance) < 0) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Failed to register client sockets\n");
utun_instance_destroy(server_instance);
utun_instance_destroy(client_instance);
return 1;
}
// Initialize instance (TUN is initialized in utun_instance_create if enabled)
if (utun_instance_init(client_instance) < 0) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Failed to initialize client instance\n");
utun_instance_destroy(server_instance);
utun_instance_destroy(client_instance);
return 1;
}
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Client instance ready (node_id=%llx)\n\n", (unsigned long long)client_instance->node_id);
@ -278,14 +253,14 @@ int main() {
if (test_completed == 1) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "\n=== TEST PASSED ===\n");
// Check if TUN was disabled and add note
if (server_instance->tun.fd < 0 || client_instance->tun.fd < 0) {
if (!server_instance->tun || !client_instance->tun) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "✅ ETCP connection test successful with TUN disabled\n");
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "✅ Core ETCP protocol functionality verified\n");
}
return 0;
} else if (test_completed == 2) {
// Check if TUN was disabled - if so, timeout is expected and acceptable
if (server_instance->tun.fd < 0 || client_instance->tun.fd < 0) {
if (!server_instance->tun || !client_instance->tun) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "\n=== TEST PASSED ===\n");
DEBUG_INFO(DEBUG_CATEGORY_ETCP, " Connection timeout expected with TUN disabled\n");
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "✅ ETCP core infrastructure verified successfully\n");

BIN
tests/test_intensive_memory_pool

Binary file not shown.

BIN
tests/test_ll_queue

Binary file not shown.

BIN
tests/test_memory_pool_and_config

Binary file not shown.

BIN
tests/test_packet_dump

Binary file not shown.

BIN
tests/test_pkt_normalizer_etcp

Binary file not shown.

BIN
tests/test_pkt_normalizer_standalone

Binary file not shown.

BIN
tests/test_u_async_comprehensive

Binary file not shown.

BIN
tests/test_u_async_performance

Binary file not shown.
Loading…
Cancel
Save