From f2c10dcbf93dc7e02182c58c9cc1fdddfe35ac13 Mon Sep 17 00:00:00 2001 From: jek Date: Thu, 15 Jan 2026 17:13:15 +0300 Subject: [PATCH] Reorganize project structure: move sources to src/, update Makefile, add header symlinks --- .gitignore | 8 +- Makefile | 128 +++++++--- changelog.txt | 7 + config_parser.h | 118 +-------- connection.h | 130 +--------- control_socket.h | 209 +--------------- etcp.h | 235 +----------------- ll_queue.h | 142 +---------- monitor.py | 2 +- pkt_normalizer.h | 76 +----- routing.h | 171 +------------ sc_lib.h | 120 +-------- settings.h | 12 +- config_parser.c => src/config_parser.c | 0 src/config_parser.h | 117 +++++++++ connection.c => src/connection.c | 0 src/connection.h | 129 ++++++++++ control_socket.c => src/control_socket.c | 0 src/control_socket.h | 208 ++++++++++++++++ etcp.c => src/etcp.c | 0 src/etcp.h | 234 +++++++++++++++++ ll_queue.c => src/ll_queue.c | 0 src/ll_queue.h | 141 +++++++++++ pkt_normalizer.c => src/pkt_normalizer.c | 0 src/pkt_normalizer.h | 75 ++++++ routing.c => src/routing.c | 0 src/routing.h | 170 +++++++++++++ sc_lib.c => src/sc_lib.c | 0 src/sc_lib.h | 119 +++++++++ settings.c => src/settings.c | 0 src/settings.h | 11 + timeout_heap.c => src/timeout_heap.c | 0 src/timeout_heap.h | 92 +++++++ tun_if.c => src/tun_if.c | 0 src/tun_if.h | 95 +++++++ u_async.c => src/u_async.c | 0 src/u_async.h | 47 ++++ utun.c => src/utun.c | 0 src/utun_state.h | 30 +++ timeout_heap.h | 93 +------ todo.txt | 1 - tun_if.h | 96 +------ u_async.c.backup | 304 ----------------------- u_async.h | 48 +--- utun_state.h | 31 +-- 45 files changed, 1593 insertions(+), 1806 deletions(-) mode change 100644 => 120000 config_parser.h mode change 100644 => 120000 connection.h mode change 100644 => 120000 control_socket.h mode change 100644 => 120000 etcp.h mode change 100644 => 120000 ll_queue.h mode change 100644 => 120000 pkt_normalizer.h mode change 100644 => 120000 routing.h mode change 100644 => 120000 sc_lib.h mode change 100644 => 120000 settings.h rename config_parser.c => src/config_parser.c (100%) create mode 100644 src/config_parser.h rename connection.c => src/connection.c (100%) create mode 100644 src/connection.h rename control_socket.c => src/control_socket.c (100%) create mode 100644 src/control_socket.h rename etcp.c => src/etcp.c (100%) create mode 100644 src/etcp.h rename ll_queue.c => src/ll_queue.c (100%) create mode 100644 src/ll_queue.h rename pkt_normalizer.c => src/pkt_normalizer.c (100%) create mode 100644 src/pkt_normalizer.h rename routing.c => src/routing.c (100%) create mode 100644 src/routing.h rename sc_lib.c => src/sc_lib.c (100%) create mode 100644 src/sc_lib.h rename settings.c => src/settings.c (100%) create mode 100644 src/settings.h rename timeout_heap.c => src/timeout_heap.c (100%) create mode 100644 src/timeout_heap.h rename tun_if.c => src/tun_if.c (100%) create mode 100644 src/tun_if.h rename u_async.c => src/u_async.c (100%) create mode 100644 src/u_async.h rename utun.c => src/utun.c (100%) create mode 100644 src/utun_state.h mode change 100644 => 120000 timeout_heap.h delete mode 100755 todo.txt mode change 100644 => 120000 tun_if.h delete mode 100644 u_async.c.backup mode change 100644 => 120000 u_async.h mode change 100644 => 120000 utun_state.h diff --git a/.gitignore b/.gitignore index e146f711..0c03badb 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,10 @@ tinycrypt/tests/*.o # OS files .DS_Store -Thumbs.db \ No newline at end of file +Thumbs.db + +# Header symlinks (headers are in src/) +/*.h + +# Build directories +/obj/ \ No newline at end of file diff --git a/Makefile b/Makefile index 42610ec9..df770654 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,15 @@ CC := gcc CFLAGS := -Os -std=c99 -Wall -Wextra -D_ISOC99_SOURCE -DENABLE_TESTS -DETCP_DEBUG -DETCP_DEBUG_EXT -INCLUDES := -Itinycrypt/lib/include/ -Itinycrypt/lib/source/ -Itinycrypt/tests/include/ -I. +SRC_DIR := src TEST_DIR := tests +INCLUDES := -I$(SRC_DIR) -Itinycrypt/lib/include/ -Itinycrypt/lib/source/ -Itinycrypt/tests/include/ -I. +# Директории для объектных файлов +OBJ_DIR := obj +SRC_OBJ_DIR := $(OBJ_DIR)/src +TEST_OBJ_DIR := $(OBJ_DIR)/tests + +# Исходники tinycrypt TINYCRYPT_SRCS := \ tinycrypt/lib/source/ecc.c \ tinycrypt/lib/source/ecc_dh.c \ @@ -13,65 +20,124 @@ TINYCRYPT_SRCS := \ tinycrypt/lib/source/ctr_mode.c \ tinycrypt/lib/source/ccm_mode.c +# Объектные файлы tinycrypt (остаются в своих директориях) TINYCRYPT_OBJS := $(TINYCRYPT_SRCS:.c=.o) -SC_LIB_OBJS := sc_lib.o -UASYNC_OBJS := u_async.o timeout_heap.o -PN_OBJS := pkt_normalizer.o settings.o -LL_QUEUE_OBJS := ll_queue.o -ETCP_OBJS := etcp.o -CONFIG_PARSER_OBJS := config_parser.o -TUN_IF_OBJS := tun_if.o - -all: utun $(TEST_DIR)/test_sc_lib $(TEST_DIR)/test_udp_secure $(TEST_DIR)/test_pkt_normalizer $(TEST_DIR)/test_etcp $(TEST_DIR)/test_etcp_stress $(TEST_DIR)/test_etcp_simple $(TEST_DIR)/test_connection $(TEST_DIR)/test_connection_stress $(TEST_DIR)/test_new_features $(TEST_DIR)/test_utun_integration $(TEST_DIR)/test_utun_fork +# Основные объектные файлы (будут в obj/src/) +SC_LIB_OBJS := $(SRC_OBJ_DIR)/sc_lib.o +UASYNC_OBJS := $(SRC_OBJ_DIR)/u_async.o $(SRC_OBJ_DIR)/timeout_heap.o +PN_OBJS := $(SRC_OBJ_DIR)/pkt_normalizer.o $(SRC_OBJ_DIR)/settings.o +LL_QUEUE_OBJS := $(SRC_OBJ_DIR)/ll_queue.o +ETCP_OBJS := $(SRC_OBJ_DIR)/etcp.o +CONFIG_PARSER_OBJS := $(SRC_OBJ_DIR)/config_parser.o +TUN_IF_OBJS := $(SRC_OBJ_DIR)/tun_if.o +CONNECTION_OBJS := $(SRC_OBJ_DIR)/connection.o +ROUTING_OBJS := $(SRC_OBJ_DIR)/routing.o +CONTROL_SOCKET_OBJS := $(SRC_OBJ_DIR)/control_socket.o +UTUN_OBJS := $(SRC_OBJ_DIR)/utun.o + +# Тестовые объектные файлы (будут в obj/tests/) +TEST_PKT_NORMALIZER_OBJS := $(TEST_OBJ_DIR)/test_pkt_normalizer.o +TEST_ETCP_OBJS := $(TEST_OBJ_DIR)/test_etcp.o +TEST_ETCP_STRESS_OBJS := $(TEST_OBJ_DIR)/test_etcp_stress.o +TEST_ETCP_SIMPLE_OBJS := $(TEST_OBJ_DIR)/test_etcp_simple.o +TEST_CONNECTION_OBJS := $(TEST_OBJ_DIR)/test_connection.o +TEST_CONNECTION_STRESS_OBJS := $(TEST_OBJ_DIR)/test_connection_stress.o +TEST_NEW_FEATURES_OBJS := $(TEST_OBJ_DIR)/test_new_features.o +TEST_SC_LIB_OBJS := $(TEST_OBJ_DIR)/test_sc_lib.o +TEST_UDP_SECURE_OBJS := $(TEST_OBJ_DIR)/test_udp_secure.o +TEST_UTUN_INTEGRATION_OBJS := $(TEST_OBJ_DIR)/test_utun_integration.o +TEST_UTUN_FORK_OBJS := $(TEST_OBJ_DIR)/test_utun_fork.o +SIMPLE_UASYNC_OBJS := $(TEST_OBJ_DIR)/simple_uasync.o + +# Основная цель +all: utun \ + $(TEST_DIR)/test_sc_lib \ + $(TEST_DIR)/test_udp_secure \ + $(TEST_DIR)/test_pkt_normalizer \ + $(TEST_DIR)/test_etcp \ + $(TEST_DIR)/test_etcp_stress \ + $(TEST_DIR)/test_etcp_simple \ + $(TEST_DIR)/test_connection \ + $(TEST_DIR)/test_connection_stress \ + $(TEST_DIR)/test_new_features \ + $(TEST_DIR)/test_utun_integration \ + $(TEST_DIR)/test_utun_fork + +# Создание директорий +$(OBJ_DIR): + mkdir -p $(OBJ_DIR) + +$(SRC_OBJ_DIR): $(OBJ_DIR) + mkdir -p $(SRC_OBJ_DIR) + +$(TEST_OBJ_DIR): $(OBJ_DIR) + mkdir -p $(TEST_OBJ_DIR) + +# Правило компиляции для исходников из src/ +$(SRC_OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(SRC_OBJ_DIR) + $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ -$(TEST_DIR)/test_pkt_normalizer: $(TEST_DIR)/test_pkt_normalizer.o $(PN_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) - $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ +# Правило компиляции для тестовых .c файлов +$(TEST_OBJ_DIR)/%.o: $(TEST_DIR)/%.c | $(TEST_OBJ_DIR) + $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ -$(TEST_DIR)/test_etcp: $(TEST_DIR)/test_etcp.o $(ETCP_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) - $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ +# Правило компиляции для tinycrypt (оставляем в оригинальных директориях) +tinycrypt/lib/source/%.o: tinycrypt/lib/source/%.c + $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ -$(TEST_DIR)/test_etcp_stress: $(TEST_DIR)/test_etcp_stress.o $(ETCP_OBJS) $(LL_QUEUE_OBJS) $(TEST_DIR)/simple_uasync.o +# Правила линковки +utun: $(UTUN_OBJS) $(CONFIG_PARSER_OBJS) $(TUN_IF_OBJS) $(CONNECTION_OBJS) $(ROUTING_OBJS) $(CONTROL_SOCKET_OBJS) $(ETCP_OBJS) $(PN_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ -$(TEST_DIR)/test_etcp_simple: $(TEST_DIR)/test_etcp_simple.o $(ETCP_OBJS) $(LL_QUEUE_OBJS) $(TEST_DIR)/simple_uasync.o +$(TEST_DIR)/test_pkt_normalizer: $(TEST_PKT_NORMALIZER_OBJS) $(PN_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ -$(TEST_DIR)/test_connection: $(TEST_DIR)/test_connection.o connection.o $(ETCP_OBJS) $(PN_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) +$(TEST_DIR)/test_etcp: $(TEST_ETCP_OBJS) $(ETCP_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ -$(TEST_DIR)/test_connection_stress: $(TEST_DIR)/test_connection_stress.o connection.o $(ETCP_OBJS) $(PN_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) +$(TEST_DIR)/test_etcp_stress: $(TEST_ETCP_STRESS_OBJS) $(ETCP_OBJS) $(LL_QUEUE_OBJS) $(SIMPLE_UASYNC_OBJS) $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ -$(TEST_DIR)/test_new_features: $(TEST_DIR)/test_new_features.o $(ETCP_OBJS) $(PN_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) connection.o $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) +$(TEST_DIR)/test_etcp_simple: $(TEST_ETCP_SIMPLE_OBJS) $(ETCP_OBJS) $(LL_QUEUE_OBJS) $(SIMPLE_UASYNC_OBJS) $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ -utun: utun.o $(CONFIG_PARSER_OBJS) $(TUN_IF_OBJS) connection.o routing.o control_socket.o $(ETCP_OBJS) $(PN_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) +$(TEST_DIR)/test_connection: $(TEST_CONNECTION_OBJS) $(CONNECTION_OBJS) $(ETCP_OBJS) $(PN_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ -$(TEST_DIR)/test_sc_lib: $(TEST_DIR)/test_sc_lib.o $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) +$(TEST_DIR)/test_connection_stress: $(TEST_CONNECTION_STRESS_OBJS) $(CONNECTION_OBJS) $(ETCP_OBJS) $(PN_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ -$(TEST_DIR)/test_udp_secure: $(TEST_DIR)/test_udp_secure.o $(SC_LIB_OBJS) $(UASYNC_OBJS) $(TINYCRYPT_OBJS) +$(TEST_DIR)/test_new_features: $(TEST_NEW_FEATURES_OBJS) $(ETCP_OBJS) $(PN_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) $(CONNECTION_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ -$(TEST_DIR)/test_utun_integration: $(TEST_DIR)/test_utun_integration.o $(CONFIG_PARSER_OBJS) $(TUN_IF_OBJS) connection.o $(ETCP_OBJS) $(PN_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) +$(TEST_DIR)/test_sc_lib: $(TEST_SC_LIB_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ -$(TEST_DIR)/test_utun_fork: $(TEST_DIR)/test_utun_fork.o $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) +$(TEST_DIR)/test_udp_secure: $(TEST_UDP_SECURE_OBJS) $(SC_LIB_OBJS) $(UASYNC_OBJS) $(TINYCRYPT_OBJS) $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ -$(TEST_DIR)/test_pkt_normalizer: $(TEST_DIR)/test_pkt_normalizer.o $(PN_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) +$(TEST_DIR)/test_utun_integration: $(TEST_UTUN_INTEGRATION_OBJS) $(CONFIG_PARSER_OBJS) $(TUN_IF_OBJS) $(CONNECTION_OBJS) $(ETCP_OBJS) $(PN_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ -$(TEST_DIR)/test_etcp: $(TEST_DIR)/test_etcp.o $(ETCP_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) +$(TEST_DIR)/test_utun_fork: $(TEST_UTUN_FORK_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ -%.o: %.c - $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ - +# Очистка clean: - rm -f utun $(TEST_DIR)/test_sc_lib $(TEST_DIR)/test_udp_secure $(TEST_DIR)/test_pkt_normalizer $(TEST_DIR)/test_etcp $(TEST_DIR)/test_etcp_stress $(TEST_DIR)/test_etcp_simple $(TEST_DIR)/test_connection $(TEST_DIR)/test_connection_stress $(TEST_DIR)/test_new_features $(TEST_DIR)/test_utun_integration $(TEST_DIR)/test_utun_fork \ - *.o tinycrypt/lib/source/*.o $(TEST_DIR)/*.o + rm -rf $(OBJ_DIR) + rm -f utun \ + $(TEST_DIR)/test_sc_lib \ + $(TEST_DIR)/test_udp_secure \ + $(TEST_DIR)/test_pkt_normalizer \ + $(TEST_DIR)/test_etcp \ + $(TEST_DIR)/test_etcp_stress \ + $(TEST_DIR)/test_etcp_simple \ + $(TEST_DIR)/test_connection \ + $(TEST_DIR)/test_connection_stress \ + $(TEST_DIR)/test_new_features \ + $(TEST_DIR)/test_utun_integration \ + $(TEST_DIR)/test_utun_fork + rm -f *.o $(TEST_DIR)/*.o tinycrypt/lib/source/*.o .PHONY: all clean \ No newline at end of file diff --git a/changelog.txt b/changelog.txt index 9f7324a8..b6e18b9a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -46,3 +46,10 @@ Thu Jan 15 2026 21:30: Добавление детектора утечек па - Добавлена проверка утечек в uasync_destroy с аварийным завершением при обнаружении неосвобожденных ресурсов после очистки - Исправлен подсчет освобождений: теперь все таймеры учитываются правильно - Все тесты проходят, утечки не обнаруживаются после очистки + +Thu Jan 15 2026 17:09: Реорганизация структуры проекта и обновление Makefile +- Исходные файлы перемещены в каталог src/ +- Обновлен Makefile для сборки объектных файлов в obj/src и obj/tests +- Добавлены символические ссылки на заголовочные файлы в корне для совместимости с тестами +- Обновлены пути включения заголовков (-Isrc) +- Все цели сборки работают корректно diff --git a/config_parser.h b/config_parser.h deleted file mode 100644 index 6f776b30..00000000 --- a/config_parser.h +++ /dev/null @@ -1,117 +0,0 @@ -// config_parser.h - Configuration parser for utun application -#ifndef CONFIG_PARSER_H -#define CONFIG_PARSER_H - -#include -#include -#include "connection.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// Maximum lengths for strings in config -#define MAX_CONN_NAME_LEN 64 -#define MAX_KEY_LEN 256 // HEX key length (64 bytes * 2 chars + null) -#define MAX_ADDR_LEN 64 -#define MAX_NETIF_LEN 16 -#define MAX_OPTION_VALUE_LEN 256 -#define MAX_ALLOWED_SUBNETS 32 - -// Connection mode (config parser internal) -typedef enum { - CONFIG_MODE_UNKNOWN = 0, - CONFIG_MODE_CLIENT, - CONFIG_MODE_SERVER -} config_conn_mode_t; - -// Subnet entry for allowed routing -typedef struct { - char subnet[MAX_ADDR_LEN]; // Format: "192.168.0.0/24" -} subnet_entry_t; - -// Connection configuration -typedef struct { - char name[MAX_CONN_NAME_LEN]; // Connection name from [connection: name] - config_conn_mode_t mode; // server or client - char local_addr[MAX_ADDR_LEN]; // For client: from_addr, for server: addr - char remote_addr[MAX_ADDR_LEN]; // For client: to_addr, for server: N/A - char peer_public_key_hex[MAX_KEY_LEN]; // Peer's public key in HEX - int so_mark; // Socket mark (0 = not set) - char netif[MAX_NETIF_LEN]; // Network interface to bind to - char tun_ifname[MAX_NETIF_LEN]; // TUN interface name (e.g., tun12) - char tun_ip[MAX_ADDR_LEN]; // TUN interface IP address (e.g., 10.0.0.1/24) -} connection_config_t; - -// Global configuration -typedef struct { - char my_private_key_hex[MAX_KEY_LEN]; // Our private key in HEX - char my_public_key_hex[MAX_KEY_LEN]; // Our public key in HEX - char option_value[MAX_OPTION_VALUE_LEN]; // Global option value - char control_ip[MAX_ADDR_LEN]; // Control socket IP (empty for disabled) - uint16_t control_port; // Control socket port - int net_debug; // Network debug mode: 1 = enable network emulator -} global_config_t; - -// Complete configuration -typedef struct { - global_config_t global; - connection_config_t *connections; - int connection_count; - int connection_capacity; - subnet_entry_t allowed_subnets[MAX_ALLOWED_SUBNETS]; - int allowed_subnet_count; -} utun_config_t; - -/** - * @brief Parse configuration file - * @param filename Path to configuration file - * @return Pointer to parsed configuration, NULL on error - * - * Parses INI-style configuration file with format: - * [global] - * option=value - * my_private_key=HEX - * my_public_key=HEX - * - * [connection: name] - * mode=server|client - * addr=ip:port (for server) - * from_addr=ip:port (for client) - * to_addr=ip:port (for client) - * peer_public_key=HEX - * so_mark=number - * netif=interface_name - */ -utun_config_t* parse_config(const char *filename); - -/** - * @brief Free configuration structure - * @param config Configuration to free - */ -void free_config(utun_config_t *config); - -/** - * @brief Print configuration for debugging - * @param config Configuration to print - */ -void print_config(const utun_config_t *config); - -/** - * @brief Update keys in configuration file - * @param filename Path to configuration file - * @param private_key_hex Private key in HEX format - * @param public_key_hex Public key in HEX format - * @return 0 on success, -1 on error - * - * Updates or adds my_private_key and my_public_key lines in [global] section - */ -int update_config_keys(const char *filename, - const char *private_key_hex, - const char *public_key_hex); - -#ifdef __cplusplus -} -#endif - -#endif /* CONFIG_PARSER_H */ \ No newline at end of file diff --git a/config_parser.h b/config_parser.h new file mode 120000 index 00000000..5966bbeb --- /dev/null +++ b/config_parser.h @@ -0,0 +1 @@ +src/config_parser.h \ No newline at end of file diff --git a/connection.h b/connection.h deleted file mode 100644 index e17d5181..00000000 --- a/connection.h +++ /dev/null @@ -1,129 +0,0 @@ -// connection.h - Минималистичный API для защищенных UDP подключений -#ifndef CONNECTION_H -#define CONNECTION_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* Непрозрачный дескриптор подключения */ -typedef struct conn_handle conn_handle_t; - -/* Forward declaration для uasync */ -typedef struct uasync_s uasync_t; - -/* Режим подключения */ -typedef enum { - CONN_MODE_CLIENT, /* Инициируем подключение к указанному удаленному адресу */ - CONN_MODE_SERVER /* Ожидаем входящие подключения */ -} conn_mode_t; - -/* Callback для входящих данных */ -typedef void (*conn_recv_callback_t)(conn_handle_t* conn, - const uint8_t* data, - size_t len, - void* user_data); - -/* - * Создание дескриптора подключения (только выделение памяти). - * ua - экземпляр uasync для таймеров (обязательный параметр) - * Возвращает NULL при ошибке. - */ -conn_handle_t* conn_create(uasync_t* ua); - -/* - * Установка криптографических ключей. - * Должна быть вызвана до conn_connect(). - * - * @param conn Дескриптор подключения - * @param my_pub_key Публичный ключ (64 байта для secp256r1), NULL для авто-генерации - * @param my_priv_key Приватный ключ (32 байта), NULL для авто-генерации - * @param peer_pub_key Публичный ключ пира (64 байта), NULL для сервера (получит из первого пакета) - * - * @return 0 при успехе, -1 при ошибке - */ -int conn_set_keys(conn_handle_t* conn, - const uint8_t* my_pub_key, - const uint8_t* my_priv_key, - const uint8_t* peer_pub_key); - -/* - * Подключение к удаленному узлу или начало ожидания входящих подключений. - * - * @param conn Дескриптор подключения - * @param local_ip Локальный IP для bind (NULL для "0.0.0.0") - * @param local_port Локальный порт (0 для авто-выбора) - * @param remote_ip Удаленный IP (NULL для серверного режима) - * @param remote_port Удаленный порт (игнорируется если remote_ip NULL) - * @param mode Режим подключения (CONN_MODE_CLIENT/SERVER) - * - * @return 0 при успехе, -1 при ошибке - */ -int conn_connect(conn_handle_t* conn, - const char* local_ip, - uint16_t local_port, - const char* remote_ip, - uint16_t remote_port, - conn_mode_t mode); - -/* - * Установка callback'а для входящих данных. - * Callback будет вызываться при получении полных собранных пакетов. - */ -void conn_set_recv_callback(conn_handle_t* conn, - conn_recv_callback_t callback, - void* user_data); - -/* - * Отправка данных. - * Данные будут автоматически фрагментированы, зашифрованы и отправлены. - * - * @return 0 при успехе, -1 при ошибке - */ -int conn_send(conn_handle_t* conn, const uint8_t* data, size_t len); - -/* - * Закрытие подключения (немедленное, без протокола завершения). - * После вызова дескриптор можно уничтожить через conn_destroy(). - */ -void conn_close(conn_handle_t* conn); - -/* - * Сброс соединения с использованием служебных пакетов. - * Отправляет пакет сброса через ETCP и сбрасывает состояние всех компонентов. - * Предназначено для тестирования и восстановления после сбоев. - */ -void conn_reset(conn_handle_t* conn); - -/* - * Полное уничтожение дескриптора подключения и освобождение всех ресурсов. - * Автоматически вызывает conn_close() если подключение активно. - */ -void conn_destroy(conn_handle_t* conn); - -/* - * Получение статистики подключения (опционально). - * - * @return 0 при успехе, -1 при ошибке - */ -typedef struct { - uint64_t bytes_sent; - uint64_t bytes_received; - uint32_t packets_sent; - uint32_t packets_received; - uint32_t retransmissions; - uint32_t fragments_assembled; - uint16_t current_rtt_ms; /* Текущее RTT в миллисекундах */ - uint16_t jitter_ms; /* Джиттер в миллисекундах */ -} conn_stats_t; - -int conn_get_stats(conn_handle_t* conn, conn_stats_t* stats); - -#ifdef __cplusplus -} -#endif - -#endif /* CONNECTION_H */ \ No newline at end of file diff --git a/connection.h b/connection.h new file mode 120000 index 00000000..087b7bc1 --- /dev/null +++ b/connection.h @@ -0,0 +1 @@ +src/connection.h \ No newline at end of file diff --git a/control_socket.h b/control_socket.h deleted file mode 100644 index 4a0e2ad6..00000000 --- a/control_socket.h +++ /dev/null @@ -1,208 +0,0 @@ -/** - * @file control_socket.h - * @brief Control socket for statistics and diagnostics over UDP - * @details Provides remote monitoring of utun VPN tunnel statistics - */ - -#ifndef CONTROL_SOCKET_H -#define CONTROL_SOCKET_H - -#include -#include -#include - -// Forward declarations for application state -struct utun_state; - -#ifdef __cplusplus -extern "C" { -#endif - -// Maximum connections for statistics -#define MAX_CONN_STATS 16 -#define MAX_ROUTE_STATS 100 - -// Control socket command types -typedef enum { - CONTROL_CMD_GET_STATS = 1, // Request statistics - CONTROL_CMD_RESET_STATS = 2, // Reset statistics counters - CONTROL_CMD_GET_STATUS = 3, // Request status information -} control_cmd_t; - -// Response types -typedef enum { - CONTROL_RESP_STATS = 1, // Statistics response - CONTROL_RESP_STATUS = 2, // Status response - CONTROL_RESP_ERROR = 0xFF, // Error response -} control_resp_t; - -// Error codes -typedef enum { - CONTROL_ERR_NONE = 0, - CONTROL_ERR_INVALID_CMD = 1, - CONTROL_ERR_INTERNAL = 2, -} control_err_t; - -// Packet normalizer statistics -typedef struct __attribute__((packed)) { - uint32_t packer_errors; // Packer error count - uint32_t unpacker_errors; // Unpacker error count - uint32_t fragments_assembled; // Fragments assembled successfully - uint32_t service_packets; // Service packets processed -} pkt_normalizer_stats_t; - -// ETCP statistics -typedef struct __attribute__((packed)) { - uint32_t retransmissions; // Retransmission count - uint32_t total_packets_sent; // Total packets sent (including retransmissions) - uint32_t unique_packets_sent; // Unique packets sent (excluding retransmissions) - uint32_t bytes_sent_total; // Total bytes sent - uint32_t bytes_received_total;// Total bytes received - uint32_t ack_packets_count; // ACK packets sent - uint32_t control_packets_count; // Control packets sent - uint16_t current_rtt; // Current RTT (0.1ms units) - uint16_t jitter; // Jitter (0.1ms units) - uint32_t window_size; // Current window size (bytes) - uint32_t unacked_bytes; // Unacknowledged bytes in flight -} etcp_stats_t; - -// Connection statistics -typedef struct __attribute__((packed)) { - uint64_t bytes_sent; - uint64_t bytes_received; - uint32_t packets_sent; - uint32_t packets_received; - uint32_t retransmissions; - uint32_t fragments_assembled; - uint16_t current_rtt_ms; - uint16_t jitter_ms; - uint8_t is_active; // 1 if connection is active - char name[32]; // Connection name from config -} conn_stats_entry_t; - -// Routing statistics -typedef struct __attribute__((packed)) { - uint32_t total_routes; // Total routes in table - uint32_t static_routes; // Static routes count - uint32_t dynamic_routes; // Dynamic routes count - uint32_t local_routes; // Local routes count - uint32_t learned_routes; // Learned routes count - uint32_t lookup_count; // Total lookups performed - uint32_t hit_count; // Successful lookups - uint32_t miss_count; // Failed lookups (no route) -} routing_stats_t; - -// TUN interface statistics -typedef struct __attribute__((packed)) { - 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 - char ifname[16]; // Interface name - char ip_addr[32]; // IP address with prefix -} tun_stats_t; - -// System status -typedef struct __attribute__((packed)) { - uint32_t uptime_seconds; // Seconds since startup - uint32_t memory_usage_kb; // Memory usage in KB (approximate) - uint16_t cpu_usage_percent; // CPU usage percentage (0-100) - uint8_t running; // 1 if main loop is running - uint8_t connection_count; // Number of active connections - uint16_t control_port; // Control socket port - char version[32]; // Version string -} system_status_t; - -// Complete statistics packet -typedef struct __attribute__((packed)) { - uint8_t response_type; // CONTROL_RESP_STATS - uint8_t error_code; // CONTROL_ERR_NONE if success - uint16_t sequence; // Sequence number (echoed from request) - - // Timestamps - uint64_t timestamp; // Unix timestamp in microseconds - - // Module statistics - pkt_normalizer_stats_t pkt_normalizer; - etcp_stats_t etcp; - routing_stats_t routing; - tun_stats_t tun; - - // Connection statistics (variable length, up to MAX_CONN_STATS) - uint8_t conn_count; // Number of connection entries - conn_stats_entry_t connections[MAX_CONN_STATS]; - - // System status - system_status_t system; - - // Reserved for future expansion - uint8_t reserved[64]; -} control_stats_packet_t; - -// Status response packet -typedef struct __attribute__((packed)) { - uint8_t response_type; // CONTROL_RESP_STATUS - uint8_t error_code; // CONTROL_ERR_NONE if success - uint16_t sequence; // Sequence number - - system_status_t system; - uint8_t running; // Main loop running flag - char status_msg[128]; // Human-readable status message -} control_status_packet_t; - -// Request packet (from client) -typedef struct __attribute__((packed)) { - uint8_t command; // CONTROL_CMD_* - uint16_t sequence; // Sequence number for response matching - uint8_t reserved; // Reserved, must be 0 -} control_request_packet_t; - -// Control socket handle (opaque) -typedef struct control_socket control_socket_t; - -/** - * @brief Create and initialize control socket - * @param ip IP address to bind to (NULL for any) - * @param port UDP port to listen on - * @return Control socket handle or NULL on error - */ -control_socket_t* control_socket_create(const char *ip, uint16_t port); - -/** - * @brief Destroy control socket and free resources - * @param cs Control socket handle - */ -void control_socket_destroy(control_socket_t *cs); - -/** - * @brief Get file descriptor for polling - * @param cs Control socket handle - * @return Socket file descriptor or -1 if invalid - */ -int control_socket_get_fd(const control_socket_t *cs); - -/** - * @brief Process incoming control socket requests - * @param cs Control socket handle - * @param state Application state (for collecting statistics) - * @return 0 on success, -1 on error - * - * This function should be called when the socket is readable. - * It will handle incoming requests and send responses. - */ -int control_socket_process(control_socket_t *cs, void *state); - -/** - * @brief Set application state pointer for statistics collection - * @param cs Control socket handle - * @param state Application state (utun_state_t*) - */ -void control_socket_set_state(control_socket_t *cs, void *state); - -#ifdef __cplusplus -} -#endif - -#endif /* CONTROL_SOCKET_H */ \ No newline at end of file diff --git a/control_socket.h b/control_socket.h new file mode 120000 index 00000000..ef6b4c86 --- /dev/null +++ b/control_socket.h @@ -0,0 +1 @@ +src/control_socket.h \ No newline at end of file diff --git a/etcp.h b/etcp.h deleted file mode 100644 index 3a510533..00000000 --- a/etcp.h +++ /dev/null @@ -1,234 +0,0 @@ -// etcp.h - Расширенный протокол управления передачей (Extended Transmission Control Protocol) -#ifndef ETCP_H -#define ETCP_H - -#include -#include -#include "ll_queue.h" -#include "u_async.h" - -// Отладочное логирование -#ifdef ETCP_DEBUG -#include -#define ETCP_LOG(fmt, ...) printf("[ETCP] " fmt, ##__VA_ARGS__) -#ifdef ETCP_DEBUG_EXT -#define ETCP_DEBUG_LOG(fmt, ...) printf("[ETCP_DEBUG] " fmt, ##__VA_ARGS__) -#else -#define ETCP_DEBUG_LOG(fmt, ...) ((void)0) -#endif -#else -#define ETCP_LOG(fmt, ...) ((void)0) -#define ETCP_DEBUG_LOG(fmt, ...) ((void)0) -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// Предварительные объявления -typedef struct epkt epkt_t; - -// Тип обратного вызова для отправки пакетов через UDP -typedef void (*etcp_tx_callback_t)(epkt_t* epkt, uint8_t* pkt, uint16_t len, void* arg); - -// Основная структура ETCP -struct epkt { - // Очереди - ll_queue_t* tx_queue; // Очередь данных для отправки - ll_queue_t* output_queue; // Выходная очередь (собранные данные) - - // Список полученных пакетов (отсортированный связанный список) - struct rx_packet* rx_list; - - // Отправленные пакеты (для повторной передачи) - struct sent_packet* sent_list; - - // Метрики - uint16_t rtt_last; // Последнее RTT (в единицах времени 0.1 мкс) - uint16_t rtt_avg_10; // Среднее RTT за последние 10 пакетов - uint16_t rtt_avg_100; // Среднее RTT за последние 100 пакетов - uint16_t jitter; // Джиттер (усредненный) - uint16_t bandwidth; // Текущая пропускная способность (байты за единицу времени) - uint32_t bytes_sent_total; // Общее количество отправленных байт - uint16_t last_sent_timestamp; // Временная метка последнего отправленного пакета - uint32_t bytes_allowed; // Рассчитанное количество разрешенных к отправке байт - - // Статистика - uint32_t retransmissions_count; // Количество ретрансмиссий - uint32_t ack_packets_count; // Количество отправленных пакетов подтверждения - uint32_t control_packets_count; // Количество отправленных управляющих пакетов (ACK + запросы ретрансмиссии) - uint32_t total_packets_sent; // Общее количество отправленных пакетов (включая ретрансмиссии) - uint32_t unique_packets_sent; // Количество уникальных отправленных пакетов (без ретрансмиссий) - uint32_t bytes_received_total; // Общее количество полученных байт - - // Состояние - uint16_t next_tx_id; // Следующий ID для передачи - uint16_t last_sent_id; // Последний отправленный ID (для ретрансмиссии самого нового пакета) - uint16_t last_rx_id; // Последний полученный ID (для подтверждения) - uint16_t last_delivered_id; // Последний ID, переданный в output_queue - - // Таймеры - void* next_tx_timer; // Таймер для следующей передачи - void* retransmit_timer; // Таймер для повторных передач - uasync_t* ua; // Экземпляр uasync для таймеров - - // Обратный вызов - etcp_tx_callback_t tx_callback; - void* tx_callback_arg; - - // История RTT для усреднения - uint16_t rtt_history[100]; - uint8_t rtt_history_idx; - uint8_t rtt_history_count; - - // Ожидающие подтверждения - uint16_t pending_ack_ids[32]; - uint16_t pending_ack_timestamps[32]; - uint8_t pending_ack_count; - - // Ожидающие запросы на повторную передачу - uint16_t pending_retransmit_ids[32]; - uint8_t pending_retransmit_count; - - // Управление окном - uint32_t unacked_bytes; // Количество байт, отправленных но еще не подтвержденных - uint32_t window_size; // Текущий размер окна в байтах (рассчитывается) - uint16_t last_acked_id; // Последний подтвержденный ID пакета - uint16_t last_rx_ack_id; // Последний полученный ID подтверждения от получателя - uint16_t retrans_timer_period; // Текущий период таймера повторной передачи (в единицах времени) - uint16_t next_retrans_time; // Время следующей проверки повторной передачи - uint8_t window_blocked; // Флаг: передача заблокирована из-за ограничения окна - - // Forward progress tracking - uint16_t oldest_missing_id; // Oldest missing packet ID - uint16_t missing_since_time; // Time when oldest missing packet was first detected - - // Reset state - uint8_t reset_pending; // Reset packet sent, waiting for ACK - uint8_t reset_ack_received; // Reset ACK received - void* reset_timer; // Timer for reset retransmission - uint16_t reset_retry_count; // Number of reset retries -}; - -// Функции API - -/** - * @brief Инициализировать новый экземпляр ETCP - * @param ua Экземпляр uasync для таймеров (обязательный параметр) - * @return Указатель на новый экземпляр или NULL в случае ошибки - */ -epkt_t* etcp_init(uasync_t* ua); - -/** - * @brief Освободить экземпляр ETCP и все связанные ресурсы - * @param epkt Экземпляр для освобождения - */ -void etcp_free(epkt_t* epkt); - -/** - * @brief Установить обратный вызов для отправки пакетов через UDP - * @param epkt Экземпляр ETCP - * @param cb Функция обратного вызова - * @param arg Пользовательский аргумент, передаваемый в обратный вызов - */ -void etcp_set_callback(epkt_t* epkt, etcp_tx_callback_t cb, void* arg); - -/** - * @brief Обработать полученный UDP пакет - * @param epkt Экземпляр ETCP - * @param pkt Данные пакета - * @param len Длина пакета - * @return 0 при успехе, -1 при ошибке - */ -int etcp_rx_input(epkt_t* epkt, uint8_t* pkt, uint16_t len); - -/** - * @brief Получить общее количество пакетов, ожидающих в очередях передачи - * @param epkt Экземпляр ETCP - * @return Количество пакетов - */ -int etcp_tx_queue_size(epkt_t* epkt); - -/** - * @brief Поместить данные в очередь передачи - * @param epkt Экземпляр ETCP - * @param data Данные для отправки - * @param len Длина данных - * @return 0 при успехе, -1 при ошибке - */ -int etcp_tx_put(epkt_t* epkt, uint8_t* data, uint16_t len); - -/** - * @brief Получить выходную очередь для чтения полученных данных - * @param epkt Экземпляр ETCP - * @return Указатель на выходную очередь (ll_queue_t*) - */ -ll_queue_t* etcp_get_output_queue(epkt_t* epkt); - -/** - * @brief Установить ограничение пропускной способности - * @param epkt Экземпляр ETCP - * @param bandwidth Байты за единицу времени (0.1 мкс) - */ -void etcp_set_bandwidth(epkt_t* epkt, uint16_t bandwidth); - -/** - * @brief Обновить размер окна на основе текущего RTT и пропускной способности - * @param epkt Экземпляр ETCP - * Размер окна = RTT * пропускная способность * 2 (байт в пути) - */ -void etcp_update_window(epkt_t* epkt); - -/** - * @brief Получить текущее RTT - * @param epkt Экземпляр ETCP - * @return RTT в единицах времени - */ -uint16_t etcp_get_rtt(epkt_t* epkt); - -/** - * @brief Получить текущий джиттер - * @param epkt Экземпляр ETCP - * @return Джиттер в единицах времени - */ -uint16_t etcp_get_jitter(epkt_t* epkt); - -/** - * @brief Сбросить состояние соединения (очистить очереди, метрики, таймеры) - * @param epkt Экземпляр ETCP - * Примечание: Сохраняет настройки пропускной способности и обратного вызова - */ -void etcp_reset(epkt_t* epkt); - -/** - * @brief Инициировать сброс соединения через служебные пакеты - * @param epkt Экземпляр ETCP - * Отправляет пакет сброса (0x02) и ждет подтверждения (0x03) с повторными попытками каждые 100мс - */ -void etcp_reset_connection(epkt_t* epkt); - -/** - * @brief Получить статистику ETCP - * @param epkt Экземпляр ETCP - * @param retransmissions Указатель для возврата количества ретрансмиссий - * @param total_packets_sent Указатель для возврата общего количества отправленных пакетов - * @param unique_packets_sent Указатель для возврата количества уникальных отправленных пакетов - * @param bytes_sent_total Указатель для возврата общего количества отправленных байт - * @param bytes_received_total Указатель для возврата общего количества полученных байт - * @param ack_packets_count Указатель для возврата количества отправленных пакетов подтверждения - * @param control_packets_count Указатель для возврата количества отправленных управляющих пакетов - */ -void etcp_get_stats(epkt_t* epkt, - uint32_t* retransmissions, - uint32_t* total_packets_sent, - uint32_t* unique_packets_sent, - uint32_t* bytes_sent_total, - uint32_t* bytes_received_total, - uint32_t* ack_packets_count, - uint32_t* control_packets_count); - -#ifdef __cplusplus -} -#endif - -#endif // ETCP_H diff --git a/etcp.h b/etcp.h new file mode 120000 index 00000000..1705706e --- /dev/null +++ b/etcp.h @@ -0,0 +1 @@ +src/etcp.h \ No newline at end of file diff --git a/ll_queue.h b/ll_queue.h deleted file mode 100644 index 00cabaaf..00000000 --- a/ll_queue.h +++ /dev/null @@ -1,141 +0,0 @@ -#ifndef LL_QUEUE_H -#define LL_QUEUE_H - -#include // для size_t - -// Предварительные объявления -typedef struct ll_queue ll_queue_t; -typedef struct uasync_s uasync_t; -typedef struct ll_entry ll_entry_t; - -// Тип коллбэка: вызывается при добавлении элемента в пустую очередь или для продолжения обработки -// Параметры: указатель на очередь, указатель на элемент (первый в очереди), пользовательский аргумент -typedef void (*queue_callback_t)(ll_queue_t* q, ll_entry_t* entry, void* arg); - -// Структура элемента - переменный размер, данные расположены сразу после структуры -struct ll_entry { - struct ll_entry* next; // Указатель на следующий элемент в очереди - size_t size; // Размер данных элемента (байт) -}; - -// Структура условия ожидания (waiter) -struct queue_waiter { - int max_packets; // Максимальное количество пакетов - size_t max_bytes; // Максимальное количество байт - void (*callback)(ll_queue_t* q, void* arg); // Коллбэк для вызова - void* callback_arg; // Аргумент коллбэка - struct queue_waiter* next; // Следующий ожидающий в списке -}; - -typedef struct queue_waiter queue_waiter_t; -typedef void (*queue_threshold_callback_t)(ll_queue_t* q, void* arg); - -// Структура очереди -struct ll_queue { - ll_entry_t* head; // Первый элемент (извлекается отсюда) - ll_entry_t* tail; // Последний элемент (добавляется сюда) - int count; // Текущее количество элементов - size_t total_bytes; // Общий размер данных всех элементов (байт) - int size_limit; // Максимальное количество (-1 = без ограничения) - - queue_callback_t callback; // Функция коллбэка - void* callback_arg; // Пользовательский аргумент для коллбэка - int callback_suspended; // 1 если коллбэки приостановлены (во время обработки) - - void* resume_timeout_id; // ID таймаута uasync для отложенного возобновления - uasync_t* ua; // Экземпляр uasync для таймеров - - queue_waiter_t* waiters; // Список ожидающих коллбэков -}; - -// ==================== Управление очередью ==================== - -// Создать новую пустую очередь -// ua - экземпляр uasync для таймеров (обязательный параметр) -// Возвращает: указатель на очередь или NULL при ошибке выделения памяти -ll_queue_t* queue_new(uasync_t* ua); - -// Освободить очередь и все её элементы -// Также отменяет отложенное возобновление если оно запланировано -void queue_free(ll_queue_t* q); - -// ==================== Конфигурация очереди ==================== - -// Установить функцию и аргумент коллбэка для очереди -// Коллбэк вызывается при добавлении элемента в пустую очередь (разрешенные коллбэки) -// обработчик должен обработать этот пакет и когда будет готов к приёму следующего - вызывает resume_callback. обработка строго по одному пакету. -void queue_set_callback(ll_queue_t* q, queue_callback_t cbk_fn, void* arg); - -// Возобновить коллбэки после обработки элемента переданного в коллбэке (тянуть дополнительные элементы из очереди не предусмотернные api нельзя). -// эта функция должна вызываться всегда после того как cbk_fn обработала пакет (можно с ожиданием через async), иначе очередь застрянет. -// Если в очереди остались элементы, запланирует вызов коллбэка через uasync_set_timeout(0) -// Это предотвращает накопление рекурсии в стеке вызовов -void queue_resume_callback(ll_queue_t* q); - -// Установить максимальное количество элементов в очереди -// При превышении лимита новый элемент автоматически освобождается -void queue_set_size_limit(ll_queue_t* q, int lim); - -// ==================== Управление элементами ==================== - -// Создать новый элемент с областью данных указанного размера -// Память выделяется одним блоком: [ll_entry_t][область данных data_size байт] -// Возвращает: указатель на элемент или NULL при ошибке выделения памяти -ll_entry_t* queue_entry_new(size_t data_size); - -// Освободить элемент (не влияет на связи в очереди) -void queue_entry_free(ll_entry_t* entry); - -// ==================== Операции с очередью ==================== - -// Добавить элемент в конец очереди (FIFO) -// Если очередь была пустой и коллбэки разрешены - вызывает коллбэк -// Возвращает: 0 при успехе, -1 если превышен лимит размера (элемент освобожден) -int queue_entry_put(ll_queue_t* q, ll_entry_t* entry); - -// Добавить элемент в начало очереди (LIFO, высокий приоритет) -// Если очередь была пустой и коллбэки разрешены - вызывает коллбэк -// Возвращает: 0 при успехе, -1 если превышен лимит размера (элемент освобожден) -int queue_entry_put_first(ll_queue_t* q, ll_entry_t* entry); - -// Извлечь элемент из начала очереди -// При извлечении приостанавливает коллбэки (callback_suspended = 1) чтобы предотвратить рекурсию -// Возвращает: указатель на элемент или NULL если очередь пуста -ll_entry_t* queue_entry_get(ll_queue_t* q); - -// Получить текущее количество элементов в очереди -int queue_entry_count(ll_queue_t* q); - -// ==================== Вспомогательные функции ==================== - -// Получить указатель на область данных элемента -// Данные расположены сразу после структуры ll_entry_t -static inline void* ll_entry_data(ll_entry_t* entry) { - return (void*)(entry + 1); -} - -// Получить размер данных элемента -static inline size_t ll_entry_size(ll_entry_t* entry) { - return entry->size; -} - -// ==================== Асинхронное ожидание ==================== - -// Зарегистрировать коллбэк, который будет вызван когда очередь будет иметь -// не более max_packets пакетов и не более max_bytes байт. -// Если условие уже выполнено, коллбэк вызывается немедленно. -// Можно зарегистрировать несколько ожиданий на одной очереди. -// Возвращает указатель на waiter для возможной отмены через queue_cancel_wait -queue_waiter_t* queue_wait_threshold(ll_queue_t* q, int max_packets, size_t max_bytes, - queue_threshold_callback_t callback, void* arg); - -// Отменить ожидание (удалить waiter из списка) -void queue_cancel_wait(ll_queue_t* q, queue_waiter_t* waiter); - -// Получить общий размер данных в очереди (байт) -static inline size_t queue_total_bytes(ll_queue_t* q) { - if (!q) return 0; - return q->total_bytes; -} - -#endif // LL_QUEUE_H diff --git a/ll_queue.h b/ll_queue.h new file mode 120000 index 00000000..92308666 --- /dev/null +++ b/ll_queue.h @@ -0,0 +1 @@ +src/ll_queue.h \ No newline at end of file diff --git a/monitor.py b/monitor.py index f48eae70..d35a7fbc 100644 --- a/monitor.py +++ b/monitor.py @@ -25,7 +25,7 @@ CONTROL_ERR_NONE = 0 CONTROL_ERR_INVALID_CMD = 1 CONTROL_ERR_INTERNAL = 2 -def send_command(host='127.0.0.1', port=5555, command=CONTROL_CMD_GET_STATS, sequence=1): +def send_command(host='192.168.29.117', port=5555, command=CONTROL_CMD_GET_STATS, sequence=1): """Send a control command and receive response""" sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.settimeout(2.0) diff --git a/pkt_normalizer.h b/pkt_normalizer.h deleted file mode 100644 index e6dd895b..00000000 --- a/pkt_normalizer.h +++ /dev/null @@ -1,75 +0,0 @@ -// pkt_normalizer.h -#ifndef PKT_NORMALIZER_H -#define PKT_NORMALIZER_H - -#include "ll_queue.h" -#include "u_async.h" -#include - -/* Default fragment reassembly timeout in uasync timebase units (0.1 ms) */ -#ifndef PKT_NORMALIZER_FRAGMENT_TIMEOUT -#define PKT_NORMALIZER_FRAGMENT_TIMEOUT 5000 /* 500 ms */ -#endif - -typedef struct pn_struct pn_struct; -typedef struct pkt_normalizer_pair pkt_normalizer_pair; - -/* Service packet callback type */ -typedef void (*pkt_normalizer_service_callback_t)(void* user_data, uint8_t type, const uint8_t* data, size_t len); - -struct pn_struct { - ll_queue_t* input; - ll_queue_t* output; - uasync_t* ua; - int is_packer; - union { - struct { - uint8_t* buf; - size_t len; - size_t cap; - int error_count; - } packer; - struct { - uint8_t* buf; /* буфер для сборки фрагментов */ - size_t len; /* текущая накопленная длина */ - size_t total_len; /* ожидаемая общая длина из первого фрагмента */ - size_t cap; /* ёмкость буфера */ - int error_count; /* счетчик ошибок сборки */ - int in_fragment; /* флаг: идет сборка фрагментов (1) или нет (0) */ - /* Service packet reassembly */ - uint8_t* service_buf; /* буфер для сборки сервисных пакетов */ - size_t service_len; /* текущая накопленная длина сервисного пакета */ - size_t service_cap; /* ёмкость буфера сервисного пакета */ - uint8_t service_type; /* тип сервисного пакета */ - int in_service; /* флаг: идет сборка сервисного пакета (1) или нет (0) */ - } unpacker; - } u; - /* Service packet callback */ - pkt_normalizer_service_callback_t service_callback; - void* service_callback_user_data; -}; - -pn_struct* pkt_normalizer_init(uasync_t* ua, int is_packer); // 1 for packer, 0 for unpacker -void pkt_normalizer_deinit(pn_struct* pn); - -pkt_normalizer_pair* pkt_normalizer_pair_init(uasync_t* ua); -void pkt_normalizer_pair_deinit(pkt_normalizer_pair* pair); - -/* Error handling */ -int pkt_normalizer_get_error_count(const pn_struct* pn); -void pkt_normalizer_reset_error_count(pn_struct* pn); - -/* Flush internal buffer (packer only) */ -void pkt_normalizer_flush(pn_struct* pn); - -int pkt_normalizer_send_service(pn_struct* pn, uint8_t type, const void* data, size_t len); -void pkt_normalizer_set_service_callback(pn_struct* pn, pkt_normalizer_service_callback_t callback, void* user_data); -void pkt_normalizer_reset_service_state(pn_struct* pn); -void pkt_normalizer_reset_state(pn_struct* pn); - -struct pkt_normalizer_pair { - pn_struct* packer; - pn_struct* unpacker; -}; - -#endif // PKT_NORMALIZER_H diff --git a/pkt_normalizer.h b/pkt_normalizer.h new file mode 120000 index 00000000..1390e790 --- /dev/null +++ b/pkt_normalizer.h @@ -0,0 +1 @@ +src/pkt_normalizer.h \ No newline at end of file diff --git a/routing.h b/routing.h deleted file mode 100644 index a8d7dc8b..00000000 --- a/routing.h +++ /dev/null @@ -1,170 +0,0 @@ -/** - * @file routing.h - * @brief Улучшенная система маршрутизации с поддержкой пропускной способности и типов маршрутов - * @details Поддерживает статические/динамические маршруты с метриками и валидацией - */ -#ifndef ROUTING_H -#define ROUTING_H -#include -#include -#include -#include "connection.h" -#include "control_socket.h" - -// Типы маршрутов -typedef enum { - ROUTE_TYPE_STATIC = 0, // Статические маршруты, загружаемые при старте - ROUTE_TYPE_DYNAMIC = 1, // Динамические маршруты, полученные от соседей - ROUTE_TYPE_LOCAL = 2, // Локальные подсети - ROUTE_TYPE_LEARNED = 3 // Маршруты, полученные от других узлов -} route_type_t; - -// Флаги маршрута -typedef enum { - ROUTE_FLAG_ACTIVE = (1 << 0), // Маршрут активен (лучший путь) - ROUTE_FLAG_VALIDATED = (1 << 1), // Маршрут прошёл валидацию (по разрешенным подсетям в конфиге) - ROUTE_FLAG_ADVERTISED = (1 << 2), // Маршрут анонсируется другим узлам - ROUTE_FLAG_LEARNED = (1 << 3) // Маршрут получен от соседа -} route_flags_t; - -// Расширенные метрики маршрута -typedef struct { - uint32_t bandwidth_kbps; // Доступная (минимальная по всем узлам) пропускная способность до узла по этому маршруту, кбит/с - uint16_t packet_loss_rate; // Процент потерь пакетов (0–10000 = 0.00–100.00%) - uint16_t latency_ms; // Задержка в миллисекундах (суммарная до узла, не вулючает задержку до next hop) - uint8_t hop_count; // Количество хопов до цели (не включая next hop) - uint64_t last_updated; // Время последнего обновления (в timebase 0.1ms) -} route_metrics_t; - -// Расширенная запись маршрута -typedef struct { - uint32_t network; // Адрес сети (в сетевом порядке байтов) - uint8_t prefix_length; // Длина префикса (0–32) - uint32_t next_hop_ip; // IP-адрес следующего хопа (узла который анонсировал маршрут) - conn_handle_t* next_hop; // Указатель на соединение со следующим хопом - - route_type_t type; // Тип маршрута - uint8_t flags; // Флаги маршрута - - route_metrics_t metrics; // Метрики маршрута - uint64_t created_time; // Время создания записи - uint64_t last_update; // Время последнего обновления - uint64_t last_used; // Время последнего использования - -} route_entry_t; - - - -// Расширенная таблица маршрутизации (элементы сортированы по IP), может содержать дублирующие маршруты по альтернативным каналам. -typedef struct { - route_entry_t *entries; // Массив записей маршрутов - size_t count; // Количество активных записей - size_t capacity; // Выделенная ёмкость массива (расширение x2 при нехватке места) - - // Диапазоны для валидации подсетей - uint32_t *dynamic_subnets; // Разрешённые диапазоны динамических маршрутов (анонс не принимается если вне этой таблицы) - size_t dynamic_subnet_count; - - // Локальные подсети, которые будут анонсироваться - uint32_t *local_subnets; - size_t local_subnet_count; - routing_stats_t stats; // Statistics counters -} routing_table_t; - -/** - * @brief Создаёт улучшенную таблицу маршрутизации - * @return указатель на новую таблицу или NULL при ошибке - */ -routing_table_t *routing_table_create(void); - -/** - * @brief Уничтожает таблицу маршрутизации - */ -void routing_table_destroy(routing_table_t *table); - -/** - * @brief Получить статистику таблицы маршрутизации - * @param table таблица маршрутизации - * @param stats указатель на структуру для заполнения статистики - */ -void routing_get_stats(const routing_table_t *table, routing_stats_t *stats); - -/** - * @brief Добавляет маршрут в таблицу - * - * @param table таблица маршрутизации - * @param entry структура маршрута для вставки - * @return true при успехе, false при ошибке - */ -bool routing_table_insert(routing_table_t *table, const route_entry_t *entry); - -/** - * @brief Удаляет маршрут из таблицы - * - * @param table таблица маршрутизации - * @param network адрес сети - * @param prefix_length длина префикса - * @param source_node_id идентификатор узла-источника - * @return true — маршрут удалён, false — не найден - */ -bool routing_table_delete(routing_table_t *table, uint32_t network, uint8_t prefix_length, uint32_t source_node_id); - -/** - * @brief Ищет лучший маршрут до указанного адреса - * - * @param table таблица маршрутизации - * @param dest_ip целевой IP-адрес - * @param best_route [out] сюда будет записан лучший маршрут - * @return true — маршрут найден, false — нет подходящего маршрута - */ -bool routing_table_lookup(routing_table_t *table, uint32_t dest_ip, route_entry_t *best_route); - -/** - * @brief Проверяет маршрут на соответствие разрешённым подсетям - * - * @param table таблица с диапазонами валидации - * @param network адрес сети - * @param prefix_length длина префикса - * @param route_type ожидаемый тип маршрута - * @return true — маршрут разрешён, false — запрещён - */ -bool routing_validate_route(routing_table_t *table, uint32_t network, uint8_t prefix_length, route_type_t route_type); - -/** - * @brief Добавляет диапазон подсети для динамической валидации - */ -bool routing_add_dynamic_subnet(routing_table_t *table, uint32_t network, uint8_t prefix_length); - -/** - * @brief Добавляет локальную подсеть, которая будет анонсироваться соседям - */ -bool routing_add_local_subnet(routing_table_t *table, uint32_t network, uint8_t prefix_length); - -/** - * @brief Возвращает все маршруты для указанной сети/префикса - * - * @param routes [out] массив указателей (выделяется внутри, нужно освободить) - */ -bool routing_get_all_routes(const routing_table_t *table, uint32_t network, uint8_t prefix_length, - route_entry_t **routes, size_t *count); - -/** - * @brief Выводит содержимое таблицы маршрутизации (для отладки) - */ -void routing_table_print(const routing_table_t *table); - -/** - * @brief Преобразует тип маршрута в строку - * @return текстовое представление типа - */ -const char *route_type_to_string(route_type_t type); - -/** - * @brief Преобразует IP-адрес в строку (для отладки) - * - * @param ip адрес в сетевом порядке байтов - * @param buffer буфер минимум 16 байт - * @return указатель на заполненный буфер - */ -char *ip_to_string(uint32_t ip, char *buffer); -#endif // ROUTING_H \ No newline at end of file diff --git a/routing.h b/routing.h new file mode 120000 index 00000000..302a8351 --- /dev/null +++ b/routing.h @@ -0,0 +1 @@ +src/routing.h \ No newline at end of file diff --git a/sc_lib.h b/sc_lib.h deleted file mode 100644 index d3a384db..00000000 --- a/sc_lib.h +++ /dev/null @@ -1,119 +0,0 @@ -#ifndef SECURE_CHANNEL_H -#define SECURE_CHANNEL_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* ===== Константы ===== */ - -#define SC_PUBKEY_SIZE 64 /* secp256r1: X || Y */ -#define SC_PRIVKEY_SIZE 32 -#define SC_SHARED_SECRET_SIZE 32 -#define SC_SESSION_KEY_SIZE 16 /* AES-128 key size */ -#define SC_NONCE_SIZE 13 -#define SC_TAG_SIZE 16 - -/* ===== Коды ошибок ===== */ - -typedef enum { - SC_OK = 0, - SC_ERR_INVALID_ARG, - SC_ERR_CRYPTO, - SC_ERR_NOT_INITIALIZED, - SC_ERR_AUTH_FAILED -} sc_status_t; - -/* ===== Контекст защищённого канала ===== */ - -typedef struct -{ - /* Локальные ключи */ - uint8_t private_key[SC_PRIVKEY_SIZE]; - uint8_t public_key[SC_PUBKEY_SIZE]; - - /* Ключ пира */ - uint8_t peer_public_key[SC_PUBKEY_SIZE]; - uint8_t peer_key_set; - - /* Производные ключи */ - uint8_t session_key[SC_SESSION_KEY_SIZE]; - - /* Nonce / counters */ - uint32_t tx_counter; - uint32_t rx_counter; - - /* Флаги состояния */ - uint8_t initialized; - uint8_t session_ready; - -} sc_context_t; - -/* ===== API ===== */ - -/** - * @brief Сгенерировать пару ECDH ключей - * - * @param ctx Контекст - * @return SC_OK или ошибка - */ -sc_status_t sc_generate_keypair(sc_context_t *ctx); - -/** - * @brief Инициализация контекста с уже существующими ключами - * - * @param ctx Контекст - * @param public_key Указатель на публичный ключ (64 байта) - * @param private_key Указатель на приватный ключ (32 байта) - */ -sc_status_t sc_init_local_keys(sc_context_t *ctx, - const uint8_t *public_key, - const uint8_t *private_key); - -/** - * @brief Установить публичный ключ пира и вычислить session key - * - * @param ctx Контекст - * @param peer_public_key Публичный ключ пира (64 байта) - */ -sc_status_t sc_set_peer_public_key(sc_context_t *ctx, - const uint8_t *peer_public_key); - -/** - * @brief Зашифровать сообщение - * - * @param ctx Контекст - * @param plaintext Входные данные - * @param plaintext_len Длина - * @param ciphertext Выход (может совпадать с plaintext) - * @param tag MAC-тег (16 байт) - */ -sc_status_t sc_encrypt(sc_context_t *ctx, - const uint8_t *plaintext, - size_t plaintext_len, - uint8_t *ciphertext, - uint8_t *tag); - -/** - * @brief Расшифровать и проверить сообщение - * - * @param ctx Контекст - * @param ciphertext Зашифрованные данные - * @param ciphertext_len Длина - * @param tag MAC-тег - * @param plaintext Выход - */ -sc_status_t sc_decrypt(sc_context_t *ctx, - const uint8_t *ciphertext, - size_t ciphertext_len, - const uint8_t *tag, - uint8_t *plaintext); - -#ifdef __cplusplus -} -#endif - -#endif /* SECURE_CHANNEL_H */ diff --git a/sc_lib.h b/sc_lib.h new file mode 120000 index 00000000..c117af63 --- /dev/null +++ b/sc_lib.h @@ -0,0 +1 @@ +src/sc_lib.h \ No newline at end of file diff --git a/settings.h b/settings.h deleted file mode 100644 index 395b9120..00000000 --- a/settings.h +++ /dev/null @@ -1,11 +0,0 @@ -// settings.h -#ifndef SETTINGS_H -#define SETTINGS_H - -typedef struct { - int max_fragment_size; -} settings_t; - -extern settings_t settings; - -#endif // SETTINGS_H diff --git a/settings.h b/settings.h new file mode 120000 index 00000000..a921f160 --- /dev/null +++ b/settings.h @@ -0,0 +1 @@ +src/settings.h \ No newline at end of file diff --git a/config_parser.c b/src/config_parser.c similarity index 100% rename from config_parser.c rename to src/config_parser.c diff --git a/src/config_parser.h b/src/config_parser.h new file mode 100644 index 00000000..6f776b30 --- /dev/null +++ b/src/config_parser.h @@ -0,0 +1,117 @@ +// config_parser.h - Configuration parser for utun application +#ifndef CONFIG_PARSER_H +#define CONFIG_PARSER_H + +#include +#include +#include "connection.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Maximum lengths for strings in config +#define MAX_CONN_NAME_LEN 64 +#define MAX_KEY_LEN 256 // HEX key length (64 bytes * 2 chars + null) +#define MAX_ADDR_LEN 64 +#define MAX_NETIF_LEN 16 +#define MAX_OPTION_VALUE_LEN 256 +#define MAX_ALLOWED_SUBNETS 32 + +// Connection mode (config parser internal) +typedef enum { + CONFIG_MODE_UNKNOWN = 0, + CONFIG_MODE_CLIENT, + CONFIG_MODE_SERVER +} config_conn_mode_t; + +// Subnet entry for allowed routing +typedef struct { + char subnet[MAX_ADDR_LEN]; // Format: "192.168.0.0/24" +} subnet_entry_t; + +// Connection configuration +typedef struct { + char name[MAX_CONN_NAME_LEN]; // Connection name from [connection: name] + config_conn_mode_t mode; // server or client + char local_addr[MAX_ADDR_LEN]; // For client: from_addr, for server: addr + char remote_addr[MAX_ADDR_LEN]; // For client: to_addr, for server: N/A + char peer_public_key_hex[MAX_KEY_LEN]; // Peer's public key in HEX + int so_mark; // Socket mark (0 = not set) + char netif[MAX_NETIF_LEN]; // Network interface to bind to + char tun_ifname[MAX_NETIF_LEN]; // TUN interface name (e.g., tun12) + char tun_ip[MAX_ADDR_LEN]; // TUN interface IP address (e.g., 10.0.0.1/24) +} connection_config_t; + +// Global configuration +typedef struct { + char my_private_key_hex[MAX_KEY_LEN]; // Our private key in HEX + char my_public_key_hex[MAX_KEY_LEN]; // Our public key in HEX + char option_value[MAX_OPTION_VALUE_LEN]; // Global option value + char control_ip[MAX_ADDR_LEN]; // Control socket IP (empty for disabled) + uint16_t control_port; // Control socket port + int net_debug; // Network debug mode: 1 = enable network emulator +} global_config_t; + +// Complete configuration +typedef struct { + global_config_t global; + connection_config_t *connections; + int connection_count; + int connection_capacity; + subnet_entry_t allowed_subnets[MAX_ALLOWED_SUBNETS]; + int allowed_subnet_count; +} utun_config_t; + +/** + * @brief Parse configuration file + * @param filename Path to configuration file + * @return Pointer to parsed configuration, NULL on error + * + * Parses INI-style configuration file with format: + * [global] + * option=value + * my_private_key=HEX + * my_public_key=HEX + * + * [connection: name] + * mode=server|client + * addr=ip:port (for server) + * from_addr=ip:port (for client) + * to_addr=ip:port (for client) + * peer_public_key=HEX + * so_mark=number + * netif=interface_name + */ +utun_config_t* parse_config(const char *filename); + +/** + * @brief Free configuration structure + * @param config Configuration to free + */ +void free_config(utun_config_t *config); + +/** + * @brief Print configuration for debugging + * @param config Configuration to print + */ +void print_config(const utun_config_t *config); + +/** + * @brief Update keys in configuration file + * @param filename Path to configuration file + * @param private_key_hex Private key in HEX format + * @param public_key_hex Public key in HEX format + * @return 0 on success, -1 on error + * + * Updates or adds my_private_key and my_public_key lines in [global] section + */ +int update_config_keys(const char *filename, + const char *private_key_hex, + const char *public_key_hex); + +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_PARSER_H */ \ No newline at end of file diff --git a/connection.c b/src/connection.c similarity index 100% rename from connection.c rename to src/connection.c diff --git a/src/connection.h b/src/connection.h new file mode 100644 index 00000000..e17d5181 --- /dev/null +++ b/src/connection.h @@ -0,0 +1,129 @@ +// connection.h - Минималистичный API для защищенных UDP подключений +#ifndef CONNECTION_H +#define CONNECTION_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Непрозрачный дескриптор подключения */ +typedef struct conn_handle conn_handle_t; + +/* Forward declaration для uasync */ +typedef struct uasync_s uasync_t; + +/* Режим подключения */ +typedef enum { + CONN_MODE_CLIENT, /* Инициируем подключение к указанному удаленному адресу */ + CONN_MODE_SERVER /* Ожидаем входящие подключения */ +} conn_mode_t; + +/* Callback для входящих данных */ +typedef void (*conn_recv_callback_t)(conn_handle_t* conn, + const uint8_t* data, + size_t len, + void* user_data); + +/* + * Создание дескриптора подключения (только выделение памяти). + * ua - экземпляр uasync для таймеров (обязательный параметр) + * Возвращает NULL при ошибке. + */ +conn_handle_t* conn_create(uasync_t* ua); + +/* + * Установка криптографических ключей. + * Должна быть вызвана до conn_connect(). + * + * @param conn Дескриптор подключения + * @param my_pub_key Публичный ключ (64 байта для secp256r1), NULL для авто-генерации + * @param my_priv_key Приватный ключ (32 байта), NULL для авто-генерации + * @param peer_pub_key Публичный ключ пира (64 байта), NULL для сервера (получит из первого пакета) + * + * @return 0 при успехе, -1 при ошибке + */ +int conn_set_keys(conn_handle_t* conn, + const uint8_t* my_pub_key, + const uint8_t* my_priv_key, + const uint8_t* peer_pub_key); + +/* + * Подключение к удаленному узлу или начало ожидания входящих подключений. + * + * @param conn Дескриптор подключения + * @param local_ip Локальный IP для bind (NULL для "0.0.0.0") + * @param local_port Локальный порт (0 для авто-выбора) + * @param remote_ip Удаленный IP (NULL для серверного режима) + * @param remote_port Удаленный порт (игнорируется если remote_ip NULL) + * @param mode Режим подключения (CONN_MODE_CLIENT/SERVER) + * + * @return 0 при успехе, -1 при ошибке + */ +int conn_connect(conn_handle_t* conn, + const char* local_ip, + uint16_t local_port, + const char* remote_ip, + uint16_t remote_port, + conn_mode_t mode); + +/* + * Установка callback'а для входящих данных. + * Callback будет вызываться при получении полных собранных пакетов. + */ +void conn_set_recv_callback(conn_handle_t* conn, + conn_recv_callback_t callback, + void* user_data); + +/* + * Отправка данных. + * Данные будут автоматически фрагментированы, зашифрованы и отправлены. + * + * @return 0 при успехе, -1 при ошибке + */ +int conn_send(conn_handle_t* conn, const uint8_t* data, size_t len); + +/* + * Закрытие подключения (немедленное, без протокола завершения). + * После вызова дескриптор можно уничтожить через conn_destroy(). + */ +void conn_close(conn_handle_t* conn); + +/* + * Сброс соединения с использованием служебных пакетов. + * Отправляет пакет сброса через ETCP и сбрасывает состояние всех компонентов. + * Предназначено для тестирования и восстановления после сбоев. + */ +void conn_reset(conn_handle_t* conn); + +/* + * Полное уничтожение дескриптора подключения и освобождение всех ресурсов. + * Автоматически вызывает conn_close() если подключение активно. + */ +void conn_destroy(conn_handle_t* conn); + +/* + * Получение статистики подключения (опционально). + * + * @return 0 при успехе, -1 при ошибке + */ +typedef struct { + uint64_t bytes_sent; + uint64_t bytes_received; + uint32_t packets_sent; + uint32_t packets_received; + uint32_t retransmissions; + uint32_t fragments_assembled; + uint16_t current_rtt_ms; /* Текущее RTT в миллисекундах */ + uint16_t jitter_ms; /* Джиттер в миллисекундах */ +} conn_stats_t; + +int conn_get_stats(conn_handle_t* conn, conn_stats_t* stats); + +#ifdef __cplusplus +} +#endif + +#endif /* CONNECTION_H */ \ No newline at end of file diff --git a/control_socket.c b/src/control_socket.c similarity index 100% rename from control_socket.c rename to src/control_socket.c diff --git a/src/control_socket.h b/src/control_socket.h new file mode 100644 index 00000000..4a0e2ad6 --- /dev/null +++ b/src/control_socket.h @@ -0,0 +1,208 @@ +/** + * @file control_socket.h + * @brief Control socket for statistics and diagnostics over UDP + * @details Provides remote monitoring of utun VPN tunnel statistics + */ + +#ifndef CONTROL_SOCKET_H +#define CONTROL_SOCKET_H + +#include +#include +#include + +// Forward declarations for application state +struct utun_state; + +#ifdef __cplusplus +extern "C" { +#endif + +// Maximum connections for statistics +#define MAX_CONN_STATS 16 +#define MAX_ROUTE_STATS 100 + +// Control socket command types +typedef enum { + CONTROL_CMD_GET_STATS = 1, // Request statistics + CONTROL_CMD_RESET_STATS = 2, // Reset statistics counters + CONTROL_CMD_GET_STATUS = 3, // Request status information +} control_cmd_t; + +// Response types +typedef enum { + CONTROL_RESP_STATS = 1, // Statistics response + CONTROL_RESP_STATUS = 2, // Status response + CONTROL_RESP_ERROR = 0xFF, // Error response +} control_resp_t; + +// Error codes +typedef enum { + CONTROL_ERR_NONE = 0, + CONTROL_ERR_INVALID_CMD = 1, + CONTROL_ERR_INTERNAL = 2, +} control_err_t; + +// Packet normalizer statistics +typedef struct __attribute__((packed)) { + uint32_t packer_errors; // Packer error count + uint32_t unpacker_errors; // Unpacker error count + uint32_t fragments_assembled; // Fragments assembled successfully + uint32_t service_packets; // Service packets processed +} pkt_normalizer_stats_t; + +// ETCP statistics +typedef struct __attribute__((packed)) { + uint32_t retransmissions; // Retransmission count + uint32_t total_packets_sent; // Total packets sent (including retransmissions) + uint32_t unique_packets_sent; // Unique packets sent (excluding retransmissions) + uint32_t bytes_sent_total; // Total bytes sent + uint32_t bytes_received_total;// Total bytes received + uint32_t ack_packets_count; // ACK packets sent + uint32_t control_packets_count; // Control packets sent + uint16_t current_rtt; // Current RTT (0.1ms units) + uint16_t jitter; // Jitter (0.1ms units) + uint32_t window_size; // Current window size (bytes) + uint32_t unacked_bytes; // Unacknowledged bytes in flight +} etcp_stats_t; + +// Connection statistics +typedef struct __attribute__((packed)) { + uint64_t bytes_sent; + uint64_t bytes_received; + uint32_t packets_sent; + uint32_t packets_received; + uint32_t retransmissions; + uint32_t fragments_assembled; + uint16_t current_rtt_ms; + uint16_t jitter_ms; + uint8_t is_active; // 1 if connection is active + char name[32]; // Connection name from config +} conn_stats_entry_t; + +// Routing statistics +typedef struct __attribute__((packed)) { + uint32_t total_routes; // Total routes in table + uint32_t static_routes; // Static routes count + uint32_t dynamic_routes; // Dynamic routes count + uint32_t local_routes; // Local routes count + uint32_t learned_routes; // Learned routes count + uint32_t lookup_count; // Total lookups performed + uint32_t hit_count; // Successful lookups + uint32_t miss_count; // Failed lookups (no route) +} routing_stats_t; + +// TUN interface statistics +typedef struct __attribute__((packed)) { + 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 + char ifname[16]; // Interface name + char ip_addr[32]; // IP address with prefix +} tun_stats_t; + +// System status +typedef struct __attribute__((packed)) { + uint32_t uptime_seconds; // Seconds since startup + uint32_t memory_usage_kb; // Memory usage in KB (approximate) + uint16_t cpu_usage_percent; // CPU usage percentage (0-100) + uint8_t running; // 1 if main loop is running + uint8_t connection_count; // Number of active connections + uint16_t control_port; // Control socket port + char version[32]; // Version string +} system_status_t; + +// Complete statistics packet +typedef struct __attribute__((packed)) { + uint8_t response_type; // CONTROL_RESP_STATS + uint8_t error_code; // CONTROL_ERR_NONE if success + uint16_t sequence; // Sequence number (echoed from request) + + // Timestamps + uint64_t timestamp; // Unix timestamp in microseconds + + // Module statistics + pkt_normalizer_stats_t pkt_normalizer; + etcp_stats_t etcp; + routing_stats_t routing; + tun_stats_t tun; + + // Connection statistics (variable length, up to MAX_CONN_STATS) + uint8_t conn_count; // Number of connection entries + conn_stats_entry_t connections[MAX_CONN_STATS]; + + // System status + system_status_t system; + + // Reserved for future expansion + uint8_t reserved[64]; +} control_stats_packet_t; + +// Status response packet +typedef struct __attribute__((packed)) { + uint8_t response_type; // CONTROL_RESP_STATUS + uint8_t error_code; // CONTROL_ERR_NONE if success + uint16_t sequence; // Sequence number + + system_status_t system; + uint8_t running; // Main loop running flag + char status_msg[128]; // Human-readable status message +} control_status_packet_t; + +// Request packet (from client) +typedef struct __attribute__((packed)) { + uint8_t command; // CONTROL_CMD_* + uint16_t sequence; // Sequence number for response matching + uint8_t reserved; // Reserved, must be 0 +} control_request_packet_t; + +// Control socket handle (opaque) +typedef struct control_socket control_socket_t; + +/** + * @brief Create and initialize control socket + * @param ip IP address to bind to (NULL for any) + * @param port UDP port to listen on + * @return Control socket handle or NULL on error + */ +control_socket_t* control_socket_create(const char *ip, uint16_t port); + +/** + * @brief Destroy control socket and free resources + * @param cs Control socket handle + */ +void control_socket_destroy(control_socket_t *cs); + +/** + * @brief Get file descriptor for polling + * @param cs Control socket handle + * @return Socket file descriptor or -1 if invalid + */ +int control_socket_get_fd(const control_socket_t *cs); + +/** + * @brief Process incoming control socket requests + * @param cs Control socket handle + * @param state Application state (for collecting statistics) + * @return 0 on success, -1 on error + * + * This function should be called when the socket is readable. + * It will handle incoming requests and send responses. + */ +int control_socket_process(control_socket_t *cs, void *state); + +/** + * @brief Set application state pointer for statistics collection + * @param cs Control socket handle + * @param state Application state (utun_state_t*) + */ +void control_socket_set_state(control_socket_t *cs, void *state); + +#ifdef __cplusplus +} +#endif + +#endif /* CONTROL_SOCKET_H */ \ No newline at end of file diff --git a/etcp.c b/src/etcp.c similarity index 100% rename from etcp.c rename to src/etcp.c diff --git a/src/etcp.h b/src/etcp.h new file mode 100644 index 00000000..3a510533 --- /dev/null +++ b/src/etcp.h @@ -0,0 +1,234 @@ +// etcp.h - Расширенный протокол управления передачей (Extended Transmission Control Protocol) +#ifndef ETCP_H +#define ETCP_H + +#include +#include +#include "ll_queue.h" +#include "u_async.h" + +// Отладочное логирование +#ifdef ETCP_DEBUG +#include +#define ETCP_LOG(fmt, ...) printf("[ETCP] " fmt, ##__VA_ARGS__) +#ifdef ETCP_DEBUG_EXT +#define ETCP_DEBUG_LOG(fmt, ...) printf("[ETCP_DEBUG] " fmt, ##__VA_ARGS__) +#else +#define ETCP_DEBUG_LOG(fmt, ...) ((void)0) +#endif +#else +#define ETCP_LOG(fmt, ...) ((void)0) +#define ETCP_DEBUG_LOG(fmt, ...) ((void)0) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// Предварительные объявления +typedef struct epkt epkt_t; + +// Тип обратного вызова для отправки пакетов через UDP +typedef void (*etcp_tx_callback_t)(epkt_t* epkt, uint8_t* pkt, uint16_t len, void* arg); + +// Основная структура ETCP +struct epkt { + // Очереди + ll_queue_t* tx_queue; // Очередь данных для отправки + ll_queue_t* output_queue; // Выходная очередь (собранные данные) + + // Список полученных пакетов (отсортированный связанный список) + struct rx_packet* rx_list; + + // Отправленные пакеты (для повторной передачи) + struct sent_packet* sent_list; + + // Метрики + uint16_t rtt_last; // Последнее RTT (в единицах времени 0.1 мкс) + uint16_t rtt_avg_10; // Среднее RTT за последние 10 пакетов + uint16_t rtt_avg_100; // Среднее RTT за последние 100 пакетов + uint16_t jitter; // Джиттер (усредненный) + uint16_t bandwidth; // Текущая пропускная способность (байты за единицу времени) + uint32_t bytes_sent_total; // Общее количество отправленных байт + uint16_t last_sent_timestamp; // Временная метка последнего отправленного пакета + uint32_t bytes_allowed; // Рассчитанное количество разрешенных к отправке байт + + // Статистика + uint32_t retransmissions_count; // Количество ретрансмиссий + uint32_t ack_packets_count; // Количество отправленных пакетов подтверждения + uint32_t control_packets_count; // Количество отправленных управляющих пакетов (ACK + запросы ретрансмиссии) + uint32_t total_packets_sent; // Общее количество отправленных пакетов (включая ретрансмиссии) + uint32_t unique_packets_sent; // Количество уникальных отправленных пакетов (без ретрансмиссий) + uint32_t bytes_received_total; // Общее количество полученных байт + + // Состояние + uint16_t next_tx_id; // Следующий ID для передачи + uint16_t last_sent_id; // Последний отправленный ID (для ретрансмиссии самого нового пакета) + uint16_t last_rx_id; // Последний полученный ID (для подтверждения) + uint16_t last_delivered_id; // Последний ID, переданный в output_queue + + // Таймеры + void* next_tx_timer; // Таймер для следующей передачи + void* retransmit_timer; // Таймер для повторных передач + uasync_t* ua; // Экземпляр uasync для таймеров + + // Обратный вызов + etcp_tx_callback_t tx_callback; + void* tx_callback_arg; + + // История RTT для усреднения + uint16_t rtt_history[100]; + uint8_t rtt_history_idx; + uint8_t rtt_history_count; + + // Ожидающие подтверждения + uint16_t pending_ack_ids[32]; + uint16_t pending_ack_timestamps[32]; + uint8_t pending_ack_count; + + // Ожидающие запросы на повторную передачу + uint16_t pending_retransmit_ids[32]; + uint8_t pending_retransmit_count; + + // Управление окном + uint32_t unacked_bytes; // Количество байт, отправленных но еще не подтвержденных + uint32_t window_size; // Текущий размер окна в байтах (рассчитывается) + uint16_t last_acked_id; // Последний подтвержденный ID пакета + uint16_t last_rx_ack_id; // Последний полученный ID подтверждения от получателя + uint16_t retrans_timer_period; // Текущий период таймера повторной передачи (в единицах времени) + uint16_t next_retrans_time; // Время следующей проверки повторной передачи + uint8_t window_blocked; // Флаг: передача заблокирована из-за ограничения окна + + // Forward progress tracking + uint16_t oldest_missing_id; // Oldest missing packet ID + uint16_t missing_since_time; // Time when oldest missing packet was first detected + + // Reset state + uint8_t reset_pending; // Reset packet sent, waiting for ACK + uint8_t reset_ack_received; // Reset ACK received + void* reset_timer; // Timer for reset retransmission + uint16_t reset_retry_count; // Number of reset retries +}; + +// Функции API + +/** + * @brief Инициализировать новый экземпляр ETCP + * @param ua Экземпляр uasync для таймеров (обязательный параметр) + * @return Указатель на новый экземпляр или NULL в случае ошибки + */ +epkt_t* etcp_init(uasync_t* ua); + +/** + * @brief Освободить экземпляр ETCP и все связанные ресурсы + * @param epkt Экземпляр для освобождения + */ +void etcp_free(epkt_t* epkt); + +/** + * @brief Установить обратный вызов для отправки пакетов через UDP + * @param epkt Экземпляр ETCP + * @param cb Функция обратного вызова + * @param arg Пользовательский аргумент, передаваемый в обратный вызов + */ +void etcp_set_callback(epkt_t* epkt, etcp_tx_callback_t cb, void* arg); + +/** + * @brief Обработать полученный UDP пакет + * @param epkt Экземпляр ETCP + * @param pkt Данные пакета + * @param len Длина пакета + * @return 0 при успехе, -1 при ошибке + */ +int etcp_rx_input(epkt_t* epkt, uint8_t* pkt, uint16_t len); + +/** + * @brief Получить общее количество пакетов, ожидающих в очередях передачи + * @param epkt Экземпляр ETCP + * @return Количество пакетов + */ +int etcp_tx_queue_size(epkt_t* epkt); + +/** + * @brief Поместить данные в очередь передачи + * @param epkt Экземпляр ETCP + * @param data Данные для отправки + * @param len Длина данных + * @return 0 при успехе, -1 при ошибке + */ +int etcp_tx_put(epkt_t* epkt, uint8_t* data, uint16_t len); + +/** + * @brief Получить выходную очередь для чтения полученных данных + * @param epkt Экземпляр ETCP + * @return Указатель на выходную очередь (ll_queue_t*) + */ +ll_queue_t* etcp_get_output_queue(epkt_t* epkt); + +/** + * @brief Установить ограничение пропускной способности + * @param epkt Экземпляр ETCP + * @param bandwidth Байты за единицу времени (0.1 мкс) + */ +void etcp_set_bandwidth(epkt_t* epkt, uint16_t bandwidth); + +/** + * @brief Обновить размер окна на основе текущего RTT и пропускной способности + * @param epkt Экземпляр ETCP + * Размер окна = RTT * пропускная способность * 2 (байт в пути) + */ +void etcp_update_window(epkt_t* epkt); + +/** + * @brief Получить текущее RTT + * @param epkt Экземпляр ETCP + * @return RTT в единицах времени + */ +uint16_t etcp_get_rtt(epkt_t* epkt); + +/** + * @brief Получить текущий джиттер + * @param epkt Экземпляр ETCP + * @return Джиттер в единицах времени + */ +uint16_t etcp_get_jitter(epkt_t* epkt); + +/** + * @brief Сбросить состояние соединения (очистить очереди, метрики, таймеры) + * @param epkt Экземпляр ETCP + * Примечание: Сохраняет настройки пропускной способности и обратного вызова + */ +void etcp_reset(epkt_t* epkt); + +/** + * @brief Инициировать сброс соединения через служебные пакеты + * @param epkt Экземпляр ETCP + * Отправляет пакет сброса (0x02) и ждет подтверждения (0x03) с повторными попытками каждые 100мс + */ +void etcp_reset_connection(epkt_t* epkt); + +/** + * @brief Получить статистику ETCP + * @param epkt Экземпляр ETCP + * @param retransmissions Указатель для возврата количества ретрансмиссий + * @param total_packets_sent Указатель для возврата общего количества отправленных пакетов + * @param unique_packets_sent Указатель для возврата количества уникальных отправленных пакетов + * @param bytes_sent_total Указатель для возврата общего количества отправленных байт + * @param bytes_received_total Указатель для возврата общего количества полученных байт + * @param ack_packets_count Указатель для возврата количества отправленных пакетов подтверждения + * @param control_packets_count Указатель для возврата количества отправленных управляющих пакетов + */ +void etcp_get_stats(epkt_t* epkt, + uint32_t* retransmissions, + uint32_t* total_packets_sent, + uint32_t* unique_packets_sent, + uint32_t* bytes_sent_total, + uint32_t* bytes_received_total, + uint32_t* ack_packets_count, + uint32_t* control_packets_count); + +#ifdef __cplusplus +} +#endif + +#endif // ETCP_H diff --git a/ll_queue.c b/src/ll_queue.c similarity index 100% rename from ll_queue.c rename to src/ll_queue.c diff --git a/src/ll_queue.h b/src/ll_queue.h new file mode 100644 index 00000000..00cabaaf --- /dev/null +++ b/src/ll_queue.h @@ -0,0 +1,141 @@ +#ifndef LL_QUEUE_H +#define LL_QUEUE_H + +#include // для size_t + +// Предварительные объявления +typedef struct ll_queue ll_queue_t; +typedef struct uasync_s uasync_t; +typedef struct ll_entry ll_entry_t; + +// Тип коллбэка: вызывается при добавлении элемента в пустую очередь или для продолжения обработки +// Параметры: указатель на очередь, указатель на элемент (первый в очереди), пользовательский аргумент +typedef void (*queue_callback_t)(ll_queue_t* q, ll_entry_t* entry, void* arg); + +// Структура элемента - переменный размер, данные расположены сразу после структуры +struct ll_entry { + struct ll_entry* next; // Указатель на следующий элемент в очереди + size_t size; // Размер данных элемента (байт) +}; + +// Структура условия ожидания (waiter) +struct queue_waiter { + int max_packets; // Максимальное количество пакетов + size_t max_bytes; // Максимальное количество байт + void (*callback)(ll_queue_t* q, void* arg); // Коллбэк для вызова + void* callback_arg; // Аргумент коллбэка + struct queue_waiter* next; // Следующий ожидающий в списке +}; + +typedef struct queue_waiter queue_waiter_t; +typedef void (*queue_threshold_callback_t)(ll_queue_t* q, void* arg); + +// Структура очереди +struct ll_queue { + ll_entry_t* head; // Первый элемент (извлекается отсюда) + ll_entry_t* tail; // Последний элемент (добавляется сюда) + int count; // Текущее количество элементов + size_t total_bytes; // Общий размер данных всех элементов (байт) + int size_limit; // Максимальное количество (-1 = без ограничения) + + queue_callback_t callback; // Функция коллбэка + void* callback_arg; // Пользовательский аргумент для коллбэка + int callback_suspended; // 1 если коллбэки приостановлены (во время обработки) + + void* resume_timeout_id; // ID таймаута uasync для отложенного возобновления + uasync_t* ua; // Экземпляр uasync для таймеров + + queue_waiter_t* waiters; // Список ожидающих коллбэков +}; + +// ==================== Управление очередью ==================== + +// Создать новую пустую очередь +// ua - экземпляр uasync для таймеров (обязательный параметр) +// Возвращает: указатель на очередь или NULL при ошибке выделения памяти +ll_queue_t* queue_new(uasync_t* ua); + +// Освободить очередь и все её элементы +// Также отменяет отложенное возобновление если оно запланировано +void queue_free(ll_queue_t* q); + +// ==================== Конфигурация очереди ==================== + +// Установить функцию и аргумент коллбэка для очереди +// Коллбэк вызывается при добавлении элемента в пустую очередь (разрешенные коллбэки) +// обработчик должен обработать этот пакет и когда будет готов к приёму следующего - вызывает resume_callback. обработка строго по одному пакету. +void queue_set_callback(ll_queue_t* q, queue_callback_t cbk_fn, void* arg); + +// Возобновить коллбэки после обработки элемента переданного в коллбэке (тянуть дополнительные элементы из очереди не предусмотернные api нельзя). +// эта функция должна вызываться всегда после того как cbk_fn обработала пакет (можно с ожиданием через async), иначе очередь застрянет. +// Если в очереди остались элементы, запланирует вызов коллбэка через uasync_set_timeout(0) +// Это предотвращает накопление рекурсии в стеке вызовов +void queue_resume_callback(ll_queue_t* q); + +// Установить максимальное количество элементов в очереди +// При превышении лимита новый элемент автоматически освобождается +void queue_set_size_limit(ll_queue_t* q, int lim); + +// ==================== Управление элементами ==================== + +// Создать новый элемент с областью данных указанного размера +// Память выделяется одним блоком: [ll_entry_t][область данных data_size байт] +// Возвращает: указатель на элемент или NULL при ошибке выделения памяти +ll_entry_t* queue_entry_new(size_t data_size); + +// Освободить элемент (не влияет на связи в очереди) +void queue_entry_free(ll_entry_t* entry); + +// ==================== Операции с очередью ==================== + +// Добавить элемент в конец очереди (FIFO) +// Если очередь была пустой и коллбэки разрешены - вызывает коллбэк +// Возвращает: 0 при успехе, -1 если превышен лимит размера (элемент освобожден) +int queue_entry_put(ll_queue_t* q, ll_entry_t* entry); + +// Добавить элемент в начало очереди (LIFO, высокий приоритет) +// Если очередь была пустой и коллбэки разрешены - вызывает коллбэк +// Возвращает: 0 при успехе, -1 если превышен лимит размера (элемент освобожден) +int queue_entry_put_first(ll_queue_t* q, ll_entry_t* entry); + +// Извлечь элемент из начала очереди +// При извлечении приостанавливает коллбэки (callback_suspended = 1) чтобы предотвратить рекурсию +// Возвращает: указатель на элемент или NULL если очередь пуста +ll_entry_t* queue_entry_get(ll_queue_t* q); + +// Получить текущее количество элементов в очереди +int queue_entry_count(ll_queue_t* q); + +// ==================== Вспомогательные функции ==================== + +// Получить указатель на область данных элемента +// Данные расположены сразу после структуры ll_entry_t +static inline void* ll_entry_data(ll_entry_t* entry) { + return (void*)(entry + 1); +} + +// Получить размер данных элемента +static inline size_t ll_entry_size(ll_entry_t* entry) { + return entry->size; +} + +// ==================== Асинхронное ожидание ==================== + +// Зарегистрировать коллбэк, который будет вызван когда очередь будет иметь +// не более max_packets пакетов и не более max_bytes байт. +// Если условие уже выполнено, коллбэк вызывается немедленно. +// Можно зарегистрировать несколько ожиданий на одной очереди. +// Возвращает указатель на waiter для возможной отмены через queue_cancel_wait +queue_waiter_t* queue_wait_threshold(ll_queue_t* q, int max_packets, size_t max_bytes, + queue_threshold_callback_t callback, void* arg); + +// Отменить ожидание (удалить waiter из списка) +void queue_cancel_wait(ll_queue_t* q, queue_waiter_t* waiter); + +// Получить общий размер данных в очереди (байт) +static inline size_t queue_total_bytes(ll_queue_t* q) { + if (!q) return 0; + return q->total_bytes; +} + +#endif // LL_QUEUE_H diff --git a/pkt_normalizer.c b/src/pkt_normalizer.c similarity index 100% rename from pkt_normalizer.c rename to src/pkt_normalizer.c diff --git a/src/pkt_normalizer.h b/src/pkt_normalizer.h new file mode 100644 index 00000000..e6dd895b --- /dev/null +++ b/src/pkt_normalizer.h @@ -0,0 +1,75 @@ +// pkt_normalizer.h +#ifndef PKT_NORMALIZER_H +#define PKT_NORMALIZER_H + +#include "ll_queue.h" +#include "u_async.h" +#include + +/* Default fragment reassembly timeout in uasync timebase units (0.1 ms) */ +#ifndef PKT_NORMALIZER_FRAGMENT_TIMEOUT +#define PKT_NORMALIZER_FRAGMENT_TIMEOUT 5000 /* 500 ms */ +#endif + +typedef struct pn_struct pn_struct; +typedef struct pkt_normalizer_pair pkt_normalizer_pair; + +/* Service packet callback type */ +typedef void (*pkt_normalizer_service_callback_t)(void* user_data, uint8_t type, const uint8_t* data, size_t len); + +struct pn_struct { + ll_queue_t* input; + ll_queue_t* output; + uasync_t* ua; + int is_packer; + union { + struct { + uint8_t* buf; + size_t len; + size_t cap; + int error_count; + } packer; + struct { + uint8_t* buf; /* буфер для сборки фрагментов */ + size_t len; /* текущая накопленная длина */ + size_t total_len; /* ожидаемая общая длина из первого фрагмента */ + size_t cap; /* ёмкость буфера */ + int error_count; /* счетчик ошибок сборки */ + int in_fragment; /* флаг: идет сборка фрагментов (1) или нет (0) */ + /* Service packet reassembly */ + uint8_t* service_buf; /* буфер для сборки сервисных пакетов */ + size_t service_len; /* текущая накопленная длина сервисного пакета */ + size_t service_cap; /* ёмкость буфера сервисного пакета */ + uint8_t service_type; /* тип сервисного пакета */ + int in_service; /* флаг: идет сборка сервисного пакета (1) или нет (0) */ + } unpacker; + } u; + /* Service packet callback */ + pkt_normalizer_service_callback_t service_callback; + void* service_callback_user_data; +}; + +pn_struct* pkt_normalizer_init(uasync_t* ua, int is_packer); // 1 for packer, 0 for unpacker +void pkt_normalizer_deinit(pn_struct* pn); + +pkt_normalizer_pair* pkt_normalizer_pair_init(uasync_t* ua); +void pkt_normalizer_pair_deinit(pkt_normalizer_pair* pair); + +/* Error handling */ +int pkt_normalizer_get_error_count(const pn_struct* pn); +void pkt_normalizer_reset_error_count(pn_struct* pn); + +/* Flush internal buffer (packer only) */ +void pkt_normalizer_flush(pn_struct* pn); + +int pkt_normalizer_send_service(pn_struct* pn, uint8_t type, const void* data, size_t len); +void pkt_normalizer_set_service_callback(pn_struct* pn, pkt_normalizer_service_callback_t callback, void* user_data); +void pkt_normalizer_reset_service_state(pn_struct* pn); +void pkt_normalizer_reset_state(pn_struct* pn); + +struct pkt_normalizer_pair { + pn_struct* packer; + pn_struct* unpacker; +}; + +#endif // PKT_NORMALIZER_H diff --git a/routing.c b/src/routing.c similarity index 100% rename from routing.c rename to src/routing.c diff --git a/src/routing.h b/src/routing.h new file mode 100644 index 00000000..a8d7dc8b --- /dev/null +++ b/src/routing.h @@ -0,0 +1,170 @@ +/** + * @file routing.h + * @brief Улучшенная система маршрутизации с поддержкой пропускной способности и типов маршрутов + * @details Поддерживает статические/динамические маршруты с метриками и валидацией + */ +#ifndef ROUTING_H +#define ROUTING_H +#include +#include +#include +#include "connection.h" +#include "control_socket.h" + +// Типы маршрутов +typedef enum { + ROUTE_TYPE_STATIC = 0, // Статические маршруты, загружаемые при старте + ROUTE_TYPE_DYNAMIC = 1, // Динамические маршруты, полученные от соседей + ROUTE_TYPE_LOCAL = 2, // Локальные подсети + ROUTE_TYPE_LEARNED = 3 // Маршруты, полученные от других узлов +} route_type_t; + +// Флаги маршрута +typedef enum { + ROUTE_FLAG_ACTIVE = (1 << 0), // Маршрут активен (лучший путь) + ROUTE_FLAG_VALIDATED = (1 << 1), // Маршрут прошёл валидацию (по разрешенным подсетям в конфиге) + ROUTE_FLAG_ADVERTISED = (1 << 2), // Маршрут анонсируется другим узлам + ROUTE_FLAG_LEARNED = (1 << 3) // Маршрут получен от соседа +} route_flags_t; + +// Расширенные метрики маршрута +typedef struct { + uint32_t bandwidth_kbps; // Доступная (минимальная по всем узлам) пропускная способность до узла по этому маршруту, кбит/с + uint16_t packet_loss_rate; // Процент потерь пакетов (0–10000 = 0.00–100.00%) + uint16_t latency_ms; // Задержка в миллисекундах (суммарная до узла, не вулючает задержку до next hop) + uint8_t hop_count; // Количество хопов до цели (не включая next hop) + uint64_t last_updated; // Время последнего обновления (в timebase 0.1ms) +} route_metrics_t; + +// Расширенная запись маршрута +typedef struct { + uint32_t network; // Адрес сети (в сетевом порядке байтов) + uint8_t prefix_length; // Длина префикса (0–32) + uint32_t next_hop_ip; // IP-адрес следующего хопа (узла который анонсировал маршрут) + conn_handle_t* next_hop; // Указатель на соединение со следующим хопом + + route_type_t type; // Тип маршрута + uint8_t flags; // Флаги маршрута + + route_metrics_t metrics; // Метрики маршрута + uint64_t created_time; // Время создания записи + uint64_t last_update; // Время последнего обновления + uint64_t last_used; // Время последнего использования + +} route_entry_t; + + + +// Расширенная таблица маршрутизации (элементы сортированы по IP), может содержать дублирующие маршруты по альтернативным каналам. +typedef struct { + route_entry_t *entries; // Массив записей маршрутов + size_t count; // Количество активных записей + size_t capacity; // Выделенная ёмкость массива (расширение x2 при нехватке места) + + // Диапазоны для валидации подсетей + uint32_t *dynamic_subnets; // Разрешённые диапазоны динамических маршрутов (анонс не принимается если вне этой таблицы) + size_t dynamic_subnet_count; + + // Локальные подсети, которые будут анонсироваться + uint32_t *local_subnets; + size_t local_subnet_count; + routing_stats_t stats; // Statistics counters +} routing_table_t; + +/** + * @brief Создаёт улучшенную таблицу маршрутизации + * @return указатель на новую таблицу или NULL при ошибке + */ +routing_table_t *routing_table_create(void); + +/** + * @brief Уничтожает таблицу маршрутизации + */ +void routing_table_destroy(routing_table_t *table); + +/** + * @brief Получить статистику таблицы маршрутизации + * @param table таблица маршрутизации + * @param stats указатель на структуру для заполнения статистики + */ +void routing_get_stats(const routing_table_t *table, routing_stats_t *stats); + +/** + * @brief Добавляет маршрут в таблицу + * + * @param table таблица маршрутизации + * @param entry структура маршрута для вставки + * @return true при успехе, false при ошибке + */ +bool routing_table_insert(routing_table_t *table, const route_entry_t *entry); + +/** + * @brief Удаляет маршрут из таблицы + * + * @param table таблица маршрутизации + * @param network адрес сети + * @param prefix_length длина префикса + * @param source_node_id идентификатор узла-источника + * @return true — маршрут удалён, false — не найден + */ +bool routing_table_delete(routing_table_t *table, uint32_t network, uint8_t prefix_length, uint32_t source_node_id); + +/** + * @brief Ищет лучший маршрут до указанного адреса + * + * @param table таблица маршрутизации + * @param dest_ip целевой IP-адрес + * @param best_route [out] сюда будет записан лучший маршрут + * @return true — маршрут найден, false — нет подходящего маршрута + */ +bool routing_table_lookup(routing_table_t *table, uint32_t dest_ip, route_entry_t *best_route); + +/** + * @brief Проверяет маршрут на соответствие разрешённым подсетям + * + * @param table таблица с диапазонами валидации + * @param network адрес сети + * @param prefix_length длина префикса + * @param route_type ожидаемый тип маршрута + * @return true — маршрут разрешён, false — запрещён + */ +bool routing_validate_route(routing_table_t *table, uint32_t network, uint8_t prefix_length, route_type_t route_type); + +/** + * @brief Добавляет диапазон подсети для динамической валидации + */ +bool routing_add_dynamic_subnet(routing_table_t *table, uint32_t network, uint8_t prefix_length); + +/** + * @brief Добавляет локальную подсеть, которая будет анонсироваться соседям + */ +bool routing_add_local_subnet(routing_table_t *table, uint32_t network, uint8_t prefix_length); + +/** + * @brief Возвращает все маршруты для указанной сети/префикса + * + * @param routes [out] массив указателей (выделяется внутри, нужно освободить) + */ +bool routing_get_all_routes(const routing_table_t *table, uint32_t network, uint8_t prefix_length, + route_entry_t **routes, size_t *count); + +/** + * @brief Выводит содержимое таблицы маршрутизации (для отладки) + */ +void routing_table_print(const routing_table_t *table); + +/** + * @brief Преобразует тип маршрута в строку + * @return текстовое представление типа + */ +const char *route_type_to_string(route_type_t type); + +/** + * @brief Преобразует IP-адрес в строку (для отладки) + * + * @param ip адрес в сетевом порядке байтов + * @param buffer буфер минимум 16 байт + * @return указатель на заполненный буфер + */ +char *ip_to_string(uint32_t ip, char *buffer); +#endif // ROUTING_H \ No newline at end of file diff --git a/sc_lib.c b/src/sc_lib.c similarity index 100% rename from sc_lib.c rename to src/sc_lib.c diff --git a/src/sc_lib.h b/src/sc_lib.h new file mode 100644 index 00000000..d3a384db --- /dev/null +++ b/src/sc_lib.h @@ -0,0 +1,119 @@ +#ifndef SECURE_CHANNEL_H +#define SECURE_CHANNEL_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ===== Константы ===== */ + +#define SC_PUBKEY_SIZE 64 /* secp256r1: X || Y */ +#define SC_PRIVKEY_SIZE 32 +#define SC_SHARED_SECRET_SIZE 32 +#define SC_SESSION_KEY_SIZE 16 /* AES-128 key size */ +#define SC_NONCE_SIZE 13 +#define SC_TAG_SIZE 16 + +/* ===== Коды ошибок ===== */ + +typedef enum { + SC_OK = 0, + SC_ERR_INVALID_ARG, + SC_ERR_CRYPTO, + SC_ERR_NOT_INITIALIZED, + SC_ERR_AUTH_FAILED +} sc_status_t; + +/* ===== Контекст защищённого канала ===== */ + +typedef struct +{ + /* Локальные ключи */ + uint8_t private_key[SC_PRIVKEY_SIZE]; + uint8_t public_key[SC_PUBKEY_SIZE]; + + /* Ключ пира */ + uint8_t peer_public_key[SC_PUBKEY_SIZE]; + uint8_t peer_key_set; + + /* Производные ключи */ + uint8_t session_key[SC_SESSION_KEY_SIZE]; + + /* Nonce / counters */ + uint32_t tx_counter; + uint32_t rx_counter; + + /* Флаги состояния */ + uint8_t initialized; + uint8_t session_ready; + +} sc_context_t; + +/* ===== API ===== */ + +/** + * @brief Сгенерировать пару ECDH ключей + * + * @param ctx Контекст + * @return SC_OK или ошибка + */ +sc_status_t sc_generate_keypair(sc_context_t *ctx); + +/** + * @brief Инициализация контекста с уже существующими ключами + * + * @param ctx Контекст + * @param public_key Указатель на публичный ключ (64 байта) + * @param private_key Указатель на приватный ключ (32 байта) + */ +sc_status_t sc_init_local_keys(sc_context_t *ctx, + const uint8_t *public_key, + const uint8_t *private_key); + +/** + * @brief Установить публичный ключ пира и вычислить session key + * + * @param ctx Контекст + * @param peer_public_key Публичный ключ пира (64 байта) + */ +sc_status_t sc_set_peer_public_key(sc_context_t *ctx, + const uint8_t *peer_public_key); + +/** + * @brief Зашифровать сообщение + * + * @param ctx Контекст + * @param plaintext Входные данные + * @param plaintext_len Длина + * @param ciphertext Выход (может совпадать с plaintext) + * @param tag MAC-тег (16 байт) + */ +sc_status_t sc_encrypt(sc_context_t *ctx, + const uint8_t *plaintext, + size_t plaintext_len, + uint8_t *ciphertext, + uint8_t *tag); + +/** + * @brief Расшифровать и проверить сообщение + * + * @param ctx Контекст + * @param ciphertext Зашифрованные данные + * @param ciphertext_len Длина + * @param tag MAC-тег + * @param plaintext Выход + */ +sc_status_t sc_decrypt(sc_context_t *ctx, + const uint8_t *ciphertext, + size_t ciphertext_len, + const uint8_t *tag, + uint8_t *plaintext); + +#ifdef __cplusplus +} +#endif + +#endif /* SECURE_CHANNEL_H */ diff --git a/settings.c b/src/settings.c similarity index 100% rename from settings.c rename to src/settings.c diff --git a/src/settings.h b/src/settings.h new file mode 100644 index 00000000..395b9120 --- /dev/null +++ b/src/settings.h @@ -0,0 +1,11 @@ +// settings.h +#ifndef SETTINGS_H +#define SETTINGS_H + +typedef struct { + int max_fragment_size; +} settings_t; + +extern settings_t settings; + +#endif // SETTINGS_H diff --git a/timeout_heap.c b/src/timeout_heap.c similarity index 100% rename from timeout_heap.c rename to src/timeout_heap.c diff --git a/src/timeout_heap.h b/src/timeout_heap.h new file mode 100644 index 00000000..5609df7a --- /dev/null +++ b/src/timeout_heap.h @@ -0,0 +1,92 @@ +// timeout_heap.h + +#ifndef TIMEOUT_HEAP_H +#define TIMEOUT_HEAP_H + +#include // For uint64_t +#include // For size_t + +typedef uint64_t TimeoutTime; // e.g., milliseconds since epoch or from now + +typedef struct { + TimeoutTime expiration; // Sort key (smaller = earlier) + void *data; // User data (e.g., callback or ID) + int deleted; // 0 = active, 1 = deleted +} TimeoutEntry; + +typedef struct TimeoutHeap TimeoutHeap; + +struct TimeoutHeap { + TimeoutEntry *heap; // Dynamic array + size_t size; // Current number of elements + size_t capacity; // Allocated size + size_t freed_count; // Number of freed timer nodes + void* user_data; // User data for free callback + void (*free_callback)(void* user_data, void* data); // Callback to free data +}; + +/** + * Create a new timeout heap with initial capacity. + * @param initial_capacity Starting capacity (will grow as needed). + * @return Pointer to the heap, or NULL on failure. + */ +TimeoutHeap *timeout_heap_create(size_t initial_capacity); + +/** + * Destroy the timeout heap and free resources. + * @param h The heap to destroy. + */ +void timeout_heap_destroy(TimeoutHeap *h); + +/** + * Set a callback function to free data when deleted nodes are removed. + * @param h The heap. + * @param user_data User data passed to callback. + * @param callback Callback function (if NULL, data is freed with free()). + */ +void timeout_heap_set_free_callback(TimeoutHeap *h, void* user_data, void (*callback)(void* user_data, void* data)); + +/** + * Insert a new timeout into the heap. + * @param h The heap. + * @param expiration The expiration time. + * @param data User data associated with the timeout. + * @return 0 on success, -1 on allocation failure. + */ +int timeout_heap_push(TimeoutHeap *h, TimeoutTime expiration, void *data); + +/** + * Peek at the earliest non-deleted timeout without removing it. + * @param h The heap. + * @param out Where to store the entry. + * @return 0 on success, -1 if empty. + */ +int timeout_heap_peek(TimeoutHeap *h, TimeoutEntry *out); + +/** + * Pop the earliest non-deleted timeout from the heap. + * @param h The heap. + * @param out Where to store the entry. + * @return 0 on success, -1 if empty. + */ +int timeout_heap_pop(TimeoutHeap *h, TimeoutEntry *out); + +/** + * Cancel a timeout by matching expiration and data. + * Scans the heap linearly, so O(n) time. + * Assumes combinations are unique; cancels the first match. + * @param h The heap. + * @param expiration The expiration time to match. + * @param data The data to match. + * @return 0 if found and canceled, -1 if not found. + */ +int timeout_heap_cancel(TimeoutHeap *h, TimeoutTime expiration, void *data); + +/** + * Get the number of freed timer nodes. + * @param h The heap. + * @return Count of freed timer nodes. + */ +size_t timeout_heap_get_freed_count(TimeoutHeap *h); + +#endif // TIMEOUT_HEAP_H diff --git a/tun_if.c b/src/tun_if.c similarity index 100% rename from tun_if.c rename to src/tun_if.c diff --git a/src/tun_if.h b/src/tun_if.h new file mode 100644 index 00000000..7b04d3b6 --- /dev/null +++ b/src/tun_if.h @@ -0,0 +1,95 @@ +// tun_if.h - TUN interface management for utun +#ifndef TUN_IF_H +#define TUN_IF_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// TUN interface configuration +typedef struct { + 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 + // 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 +} tun_config_t; + +/** + * @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(tun_config_t *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 + */ +int tun_set_ip(const char *ifname, const char *ip_addr); + +/** + * @brief Bring TUN interface up + * @param ifname Interface name + * @return 0 on success, -1 on error + */ +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); + +/** + * @brief Write packet to TUN interface + * @param fd TUN file descriptor + * @param buffer Packet data + * @param size 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(tun_config_t *config); + +/** + * @brief Get current TUN configuration + * @param ifname Interface name + * @param config Output configuration + * @return 0 on success, -1 on error + */ +int tun_get_config(const char *ifname, tun_config_t *config); + +#ifdef __cplusplus +} +#endif + +#endif /* TUN_IF_H */ \ No newline at end of file diff --git a/u_async.c b/src/u_async.c similarity index 100% rename from u_async.c rename to src/u_async.c diff --git a/src/u_async.h b/src/u_async.h new file mode 100644 index 00000000..18ab6287 --- /dev/null +++ b/src/u_async.h @@ -0,0 +1,47 @@ +// uasync.h + +// модуль асинхронных операций. добавляем сокеты и таймауты и mainloop их обслуживает. + +#ifndef UASYNC_H +#define UASYNC_H + +#include +#include +#include + +typedef void (*timeout_callback_t)(void* user_arg);// передаёт user_arg из uasync_set_timeout +typedef void (*socket_callback_t)(int fd, void* user_arg);// передаёт user_arg из uasync_add_socket +// user_arg полезен если нужно передать управляющую структуру. Ее можно выделить в памяти и в ней хранить всё что надо. т.е. при set_timeout передаём и получаем ее в callback-е + + +// Error type +typedef int err_t; +#define ERR_OK 0 +#define ERR_FAIL -1 + +// Opaque uasync instance handle +typedef struct uasync_s uasync_t; + +// Instance API - основной API для работы с uasync +uasync_t* uasync_create(void); +void uasync_destroy(uasync_t* ua); +void uasync_init_instance(uasync_t* ua); + +// Timeouts, timebase = 0.1 mS +void* uasync_set_timeout(uasync_t* ua, int timeout_tb, void* user_arg, timeout_callback_t callback); +err_t uasync_cancel_timeout(uasync_t* ua, void* t_id); + +// Sockets +void* uasync_add_socket(uasync_t* ua, int fd, socket_callback_t read_cbk, socket_callback_t write_cbk, socket_callback_t except_cbk, void* user_arg); +err_t uasync_remove_socket(uasync_t* ua, void* s_id); + +// Single iteration of event loop with timeout (timebase units) +void uasync_poll(uasync_t* ua, int timeout_tb); + +// Mainloop (бесконечный цикл, __noreturn) +void uasync_mainloop(uasync_t* ua); + +// Debug statistics +void uasync_get_stats(uasync_t* ua, size_t* timer_alloc, size_t* timer_free, size_t* socket_alloc, size_t* socket_free); + +#endif // UASYNC_H diff --git a/utun.c b/src/utun.c similarity index 100% rename from utun.c rename to src/utun.c diff --git a/src/utun_state.h b/src/utun_state.h new file mode 100644 index 00000000..193328cc --- /dev/null +++ b/src/utun_state.h @@ -0,0 +1,30 @@ +/** + * @file utun_state.h + * @brief Main application state structure + * @details Contains all module instances and configuration + */ + +#ifndef UTUN_STATE_H +#define UTUN_STATE_H + +#include +#include "tun_if.h" +#include "connection.h" +#include "routing.h" +#include "control_socket.h" +#include "config_parser.h" + +// Main application state +typedef struct utun_state { + tun_config_t tun; + conn_handle_t **connections; + int connection_count; + routing_table_t *routing_table; + control_socket_t *control_socket; + int running; + uasync_t *ua; + utun_config_t *config; + FILE *log_fp; +} utun_state_t; + +#endif /* UTUN_STATE_H */ \ No newline at end of file diff --git a/timeout_heap.h b/timeout_heap.h deleted file mode 100644 index 5609df7a..00000000 --- a/timeout_heap.h +++ /dev/null @@ -1,92 +0,0 @@ -// timeout_heap.h - -#ifndef TIMEOUT_HEAP_H -#define TIMEOUT_HEAP_H - -#include // For uint64_t -#include // For size_t - -typedef uint64_t TimeoutTime; // e.g., milliseconds since epoch or from now - -typedef struct { - TimeoutTime expiration; // Sort key (smaller = earlier) - void *data; // User data (e.g., callback or ID) - int deleted; // 0 = active, 1 = deleted -} TimeoutEntry; - -typedef struct TimeoutHeap TimeoutHeap; - -struct TimeoutHeap { - TimeoutEntry *heap; // Dynamic array - size_t size; // Current number of elements - size_t capacity; // Allocated size - size_t freed_count; // Number of freed timer nodes - void* user_data; // User data for free callback - void (*free_callback)(void* user_data, void* data); // Callback to free data -}; - -/** - * Create a new timeout heap with initial capacity. - * @param initial_capacity Starting capacity (will grow as needed). - * @return Pointer to the heap, or NULL on failure. - */ -TimeoutHeap *timeout_heap_create(size_t initial_capacity); - -/** - * Destroy the timeout heap and free resources. - * @param h The heap to destroy. - */ -void timeout_heap_destroy(TimeoutHeap *h); - -/** - * Set a callback function to free data when deleted nodes are removed. - * @param h The heap. - * @param user_data User data passed to callback. - * @param callback Callback function (if NULL, data is freed with free()). - */ -void timeout_heap_set_free_callback(TimeoutHeap *h, void* user_data, void (*callback)(void* user_data, void* data)); - -/** - * Insert a new timeout into the heap. - * @param h The heap. - * @param expiration The expiration time. - * @param data User data associated with the timeout. - * @return 0 on success, -1 on allocation failure. - */ -int timeout_heap_push(TimeoutHeap *h, TimeoutTime expiration, void *data); - -/** - * Peek at the earliest non-deleted timeout without removing it. - * @param h The heap. - * @param out Where to store the entry. - * @return 0 on success, -1 if empty. - */ -int timeout_heap_peek(TimeoutHeap *h, TimeoutEntry *out); - -/** - * Pop the earliest non-deleted timeout from the heap. - * @param h The heap. - * @param out Where to store the entry. - * @return 0 on success, -1 if empty. - */ -int timeout_heap_pop(TimeoutHeap *h, TimeoutEntry *out); - -/** - * Cancel a timeout by matching expiration and data. - * Scans the heap linearly, so O(n) time. - * Assumes combinations are unique; cancels the first match. - * @param h The heap. - * @param expiration The expiration time to match. - * @param data The data to match. - * @return 0 if found and canceled, -1 if not found. - */ -int timeout_heap_cancel(TimeoutHeap *h, TimeoutTime expiration, void *data); - -/** - * Get the number of freed timer nodes. - * @param h The heap. - * @return Count of freed timer nodes. - */ -size_t timeout_heap_get_freed_count(TimeoutHeap *h); - -#endif // TIMEOUT_HEAP_H diff --git a/timeout_heap.h b/timeout_heap.h new file mode 120000 index 00000000..b4e16069 --- /dev/null +++ b/timeout_heap.h @@ -0,0 +1 @@ +src/timeout_heap.h \ No newline at end of file diff --git a/todo.txt b/todo.txt deleted file mode 100755 index 5f282702..00000000 --- a/todo.txt +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/tun_if.h b/tun_if.h deleted file mode 100644 index 7b04d3b6..00000000 --- a/tun_if.h +++ /dev/null @@ -1,95 +0,0 @@ -// tun_if.h - TUN interface management for utun -#ifndef TUN_IF_H -#define TUN_IF_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// TUN interface configuration -typedef struct { - 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 - // 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 -} tun_config_t; - -/** - * @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(tun_config_t *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 - */ -int tun_set_ip(const char *ifname, const char *ip_addr); - -/** - * @brief Bring TUN interface up - * @param ifname Interface name - * @return 0 on success, -1 on error - */ -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); - -/** - * @brief Write packet to TUN interface - * @param fd TUN file descriptor - * @param buffer Packet data - * @param size 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(tun_config_t *config); - -/** - * @brief Get current TUN configuration - * @param ifname Interface name - * @param config Output configuration - * @return 0 on success, -1 on error - */ -int tun_get_config(const char *ifname, tun_config_t *config); - -#ifdef __cplusplus -} -#endif - -#endif /* TUN_IF_H */ \ No newline at end of file diff --git a/tun_if.h b/tun_if.h new file mode 120000 index 00000000..3a44fbee --- /dev/null +++ b/tun_if.h @@ -0,0 +1 @@ +src/tun_if.h \ No newline at end of file diff --git a/u_async.c.backup b/u_async.c.backup deleted file mode 100644 index 37647a8c..00000000 --- a/u_async.c.backup +++ /dev/null @@ -1,304 +0,0 @@ -// uasync.c - -#include "u_async.h" -#include "timeout_heap.h" -#include -#include -#include -#include -#include - -#ifndef FD_SETSIZE -#define FD_SETSIZE 1024 // Assume standard size; adjust if needed for your platform -#endif - -// Timeout node -struct timeout_node { - void* arg; - timeout_callback_t callback; - uint64_t expiration_ms; // absolute expiration time in milliseconds -}; - -// Socket node -struct socket_node { - int fd; - socket_callback_t read_cbk; - socket_callback_t write_cbk; - socket_callback_t except_cbk; - void* user_data; - struct socket_node* next; -}; - -// Global state -static TimeoutHeap* timeout_heap = NULL; // Heap for timeout management -static struct socket_node* socket_head = NULL; -static int max_fd = -1; - -// New: Persistent master fd_sets, updated only on add/remove -static fd_set master_readfds; -static fd_set master_writefds; -static fd_set master_exceptfds; - -// New: FD-to-node map for faster post-select lookup (addresses point 2) -static struct socket_node* fd_to_node[FD_SETSIZE]; - -// Helper to get current time -static void get_current_time(struct timeval* tv) { - gettimeofday(tv, NULL); -} - - - -// Helper to add timeval: tv += dt (timebase units) -static void timeval_add_tb(struct timeval* tv, int dt) { - tv->tv_usec += (dt % 10000) * 100; - tv->tv_sec += dt / 10000 + tv->tv_usec / 1000000; - tv->tv_usec %= 1000000; -} - -// Convert timeval to milliseconds (uint64_t) -static uint64_t timeval_to_ms(const struct timeval* tv) { - return (uint64_t)tv->tv_sec * 1000ULL + (uint64_t)tv->tv_usec / 1000ULL; -} - - - -// Process expired timeouts -static void process_timeouts() { - if (!timeout_heap) return; - - struct timeval now_tv; - get_current_time(&now_tv); - uint64_t now_ms = timeval_to_ms(&now_tv); - - while (1) { - TimeoutEntry entry; - if (timeout_heap_peek(timeout_heap, &entry) != 0) break; - if (entry.expiration > now_ms) break; - - // Pop the expired timeout - timeout_heap_pop(timeout_heap, &entry); - struct timeout_node* node = (struct timeout_node*)entry.data; - if (node && node->callback) { - node->callback(node->arg); - } - free(node); - } -} - -// Compute time to next timeout -static void get_next_timeout(struct timeval* tv) { - if (!timeout_heap) { - tv->tv_sec = 0; - tv->tv_usec = 0; - return; - } - - TimeoutEntry entry; - if (timeout_heap_peek(timeout_heap, &entry) != 0) { - tv->tv_sec = 0; - tv->tv_usec = 0; - return; - } - - struct timeval now_tv; - get_current_time(&now_tv); - uint64_t now_ms = timeval_to_ms(&now_tv); - - if (entry.expiration <= now_ms) { - tv->tv_sec = 0; - tv->tv_usec = 0; - return; - } - - uint64_t delta_ms = entry.expiration - now_ms; - if (delta_ms > 86400000) { // Cap at 1 day to avoid overflow - delta_ms = 86400000; - } - tv->tv_sec = delta_ms / 1000; - tv->tv_usec = (delta_ms % 1000) * 1000; -} - -void uasync_init(void) { - FD_ZERO(&master_readfds); - FD_ZERO(&master_writefds); - FD_ZERO(&master_exceptfds); - memset(fd_to_node, 0, sizeof(fd_to_node)); // Init map to NULL - - if (!timeout_heap) { - timeout_heap = timeout_heap_create(16); // initial capacity 16 - } -} - -void* uasync_set_timeout(int timeout_tb, void* arg, timeout_callback_t callback) { - if (timeout_tb < 0 || !callback) return NULL; - if (!timeout_heap) return NULL; - - struct timeout_node* node = malloc(sizeof(struct timeout_node)); - if (!node) return NULL; - - node->arg = arg; - node->callback = callback; - - // Calculate expiration time in milliseconds - struct timeval now; - get_current_time(&now); - timeval_add_tb(&now, timeout_tb); - node->expiration_ms = timeval_to_ms(&now); - - // Insert into heap - if (timeout_heap_push(timeout_heap, node->expiration_ms, node) != 0) { - free(node); - return NULL; - } - - return node; -} - -err_t uasync_cancel_timeout(void* t_id) { - if (!t_id || !timeout_heap) return ERR_FAIL; - - struct timeout_node* node = (struct timeout_node*)t_id; - - // Try to cancel from heap - if (timeout_heap_cancel(timeout_heap, node->expiration_ms, node) == 0) { - free(node); - return ERR_OK; - } - - // If not found in heap (maybe already expired and removed), still free - free(node); - return ERR_FAIL; -} - -void* uasync_add_socket(int fd, socket_callback_t read_cbk, socket_callback_t write_cbk, socket_callback_t except_cbk, void* user_data) { - if (fd < 0 || fd >= FD_SETSIZE) return NULL; // Add bounds check for map - - struct socket_node* node = malloc(sizeof(struct socket_node)); - if (!node) return NULL; - - node->fd = fd; - node->read_cbk = read_cbk; - node->write_cbk = write_cbk; - node->except_cbk = except_cbk; - node->user_data = user_data; - node->next = socket_head; - socket_head = node; - - // Update masters (point 1) - if (read_cbk) FD_SET(fd, &master_readfds); - if (write_cbk) FD_SET(fd, &master_writefds); - if (except_cbk) FD_SET(fd, &master_exceptfds); - - // Update map (point 2) - fd_to_node[fd] = node; - - if (fd > max_fd) max_fd = fd; - - return node; -} - -err_t uasync_remove_socket(void* s_id) { - if (!s_id) return ERR_FAIL; - - struct socket_node* node = (struct socket_node*)s_id; - struct socket_node* cur = socket_head; - struct socket_node* prev = NULL; - - while (cur) { - if (cur == node) { - if (prev) { - prev->next = cur->next; - } else { - socket_head = cur->next; - } - - // Update masters (point 1) - if (node->read_cbk) FD_CLR(node->fd, &master_readfds); - if (node->write_cbk) FD_CLR(node->fd, &master_writefds); - if (node->except_cbk) FD_CLR(node->fd, &master_exceptfds); - - // Update map (point 2) - fd_to_node[node->fd] = NULL; - - free(cur); - - // Update max_fd (simple rescan; optimize if needed by checking if removed == max_fd) - max_fd = -1; - cur = socket_head; - while (cur) { - if (cur->fd > max_fd) max_fd = cur->fd; - cur = cur->next; - } - return ERR_OK; - } - prev = cur; - cur = cur->next; - } - return ERR_FAIL; -} - -void uasync_mainloop(void) { - while (1) { - uasync_poll(-1); /* infinite timeout */ - } -} - -void uasync_poll(int timeout_tb) { - /* Process expired timeouts */ - process_timeouts(); - - /* Prepare select with copies of masters */ - fd_set readfds = master_readfds; - fd_set writefds = master_writefds; - fd_set exceptfds = master_exceptfds; - - struct timeval tv; - get_next_timeout(&tv); - - /* If timeout_tb >= 0, compute timeout as min(timeout_tb, existing timer) */ - if (timeout_tb >= 0) { - struct timeval user_tv; - user_tv.tv_sec = timeout_tb / 10000; - user_tv.tv_usec = (timeout_tb % 10000) * 100; - - /* If no internal timer or user timeout is smaller */ - if (tv.tv_sec == 0 && tv.tv_usec == 0 && (!timeout_heap || timeout_heap->size == 0)) { - tv = user_tv; - } else if (user_tv.tv_sec < tv.tv_sec || - (user_tv.tv_sec == tv.tv_sec && user_tv.tv_usec < tv.tv_usec)) { - tv = user_tv; - } - } - - struct timeval* ptv = (tv.tv_sec == 0 && tv.tv_usec == 0 && (!timeout_heap || timeout_heap->size == 0)) ? NULL : &tv; - - int nfds = select(max_fd + 1, &readfds, &writefds, &exceptfds, ptv); - if (nfds < 0) { - if (errno == EINTR) return; - perror("select"); - return; - } - - /* Process timeouts that may have expired during select */ - process_timeouts(); - - /* Process sockets with faster dispatch */ - for (int fd = 0; nfds > 0 && fd <= max_fd; fd++) { - struct socket_node* node = fd_to_node[fd]; - if (!node) continue; - - if (node->except_cbk && FD_ISSET(fd, &exceptfds)) { - node->except_cbk(fd, node->user_data); - nfds--; - } - if (node->read_cbk && FD_ISSET(fd, &readfds)) { - node->read_cbk(fd, node->user_data); - nfds--; - } - if (node->write_cbk && FD_ISSET(fd, &writefds)) { - node->write_cbk(fd, node->user_data); - nfds--; - } - } -} diff --git a/u_async.h b/u_async.h deleted file mode 100644 index 18ab6287..00000000 --- a/u_async.h +++ /dev/null @@ -1,47 +0,0 @@ -// uasync.h - -// модуль асинхронных операций. добавляем сокеты и таймауты и mainloop их обслуживает. - -#ifndef UASYNC_H -#define UASYNC_H - -#include -#include -#include - -typedef void (*timeout_callback_t)(void* user_arg);// передаёт user_arg из uasync_set_timeout -typedef void (*socket_callback_t)(int fd, void* user_arg);// передаёт user_arg из uasync_add_socket -// user_arg полезен если нужно передать управляющую структуру. Ее можно выделить в памяти и в ней хранить всё что надо. т.е. при set_timeout передаём и получаем ее в callback-е - - -// Error type -typedef int err_t; -#define ERR_OK 0 -#define ERR_FAIL -1 - -// Opaque uasync instance handle -typedef struct uasync_s uasync_t; - -// Instance API - основной API для работы с uasync -uasync_t* uasync_create(void); -void uasync_destroy(uasync_t* ua); -void uasync_init_instance(uasync_t* ua); - -// Timeouts, timebase = 0.1 mS -void* uasync_set_timeout(uasync_t* ua, int timeout_tb, void* user_arg, timeout_callback_t callback); -err_t uasync_cancel_timeout(uasync_t* ua, void* t_id); - -// Sockets -void* uasync_add_socket(uasync_t* ua, int fd, socket_callback_t read_cbk, socket_callback_t write_cbk, socket_callback_t except_cbk, void* user_arg); -err_t uasync_remove_socket(uasync_t* ua, void* s_id); - -// Single iteration of event loop with timeout (timebase units) -void uasync_poll(uasync_t* ua, int timeout_tb); - -// Mainloop (бесконечный цикл, __noreturn) -void uasync_mainloop(uasync_t* ua); - -// Debug statistics -void uasync_get_stats(uasync_t* ua, size_t* timer_alloc, size_t* timer_free, size_t* socket_alloc, size_t* socket_free); - -#endif // UASYNC_H diff --git a/u_async.h b/u_async.h new file mode 120000 index 00000000..d49a0084 --- /dev/null +++ b/u_async.h @@ -0,0 +1 @@ +src/u_async.h \ No newline at end of file diff --git a/utun_state.h b/utun_state.h deleted file mode 100644 index 193328cc..00000000 --- a/utun_state.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file utun_state.h - * @brief Main application state structure - * @details Contains all module instances and configuration - */ - -#ifndef UTUN_STATE_H -#define UTUN_STATE_H - -#include -#include "tun_if.h" -#include "connection.h" -#include "routing.h" -#include "control_socket.h" -#include "config_parser.h" - -// Main application state -typedef struct utun_state { - tun_config_t tun; - conn_handle_t **connections; - int connection_count; - routing_table_t *routing_table; - control_socket_t *control_socket; - int running; - uasync_t *ua; - utun_config_t *config; - FILE *log_fp; -} utun_state_t; - -#endif /* UTUN_STATE_H */ \ No newline at end of file diff --git a/utun_state.h b/utun_state.h new file mode 120000 index 00000000..b0bf1ff1 --- /dev/null +++ b/utun_state.h @@ -0,0 +1 @@ +src/utun_state.h \ No newline at end of file