// utun_instance.c - Root instance implementation #include "utun_instance.h" #include "config_parser.h" #include "config_updater.h" #include "tun_if.h" #include "routing.h" #include "etcp_connections.h" #include "etcp.h" #include "../lib/u_async.h" #include "../lib/debug_config.h" #include #include #include #include #include #include // Forward declarations static void tun_read_callback(int fd, void* user_arg); static uint32_t get_dest_ip(const uint8_t *packet, size_t len); // Global instance for signal handlers static struct UTUN_INSTANCE *g_instance = NULL; // Create and initialize root instance struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char *config_file, const char *log_file) { struct UTUN_INSTANCE *instance = calloc(1, sizeof(struct UTUN_INSTANCE)); if (!instance) return NULL; // Initialize basic fields instance->running = 0; instance->log_fp = NULL; instance->ua = ua; // Ensure keys and node_id exist in config if (config_ensure_keys_and_node_id(config_file) < 0) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to ensure keys and node_id in config: %s", config_file); free(instance); return NULL; } // Load configuration instance->config = parse_config(config_file); if (!instance->config) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to load config from %s", config_file); free(instance); return NULL; } // Open log file if (log_file) { instance->log_fp = fopen(log_file, "a"); if (!instance->log_fp) { DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to open log file %s: %s", log_file, strerror(errno)); } } // Set node_id from config instance->node_id = instance->config->global.my_node_id; // Set my keys if (sc_init_local_keys(&instance->my_keys, instance->config->global.my_public_key_hex, instance->config->global.my_private_key_hex)) { DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to initialize local keys"); } instance->pkt_pool=memory_pool_init(PACKET_DATA_SIZE+100); /* // Initialize TUN device if (tun_create(&instance->tun) < 0) { DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to create TUN device"); return -1; } // Configure TUN device if (tun_set_ip(instance->tun.ifname, instance->config->global.tun_ip) < 0) { DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to set TUN IP"); tun_close(&instance->tun); return -1; } if (instance->config->global.mtu > 0) { if (tun_set_mtu(instance->tun.ifname, instance->config->global.mtu) < 0) { DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to set TUN MTU"); tun_close(&instance->tun); return -1; } } if (tun_set_up(instance->tun.ifname) < 0) { DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to bring up TUN interface"); tun_close(&instance->tun); return -1; } // Create routing table instance->routing_table = routing_table_create(); if (!instance->routing_table) { DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to create routing table"); return -1; } */ // Initialize connections from configuration - moved to utun_instance_init // to avoid double initialization /* if (init_connections(instance) < 0) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to initialize connections"); // Cleanup will be handled by utun_instance_destroy return NULL; } */ return instance; } // Destroy instance and cleanup resources void utun_instance_destroy(struct UTUN_INSTANCE *instance) { if (!instance) return; printf("[INSTANCE_DESTROY] Starting cleanup for instance %p\n", instance); // Диагностика ресурсов ДО cleanup utun_instance_diagnose_leaks(instance, "BEFORE_CLEANUP"); // Stop running if not already instance->running = 0; // 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; while (sock) { struct ETCP_SOCKET* next = sock->next; DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Removing socket %p, fd=%d", sock, sock->fd); etcp_socket_remove(sock); // Полный cleanup сокета sock = next; } instance->etcp_sockets = NULL; DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] ETCP sockets cleanup complete"); struct ETCP_CONN* conn = instance->connections; while (conn) { struct ETCP_CONN* next = conn->next; DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Closing connection %p", conn); etcp_connection_close(conn); // Закрыть соединение conn = next; } instance->connections = NULL; DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] ETCP connections cleanup complete"); // Cleanup other components if (instance->routing_table) { DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Destroying routing table"); routing_table_destroy(instance->routing_table); instance->routing_table = NULL; } // Cleanup TUN if (instance->tun.fd >= 0) { DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Closing TUN interface"); tun_close(&instance->tun); } // Cleanup config if (instance->config) { DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Freeing configuration"); free_config(instance->config); instance->config = NULL; } // Close log file if (instance->log_fp) { DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Closing log file"); fclose(instance->log_fp); instance->log_fp = NULL; } // Cleanup packet pool (ensure no leak if stop wasn't called) if (instance->pkt_pool) { DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Destroying packet pool"); memory_pool_destroy(instance->pkt_pool); instance->pkt_pool = NULL; } // FINALLY destroy uasync (after all resources are cleaned up) if (instance->ua) { DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Destroying uasync instance"); uasync_destroy(instance->ua); instance->ua = NULL; } // Clear global instance if (g_instance == instance) { g_instance = NULL; } // Free the instance memory DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Freeing instance memory"); free(instance); DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Instance destroyed completely"); } // Stop instance void utun_instance_stop(struct UTUN_INSTANCE *instance) { if (!instance) return; instance->running = 0; // Wakeup main loop using built-in uasync wakeup if (instance->ua) { memory_pool_destroy(instance->pkt_pool); uasync_wakeup(instance->ua); } } int utun_instance_init(struct UTUN_INSTANCE *instance) { if (!instance) return -1; // Initialize connections if (init_connections(instance) < 0) { return -1; } return 0; } // Диагностическая функция для анализа утечек void utun_instance_diagnose_leaks(struct UTUN_INSTANCE *instance, const char *phase) { if (!instance) { printf("[DIAGNOSE] NULL instance for phase: %s\n", phase); return; } struct { int etcp_sockets_count; int etcp_connections_count; int etcp_links_count; } report = {0}; // Подсчёт ETCP сокетов struct ETCP_SOCKET *sock = instance->etcp_sockets; while (sock) { report.etcp_sockets_count++; // Подсчёт линков в каждом сокете for (size_t i = 0; i < sock->num_channels; i++) { if (sock->links[i]) { report.etcp_links_count++; } } sock = sock->next; } // Подсчёт ETCP соединений struct ETCP_CONN *conn = instance->connections; while (conn) { report.etcp_connections_count++; // Подсчёт линков в соединениях struct ETCP_LINK *link = conn->links; while (link) { report.etcp_links_count++; link = link->next; } conn = conn->next; } printf("\n🔍 [UTUN_INSTANCE LEAK DIAGNOSIS] Phase: %s\n", phase); printf(" Instance: %p\n", instance); printf(" Node ID: %llu\n", (unsigned long long)instance->node_id); printf(" UA instance: %p\n", instance->ua); printf(" Running: %d\n", instance->running); printf("\n📊 STRUCTURE COUNTS:\n"); printf(" ETCP Sockets: %d active\n", report.etcp_sockets_count); printf(" ETCP Connections: %d active\n", report.etcp_connections_count); printf(" ETCP Links: %d total\n", report.etcp_links_count); 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(" Connections list: %p\n", instance->connections); printf(" ETCP Sockets list: %p\n", instance->etcp_sockets); printf("\n⚠️ POTENTIAL LEAKS:\n"); if (instance->pkt_pool) { printf(" ❌ Memory Pool not freed\n"); } if (instance->tun_socket_id) { printf(" ❌ TUN socket not unregistered from uasync\n"); } if (report.etcp_sockets_count > 0) { printf(" ❌ %d ETCP sockets still allocated\n", report.etcp_sockets_count); } if (report.etcp_connections_count > 0) { printf(" ❌ %d ETCP connections still allocated\n", report.etcp_connections_count); } if (report.etcp_links_count > 0) { printf(" ❌ %d ETCP links still allocated\n", report.etcp_links_count); } printf("\n📋 RECOMMENDATIONS:\n"); 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 (report.etcp_sockets_count > 0) { printf(" → Iterate and call etcp_socket_remove() for each socket\n"); } if (report.etcp_connections_count > 0) { printf(" → Iterate and call etcp_connection_close() for each connection\n"); } printf("\n"); }