45 changed files with 1593 additions and 1806 deletions
@ -1,117 +0,0 @@ |
|||||||
// config_parser.h - Configuration parser for utun application
|
|
||||||
#ifndef CONFIG_PARSER_H |
|
||||||
#define CONFIG_PARSER_H |
|
||||||
|
|
||||||
#include <stdint.h> |
|
||||||
#include <stddef.h> |
|
||||||
#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 */ |
|
||||||
@ -1,129 +0,0 @@ |
|||||||
// connection.h - Минималистичный API для защищенных UDP подключений
|
|
||||||
#ifndef CONNECTION_H |
|
||||||
#define CONNECTION_H |
|
||||||
|
|
||||||
#include <stdint.h> |
|
||||||
#include <stddef.h> |
|
||||||
|
|
||||||
#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 */ |
|
||||||
@ -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 <stdint.h> |
|
||||||
#include <stddef.h> |
|
||||||
#include <stdbool.h> |
|
||||||
|
|
||||||
// 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 */ |
|
||||||
@ -1,234 +0,0 @@ |
|||||||
// etcp.h - Расширенный протокол управления передачей (Extended Transmission Control Protocol)
|
|
||||||
#ifndef ETCP_H |
|
||||||
#define ETCP_H |
|
||||||
|
|
||||||
#include <stdint.h> |
|
||||||
#include <stddef.h> |
|
||||||
#include "ll_queue.h" |
|
||||||
#include "u_async.h" |
|
||||||
|
|
||||||
// Отладочное логирование
|
|
||||||
#ifdef ETCP_DEBUG |
|
||||||
#include <stdio.h> |
|
||||||
#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
|
|
||||||
@ -1,141 +0,0 @@ |
|||||||
#ifndef LL_QUEUE_H |
|
||||||
#define LL_QUEUE_H |
|
||||||
|
|
||||||
#include <stddef.h> // для 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
|
|
||||||
@ -1,75 +0,0 @@ |
|||||||
// pkt_normalizer.h
|
|
||||||
#ifndef PKT_NORMALIZER_H |
|
||||||
#define PKT_NORMALIZER_H |
|
||||||
|
|
||||||
#include "ll_queue.h" |
|
||||||
#include "u_async.h" |
|
||||||
#include <stdint.h> |
|
||||||
|
|
||||||
/* 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
|
|
||||||
@ -1,170 +0,0 @@ |
|||||||
/**
|
|
||||||
* @file routing.h |
|
||||||
* @brief Улучшенная система маршрутизации с поддержкой пропускной способности и типов маршрутов |
|
||||||
* @details Поддерживает статические/динамические маршруты с метриками и валидацией |
|
||||||
*/ |
|
||||||
#ifndef ROUTING_H |
|
||||||
#define ROUTING_H |
|
||||||
#include <stdint.h> |
|
||||||
#include <stddef.h> |
|
||||||
#include <stdbool.h> |
|
||||||
#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
|
|
||||||
@ -1,119 +0,0 @@ |
|||||||
#ifndef SECURE_CHANNEL_H |
|
||||||
#define SECURE_CHANNEL_H |
|
||||||
|
|
||||||
#include <stdint.h> |
|
||||||
#include <stddef.h> |
|
||||||
|
|
||||||
#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 */ |
|
||||||
@ -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
|
|
||||||
@ -0,0 +1,117 @@ |
|||||||
|
// config_parser.h - Configuration parser for utun application
|
||||||
|
#ifndef CONFIG_PARSER_H |
||||||
|
#define CONFIG_PARSER_H |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
#include <stddef.h> |
||||||
|
#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 */ |
||||||
@ -0,0 +1,129 @@ |
|||||||
|
// connection.h - Минималистичный API для защищенных UDP подключений
|
||||||
|
#ifndef CONNECTION_H |
||||||
|
#define CONNECTION_H |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
#include <stddef.h> |
||||||
|
|
||||||
|
#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 */ |
||||||
@ -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 <stdint.h> |
||||||
|
#include <stddef.h> |
||||||
|
#include <stdbool.h> |
||||||
|
|
||||||
|
// 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 */ |
||||||
@ -0,0 +1,234 @@ |
|||||||
|
// etcp.h - Расширенный протокол управления передачей (Extended Transmission Control Protocol)
|
||||||
|
#ifndef ETCP_H |
||||||
|
#define ETCP_H |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
#include <stddef.h> |
||||||
|
#include "ll_queue.h" |
||||||
|
#include "u_async.h" |
||||||
|
|
||||||
|
// Отладочное логирование
|
||||||
|
#ifdef ETCP_DEBUG |
||||||
|
#include <stdio.h> |
||||||
|
#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
|
||||||
@ -0,0 +1,141 @@ |
|||||||
|
#ifndef LL_QUEUE_H |
||||||
|
#define LL_QUEUE_H |
||||||
|
|
||||||
|
#include <stddef.h> // для 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
|
||||||
@ -0,0 +1,75 @@ |
|||||||
|
// pkt_normalizer.h
|
||||||
|
#ifndef PKT_NORMALIZER_H |
||||||
|
#define PKT_NORMALIZER_H |
||||||
|
|
||||||
|
#include "ll_queue.h" |
||||||
|
#include "u_async.h" |
||||||
|
#include <stdint.h> |
||||||
|
|
||||||
|
/* 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
|
||||||
@ -0,0 +1,170 @@ |
|||||||
|
/**
|
||||||
|
* @file routing.h |
||||||
|
* @brief Улучшенная система маршрутизации с поддержкой пропускной способности и типов маршрутов |
||||||
|
* @details Поддерживает статические/динамические маршруты с метриками и валидацией |
||||||
|
*/ |
||||||
|
#ifndef ROUTING_H |
||||||
|
#define ROUTING_H |
||||||
|
#include <stdint.h> |
||||||
|
#include <stddef.h> |
||||||
|
#include <stdbool.h> |
||||||
|
#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
|
||||||
@ -0,0 +1,119 @@ |
|||||||
|
#ifndef SECURE_CHANNEL_H |
||||||
|
#define SECURE_CHANNEL_H |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
#include <stddef.h> |
||||||
|
|
||||||
|
#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 */ |
||||||
@ -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
|
||||||
@ -0,0 +1,92 @@ |
|||||||
|
// timeout_heap.h
|
||||||
|
|
||||||
|
#ifndef TIMEOUT_HEAP_H |
||||||
|
#define TIMEOUT_HEAP_H |
||||||
|
|
||||||
|
#include <stdint.h> // For uint64_t |
||||||
|
#include <stddef.h> // 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
|
||||||
@ -0,0 +1,95 @@ |
|||||||
|
// tun_if.h - TUN interface management for utun
|
||||||
|
#ifndef TUN_IF_H |
||||||
|
#define TUN_IF_H |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
#include <stddef.h> |
||||||
|
#include <sys/types.h> |
||||||
|
|
||||||
|
#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 */ |
||||||
@ -0,0 +1,47 @@ |
|||||||
|
// uasync.h
|
||||||
|
|
||||||
|
// модуль асинхронных операций. добавляем сокеты и таймауты и mainloop их обслуживает.
|
||||||
|
|
||||||
|
#ifndef UASYNC_H |
||||||
|
#define UASYNC_H |
||||||
|
|
||||||
|
#include <sys/time.h> |
||||||
|
#include <sys/select.h> |
||||||
|
#include <stddef.h> |
||||||
|
|
||||||
|
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
|
||||||
@ -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 <stdio.h> |
||||||
|
#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 */ |
||||||
@ -1,92 +0,0 @@ |
|||||||
// timeout_heap.h
|
|
||||||
|
|
||||||
#ifndef TIMEOUT_HEAP_H |
|
||||||
#define TIMEOUT_HEAP_H |
|
||||||
|
|
||||||
#include <stdint.h> // For uint64_t |
|
||||||
#include <stddef.h> // 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
|
|
||||||
@ -1,95 +0,0 @@ |
|||||||
// tun_if.h - TUN interface management for utun
|
|
||||||
#ifndef TUN_IF_H |
|
||||||
#define TUN_IF_H |
|
||||||
|
|
||||||
#include <stdint.h> |
|
||||||
#include <stddef.h> |
|
||||||
#include <sys/types.h> |
|
||||||
|
|
||||||
#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 */ |
|
||||||
@ -1,304 +0,0 @@ |
|||||||
// uasync.c |
|
||||||
|
|
||||||
#include "u_async.h" |
|
||||||
#include "timeout_heap.h" |
|
||||||
#include <stdio.h> |
|
||||||
#include <string.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <unistd.h> |
|
||||||
#include <errno.h> |
|
||||||
|
|
||||||
#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--; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,47 +0,0 @@ |
|||||||
// uasync.h
|
|
||||||
|
|
||||||
// модуль асинхронных операций. добавляем сокеты и таймауты и mainloop их обслуживает.
|
|
||||||
|
|
||||||
#ifndef UASYNC_H |
|
||||||
#define UASYNC_H |
|
||||||
|
|
||||||
#include <sys/time.h> |
|
||||||
#include <sys/select.h> |
|
||||||
#include <stddef.h> |
|
||||||
|
|
||||||
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
|
|
||||||
@ -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 <stdio.h> |
|
||||||
#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 */ |
|
||||||
Loading…
Reference in new issue