diff --git a/!/Makefile.am b/!/Makefile.am deleted file mode 100755 index a04a4f73..00000000 --- a/!/Makefile.am +++ /dev/null @@ -1,45 +0,0 @@ -bin_PROGRAMS = utun - -utun_SOURCES = \ - utun.c \ - utun_instance.c \ - config_parser.c \ - config_updater.c \ - routing.c \ - tun_if.c \ - etcp.c \ - etcp_connections.c \ - etcp_loadbalancer.c \ - secure_channel.c \ - crc32.c \ - pkt_normalizer.c \ - utun_test_hooks.c \ - $(top_srcdir)/tinycrypt/lib/source/aes_encrypt.c \ - $(top_srcdir)/tinycrypt/lib/source/aes_decrypt.c \ - $(top_srcdir)/tinycrypt/lib/source/cbc_mode.c \ - $(top_srcdir)/tinycrypt/lib/source/ccm_mode.c \ - $(top_srcdir)/tinycrypt/lib/source/cmac_mode.c \ - $(top_srcdir)/tinycrypt/lib/source/ctr_mode.c \ - $(top_srcdir)/tinycrypt/lib/source/ecc.c \ - $(top_srcdir)/tinycrypt/lib/source/ecc_dh.c \ - $(top_srcdir)/tinycrypt/lib/source/ecc_dsa.c \ - $(top_srcdir)/tinycrypt/lib/source/ecc_platform_specific.c \ - $(top_srcdir)/tinycrypt/lib/source/hmac.c \ - $(top_srcdir)/tinycrypt/lib/source/sha256.c \ - $(top_srcdir)/tinycrypt/lib/source/utils.c - -utun_CFLAGS = \ - -I$(top_srcdir)/lib \ - -I$(top_srcdir)/tinycrypt/lib/include \ - -I$(top_srcdir)/tinycrypt/lib/source \ - $(DEBUG_FLAGS) - -utun_LDADD = \ - $(top_builddir)/lib/libuasync.a \ - -lpthread \ - -lm - -# Install directories -install-exec-hook: - $(MKDIR_P) $(DESTDIR)$(bindir) - $(MKDIR_P) $(DESTDIR)$(sysconfdir)/utun diff --git a/!/config_parser.c b/!/config_parser.c deleted file mode 100755 index 1e1ad4b4..00000000 --- a/!/config_parser.c +++ /dev/null @@ -1,586 +0,0 @@ -// config_parser.c - Configuration parser for utun application (updated for new structures) -#define _POSIX_C_SOURCE 200809L -#include "config_parser.h" -#include -#include -#include -#include -#include "../lib/debug_config.h" -#include -#include -#include -#include -#include -#include - -#define MAX_LINE_LEN 1024 -#define INITIAL_ARRAY_CAPACITY 8 - -typedef enum { - SECTION_UNKNOWN, - SECTION_GLOBAL, - SECTION_SERVER, - SECTION_CLIENT, - SECTION_ROUTING -} section_type_t; - -static char* trim(char *str) { - if (!str) return NULL; - while (isspace((unsigned char)*str)) str++; - char *end = str + strlen(str) - 1; - while (end > str && isspace((unsigned char)*end)) end--; - *(end + 1) = '\0'; - return str; -} - -static int parse_key_value(const char *line, char *key, size_t key_len, char *value, size_t value_len) { - char *equal = strchr(line, '='); - if (!equal) return -1; - - size_t key_size = equal - line; - if (key_size >= key_len) return -1; - strncpy(key, line, key_size); - key[key_size] = '\0'; - trim(key); - - const char *val_start = equal + 1; - size_t val_len = strlen(val_start); - if (val_len >= value_len) return -1; - strcpy(value, val_start); - trim(value); - - return 0; -} - -static int assign_string(char *dest, size_t dest_size, const char *src) { - if (!dest || !src || strlen(src) >= dest_size) return -1; - strcpy(dest, src); - return 0; -} - -static int parse_ip_with_netmask(const char *str, struct IP *ip, uint8_t *netmask) { - char ip_str[64]; - strncpy(ip_str, str, sizeof(ip_str) - 1); - ip_str[sizeof(ip_str) - 1] = '\0'; - - char *slash = strchr(ip_str, '/'); - if (slash) { - *slash = '\0'; - *netmask = atoi(slash + 1); - } else { - *netmask = 32; // Default IPv4 netmask - } - - // Try IPv4 first - struct in_addr addr4; - if (inet_pton(AF_INET, ip_str, &addr4) == 1) { - ip->family = AF_INET; - ip->addr.v4 = addr4; - return 0; - } - - // Try IPv6 - struct in6_addr addr6; - if (inet_pton(AF_INET6, ip_str, &addr6) == 1) { - ip->family = AF_INET6; - ip->addr.v6 = addr6; - if (*netmask == 32) *netmask = 128; // Default IPv6 netmask - return 0; - } - - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "parse_ip_with_netmask: invalid IP address format: %s", str); - return -1; -} - -static int parse_sockaddr(const char *addr_str, const char *port_str, struct sockaddr_storage *sockaddr) { - struct addrinfo hints = {0}; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - - struct addrinfo *result; - if (getaddrinfo(addr_str, port_str, &hints, &result) != 0) { - return -1; - } - - memcpy(sockaddr, result->ai_addr, result->ai_addrlen); - freeaddrinfo(result); - return 0; -} - -static int parse_address_and_port(const char *str, struct sockaddr_storage *sockaddr) { - char addr_copy[MAX_ADDR_LEN]; - if (strlen(str) >= sizeof(addr_copy)) return -1; - strcpy(addr_copy, str); - - char *port_str = strrchr(addr_copy, ':'); - if (!port_str) return -1; - - *port_str = '\0'; - port_str++; - - return parse_sockaddr(addr_copy, port_str, sockaddr); -} - -static uint32_t get_netif_index(const char *ifname) { - if (!ifname || strlen(ifname) == 0) return 0; - return if_nametoindex(ifname); -} - -static struct CFG_CLIENT_LINK* create_client_link(struct CFG_SERVER* local_srv, const char *remote_addr) { - struct CFG_CLIENT_LINK *link = calloc(1, sizeof(struct CFG_CLIENT_LINK)); - if (!link) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "create_client_link: failed to allocate memory for client link"); - return NULL; - } - - link->local_srv = local_srv; - - if (parse_address_and_port(remote_addr, &link->remote_addr) < 0) { - free(link); - return NULL; - } - - link->next = NULL; - return link; -} - -static void free_cfg_client_links(struct CFG_CLIENT_LINK *links) { - while (links) { - struct CFG_CLIENT_LINK *next = links->next; - free(links); - links = next; - } -} - -static struct CFG_ROUTE_ENTRY* create_route_entry(const char *subnet_str) { - struct CFG_ROUTE_ENTRY *entry = calloc(1, sizeof(struct CFG_ROUTE_ENTRY)); - if (!entry) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "create_route_entry: failed to allocate memory for route entry"); - return NULL; - } - - if (parse_ip_with_netmask(subnet_str, &entry->ip, &entry->netmask) < 0) { - free(entry); - return NULL; - } - - entry->next = NULL; - return entry; -} - -static void free_route_entries(struct CFG_ROUTE_ENTRY *entries) { - while (entries) { - struct CFG_ROUTE_ENTRY *next = entries->next; - free(entries); - entries = next; - } -} - -static int add_route_entry(struct CFG_ROUTE_ENTRY **list, const char *subnet_str) { - struct CFG_ROUTE_ENTRY *new_entry = create_route_entry(subnet_str); - if (!new_entry) return -1; - - // Add to head of list - new_entry->next = *list; - *list = new_entry; - return 0; -} - -static struct CFG_SERVER* find_server_by_name(struct CFG_SERVER *servers, const char *name) { - struct CFG_SERVER *srv = servers; - while (srv) { - if (strcmp(srv->name, name) == 0) { - return srv; - } - srv = srv->next; - } - return NULL; -} - -static int parse_global(const char *key, const char *value, struct global_config *global) { - if (strcmp(key, "my_private_key") == 0) { - return assign_string(global->my_private_key_hex, MAX_KEY_LEN, value); - } - if (strcmp(key, "my_public_key") == 0) { - return assign_string(global->my_public_key_hex, MAX_KEY_LEN, value); - } - if (strcmp(key, "my_node_id") == 0) { - global->my_node_id = strtoull(value, NULL, 16); - return 0; - } - if (strcmp(key, "tun_ifname") == 0) { - snprintf(global->tun_ifname, sizeof(global->tun_ifname), "%s", value); - return 0; - } - if (strcmp(key, "tun_ip") == 0) { - uint8_t netmask; - return parse_ip_with_netmask(value, &global->tun_ip, &netmask); - } - if (strcmp(key, "mtu") == 0) { - global->mtu = atoi(value); - return 0; - } - if (strcmp(key, "control_ip") == 0) { - // Store for later processing with control_port - return 0; // We'll handle this when we see control_port - } - if (strcmp(key, "control_port") == 0) { - // This is tricky - we need to get control_ip from previous parsing - // For now, we'll use a simple approach - struct global_config temp_global = *global; - // Assume we stored control_ip somewhere or use default - char control_ip[MAX_ADDR_LEN] = "127.0.0.1"; // Default - char port_str[16]; - snprintf(port_str, sizeof(port_str), "%s", value); - parse_sockaddr(control_ip, port_str, &global->control_sock); - return 0; - } - if (strcmp(key, "net_debug") == 0) { - global->net_debug = atoi(value); - return 0; - } - return 0; -} - -static int parse_server(const char *key, const char *value, struct CFG_SERVER *srv) { - if (strcmp(key, "addr") == 0) { - return parse_address_and_port(value, &srv->ip); - } - if (strcmp(key, "so_mark") == 0) { - srv->so_mark = atoi(value); - return 0; - } - if (strcmp(key, "netif") == 0) { - srv->netif_index = get_netif_index(value); - return 0; - } - if (strcmp(key, "type") == 0) { - if (strcmp(value, "public") == 0) { - srv->type = CFG_SERVER_TYPE_PUBLIC; - } else if (strcmp(value, "nat") == 0) { - srv->type = CFG_SERVER_TYPE_NAT; - } else if (strcmp(value, "private") == 0) { - srv->type = CFG_SERVER_TYPE_PRIVATE; - } else { - srv->type = CFG_SERVER_TYPE_UNKNOWN; - } - return 0; - } - return 0; -} - -static int parse_client(const char *key, const char *value, struct CFG_CLIENT *cli, struct CFG_SERVER *servers) { - if (strcmp(key, "link") == 0) { - char link_copy[MAX_CONN_NAME_LEN + MAX_ADDR_LEN]; - if (strlen(value) >= sizeof(link_copy)) return -1; - strcpy(link_copy, value); - - // Find first colon (separator between server and ip:port) - char *first_colon = strchr(link_copy, ':'); - if (!first_colon) return -1; - - *first_colon = '\0'; - - // Find server by name - struct CFG_SERVER *local_srv = find_server_by_name(servers, link_copy); - if (!local_srv) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "parse_client: server '%s' not found for client link", link_copy); - return -1; - } - - struct CFG_CLIENT_LINK *new_link = create_client_link(local_srv, first_colon + 1); - if (!new_link) return -1; - - // Add to linked list (prepend) - new_link->next = cli->links; - cli->links = new_link; - - return 0; - } - - if (strcmp(key, "peer_public_key") == 0) { - return assign_string(cli->peer_public_key_hex, MAX_KEY_LEN, value); - } - - if (strcmp(key, "keepalive") == 0) { - cli->keepalive = atoi(value); - return 0; - } - - return 0; -} - -static section_type_t parse_section_header(const char *line, char *name, size_t name_len) { - if (line[0] != '[') return SECTION_UNKNOWN; - - size_t line_len = strlen(line); - if (line[line_len - 1] != ']') return SECTION_UNKNOWN; - - char section[128]; - if (line_len - 2 >= sizeof(section)) return SECTION_UNKNOWN; - - strncpy(section, line + 1, line_len - 2); - section[line_len - 2] = '\0'; - trim(section); - - if (strcasecmp(section, "global") == 0) return SECTION_GLOBAL; - if (strcasecmp(section, "routing") == 0) return SECTION_ROUTING; - - char *colon = strchr(section, ':'); - if (!colon) return SECTION_UNKNOWN; - - *colon = '\0'; - char *type = trim(section); - char *n = trim(colon + 1); - - if (strlen(n) >= name_len) return SECTION_UNKNOWN; - strcpy(name, n); - - if (strcasecmp(type, "server") == 0) return SECTION_SERVER; - if (strcasecmp(type, "client") == 0) return SECTION_CLIENT; - - return SECTION_UNKNOWN; -} - -static struct utun_config* parse_config_internal(FILE *fp, const char *filename) { - struct utun_config *cfg = calloc(1, sizeof(struct utun_config)); - if (!cfg) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "parse_config_internal: failed to allocate memory for config structure"); - return NULL; - } - - section_type_t cur_section = SECTION_UNKNOWN; - struct CFG_SERVER *cur_server = NULL; - struct CFG_CLIENT *cur_client = NULL; - char line[MAX_LINE_LEN]; - int line_num = 0; - - while (fgets(line, sizeof(line), fp)) { - line_num++; - char *trimmed = trim(line); - - if (trimmed[0] == '\0' || trimmed[0] == '#') continue; - - if (trimmed[0] == '[') { - // Handle previous section - if (cur_section == SECTION_SERVER && cur_server) { - // Add server to linked list - cur_server->next = cfg->servers; - cfg->servers = cur_server; - cur_server = NULL; - } - if (cur_section == SECTION_CLIENT && cur_client) { - // Add client to linked list - cur_client->next = cfg->clients; - cfg->clients = cur_client; - cur_client = NULL; - } - - char name[MAX_CONN_NAME_LEN]; - cur_section = parse_section_header(trimmed, name, sizeof(name)); - - if (cur_section == SECTION_SERVER) { - cur_server = calloc(1, sizeof(struct CFG_SERVER)); - if (!cur_server) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "parse_config_internal: failed to allocate memory for server %s", name); - goto error; - } - strcpy(cur_server->name, name); - } else if (cur_section == SECTION_CLIENT) { - cur_client = calloc(1, sizeof(struct CFG_CLIENT)); - if (!cur_client) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "parse_config_internal: failed to allocate memory for client %s", name); - goto error; - } - strcpy(cur_client->name, name); - } - continue; - } - - char key[MAX_LINE_LEN], value[MAX_LINE_LEN]; - if (parse_key_value(trimmed, key, sizeof(key), value, sizeof(value)) < 0) { - printf( "%s:%d: Invalid key=value format", filename, line_num); - continue; - } - - switch (cur_section) { - case SECTION_GLOBAL: - if (parse_global(key, value, &cfg->global) < 0) { - printf( "%s:%d: Invalid global key '%s'", filename, line_num, key); - } - break; - case SECTION_SERVER: - if (cur_server && parse_server(key, value, cur_server) < 0) { - printf( "%s:%d: Invalid server key '%s'", filename, line_num, key); - } - break; - case SECTION_CLIENT: - if (cur_client && parse_client(key, value, cur_client, cfg->servers) < 0) { - printf( "%s:%d: Invalid client key '%s'", filename, line_num, key); - } - break; - case SECTION_ROUTING: - if (strcmp(key, "allowed_subnet") == 0) { - add_route_entry(&cfg->allowed_subnets, value); - } else if (strcmp(key, "my_subnet") == 0) { - add_route_entry(&cfg->my_subnets, value); - } - break; - default: - printf( "%s:%d: Key outside section: %s", filename, line_num, key); - break; - } - } - - // Handle final sections - if (cur_section == SECTION_SERVER && cur_server) { - cur_server->next = cfg->servers; - cfg->servers = cur_server; - } - if (cur_section == SECTION_CLIENT && cur_client) { - cur_client->next = cfg->clients; - cfg->clients = cur_client; - } - - // Set default TUN interface name if not provided - if (cfg->global.tun_ifname[0] == '\0') { - snprintf(cfg->global.tun_ifname, sizeof(cfg->global.tun_ifname), "tun0"); - DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Auto-generated TUN interface name: %s", cfg->global.tun_ifname); - } - - return cfg; - -error: - if (cur_server) free(cur_server); - if (cur_client) { - free_cfg_client_links(cur_client->links); - free(cur_client); - } - free_config(cfg); - return NULL; -} - -struct utun_config* parse_config(const char *filename) { - printf("[CONFIG DEBUG] Opening config file: %s\n", filename); - FILE *fp = fopen(filename, "r"); - if (!fp) { - printf("[CONFIG ERROR] Failed to open config file: %s (errno=%d)\n", filename, errno); - return NULL; - } - - printf("[CONFIG DEBUG] Successfully opened config file\n"); - struct utun_config *config = parse_config_internal(fp, filename); - fclose(fp); - return config; -} - -void free_config(struct utun_config *config) { - if (!config) return; - - // Free servers - struct CFG_SERVER *server = config->servers; - while (server) { - struct CFG_SERVER *next = server->next; - free(server); - server = next; - } - - // Free clients and their links - struct CFG_CLIENT *client = config->clients; - while (client) { - struct CFG_CLIENT *next = client->next; - free_cfg_client_links(client->links); - free(client); - client = next; - } - - // Free route entries - free_route_entries(config->allowed_subnets); - free_route_entries(config->my_subnets); - - free(config); -} - -static const char* ip_to_string(const struct IP *ip, char *buffer, size_t buffer_size) { - if (ip->family == AF_INET) { - inet_ntop(AF_INET, &ip->addr.v4, buffer, buffer_size); - } else if (ip->family == AF_INET6) { - inet_ntop(AF_INET6, &ip->addr.v6, buffer, buffer_size); - } else { - snprintf(buffer, buffer_size, "invalid"); - } - return buffer; -} - -void print_config(const struct utun_config *cfg) { - if (!cfg) return; - - const struct global_config *g = &cfg->global; - char ip_buffer[64]; - - printf("Global:\n"); - printf(" Private key: %s\n", g->my_private_key_hex); - printf(" Public key: %s\n", g->my_public_key_hex); - printf(" Node ID: %llx\n", (unsigned long long)g->my_node_id); - printf(" TUN interface: %s\n", g->tun_ifname[0] ? g->tun_ifname : "auto"); - printf(" TUN IP: %s\n", ip_to_string(&g->tun_ip, ip_buffer, sizeof(ip_buffer))); - printf(" MTU: %d\n", g->mtu); - printf(" Net debug: %d\n", g->net_debug); - - printf("\nServers:\n"); - struct CFG_SERVER *s = cfg->servers; - while (s) { - char addr_buffer[64]; - struct sockaddr_in *sin = (struct sockaddr_in *)&s->ip; - inet_ntop(AF_INET, &sin->sin_addr, addr_buffer, sizeof(addr_buffer)); - printf(" %s: %s:%d (mark=%d, netif=%u, type=%u)\n", - s->name, addr_buffer, ntohs(sin->sin_port), - s->so_mark, s->netif_index, s->type); - s = s->next; - } - - printf("\nClients:\n"); - struct CFG_CLIENT *c = cfg->clients; - while (c) { - printf(" %s:\n", c->name); - struct CFG_CLIENT_LINK *link = c->links; - int link_num = 1; - while (link) { - char addr_buffer[64]; - struct sockaddr_in *sin = (struct sockaddr_in *)&link->remote_addr; - inet_ntop(AF_INET, &sin->sin_addr, addr_buffer, sizeof(addr_buffer)); - printf(" Link %d: %s:%d (via %s)\n", link_num++, addr_buffer, ntohs(sin->sin_port), link->local_srv->name); - link = link->next; - } - printf(" Peer key: %s\n", c->peer_public_key_hex); - printf(" Keepalive: %d\n", c->keepalive); - c = c->next; - } - - printf("\nAllowed Subnets:\n"); - struct CFG_ROUTE_ENTRY *allowed = cfg->allowed_subnets; - while (allowed) { - printf(" %s/%d\n", ip_to_string(&allowed->ip, ip_buffer, sizeof(ip_buffer)), allowed->netmask); - allowed = allowed->next; - } - - printf("\nMy Subnets:\n"); - struct CFG_ROUTE_ENTRY *my = cfg->my_subnets; - while (my) { - printf(" %s/%d\n", ip_to_string(&my->ip, ip_buffer, sizeof(ip_buffer)), my->netmask); - my = my->next; - } -} - -int update_config_keys(const char *filename, const char *priv_key, const char *pub_key) { - // Minimal implementation: just append to file - FILE *fp = fopen(filename, "a"); - if (!fp) return -1; - - fprintf(fp, "\n[global]\n"); - fprintf(fp, "my_private_key=%s\n", priv_key); - fprintf(fp, "my_public_key=%s\n", pub_key); - - fclose(fp); - return 0; -} \ No newline at end of file diff --git a/!/config_parser.h b/!/config_parser.h deleted file mode 100755 index 93861f89..00000000 --- a/!/config_parser.h +++ /dev/null @@ -1,89 +0,0 @@ -// config_parser.h - Configuration parser for utun application -#ifndef CONFIG_PARSER_H -#define CONFIG_PARSER_H - -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define MAX_CONN_NAME_LEN 64 -#define MAX_KEY_LEN 256 -#define MAX_ADDR_LEN 64 - -struct IP { - sa_family_t family; - union { - struct in_addr v4; - struct in6_addr v6; - } addr; -}; - -#define CFG_SERVER_TYPE_UNKNOWN 0 -#define CFG_SERVER_TYPE_PUBLIC 1 -#define CFG_SERVER_TYPE_NAT 2 -#define CFG_SERVER_TYPE_PRIVATE 3 - -struct CFG_SERVER { - struct CFG_SERVER* next; - char name[MAX_CONN_NAME_LEN]; - struct sockaddr_storage ip; // ip:port - uint32_t netif_index;// if_nameindex, 0 - no interface specified - int so_mark; - uint8_t type; // public/nat/private -}; - -struct CFG_CLIENT_LINK { - struct CFG_CLIENT_LINK *next; // Next link in linked list - struct CFG_SERVER* local_srv; - struct sockaddr_storage remote_addr; // ip:port -}; - -struct CFG_CLIENT { - char name[MAX_CONN_NAME_LEN]; - char peer_public_key_hex[MAX_KEY_LEN]; - int keepalive; - struct CFG_CLIENT_LINK *links; // Linked list of links - struct CFG_CLIENT *next; // Next client in linked list -}; - -struct CFG_ROUTE_ENTRY { - struct CFG_ROUTE_ENTRY* next; - struct IP ip; - uint8_t netmask; -}; - -struct global_config { - char my_private_key_hex[MAX_KEY_LEN]; - char my_public_key_hex[MAX_KEY_LEN]; - uint64_t my_node_id; - char tun_ifname[16]; // TUN interface name (e.g., "tun12") - struct IP tun_ip; - int mtu; - struct sockaddr_storage control_sock; - int net_debug; -}; - -struct utun_config { - struct global_config global; - struct CFG_SERVER* servers; - struct CFG_CLIENT* clients; - struct CFG_ROUTE_ENTRY* allowed_subnets; - struct CFG_ROUTE_ENTRY* my_subnets; -}; - -struct utun_config* parse_config(const char *filename); -void free_config(struct utun_config *config); -void print_config(const struct utun_config *config); -int update_config_keys(const char *filename, const char *priv_key, const char *pub_key); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/!/config_updater.c b/!/config_updater.c deleted file mode 100755 index 8fa3d797..00000000 --- a/!/config_updater.c +++ /dev/null @@ -1,427 +0,0 @@ -// config_updater.c - Configuration file updater implementation -#define _POSIX_C_SOURCE 200809L -#include "config_updater.h" -#include "config_parser.h" -#include "secure_channel.h" -#include "debug_config.h" -#include -#include -#include -#include -#include -#include -#include - -#define PRIV_HEXKEY_LEN 65 // 32 bytes * 2 hex chars + null -#define PUB_HEXKEY_LEN 129 // 64 bytes * 2 hex chars + null -#define HEXNODEID_LEN 17 // 8 bytes * 2 hex chars + null -#define MAX_LINE_LEN 1024 - -void bytes_to_hex(const uint8_t *bytes, size_t len, char *hex_str, size_t hex_len) { - if (!bytes || !hex_str || hex_len < len * 2 + 1) { - if (hex_str && hex_len > 0) hex_str[0] = '\0'; - return; - } - for (size_t i = 0; i < len; i++) { - snprintf(hex_str + i * 2, hex_len - i * 2, "%02x", bytes[i]); - - } - hex_str[len * 2] = '\0'; -} - - -static int is_valid_priv_key(const char *key) { - if (!key || strlen(key) != 64) return 0; - for (int i = 0; i < 64; i++) { - if (!isxdigit((unsigned char)key[i])) return 0; - } - return 1; -} - -static int is_valid_pub_key(const char *key) { - if (!key || strlen(key) != 128) return 0; - for (int i = 0; i < 128; i++) { - if (!isxdigit((unsigned char)key[i])) return 0; - } - return 1; -} - -static int is_valid_node_id(uint64_t node_id) { - return node_id != 0; -} - -static int read_file_to_mem(const char *filename, char **buffer, size_t *size) { - FILE *fp = fopen(filename, "r"); - - if (!fp) return -1; - - fseek(fp, 0, SEEK_END); - - long file_size = ftell(fp); - - if (file_size < 0) { - fclose(fp); - - return -1; - } - fseek(fp, 0, SEEK_SET); - - - *buffer = malloc(file_size + 1); - - if (!*buffer) { - fclose(fp); - - return -1; - } - - size_t read_size = fread(*buffer, 1, file_size, fp); - - if (read_size != (size_t)file_size) { - free(*buffer); - - fclose(fp); - - return -1; - } - - (*buffer)[file_size] = '\0'; - *size = file_size; - fclose(fp); - - return 0; -} - -static int write_mem_to_file(const char *filename, const char *buffer, size_t size) { - FILE *fp = fopen(filename, "w"); - - if (!fp) return -1; - - size_t written = fwrite(buffer, 1, size, fp); - - if (written != size) { - fclose(fp); - - return -1; - } - - fclose(fp); - - return 0; -} - -static char* find_section_global(char *buf, size_t buf_len) { - char *p = buf; - while (p < buf + buf_len) { - if (p[0] == '[' && strncmp(p + 1, "global", 6) == 0) { - char *end = strchr(p, ']'); - - if (end) return end + 1; - } - p = strchr(p, '\n'); - - if (!p) break; - p++; // skip '\n' - } - return NULL; -} - -static char* find_option(char *buf, size_t buf_len, const char *option) { - char *p = buf; - while (p < buf + buf_len) { - if (strncmp(p, option, strlen(option)) == 0) { - char *after_key = p + strlen(option); - - if (after_key[0] == '=') return p; - } - p = strchr(p, '\n'); - - if (!p) break; - p++; - } - return NULL; -} - -static int insert_or_replace_option(char **buf, size_t *buf_len, size_t *buf_capacity, const char *option, const char *value) { - if (!buf || !*buf || !buf_len || !buf_capacity || !option || !value) return -1; - - // Check if option already exists - char *opt_pos = find_option(*buf, *buf_len, option); - - if (opt_pos) { - // Find option line end - char *line_end = strchr(opt_pos, '\n'); - - if (!line_end) line_end = *buf + *buf_len; - - // Prepare new line - char new_line[MAX_LINE_LEN]; - int new_len = snprintf(new_line, sizeof(new_line), "%s=%s\n", option, value); - - if (new_len <= 0 || new_len >= (int)sizeof(new_line)) return -1; - - // Calculate length difference - size_t old_line_len = line_end - opt_pos + 1; - long len_diff = new_len - old_line_len; - - // Ensure buffer capacity - if (*buf_len + len_diff + 1 > *buf_capacity) { - *buf_capacity = *buf_len + len_diff + 1024; - char *new_buf = realloc(*buf, *buf_capacity); - - if (!new_buf) return -1; - *buf = new_buf; - // Recalculate positions after realloc - opt_pos = find_option(*buf, *buf_len, option); - - if (!opt_pos) return -1; - line_end = strchr(opt_pos, '\n'); - - if (!line_end) line_end = *buf + *buf_len; - } - - // Move content and insert new line - memmove(opt_pos + new_len, line_end, *buf_len - (line_end - *buf) + 1); - - memcpy(opt_pos, new_line, new_len); - - *buf_len += len_diff; - - } else { - // Insert after [global] section - char *section_end = find_section_global(*buf, *buf_len); - - if (!section_end) return -1; - - // Find end of global section (next [ or end of buffer) - char *insert_pos = strchr(section_end, '['); - - if (!insert_pos) insert_pos = *buf + *buf_len; - else { - // Move to beginning of next line - char *prev_nl = insert_pos; - while (prev_nl > *buf && *prev_nl != '\n') prev_nl--; - if (*prev_nl == '\n') insert_pos = prev_nl + 1; - } - - // Prepare new line - char new_line[MAX_LINE_LEN]; - int new_len = snprintf(new_line, sizeof(new_line), "%s=%s\n", option, value); - - if (new_len <= 0 || new_len >= (int)sizeof(new_line)) return -1; - - // Ensure buffer capacity - if (*buf_len + new_len + 1 > *buf_capacity) { - *buf_capacity = *buf_len + new_len + 1024; - char *new_buf = realloc(*buf, *buf_capacity); - - if (!new_buf) return -1; - *buf = new_buf; - // Recalculate insert position after realloc - section_end = find_section_global(*buf, *buf_len); - - if (!section_end) return -1; - insert_pos = strchr(section_end, '['); - - if (!insert_pos) insert_pos = *buf + *buf_len; - else { - char *prev_nl = insert_pos; - while (prev_nl > *buf && *prev_nl != '\n') prev_nl--; - if (*prev_nl == '\n') insert_pos = prev_nl + 1; - } - } - - // Move content and insert new line - memmove(insert_pos + new_len, insert_pos, *buf_len - (insert_pos - *buf) + 1); - - memcpy(insert_pos, new_line, new_len); - - *buf_len += new_len; - } - - return 0; -} - -int config_ensure_keys_and_node_id(const char *filename) { - struct utun_config *config = parse_config(filename); - - if (!config) { - printf("[CONFIG ERROR] Failed to parse config: %s\n", filename); - - return -1; - } - - struct global_config *global = &config->global; - - // Debug: print what we found - printf("[CONFIG DEBUG] Checking config - priv_key='%s' (len=%zu), pub_key='%s' (len=%zu), node_id=%llu\n", - global->my_private_key_hex ? global->my_private_key_hex : "NULL", - global->my_private_key_hex ? strlen(global->my_private_key_hex) : 0, - global->my_public_key_hex ? global->my_public_key_hex : "NULL", - global->my_public_key_hex ? strlen(global->my_public_key_hex) : 0, - (unsigned long long)global->my_node_id); - - - // Check if we need to generate anything - int need_priv_key = !is_valid_priv_key(global->my_private_key_hex); - - int need_pub_key = !is_valid_pub_key(global->my_public_key_hex); - - int need_node_id = !is_valid_node_id(global->my_node_id); - - - printf("[CONFIG DEBUG] Validation results - need_priv_key=%d, need_pub_key=%d, need_node_id=%d\n", - need_priv_key, need_pub_key, need_node_id); - - - if (!need_priv_key && !need_pub_key && !need_node_id) { - free_config(config); - - return 0; - } - - // Generate keys if needed - char new_priv_key[PRIV_HEXKEY_LEN] = {0}; - char new_pub_key[PUB_HEXKEY_LEN] = {0}; - uint64_t new_node_id = 0; - - if (need_priv_key) { - // Generate new keypair if private key is invalid - struct SC_MYKEYS mykeys; - if (sc_generate_keypair(&mykeys) != SC_OK) { - printf( "Failed to generate keypair"); - - free_config(config); - - return -1; - } - bytes_to_hex(mykeys.private_key, SC_PRIVKEY_SIZE, new_priv_key, sizeof(new_priv_key)); - - bytes_to_hex(mykeys.public_key, SC_PUBKEY_SIZE, new_pub_key, sizeof(new_pub_key)); - - } else if (need_pub_key) { - // Compute public key from existing private key - uint8_t priv_bin[SC_PRIVKEY_SIZE]; - uint8_t pub_bin[SC_PUBKEY_SIZE]; - - // Convert private key from hex to binary - for (int i = 0; i < SC_PRIVKEY_SIZE; i++) { - unsigned int byte; - if (sscanf(global->my_private_key_hex + i * 2, "%2x", &byte) != 1) { - printf( "Invalid private key hex format"); - - free_config(config); - - return -1; - } - priv_bin[i] = (uint8_t)byte; - } - - // Compute public key - if (sc_compute_public_key_from_private(priv_bin, pub_bin) != SC_OK) { - printf( "Failed to compute public key from private key"); - - free_config(config); - - return -1; - } - - // Convert to hex - bytes_to_hex(priv_bin, SC_PRIVKEY_SIZE, new_priv_key, sizeof(new_priv_key)); - - bytes_to_hex(pub_bin, SC_PUBKEY_SIZE, new_pub_key, sizeof(new_pub_key)); - - } - - if (need_node_id) { - int fd = open("/dev/urandom", O_RDONLY); - - if (fd < 0) { - printf( "Failed to open /dev/urandom"); - - free_config(config); - - return -1; - } - if (read(fd, &new_node_id, sizeof(new_node_id)) != sizeof(new_node_id)) { - close(fd); - - printf( "Failed to read random bytes for node_id"); - - free_config(config); - - return -1; - } - close(fd); - - new_node_id &= 0x7FFFFFFFFFFFFFFF; - } - - free_config(config); - - - // Read entire config file to memory - char *file_buf = NULL; - size_t file_size = 0; - if (read_file_to_mem(filename, &file_buf, &file_size) < 0) { - printf( "Failed to read config file: %s", filename); - - return -1; - } - - // Update config file - size_t buf_capacity = file_size + 1024; - char *work_buf = malloc(buf_capacity); - - if (!work_buf) { - free(file_buf); - - return -1; - } - memcpy(work_buf, file_buf, file_size); - - size_t work_len = file_size; - - int ret = 0; - - if (need_node_id) { - char node_id_hex[HEXNODEID_LEN + 1]; - snprintf(node_id_hex, sizeof(node_id_hex), "%llx", (unsigned long long)new_node_id); - - if (insert_or_replace_option(&work_buf, &work_len, &buf_capacity, "my_node_id", node_id_hex) < 0) { - ret = -1; - } - } - - if (need_priv_key && ret == 0) { - if (insert_or_replace_option(&work_buf, &work_len, &buf_capacity, "my_private_key", new_priv_key) < 0) { - ret = -1; - } - } - - if (need_pub_key && ret == 0) { - if (insert_or_replace_option(&work_buf, &work_len, &buf_capacity, "my_public_key", new_pub_key) < 0) { - ret = -1; - } - } - - if (ret == 0) { - printf("[CONFIG DEBUG] Writing updated config file, work_len=%zu\n", work_len); - - if (write_mem_to_file(filename, work_buf, work_len) < 0) { - printf( "Failed to write updated config file: %s", filename); - - ret = -1; - } else { - printf("[CONFIG DEBUG] Successfully updated config file: %s\n", filename); - - } - } - - free(file_buf); - - free(work_buf); - - - return ret; -} diff --git a/!/config_updater.h b/!/config_updater.h deleted file mode 100755 index 283f434f..00000000 --- a/!/config_updater.h +++ /dev/null @@ -1,23 +0,0 @@ -// config_updater.h - Configuration file updater -#ifndef CONFIG_UPDATER_H -#define CONFIG_UPDATER_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// Ensures config file has valid my_private_key, my_public_key, and my_node_id -// If any are missing or invalid, generates and updates them -// Returns 0 on success, -1 on error -int config_ensure_keys_and_node_id(const char *filename); - -void bytes_to_hex(const uint8_t *bytes, size_t len, char *hex_str, size_t hex_len); - -#ifdef __cplusplus -} -#endif - -#endif // CONFIG_UPDATER_H diff --git a/!/crc32.c b/!/crc32.c deleted file mode 100755 index 8ed4db45..00000000 --- a/!/crc32.c +++ /dev/null @@ -1,66 +0,0 @@ -// crc32.c - CRC32 checksum implementation -#include "crc32.h" -#include - -static uint32_t crc32_table[256]; -static int crc32_table_initialized = 0; - -static void init_crc32_table(void) { - if (crc32_table_initialized) return; - - for (uint32_t i = 0; i < 256; i++) { - uint32_t crc = i; - for (int j = 0; j < 8; j++) { - if (crc & 1) { - crc = (crc >> 1) ^ 0xEDB88320; - } else { - crc >>= 1; - } - } - crc32_table[i] = crc; - } - - crc32_table_initialized = 1; -} - -void crc32_init(void) { - init_crc32_table(); -} - -uint32_t crc32_calc(const uint8_t *data, size_t len) { - if (!crc32_table_initialized) { - init_crc32_table(); - } - - if (!data || len == 0) return 0xFFFFFFFF; - - uint32_t crc = 0xFFFFFFFF; - for (size_t i = 0; i < len; i++) { - uint8_t byte = data[i]; - uint32_t table_index = (crc ^ byte) & 0xFF; - crc = (crc >> 8) ^ crc32_table[table_index]; - } - - return ~crc; -} - -uint32_t crc32_calc_ex(const uint8_t *data, size_t len, uint32_t initial_crc) { - if (!crc32_table_initialized) { - init_crc32_table(); - } - - if (!data || len == 0) return initial_crc; - - uint32_t crc = initial_crc; - for (size_t i = 0; i < len; i++) { - uint8_t byte = data[i]; - uint32_t table_index = (crc ^ byte) & 0xFF; - crc = (crc >> 8) ^ crc32_table[table_index]; - } - - return crc; -} - -uint32_t crc32_update(uint32_t crc, const uint8_t *data, size_t len) { - return crc32_calc_ex(data, len, crc); -} \ No newline at end of file diff --git a/!/crc32.h b/!/crc32.h deleted file mode 100755 index ea1a334b..00000000 --- a/!/crc32.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef CRC32_H -#define CRC32_H - -#include -#include - -// Initialize CRC32 table (called automatically on first use) -void crc32_init(void); - -// Calculate CRC32 checksum -uint32_t crc32_calc(const uint8_t *data, size_t len); - -// Calculate CRC32 with initial value -uint32_t crc32_calc_ex(const uint8_t *data, size_t len, uint32_t initial_crc); - -// Update CRC32 incrementally -uint32_t crc32_update(uint32_t crc, const uint8_t *data, size_t len); - -#endif // CRC32_H \ No newline at end of file diff --git a/!/etcp.c b/!/etcp.c deleted file mode 100755 index b4b0da02..00000000 --- a/!/etcp.c +++ /dev/null @@ -1,1112 +0,0 @@ -// etcp.c - ETCP Protocol Implementation (refactored and expanded based on etcp_protocol.txt) -#include "etcp.h" -#include "etcp_loadbalancer.h" -#include "../lib/u_async.h" -#include "../lib/debug_config.h" -#include "crc32.h" -#include -#include -#include -#include // For bandwidth calcs - -// Enable comprehensive debug output for ETCP module -#define DEBUG_CATEGORY_ETCP_DETAILED 1 - -// Constants from spec (adjusted for completeness) -#define MAX_INFLIGHT_BYTES 65536 // Initial window -#define RETRANS_K1 2.0f // RTT multiplier for retrans timeout -#define RETRANS_K2 1.5f // Jitter multiplier -#define ACK_DELAY_TB 20 // ACK timer delay (2ms in 0.1ms units) -#define BURST_DELAY_FACTOR 4 // Delay before burst -#define BURST_SIZE 5 // Packets in burst (1 delayed + 4 burst) -#define RTT_HISTORY_SIZE 10 // For jitter calc -#define MAX_PENDING 32 // For ACKs/retrans -#define SECTION_HEADER_SIZE 3 // type(1) + len(2) - -// Forward declaration for callback function -static void input_queue_cb(struct ll_queue* q, struct ll_entry* entry, void* arg); - -// Timestamp diff (with wrap-around) -static uint16_t timestamp_diff(uint16_t t1, uint16_t t2) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "timestamp_diff: t1=%u, t2=%u", t1, t2); - if (t1 >= t2) { - uint16_t diff = t1 - t2; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "timestamp_diff: normal case, diff=%u", diff); - return diff; - } - uint16_t diff = (0xFFFF - t2) + t1 + 1; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "timestamp_diff: wraparound case, diff=%u", diff); - return diff; -} - -// Get current time in 0.1ms units -uint64_t get_current_time_units() { - struct timeval tv; - gettimeofday(&tv, NULL); - uint64_t time_units = ((uint64_t)tv.tv_sec * 10000ULL) + (tv.tv_usec / 100); - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "get_current_time_units: tv_sec=%ld, tv_usec=%ld, result=%llu", - tv.tv_sec, tv.tv_usec, (unsigned long long)time_units); - return time_units; -} - -uint16_t get_current_timestamp() { - uint16_t timestamp = (uint16_t)(get_current_time_units() & 0xFFFF); - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "get_current_timestamp: result=%u", timestamp); - return timestamp; -} - -// Internal functions (expanded) -static void retrans_timer_cb(void* arg); -static void ack_timer_cb(void* arg); -static void update_rtt(struct ETCP_CONN* etcp, uint16_t new_rtt); -static void calculate_jitter(struct ETCP_CONN* etcp); -static void detect_gaps_and_request_retrans(struct ETCP_CONN* etcp); -static void process_section_ack(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len); -static void process_section_retrans(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len); -static void process_section_timestamp(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len); -static void process_section_payload(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len); -static void process_section_meas_ts(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len); -static void process_section_meas_resp(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len); -static uint16_t append_optional_sections(struct ETCP_CONN* etcp, uint8_t* buf, struct ETCP_LINK* link); -static void deliver_contiguous_packets(struct ETCP_CONN* etcp); -static void retrans_check(struct ETCP_CONN* etcp); -static inflight_packet_t* find_inflight(struct ETCP_CONN* etcp, uint16_t id, uint8_t state); -static void move_to_wait_send(struct ETCP_CONN* etcp, inflight_packet_t* pkt); -static void remove_inflight(struct ETCP_CONN* etcp, inflight_packet_t* pkt); -static void free_inflight_packet(inflight_packet_t* pkt); -static void start_burst_measurement(struct ETCP_CONN* etcp, struct ETCP_LINK* link); -static void update_link_bandwidth(struct ETCP_LINK* link, uint32_t new_bw); - -// Add RTT history to struct (for jitter) -/// In etcp.h, add to ETCP_CONN: -/// uint16_t rtt_history[RTT_HISTORY_SIZE]; -/// uint8_t rtt_history_idx; - -// Create ETCP connection (unchanged) -struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_create: instance=%p", instance); - - struct ETCP_CONN* etcp = calloc(1, sizeof(struct ETCP_CONN)); - if (!etcp) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_connection_create: failed to allocate ETCP_CONN"); - return NULL; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_create: allocated etcp=%p", etcp); - - etcp->instance = instance; - etcp->input_queue = queue_new(instance->ua, instance->pkt_pool); - etcp->output_queue = queue_new(instance->ua, instance->pkt_pool); - etcp->mtu = 1500; // Default - etcp->window_size = MAX_INFLIGHT_BYTES; - etcp->next_tx_id = 1; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_create: queues created, mtu=%d, window_size=%u, next_tx_id=%u", - etcp->mtu, etcp->window_size, etcp->next_tx_id); - - // Init crypto (as per original) - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_create: initializing crypto context"); - if (sc_init_ctx(&etcp->crypto_ctx, &instance->my_keys) != SC_OK) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_connection_create: crypto initialization failed"); - etcp_connection_close(etcp); - return NULL; - } - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_connection_create: successfully created ETCP connection %p", etcp); - return etcp; -} - -// Close connection (expanded free) -void etcp_connection_close(struct ETCP_CONN* etcp) { - if (!etcp) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_connection_close: called with NULL etcp"); - return; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: closing connection %p", etcp); - - // Cancel timers - if (etcp->retrans_timer) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: canceling retrans_timer"); - uasync_cancel_timeout(etcp->instance->ua, etcp->retrans_timer); - } - if (etcp->ack_timer) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: canceling ack_timer"); - uasync_cancel_timeout(etcp->instance->ua, etcp->ack_timer); - } - - // Free inflight - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freeing wait_ack_list"); - inflight_packet_t* pkt = etcp->wait_ack_list; - int wait_ack_count = 0; - while (pkt) { - inflight_packet_t* next = pkt->next; - free_inflight_packet(pkt); - pkt = next; - wait_ack_count++; - } - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freed %d packets from wait_ack_list", wait_ack_count); - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freeing wait_send_list"); - pkt = etcp->wait_send_list; - int wait_send_count = 0; - while (pkt) { - inflight_packet_t* next = pkt->next; - free_inflight_packet(pkt); - pkt = next; - wait_send_count++; - } - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freed %d packets from wait_send_list", wait_send_count); - - // Free rx_list - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freeing rx_list"); - rx_packet_t* rx = etcp->rx_list; - int rx_count = 0; - while (rx) { - rx_packet_t* next = rx->next; - free(rx->data); - free(rx); - rx = next; - rx_count++; - } - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freed %d packets from rx_list", rx_count); - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freeing queues"); - queue_free(etcp->input_queue); - queue_free(etcp->output_queue); - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_connection_close: connection %p closed successfully", etcp); - free(etcp); -} - -static void free_inflight_packet(inflight_packet_t* pkt) { - if (pkt) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "free_inflight_packet: freeing packet %p (id=%u, data_len=%u)", - pkt, pkt->id, pkt->data_len); - free(pkt->data); - free(pkt); - } -} - -// Reset connection (unchanged) -void etcp_conn_reset(struct ETCP_CONN* etcp) { - if (!etcp) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_conn_reset: called with NULL etcp"); - return; - } - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_conn_reset: resetting connection %p", etcp); - - // Cancel timers - if (etcp->retrans_timer) uasync_cancel_timeout(etcp->instance->ua, etcp->retrans_timer); - if (etcp->ack_timer) uasync_cancel_timeout(etcp->instance->ua, etcp->ack_timer); - - // Free lists - inflight_packet_t* pkt = etcp->wait_ack_list; - while (pkt) { - inflight_packet_t* next = pkt->next; - free_inflight_packet(pkt); - pkt = next; - } - etcp->wait_ack_list = NULL; - pkt = etcp->wait_send_list; - while (pkt) { - inflight_packet_t* next = pkt->next; - free_inflight_packet(pkt); - pkt = next; - } - etcp->wait_send_list = NULL; - - rx_packet_t* rx = etcp->rx_list; - while (rx) { - rx_packet_t* next = rx->next; - free(rx->data); - free(rx); - rx = next; - } - etcp->rx_list = NULL; - - // Reset state - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_conn_reset: clearing packet lists and resetting state"); - etcp->next_tx_id = 1; - etcp->last_rx_id = 0; - etcp->last_delivered_id = 0; - etcp->unacked_bytes = 0; - etcp->pending_ack_count = 0; - etcp->pending_retrans_count = 0; - etcp->rtt_last = 0; - etcp->rtt_avg_10 = 0; - etcp->rtt_avg_100 = 0; - etcp->jitter = 0; - etcp->burst_in_progress = 0; - etcp->rtt_history_idx = 0; - memset(etcp->rtt_history, 0, sizeof(etcp->rtt_history)); - // Queues cleared externally if needed - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_conn_reset: connection %p reset completed", etcp); -} - -// Input decrypted packet (unchanged structure, but calls expanded processes) -void etcp_conn_input(struct ETCP_DGRAM* pkt) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_conn_input: pkt=%p, link=%p, etcp=%p", - pkt, pkt ? pkt->link : NULL, pkt && pkt->link ? pkt->link->etcp : NULL); - - if (!pkt || !pkt->link || !pkt->link->etcp) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_conn_input: invalid parameters (pkt=%p, link=%p, etcp=%p)", - pkt, pkt ? pkt->link : NULL, pkt && pkt->link ? pkt->link->etcp : NULL); - return; - } - - struct ETCP_CONN* etcp = pkt->link->etcp; - uint8_t* data = pkt->data; - uint16_t len = pkt->data_len; - uint16_t ts = pkt->timestamp; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_conn_input: processing packet - etcp=%p, data_len=%u, timestamp=%u, link=%p", - etcp, len, ts, pkt->link); - - // Update link activity - pkt->link->last_activity = get_current_time_units(); - pkt->link->last_recv_local_time = pkt->link->last_activity; - pkt->link->last_recv_timestamp = ts; - - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_conn_input: updated link activity - last_activity=%llu, last_recv_timestamp=%u", - (unsigned long long)pkt->link->last_activity, pkt->link->last_recv_timestamp); - - // Parse sections - uint16_t pos = 0; - while (pos < len) { - if (pos + SECTION_HEADER_SIZE > len) break; - - uint8_t type = data[pos]; - uint16_t sec_len = (data[pos+1] << 8) | data[pos+2]; - pos += SECTION_HEADER_SIZE; - - if (pos + sec_len > len) break; - - uint8_t* sec_data = data + pos; - switch (type) { - case ETCP_SECTION_ACK: - process_section_ack(etcp, sec_data, sec_len); - break; - case ETCP_SECTION_RETRANS: - process_section_retrans(etcp, sec_data, sec_len); - break; - case ETCP_SECTION_TIMESTAMP: - process_section_timestamp(etcp, sec_data, sec_len); - break; - case ETCP_SECTION_PAYLOAD: - process_section_payload(etcp, sec_data, sec_len); - break; - case ETCP_SECTION_MEAS_TS: - process_section_meas_ts(etcp, sec_data, sec_len); - break; - case ETCP_SECTION_MEAS_RESP: - process_section_meas_resp(etcp, sec_data, sec_len); - break; - default: - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "Unknown section type: 0x%02x", type); - break; - } - pos += sec_len; - } - - // Post-processing - detect_gaps_and_request_retrans(etcp); - deliver_contiguous_packets(etcp); - - // Trigger if waiting - if (etcp->wait_timeout_active) { - etcp->wait_timeout_active = 0; - // Assume load balancer polls again - } -} - -// Request next packet (expanded) -struct ETCP_DGRAM* etcp_request_pkt(struct ETCP_CONN* etcp) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: etcp=%p", etcp); - - if (!etcp) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: called with NULL etcp"); - return NULL; - } - - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: input_queue_count=%d, wait_send_list=%p, unacked_bytes=%u, window_size=%u", - queue_entry_count(etcp->input_queue), etcp->wait_send_list, - etcp->unacked_bytes, etcp->window_size); - - // Check waiting conditions - if (queue_entry_count(etcp->input_queue) == 0 && etcp->wait_send_list == NULL) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: no packets available, setting callback and returning NULL"); - // Wait for input or retrans - // Set callback for resume - queue_set_callback(etcp->input_queue, input_queue_cb, etcp); // Define cb to resume - return NULL; - } - - if (etcp->unacked_bytes >= etcp->window_size) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: window full (unacked_bytes=%u >= window_size=%u), waiting", - etcp->unacked_bytes, etcp->window_size); - // Wait ACK or timeout - etcp->wait_timeout_active = 1; - return NULL; - } - - if (etcp->unacked_bytes >= etcp->window_size) { - // Wait ACK or timeout - etcp->wait_timeout_active = 1; - return NULL; - } - - // Get packet (prefer retrans) - inflight_packet_t* ipkt = etcp->wait_send_list; - if (ipkt) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: using retransmission packet id=%u", ipkt->id); - remove_inflight(etcp, ipkt); - } else { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: getting new packet from input queue"); - struct ll_entry* entry = queue_entry_get(etcp->input_queue); - if (!entry) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: no entry available from input queue"); - return NULL; - } - - ipkt = calloc(1, sizeof(inflight_packet_t)); - if (!ipkt) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: failed to allocate inflight_packet_t"); - queue_entry_put_first(etcp->input_queue, entry); - return NULL; - } - - ipkt->id = etcp->next_tx_id++; - ipkt->data_len = ll_entry_size(entry); - ipkt->data = malloc(ipkt->data_len); - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: created new packet id=%u, data_len=%u", - ipkt->id, ipkt->data_len); - - if (!ipkt->data) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: failed to allocate packet data buffer"); - free(ipkt); - queue_entry_put_first(etcp->input_queue, entry); - return NULL; - } - memcpy(ipkt->data, ll_entry_data(entry), ipkt->data_len); - ipkt->payload_len = ipkt->data_len; // Assume full is payload for window - queue_entry_free(entry); - } - - // Select link - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: selecting link via loadbalancer"); - struct ETCP_LINK* link = etcp_loadbalancer_select_link(etcp); - if (!link) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: no suitable link available"); - // Put back if new - if (ipkt->send_count == 0) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: putting new packet back to input queue"); - struct ll_entry* entry = queue_entry_new(ipkt->data_len); - memcpy(ll_entry_data(entry), ipkt->data, ipkt->data_len); - queue_entry_put_first(etcp->input_queue, entry); - } - free_inflight_packet(ipkt); - return NULL; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: selected link %p", link); - - // Build packet buf - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: building packet with optional sections"); - uint8_t buf[1600]; - uint16_t len = append_optional_sections(etcp, buf, link); - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: optional sections added, len=%u", len); - - // Add payload (assume payload includes ID as first 2 bytes) - uint16_t pay_len = ipkt->payload_len + 2; // ID - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: payload section - pay_len=%u (payload_len=%u + 2 for ID)", - pay_len, ipkt->payload_len); - - if (len + SECTION_HEADER_SIZE + pay_len > sizeof(buf)) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: packet too large (%u + %u + %u > %u), dropping", - len, SECTION_HEADER_SIZE, pay_len, (unsigned)sizeof(buf)); - free_inflight_packet(ipkt); - return NULL; - } - buf[len++] = ETCP_SECTION_PAYLOAD; - buf[len++] = (pay_len >> 8) & 0xFF; - buf[len++] = pay_len & 0xFF; - buf[len++] = (ipkt->id >> 8) & 0xFF; - buf[len++] = ipkt->id & 0xFF; - memcpy(buf + len, ipkt->data, ipkt->payload_len); - len += ipkt->payload_len; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: payload added, total len=%u", len); - - // Alloc dgram - struct ETCP_DGRAM* dgram = memory_pool_alloc(etcp->instance->pkt_pool); - if (!dgram) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: failed to allocate dgram from memory pool"); - free_inflight_packet(ipkt); - return NULL; - } - dgram->link = link; - dgram->data_len = len; - dgram->noencrypt_len = 0; - dgram->timestamp = get_current_timestamp(); - memcpy(dgram->data, buf, len); - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: allocated dgram %p (link=%p, data_len=%u, timestamp=%u)", - dgram, link, len, dgram->timestamp); - - // Update inflight - ipkt->last_link = link; - ipkt->last_timestamp = dgram->timestamp; - ipkt->send_count++; - etcp->unacked_bytes += ipkt->payload_len; - etcp->bytes_sent_total += len; // Approx - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: updated inflight - send_count=%u, unacked_bytes=%u, bytes_sent_total=%u", - ipkt->send_count, etcp->unacked_bytes, etcp->bytes_sent_total); - - // Move to wait_ack - ipkt->state = INFLIGHT_STATE_WAIT_ACK; - ipkt->next = etcp->wait_ack_list; - etcp->wait_ack_list = ipkt; - - // Add to wait_ack list - ipkt->next = etcp->wait_ack_list; - etcp->wait_ack_list = ipkt; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: added packet %u to wait_ack_list", ipkt->id); - - // Start retrans timer if empty before - if (etcp->wait_ack_list->next == NULL && !etcp->retrans_timer) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: starting retrans_timer (wait_ack_list was empty)"); - etcp->retrans_timer = uasync_set_timeout(etcp->instance->ua, 20, etcp, retrans_timer_cb); - } - - // Update load balancer after send (call from connections after actual send) - // etcp_loadbalancer_update_after_send(link, len + headers); // Assume called externally - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: successfully created dgram %p for packet id=%u", - dgram, ipkt->id); - return dgram; -} - -// Input queue callback (placeholder to resume load balancer) -static void input_queue_cb(struct ll_queue* q, struct ll_entry* entry, void* arg) { - (void)q; - (void)entry; - struct ETCP_CONN* etcp = arg; - // Resume polling etcp_request_pkt - queue_resume_callback(q); -} - -// Append optional (expanded with debug) -static uint16_t append_optional_sections(struct ETCP_CONN* etcp, uint8_t* buf, struct ETCP_LINK* link) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "append_optional_sections: etcp=%p, link=%p", etcp, link); - - uint16_t len = 0; - int sections_added = 0; - - // Timestamp (assume 2 bytes TS) - uint16_t ts = get_current_timestamp(); - buf[len++] = ETCP_SECTION_TIMESTAMP; - buf[len++] = 0; // len high - buf[len++] = 2; // len low - buf[len++] = (ts >> 8) & 0xFF; - buf[len++] = ts & 0xFF; - sections_added++; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "append_optional_sections: added TIMESTAMP section (ts=%u, len=%u)", ts, len); - - // ACK (assume count(1) + [id(2)+ts(2)]*count) - if (etcp->pending_ack_count > 0) { - uint16_t ack_len = 1 + etcp->pending_ack_count * 4; - buf[len++] = ETCP_SECTION_ACK; - buf[len++] = (ack_len >> 8) & 0xFF; - buf[len++] = ack_len & 0xFF; - buf[len++] = etcp->pending_ack_count; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "append_optional_sections: adding ACK section with %u ACKs", etcp->pending_ack_count); - - for (uint8_t i = 0; i < etcp->pending_ack_count; i++) { - uint16_t id = etcp->pending_ack_ids[i]; - uint16_t ats = etcp->pending_ack_ts[i]; - buf[len++] = (id >> 8) & 0xFF; - buf[len++] = id & 0xFF; - buf[len++] = (ats >> 8) & 0xFF; - buf[len++] = ats & 0xFF; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "append_optional_sections: ACK[%u] - id=%u, ts=%u", i, id, ats); - } - - etcp->pending_ack_count = 0; - etcp->ack_packets_count++; - sections_added++; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "append_optional_sections: added ACK section (total_len=%u)", len); - } - - // RETRANS (similar: count(1) + id(2)*count) - if (etcp->pending_retrans_count > 0) { - uint16_t ret_len = 1 + etcp->pending_retrans_count * 2; - buf[len++] = ETCP_SECTION_RETRANS; - buf[len++] = (ret_len >> 8) & 0xFF; - buf[len++] = ret_len & 0xFF; - buf[len++] = etcp->pending_retrans_count; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "append_optional_sections: adding RETRANS section with %u requests", etcp->pending_retrans_count); - - for (uint8_t i = 0; i < etcp->pending_retrans_count; i++) { - uint16_t id = etcp->pending_retrans_ids[i]; - buf[len++] = (id >> 8) & 0xFF; - buf[len++] = id & 0xFF; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "append_optional_sections: RETRANS[%u] - id=%u", i, id); - } - - etcp->pending_retrans_count = 0; - sections_added++; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "append_optional_sections: added RETRANS section (total_len=%u)", len); - } - - // MEAS_TS if burst (assume [start_id(2)][n(1)]) - if (etcp->burst_in_progress) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "append_optional_sections: burst measurement in progress, would add MEAS_TS"); - // Logic for adding to burst packets - // Placeholder - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "append_optional_sections: completed - added %u sections, total_len=%u", - sections_added, len); - - return len; -} - -// Process ACK (expanded) -static void process_section_ack(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_ack: etcp=%p, data=%p, len=%u", etcp, data, len); - - if (len < 1) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_ack: invalid length %u", len); - return; - } - uint8_t count = data[0]; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_ack: count=%u", count); - - if (1 + count * 4 > len) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "process_section_ack: invalid count %u for len %u", count, len); - return; - } - - uint16_t lp_ts = 0; - int acked_count = 0; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_ack: processing %u ACK entries", count); - - for (uint8_t i = 0; i < count; i++) { - uint16_t id = (data[1 + i*4] << 8) | data[2 + i*4]; - uint16_t ts = (data[3 + i*4] << 8) | data[4 + i*4]; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_ack: entry %u - id=%u, ts=%u", i, id, ts); - - inflight_packet_t* pkt = find_inflight(etcp, id, INFLIGHT_STATE_WAIT_ACK); - if (pkt) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_ack: found inflight packet %u, removing (payload_len=%u)", - id, pkt->payload_len); - etcp->unacked_bytes -= pkt->payload_len; - remove_inflight(etcp, pkt); - free_inflight_packet(pkt); - lp_ts = ts; // Update last positive ts - acked_count++; - } else { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_ack: no inflight packet found for id=%u", id); - } - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_ack: successfully ACKed %u/%u packets", acked_count, count); - // Use lp_ts in retrans_check if needed - etcp->last_rx_ack_id = (data[1 + (count-1)*4] << 8) | data[2 + (count-1)*4]; // Last ACK ID -} - -// Process RETRANS (expanded) -static void process_section_retrans(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_retrans: etcp=%p, data=%p, len=%u", etcp, data, len); - - if (len < 1) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_retrans: invalid length %u", len); - return; - } - uint8_t count = data[0]; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_retrans: count=%u", count); - - if (1 + count * 2 > len) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "process_section_retrans: invalid count %u for len %u", count, len); - return; - } - - int retrans_count = 0; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_retrans: processing %u retrans requests", count); - - for (uint8_t i = 0; i < count; i++) { - uint16_t id = (data[1 + i*2] << 8) | data[2 + i*2]; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_retrans: requesting retrans for id=%u", id); - - inflight_packet_t* pkt = find_inflight(etcp, id, INFLIGHT_STATE_WAIT_ACK); - if (pkt) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_retrans: found packet %u, marking for retransmission", id); - pkt->retrans_req_count++; - pkt->need_retrans = 1; - move_to_wait_send(etcp, pkt); - retrans_count++; - } else { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_retrans: no inflight packet found for id=%u", id); - } - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_retrans: marked %u/%u packets for retransmission", retrans_count, count); -} - -// Process TIMESTAMP (expanded) -static void process_section_timestamp(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_timestamp: etcp=%p, data=%p, len=%u", etcp, data, len); - - if (len != 2) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_timestamp: invalid length %u (expected 2)", len); - return; - } - uint16_t recv_ts = (data[0] << 8) | data[1]; - uint16_t current_ts = get_current_timestamp(); - uint16_t rtt = timestamp_diff(current_ts, recv_ts); - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_timestamp: recv_ts=%u, current_ts=%u, calculated_rtt=%u", - recv_ts, current_ts, rtt); - update_rtt(etcp, rtt); -} - -// Process PAYLOAD (expanded) -static void process_section_payload(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: etcp=%p, data=%p, len=%u", etcp, data, len); - - if (len < 2) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_payload: invalid length %u (minimum 2)", len); - return; - } - uint16_t id = (data[0] << 8) | data[1]; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: packet id=%u, last_rx_id=%u", id, etcp->last_rx_id); - - if (id <= etcp->last_rx_id) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_payload: duplicate packet id=%u (last_rx_id=%u), ignoring", - id, etcp->last_rx_id); - return; // Dup - } - - rx_packet_t* new_rx = calloc(1, sizeof(rx_packet_t)); - if (!new_rx) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "process_section_payload: failed to allocate rx_packet_t"); - return; - } - - new_rx->id = id; - new_rx->timestamp = get_current_timestamp(); - new_rx->data_len = len - 2; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: allocated rx_packet %p (id=%u, data_len=%u, timestamp=%u)", - new_rx, new_rx->id, new_rx->data_len, new_rx->timestamp); - - new_rx->data = malloc(new_rx->data_len); - if (!new_rx->data) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "process_section_payload: failed to allocate rx data buffer (size=%u)", new_rx->data_len); - free(new_rx); - return; - } - memcpy(new_rx->data, data + 2, new_rx->data_len); - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: copied %u bytes of payload data", new_rx->data_len); - - // Insert sorted (assume IDs sequential, no wrap for simplicity) - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_payload: inserting packet into rx_list (id=%u)", id); - rx_packet_t** ptr = &etcp->rx_list; - while (*ptr && (*ptr)->id < id) ptr = &(*ptr)->next; - if (*ptr && (*ptr)->id == id) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_payload: duplicate packet id=%u found in rx_list, discarding", id); - free(new_rx->data); - free(new_rx); - return; - } - new_rx->next = *ptr; - *ptr = new_rx; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: successfully inserted packet id=%u into rx_list", id); - - if (id > etcp->last_rx_id) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_payload: updating last_rx_id from %u to %u", - etcp->last_rx_id, id); - etcp->last_rx_id = id; - } - - // Pending ACK - if (etcp->pending_ack_count < MAX_PENDING) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_payload: adding packet id=%u to pending ACKs (count=%u)", - id, etcp->pending_ack_count + 1); - etcp->pending_ack_ids[etcp->pending_ack_count] = id; - etcp->pending_ack_ts[etcp->pending_ack_count++] = new_rx->timestamp; - } else { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_payload: pending ACK buffer full (%u), cannot add id=%u", - MAX_PENDING, id); - } - - // Schedule ACK - if (!etcp->ack_timer) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: scheduling ACK timer (delay=%u tb)", ACK_DELAY_TB); - etcp->ack_timer = uasync_set_timeout(etcp->instance->ua, ACK_DELAY_TB, etcp, ack_timer_cb); - } - - etcp->bytes_received_total += len; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: packet id=%u processed successfully, bytes_received_total=%u", - id, etcp->bytes_received_total); -} - -// Process MEAS_TS (expanded: send resp) -static void process_section_meas_ts(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_meas_ts: etcp=%p, data=%p, len=%u", etcp, data, len); - - if (len < 3) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_meas_ts: invalid length %u (minimum 3)", len); - return; - } - uint16_t start_id = (data[0] << 8) | data[1]; - uint8_t n = data[2]; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_meas_ts: start_id=%u, n=%u", start_id, n); - - // Send MEAS_RESP (add to pending or direct) - // Placeholder: assume added to next packet - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "MEAS_TS: start_id=%u n=%u", start_id, n); - // Build resp [start_id(2)][n(1)][recv_ts(2)] - // But since appended in optional, set state -} - -// Process MEAS_RESP (expanded: calc bw) -static void process_section_meas_resp(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_meas_resp: etcp=%p, data=%p, len=%u", etcp, data, len); - - // Assume format [start_id(2)][n(1)][recv_ts(2)] - if (len < 5) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_meas_resp: invalid length %u (minimum 5)", len); - return; - } - uint16_t start_id = (data[0] << 8) | data[1]; - uint8_t n = data[2]; - uint16_t recv_ts = (data[3] << 8) | data[4]; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_meas_resp: start_id=%u, n=%u, recv_ts=%u", start_id, n, recv_ts); - - if (etcp->burst_start_id != start_id || !etcp->burst_in_progress) return; - - // Calc bw based on burst (placeholder logic) - uint16_t delta = timestamp_diff(get_current_timestamp(), recv_ts); - uint32_t bw = (BURST_SIZE * etcp->mtu * 8) / (delta / 1000.0); // bits/sec approx - update_link_bandwidth(etcp->links, bw); // Assume primary link - etcp->burst_in_progress = 0; -} - -// Detect gaps (expanded) -static void detect_gaps_and_request_retrans(struct ETCP_CONN* etcp) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: etcp=%p, last_delivered_id=%u", - etcp, etcp->last_delivered_id); - - rx_packet_t* rx = etcp->rx_list; - uint16_t expected = etcp->last_delivered_id + 1; - int gaps_found = 0; - int retrans_requested = 0; - - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: starting gap detection from expected_id=%u", expected); - - while (rx) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: checking rx packet id=%u (expected=%u)", - rx->id, expected); - - if (rx->id > expected) { - // Gap: add retrans for expected to rx->id -1 - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: gap detected - expected=%u, found=%u", - expected, rx->id); - gaps_found++; - - for (uint16_t gid = expected; gid < rx->id && etcp->pending_retrans_count < MAX_PENDING; gid++) { - etcp->pending_retrans_ids[etcp->pending_retrans_count++] = gid; - retrans_requested++; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: queued retrans request for id=%u", gid); - } - expected = rx->id + 1; - } else if (rx->id == expected) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: found expected packet id=%u", expected); - expected++; - } else { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: packet id=%u < expected=%u, already processed", - rx->id, expected); - } - rx = rx->next; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: completed - gaps_found=%d, retrans_requested=%u", - gaps_found, retrans_requested); -} - -// Deliver contiguous (expanded) -static void deliver_contiguous_packets(struct ETCP_CONN* etcp) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "deliver_contiguous_packets: etcp=%p, last_delivered_id=%u", - etcp, etcp->last_delivered_id); - - rx_packet_t** ptr = &etcp->rx_list; - int delivered_count = 0; - uint32_t delivered_bytes = 0; - - while (*ptr && (*ptr)->id == etcp->last_delivered_id + 1) { - rx_packet_t* rx = *ptr; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "deliver_contiguous_packets: delivering packet id=%u (data_len=%u)", - rx->id, rx->data_len); - - struct ll_entry* entry = queue_entry_new(rx->data_len); - if (entry) { - memcpy(ll_entry_data(entry), rx->data, rx->data_len); - queue_entry_put(etcp->output_queue, entry); - delivered_bytes += rx->data_len; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "deliver_contiguous_packets: queued packet id=%u to output_queue", rx->id); - } else { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "deliver_contiguous_packets: failed to allocate queue entry for packet id=%u", rx->id); - } - - etcp->last_delivered_id = rx->id; - *ptr = rx->next; - free(rx->data); - free(rx); - delivered_count++; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "deliver_contiguous_packets: delivered %u contiguous packets (%u bytes), last_delivered_id=%u", - delivered_count, delivered_bytes, etcp->last_delivered_id); -} - -// Retrans check (expanded with lp_ts) -static void retrans_check(struct ETCP_CONN* etcp) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_check: etcp=%p, wait_ack_list=%p, rtt_avg_10=%u, jitter=%u", - etcp, etcp->wait_ack_list, etcp->rtt_avg_10, etcp->jitter); - - uint64_t now = get_current_time_units(); - inflight_packet_t** ptr = &etcp->wait_ack_list; - uint16_t lp_ts = 0; - int checked_packets = 0; - int retrans_packets = 0; - uint16_t timeout_calc = (uint16_t)(etcp->rtt_avg_10 * RETRANS_K1 + etcp->jitter * RETRANS_K2); - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_check: timeout calculation: rtt_avg_10=%u * %.1f + jitter=%u * %.1f = %u", - etcp->rtt_avg_10, RETRANS_K1, etcp->jitter, RETRANS_K2, timeout_calc); - - while (*ptr) { - inflight_packet_t* pkt = *ptr; - checked_packets++; - uint16_t timeout = (uint16_t)(etcp->rtt_avg_10 * RETRANS_K1 + etcp->jitter * RETRANS_K2); - uint16_t time_since_send = timestamp_diff(now, pkt->last_timestamp); - - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "retrans_check: checking packet id=%u (time_since_send=%u, timeout=%u, need_retrans=%u)", - pkt->id, time_since_send, timeout, pkt->need_retrans); - - if (time_since_send > timeout) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_check: packet id=%u timed out, marking for retransmission", pkt->id); - pkt->need_retrans = 1; - move_to_wait_send(etcp, pkt); - etcp->retransmissions_count++; - retrans_packets++; - ptr = &etcp->wait_ack_list; // Restart scan after move - continue; - } - // lp_ts logic (per spec: if acked, remember ts; if later unacked with ts < lp_ts, ?) - // Assume if pkt acked (but shouldn't be in list), or for forward progress - ptr = &pkt->next; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_check: completed - checked %d packets, retransmitted %d packets, total_retransmissions=%u", - checked_packets, retrans_packets, etcp->retransmissions_count); - - // Reschedule if list not empty - if (etcp->wait_ack_list) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_check: rescheduling retrans_timer (wait_ack_list not empty)"); - etcp->retrans_timer = uasync_set_timeout(etcp->instance->ua, 20, etcp, retrans_timer_cb); - } else { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_check: clearing retrans_timer (wait_ack_list empty)"); - etcp->retrans_timer = NULL; - } -} - -// Find inflight (expanded) -static inflight_packet_t* find_inflight(struct ETCP_CONN* etcp, uint16_t id, uint8_t state) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "find_inflight: etcp=%p, id=%u, state=%u", etcp, id, state); - - inflight_packet_t* list = (state == INFLIGHT_STATE_WAIT_ACK) ? etcp->wait_ack_list : etcp->wait_send_list; - inflight_packet_t* pkt = list; - int position = 0; - - while (pkt && pkt->id != id) { - pkt = pkt->next; - position++; - } - - if (pkt) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "find_inflight: found packet %u at position %d in %s list", - id, position, (state == INFLIGHT_STATE_WAIT_ACK) ? "wait_ack" : "wait_send"); - } else { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "find_inflight: packet %u not found in %s list", - id, (state == INFLIGHT_STATE_WAIT_ACK) ? "wait_ack" : "wait_send"); - } - - return pkt; - return pkt; -} - -// Move to wait_send (expanded) -static void move_to_wait_send(struct ETCP_CONN* etcp, inflight_packet_t* pkt) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "move_to_wait_send: etcp=%p, pkt=%p (id=%u, state=%u)", - etcp, pkt, pkt->id, pkt->state); - - remove_inflight(etcp, pkt); - pkt->state = INFLIGHT_STATE_WAIT_SEND; - pkt->next = etcp->wait_send_list; - etcp->wait_send_list = pkt; - - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "move_to_wait_send: moved packet %u to wait_send_list", pkt->id); -} - -// Remove inflight (expanded) -static void remove_inflight(struct ETCP_CONN* etcp, inflight_packet_t* pkt) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "remove_inflight: etcp=%p, pkt=%p (id=%u, state=%u)", - etcp, pkt, pkt->id, pkt->state); - - inflight_packet_t** list = (pkt->state == INFLIGHT_STATE_WAIT_ACK) ? &etcp->wait_ack_list : &etcp->wait_send_list; - inflight_packet_t** ptr = list; - int position = 0; - - while (*ptr && *ptr != pkt) { - ptr = &(*ptr)->next; - position++; - } - - if (*ptr) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "remove_inflight: found packet %u at position %d in %s list", - pkt->id, position, (pkt->state == INFLIGHT_STATE_WAIT_ACK) ? "wait_ack" : "wait_send"); - *ptr = (*ptr)->next; - } else { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "remove_inflight: packet %u not found in %s list", - pkt->id, (pkt->state == INFLIGHT_STATE_WAIT_ACK) ? "wait_ack" : "wait_send"); - } -} - -// Start burst (placeholder expanded) -static void start_burst_measurement(struct ETCP_CONN* etcp, struct ETCP_LINK* link) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "start_burst_measurement: etcp=%p, link=%p", etcp, link); - - // Periodically call this - etcp->burst_in_progress = 1; - uint16_t old_start_id = etcp->burst_start_id; - etcp->burst_start_id = etcp->next_tx_id; - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "start_burst_measurement: started burst measurement - burst_start_id=%u (was %u)", - etcp->burst_start_id, old_start_id); - - // Delay first, then burst 4 - // Assume handled in request_pkt by adding meas_ts to next BURST_SIZE pkts -} - -// Update link bw (expanded) -static void update_link_bandwidth(struct ETCP_LINK* link, uint32_t new_bw) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "update_link_bandwidth: link=%p, new_bw=%u bits/sec (current=%u)", - link, new_bw, link->bandwidth); - - uint32_t old_bw = link->bandwidth; - link->bandwidth = (uint32_t)((link->bandwidth * 0.9) + (new_bw * 0.1)); // Smooth - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "update_link_bandwidth: updated link bandwidth from %u to %u bits/sec (new_bw=%u)", - old_bw, link->bandwidth, new_bw); -} - -// Update RTT (expanded with history) -static void update_rtt(struct ETCP_CONN* etcp, uint16_t new_rtt) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "update_rtt: etcp=%p, new_rtt=%u (last_rtt=%u, avg_10=%u, avg_100=%u)", - etcp, new_rtt, etcp->rtt_last, etcp->rtt_avg_10, etcp->rtt_avg_100); - - etcp->rtt_last = new_rtt; - etcp->rtt_avg_10 = (etcp->rtt_avg_10 * 9 + new_rtt) / 10; - etcp->rtt_avg_100 = (etcp->rtt_avg_100 * 99 + new_rtt) / 100; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "update_rtt: updated RTT metrics - last=%u, avg_10=%u, avg_100=%u", - etcp->rtt_last, etcp->rtt_avg_10, etcp->rtt_avg_100); - - // History for jitter - etcp->rtt_history[etcp->rtt_history_idx++] = new_rtt; - if (etcp->rtt_history_idx >= RTT_HISTORY_SIZE) etcp->rtt_history_idx = 0; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "update_rtt: stored RTT in history at index %u", - (etcp->rtt_history_idx + RTT_HISTORY_SIZE - 1) % RTT_HISTORY_SIZE); - - calculate_jitter(etcp); -} - -static void calculate_jitter(struct ETCP_CONN* etcp) { - uint16_t min_rtt = UINT16_MAX; - uint16_t max_rtt = 0; - int valid_samples = 0; - - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "calculate_jitter: analyzing RTT history (history_idx=%u)", etcp->rtt_history_idx); - - for (int i = 0; i < RTT_HISTORY_SIZE; i++) { - if (etcp->rtt_history[i] == 0) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "calculate_jitter: history[%d] = 0 (invalid), skipping", i); - continue; - } - valid_samples++; - if (etcp->rtt_history[i] < min_rtt) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "calculate_jitter: new min_rtt=%u (was %u) at history[%d]", - etcp->rtt_history[i], min_rtt, i); - min_rtt = etcp->rtt_history[i]; - } - if (etcp->rtt_history[i] > max_rtt) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "calculate_jitter: new max_rtt=%u (was %u) at history[%d]", - etcp->rtt_history[i], max_rtt, i); - max_rtt = etcp->rtt_history[i]; - } - } - - uint16_t old_jitter = etcp->jitter; - etcp->jitter = max_rtt - min_rtt; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "calculate_jitter: completed - valid_samples=%d, min_rtt=%u, max_rtt=%u, jitter=%u (was %u)", - valid_samples, min_rtt, max_rtt, etcp->jitter, old_jitter); -} - -// Timers (expanded with debug) -static void retrans_timer_cb(void* arg) { - struct ETCP_CONN* etcp = (struct ETCP_CONN*)arg; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_timer_cb: etcp=%p, triggered retransmission check", etcp); - retrans_check(etcp); -} - -static void ack_timer_cb(void* arg) { - struct ETCP_CONN* etcp = (struct ETCP_CONN*)arg; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "ack_timer_cb: etcp=%p, processing pending ACKs", etcp); - etcp->ack_timer = NULL; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "ack_timer_cb: processing %u pending ACKs", etcp->pending_ack_count); - - // Force send ACK if pending (e.g., empty payload pkt) - // For now, assume appended next - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "ack_timer_cb: ACK processing completed"); -} - -// Get stats (expanded) -void etcp_get_stats(struct ETCP_CONN* etcp, size_t* packets_sent, size_t* packets_recv, - size_t* pool_allocs, size_t* pool_reuse) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_get_stats: etcp=%p", etcp); - - if (packets_sent) { - *packets_sent = etcp->total_packets_sent; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_get_stats: total_packets_sent=%zu", *packets_sent); - } - if (packets_recv) { - *packets_recv = etcp->bytes_received_total / 1400; // Approx MTU - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_get_stats: bytes_received_total=%u, estimated_packets=%zu", - etcp->bytes_received_total, *packets_recv); - } - if (pool_allocs || pool_reuse) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_get_stats: getting memory pool stats"); - memory_pool_get_stats(etcp->instance->pkt_pool, pool_allocs, pool_reuse); - if (pool_allocs) DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_get_stats: pool_allocs=%zu", *pool_allocs); - if (pool_reuse) DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_get_stats: pool_reuse=%zu", *pool_reuse); - } -} \ No newline at end of file diff --git a/!/etcp.c1 b/!/etcp.c1 deleted file mode 100755 index 5508a6d0..00000000 --- a/!/etcp.c1 +++ /dev/null @@ -1,1147 +0,0 @@ -// etcp.c - ETCP Protocol Implementation (refactored and expanded based on etcp_protocol.txt) -#include "etcp.h" -#include "etcp_loadbalancer.h" -#include "../lib/u_async.h" -#include "../lib/debug_config.h" -#include "crc32.h" -#include -#include -#include -#include // For bandwidth calcs - -// Enable comprehensive debug output for ETCP module -#define DEBUG_CATEGORY_ETCP_DETAILED 1 - -// Constants from spec (adjusted for completeness) -#define MAX_INFLIGHT_BYTES 65536 // Initial window -#define RETRANS_K1 2.0f // RTT multiplier for retrans timeout -#define RETRANS_K2 1.5f // Jitter multiplier -#define ACK_DELAY_TB 20 // ACK timer delay (2ms in 0.1ms units) -#define BURST_DELAY_FACTOR 4 // Delay before burst -#define BURST_SIZE 5 // Packets in burst (1 delayed + 4 burst) -#define RTT_HISTORY_SIZE 10 // For jitter calc -#define MAX_PENDING 32 // For ACKs/retrans -#define SECTION_HEADER_SIZE 3 // type(1) + len(2) - -// Forward declaration for callback function -static void input_queue_cb(struct ll_queue* q, struct ll_entry* entry, void* arg); - -// Timestamp diff (with wrap-around) -static uint16_t timestamp_diff(uint16_t t1, uint16_t t2) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "timestamp_diff: t1=%u, t2=%u", t1, t2); - if (t1 >= t2) { - uint16_t diff = t1 - t2; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "timestamp_diff: normal case, diff=%u", diff); - return diff; - } - uint16_t diff = (0xFFFF - t2) + t1 + 1; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "timestamp_diff: wraparound case, diff=%u", diff); - return diff; -} - -// Get current time in 0.1ms units -uint64_t get_current_time_units() { - struct timeval tv; - gettimeofday(&tv, NULL); - uint64_t time_units = ((uint64_t)tv.tv_sec * 10000ULL) + (tv.tv_usec / 100); - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "get_current_time_units: tv_sec=%ld, tv_usec=%ld, result=%llu", - tv.tv_sec, tv.tv_usec, (unsigned long long)time_units); - return time_units; -} - -uint16_t get_current_timestamp() { - uint16_t timestamp = (uint16_t)(get_current_time_units() & 0xFFFF); - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "get_current_timestamp: result=%u", timestamp); - return timestamp; -} - -// Internal functions (expanded) -static void retrans_timer_cb(void* arg); -static void ack_timer_cb(void* arg); -static void update_rtt(struct ETCP_CONN* etcp, uint16_t new_rtt); -static void calculate_jitter(struct ETCP_CONN* etcp); -static void detect_gaps_and_request_retrans(struct ETCP_CONN* etcp); -static void process_section_ack(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len); -static void process_section_retrans(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len); -static void process_section_timestamp(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len); -static void process_section_payload(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len); -static void process_section_meas_ts(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len); -static void process_section_meas_resp(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len); -static uint16_t append_optional_sections(struct ETCP_CONN* etcp, uint8_t* buf, struct ETCP_LINK* link); -static void deliver_contiguous_packets(struct ETCP_CONN* etcp); -static void retrans_check(struct ETCP_CONN* etcp); -static inflight_packet_t* find_inflight(struct ETCP_CONN* etcp, uint16_t id, uint8_t state); -static void move_to_wait_send(struct ETCP_CONN* etcp, inflight_packet_t* pkt); -static void remove_inflight(struct ETCP_CONN* etcp, inflight_packet_t* pkt); -static void free_inflight_packet(inflight_packet_t* pkt); -static void start_burst_measurement(struct ETCP_CONN* etcp, struct ETCP_LINK* link); -static void update_link_bandwidth(struct ETCP_LINK* link, uint32_t new_bw); - -// Add RTT history to struct (for jitter) -/// In etcp.h, add to ETCP_CONN: -/// uint16_t rtt_history[RTT_HISTORY_SIZE]; -/// uint8_t rtt_history_idx; - -//======================================================================================================================================================================= -// Create ETCP connection (unchanged) -struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_create: instance=%p", instance); - - struct ETCP_CONN* etcp = calloc(1, sizeof(struct ETCP_CONN)); - if (!etcp) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_connection_create: failed to allocate ETCP_CONN"); - return NULL; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_create: allocated etcp=%p", etcp); - - etcp->instance = instance; - etcp->input_queue = queue_new(instance->ua, instance->pkt_pool); - etcp->output_queue = queue_new(instance->ua, instance->pkt_pool); - etcp->mtu = 1500; // Default - etcp->window_size = MAX_INFLIGHT_BYTES; - etcp->next_tx_id = 1; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_create: queues created, mtu=%d, window_size=%u, next_tx_id=%u", - etcp->mtu, etcp->window_size, etcp->next_tx_id); - - // Init crypto (as per original) - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_create: initializing crypto context"); - if (sc_init_ctx(&etcp->crypto_ctx, &instance->my_keys) != SC_OK) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_connection_create: crypto initialization failed"); - etcp_connection_close(etcp); - return NULL; - } - - // Add connection to instance list - etcp->next = instance->connections; - instance->connections = etcp; - instance->connections_count++; - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_connection_create: successfully created ETCP connection %p", etcp); - return etcp; -} -//======================================================================================================================================================================= -// Close connection (expanded free) -void etcp_connection_close(struct ETCP_CONN* etcp) { - if (!etcp) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_connection_close: called with NULL etcp"); - return; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: closing connection %p", etcp); - - // Remove connection from instance list - if (etcp->instance) { - struct ETCP_CONN** prev = &etcp->instance->connections; - struct ETCP_CONN* cur = *prev; - while (cur) { - if (cur == etcp) { - *prev = cur->next; - etcp->instance->connections_count--; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: removed from instance list, count=%d", - etcp->instance->connections_count); - break; - } - prev = &cur->next; - cur = cur->next; - } - } - - // Cancel timers - if (etcp->retrans_timer) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: canceling retrans_timer"); - uasync_cancel_timeout(etcp->instance->ua, etcp->retrans_timer); - } - if (etcp->ack_timer) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: canceling ack_timer"); - uasync_cancel_timeout(etcp->instance->ua, etcp->ack_timer); - } - - // Free inflight - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freeing wait_ack_list"); - inflight_packet_t* pkt = etcp->wait_ack_list; - int wait_ack_count = 0; - while (pkt) { - inflight_packet_t* next = pkt->next; - free_inflight_packet(pkt); - pkt = next; - wait_ack_count++; - } - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freed %d packets from wait_ack_list", wait_ack_count); - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freeing wait_send_list"); - pkt = etcp->wait_send_list; - int wait_send_count = 0; - while (pkt) { - inflight_packet_t* next = pkt->next; - free_inflight_packet(pkt); - pkt = next; - wait_send_count++; - } - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freed %d packets from wait_send_list", wait_send_count); - - // Free rx_list - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freeing rx_list"); - rx_packet_t* rx = etcp->rx_list; - int rx_count = 0; - while (rx) { - rx_packet_t* next = rx->next; - free(rx->data); - free(rx); - rx = next; - rx_count++; - } - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freed %d packets from rx_list", rx_count); - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freeing queues"); - queue_free(etcp->input_queue); - queue_free(etcp->output_queue); - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_connection_close: connection %p closed successfully", etcp); - free(etcp); -} - -//======================================================================================================================================================================= - -static void free_inflight_packet(inflight_packet_t* pkt) { - if (pkt) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "free_inflight_packet: freeing packet %p (id=%u, data_len=%u)", - pkt, pkt->id, pkt->data_len); - free(pkt->data); - free(pkt); - } -} - -//======================================================================================================================================================================= - -// Reset connection (unchanged) -void etcp_conn_reset(struct ETCP_CONN* etcp) { - if (!etcp) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_conn_reset: called with NULL etcp"); - return; - } - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_conn_reset: resetting connection %p", etcp); - - // Cancel timers - if (etcp->retrans_timer) uasync_cancel_timeout(etcp->instance->ua, etcp->retrans_timer); - if (etcp->ack_timer) uasync_cancel_timeout(etcp->instance->ua, etcp->ack_timer); - - // Free lists - inflight_packet_t* pkt = etcp->wait_ack_list; - while (pkt) { - inflight_packet_t* next = pkt->next; - free_inflight_packet(pkt); - pkt = next; - } - etcp->wait_ack_list = NULL; - pkt = etcp->wait_send_list; - while (pkt) { - inflight_packet_t* next = pkt->next; - free_inflight_packet(pkt); - pkt = next; - } - etcp->wait_send_list = NULL; - - rx_packet_t* rx = etcp->rx_list; - while (rx) { - rx_packet_t* next = rx->next; - free(rx->data); - free(rx); - rx = next; - } - etcp->rx_list = NULL; - - // Reset state - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_conn_reset: clearing packet lists and resetting state"); - etcp->next_tx_id = 1; - etcp->last_rx_id = 0; - etcp->last_delivered_id = 0; - etcp->unacked_bytes = 0; - etcp->pending_ack_count = 0; - etcp->pending_retrans_count = 0; - etcp->rtt_last = 0; - etcp->rtt_avg_10 = 0; - etcp->rtt_avg_100 = 0; - etcp->jitter = 0; - etcp->burst_in_progress = 0; - etcp->rtt_history_idx = 0; - memset(etcp->rtt_history, 0, sizeof(etcp->rtt_history)); - // Queues cleared externally if needed - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_conn_reset: connection %p reset completed", etcp); -} - -//======================================================================================================================================================================= -// PACKET INPUT processing -//======================================================================================================================================================================= - - -// Input decrypted packet (unchanged structure, but calls expanded processes) -void etcp_conn_input(struct ETCP_DGRAM* pkt) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_conn_input: pkt=%p, link=%p, etcp=%p", - pkt, pkt ? pkt->link : NULL, pkt && pkt->link ? pkt->link->etcp : NULL); - - if (!pkt || !pkt->link || !pkt->link->etcp) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_conn_input: invalid parameters (pkt=%p, link=%p, etcp=%p)", - pkt, pkt ? pkt->link : NULL, pkt && pkt->link ? pkt->link->etcp : NULL); - return; - } - - struct ETCP_CONN* etcp = pkt->link->etcp; - uint8_t* data = pkt->data; - uint16_t len = pkt->data_len; - uint16_t ts = pkt->timestamp; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_conn_input: processing packet - etcp=%p, data_len=%u, timestamp=%u, link=%p", - etcp, len, ts, pkt->link); - - // Update link activity - pkt->link->last_activity = get_current_time_units(); - pkt->link->last_recv_local_time = pkt->link->last_activity; - pkt->link->last_recv_timestamp = ts; - - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_conn_input: updated link activity - last_activity=%llu, last_recv_timestamp=%u", - (unsigned long long)pkt->link->last_activity, pkt->link->last_recv_timestamp); - - // Parse sections - uint16_t pos = 0; - while (pos < len) { - if (pos + SECTION_HEADER_SIZE > len) break; - - uint8_t type = data[pos]; - uint16_t sec_len = (data[pos+1] << 8) | data[pos+2]; - pos += SECTION_HEADER_SIZE; - - if (pos + sec_len > len) break; - - uint8_t* sec_data = data + pos; - switch (type) { - case ETCP_SECTION_ACK: - process_section_ack(etcp, sec_data, sec_len); - break; - case ETCP_SECTION_RETRANS: - process_section_retrans(etcp, sec_data, sec_len); - break; - case ETCP_SECTION_TIMESTAMP: - process_section_timestamp(etcp, sec_data, sec_len); - break; - case ETCP_SECTION_PAYLOAD: - process_section_payload(etcp, sec_data, sec_len); - break; - case ETCP_SECTION_MEAS_TS: - process_section_meas_ts(etcp, sec_data, sec_len); - break; - case ETCP_SECTION_MEAS_RESP: - process_section_meas_resp(etcp, sec_data, sec_len); - break; - default: - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "Unknown section type: 0x%02x", type); - break; - } - pos += sec_len; - } - - // Post-processing - detect_gaps_and_request_retrans(etcp); - deliver_contiguous_packets(etcp); - - // Trigger if waiting - if (etcp->wait_timeout_active) { - etcp->wait_timeout_active = 0; - // Assume load balancer polls again - } -} - -// Request next packet (expanded) -// source 1: wait_ack_list -// source 2: queue > wait_ack_list - -struct ETCP_DGRAM* etcp_request_pkt(struct ETCP_CONN* etcp) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: etcp=%p", etcp); - - if (!etcp) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: called with NULL etcp"); - return NULL; - } - - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: input_queue_count=%d, wait_send_list=%p, unacked_bytes=%u, window_size=%u", - queue_entry_count(etcp->input_queue), etcp->wait_send_list, - etcp->unacked_bytes, etcp->window_size); - - // Check waiting conditions - if (queue_entry_count(etcp->input_queue) == 0 && etcp->wait_send_list == NULL) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: no packets available, setting callback and returning NULL"); - // Wait for input or retrans - // Set callback for resume - queue_set_callback(etcp->input_queue, input_queue_cb, etcp); // Define cb to resume - return NULL; - } - - if (etcp->unacked_bytes >= etcp->window_size) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: window full (unacked_bytes=%u >= window_size=%u), waiting", - etcp->unacked_bytes, etcp->window_size); - // Wait ACK or timeout - etcp->wait_timeout_active = 1; - return NULL; - } - - if (etcp->unacked_bytes >= etcp->window_size) { - // Wait ACK or timeout - etcp->wait_timeout_active = 1; - return NULL; - } - - // Get packet (prefer retrans) - inflight_packet_t* ipkt = etcp->wait_send_list; - if (ipkt) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: using retransmission packet id=%u", ipkt->id); - remove_inflight(etcp, ipkt); - } else { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: getting new packet from input queue"); - struct ll_entry* entry = queue_entry_get(etcp->input_queue); - if (!entry) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: no entry available from input queue"); - return NULL; - } - - ipkt = calloc(1, sizeof(inflight_packet_t)); - if (!ipkt) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: failed to allocate inflight_packet_t"); - queue_entry_put_first(etcp->input_queue, entry); - return NULL; - } - - ipkt->id = etcp->next_tx_id++; - ipkt->data_len = ll_entry_size(entry); - ipkt->data = malloc(ipkt->data_len); - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: created new packet id=%u, data_len=%u", - ipkt->id, ipkt->data_len); - - if (!ipkt->data) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: failed to allocate packet data buffer"); - free(ipkt); - queue_entry_put_first(etcp->input_queue, entry); - return NULL; - } - memcpy(ipkt->data, ll_entry_data(entry), ipkt->data_len); - ipkt->payload_len = ipkt->data_len; // Assume full is payload for window - queue_entry_free(entry); - } - - // Select link - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: selecting link via loadbalancer"); - struct ETCP_LINK* link = etcp_loadbalancer_select_link(etcp); - if (!link) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: no suitable link available"); - // Put back if new - if (ipkt->send_count == 0) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: putting new packet back to input queue"); - struct ll_entry* entry = queue_entry_new(ipkt->data_len); - memcpy(ll_entry_data(entry), ipkt->data, ipkt->data_len); - queue_entry_put_first(etcp->input_queue, entry); - } - free_inflight_packet(ipkt); - return NULL; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: selected link %p", link); - - // Build packet buf - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: building packet with optional sections"); - uint8_t buf[1600]; - uint16_t len = append_optional_sections(etcp, buf, link); - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: optional sections added, len=%u", len); - - // Add payload (assume payload includes ID as first 2 bytes) - uint16_t pay_len = ipkt->payload_len + 2; // ID - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: payload section - pay_len=%u (payload_len=%u + 2 for ID)", - pay_len, ipkt->payload_len); - - if (len + SECTION_HEADER_SIZE + pay_len > sizeof(buf)) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: packet too large (%u + %u + %u > %u), dropping", - len, SECTION_HEADER_SIZE, pay_len, (unsigned)sizeof(buf)); - free_inflight_packet(ipkt); - return NULL; - } - buf[len++] = ETCP_SECTION_PAYLOAD; - buf[len++] = (pay_len >> 8) & 0xFF; - buf[len++] = pay_len & 0xFF; - buf[len++] = (ipkt->id >> 8) & 0xFF; - buf[len++] = ipkt->id & 0xFF; - memcpy(buf + len, ipkt->data, ipkt->payload_len); - len += ipkt->payload_len; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: payload added, total len=%u", len); - - // Alloc dgram - struct ETCP_DGRAM* dgram = memory_pool_alloc(etcp->instance->pkt_pool); - if (!dgram) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: failed to allocate dgram from memory pool"); - free_inflight_packet(ipkt); - return NULL; - } - dgram->link = link; - dgram->data_len = len; - dgram->noencrypt_len = 0; - dgram->timestamp = get_current_timestamp(); - memcpy(dgram->data, buf, len); - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: allocated dgram %p (link=%p, data_len=%u, timestamp=%u)", - dgram, link, len, dgram->timestamp); - - // Update inflight - ipkt->last_link = link; - ipkt->last_timestamp = dgram->timestamp; - ipkt->send_count++; - etcp->unacked_bytes += ipkt->payload_len; - etcp->bytes_sent_total += len; // Approx - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: updated inflight - send_count=%u, unacked_bytes=%u, bytes_sent_total=%u", - ipkt->send_count, etcp->unacked_bytes, etcp->bytes_sent_total); - - // Move to wait_ack - ipkt->state = INFLIGHT_STATE_WAIT_ACK; - ipkt->next = etcp->wait_ack_list; - etcp->wait_ack_list = ipkt; - - // Add to wait_ack list - ipkt->next = etcp->wait_ack_list; - etcp->wait_ack_list = ipkt; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: added packet %u to wait_ack_list", ipkt->id); - - // Start retrans timer if empty before - if (etcp->wait_ack_list->next == NULL && !etcp->retrans_timer) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: starting retrans_timer (wait_ack_list was empty)"); - etcp->retrans_timer = uasync_set_timeout(etcp->instance->ua, 20, etcp, retrans_timer_cb); - } - - // Update load balancer after send (call from connections after actual send) - // etcp_loadbalancer_update_after_send(link, len + headers); // Assume called externally - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: successfully created dgram %p for packet id=%u", - dgram, ipkt->id); - return dgram; -} - -// Input queue callback (placeholder to resume load balancer) -static void input_queue_cb(struct ll_queue* q, struct ll_entry* entry, void* arg) { - (void)q; - (void)entry; - struct ETCP_CONN* etcp = arg; - // Resume polling etcp_request_pkt - queue_resume_callback(q); -} - -// Append optional (expanded with debug) -static uint16_t append_optional_sections(struct ETCP_CONN* etcp, uint8_t* buf, struct ETCP_LINK* link) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "append_optional_sections: etcp=%p, link=%p", etcp, link); - - uint16_t len = 0; - int sections_added = 0; - - // Timestamp (assume 2 bytes TS) - uint16_t ts = get_current_timestamp(); - buf[len++] = ETCP_SECTION_TIMESTAMP; - buf[len++] = 0; // len high - buf[len++] = 2; // len low - buf[len++] = (ts >> 8) & 0xFF; - buf[len++] = ts & 0xFF; - sections_added++; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "append_optional_sections: added TIMESTAMP section (ts=%u, len=%u)", ts, len); - - // ACK (assume count(1) + [id(2)+ts(2)]*count) - if (etcp->pending_ack_count > 0) { - uint16_t ack_len = 1 + etcp->pending_ack_count * 4; - buf[len++] = ETCP_SECTION_ACK; - buf[len++] = (ack_len >> 8) & 0xFF; - buf[len++] = ack_len & 0xFF; - buf[len++] = etcp->pending_ack_count; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "append_optional_sections: adding ACK section with %u ACKs", etcp->pending_ack_count); - - for (uint8_t i = 0; i < etcp->pending_ack_count; i++) { - uint16_t id = etcp->pending_ack_ids[i]; - uint16_t ats = etcp->pending_ack_ts[i]; - buf[len++] = (id >> 8) & 0xFF; - buf[len++] = id & 0xFF; - buf[len++] = (ats >> 8) & 0xFF; - buf[len++] = ats & 0xFF; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "append_optional_sections: ACK[%u] - id=%u, ts=%u", i, id, ats); - } - - etcp->pending_ack_count = 0; - etcp->ack_packets_count++; - sections_added++; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "append_optional_sections: added ACK section (total_len=%u)", len); - } - - // RETRANS (similar: count(1) + id(2)*count) - if (etcp->pending_retrans_count > 0) { - uint16_t ret_len = 1 + etcp->pending_retrans_count * 2; - buf[len++] = ETCP_SECTION_RETRANS; - buf[len++] = (ret_len >> 8) & 0xFF; - buf[len++] = ret_len & 0xFF; - buf[len++] = etcp->pending_retrans_count; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "append_optional_sections: adding RETRANS section with %u requests", etcp->pending_retrans_count); - - for (uint8_t i = 0; i < etcp->pending_retrans_count; i++) { - uint16_t id = etcp->pending_retrans_ids[i]; - buf[len++] = (id >> 8) & 0xFF; - buf[len++] = id & 0xFF; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "append_optional_sections: RETRANS[%u] - id=%u", i, id); - } - - etcp->pending_retrans_count = 0; - sections_added++; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "append_optional_sections: added RETRANS section (total_len=%u)", len); - } - - // MEAS_TS if burst (assume [start_id(2)][n(1)]) - if (etcp->burst_in_progress) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "append_optional_sections: burst measurement in progress, would add MEAS_TS"); - // Logic for adding to burst packets - // Placeholder - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "append_optional_sections: completed - added %u sections, total_len=%u", - sections_added, len); - - return len; -} - -// Process ACK (expanded) -static void process_section_ack(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_ack: etcp=%p, data=%p, len=%u", etcp, data, len); - - if (len < 1) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_ack: invalid length %u", len); - return; - } - uint8_t count = data[0]; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_ack: count=%u", count); - - if (1 + count * 4 > len) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "process_section_ack: invalid count %u for len %u", count, len); - return; - } - - uint16_t lp_ts = 0; - int acked_count = 0; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_ack: processing %u ACK entries", count); - - for (uint8_t i = 0; i < count; i++) { - uint16_t id = (data[1 + i*4] << 8) | data[2 + i*4]; - uint16_t ts = (data[3 + i*4] << 8) | data[4 + i*4]; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_ack: entry %u - id=%u, ts=%u", i, id, ts); - - inflight_packet_t* pkt = find_inflight(etcp, id, INFLIGHT_STATE_WAIT_ACK); - if (pkt) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_ack: found inflight packet %u, removing (payload_len=%u)", - id, pkt->payload_len); - etcp->unacked_bytes -= pkt->payload_len; - remove_inflight(etcp, pkt); - free_inflight_packet(pkt); - lp_ts = ts; // Update last positive ts - acked_count++; - } else { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_ack: no inflight packet found for id=%u", id); - } - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_ack: successfully ACKed %u/%u packets", acked_count, count); - // Use lp_ts in retrans_check if needed - etcp->last_rx_ack_id = (data[1 + (count-1)*4] << 8) | data[2 + (count-1)*4]; // Last ACK ID -} - -// Process RETRANS (expanded) -static void process_section_retrans(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_retrans: etcp=%p, data=%p, len=%u", etcp, data, len); - - if (len < 1) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_retrans: invalid length %u", len); - return; - } - uint8_t count = data[0]; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_retrans: count=%u", count); - - if (1 + count * 2 > len) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "process_section_retrans: invalid count %u for len %u", count, len); - return; - } - - int retrans_count = 0; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_retrans: processing %u retrans requests", count); - - for (uint8_t i = 0; i < count; i++) { - uint16_t id = (data[1 + i*2] << 8) | data[2 + i*2]; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_retrans: requesting retrans for id=%u", id); - - inflight_packet_t* pkt = find_inflight(etcp, id, INFLIGHT_STATE_WAIT_ACK); - if (pkt) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_retrans: found packet %u, marking for retransmission", id); - pkt->retrans_req_count++; - pkt->need_retrans = 1; - move_to_wait_send(etcp, pkt); - retrans_count++; - } else { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_retrans: no inflight packet found for id=%u", id); - } - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_retrans: marked %u/%u packets for retransmission", retrans_count, count); -} - -// Process TIMESTAMP (expanded) -static void process_section_timestamp(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_timestamp: etcp=%p, data=%p, len=%u", etcp, data, len); - - if (len != 2) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_timestamp: invalid length %u (expected 2)", len); - return; - } - uint16_t recv_ts = (data[0] << 8) | data[1]; - uint16_t current_ts = get_current_timestamp(); - uint16_t rtt = timestamp_diff(current_ts, recv_ts); - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_timestamp: recv_ts=%u, current_ts=%u, calculated_rtt=%u", - recv_ts, current_ts, rtt); - update_rtt(etcp, rtt); -} - -// Process PAYLOAD (expanded) -static void process_section_payload(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: etcp=%p, data=%p, len=%u", etcp, data, len); - - if (len < 2) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_payload: invalid length %u (minimum 2)", len); - return; - } - uint16_t id = (data[0] << 8) | data[1]; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: packet id=%u, last_rx_id=%u", id, etcp->last_rx_id); - - if (id <= etcp->last_rx_id) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_payload: duplicate packet id=%u (last_rx_id=%u), ignoring", - id, etcp->last_rx_id); - return; // Dup - } - - rx_packet_t* new_rx = calloc(1, sizeof(rx_packet_t)); - if (!new_rx) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "process_section_payload: failed to allocate rx_packet_t"); - return; - } - - new_rx->id = id; - new_rx->timestamp = get_current_timestamp(); - new_rx->data_len = len - 2; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: allocated rx_packet %p (id=%u, data_len=%u, timestamp=%u)", - new_rx, new_rx->id, new_rx->data_len, new_rx->timestamp); - - new_rx->data = malloc(new_rx->data_len); - if (!new_rx->data) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "process_section_payload: failed to allocate rx data buffer (size=%u)", new_rx->data_len); - free(new_rx); - return; - } - memcpy(new_rx->data, data + 2, new_rx->data_len); - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: copied %u bytes of payload data", new_rx->data_len); - - // Insert sorted (assume IDs sequential, no wrap for simplicity) - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_payload: inserting packet into rx_list (id=%u)", id); - rx_packet_t** ptr = &etcp->rx_list; - while (*ptr && (*ptr)->id < id) ptr = &(*ptr)->next; - if (*ptr && (*ptr)->id == id) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_payload: duplicate packet id=%u found in rx_list, discarding", id); - free(new_rx->data); - free(new_rx); - return; - } - new_rx->next = *ptr; - *ptr = new_rx; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: successfully inserted packet id=%u into rx_list", id); - - if (id > etcp->last_rx_id) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_payload: updating last_rx_id from %u to %u", - etcp->last_rx_id, id); - etcp->last_rx_id = id; - } - - // Pending ACK - if (etcp->pending_ack_count < MAX_PENDING) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_payload: adding packet id=%u to pending ACKs (count=%u)", - id, etcp->pending_ack_count + 1); - etcp->pending_ack_ids[etcp->pending_ack_count] = id; - etcp->pending_ack_ts[etcp->pending_ack_count++] = new_rx->timestamp; - } else { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_payload: pending ACK buffer full (%u), cannot add id=%u", - MAX_PENDING, id); - } - - // Schedule ACK - if (!etcp->ack_timer) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: scheduling ACK timer (delay=%u tb)", ACK_DELAY_TB); - etcp->ack_timer = uasync_set_timeout(etcp->instance->ua, ACK_DELAY_TB, etcp, ack_timer_cb); - } - - etcp->bytes_received_total += len; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: packet id=%u processed successfully, bytes_received_total=%u", - id, etcp->bytes_received_total); -} - -// Process MEAS_TS (expanded: send resp) -static void process_section_meas_ts(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_meas_ts: etcp=%p, data=%p, len=%u", etcp, data, len); - - if (len < 3) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_meas_ts: invalid length %u (minimum 3)", len); - return; - } - uint16_t start_id = (data[0] << 8) | data[1]; - uint8_t n = data[2]; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_meas_ts: start_id=%u, n=%u", start_id, n); - - // Send MEAS_RESP (add to pending or direct) - // Placeholder: assume added to next packet - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "MEAS_TS: start_id=%u n=%u", start_id, n); - // Build resp [start_id(2)][n(1)][recv_ts(2)] - // But since appended in optional, set state -} - -// Process MEAS_RESP (expanded: calc bw) -static void process_section_meas_resp(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_meas_resp: etcp=%p, data=%p, len=%u", etcp, data, len); - - // Assume format [start_id(2)][n(1)][recv_ts(2)] - if (len < 5) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_meas_resp: invalid length %u (minimum 5)", len); - return; - } - uint16_t start_id = (data[0] << 8) | data[1]; - uint8_t n = data[2]; - uint16_t recv_ts = (data[3] << 8) | data[4]; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_meas_resp: start_id=%u, n=%u, recv_ts=%u", start_id, n, recv_ts); - - if (etcp->burst_start_id != start_id || !etcp->burst_in_progress) return; - - // Calc bw based on burst (placeholder logic) - uint16_t delta = timestamp_diff(get_current_timestamp(), recv_ts); - uint32_t bw = (BURST_SIZE * etcp->mtu * 8) / (delta / 1000.0); // bits/sec approx - update_link_bandwidth(etcp->links, bw); // Assume primary link - etcp->burst_in_progress = 0; -} - -// Detect gaps (expanded) -static void detect_gaps_and_request_retrans(struct ETCP_CONN* etcp) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: etcp=%p, last_delivered_id=%u", - etcp, etcp->last_delivered_id); - - rx_packet_t* rx = etcp->rx_list; - uint16_t expected = etcp->last_delivered_id + 1; - int gaps_found = 0; - int retrans_requested = 0; - - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: starting gap detection from expected_id=%u", expected); - - while (rx) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: checking rx packet id=%u (expected=%u)", - rx->id, expected); - - if (rx->id > expected) { - // Gap: add retrans for expected to rx->id -1 - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: gap detected - expected=%u, found=%u", - expected, rx->id); - gaps_found++; - - for (uint16_t gid = expected; gid < rx->id && etcp->pending_retrans_count < MAX_PENDING; gid++) { - etcp->pending_retrans_ids[etcp->pending_retrans_count++] = gid; - retrans_requested++; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: queued retrans request for id=%u", gid); - } - expected = rx->id + 1; - } else if (rx->id == expected) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: found expected packet id=%u", expected); - expected++; - } else { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: packet id=%u < expected=%u, already processed", - rx->id, expected); - } - rx = rx->next; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: completed - gaps_found=%d, retrans_requested=%u", - gaps_found, retrans_requested); -} - -// Deliver contiguous (expanded) -static void deliver_contiguous_packets(struct ETCP_CONN* etcp) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "deliver_contiguous_packets: etcp=%p, last_delivered_id=%u", - etcp, etcp->last_delivered_id); - - rx_packet_t** ptr = &etcp->rx_list; - int delivered_count = 0; - uint32_t delivered_bytes = 0; - - while (*ptr && (*ptr)->id == etcp->last_delivered_id + 1) { - rx_packet_t* rx = *ptr; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "deliver_contiguous_packets: delivering packet id=%u (data_len=%u)", - rx->id, rx->data_len); - - struct ll_entry* entry = queue_entry_new(rx->data_len); - if (entry) { - memcpy(ll_entry_data(entry), rx->data, rx->data_len); - queue_entry_put(etcp->output_queue, entry); - delivered_bytes += rx->data_len; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "deliver_contiguous_packets: queued packet id=%u to output_queue", rx->id); - } else { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "deliver_contiguous_packets: failed to allocate queue entry for packet id=%u", rx->id); - } - - etcp->last_delivered_id = rx->id; - *ptr = rx->next; - free(rx->data); - free(rx); - delivered_count++; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "deliver_contiguous_packets: delivered %u contiguous packets (%u bytes), last_delivered_id=%u", - delivered_count, delivered_bytes, etcp->last_delivered_id); -} - -// Retrans check (expanded with lp_ts) -static void retrans_check(struct ETCP_CONN* etcp) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_check: etcp=%p, wait_ack_list=%p, rtt_avg_10=%u, jitter=%u", - etcp, etcp->wait_ack_list, etcp->rtt_avg_10, etcp->jitter); - - uint64_t now = get_current_time_units(); - inflight_packet_t** ptr = &etcp->wait_ack_list; - uint16_t lp_ts = 0; - int checked_packets = 0; - int retrans_packets = 0; - uint16_t timeout_calc = (uint16_t)(etcp->rtt_avg_10 * RETRANS_K1 + etcp->jitter * RETRANS_K2); - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_check: timeout calculation: rtt_avg_10=%u * %.1f + jitter=%u * %.1f = %u", - etcp->rtt_avg_10, RETRANS_K1, etcp->jitter, RETRANS_K2, timeout_calc); - - while (*ptr) { - inflight_packet_t* pkt = *ptr; - checked_packets++; - uint16_t timeout = (uint16_t)(etcp->rtt_avg_10 * RETRANS_K1 + etcp->jitter * RETRANS_K2); - uint16_t time_since_send = timestamp_diff(now, pkt->last_timestamp); - - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "retrans_check: checking packet id=%u (time_since_send=%u, timeout=%u, need_retrans=%u)", - pkt->id, time_since_send, timeout, pkt->need_retrans); - - if (time_since_send > timeout) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_check: packet id=%u timed out, marking for retransmission", pkt->id); - pkt->need_retrans = 1; - move_to_wait_send(etcp, pkt); - etcp->retransmissions_count++; - retrans_packets++; - ptr = &etcp->wait_ack_list; // Restart scan after move - continue; - } - // lp_ts logic (per spec: if acked, remember ts; if later unacked with ts < lp_ts, ?) - // Assume if pkt acked (but shouldn't be in list), or for forward progress - ptr = &pkt->next; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_check: completed - checked %d packets, retransmitted %d packets, total_retransmissions=%u", - checked_packets, retrans_packets, etcp->retransmissions_count); - - // Reschedule if list not empty - if (etcp->wait_ack_list) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_check: rescheduling retrans_timer (wait_ack_list not empty)"); - etcp->retrans_timer = uasync_set_timeout(etcp->instance->ua, 20, etcp, retrans_timer_cb); - } else { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_check: clearing retrans_timer (wait_ack_list empty)"); - etcp->retrans_timer = NULL; - } -} - -// Find inflight (expanded) -static inflight_packet_t* find_inflight(struct ETCP_CONN* etcp, uint16_t id, uint8_t state) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "find_inflight: etcp=%p, id=%u, state=%u", etcp, id, state); - - inflight_packet_t* list = (state == INFLIGHT_STATE_WAIT_ACK) ? etcp->wait_ack_list : etcp->wait_send_list; - inflight_packet_t* pkt = list; - int position = 0; - - while (pkt && pkt->id != id) { - pkt = pkt->next; - position++; - } - - if (pkt) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "find_inflight: found packet %u at position %d in %s list", - id, position, (state == INFLIGHT_STATE_WAIT_ACK) ? "wait_ack" : "wait_send"); - } else { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "find_inflight: packet %u not found in %s list", - id, (state == INFLIGHT_STATE_WAIT_ACK) ? "wait_ack" : "wait_send"); - } - - return pkt; - return pkt; -} - -// Move to wait_send (expanded) -static void move_to_wait_send(struct ETCP_CONN* etcp, inflight_packet_t* pkt) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "move_to_wait_send: etcp=%p, pkt=%p (id=%u, state=%u)", - etcp, pkt, pkt->id, pkt->state); - - remove_inflight(etcp, pkt); - pkt->state = INFLIGHT_STATE_WAIT_SEND; - pkt->next = etcp->wait_send_list; - etcp->wait_send_list = pkt; - - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "move_to_wait_send: moved packet %u to wait_send_list", pkt->id); -} - -// Remove inflight (expanded) -static void remove_inflight(struct ETCP_CONN* etcp, inflight_packet_t* pkt) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "remove_inflight: etcp=%p, pkt=%p (id=%u, state=%u)", - etcp, pkt, pkt->id, pkt->state); - - inflight_packet_t** list = (pkt->state == INFLIGHT_STATE_WAIT_ACK) ? &etcp->wait_ack_list : &etcp->wait_send_list; - inflight_packet_t** ptr = list; - int position = 0; - - while (*ptr && *ptr != pkt) { - ptr = &(*ptr)->next; - position++; - } - - if (*ptr) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "remove_inflight: found packet %u at position %d in %s list", - pkt->id, position, (pkt->state == INFLIGHT_STATE_WAIT_ACK) ? "wait_ack" : "wait_send"); - *ptr = (*ptr)->next; - } else { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "remove_inflight: packet %u not found in %s list", - pkt->id, (pkt->state == INFLIGHT_STATE_WAIT_ACK) ? "wait_ack" : "wait_send"); - } -} - -// Start burst (placeholder expanded) -static void start_burst_measurement(struct ETCP_CONN* etcp, struct ETCP_LINK* link) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "start_burst_measurement: etcp=%p, link=%p", etcp, link); - - // Periodically call this - etcp->burst_in_progress = 1; - uint16_t old_start_id = etcp->burst_start_id; - etcp->burst_start_id = etcp->next_tx_id; - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "start_burst_measurement: started burst measurement - burst_start_id=%u (was %u)", - etcp->burst_start_id, old_start_id); - - // Delay first, then burst 4 - // Assume handled in request_pkt by adding meas_ts to next BURST_SIZE pkts -} - -// Update link bw (expanded) -static void update_link_bandwidth(struct ETCP_LINK* link, uint32_t new_bw) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "update_link_bandwidth: link=%p, new_bw=%u bits/sec (current=%u)", - link, new_bw, link->bandwidth); - - uint32_t old_bw = link->bandwidth; - link->bandwidth = (uint32_t)((link->bandwidth * 0.9) + (new_bw * 0.1)); // Smooth - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "update_link_bandwidth: updated link bandwidth from %u to %u bits/sec (new_bw=%u)", - old_bw, link->bandwidth, new_bw); -} - -// Update RTT (expanded with history) -static void update_rtt(struct ETCP_CONN* etcp, uint16_t new_rtt) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "update_rtt: etcp=%p, new_rtt=%u (last_rtt=%u, avg_10=%u, avg_100=%u)", - etcp, new_rtt, etcp->rtt_last, etcp->rtt_avg_10, etcp->rtt_avg_100); - - etcp->rtt_last = new_rtt; - etcp->rtt_avg_10 = (etcp->rtt_avg_10 * 9 + new_rtt) / 10; - etcp->rtt_avg_100 = (etcp->rtt_avg_100 * 99 + new_rtt) / 100; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "update_rtt: updated RTT metrics - last=%u, avg_10=%u, avg_100=%u", - etcp->rtt_last, etcp->rtt_avg_10, etcp->rtt_avg_100); - - // History for jitter - etcp->rtt_history[etcp->rtt_history_idx++] = new_rtt; - if (etcp->rtt_history_idx >= RTT_HISTORY_SIZE) etcp->rtt_history_idx = 0; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "update_rtt: stored RTT in history at index %u", - (etcp->rtt_history_idx + RTT_HISTORY_SIZE - 1) % RTT_HISTORY_SIZE); - - calculate_jitter(etcp); -} - -static void calculate_jitter(struct ETCP_CONN* etcp) { - uint16_t min_rtt = UINT16_MAX; - uint16_t max_rtt = 0; - int valid_samples = 0; - - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "calculate_jitter: analyzing RTT history (history_idx=%u)", etcp->rtt_history_idx); - - for (int i = 0; i < RTT_HISTORY_SIZE; i++) { - if (etcp->rtt_history[i] == 0) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "calculate_jitter: history[%d] = 0 (invalid), skipping", i); - continue; - } - valid_samples++; - if (etcp->rtt_history[i] < min_rtt) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "calculate_jitter: new min_rtt=%u (was %u) at history[%d]", - etcp->rtt_history[i], min_rtt, i); - min_rtt = etcp->rtt_history[i]; - } - if (etcp->rtt_history[i] > max_rtt) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "calculate_jitter: new max_rtt=%u (was %u) at history[%d]", - etcp->rtt_history[i], max_rtt, i); - max_rtt = etcp->rtt_history[i]; - } - } - - uint16_t old_jitter = etcp->jitter; - etcp->jitter = max_rtt - min_rtt; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "calculate_jitter: completed - valid_samples=%d, min_rtt=%u, max_rtt=%u, jitter=%u (was %u)", - valid_samples, min_rtt, max_rtt, etcp->jitter, old_jitter); -} - -// Timers (expanded with debug) -static void retrans_timer_cb(void* arg) { - struct ETCP_CONN* etcp = (struct ETCP_CONN*)arg; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_timer_cb: etcp=%p, triggered retransmission check", etcp); - retrans_check(etcp); -} - -static void ack_timer_cb(void* arg) { - struct ETCP_CONN* etcp = (struct ETCP_CONN*)arg; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "ack_timer_cb: etcp=%p, processing pending ACKs", etcp); - etcp->ack_timer = NULL; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "ack_timer_cb: processing %u pending ACKs", etcp->pending_ack_count); - - // Force send ACK if pending (e.g., empty payload pkt) - // For now, assume appended next - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "ack_timer_cb: ACK processing completed"); -} - -// Get stats (expanded) -void etcp_get_stats(struct ETCP_CONN* etcp, size_t* packets_sent, size_t* packets_recv, - size_t* pool_allocs, size_t* pool_reuse) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_get_stats: etcp=%p", etcp); - - if (packets_sent) { - *packets_sent = etcp->total_packets_sent; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_get_stats: total_packets_sent=%zu", *packets_sent); - } - if (packets_recv) { - *packets_recv = etcp->bytes_received_total / 1400; // Approx MTU - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_get_stats: bytes_received_total=%u, estimated_packets=%zu", - etcp->bytes_received_total, *packets_recv); - } - if (pool_allocs || pool_reuse) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_get_stats: getting memory pool stats"); - memory_pool_get_stats(etcp->instance->pkt_pool, pool_allocs, pool_reuse); - if (pool_allocs) DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_get_stats: pool_allocs=%zu", *pool_allocs); - if (pool_reuse) DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_get_stats: pool_reuse=%zu", *pool_reuse); - } -} \ No newline at end of file diff --git a/!/etcp.c2 b/!/etcp.c2 deleted file mode 100755 index 49711d17..00000000 --- a/!/etcp.c2 +++ /dev/null @@ -1,1161 +0,0 @@ -// etcp.c - ETCP Protocol Implementation (refactored and expanded based on etcp_protocol.txt) -#include "etcp.h" -#include "etcp_loadbalancer.h" -#include "../lib/u_async.h" -#include "../lib/debug_config.h" -#include "crc32.h" -#include -#include -#include -#include // For bandwidth calcs - -// Enable comprehensive debug output for ETCP module -#define DEBUG_CATEGORY_ETCP_DETAILED 1 - -// Constants from spec (adjusted for completeness) -#define MAX_INFLIGHT_BYTES 65536 // Initial window -#define RETRANS_K1 2.0f // RTT multiplier for retrans timeout -#define RETRANS_K2 1.5f // Jitter multiplier -#define ACK_DELAY_TB 20 // ACK timer delay (2ms in 0.1ms units) -#define BURST_DELAY_FACTOR 4 // Delay before burst -#define BURST_SIZE 5 // Packets in burst (1 delayed + 4 burst) -#define RTT_HISTORY_SIZE 10 // For jitter calc -#define MAX_PENDING 32 // For ACKs/retrans -#define SECTION_HEADER_SIZE 3 // type(1) + len(2) - -// Forward declaration for callback function -static void input_queue_cb(struct ll_queue* q, struct ll_entry* entry, void* arg); - -// Timestamp diff (with wrap-around) -static uint16_t timestamp_diff(uint16_t t1, uint16_t t2) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "timestamp_diff: t1=%u, t2=%u", t1, t2); - if (t1 >= t2) { - uint16_t diff = t1 - t2; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "timestamp_diff: normal case, diff=%u", diff); - return diff; - } - uint16_t diff = (0xFFFF - t2) + t1 + 1; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "timestamp_diff: wraparound case, diff=%u", diff); - return diff; -} - -// Get current time in 0.1ms units -uint64_t get_current_time_units() { - struct timeval tv; - gettimeofday(&tv, NULL); - uint64_t time_units = ((uint64_t)tv.tv_sec * 10000ULL) + (tv.tv_usec / 100); - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "get_current_time_units: tv_sec=%ld, tv_usec=%ld, result=%llu", - tv.tv_sec, tv.tv_usec, (unsigned long long)time_units); - return time_units; -} - -uint16_t get_current_timestamp() { - uint16_t timestamp = (uint16_t)(get_current_time_units() & 0xFFFF); - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "get_current_timestamp: result=%u", timestamp); - return timestamp; -} - -// Internal functions (expanded) -static void retrans_timer_cb(void* arg); -static void ack_timer_cb(void* arg); -static void update_rtt(struct ETCP_CONN* etcp, uint16_t new_rtt); -static void calculate_jitter(struct ETCP_CONN* etcp); -static void detect_gaps_and_request_retrans(struct ETCP_CONN* etcp); -static void process_section_ack(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len); -static void process_section_retrans(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len); -static void process_section_timestamp(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len); -static void process_section_payload(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len); -static void process_section_meas_ts(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len); -static void process_section_meas_resp(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len); -static uint16_t append_optional_sections(struct ETCP_CONN* etcp, uint8_t* buf, struct ETCP_LINK* link); -static void deliver_contiguous_packets(struct ETCP_CONN* etcp); -static void retrans_check(struct ETCP_CONN* etcp); -static inflight_packet_t* find_inflight(struct ETCP_CONN* etcp, uint16_t id, uint8_t state); -static void move_to_wait_send(struct ETCP_CONN* etcp, inflight_packet_t* pkt); -static void remove_inflight(struct ETCP_CONN* etcp, inflight_packet_t* pkt); -static void free_inflight_packet(inflight_packet_t* pkt); -static void start_burst_measurement(struct ETCP_CONN* etcp, struct ETCP_LINK* link); -static void update_link_bandwidth(struct ETCP_LINK* link, uint32_t new_bw); - -// Add RTT history to struct (for jitter) -/// In etcp.h, add to ETCP_CONN: -/// uint16_t rtt_history[RTT_HISTORY_SIZE]; -/// uint8_t rtt_history_idx; - -//======================================================================================================================================================================= -// Create ETCP connection (unchanged) -struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_create: instance=%p", instance); - - struct ETCP_CONN* etcp = calloc(1, sizeof(struct ETCP_CONN)); - if (!etcp) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_connection_create: failed to allocate ETCP_CONN"); - return NULL; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_create: allocated etcp=%p", etcp); - - etcp->instance = instance; - etcp->input_queue = queue_new(instance->ua, instance->pkt_pool); - etcp->output_queue = queue_new(instance->ua, instance->pkt_pool); - etcp->mtu = 1500; // Default - etcp->window_size = MAX_INFLIGHT_BYTES; - etcp->next_tx_id = 1; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_create: queues created, mtu=%d, window_size=%u, next_tx_id=%u", - etcp->mtu, etcp->window_size, etcp->next_tx_id); - - // Init crypto (as per original) - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_create: initializing crypto context"); - if (sc_init_ctx(&etcp->crypto_ctx, &instance->my_keys) != SC_OK) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_connection_create: crypto initialization failed"); - goto conn_create_err; - } - -// создаём очереди - - if (!etcp->inflight_pool=memory_pool_init(sizeof(struct INFLIGHT_PACKET))) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_connection_create: inflight pool alloc error"); goto conn_create_err; } - if (!etcp->input_send_q=queue_new(instance->ua, etcp->inflight_pool)) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_connection_create: send q alloc error"); goto conn_create_err; } - if (!etcp->input_wait_ack=queue_new(instance->ua, etcp->inflight_pool)) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_connection_create: wait q alloc error"); goto conn_create_err; } - - // Add connection to instance list - etcp->next = instance->connections; - instance->connections = etcp; - instance->connections_count++; - -// для простоты предлагаю если что-то не так - etcp_connection_close и он закрывает все что не null - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_connection_create: successfully created ETCP connection %p", etcp); - return etcp; -conn_create_err: - etcp_connection_close(etcp); - return NULL; -} -//======================================================================================================================================================================= -// Close connection (expanded free) -void etcp_connection_close(struct ETCP_CONN* etcp) { - if (!etcp) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_connection_close: called with NULL etcp"); - return; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: closing connection %p", etcp); - - // Remove connection from instance list - if (etcp->instance) { - struct ETCP_CONN** prev = &etcp->instance->connections; - struct ETCP_CONN* cur = *prev; - while (cur) { - if (cur == etcp) { - *prev = cur->next; - etcp->instance->connections_count--; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: removed from instance list, count=%d", - etcp->instance->connections_count); - break; - } - prev = &cur->next; - cur = cur->next; - } - } - - // Cancel timers - if (etcp->retrans_timer) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: canceling retrans_timer"); - uasync_cancel_timeout(etcp->instance->ua, etcp->retrans_timer); - } - if (etcp->ack_timer) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: canceling ack_timer"); - uasync_cancel_timeout(etcp->instance->ua, etcp->ack_timer); - } - - // Free inflight - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freeing wait_ack_list"); - inflight_packet_t* pkt = etcp->wait_ack_list; - int wait_ack_count = 0; - while (pkt) { - inflight_packet_t* next = pkt->next; - free_inflight_packet(pkt); - pkt = next; - wait_ack_count++; - } - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freed %d packets from wait_ack_list", wait_ack_count); - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freeing wait_send_list"); - pkt = etcp->wait_send_list; - int wait_send_count = 0; - while (pkt) { - inflight_packet_t* next = pkt->next; - free_inflight_packet(pkt); - pkt = next; - wait_send_count++; - } - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freed %d packets from wait_send_list", wait_send_count); - - // Free rx_list - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freeing rx_list"); - rx_packet_t* rx = etcp->rx_list; - int rx_count = 0; - while (rx) { - rx_packet_t* next = rx->next; - free(rx->data); - free(rx); - rx = next; - rx_count++; - } - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freed %d packets from rx_list", rx_count); - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connection_close: freeing queues"); - queue_free(etcp->input_queue); - queue_free(etcp->output_queue); - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_connection_close: connection %p closed successfully", etcp); - free(etcp); -} - -//======================================================================================================================================================================= - -static void free_inflight_packet(inflight_packet_t* pkt) { - if (pkt) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "free_inflight_packet: freeing packet %p (id=%u, data_len=%u)", - pkt, pkt->id, pkt->data_len); - free(pkt->data); - free(pkt); - } -} - -//======================================================================================================================================================================= - -// Reset connection (unchanged) -void etcp_conn_reset(struct ETCP_CONN* etcp) { - if (!etcp) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_conn_reset: called with NULL etcp"); - return; - } - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_conn_reset: resetting connection %p", etcp); - - // Cancel timers - if (etcp->retrans_timer) uasync_cancel_timeout(etcp->instance->ua, etcp->retrans_timer); - if (etcp->ack_timer) uasync_cancel_timeout(etcp->instance->ua, etcp->ack_timer); - - // Free lists - inflight_packet_t* pkt = etcp->wait_ack_list; - while (pkt) { - inflight_packet_t* next = pkt->next; - free_inflight_packet(pkt); - pkt = next; - } - etcp->wait_ack_list = NULL; - pkt = etcp->wait_send_list; - while (pkt) { - inflight_packet_t* next = pkt->next; - free_inflight_packet(pkt); - pkt = next; - } - etcp->wait_send_list = NULL; - - rx_packet_t* rx = etcp->rx_list; - while (rx) { - rx_packet_t* next = rx->next; - free(rx->data); - free(rx); - rx = next; - } - etcp->rx_list = NULL; - - // Reset state - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_conn_reset: clearing packet lists and resetting state"); - etcp->next_tx_id = 1; - etcp->last_rx_id = 0; - etcp->last_delivered_id = 0; - etcp->unacked_bytes = 0; - etcp->pending_ack_count = 0; - etcp->pending_retrans_count = 0; - etcp->rtt_last = 0; - etcp->rtt_avg_10 = 0; - etcp->rtt_avg_100 = 0; - etcp->jitter = 0; - etcp->burst_in_progress = 0; - etcp->rtt_history_idx = 0; - memset(etcp->rtt_history, 0, sizeof(etcp->rtt_history)); - // Queues cleared externally if needed - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_conn_reset: connection %p reset completed", etcp); -} - -//======================================================================================================================================================================= -// PACKET INPUT processing -//======================================================================================================================================================================= - - -// Input decrypted packet (unchanged structure, but calls expanded processes) -void etcp_conn_input(struct ETCP_DGRAM* pkt) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_conn_input: pkt=%p, link=%p, etcp=%p", - pkt, pkt ? pkt->link : NULL, pkt && pkt->link ? pkt->link->etcp : NULL); - - if (!pkt || !pkt->link || !pkt->link->etcp) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_conn_input: invalid parameters (pkt=%p, link=%p, etcp=%p)", - pkt, pkt ? pkt->link : NULL, pkt && pkt->link ? pkt->link->etcp : NULL); - return; - } - - struct ETCP_CONN* etcp = pkt->link->etcp; - uint8_t* data = pkt->data; - uint16_t len = pkt->data_len; - uint16_t ts = pkt->timestamp; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_conn_input: processing packet - etcp=%p, data_len=%u, timestamp=%u, link=%p", - etcp, len, ts, pkt->link); - - // Update link activity - pkt->link->last_activity = get_current_time_units(); - pkt->link->last_recv_local_time = pkt->link->last_activity; - pkt->link->last_recv_timestamp = ts; - - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_conn_input: updated link activity - last_activity=%llu, last_recv_timestamp=%u", - (unsigned long long)pkt->link->last_activity, pkt->link->last_recv_timestamp); - - // Parse sections - uint16_t pos = 0; - while (pos < len) { - if (pos + SECTION_HEADER_SIZE > len) break; - - uint8_t type = data[pos]; - uint16_t sec_len = (data[pos+1] << 8) | data[pos+2]; - pos += SECTION_HEADER_SIZE; - - if (pos + sec_len > len) break; - - uint8_t* sec_data = data + pos; - switch (type) { - case ETCP_SECTION_ACK: - process_section_ack(etcp, sec_data, sec_len); - break; - case ETCP_SECTION_RETRANS: - process_section_retrans(etcp, sec_data, sec_len); - break; - case ETCP_SECTION_TIMESTAMP: - process_section_timestamp(etcp, sec_data, sec_len); - break; - case ETCP_SECTION_PAYLOAD: - process_section_payload(etcp, sec_data, sec_len); - break; - case ETCP_SECTION_MEAS_TS: - process_section_meas_ts(etcp, sec_data, sec_len); - break; - case ETCP_SECTION_MEAS_RESP: - process_section_meas_resp(etcp, sec_data, sec_len); - break; - default: - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "Unknown section type: 0x%02x", type); - break; - } - pos += sec_len; - } - - // Post-processing - detect_gaps_and_request_retrans(etcp); - deliver_contiguous_packets(etcp); - - // Trigger if waiting - if (etcp->wait_timeout_active) { - etcp->wait_timeout_active = 0; - // Assume load balancer polls again - } -} - -// Request next packet (expanded) -// source 1: wait_ack_list -// source 2: queue > wait_ack_list - -// Эта основная функция для формирования кодограмм на передачу из входящей очереди в UDP -// она вызывается когда какой-либо из каналов освободился, либо появились данные во входящей очереди, либо сработал таймер ретрансмиссии -// должна формировать пакеты до тех пор пока их может принимать loadbalancer -struct ETCP_DGRAM* etcp_request_pkt(struct ETCP_CONN* etcp) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: etcp=%p", etcp); - - if (!etcp) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: called with NULL etcp"); - return NULL; - } - - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: input_queue_count=%d, wait_send_list=%p, unacked_bytes=%u, window_size=%u", - queue_entry_count(etcp->input_queue), etcp->wait_send_list, - etcp->unacked_bytes, etcp->window_size); - - etcp_get_wait_list(); - // Check waiting conditions - if (queue_entry_count(etcp->input_queue) == 0 && etcp->wait_send_list == NULL) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: no packets available, setting callback and returning NULL"); - // Wait for input or retrans - // Set callback for resume - queue_set_callback(etcp->input_queue, input_queue_cb, etcp); // Define cb to resume - return NULL; - } - - if (etcp->unacked_bytes >= etcp->window_size) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: window full (unacked_bytes=%u >= window_size=%u), waiting", - etcp->unacked_bytes, etcp->window_size); - // Wait ACK or timeout - etcp->wait_timeout_active = 1; - return NULL; - } - - if (etcp->unacked_bytes >= etcp->window_size) { - // Wait ACK or timeout - etcp->wait_timeout_active = 1; - return NULL; - } - - // Get packet (prefer retrans) - inflight_packet_t* ipkt = etcp->wait_send_list; - if (ipkt) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: using retransmission packet id=%u", ipkt->id); - remove_inflight(etcp, ipkt); - } else { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: getting new packet from input queue"); - struct ll_entry* entry = queue_entry_get(etcp->input_queue); - if (!entry) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: no entry available from input queue"); - return NULL; - } - - ipkt = calloc(1, sizeof(inflight_packet_t)); - if (!ipkt) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: failed to allocate inflight_packet_t"); - queue_entry_put_first(etcp->input_queue, entry); - return NULL; - } - - ipkt->id = etcp->next_tx_id++; - ipkt->data_len = ll_entry_size(entry); - ipkt->data = malloc(ipkt->data_len); - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: created new packet id=%u, data_len=%u", - ipkt->id, ipkt->data_len); - - if (!ipkt->data) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: failed to allocate packet data buffer"); - free(ipkt); - queue_entry_put_first(etcp->input_queue, entry); - return NULL; - } - memcpy(ipkt->data, ll_entry_data(entry), ipkt->data_len); - ipkt->payload_len = ipkt->data_len; // Assume full is payload for window - queue_entry_free(entry); - } - - // Select link - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: selecting link via loadbalancer"); - struct ETCP_LINK* link = etcp_loadbalancer_select_link(etcp); - if (!link) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: no suitable link available"); - // Put back if new - if (ipkt->send_count == 0) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: putting new packet back to input queue"); - struct ll_entry* entry = queue_entry_new(ipkt->data_len); - memcpy(ll_entry_data(entry), ipkt->data, ipkt->data_len); - queue_entry_put_first(etcp->input_queue, entry); - } - free_inflight_packet(ipkt); - return NULL; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: selected link %p", link); - - // Build packet buf - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: building packet with optional sections"); - uint8_t buf[1600]; - uint16_t len = append_optional_sections(etcp, buf, link); - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: optional sections added, len=%u", len); - - // Add payload (assume payload includes ID as first 2 bytes) - uint16_t pay_len = ipkt->payload_len + 2; // ID - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: payload section - pay_len=%u (payload_len=%u + 2 for ID)", - pay_len, ipkt->payload_len); - - if (len + SECTION_HEADER_SIZE + pay_len > sizeof(buf)) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: packet too large (%u + %u + %u > %u), dropping", - len, SECTION_HEADER_SIZE, pay_len, (unsigned)sizeof(buf)); - free_inflight_packet(ipkt); - return NULL; - } - buf[len++] = ETCP_SECTION_PAYLOAD; - buf[len++] = (pay_len >> 8) & 0xFF; - buf[len++] = pay_len & 0xFF; - buf[len++] = (ipkt->id >> 8) & 0xFF; - buf[len++] = ipkt->id & 0xFF; - memcpy(buf + len, ipkt->data, ipkt->payload_len); - len += ipkt->payload_len; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: payload added, total len=%u", len); - - // Alloc dgram - struct ETCP_DGRAM* dgram = memory_pool_alloc(etcp->instance->pkt_pool); - if (!dgram) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: failed to allocate dgram from memory pool"); - free_inflight_packet(ipkt); - return NULL; - } - dgram->link = link; - dgram->data_len = len; - dgram->noencrypt_len = 0; - dgram->timestamp = get_current_timestamp(); - memcpy(dgram->data, buf, len); - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: allocated dgram %p (link=%p, data_len=%u, timestamp=%u)", - dgram, link, len, dgram->timestamp); - - // Update inflight - ipkt->last_link = link; - ipkt->last_timestamp = dgram->timestamp; - ipkt->send_count++; - etcp->unacked_bytes += ipkt->payload_len; - etcp->bytes_sent_total += len; // Approx - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: updated inflight - send_count=%u, unacked_bytes=%u, bytes_sent_total=%u", - ipkt->send_count, etcp->unacked_bytes, etcp->bytes_sent_total); - - // Move to wait_ack - ipkt->state = INFLIGHT_STATE_WAIT_ACK; - ipkt->next = etcp->wait_ack_list; - etcp->wait_ack_list = ipkt; - - // Add to wait_ack list - ipkt->next = etcp->wait_ack_list; - etcp->wait_ack_list = ipkt; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: added packet %u to wait_ack_list", ipkt->id); - - // Start retrans timer if empty before - if (etcp->wait_ack_list->next == NULL && !etcp->retrans_timer) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: starting retrans_timer (wait_ack_list was empty)"); - etcp->retrans_timer = uasync_set_timeout(etcp->instance->ua, 20, etcp, retrans_timer_cb); - } - - // Update load balancer after send (call from connections after actual send) - // etcp_loadbalancer_update_after_send(link, len + headers); // Assume called externally - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_request_pkt: successfully created dgram %p for packet id=%u", - dgram, ipkt->id); - return dgram; -} - -// Input queue callback (placeholder to resume load balancer) -static void input_queue_cb(struct ll_queue* q, struct ll_entry* entry, void* arg) { - (void)q; - (void)entry; - struct ETCP_CONN* etcp = arg; - // Resume polling etcp_request_pkt - queue_resume_callback(q); -} - -// Append optional (expanded with debug) -static uint16_t append_optional_sections(struct ETCP_CONN* etcp, uint8_t* buf, struct ETCP_LINK* link) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "append_optional_sections: etcp=%p, link=%p", etcp, link); - - uint16_t len = 0; - int sections_added = 0; - - // Timestamp (assume 2 bytes TS) - uint16_t ts = get_current_timestamp(); - buf[len++] = ETCP_SECTION_TIMESTAMP; - buf[len++] = 0; // len high - buf[len++] = 2; // len low - buf[len++] = (ts >> 8) & 0xFF; - buf[len++] = ts & 0xFF; - sections_added++; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "append_optional_sections: added TIMESTAMP section (ts=%u, len=%u)", ts, len); - - // ACK (assume count(1) + [id(2)+ts(2)]*count) - if (etcp->pending_ack_count > 0) { - uint16_t ack_len = 1 + etcp->pending_ack_count * 4; - buf[len++] = ETCP_SECTION_ACK; - buf[len++] = (ack_len >> 8) & 0xFF; - buf[len++] = ack_len & 0xFF; - buf[len++] = etcp->pending_ack_count; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "append_optional_sections: adding ACK section with %u ACKs", etcp->pending_ack_count); - - for (uint8_t i = 0; i < etcp->pending_ack_count; i++) { - uint16_t id = etcp->pending_ack_ids[i]; - uint16_t ats = etcp->pending_ack_ts[i]; - buf[len++] = (id >> 8) & 0xFF; - buf[len++] = id & 0xFF; - buf[len++] = (ats >> 8) & 0xFF; - buf[len++] = ats & 0xFF; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "append_optional_sections: ACK[%u] - id=%u, ts=%u", i, id, ats); - } - - etcp->pending_ack_count = 0; - etcp->ack_packets_count++; - sections_added++; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "append_optional_sections: added ACK section (total_len=%u)", len); - } - - // RETRANS (similar: count(1) + id(2)*count) - if (etcp->pending_retrans_count > 0) { - uint16_t ret_len = 1 + etcp->pending_retrans_count * 2; - buf[len++] = ETCP_SECTION_RETRANS; - buf[len++] = (ret_len >> 8) & 0xFF; - buf[len++] = ret_len & 0xFF; - buf[len++] = etcp->pending_retrans_count; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "append_optional_sections: adding RETRANS section with %u requests", etcp->pending_retrans_count); - - for (uint8_t i = 0; i < etcp->pending_retrans_count; i++) { - uint16_t id = etcp->pending_retrans_ids[i]; - buf[len++] = (id >> 8) & 0xFF; - buf[len++] = id & 0xFF; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "append_optional_sections: RETRANS[%u] - id=%u", i, id); - } - - etcp->pending_retrans_count = 0; - sections_added++; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "append_optional_sections: added RETRANS section (total_len=%u)", len); - } - - // MEAS_TS if burst (assume [start_id(2)][n(1)]) - if (etcp->burst_in_progress) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "append_optional_sections: burst measurement in progress, would add MEAS_TS"); - // Logic for adding to burst packets - // Placeholder - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "append_optional_sections: completed - added %u sections, total_len=%u", - sections_added, len); - - return len; -} - -// Process ACK (expanded) -static void process_section_ack(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_ack: etcp=%p, data=%p, len=%u", etcp, data, len); - - if (len < 1) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_ack: invalid length %u", len); - return; - } - uint8_t count = data[0]; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_ack: count=%u", count); - - if (1 + count * 4 > len) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "process_section_ack: invalid count %u for len %u", count, len); - return; - } - - uint16_t lp_ts = 0; - int acked_count = 0; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_ack: processing %u ACK entries", count); - - for (uint8_t i = 0; i < count; i++) { - uint16_t id = (data[1 + i*4] << 8) | data[2 + i*4]; - uint16_t ts = (data[3 + i*4] << 8) | data[4 + i*4]; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_ack: entry %u - id=%u, ts=%u", i, id, ts); - - inflight_packet_t* pkt = find_inflight(etcp, id, INFLIGHT_STATE_WAIT_ACK); - if (pkt) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_ack: found inflight packet %u, removing (payload_len=%u)", - id, pkt->payload_len); - etcp->unacked_bytes -= pkt->payload_len; - remove_inflight(etcp, pkt); - free_inflight_packet(pkt); - lp_ts = ts; // Update last positive ts - acked_count++; - } else { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_ack: no inflight packet found for id=%u", id); - } - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_ack: successfully ACKed %u/%u packets", acked_count, count); - // Use lp_ts in retrans_check if needed - etcp->last_rx_ack_id = (data[1 + (count-1)*4] << 8) | data[2 + (count-1)*4]; // Last ACK ID -} - -// Process RETRANS (expanded) -static void process_section_retrans(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_retrans: etcp=%p, data=%p, len=%u", etcp, data, len); - - if (len < 1) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_retrans: invalid length %u", len); - return; - } - uint8_t count = data[0]; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_retrans: count=%u", count); - - if (1 + count * 2 > len) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "process_section_retrans: invalid count %u for len %u", count, len); - return; - } - - int retrans_count = 0; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_retrans: processing %u retrans requests", count); - - for (uint8_t i = 0; i < count; i++) { - uint16_t id = (data[1 + i*2] << 8) | data[2 + i*2]; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_retrans: requesting retrans for id=%u", id); - - inflight_packet_t* pkt = find_inflight(etcp, id, INFLIGHT_STATE_WAIT_ACK); - if (pkt) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_retrans: found packet %u, marking for retransmission", id); - pkt->retrans_req_count++; - pkt->need_retrans = 1; - move_to_wait_send(etcp, pkt); - retrans_count++; - } else { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_retrans: no inflight packet found for id=%u", id); - } - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_retrans: marked %u/%u packets for retransmission", retrans_count, count); -} - -// Process TIMESTAMP (expanded) -static void process_section_timestamp(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_timestamp: etcp=%p, data=%p, len=%u", etcp, data, len); - - if (len != 2) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_timestamp: invalid length %u (expected 2)", len); - return; - } - uint16_t recv_ts = (data[0] << 8) | data[1]; - uint16_t current_ts = get_current_timestamp(); - uint16_t rtt = timestamp_diff(current_ts, recv_ts); - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_timestamp: recv_ts=%u, current_ts=%u, calculated_rtt=%u", - recv_ts, current_ts, rtt); - update_rtt(etcp, rtt); -} - -// Process PAYLOAD (expanded) -static void process_section_payload(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: etcp=%p, data=%p, len=%u", etcp, data, len); - - if (len < 2) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_payload: invalid length %u (minimum 2)", len); - return; - } - uint16_t id = (data[0] << 8) | data[1]; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: packet id=%u, last_rx_id=%u", id, etcp->last_rx_id); - - if (id <= etcp->last_rx_id) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_payload: duplicate packet id=%u (last_rx_id=%u), ignoring", - id, etcp->last_rx_id); - return; // Dup - } - - rx_packet_t* new_rx = calloc(1, sizeof(rx_packet_t)); - if (!new_rx) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "process_section_payload: failed to allocate rx_packet_t"); - return; - } - - new_rx->id = id; - new_rx->timestamp = get_current_timestamp(); - new_rx->data_len = len - 2; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: allocated rx_packet %p (id=%u, data_len=%u, timestamp=%u)", - new_rx, new_rx->id, new_rx->data_len, new_rx->timestamp); - - new_rx->data = malloc(new_rx->data_len); - if (!new_rx->data) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "process_section_payload: failed to allocate rx data buffer (size=%u)", new_rx->data_len); - free(new_rx); - return; - } - memcpy(new_rx->data, data + 2, new_rx->data_len); - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: copied %u bytes of payload data", new_rx->data_len); - - // Insert sorted (assume IDs sequential, no wrap for simplicity) - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_payload: inserting packet into rx_list (id=%u)", id); - rx_packet_t** ptr = &etcp->rx_list; - while (*ptr && (*ptr)->id < id) ptr = &(*ptr)->next; - if (*ptr && (*ptr)->id == id) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_payload: duplicate packet id=%u found in rx_list, discarding", id); - free(new_rx->data); - free(new_rx); - return; - } - new_rx->next = *ptr; - *ptr = new_rx; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: successfully inserted packet id=%u into rx_list", id); - - if (id > etcp->last_rx_id) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_payload: updating last_rx_id from %u to %u", - etcp->last_rx_id, id); - etcp->last_rx_id = id; - } - - // Pending ACK - if (etcp->pending_ack_count < MAX_PENDING) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "process_section_payload: adding packet id=%u to pending ACKs (count=%u)", - id, etcp->pending_ack_count + 1); - etcp->pending_ack_ids[etcp->pending_ack_count] = id; - etcp->pending_ack_ts[etcp->pending_ack_count++] = new_rx->timestamp; - } else { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_payload: pending ACK buffer full (%u), cannot add id=%u", - MAX_PENDING, id); - } - - // Schedule ACK - if (!etcp->ack_timer) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: scheduling ACK timer (delay=%u tb)", ACK_DELAY_TB); - etcp->ack_timer = uasync_set_timeout(etcp->instance->ua, ACK_DELAY_TB, etcp, ack_timer_cb); - } - - etcp->bytes_received_total += len; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_payload: packet id=%u processed successfully, bytes_received_total=%u", - id, etcp->bytes_received_total); -} - -// Process MEAS_TS (expanded: send resp) -static void process_section_meas_ts(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_meas_ts: etcp=%p, data=%p, len=%u", etcp, data, len); - - if (len < 3) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_meas_ts: invalid length %u (minimum 3)", len); - return; - } - uint16_t start_id = (data[0] << 8) | data[1]; - uint8_t n = data[2]; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_meas_ts: start_id=%u, n=%u", start_id, n); - - // Send MEAS_RESP (add to pending or direct) - // Placeholder: assume added to next packet - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "MEAS_TS: start_id=%u n=%u", start_id, n); - // Build resp [start_id(2)][n(1)][recv_ts(2)] - // But since appended in optional, set state -} - -// Process MEAS_RESP (expanded: calc bw) -static void process_section_meas_resp(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_meas_resp: etcp=%p, data=%p, len=%u", etcp, data, len); - - // Assume format [start_id(2)][n(1)][recv_ts(2)] - if (len < 5) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "process_section_meas_resp: invalid length %u (minimum 5)", len); - return; - } - uint16_t start_id = (data[0] << 8) | data[1]; - uint8_t n = data[2]; - uint16_t recv_ts = (data[3] << 8) | data[4]; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "process_section_meas_resp: start_id=%u, n=%u, recv_ts=%u", start_id, n, recv_ts); - - if (etcp->burst_start_id != start_id || !etcp->burst_in_progress) return; - - // Calc bw based on burst (placeholder logic) - uint16_t delta = timestamp_diff(get_current_timestamp(), recv_ts); - uint32_t bw = (BURST_SIZE * etcp->mtu * 8) / (delta / 1000.0); // bits/sec approx - update_link_bandwidth(etcp->links, bw); // Assume primary link - etcp->burst_in_progress = 0; -} - -// Detect gaps (expanded) -static void detect_gaps_and_request_retrans(struct ETCP_CONN* etcp) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: etcp=%p, last_delivered_id=%u", - etcp, etcp->last_delivered_id); - - rx_packet_t* rx = etcp->rx_list; - uint16_t expected = etcp->last_delivered_id + 1; - int gaps_found = 0; - int retrans_requested = 0; - - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: starting gap detection from expected_id=%u", expected); - - while (rx) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: checking rx packet id=%u (expected=%u)", - rx->id, expected); - - if (rx->id > expected) { - // Gap: add retrans for expected to rx->id -1 - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: gap detected - expected=%u, found=%u", - expected, rx->id); - gaps_found++; - - for (uint16_t gid = expected; gid < rx->id && etcp->pending_retrans_count < MAX_PENDING; gid++) { - etcp->pending_retrans_ids[etcp->pending_retrans_count++] = gid; - retrans_requested++; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: queued retrans request for id=%u", gid); - } - expected = rx->id + 1; - } else if (rx->id == expected) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: found expected packet id=%u", expected); - expected++; - } else { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: packet id=%u < expected=%u, already processed", - rx->id, expected); - } - rx = rx->next; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "detect_gaps_and_request_retrans: completed - gaps_found=%d, retrans_requested=%u", - gaps_found, retrans_requested); -} - -// Deliver contiguous (expanded) -static void deliver_contiguous_packets(struct ETCP_CONN* etcp) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "deliver_contiguous_packets: etcp=%p, last_delivered_id=%u", - etcp, etcp->last_delivered_id); - - rx_packet_t** ptr = &etcp->rx_list; - int delivered_count = 0; - uint32_t delivered_bytes = 0; - - while (*ptr && (*ptr)->id == etcp->last_delivered_id + 1) { - rx_packet_t* rx = *ptr; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "deliver_contiguous_packets: delivering packet id=%u (data_len=%u)", - rx->id, rx->data_len); - - struct ll_entry* entry = queue_entry_new(rx->data_len); - if (entry) { - memcpy(ll_entry_data(entry), rx->data, rx->data_len); - queue_entry_put(etcp->output_queue, entry); - delivered_bytes += rx->data_len; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "deliver_contiguous_packets: queued packet id=%u to output_queue", rx->id); - } else { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "deliver_contiguous_packets: failed to allocate queue entry for packet id=%u", rx->id); - } - - etcp->last_delivered_id = rx->id; - *ptr = rx->next; - free(rx->data); - free(rx); - delivered_count++; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "deliver_contiguous_packets: delivered %u contiguous packets (%u bytes), last_delivered_id=%u", - delivered_count, delivered_bytes, etcp->last_delivered_id); -} - -// Retrans check (expanded with lp_ts) -static void retrans_check(struct ETCP_CONN* etcp) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_check: etcp=%p, wait_ack_list=%p, rtt_avg_10=%u, jitter=%u", - etcp, etcp->wait_ack_list, etcp->rtt_avg_10, etcp->jitter); - - uint64_t now = get_current_time_units(); - inflight_packet_t** ptr = &etcp->wait_ack_list; - uint16_t lp_ts = 0; - int checked_packets = 0; - int retrans_packets = 0; - uint16_t timeout_calc = (uint16_t)(etcp->rtt_avg_10 * RETRANS_K1 + etcp->jitter * RETRANS_K2); - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_check: timeout calculation: rtt_avg_10=%u * %.1f + jitter=%u * %.1f = %u", - etcp->rtt_avg_10, RETRANS_K1, etcp->jitter, RETRANS_K2, timeout_calc); - - while (*ptr) { - inflight_packet_t* pkt = *ptr; - checked_packets++; - uint16_t timeout = (uint16_t)(etcp->rtt_avg_10 * RETRANS_K1 + etcp->jitter * RETRANS_K2); - uint16_t time_since_send = timestamp_diff(now, pkt->last_timestamp); - - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "retrans_check: checking packet id=%u (time_since_send=%u, timeout=%u, need_retrans=%u)", - pkt->id, time_since_send, timeout, pkt->need_retrans); - - if (time_since_send > timeout) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_check: packet id=%u timed out, marking for retransmission", pkt->id); - pkt->need_retrans = 1; - move_to_wait_send(etcp, pkt); - etcp->retransmissions_count++; - retrans_packets++; - ptr = &etcp->wait_ack_list; // Restart scan after move - continue; - } - // lp_ts logic (per spec: if acked, remember ts; if later unacked with ts < lp_ts, ?) - // Assume if pkt acked (but shouldn't be in list), or for forward progress - ptr = &pkt->next; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_check: completed - checked %d packets, retransmitted %d packets, total_retransmissions=%u", - checked_packets, retrans_packets, etcp->retransmissions_count); - - // Reschedule if list not empty - if (etcp->wait_ack_list) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_check: rescheduling retrans_timer (wait_ack_list not empty)"); - etcp->retrans_timer = uasync_set_timeout(etcp->instance->ua, 20, etcp, retrans_timer_cb); - } else { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_check: clearing retrans_timer (wait_ack_list empty)"); - etcp->retrans_timer = NULL; - } -} - -// Find inflight (expanded) -static inflight_packet_t* find_inflight(struct ETCP_CONN* etcp, uint16_t id, uint8_t state) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "find_inflight: etcp=%p, id=%u, state=%u", etcp, id, state); - - inflight_packet_t* list = (state == INFLIGHT_STATE_WAIT_ACK) ? etcp->wait_ack_list : etcp->wait_send_list; - inflight_packet_t* pkt = list; - int position = 0; - - while (pkt && pkt->id != id) { - pkt = pkt->next; - position++; - } - - if (pkt) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "find_inflight: found packet %u at position %d in %s list", - id, position, (state == INFLIGHT_STATE_WAIT_ACK) ? "wait_ack" : "wait_send"); - } else { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "find_inflight: packet %u not found in %s list", - id, (state == INFLIGHT_STATE_WAIT_ACK) ? "wait_ack" : "wait_send"); - } - - return pkt; - return pkt; -} - -// Move to wait_send (expanded) -static void move_to_wait_send(struct ETCP_CONN* etcp, inflight_packet_t* pkt) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "move_to_wait_send: etcp=%p, pkt=%p (id=%u, state=%u)", - etcp, pkt, pkt->id, pkt->state); - - remove_inflight(etcp, pkt); - pkt->state = INFLIGHT_STATE_WAIT_SEND; - pkt->next = etcp->wait_send_list; - etcp->wait_send_list = pkt; - - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "move_to_wait_send: moved packet %u to wait_send_list", pkt->id); -} - -// Remove inflight (expanded) -static void remove_inflight(struct ETCP_CONN* etcp, inflight_packet_t* pkt) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "remove_inflight: etcp=%p, pkt=%p (id=%u, state=%u)", - etcp, pkt, pkt->id, pkt->state); - - inflight_packet_t** list = (pkt->state == INFLIGHT_STATE_WAIT_ACK) ? &etcp->wait_ack_list : &etcp->wait_send_list; - inflight_packet_t** ptr = list; - int position = 0; - - while (*ptr && *ptr != pkt) { - ptr = &(*ptr)->next; - position++; - } - - if (*ptr) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "remove_inflight: found packet %u at position %d in %s list", - pkt->id, position, (pkt->state == INFLIGHT_STATE_WAIT_ACK) ? "wait_ack" : "wait_send"); - *ptr = (*ptr)->next; - } else { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "remove_inflight: packet %u not found in %s list", - pkt->id, (pkt->state == INFLIGHT_STATE_WAIT_ACK) ? "wait_ack" : "wait_send"); - } -} - -// Start burst (placeholder expanded) -static void start_burst_measurement(struct ETCP_CONN* etcp, struct ETCP_LINK* link) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "start_burst_measurement: etcp=%p, link=%p", etcp, link); - - // Periodically call this - etcp->burst_in_progress = 1; - uint16_t old_start_id = etcp->burst_start_id; - etcp->burst_start_id = etcp->next_tx_id; - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "start_burst_measurement: started burst measurement - burst_start_id=%u (was %u)", - etcp->burst_start_id, old_start_id); - - // Delay first, then burst 4 - // Assume handled in request_pkt by adding meas_ts to next BURST_SIZE pkts -} - -// Update link bw (expanded) -static void update_link_bandwidth(struct ETCP_LINK* link, uint32_t new_bw) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "update_link_bandwidth: link=%p, new_bw=%u bits/sec (current=%u)", - link, new_bw, link->bandwidth); - - uint32_t old_bw = link->bandwidth; - link->bandwidth = (uint32_t)((link->bandwidth * 0.9) + (new_bw * 0.1)); // Smooth - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "update_link_bandwidth: updated link bandwidth from %u to %u bits/sec (new_bw=%u)", - old_bw, link->bandwidth, new_bw); -} - -// Update RTT (expanded with history) -static void update_rtt(struct ETCP_CONN* etcp, uint16_t new_rtt) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "update_rtt: etcp=%p, new_rtt=%u (last_rtt=%u, avg_10=%u, avg_100=%u)", - etcp, new_rtt, etcp->rtt_last, etcp->rtt_avg_10, etcp->rtt_avg_100); - - etcp->rtt_last = new_rtt; - etcp->rtt_avg_10 = (etcp->rtt_avg_10 * 9 + new_rtt) / 10; - etcp->rtt_avg_100 = (etcp->rtt_avg_100 * 99 + new_rtt) / 100; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "update_rtt: updated RTT metrics - last=%u, avg_10=%u, avg_100=%u", - etcp->rtt_last, etcp->rtt_avg_10, etcp->rtt_avg_100); - - // History for jitter - etcp->rtt_history[etcp->rtt_history_idx++] = new_rtt; - if (etcp->rtt_history_idx >= RTT_HISTORY_SIZE) etcp->rtt_history_idx = 0; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "update_rtt: stored RTT in history at index %u", - (etcp->rtt_history_idx + RTT_HISTORY_SIZE - 1) % RTT_HISTORY_SIZE); - - calculate_jitter(etcp); -} - -static void calculate_jitter(struct ETCP_CONN* etcp) { - uint16_t min_rtt = UINT16_MAX; - uint16_t max_rtt = 0; - int valid_samples = 0; - - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "calculate_jitter: analyzing RTT history (history_idx=%u)", etcp->rtt_history_idx); - - for (int i = 0; i < RTT_HISTORY_SIZE; i++) { - if (etcp->rtt_history[i] == 0) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "calculate_jitter: history[%d] = 0 (invalid), skipping", i); - continue; - } - valid_samples++; - if (etcp->rtt_history[i] < min_rtt) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "calculate_jitter: new min_rtt=%u (was %u) at history[%d]", - etcp->rtt_history[i], min_rtt, i); - min_rtt = etcp->rtt_history[i]; - } - if (etcp->rtt_history[i] > max_rtt) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "calculate_jitter: new max_rtt=%u (was %u) at history[%d]", - etcp->rtt_history[i], max_rtt, i); - max_rtt = etcp->rtt_history[i]; - } - } - - uint16_t old_jitter = etcp->jitter; - etcp->jitter = max_rtt - min_rtt; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "calculate_jitter: completed - valid_samples=%d, min_rtt=%u, max_rtt=%u, jitter=%u (was %u)", - valid_samples, min_rtt, max_rtt, etcp->jitter, old_jitter); -} - -// Timers (expanded with debug) -static void retrans_timer_cb(void* arg) { - struct ETCP_CONN* etcp = (struct ETCP_CONN*)arg; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "retrans_timer_cb: etcp=%p, triggered retransmission check", etcp); - retrans_check(etcp); -} - -static void ack_timer_cb(void* arg) { - struct ETCP_CONN* etcp = (struct ETCP_CONN*)arg; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "ack_timer_cb: etcp=%p, processing pending ACKs", etcp); - etcp->ack_timer = NULL; - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "ack_timer_cb: processing %u pending ACKs", etcp->pending_ack_count); - - // Force send ACK if pending (e.g., empty payload pkt) - // For now, assume appended next - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "ack_timer_cb: ACK processing completed"); -} - -// Get stats (expanded) -void etcp_get_stats(struct ETCP_CONN* etcp, size_t* packets_sent, size_t* packets_recv, - size_t* pool_allocs, size_t* pool_reuse) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_get_stats: etcp=%p", etcp); - - if (packets_sent) { - *packets_sent = etcp->total_packets_sent; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_get_stats: total_packets_sent=%zu", *packets_sent); - } - if (packets_recv) { - *packets_recv = etcp->bytes_received_total / 1400; // Approx MTU - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_get_stats: bytes_received_total=%u, estimated_packets=%zu", - etcp->bytes_received_total, *packets_recv); - } - if (pool_allocs || pool_reuse) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_get_stats: getting memory pool stats"); - memory_pool_get_stats(etcp->instance->pkt_pool, pool_allocs, pool_reuse); - if (pool_allocs) DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_get_stats: pool_allocs=%zu", *pool_allocs); - if (pool_reuse) DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_get_stats: pool_reuse=%zu", *pool_reuse); - } -} \ No newline at end of file diff --git a/!/etcp.c_ b/!/etcp.c_ deleted file mode 100755 index e69a21f4..00000000 --- a/!/etcp.c_ +++ /dev/null @@ -1,489 +0,0 @@ -// etcp.c - ETCP Protocol Implementation -#include "../lib/u_async.h" -#include "utun_instance.h" -#include "etcp.h" -#include "../lib/debug_config.h" -#include "../lib/ll_queue.h" -#include "crc32.h" -#include "secure_channel.h" -#include -#include -#include -#include -#include - -// Service packet headers (from protocol, but reset/init handled elsewhere) -#define ETCP_ACK_HEADER 0x01 -#define ETCP_RETRANS_HEADER_BASE 0x10 // 0x10 to 0x2F for retrans requests -#define ETCP_PAYLOAD_HEADER 0x00 -#define ETCP_INIT_RESPONSE 0x03 - -// Forward declarations of internal functions (adapted from etcp_master) -static void retransmit_check(struct ETCP_CONN* etcp); -static void update_metrics(struct ETCP_CONN* etcp, uint16_t rtt); - -static uint16_t timestamp_diff(uint16_t t1, uint16_t t2); -static int id_compare(uint16_t id1, uint16_t id2); -static void retransmit_packet(struct ETCP_CONN* etcp, uint16_t id); - -// Timer callbacks -static void tx_timer_callback(void* arg); -static void retransmit_timer_callback(void* arg); - -// Internal queue callbacks -static void tx_queue_callback(struct ll_queue* q, struct ll_entry* entry, void* arg); -static void schedule_ack_timer(struct ETCP_CONN* etcp); -static void request_retransmission_for_gaps(struct ETCP_CONN* etcp); - -static void queue_clear(struct ll_queue* q) { - struct ll_entry* entry; - while ((entry = queue_entry_get(q)) != NULL) { - queue_entry_free(entry); - } -} - -static void etcp_update_window(struct ETCP_CONN* etcp) { - etcp->window_size = 65536; // Initial window size - etcp->retrans_timer_period = 20; // Default retransmit period -} - -// Reset connection (adapted from etcp_reset in master, without packet sending) -void etcp_conn_reset(struct ETCP_CONN* etcp) { - if (!etcp) return; - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_conn_reset: resetting instance"); - - // Cancel timers - if (etcp->next_tx_timer) { - uasync_cancel_timeout(etcp->instance->ua, etcp->next_tx_timer); - etcp->next_tx_timer = NULL; - } - if (etcp->retransmit_timer) { - uasync_cancel_timeout(etcp->instance->ua, etcp->retransmit_timer); - etcp->retransmit_timer = NULL; - } - - // Clear queues (but keep them) - queue_clear(etcp->input_queue); - queue_clear(etcp->output_queue); - - // Clear lists - rx_packet_t* rx = etcp->rx_list; - while (rx) { - rx_packet_t* next = rx->next; - if (rx->data) free(rx->data); - free(rx); - rx = next; - } - etcp->rx_list = NULL; - - sent_packet_t* sent = etcp->sent_list; - while (sent) { - sent_packet_t* next = sent->next; - if (sent->data) free(sent->data); - free(sent); - sent = next; - } - etcp->sent_list = NULL; - - // Reset metrics and stats - etcp->rtt_last = 0; - etcp->rtt_avg_10 = 0; - etcp->rtt_avg_100 = 0; - etcp->jitter = 0; - etcp->bytes_sent_total = 0; - etcp->retransmissions_count = 0; - etcp->ack_packets_count = 0; - etcp->control_packets_count = 0; - etcp->total_packets_sent = 0; - etcp->unique_packets_sent = 0; - etcp->bytes_received_total = 0; - - // Reset IDs - etcp->next_tx_id = 1; - etcp->last_sent_id = 0; - etcp->last_rx_id = 0; - etcp->last_delivered_id = 0; - - // Reset history - etcp->rtt_history_idx = 0; - etcp->rtt_history_count = 0; - - // Reset pending - etcp->pending_ack_count = 0; - etcp->pending_retransmit_count = 0; - - // Reset window - etcp->unacked_bytes = 0; - etcp->last_acked_id = 0; - etcp->last_rx_ack_id = 0; - etcp->next_retrans_time = 0; - etcp->window_blocked = 0; - - // Reset forward progress - etcp->oldest_missing_id = 0; - etcp->missing_since_time = 0; - - etcp_update_window(etcp); -} - -// Creating ETCP instance -// после создания надо добавить peer bublic key. -struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance) { - if (!instance) return NULL; - - struct ETCP_CONN* etcp = calloc(1, sizeof(struct ETCP_CONN)); - if (!etcp) return NULL; - - etcp->mtu = 1500; // Default MTU - - etcp->instance = instance; - - // Initialize crypto context - if (sc_init_ctx(&etcp->crypto_ctx, &etcp->instance->my_keys) != SC_OK) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "etcp_connection_create: failed to initialize crypto context for node %llu", (unsigned long long)instance->node_id); - free(etcp); - return NULL; - } - - // Initialize queues (tx_queue is input_queue) - etcp->input_queue = queue_new(instance->ua,NULL); - if (!etcp->input_queue) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "etcp_connection_create: failed to create input queue for node %llu", (unsigned long long)instance->node_id); - free(etcp); - return NULL; - } - - etcp->output_queue = queue_new(instance->ua,NULL); - if (!etcp->output_queue) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "etcp_connection_create: failed to create output queue for node %llu", (unsigned long long)instance->node_id); - queue_free(etcp->input_queue); - free(etcp); - return NULL; - } - - // Set callback for input_queue (tx_queue) - queue_set_callback(etcp->input_queue, tx_queue_callback, etcp); - - // Initialize state (from master) - etcp->bandwidth = 10000; // Default: 10000 bytes per timebase (0.1us) - etcp->last_sent_timestamp = get_current_timestamp(); - etcp->bytes_allowed = 0; - - // Reset all other fields to initial state - etcp_conn_reset(etcp); - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_connection_create: created instance with node_id=%llu, mtu=%d", - (unsigned long long)etcp->instance->node_id, etcp->mtu); - - etcp->next=instance->connections; - instance->connections=etcp; - - instance->connections_count++; - - return etcp; -} - -// Destroying ETCP instance -void etcp_connection_close(struct ETCP_CONN* etcp) { - if (!etcp) return; - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_connection_close: destroying instance"); - - // Cancel timers - if (etcp->next_tx_timer) { - uasync_cancel_timeout(etcp->instance->ua, etcp->next_tx_timer); - etcp->next_tx_timer = NULL; - } - if (etcp->retransmit_timer) { - uasync_cancel_timeout(etcp->instance->ua, etcp->retransmit_timer); - etcp->retransmit_timer = NULL; - } - - // Free queues - if (etcp->input_queue) queue_free(etcp->input_queue); - if (etcp->output_queue) queue_free(etcp->output_queue); - - // Free rx_list - rx_packet_t* rx = etcp->rx_list; - while (rx) { - rx_packet_t* next = rx->next; - if (rx->data) free(rx->data); - free(rx); - rx = next; - } - - // Free sent_list - sent_packet_t* sent = etcp->sent_list; - while (sent) { - sent_packet_t* next = sent->next; - if (sent->data) free(sent->data); - free(sent); - sent = next; - } - - free(etcp); -} - -// Process incoming packet (partial, truncated in original) -void etcp_conn_input(struct ETCP_DGRAM* pkt) { - if (!pkt) return; - struct ETCP_CONN* etcp=pkt->link->etcp; - if (!etcp) return; - - uint8_t* data = pkt->data; - size_t len = pkt->data_len; - - if (len < 4) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_conn_input: packet too short (%zu bytes) from node %llu", len, (unsigned long long)etcp->instance->node_id); - return; // Min header - } - - uint16_t id = (data[0] << 8) | data[1]; - uint16_t timestamp = (data[2] << 8) | data[3]; - - // Check for INIT_RESPONSE packet (special control packet) - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[ETCP DEBUG] etcp_conn_input: id=%u, len=%zu, first bytes: %02x %02x %02x %02x %02x", - id, len, data[0], data[1], data[2], data[3], data[4]); - - data += 4; len -= 4; // Skip header for regular packet processing - - int has_payload = 0; - uint8_t* payload_data = NULL; - size_t payload_len = 0; - int is_duplicate = 0; - - while (len > 0) { - uint8_t section_header = *data++; - len--; - - if (section_header == ETCP_ACK_HEADER) { - // ACK section - uint8_t count = *data++; - len--; - for (uint8_t i = 0; i < count; i++) { - uint16_t ack_id = (data[0] << 8) | data[1]; - uint16_t ack_ts = (data[2] << 8) | data[3]; - data += 4; len -= 4; - - // Process ACK: remove from sent_list, update window - sent_packet_t** ptr = &etcp->sent_list; - while (*ptr) { - if ((*ptr)->id == ack_id) { - sent_packet_t* to_free = *ptr; - *ptr = to_free->next; - etcp->unacked_bytes -= to_free->payload_len; - update_metrics(etcp, timestamp_diff(get_current_timestamp(), ack_ts)); - free(to_free->data); - free(to_free); - break; - } - ptr = &(*ptr)->next; - } - } - - // last_delivered and last_rx - uint16_t last_delivered = (data[0] << 8) | data[1]; - uint16_t last_rx = (data[2] << 8) | data[3]; - data += 4; len -= 4; - - etcp->last_rx_ack_id = last_rx; - - } else if ((section_header & 0xF0) == ETCP_RETRANS_HEADER_BASE) { - // Retrans request - uint8_t count = (section_header & 0x0F) + 1; - for (uint8_t i = 0; i < count; i++) { - uint16_t retrans_id = (data[0] << 8) | data[1]; - data += 2; - len -= 2; - - retransmit_packet(etcp, retrans_id); - } - - // last_delivered and last_rx - uint16_t last_delivered = (data[0] << 8) | data[1]; - uint16_t last_rx = (data[2] << 8) | data[3]; - data += 4; len -= 4; - - } else if (section_header == ETCP_PAYLOAD_HEADER) { - // Payload section - has_payload = 1; - payload_data = data; - payload_len = len; - break; // Payload is last - } - } - - // Check for duplicate - rx_packet_t* rx = etcp->rx_list; - while (rx) { - if (rx->id == id) { - is_duplicate = 1; - break; - } - rx = rx->next; - } - - if (is_duplicate) { - // Add to pending ACKs - if (etcp->pending_ack_count < 32) { - etcp->pending_ack_ids[etcp->pending_ack_count] = id; - etcp->pending_ack_timestamps[etcp->pending_ack_count] = timestamp; - etcp->pending_ack_count++; - } - schedule_ack_timer(etcp); - return; - } - - // Insert into rx_list (sorted) - rx_packet_t* new_rx = calloc(1, sizeof(rx_packet_t)); - if (!new_rx) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "etcp_conn_input: failed to allocate memory for rx packet from node %llu", (unsigned long long)etcp->instance->node_id); - return; - } - - new_rx->id = id; - new_rx->timestamp = timestamp; - new_rx->has_payload = has_payload; - if (has_payload) { - new_rx->data = malloc(payload_len); - if (!new_rx->data) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "etcp_conn_input: failed to allocate %zu bytes for payload data from node %llu", payload_len, (unsigned long long)etcp->instance->node_id); - free(new_rx); - return; - } - memcpy(new_rx->data, payload_data, payload_len); - new_rx->data_len = payload_len; - etcp->bytes_received_total += payload_len; - } - - // Insert sorted - rx_packet_t** ptr = &etcp->rx_list; - while (*ptr && id_compare((*ptr)->id, id) < 0) { - ptr = &(*ptr)->next; - } - new_rx->next = *ptr; - *ptr = new_rx; - - // Update last_rx_id - if (id_compare(id, etcp->last_rx_id) > 0) { - etcp->last_rx_id = id; - } - - // Add to pending ACKs - if (etcp->pending_ack_count < 32) { - etcp->pending_ack_ids[etcp->pending_ack_count] = id; - etcp->pending_ack_timestamps[etcp->pending_ack_count] = timestamp; - etcp->pending_ack_count++; - } - - // Request retrans for gaps and deliver contiguous - request_retransmission_for_gaps(etcp); - schedule_ack_timer(etcp); -} - - -// Getting statistics (extended with master stats) -void etcp_get_stats(struct ETCP_CONN* etcp, size_t* packets_sent, size_t* packets_recv, - size_t* pool_allocs, size_t* pool_reuse) { - if (!etcp) return; - - if (packets_sent) *packets_sent = etcp->total_packets_sent; - if (packets_recv) *packets_recv = etcp->bytes_received_total / 100; // Approximate - - if (pool_allocs || pool_reuse) { - memory_pool_get_stats(etcp->instance->pkt_pool, pool_allocs, pool_reuse); - } -} - -// ... (rest of functions from master, adapted to ETCP_CONN and using etcp_link_send for tx) - -// For tx: assume primary channel (etcp->channels), or iterate if multi-path -static void send_etcp_packet(struct ETCP_CONN* etcp, uint8_t* pkt, uint16_t len) { - if (!etcp->links) { - DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "send_etcp_packet: no links available for node %llu", (unsigned long long)etcp->instance->node_id); - return; // No links - } - - // Send to primary link (or iterate for multi-path) - char dg_mem[1600]; - struct ETCP_DGRAM* dg=(struct ETCP_DGRAM*)&dg_mem; - dg->data_len=len; - dg->noencrypt_len=0; - dg->link=etcp->links;// first link TODO: добавить отправку по нескольким линкам - etcp_encrypt_send(dg); -} - -static void update_metrics(struct ETCP_CONN* etcp, uint16_t rtt) { - etcp->rtt_last = rtt; - // Update averages, jitter, etc. - // Placeholder: etcp->rtt_avg_10 = (etcp->rtt_avg_10 * 9 + rtt) / 10; - // etcp->rtt_avg_100 = (etcp->rtt_avg_100 * 99 + rtt) / 100; -} - -uint64_t get_current_time_units() { - struct timeval tv; - gettimeofday(&tv, NULL); - return ((uint64_t)tv.tv_sec * 10000ULL) + (tv.tv_usec / 100); -} - -uint16_t get_current_timestamp() { - return (uint16_t)get_current_time_units(); -} - - -static uint16_t timestamp_diff(uint16_t t1, uint16_t t2) { - if (t1 >= t2) return t1 - t2; - return (0xFFFF - t2) + t1 + 1; // Wrap around -} - -static int id_compare(uint16_t id1, uint16_t id2) { - int16_t diff = id1 - id2; - if (diff == 0) return 0; - return (diff > 0) ? 1 : -1; // Simple for now, add wrap logic if needed -} - -static void retransmit_packet(struct ETCP_CONN* etcp, uint16_t id) { - sent_packet_t* sent = etcp->sent_list; - while (sent) { - if (sent->id == id) { - send_etcp_packet(etcp, sent->data, sent->data_len); - etcp->retransmissions_count++; - break; - } - sent = sent->next; - } -} - -static void tx_queue_callback(struct ll_queue* q, struct ll_entry* entry, void* arg) { - (void)q; - struct ETCP_CONN* etcp = (struct ETCP_CONN*)arg; - // Process entry to send packet - // Placeholder: uint8_t* data = ll_entry_data(entry); - // size_t len = ll_entry_size(entry); - // // Build packet and send - // send_etcp_packet(etcp, data, len); - queue_resume_callback(q); -} - -static void schedule_ack_timer(struct ETCP_CONN* etcp) { - // Placeholder: set timeout to send ACKs -} - -static void request_retransmission_for_gaps(struct ETCP_CONN* etcp) { - // Detect gaps in rx_list and add to pending_retransmit -} - -static void retransmit_check(struct ETCP_CONN* etcp) { - // Check sent_list for timeouts -} - -static void tx_timer_callback(void* arg) { - struct ETCP_CONN* etcp = (struct ETCP_CONN*)arg; - // Handle next tx -} - -static void retransmit_timer_callback(void* arg) { - struct ETCP_CONN* etcp = (struct ETCP_CONN*)arg; - retransmit_check(etcp); -} \ No newline at end of file diff --git a/!/etcp.h b/!/etcp.h deleted file mode 100755 index 03f1444a..00000000 --- a/!/etcp.h +++ /dev/null @@ -1,148 +0,0 @@ -// etcp.h - ETCP Protocol Header (refactored based on etcp_protocol.txt) -#ifndef ETCP_H -#define ETCP_H - -#include "etcp_connections.h" -#include "secure_channel.h" -#include "../lib/ll_queue.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// Forward declarations -struct UTUN_INSTANCE; -struct UASYNC; - -// ETCP packet section types (from protocol spec) -#define ETCP_SECTION_PAYLOAD 0x00 // Data payload -#define ETCP_SECTION_ACK 0x01 // ACK section -#define ETCP_SECTION_RETRANS 0x10 // Retransmission request base (0x10-0x2F) -#define ETCP_SECTION_TIMESTAMP 0x06 // Channel timestamp (example, adjust if needed) -#define ETCP_SECTION_MEAS_TS 0x07 // Measurement timestamp for bandwidth -#define ETCP_SECTION_MEAS_RESP 0x08 // Measurement response - -// Inflight packet states -#define INFLIGHT_STATE_WAIT_ACK 0 -#define INFLIGHT_STATE_WAIT_SEND 1 - -// Inflight packet structure -typedef struct inflight_packet { - struct inflight_packet* next; - uint16_t id; // Packet ID - struct ETCP_LINK* last_link; // Last sent link - uint16_t last_timestamp; // Last send timestamp - uint8_t send_count; // Number of sends - uint8_t retrans_req_count; // Number of retrans requests - uint8_t state; // WAIT_ACK or WAIT_SEND - uint8_t need_retrans; // Flag for forced retrans - uint8_t* data; // Packet data - uint16_t data_len; // Data length - uint16_t payload_len; // Payload length for window -} inflight_packet_t; - -// RX packet for assembly linked list -typedef struct rx_packet { - struct rx_packet* next; - uint16_t id; - uint16_t timestamp; - uint8_t* data; // Assembled data (payload only) - uint16_t data_len; -} rx_packet_t; - -// ETCP connection structure (refactored) -struct ETCP_CONN { - struct ETCP_CONN* next; - int mtu; - - struct UTUN_INSTANCE* instance; - - // Links (channels) - linked list - struct ETCP_LINK* links; - - // Crypto and state - struct secure_channel crypto_ctx; - - // Peer info - uint64_t peer_node_id; // Peer node ID - - // Queues - struct ll_queue* input_queue; // Incoming packets to send - struct ll_queue* output_queue; // Assembled outgoing packets - - // Inflight lists (two lists as per spec) - inflight_packet_t* wait_ack_list; // Waiting for ACK - inflight_packet_t* wait_send_list; // Waiting for send (retrans) - - // RX assembly list - rx_packet_t* rx_list; // Sorted by ID for gap detection - - // IDs and state - uint16_t next_tx_id; // Next TX ID - uint16_t last_rx_id; // Last received ID - uint16_t last_delivered_id; // Last delivered to output_queue - - // Pending ACKs and retrans - uint16_t pending_ack_ids[32]; - uint16_t pending_ack_ts[32]; // Timestamps for ACKs - uint8_t pending_ack_count; - uint16_t pending_retrans_ids[32]; - uint8_t pending_retrans_count; - - // Metrics (RTT, jitter, etc.) - uint16_t rtt_last; - uint16_t rtt_avg_10; - uint16_t rtt_avg_100; - uint16_t jitter; - uint32_t bytes_sent_total; - uint32_t bytes_received_total; - uint32_t retransmissions_count; - - // Window and inflight management - uint32_t unacked_bytes; // Current inflight bytes - uint32_t window_size; // Receive window - uint32_t optimal_inflight; // Sum over links - - // Timers - void* retrans_timer; // Retrans check timer - void* ack_timer; // ACK send timer - - // Bandwidth measurement state - uint8_t burst_in_progress; // Burst transmission flag - uint16_t burst_start_id; // Start ID for burst - // ... (add more for meas_ts, meas_resp) - - // Statistics counters - uint32_t ack_packets_count; // Count of ACK packets received - uint16_t last_rx_ack_id; // Last ACK ID received - uint16_t rtt_history[10]; // RTT history for jitter calculation (RTT_HISTORY_SIZE=10) - uint8_t rtt_history_idx; // Current index in RTT history - uint32_t total_packets_sent; // Total packets sent counter - - // Flags - uint8_t wait_timeout_active; // In wait timeout state -}; - -// Functions -struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance); -void etcp_connection_close(struct ETCP_CONN* etcp); -void etcp_conn_reset(struct ETCP_CONN* etcp); - -// Input from etcp_connections (decrypted packet) -void etcp_conn_input(struct ETCP_DGRAM* pkt); - -// Request next packet for load balancer -struct ETCP_DGRAM* etcp_request_pkt(struct ETCP_CONN* etcp); - -// Get stats -void etcp_get_stats(struct ETCP_CONN* etcp, size_t* packets_sent, size_t* packets_recv, - size_t* pool_allocs, size_t* pool_reuse); - -uint16_t get_current_timestamp(void); - -#ifdef __cplusplus -} -#endif - -#endif // ETCP_H \ No newline at end of file diff --git a/!/etcp_connections.c b/!/etcp_connections.c deleted file mode 100755 index ecec373d..00000000 --- a/!/etcp_connections.c +++ /dev/null @@ -1,846 +0,0 @@ -#include "etcp_connections.h" -#include -#include -#include -#include -#include -#include -#include "routing.h" -#include "utun_instance.h" -#include "utun_test_hooks.h" -#include "config_parser.h" -#include "crc32.h" -#include "etcp.h" -#include "../lib/memory_pool.h" -#include "../lib/u_async.h" -#include "../lib/debug_config.h" -#include - -// Packet dump configuration -#define ETCP_PACKET_DUMP_COMPACT 1 // Use compact single-line format -#define ETCP_PACKET_DUMP_FULL 0 // Use full multi-line format (legacy) -#include - -// Simple debug macros to replace missing debug_config.h -#define DEBUG_CATEGORY_CONNECTION 1 -#define DEBUG_CATEGORY_ETCP 2 -#define DEBUG_CATEGORY_CRYPTO 3 -#define DEBUG_CATEGORY_CONFIG 4 -#define DEBUG_CATEGORY_MEMORY 5 - -// Forward declaration -static void etcp_connections_read_callback(int fd, void* arg); - -// Single-line packet dump for debug output -static void dump_packet_bytes(const char* prefix, const uint8_t* data, size_t len) { - // Build packet data as hex string for single-line output - char hex_buf[513]; // 256 bytes * 2 chars + 1 for null terminator - size_t hex_len = 0; - size_t show_len = (len > 128) ? 128 : len; // Show max 128 bytes - - for (size_t i = 0; i < show_len && hex_len < 512 - 3; i++) { - hex_len += snprintf(hex_buf + hex_len, sizeof(hex_buf) - hex_len, "%02x", data[i]); - if (i < show_len - 1 && (i + 1) % 32 == 0) { // Add space every 32 bytes - hex_len += snprintf(hex_buf + hex_len, sizeof(hex_buf) - hex_len, " "); - } - } - - if (len > 128) { - hex_len += snprintf(hex_buf + hex_len, sizeof(hex_buf) - hex_len, "..."); - } - - // Single-line debug output with packet info - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP] %s: len=%zu hex=%s", prefix, len, hex_buf); - - // Additional debug info for first few bytes - if (len >= 2) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[ETCP] %s: first_bytes=%02x%02x last_bytes=%02x%02x", - prefix, data[0], data[1], data[len-2], data[len-1]); - } -} - -// Compact packet info for high-frequency logging -static void log_packet_compact(const char* prefix, const uint8_t* data, size_t len, struct ETCP_LINK* link) { - if (!data || len == 0) return; - - // Extract packet type from first byte - uint8_t pkt_type = data[0]; - uint16_t timestamp = 0; - - if (len >= 3) { - // Extract timestamp from bytes 1-2 (big endian) - timestamp = (data[1] << 8) | data[2]; - } - - // Single line debug with key packet info - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP] %s: link=%p type=0x%02x ts=%u len=%zu", - prefix, link, pkt_type, timestamp, len); - - // Trace level for detailed hex dump - if (len <= 64) { // Only for small packets to avoid spam - char hex_buf[133]; // 64 bytes * 2 + 1 - size_t hex_len = 0; - for (size_t i = 0; i < len && hex_len < sizeof(hex_buf) - 3; i++) { - hex_len += snprintf(hex_buf + hex_len, sizeof(hex_buf) - hex_len, "%02x", data[i]); - } - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[ETCP] %s: data=%s", prefix, hex_buf); - } -} - -// Unified packet dump function - uses configured format -static void packet_dump(const char* prefix, const uint8_t* data, size_t len, struct ETCP_LINK* link) { - if (!data || len == 0) return; - - #if ETCP_PACKET_DUMP_COMPACT - // Compact single-line format - log_packet_compact(prefix, data, len, link); - #else - // Full multi-line format (legacy) - dump_packet_bytes(prefix, data, len); - #endif -} - -// Legacy multi-line dump for compatibility (kept but not used) -static void dump_packet_bytes_multiline(const char* prefix, const uint8_t* data, size_t len) { - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP DUMP] %s: len=%zu; dump: ", prefix, len); - size_t show = len < 160 ? len : 160; - for (size_t i = 0; i < show; i++) { - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "%02x ", data[i]); - } - if (len > 160) DEBUG_INFO(DEBUG_CATEGORY_ETCP, "..."); - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "\n"); -} - - -// Forward declarations for missing functions -struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance); - -// CONNECTION MANAGEMENT (!!!это всё должно быть static!!!) -static void etcp_link_remove_from_connections(struct ETCP_SOCKET* conn, struct ETCP_LINK* link); - - -// Отправка кодограмм протокола (!!!это всё должно быть static!!!) -static void etcp_link_send_init(struct ETCP_LINK* link); -static int etcp_link_send_reset(struct ETCP_LINK* link); -static void etcp_link_init_timer_cbk(void* arg); - -#define INIT_TIMEOUT_INITIAL 500 -#define INIT_TIMEOUT_MAX 50000 - -static void etcp_link_send_init(struct ETCP_LINK* link) { - if (!link || !link->etcp || !link->etcp->instance) return; - - struct ETCP_DGRAM* dgram = malloc(sizeof(struct ETCP_DGRAM) + 100); - if (!dgram) return; - - dgram->link = link; - dgram->noencrypt_len = SC_PUBKEY_SIZE; - size_t offset = 0; - - dgram->data[offset++] = ETCP_INIT_REQUEST; - - uint64_t node_id = link->etcp->instance->node_id; - dgram->data[offset++] = (node_id >> 56) & 0xFF; - dgram->data[offset++] = (node_id >> 48) & 0xFF; - dgram->data[offset++] = (node_id >> 40) & 0xFF; - dgram->data[offset++] = (node_id >> 32) & 0xFF; - dgram->data[offset++] = (node_id >> 24) & 0xFF; - dgram->data[offset++] = (node_id >> 16) & 0xFF; - dgram->data[offset++] = (node_id >> 8) & 0xFF; - dgram->data[offset++] = node_id & 0xFF; - - dgram->data[offset++] = (link->mtu >> 8) & 0xFF; - dgram->data[offset++] = link->mtu & 0xFF; - - dgram->data[offset++] = (link->keepalive_interval >> 8) & 0xFF; - dgram->data[offset++] = link->keepalive_interval & 0xFF; - - memcpy(dgram->data + offset, link->etcp->instance->my_keys.public_key, SC_PUBKEY_SIZE); - dgram->data_len = offset + SC_PUBKEY_SIZE; - - DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Sending INIT request to link, node_id=%llu, retry=%d", (unsigned long long)node_id, link->init_retry_count); - - // Debug: print remote address before sending - if (link->remote_addr.ss_family == AF_INET) { - struct sockaddr_in* sin = (struct sockaddr_in*)&link->remote_addr; - char addr_str[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &sin->sin_addr, addr_str, INET_ADDRSTRLEN); - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP] INIT sending to %s:%d, link=%p, conn_fd=%d", addr_str, ntohs(sin->sin_port), link, link->conn->fd); - } - - etcp_encrypt_send(dgram); - free(dgram); - - link->init_retry_count++; - - if (!link->init_timer && link->is_server == 0) { - link->init_timeout = INIT_TIMEOUT_INITIAL; - link->init_timer = uasync_set_timeout(link->etcp->instance->ua, link->init_timeout, link, etcp_link_init_timer_cbk); - } else if (link->init_timer) { - if ((link->init_retry_count % 10) == 0 && link->init_timeout < INIT_TIMEOUT_MAX) { - link->init_timeout *= 2; - if (link->init_timeout > INIT_TIMEOUT_MAX) link->init_timeout = INIT_TIMEOUT_MAX; - } - uasync_cancel_timeout(link->etcp->instance->ua, link->init_timer); - link->init_timer = uasync_set_timeout(link->etcp->instance->ua, link->init_timeout, link, etcp_link_init_timer_cbk); - } -} - -static void etcp_link_init_timer_cbk(void* arg) { - struct ETCP_LINK* link = (struct ETCP_LINK*)arg; - if (!link || link->initialized || link->is_server != 0) return; - - link->init_timer = NULL; - etcp_link_send_init(link); -} - -static int etcp_link_send_reset(struct ETCP_LINK* link) { - if (!link) return -1; - - struct ETCP_DGRAM* dgram = malloc(sizeof(struct ETCP_DGRAM) + 1); - if (!dgram) return -1; - - dgram->link = link; - dgram->data_len = 1; - dgram->noencrypt_len = 0; - dgram->data[0] = 0x06; - - DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Sending RESET to link"); - int ret = etcp_encrypt_send(dgram); - free(dgram); - return ret; -} - -static uint32_t sockaddr_hash(struct sockaddr_storage* addr) { - socklen_t addr_len = (addr->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - return crc32_calc((void*)addr, addr_len); - } - -// Бинарный поиск линка по ip_port_hash -static int find_link_index(struct ETCP_SOCKET* e_sock, uint32_t hash) { - if (!e_sock || e_sock->num_channels == 0) return -1; - - int left = 0; - int right = e_sock->num_channels - 1; - - while (left <= right) { - int mid = left + (right - left) / 2; - if (e_sock->links[mid]->ip_port_hash == hash) { - return mid; - } else if (e_sock->links[mid]->ip_port_hash < hash) { - left = mid + 1; - } else { - right = mid - 1; - } - } - - return -(left + 1); -} - -// Реалокация массива линков с увеличением в 2 раза -static int realloc_links(struct ETCP_SOCKET* e_sock) { - size_t new_max = e_sock->max_channels == 0 ? 8 : e_sock->max_channels * 2; - struct ETCP_LINK** new_links = realloc(e_sock->links, new_max * sizeof(struct ETCP_LINK*)); - if (!new_links) return -1; - - e_sock->links = new_links; - e_sock->max_channels = new_max; - return 0; -} - -// Вставка линка в отсортированный массив -static int insert_link(struct ETCP_SOCKET* e_sock, struct ETCP_LINK* link) { - if (!e_sock || !link) return -1; - - if (e_sock->num_channels >= e_sock->max_channels) { - if (realloc_links(e_sock) < 0) return -1; - } - - int idx = find_link_index(e_sock, link->ip_port_hash); - if (idx >= 0) return -1; - - idx = -(idx + 1); - - if (idx < (int)e_sock->num_channels) { - memmove(&e_sock->links[idx + 1], &e_sock->links[idx], - (e_sock->num_channels - idx) * sizeof(struct ETCP_LINK*)); - } - - e_sock->links[idx] = link; - e_sock->num_channels++; - return 0; -} - -// Удаление линка из массива -static void remove_link(struct ETCP_SOCKET* e_sock, uint32_t hash) { - if (!e_sock || e_sock->num_channels == 0) return; - - int idx = find_link_index(e_sock, hash); - if (idx < 0) return; - - if (idx < (int)e_sock->num_channels - 1) { - memmove(&e_sock->links[idx], &e_sock->links[idx + 1], - (e_sock->num_channels - idx - 1) * sizeof(struct ETCP_LINK*)); - } - - e_sock->num_channels--; -} - -// надо править, используй sockaddr_hash -struct ETCP_LINK* etcp_link_find_by_addr(struct ETCP_SOCKET* e_sock, struct sockaddr_storage* addr) { - if (!e_sock || !addr) return NULL; - - int idx = find_link_index(e_sock, sockaddr_hash(addr)); - if (idx < 0) return NULL; - - return e_sock->links[idx]; -} - - -// =============================== - -struct ETCP_SOCKET* etcp_socket_add_ex(struct UTUN_INSTANCE* instance, struct sockaddr_storage* ip, uint32_t netif_index, int so_mark, uint8_t type, uint32_t flags) { - if (!instance) return NULL; - - struct ETCP_SOCKET* e_sock = calloc(1, sizeof(struct ETCP_SOCKET)); - if (!e_sock) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to allocate connection"); - return NULL; - } - - int family = AF_INET; - if (ip) { - family = ip->ss_family; - if (family != AF_INET && family != AF_INET6) { - DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Unsupported address family: %d", family); - free(e_sock); - return NULL; - } - } - - // Use test hook if available and in test mode - if ((flags & UTUN_CREATE_TEST_MODE) && g_utun_test_hooks && g_utun_test_hooks->socket_create_override) { - e_sock->fd = g_utun_test_hooks->socket_create_override(family, SOCK_DGRAM, 0, - g_utun_test_hooks->test_context); - DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Socket creation using test hook: fd=%d", e_sock->fd); - } else { - e_sock->fd = socket(family, SOCK_DGRAM, 0); - } - - if (e_sock->fd < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to create socket: %s", strerror(errno)); - free(e_sock); - return NULL; - } - - int flags_fcntl = fcntl(e_sock->fd, F_GETFL, 0); - fcntl(e_sock->fd, F_SETFL, flags_fcntl | O_NONBLOCK); - - // Set socket mark if specified - if (so_mark > 0) { -#ifdef SO_MARK - if (setsockopt(e_sock->fd, SOL_SOCKET, SO_MARK, &so_mark, sizeof(so_mark)) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to set SO_MARK: %s", strerror(errno)); - } -#endif - } - - // Bind to interface if specified - if (netif_index > 0) { -#ifdef SO_BINDTODEVICE - char ifname[IF_NAMESIZE]; - if (if_indextoname(netif_index, ifname)) { - if (setsockopt(e_sock->fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to bind to interface %s: %s", ifname, strerror(errno)); - } - } -#endif - } - - // Store the local address and bind socket if provided - if (ip) { - memcpy(&e_sock->local_addr, ip, sizeof(struct sockaddr_storage)); - - // Skip binding if requested (for test injection) - if (!(flags & UTUN_CREATE_NO_SOCKET_BIND)) { - // CRITICAL: Actually bind the socket to the address - this was missing! - socklen_t addr_len = (ip->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - if (bind(e_sock->fd, (struct sockaddr*)ip, addr_len) < 0) { - perror("bind"); - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[ETCP] Failed to bind socket to address family %d", ip->ss_family); - if (ip->ss_family == AF_INET) { - struct sockaddr_in* sin = (struct sockaddr_in*)ip; - char addr_str[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &sin->sin_addr, addr_str, INET_ADDRSTRLEN); - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[ETCP] Failed to bind to %s:%d", addr_str, ntohs(sin->sin_port)); - } - close(e_sock->fd); - free(e_sock); - return NULL; - } - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP] Successfully bound socket to local address, family=%d", ip->ss_family); - } else { - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP] Socket binding skipped (NO_SOCKET_BIND flag)"); - } - } - - e_sock->instance = instance; - e_sock->errorcode = 0; - e_sock->pkt_format_errors = 0; - - // Add to instance's socket list - e_sock->next = instance->etcp_sockets; - instance->etcp_sockets = e_sock; - - // Register socket with uasync for receiving packets - e_sock->socket_id = uasync_add_socket(instance->ua, e_sock->fd, - etcp_connections_read_callback, - NULL, NULL, e_sock); - DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Registered ETCP socket with uasync (fd=%d)", e_sock->fd); - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP] Socket %p (fd=%d) registered and active", e_sock, e_sock->fd); - - return e_sock; -} - -void etcp_socket_remove(struct ETCP_SOCKET* conn) { - if (!conn) return; - - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP] Removing socket %p, fd=%d, socket_id=%p", conn, conn->fd, conn->socket_id); - - // Remove from uasync if registered - if (conn->socket_id) { - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP] Removing socket from uasync, instance=%p, ua=%p", conn->instance, conn->instance->ua); - uasync_remove_socket(conn->instance->ua, conn->socket_id); - conn->socket_id = NULL; - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP] Unregistered socket from uasync"); - } - - if (conn->fd >= 0) { - close(conn->fd); - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP] Closed fd=%d", conn->fd); - } - - for (size_t i = 0; i < conn->num_channels; i++) { - etcp_link_close(conn->links[i]); - } - free(conn->links); - - free(conn); -} - - -struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn, struct sockaddr_storage* remote_addr, uint8_t is_server) { - if (!remote_addr) return NULL; - - struct ETCP_LINK* link = calloc(1, sizeof(struct ETCP_LINK)); - if (!link) return NULL; - - link->conn = conn; - link->etcp = etcp; - link->is_server = is_server; - link->mtu = 1500; - link->keepalive_interval = 30; - link->initialized = 0; - link->init_timer = NULL; - link->init_timeout = 0; - link->init_retry_count = 0; - - memcpy(&link->remote_addr, remote_addr, sizeof(struct sockaddr_storage)); - link->last_activity = time(NULL); - - link->ip_port_hash = sockaddr_hash(remote_addr); - - insert_link(conn, link); - - struct ETCP_LINK* l=etcp->links; - while (l && l->next) l=l->next; - if (l) l->next = link; else etcp->links = link; - - if (is_server == 0) { - etcp_link_send_init(link); - } - - return link; -} - -void etcp_link_close(struct ETCP_LINK* link) { - if (!link || !link->etcp) return; - - // Cancel init timer if active - if (link->init_timer) { - uasync_cancel_timeout(link->etcp->instance->ua, link->init_timer); - link->init_timer = NULL; - } - - // универсальное удаление из односвязного списка - struct ETCP_LINK **pp = &link->etcp->links; - while (*pp) { - if (*pp == link) { - *pp = link->next; - break; - } - pp = &(*pp)->next; - } - - remove_link(link->conn, link->ip_port_hash); - - free(link); -} - -int etcp_encrypt_send(struct ETCP_DGRAM* dgram) { -// printf("[ETCP DEBUG] etcp_encrypt_send: ENTERING FUNCTION\n"); - - int errcode=0; - sc_context_t* sc = &dgram->link->etcp->crypto_ctx; - int len=dgram->data_len-dgram->noencrypt_len;// не забываем добавить timestamp (2 bytes) - if (len<=0 || len>1480) { dgram->link->send_errors++; errcode=1; goto es_err; } - uint8_t enc_buf[1600]; - size_t enc_buf_len=0; - dgram->timestamp=get_current_timestamp(); - - // DUMP: Show packet before encryption - packet_dump("ECTP_ENCRYPT_SEND", dgram->data, dgram->data_len, dgram->link); - sc_encrypt(sc, (uint8_t*)&dgram->timestamp/*не править это, тут верно!*/, sizeof(uint16_t) + len, enc_buf, &enc_buf_len); - if (enc_buf_len == 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "etcp_encrypt_send: encryption failed for node %llu", (unsigned long long)dgram->link->etcp->instance->node_id); - dgram->link->send_errors++; - errcode=2; - goto es_err; - } - if (enc_buf_len + dgram->noencrypt_len > 1480) { dgram->link->send_errors++; errcode=2; goto es_err; } - memcpy(enc_buf+enc_buf_len, dgram->data+len, dgram->noencrypt_len); - - // DUMP: Show complete packet before sending -// dump_packet_bytes("READY TO SEND", enc_buf, enc_buf_len + dgram->noencrypt_len); - - struct sockaddr_storage* addr=&dgram->link->remote_addr; - socklen_t addr_len = (addr->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - - // Debug: print where we're sending the packet - if (addr->ss_family == AF_INET) { - struct sockaddr_in* sin = (struct sockaddr_in*)addr; - char addr_str[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &sin->sin_addr, addr_str, INET_ADDRSTRLEN); - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP] Sending packet to %s:%d, size=%zd", addr_str, ntohs(sin->sin_port), enc_buf_len + dgram->noencrypt_len); - } - - ssize_t sent = utun_sendto_hook(dgram->link->conn->fd, enc_buf, enc_buf_len + dgram->noencrypt_len, 0, (struct sockaddr*)addr, addr_len); - if (sent < 0) { dgram->link->send_errors++; errcode=3; goto es_err;} else dgram->link->total_encrypted += sent; - return (int)sent; -es_err: - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[ETCP] encrypt_send error %d", errcode); - return -1; -} - -static void etcp_connections_read_callback(int fd, void* arg) { -// !!!!!! DANGER: в этой функции ПРЕДЕЛЬНАЯ АККУРАТНОСТЬ. Если кажется что не туда указатель то невнимательно аланизировал !!!!! -// НЕ РУИНИТЬ (uint8_t*)&pkt->timestamp - это правильно !!!! -// -// Ошибки функции (errorcode): -// 1 - пакет слишком маленький для init (< SC_PUBKEY_SIZE) -// 2 - не удалось установить peer public key при init -// 3 - не удалось расшифровать init пакет -// 4 - не init пакет (неверный код) -// 5 - коллизия peer ID и ключей -// 6 - не удалось расшифровать обычный пакет -// 13 - переполнение при парсинге пакета -// 46 - расшифрованный пакет слишком маленький (< 3 байта) -// 55 - не удалось создать подключение -// 66 - не удалось создать линк - struct ETCP_SOCKET* e_sock = (struct ETCP_SOCKET*)arg; - if (!e_sock) return; - -// printf("[ETCP] Read callback triggered for fd=%d, socket=%p\n", fd, e_sock); - - struct sockaddr_storage addr; - uint8_t data[PACKET_DATA_SIZE]; - socklen_t addr_len=sizeof(addr); - memset(&addr, 0, sizeof(addr)); - ssize_t recv_len = utun_recvfrom_hook(fd, data, PACKET_DATA_SIZE, 0, (struct sockaddr*)&addr, &addr_len); - - if (recv_len <= 0) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[ETCP] recvfrom failed or no data, recv_len=%zd, errno=%d", recv_len, errno); - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_connections_read_callback: recvfrom failed, error=%zd, errno=%d", recv_len, errno); - return; - } - -// printf("[ETCP] Received packet: %zd bytes from address\n", recv_len); - - // DUMP: Show received packet content - packet_dump("RECV in:", data, recv_len, NULL); // link unknown at this point - - struct ETCP_DGRAM* pkt = memory_pool_alloc(e_sock->instance->pkt_pool); - if (!pkt) return; - size_t pkt_len=0; - int errorcode=0; - - struct ETCP_LINK* link=etcp_link_find_by_addr(e_sock, &addr); -// printf("[ETCP DEBUG] Received packet, link=%p, recv_len=%zd\n", link, recv_len); - if (link==NULL) {// пробуем расшифровать, возможно это init -// printf("[ETCP DEBUG] No existing link found, trying to decrypt as INIT packet\n"); - struct secure_channel sc; - if (recv_len<=SC_PUBKEY_SIZE) { errorcode=1; DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_connections_read_callback: packet too small for init, size=%zd", recv_len); goto ec_fr; } - sc_init_ctx(&sc, &e_sock->instance->my_keys); -// printf("[ETCP DEBUG] Extracting peer public key from position %ld, total packet size=%zd\n", recv_len-SC_PUBKEY_SIZE, recv_len); -// printf("[ETCP DEBUG] Last 64 bytes of packet (PUBKEY): "); - for (int i=0; itimestamp, &pkt_len)) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "etcp_connections_read_callback: failed to decrypt init packet"); - errorcode=3; - goto ec_fr; - } -// printf("[ETCP DEBUG] Decrypt OK\n"); - pkt->data_len=pkt_len-2; - pkt->noencrypt_len=0; - struct { - uint8_t code; - uint8_t id[8]; - uint8_t mtu[2]; - uint8_t keepalive[2]; - uint8_t pubkey[SC_PUBKEY_SIZE]; - } *ack_hdr=(void*)&pkt->data[0]; - uint64_t peer_id; - memcpy(&peer_id, &ack_hdr->id[0], 8); - if (ack_hdr->code!=ETCP_INIT_REQUEST && ack_hdr->code!=ETCP_CHANNEL_INIT) { errorcode=4; DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_connections_read_callback: not an init packet, code=%02x", ack_hdr->code); goto ec_fr; }// не init - - struct ETCP_CONN* conn=e_sock->instance->connections; - while (conn) {// ищем есть ли подключение к этому пиру - if (conn->peer_node_id==peer_id) break; - conn=conn->next; - } - - int new_conn=0; - if (!conn || conn->peer_node_id!=peer_id) {// создаём новое - new_conn=1; - conn=etcp_connection_create(e_sock->instance); - if (!conn) { errorcode=55; DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "etcp_connections_read_callback: failed to create connection"); goto ec_fr; }// облом - memcpy(&conn->crypto_ctx, &sc, sizeof(sc));// добавляем ключ - conn->peer_node_id=peer_id; - } - else {// check keys если существующее подключение - if (memcmp(conn->crypto_ctx.peer_public_key, sc.peer_public_key, SC_PUBKEY_SIZE)) { errorcode=5; DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "etcp_connections_read_callback: peer key mismatch for node %llu", (unsigned long long)peer_id); goto ec_fr; }// коллизия - peer id совпал а ключи разные. - } - struct ETCP_LINK* link = etcp_link_new(conn, e_sock, &addr, 1); - if (!link) { if (new_conn) etcp_connection_close(conn); errorcode=66; DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "etcp_connections_read_callback: failed to create link for connection"); goto ec_fr; }// облом - if (ack_hdr->code==0x02) etcp_conn_reset(conn); - - struct { - uint8_t code; - uint8_t id[8]; - uint8_t mtu[2]; - } *ack_repl_hdr=(void*)&pkt->data[0]; - ack_repl_hdr->code+=1; - memcpy(ack_repl_hdr->id, &e_sock->instance->node_id, 8); - int mtu=e_sock->instance->config->global.mtu; - ack_repl_hdr->mtu[0]=mtu>>8; - ack_repl_hdr->mtu[1]=mtu; - pkt->data_len=sizeof(*ack_repl_hdr); - pkt->noencrypt_len=0; - pkt->link=link; - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP DEBUG] Send INIT RESPONSE"); - etcp_encrypt_send(pkt); -// printf("[ETCP DEBUG] Send INIT RESPONSE ok\n"); - - memory_pool_free(e_sock->instance->pkt_pool, pkt); - return; - } - - if (sc_decrypt(&link->etcp->crypto_ctx, data, recv_len, (uint8_t*)&pkt->timestamp, &pkt_len)) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "etcp_connections_read_callback: failed to decrypt packet from node %llu", (unsigned long long)link->etcp->instance->node_id); - errorcode=6; - goto ec_fr; - } - if (pkt_len<3) { errorcode=46; DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_connections_read_callback: decrypted packet too small, size=%zu", pkt_len); goto ec_fr; } - pkt->data_len=pkt_len-2; - pkt->noencrypt_len=0; - pkt->link=link; - - link->last_recv_local_time=get_current_time_units(); - link->last_recv_timestamp=pkt->timestamp; - - size_t offset = 0; - uint8_t code = pkt->data[offset++]; - - if (code == ETCP_INIT_RESPONSE || code == ETCP_CHANNEL_RESPONSE) { - // Parse response - if (code == ETCP_INIT_RESPONSE) etcp_conn_reset(link->etcp); - uint64_t server_node_id = 0; - for (int i = 0; i < 8; i++) { - server_node_id = (server_node_id << 8) | pkt->data[offset++]; - } - link->mtu = (pkt->data[offset++] << 8) | pkt->data[offset++]; - if (offset > pkt_len) { errorcode=13; DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_connections_read_callback: packet parsing overflow, offset=%zu, pkt_len=%zu", offset, pkt_len); goto ec_fr; } - - DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Received INIT_RESPONSE from server_node_id=%llu, mtu=%d", - (unsigned long long)server_node_id, link->mtu); - - link->etcp->peer_node_id = server_node_id; // If not set - - // Mark link as initialized - link->initialized = 1; - DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[ETCP] Link initialized successfully! Server node_id=%llu, mtu=%d", - (unsigned long long)server_node_id, link->mtu); - - // Cancel init timer if exists - if (link->init_timer) { - uasync_cancel_timeout(link->etcp->instance->ua, link->init_timer); - link->init_timer = NULL; - } - - memory_pool_free(e_sock->instance->pkt_pool, pkt); - return; // INIT_RESPONSE is handled, no further processing needed - } - - packet_dump("RECV decrypted:", pkt->data, pkt->data_len, link); - - etcp_conn_input(pkt); - return; - -ec_fr: - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_connections_read_callback: error %d", errorcode); - e_sock->pkt_format_errors++; - e_sock->errorcode=errorcode; - memory_pool_free(e_sock->instance->pkt_pool, pkt); - return; -} - -int init_connections(struct UTUN_INSTANCE* instance) { - if (!instance || !instance->config) return -1; - - struct utun_config* config = instance->config; - - // Initialize servers first - create sockets for incoming connections - struct CFG_SERVER* server = config->servers; - while (server) { - // Create socket for this server - struct ETCP_SOCKET* e_sock = etcp_socket_add(instance, &server->ip, server->netif_index, server->so_mark, server->type); - if (!e_sock) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create socket for server %s", server->name); - server = server->next; - continue; - } - - // Convert IP to string for logging - char addr_str[INET6_ADDRSTRLEN + 6]; - if (server->ip.ss_family == AF_INET) { - struct sockaddr_in* sin = (struct sockaddr_in*)&server->ip; - inet_ntop(AF_INET, &sin->sin_addr, addr_str, INET_ADDRSTRLEN); - sprintf(addr_str + strlen(addr_str), ":%d", ntohs(sin->sin_port)); - } else { - struct sockaddr_in6* sin6 = (struct sockaddr_in6*)&server->ip; - inet_ntop(AF_INET6, &sin6->sin6_addr, addr_str, INET6_ADDRSTRLEN); - sprintf(addr_str + strlen(addr_str), ":%d", ntohs(sin6->sin6_port)); - } - - DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Initialized server %s on %s (links: %zu)", - server->name, addr_str, e_sock->num_channels); - server = server->next; - } - - // Initialize clients - create outgoing connections - struct CFG_CLIENT* client = config->clients; - while (client) { - // Create ETCP connection for this client - struct ETCP_CONN* etcp_conn = etcp_connection_create(instance); - if (!etcp_conn) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create ETCP connection for client %s", client->name); - client = client->next; - continue; - } - - // Initialize crypto context for this connection - if (sc_init_ctx(&etcp_conn->crypto_ctx, &instance->my_keys) != SC_OK) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "init_connections: failed to initialize crypto context for client %s", client->name); - etcp_connection_close(etcp_conn); - client = client->next; - continue; - } - // If client has peer public key configured, set it - if (strlen(client->peer_public_key_hex) > 0) { - // For now, set peer node ID to indicate we have peer key - // The actual peer key will be exchanged during connection establishment - etcp_conn->peer_node_id = 1; // Simple indicator - - DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "init_connections: setting peer public key for client %s", client->name); - // Set peer public key (assuming hex format) - if (sc_set_peer_public_key(&etcp_conn->crypto_ctx, client->peer_public_key_hex, 1) != SC_OK) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "init_connections: failed to set peer public key for client %s", client->name); - } else { - DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "init_connections: successfully set peer public key for client %s", client->name); - } - } else { - DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "init_connections: no peer public key configured for client %s", client->name); - } - - // Create links for this client - struct CFG_CLIENT_LINK* client_link = client->links; - while (client_link) { - // Find the local server for this link - struct CFG_SERVER* local_server = client_link->local_srv; - if (!local_server) { - client_link = client_link->next; - continue; - } - - // Find the socket for this server - struct ETCP_SOCKET* e_sock = NULL; - struct ETCP_SOCKET* sock = instance->etcp_sockets; - while (sock) { - if (sock->local_addr.ss_family == local_server->ip.ss_family) { - if (sock->local_addr.ss_family == AF_INET) { - struct sockaddr_in* sock_addr = (struct sockaddr_in*)&sock->local_addr; - struct sockaddr_in* srv_addr = (struct sockaddr_in*)&local_server->ip; - if (sock_addr->sin_addr.s_addr == srv_addr->sin_addr.s_addr && - sock_addr->sin_port == srv_addr->sin_port) { - e_sock = sock; - break; - } - } - } - sock = sock->next; - } - - if (!e_sock) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "No socket found for client %s link", client->name); - client_link = client_link->next; - continue; - } - - // Create link for this client connection - struct ETCP_LINK* link = etcp_link_new(etcp_conn, e_sock, &client_link->remote_addr, 0); // 0 = client initiates - if (!link) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create link for client %s", client->name); - client_link = client_link->next; - continue; - } - - client_link = client_link->next; - } - - DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Added client %s with %d links", client->name, client->keepalive); - client = client->next; - } - - // If there are clients configured but no connections created, that's an error - // If there are no clients (server-only mode), 0 connections is OK (server will accept incoming) - if (instance->connections_count == 0 && config->clients != NULL) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Clients configured but no connections initialized"); - return -1; - } - - DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Initialized %d connections", instance->connections_count); - return 0; -} - -// Wrapper for backward compatibility -struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct sockaddr_storage* ip, uint32_t netif_index, int so_mark, uint8_t type) { - return etcp_socket_add_ex(instance, ip, netif_index, so_mark, type, 0); -} diff --git a/!/etcp_connections.c1 b/!/etcp_connections.c1 deleted file mode 100755 index e846871b..00000000 --- a/!/etcp_connections.c1 +++ /dev/null @@ -1,770 +0,0 @@ -#include "etcp_connections.h" -#include -#include -#include -#include -#include -#include -#include "routing.h" -#include "utun_instance.h" -#include "config_parser.h" -#include "crc32.h" -#include "etcp.h" -#include "../lib/memory_pool.h" -#include "../lib/u_async.h" -#include -#include - -// Simple debug macros to replace missing debug_config.h -#define DEBUG_CATEGORY_CONNECTION 1 -#define DEBUG_CATEGORY_ETCP 2 -#define DEBUG_CATEGORY_CRYPTO 3 -#define DEBUG_CATEGORY_CONFIG 4 -#define DEBUG_CATEGORY_MEMORY 5 - -// Forward declaration -static void etcp_connections_read_callback(int fd, void* arg); - -#define DEBUG_ERROR(category, fmt, ...) fprintf(stderr, "ERROR: " fmt "\n", ##__VA_ARGS__) -#define DEBUG_WARN(category, fmt, ...) fprintf(stderr, "WARN: " fmt "\n", ##__VA_ARGS__) -#define DEBUG_INFO(category, fmt, ...) fprintf(stdout, "INFO: " fmt "\n", ##__VA_ARGS__) - -// Minimal packet dump - only shows first 16 bytes to avoid slowing down -static void dump_packet_bytes(const char* prefix, const uint8_t* data, size_t len) { - printf("[ETCP DUMP] %s: len=%zu; dump: ", prefix, len); - size_t show = len < 160 ? len : 160; - for (size_t i = 0; i < show; i++) { - printf("%02x ", data[i]); - } - if (len > 160) printf("..."); - printf("\n"); -} - - -// Forward declarations for missing functions -struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance); - -// CONNECTION MANAGEMENT (!!!это всё должно быть static!!!) -static void etcp_link_remove_from_connections(struct ETCP_SOCKET* conn, struct ETCP_LINK* link); - - -// Отправка кодограмм протокола (!!!это всё должно быть static!!!) -static void etcp_link_send_init(struct ETCP_LINK* link); -static int etcp_link_send_reset(struct ETCP_LINK* link); -static void etcp_link_init_timer_cbk(void* arg); - -#define INIT_TIMEOUT_INITIAL 500 -#define INIT_TIMEOUT_MAX 50000 - -static void etcp_link_send_init(struct ETCP_LINK* link) { - if (!link || !link->etcp || !link->etcp->instance) return; - - struct ETCP_DGRAM* dgram = malloc(sizeof(struct ETCP_DGRAM) + 100); - if (!dgram) return; - - dgram->link = link; - dgram->noencrypt_len = SC_PUBKEY_SIZE; - size_t offset = 0; - - dgram->data[offset++] = ETCP_INIT_REQUEST; - - uint64_t node_id = link->etcp->instance->node_id; - dgram->data[offset++] = (node_id >> 56) & 0xFF; - dgram->data[offset++] = (node_id >> 48) & 0xFF; - dgram->data[offset++] = (node_id >> 40) & 0xFF; - dgram->data[offset++] = (node_id >> 32) & 0xFF; - dgram->data[offset++] = (node_id >> 24) & 0xFF; - dgram->data[offset++] = (node_id >> 16) & 0xFF; - dgram->data[offset++] = (node_id >> 8) & 0xFF; - dgram->data[offset++] = node_id & 0xFF; - - dgram->data[offset++] = (link->mtu >> 8) & 0xFF; - dgram->data[offset++] = link->mtu & 0xFF; - - dgram->data[offset++] = (link->keepalive_interval >> 8) & 0xFF; - dgram->data[offset++] = link->keepalive_interval & 0xFF; - - memcpy(dgram->data + offset, link->etcp->instance->my_keys.public_key, SC_PUBKEY_SIZE); - dgram->data_len = offset + SC_PUBKEY_SIZE; - - DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Sending INIT request to link, node_id=%llu, retry=%d", (unsigned long long)node_id, link->init_retry_count); - - // Debug: print remote address before sending - if (link->remote_addr.ss_family == AF_INET) { - struct sockaddr_in* sin = (struct sockaddr_in*)&link->remote_addr; - char addr_str[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &sin->sin_addr, addr_str, INET_ADDRSTRLEN); - printf("[ETCP] INIT sending to %s:%d, link=%p, conn_fd=%d\n", addr_str, ntohs(sin->sin_port), link, link->conn->fd); - } - - etcp_encrypt_send(dgram); - free(dgram); - - link->init_retry_count++; - - if (!link->init_timer && link->is_server == 0) { - link->init_timeout = INIT_TIMEOUT_INITIAL; - link->init_timer = uasync_set_timeout(link->etcp->instance->ua, link->init_timeout, link, etcp_link_init_timer_cbk); - } else if (link->init_timer) { - if ((link->init_retry_count % 10) == 0 && link->init_timeout < INIT_TIMEOUT_MAX) { - link->init_timeout *= 2; - if (link->init_timeout > INIT_TIMEOUT_MAX) link->init_timeout = INIT_TIMEOUT_MAX; - } - uasync_cancel_timeout(link->etcp->instance->ua, link->init_timer); - link->init_timer = uasync_set_timeout(link->etcp->instance->ua, link->init_timeout, link, etcp_link_init_timer_cbk); - } -} - -static void etcp_link_init_timer_cbk(void* arg) { - struct ETCP_LINK* link = (struct ETCP_LINK*)arg; - if (!link || link->initialized || link->is_server != 0) return; - - link->init_timer = NULL; - etcp_link_send_init(link); -} - -static int etcp_link_send_reset(struct ETCP_LINK* link) { - if (!link) return -1; - - struct ETCP_DGRAM* dgram = malloc(sizeof(struct ETCP_DGRAM) + 1); - if (!dgram) return -1; - - dgram->link = link; - dgram->data_len = 1; - dgram->noencrypt_len = 0; - dgram->data[0] = 0x06; - - DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Sending RESET to link"); - int ret = etcp_encrypt_send(dgram); - free(dgram); - return ret; -} - -static uint32_t sockaddr_hash(struct sockaddr_storage* addr) { - socklen_t addr_len = (addr->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - return crc32_calc((void*)addr, addr_len); - } - -// Бинарный поиск линка по ip_port_hash -static int find_link_index(struct ETCP_SOCKET* e_sock, uint32_t hash) { - if (!e_sock || e_sock->num_channels == 0) return -1; - - int left = 0; - int right = e_sock->num_channels - 1; - - while (left <= right) { - int mid = left + (right - left) / 2; - if (e_sock->links[mid]->ip_port_hash == hash) { - return mid; - } else if (e_sock->links[mid]->ip_port_hash < hash) { - left = mid + 1; - } else { - right = mid - 1; - } - } - - return -(left + 1); -} - -// Реалокация массива линков с увеличением в 2 раза -static int realloc_links(struct ETCP_SOCKET* e_sock) { - size_t new_max = e_sock->max_channels == 0 ? 8 : e_sock->max_channels * 2; - struct ETCP_LINK** new_links = realloc(e_sock->links, new_max * sizeof(struct ETCP_LINK*)); - if (!new_links) return -1; - - e_sock->links = new_links; - e_sock->max_channels = new_max; - return 0; -} - -// Вставка линка в отсортированный массив -static int insert_link(struct ETCP_SOCKET* e_sock, struct ETCP_LINK* link) { - if (!e_sock || !link) return -1; - - if (e_sock->num_channels >= e_sock->max_channels) { - if (realloc_links(e_sock) < 0) return -1; - } - - int idx = find_link_index(e_sock, link->ip_port_hash); - if (idx >= 0) return -1; - - idx = -(idx + 1); - - if (idx < (int)e_sock->num_channels) { - memmove(&e_sock->links[idx + 1], &e_sock->links[idx], - (e_sock->num_channels - idx) * sizeof(struct ETCP_LINK*)); - } - - e_sock->links[idx] = link; - e_sock->num_channels++; - return 0; -} - -// Удаление линка из массива -static void remove_link(struct ETCP_SOCKET* e_sock, uint32_t hash) { - if (!e_sock || e_sock->num_channels == 0) return; - - int idx = find_link_index(e_sock, hash); - if (idx < 0) return; - - if (idx < (int)e_sock->num_channels - 1) { - memmove(&e_sock->links[idx], &e_sock->links[idx + 1], - (e_sock->num_channels - idx - 1) * sizeof(struct ETCP_LINK*)); - } - - e_sock->num_channels--; -} - -// надо править, используй sockaddr_hash -struct ETCP_LINK* etcp_link_find_by_addr(struct ETCP_SOCKET* e_sock, struct sockaddr_storage* addr) { - if (!e_sock || !addr) return NULL; - - int idx = find_link_index(e_sock, sockaddr_hash(addr)); - if (idx < 0) return NULL; - - return e_sock->links[idx]; -} - - -// =============================== - -struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct sockaddr_storage* ip, uint32_t netif_index, int so_mark, uint8_t type) { - if (!instance) return NULL; - - struct ETCP_SOCKET* e_sock = calloc(1, sizeof(struct ETCP_SOCKET)); - if (!e_sock) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to allocate connection"); - return NULL; - } - - int family = AF_INET; - if (ip) { - family = ip->ss_family; - if (family != AF_INET && family != AF_INET6) { - DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Unsupported address family: %d", family); - free(e_sock); - return NULL; - } - } - - e_sock->fd = socket(family, SOCK_DGRAM, 0); - if (e_sock->fd < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to create socket: %s", strerror(errno)); - free(e_sock); - return NULL; - } - - int flags = fcntl(e_sock->fd, F_GETFL, 0); - fcntl(e_sock->fd, F_SETFL, flags | O_NONBLOCK); - - // Set socket mark if specified - if (so_mark > 0) { -#ifdef SO_MARK - if (setsockopt(e_sock->fd, SOL_SOCKET, SO_MARK, &so_mark, sizeof(so_mark)) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to set SO_MARK: %s", strerror(errno)); - } -#endif - } - - // Bind to interface if specified - if (netif_index > 0) { -#ifdef SO_BINDTODEVICE - char ifname[IF_NAMESIZE]; - if (if_indextoname(netif_index, ifname)) { - if (setsockopt(e_sock->fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to bind to interface %s: %s", ifname, strerror(errno)); - } - } -#endif - } - - // Store the local address and bind socket if provided - if (ip) { - memcpy(&e_sock->local_addr, ip, sizeof(struct sockaddr_storage)); - - // CRITICAL: Actually bind the socket to the address - this was missing! - socklen_t addr_len = (ip->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - if (bind(e_sock->fd, (struct sockaddr*)ip, addr_len) < 0) { - perror("bind"); - printf("[ETCP] Failed to bind socket to address family %d\n", ip->ss_family); - if (ip->ss_family == AF_INET) { - struct sockaddr_in* sin = (struct sockaddr_in*)ip; - char addr_str[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &sin->sin_addr, addr_str, INET_ADDRSTRLEN); - printf("[ETCP] Failed to bind to %s:%d\n", addr_str, ntohs(sin->sin_port)); - } - close(e_sock->fd); - free(e_sock); - return NULL; - } - - printf("[ETCP] Successfully bound socket to local address, family=%d\n", ip->ss_family); - } - - e_sock->instance = instance; - e_sock->errorcode = 0; - e_sock->pkt_format_errors = 0; - - // Add to instance's socket list - e_sock->next = instance->etcp_sockets; - instance->etcp_sockets = e_sock; - - // Register socket with uasync for receiving packets - e_sock->socket_id = uasync_add_socket(instance->ua, e_sock->fd, - etcp_connections_read_callback, - NULL, NULL, e_sock); - DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Registered ETCP socket with uasync (fd=%d)", e_sock->fd); - - printf("[ETCP] Socket %p (fd=%d) registered and active\n", e_sock, e_sock->fd); - - return e_sock; -} - -void etcp_socket_remove(struct ETCP_SOCKET* conn) { - if (!conn) return; - - printf("[ETCP] Removing socket %p, fd=%d\n", conn, conn->fd); - - if (conn->fd >= 0) { - close(conn->fd); - printf("[ETCP] Closed fd=%d\n", conn->fd); - } - - for (size_t i = 0; i < conn->num_channels; i++) { - etcp_link_close(conn->links[i]); - } - free(conn->links); - - free(conn); -} - - -struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn, struct sockaddr_storage* remote_addr, uint8_t is_server) { - if (!remote_addr) return NULL; - - struct ETCP_LINK* link = calloc(1, sizeof(struct ETCP_LINK)); - if (!link) return NULL; - - link->conn = conn; - link->etcp = etcp; - link->is_server = is_server; - link->mtu = 1500; - link->keepalive_interval = 30; - link->initialized = 0; - link->init_timer = NULL; - link->init_timeout = 0; - link->init_retry_count = 0; - - memcpy(&link->remote_addr, remote_addr, sizeof(struct sockaddr_storage)); - link->last_activity = time(NULL); - - link->ip_port_hash = sockaddr_hash(remote_addr); - - insert_link(conn, link); - - struct ETCP_LINK* l=etcp->links; - while (l && l->next) l=l->next; - if (l) l->next = link; else etcp->links = link; - - if (is_server == 0) { - etcp_link_send_init(link); - } - - return link; -} - -void etcp_link_close(struct ETCP_LINK* link) { - if (!link || !link->etcp) return; - - // Cancel init timer if active - if (link->init_timer) { - uasync_cancel_timeout(link->etcp->instance->ua, link->init_timer); - link->init_timer = NULL; - } - - // универсальное удаление из односвязного списка - struct ETCP_LINK **pp = &link->etcp->links; - while (*pp) { - if (*pp == link) { - *pp = link->next; - break; - } - pp = &(*pp)->next; - } - - remove_link(link->conn, link->ip_port_hash); - - free(link); -} - -int etcp_encrypt_send(struct ETCP_DGRAM* dgram) { -// printf("[ETCP DEBUG] etcp_encrypt_send: ENTERING FUNCTION\n"); - - int errcode=0; - sc_context_t* sc = &dgram->link->etcp->crypto_ctx; - int len=dgram->data_len-dgram->noencrypt_len;// не забываем добавить timestamp (2 bytes) - if (len<=0 || len>1480) { dgram->link->send_errors++; errcode=1; goto es_err; } - uint8_t enc_buf[1600]; - size_t enc_buf_len=0; - dgram->timestamp=get_current_timestamp(); - - // DUMP: Show packet before encryption - dump_packet_bytes("ECTP_ENCRYPT_SEND", dgram->data, dgram->data_len); - sc_encrypt(sc, (uint8_t*)&dgram->timestamp/*нейронка не правь блять это, тут верно!*/, sizeof(uint16_t) + len, enc_buf, &enc_buf_len); - if (enc_buf_len == 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "etcp_encrypt_send: encryption failed for node %llu", (unsigned long long)dgram->link->etcp->instance->node_id); - dgram->link->send_errors++; - errcode=2; - goto es_err; - } - if (enc_buf_len + dgram->noencrypt_len > 1480) { dgram->link->send_errors++; errcode=2; goto es_err; } - memcpy(enc_buf+enc_buf_len, dgram->data+len, dgram->noencrypt_len); - - // DUMP: Show complete packet before sending -// dump_packet_bytes("READY TO SEND", enc_buf, enc_buf_len + dgram->noencrypt_len); - - struct sockaddr_storage* addr=&dgram->link->remote_addr; - socklen_t addr_len = (addr->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - - // Debug: print where we're sending the packet - if (addr->ss_family == AF_INET) { - struct sockaddr_in* sin = (struct sockaddr_in*)addr; - char addr_str[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &sin->sin_addr, addr_str, INET_ADDRSTRLEN); - printf("[ETCP] Sending packet to %s:%d, size=%zd\n", addr_str, ntohs(sin->sin_port), enc_buf_len + dgram->noencrypt_len); - } - - ssize_t sent = sendto(dgram->link->conn->fd, enc_buf, enc_buf_len + dgram->noencrypt_len, 0, (struct sockaddr*)addr, addr_len); - if (sent < 0) { dgram->link->send_errors++; errcode=3; goto es_err;} else dgram->link->total_encrypted += sent; - return (int)sent; -es_err: - printf("[ETCP] encrypt_send error %d\n", errcode); - return -1; -} - -static void etcp_connections_read_callback(int fd, void* arg) { -// !!!!!! DANGER: в этой функции ПРЕДЕЛЬНАЯ АККУРАТНОСТЬ. Если кажется что не туда указатель то невнимательно аланизировал !!!!! -// НЕ РУИНИТЬ (uint8_t*)&pkt->timestamp - это правильно !!!! - struct ETCP_SOCKET* e_sock = (struct ETCP_SOCKET*)arg; - if (!e_sock) return; - -// printf("[ETCP] Read callback triggered for fd=%d, socket=%p\n", fd, e_sock); - - struct sockaddr_storage addr; - uint8_t data[PACKET_DATA_SIZE]; - socklen_t addr_len=sizeof(addr); - memset(&addr, 0, sizeof(addr)); - ssize_t recv_len = recvfrom(fd, data, PACKET_DATA_SIZE, 0, (struct sockaddr*)&addr, &addr_len); - - if (recv_len <= 0) { - printf("[ETCP] recvfrom failed or no data, recv_len=%zd, errno=%d\n", recv_len, errno); - return; - } - -// printf("[ETCP] Received packet: %zd bytes from address\n", recv_len); - - // DUMP: Show received packet content - dump_packet_bytes("RECV in:", data, recv_len); - - struct ETCP_DGRAM* pkt = memory_pool_alloc(e_sock->instance->pkt_pool); - if (!pkt) return; - size_t pkt_len=0; - int errorcode=0; - - struct ETCP_LINK* link=etcp_link_find_by_addr(e_sock, &addr); -// printf("[ETCP DEBUG] Received packet, link=%p, recv_len=%zd\n", link, recv_len); - if (link==NULL) {// пробуем расшифровать, возможно это init -// printf("[ETCP DEBUG] No existing link found, trying to decrypt as INIT packet\n"); - struct secure_channel sc; - if (recv_len<=SC_PUBKEY_SIZE) { errorcode=1; goto ec_fr; } - sc_init_ctx(&sc, &e_sock->instance->my_keys); -// printf("[ETCP DEBUG] Extracting peer public key from position %ld, total packet size=%zd\n", recv_len-SC_PUBKEY_SIZE, recv_len); -// printf("[ETCP DEBUG] Last 64 bytes of packet (PUBKEY): "); - for (int i=0; itimestamp, &pkt_len)) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "etcp_connections_read_callback: failed to decrypt init packet"); - errorcode=3; - goto ec_fr; - } -// printf("[ETCP DEBUG] Decrypt OK\n"); - pkt->data_len=pkt_len-2; - pkt->noencrypt_len=0; - struct { - uint8_t code; - uint8_t id[8]; - uint8_t mtu[2]; - uint8_t keepalive[2]; - uint8_t pubkey[SC_PUBKEY_SIZE]; - } *ack_hdr=(void*)&pkt->data[0]; - uint64_t peer_id; - memcpy(&peer_id, &ack_hdr->id[0], 8); - if (ack_hdr->code!=ETCP_INIT_REQUEST && ack_hdr->code!=ETCP_CHANNEL_INIT) { errorcode=4; goto ec_fr; }// не init - - struct ETCP_CONN* conn=e_sock->instance->connections; - while (conn) {// ищем есть ли подключение к этому пиру - if (conn->peer_node_id==peer_id) break; - conn=conn->next; - } - - int new_conn=0; - if (!conn || conn->peer_node_id!=peer_id) {// создаём новое - new_conn=1; - conn=etcp_connection_create(e_sock->instance); - if (!conn) { errorcode=55; goto ec_fr; }// облом - memcpy(&conn->crypto_ctx, &sc, sizeof(sc));// добавляем ключ - conn->peer_node_id=peer_id; - } - else {// check keys если существующее подключение - if (memcmp(conn->crypto_ctx.peer_public_key, sc.peer_public_key, SC_PUBKEY_SIZE)) { errorcode=5; goto ec_fr; }// коллизия - peer id совпал а ключи разные. - } - struct ETCP_LINK* link = etcp_link_new(conn, e_sock, &addr, 1); - if (!link) { if (new_conn) etcp_connection_close(conn); errorcode=66; goto ec_fr; }// облом - if (ack_hdr->code==0x02) etcp_conn_reset(conn); - - struct { - uint8_t code; - uint8_t id[8]; - uint8_t mtu[2]; - } *ack_repl_hdr=(void*)&pkt->data[0]; - ack_repl_hdr->code+=1; - memcpy(ack_repl_hdr->id, &e_sock->instance->node_id, 8); - int mtu=e_sock->instance->config->global.mtu; - ack_repl_hdr->mtu[0]=mtu>>8; - ack_repl_hdr->mtu[1]=mtu; - pkt->data_len=sizeof(*ack_repl_hdr); - pkt->noencrypt_len=0; - pkt->link=link; - printf("[ETCP DEBUG] Send INIT RESPONSE\n"); - etcp_encrypt_send(pkt); -// printf("[ETCP DEBUG] Send INIT RESPONSE ok\n"); - - memory_pool_free(e_sock->instance->pkt_pool, pkt); - return; - } - - if (sc_decrypt(&link->etcp->crypto_ctx, data, recv_len, (uint8_t*)&pkt->timestamp, &pkt_len)) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "etcp_connections_read_callback: failed to decrypt packet from node %llu", (unsigned long long)link->etcp->instance->node_id); - errorcode=6; - goto ec_fr; - } - if (pkt_len<3) { errorcode=46; goto ec_fr; } - pkt->data_len=pkt_len-2; - pkt->noencrypt_len=0; - pkt->link=link; - - link->last_recv_local_time=get_current_time_units(); - link->last_recv_timestamp=pkt->timestamp; - - size_t offset = 0; - uint8_t code = pkt->data[offset++]; - - if (code == ETCP_INIT_RESPONSE || code == ETCP_CHANNEL_RESPONSE) { - // Parse response - if (code == ETCP_INIT_RESPONSE) etcp_conn_reset(link->etcp); - uint64_t server_node_id = 0; - for (int i = 0; i < 8; i++) { - server_node_id = (server_node_id << 8) | pkt->data[offset++]; - } - link->mtu = (pkt->data[offset++] << 8) | pkt->data[offset++]; - if (offset > pkt_len) { errorcode=13; goto ec_fr; } - - DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Received INIT_RESPONSE from server_node_id=%llu, mtu=%d", - (unsigned long long)server_node_id, link->mtu); - - link->etcp->peer_node_id = server_node_id; // If not set - - // Mark link as initialized - link->initialized = 1; - printf("[ETCP] Link initialized successfully! Server node_id=%llu, mtu=%d\n", - (unsigned long long)server_node_id, link->mtu); - - // Cancel init timer if exists - if (link->init_timer) { - uasync_cancel_timeout(link->etcp->instance->ua, link->init_timer); - link->init_timer = NULL; - } - - memory_pool_free(e_sock->instance->pkt_pool, pkt); - return; // INIT_RESPONSE is handled, no further processing needed - } - - dump_packet_bytes("RECV decrypted:", pkt->data, pkt->data_len); - - etcp_conn_input(pkt); - return; - -ec_fr: - printf("etcp_connections_read_callback: error %d\n", errorcode); - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "etcp_connections_read_callback: error %d", errorcode); - e_sock->pkt_format_errors++; - e_sock->errorcode=errorcode; - memory_pool_free(e_sock->instance->pkt_pool, pkt); - return; -} - -int init_connections(struct UTUN_INSTANCE* instance) { - if (!instance || !instance->config) return -1; - - struct utun_config* config = instance->config; - - // Initialize servers first - create sockets for incoming connections - struct CFG_SERVER* server = config->servers; - while (server) { - // Create socket for this server - struct ETCP_SOCKET* e_sock = etcp_socket_add(instance, &server->ip, server->netif_index, server->so_mark, server->type); - if (!e_sock) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create socket for server %s", server->name); - server = server->next; - continue; - } - - // Convert IP to string for logging - char addr_str[INET6_ADDRSTRLEN + 6]; - if (server->ip.ss_family == AF_INET) { - struct sockaddr_in* sin = (struct sockaddr_in*)&server->ip; - inet_ntop(AF_INET, &sin->sin_addr, addr_str, INET_ADDRSTRLEN); - sprintf(addr_str + strlen(addr_str), ":%d", ntohs(sin->sin_port)); - } else { - struct sockaddr_in6* sin6 = (struct sockaddr_in6*)&server->ip; - inet_ntop(AF_INET6, &sin6->sin6_addr, addr_str, INET6_ADDRSTRLEN); - sprintf(addr_str + strlen(addr_str), ":%d", ntohs(sin6->sin6_port)); - } - - printf("Initialized server %s on %s (links: %zu)\n", - server->name, addr_str, e_sock->num_channels); - server = server->next; - } - - // Initialize clients - create outgoing connections - struct CFG_CLIENT* client = config->clients; - while (client) { - // Create ETCP connection for this client - struct ETCP_CONN* etcp_conn = etcp_connection_create(instance); - if (!etcp_conn) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create ETCP connection for client %s", client->name); - client = client->next; - continue; - } - - // Initialize crypto context for this connection - if (sc_init_ctx(&etcp_conn->crypto_ctx, &instance->my_keys) != SC_OK) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "init_connections: failed to initialize crypto context for client %s", client->name); - etcp_connection_close(etcp_conn); - client = client->next; - continue; - } - // If client has peer public key configured, set it - if (strlen(client->peer_public_key_hex) > 0) { - // For now, set peer node ID to indicate we have peer key - // The actual peer key will be exchanged during connection establishment - etcp_conn->peer_node_id = 1; // Simple indicator - - DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "init_connections: setting peer public key for client %s", client->name); - // Set peer public key (assuming hex format) - if (sc_set_peer_public_key(&etcp_conn->crypto_ctx, client->peer_public_key_hex, 1) != SC_OK) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "init_connections: failed to set peer public key for client %s", client->name); - } else { - DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "init_connections: successfully set peer public key for client %s", client->name); - } - } else { - DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "init_connections: no peer public key configured for client %s", client->name); - } - - // Create links for this client - struct CFG_CLIENT_LINK* client_link = client->links; - while (client_link) { - // Find the local server for this link - struct CFG_SERVER* local_server = client_link->local_srv; - if (!local_server) { - client_link = client_link->next; - continue; - } - - // Find the socket for this server - struct ETCP_SOCKET* e_sock = NULL; - struct ETCP_SOCKET* sock = instance->etcp_sockets; - while (sock) { - if (sock->local_addr.ss_family == local_server->ip.ss_family) { - if (sock->local_addr.ss_family == AF_INET) { - struct sockaddr_in* sock_addr = (struct sockaddr_in*)&sock->local_addr; - struct sockaddr_in* srv_addr = (struct sockaddr_in*)&local_server->ip; - if (sock_addr->sin_addr.s_addr == srv_addr->sin_addr.s_addr && - sock_addr->sin_port == srv_addr->sin_port) { - e_sock = sock; - break; - } - } - } - sock = sock->next; - } - - if (!e_sock) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "No socket found for client %s link", client->name); - client_link = client_link->next; - continue; - } - - // Create link for this client connection - struct ETCP_LINK* link = etcp_link_new(etcp_conn, e_sock, &client_link->remote_addr, 0); // 0 = client initiates - if (!link) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create link for client %s", client->name); - client_link = client_link->next; - continue; - } - - client_link = client_link->next; - } - - printf("Added client %s with %d links\n", client->name, client->keepalive); - client = client->next; - } - - // If there are clients configured but no connections created, that's an error - // If there are no clients (server-only mode), 0 connections is OK (server will accept incoming) - if (instance->connections_count == 0 && config->clients != NULL) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Clients configured but no connections initialized"); - return -1; - } - - printf("Initialized %d connections\n", instance->connections_count); - return 0; -} - -int etcp_connections_send(struct ETCP_SOCKET* e_sock, uint8_t* data, size_t len, struct sockaddr* addr, socklen_t addr_len) { - if (!e_sock || !data || !addr || len == 0) return -1; - - struct sockaddr_storage remote_addr; - memcpy(&remote_addr, addr, addr_len); - - struct ETCP_LINK* link = etcp_link_find_by_addr(e_sock, &remote_addr); - if (!link) { - DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "No link found for address"); - return -1; - } - - if (!link->initialized && link->is_server == 0) { - DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Link not initialized, triggering connection establishment"); - if (!link->init_timer) { - etcp_link_send_init(link); - } - return -1; - } - - struct ETCP_DGRAM* dgram = malloc(sizeof(struct ETCP_DGRAM) + len); - if (!dgram) return -1; - - dgram->link = link; - dgram->data_len = len; - dgram->noencrypt_len = 0; - memcpy(dgram->data, data, len); - - int ret = etcp_encrypt_send(dgram); - free(dgram); - return ret; -} diff --git a/!/etcp_connections.h b/!/etcp_connections.h deleted file mode 100755 index 54fa4f71..00000000 --- a/!/etcp_connections.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef ETCP_CONNECTIONS_H -#define ETCP_CONNECTIONS_H - -// подмодуль ETCP который обслуживает сокеты ETCP для приёма-передачи пакетов и одно ETCP подключение через несколько каналов связи (failover) - -#include "secure_channel.h" -#include "utun_instance.h" -#include -#include - -#define PACKET_DATA_SIZE 1536 - -// Типы кодограмм протокола -#define ETCP_INIT_REQUEST 0x02 -#define ETCP_INIT_RESPONSE 0x03 -#define ETCP_CHANNEL_INIT 0x04 -#define ETCP_CHANNEL_RESPONSE 0x05 - - -struct ETCP_DGRAM {// пакет (незашифрованный) - struct ETCP_LINK* link;// откуда получена или куда отправялем - uint16_t data_len;// общий размер пакета не включая timestamp - uint16_t noencrypt_len;// число байт (с конца) которые не надо шифровать. для передачи pubkey - uint16_t timestamp;// timestamp принятого или для отправки - uint8_t data[0];// данные пакета (без timestamp) -}; - -// список активных подключений которые обслуживает сокет. каждый сокет может обслуживать много подключений -struct ETCP_SOCKET { - struct ETCP_SOCKET* next; // Linked list для всех соединений - struct UTUN_INSTANCE* instance; - int fd; // Файловый дескриптор UDP сокета - struct sockaddr_storage local_addr; // Локальный адрес - - // для входящих подключений (links) - массив упорядоченный по ip_port_hash - size_t max_channels; // сколько выделено памяти - size_t num_channels; // сколько активно - struct ETCP_LINK** links;// массив указателей на линки, сортированный по ip_port_hash - int errorcode; - size_t pkt_format_errors; - - void* socket_id; // Socket ID from uasync_add_socket -}; - -// ETCP Link - одно динамическое соединение (один путь) -struct ETCP_LINK { - uint32_t ip_port_hash; // crc32 для быстрого поиска - struct ETCP_LINK* next; // Linked list подключений для ETCP_CONN (каждое подключение это child для ETCP_CONN) - - struct ETCP_CONN* etcp; // подключение (parent) - struct ETCP_SOCKET* conn; // сокет через который работаем - - // Путь соединения - struct sockaddr_storage remote_addr; // Удалённый адрес - - // Параметры соединения - uint16_t mtu; // MTU удаленного узла - uint16_t keepalive_interval; // Keepalive интервал - uint8_t is_server; // инициирует подключение клиент - uint8_t initialized; // Флаг инициализации (1=подтверждено или получен request) - - // Состояние установки соединения (только для клиентов) - void* init_timer; // Таймер для повторов INIT (NULL=не подключается) - uint16_t init_timeout; // Текущий таймаут в мс - uint16_t init_retry_count; // Счетчик попыток - - uint64_t last_activity; // Время последней активности - uint64_t last_recv_local_time; - uint16_t last_recv_timestamp; - - size_t encrypt_errors; - size_t decrypt_errors; - size_t send_errors; - size_t recv_errors; - size_t total_encrypted; - size_t total_decrypted; - - uint32_t bandwidth; // Link bandwidth in bits/sec -}; - -// INITIALIZATION (создаёт listen-сокеты и подключения из конфига) -int init_connections(struct UTUN_INSTANCE* instance); - -// SOCKET FUNCTIONS -// добавляет новый версер (сокет для приёма и отправки кодограмм. обслуживает много подключений) -struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct sockaddr_storage* ip, uint32_t netif_index, int so_mark, uint8_t type); -struct ETCP_SOCKET* etcp_socket_add_ex(struct UTUN_INSTANCE* instance, struct sockaddr_storage* ip, uint32_t netif_index, int so_mark, uint8_t type, uint32_t flags); -// удаляет сокет и освобождает ресурсы (грохает все его подключения и сокет) -void etcp_socket_remove(struct ETCP_SOCKET* conn); - -// connection functions -// создает новый канал связи для etcp подключения (ETCP_CONN) -struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn, struct sockaddr_storage* remote_addr, uint8_t is_server); -void etcp_link_close(struct ETCP_LINK* link); -//int etcp_input_cbk(struct packet_buffer* pkt, struct ETCP_SOCKET* conn);// получает расшифрованный пакет -int etcp_encrypt_send(struct ETCP_DGRAM* dgram);// зашифровывает и отправляет пакет -// find link by address -struct ETCP_LINK* etcp_link_find_by_addr(struct ETCP_SOCKET* e_sock, struct sockaddr_storage* addr); - -#endif // ETCP_CONNECTIONS_H diff --git a/!/etcp_loadbalancer.c b/!/etcp_loadbalancer.c deleted file mode 100755 index 7e0e16c5..00000000 --- a/!/etcp_loadbalancer.c +++ /dev/null @@ -1,164 +0,0 @@ -// etcp_loadbalancer.c - Load Balancer Implementation (based on etcp_protocol.txt) -#include "etcp_loadbalancer.h" -#include "../lib/debug_config.h" -#include "../lib/u_async.h" -#include - -// Enable comprehensive debug output for loadbalancer module -#define DEBUG_CATEGORY_LOADBALANCER 1 - -// Forward declaration -static void init_timeout_cb(void* arg); - -// Constants -#define TIMEBASE_NS 100000 // 0.1ms = 100us = 100000ns -#define DELTA_TIME_NS 10000 // Example delta - -// Internal -static uint64_t get_current_nanotime() { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - uint64_t nanotime = (uint64_t)ts.tv_sec * 1000000000ULL + ts.tv_nsec; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "get_current_nanotime: tv_sec=%ld, tv_nsec=%ld, result=%llu", - ts.tv_sec, ts.tv_nsec, (unsigned long long)nanotime); - return nanotime; -} - -// Select link for transmission (per spec) -struct ETCP_LINK* etcp_loadbalancer_select_link(struct ETCP_CONN* etcp) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_select_link: etcp=%p", etcp); - - if (!etcp || !etcp->links) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_select_link: invalid parameters (etcp=%p, links=%p)", - etcp, etcp ? etcp->links : NULL); - return NULL; - } - - struct ETCP_LINK* best = NULL; - uint64_t min_load_time = UINT64_MAX; - uint64_t now_ns = get_current_nanotime(); - uint64_t now_tb = now_ns / (TIMEBASE_NS / 10); // To 0.1ms units - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_select_link: current time=%llu tb, scanning %d links", - (unsigned long long)now_tb, etcp->links ? 1 : 0); - - struct ETCP_LINK* link = etcp->links; - int link_index = 0; - while (link) { - link_index++; - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_select_link: evaluating link %d (%p) - initialized=%u, is_server=%u, bandwidth=%u", - link_index, link, link->initialized, link->is_server, link->bandwidth); - - if (!link->initialized) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_select_link: link %d not initialized, checking if client connection needed", - link_index); - // Initiate connection if client - if (!link->is_server && !link->init_timer) { - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_select_link: initiating client connection for link %d", link_index); - // Send INIT (via etcp_encrypt_send with special dgram) - // Set timer - link->init_timer = uasync_set_timeout(etcp->instance->ua, link->init_timeout, link, init_timeout_cb); // Define cb - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_select_link: set init timer for link %d", link_index); - } - link = link->next; - continue; - } - - // Update load time if inactive - if (link->last_activity < now_tb - (DELTA_TIME_NS / (TIMEBASE_NS / 10))) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_select_link: link %d inactive, updating last_activity from %llu to %llu", - link_index, (unsigned long long)link->last_activity, - (unsigned long long)(now_tb - (DELTA_TIME_NS / (TIMEBASE_NS / 10)))); - link->last_activity = now_tb - (DELTA_TIME_NS / (TIMEBASE_NS / 10)); - } - - // Check if can send (load time < now) - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_select_link: link %d last_activity=%llu, now_tb=%llu", - link_index, (unsigned long long)link->last_activity, (unsigned long long)now_tb); - - if (link->last_activity < now_tb) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_select_link: link %d can send (load_time < now)", link_index); - if (link->last_activity < min_load_time) { - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_select_link: link %d is better candidate (activity=%llu < %llu)", - link_index, (unsigned long long)link->last_activity, (unsigned long long)min_load_time); - min_load_time = link->last_activity; - best = link; - } - } else { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_select_link: link %d cannot send yet (load_time >= now)", link_index); - } - - link = link->next; - } - - if (best) { - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_select_link: selected link %p (activity=%llu)", - best, (unsigned long long)min_load_time); - } else { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_select_link: no suitable link found"); - } - - return best; -} - -// Init timeout callback (placeholder) -static void init_timeout_cb(void* arg) { - struct ETCP_LINK* link = (struct ETCP_LINK*)arg; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "init_timeout_cb: link=%p, retry_count=%u, timeout=%u", - link, link->init_retry_count, link->init_timeout); - - // Resend INIT, increment retry - link->init_retry_count++; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "init_timeout_cb: incremented retry_count to %u", link->init_retry_count); - - if (link->init_retry_count > 5) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "init_timeout_cb: max retries exceeded (%u > 5), closing link", link->init_retry_count); - // Fail - etcp_link_close(link); - return; - } - - // Resend... - link->init_timeout *= 2; // Backoff - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "init_timeout_cb: doubled timeout to %u ms", link->init_timeout); - link->init_timer = uasync_set_timeout(link->etcp->instance->ua, link->init_timeout, link, init_timeout_cb); - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "init_timeout_cb: rescheduled timer"); -} - -// Bandwidth limit update (called after send) -void etcp_loadbalancer_update_after_send(struct ETCP_LINK* link, size_t pkt_size) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_update_after_send: link=%p, pkt_size=%zu", link, pkt_size); - - if (!link) { - DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_update_after_send: called with NULL link"); - return; - } - - if (link->bandwidth == 0) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_update_after_send: link bandwidth is 0, skipping update"); - return; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_update_after_send: link bandwidth=%u bits/sec, packet size=%zu bytes", - link->bandwidth, pkt_size); - - // Time to transmit (ns) - double byte_time_ns = 1000000000.0 / (link->bandwidth * 8.0); // bits/sec to byte/ns - uint64_t tx_time_ns = (uint64_t)(pkt_size * byte_time_ns); - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_update_after_send: byte_time_ns=%.2f, tx_time_ns=%llu", - byte_time_ns, (unsigned long long)tx_time_ns); - - // To timebase (0.1ms units) - uint64_t tx_time_tb = tx_time_ns / (TIMEBASE_NS / 10); - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_update_after_send: tx_time_tb=%llu", (unsigned long long)tx_time_tb); - - // Update last_activity - uint64_t now_tb = get_current_nanotime() / (TIMEBASE_NS / 10); - uint64_t old_activity = link->last_activity; - link->last_activity += tx_time_tb; - if (link->last_activity < now_tb - (DELTA_TIME_NS / (TIMEBASE_NS / 10))) { - link->last_activity = now_tb - (DELTA_TIME_NS / (TIMEBASE_NS / 10)); - } - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_loadbalancer_update_after_send: updated last_activity from %llu to %llu", - (unsigned long long)old_activity, (unsigned long long)link->last_activity); -} \ No newline at end of file diff --git a/!/etcp_loadbalancer.h b/!/etcp_loadbalancer.h deleted file mode 100755 index 7e46d309..00000000 --- a/!/etcp_loadbalancer.h +++ /dev/null @@ -1,20 +0,0 @@ -// etcp_loadbalancer.h - Load Balancer for ETCP Channels -#ifndef ETCP_LOADBALANCER_H -#define ETCP_LOADBALANCER_H - -#include "etcp.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// Functions -struct ETCP_LINK* etcp_loadbalancer_select_link(struct ETCP_CONN* etcp); - -// Add more as needed (e.g., update bandwidth) - -#ifdef __cplusplus -} -#endif - -#endif // ETCP_LOADBALANCER_H \ No newline at end of file diff --git a/!/fix.patch b/!/fix.patch deleted file mode 100755 index d26c3d66..00000000 --- a/!/fix.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- etcp_connections.c.backup -+++ etcp_connections.c -@@ -409,6 +409,7 @@ - uint8_t enc_buf[1600]; - size_t enc_buf_len; - dgram->timestamp=get_current_timestamp(); -+ printf("[ETCP DEBUG] About to encrypt: data_len=%d, noencrypt_len=%d, len=%d\\n", dgram->data_len, dgram->noencrypt_len, len); - - // DUMP: Show packet before encryption - dump_packet_bytes("BEFORE ENCRYPT", dgram->data, dgram->data_len); diff --git a/!/packet_dump.h b/!/packet_dump.h deleted file mode 100755 index 7c15f3d0..00000000 --- a/!/packet_dump.h +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include -#include -#include -#include - -// Packet dump function for debugging -static void dump_packet(const char* direction, const uint8_t* data, size_t len, struct sockaddr_storage* addr) { - printf("[DUMP] %s packet: %zd bytes ", direction, len); - - // Print address if provided - if (addr) { - if (addr->ss_family == AF_INET) { - struct sockaddr_in* sin = (struct sockaddr_in*)addr; - printf("to/from %s:%d ", - inet_ntoa(sin->sin_addr), - ntohs(sin->sin_port)); - } - } - - // Print first 64 bytes - printf("data: "); - for (size_t i = 0; i < len && i < 64; i++) { - printf("%02x", data[i]); - if (i % 4 == 3) printf(" "); - } - if (len > 64) printf("..."); - - // If it's INIT packet, parse fields - if (len > 0 && data[0] == 0x02) { // ETCP_INIT_REQUEST - if (len >= 15) { // Minimum INIT size: code(1) + node_id(8) + mtu(2) + keepalive(2) + pubkey(2 at least) - uint64_t node_id = 0; - memcpy(&node_id, data + 1, 8); - uint16_t mtu = (data[9] << 8) | data[10]; - uint16_t keepalive = (data[11] << 8) | data[12]; - printf(" | INIT: node_id=%llu mtu=%d keepalive=%d", - (unsigned long long)node_id, mtu, keepalive); - } - } - - printf("\n"); -} \ No newline at end of file diff --git a/!/pkt_normalizer.c b/!/pkt_normalizer.c deleted file mode 100755 index cfc1cfc2..00000000 --- a/!/pkt_normalizer.c +++ /dev/null @@ -1,604 +0,0 @@ -#include "pkt_normalizer.h" -#include "../lib/u_async.h" -#include -#include -#include -#include -static void packer_handler(struct ll_queue* q, struct ll_entry* unused, void* arg); -static void unpacker_handler(struct ll_queue* q, struct ll_entry* unused, void* arg); -static void send_buf(struct pn_struct* pn); -static int get_header(uint8_t* header, size_t L); -/* Calculate fragment size from mtu */ -struct pn_struct* pkt_normalizer_init(uasync_t* ua, int is_packer, int mtu) { - struct pn_struct* pn = malloc(sizeof(struct pn_struct)); - if (!pn) return NULL; - pn->ua = ua; - pn->input = queue_new(ua, NULL); // No memory pool for now - if (!pn->input) { - free(pn); - return NULL; - } - pn->output = queue_new(ua, NULL); // No memory pool for now - if (!pn->output) { - queue_free(pn->input); - free(pn); - return NULL; - } - pn->is_packer = is_packer; - if (is_packer) { - // Calculate fragment size from mtu: fragment = mtu - 100 - int fragment_size = mtu - ETCP_OVERHEAD; - if (fragment_size < 256) fragment_size = 256; // Minimum sane value - pn->u.packer.cap = fragment_size; - pn->u.packer.buf = malloc(pn->u.packer.cap); - if (!pn->u.packer.buf) { - queue_free(pn->input); - queue_free(pn->output); - free(pn); - return NULL; - } - pn->u.packer.len = 0; - pn->u.packer.error_count = 0; - queue_set_callback(pn->input, packer_handler, pn); - } else { - pn->u.unpacker.buf = NULL; - pn->u.unpacker.len = 0; - pn->u.unpacker.total_len = 0; - pn->u.unpacker.cap = 0; - pn->u.unpacker.error_count = 0; - queue_set_callback(pn->input, unpacker_handler, pn); - } - return pn; -} - -void pkt_normalizer_deinit(struct pn_struct* pn) { - if (!pn) return; - queue_free(pn->input); - queue_free(pn->output); - if (pn->is_packer) { - free(pn->u.packer.buf); - } else { - free(pn->u.unpacker.buf); - free(pn->u.unpacker.service_buf); - } - free(pn); -} -struct pkt_normalizer_pair* pkt_normalizer_pair_init(uasync_t* ua, int mtu) { - struct pkt_normalizer_pair* pair = malloc(sizeof(struct pkt_normalizer_pair)); - if (!pair) return NULL; - pair->packer = pkt_normalizer_init(ua, 1, mtu); - if (!pair->packer) { - free(pair); - return NULL; - } - pair->unpacker = pkt_normalizer_init(ua, 0, mtu); - if (!pair->unpacker) { - pkt_normalizer_deinit(pair->packer); - free(pair); - return NULL; - } - return pair; -} -void pkt_normalizer_pair_deinit(struct pkt_normalizer_pair* pair) { - if (!pair) return; - pkt_normalizer_deinit(pair->packer); - pkt_normalizer_deinit(pair->unpacker); - free(pair); -} -static int get_header(uint8_t* header, size_t L) { - if (L > 1535) return -1; - if (L <= 239) { - header[0] = (uint8_t)L; - return 1; - } else { - uint8_t high = (uint8_t)(L >> 8); - if (high > 5) return -1; - header[0] = 0xF0 + high; - header[1] = (uint8_t)(L & 0xFF); - return 2; - } -} -/* Сбросить состояние сборки фрагментов */ -static void reset_fragment_state(struct pn_struct* pn) { - if (!pn->is_packer) { - pn->u.unpacker.len = 0; - pn->u.unpacker.total_len = 0; - pn->u.unpacker.in_fragment = 0; - } -} -/* Таймаут для сборки фрагментов */ -static void send_buf(struct pn_struct* pn) { - if (pn->u.packer.len == 0) return; - size_t payload_len = pn->u.packer.len; - struct ll_entry* out = queue_entry_new(2 + payload_len); - if (!out) return; - uint8_t* d = ll_entry_data(out); - *(uint16_t*)d = (uint16_t)payload_len; - memcpy(d + 2, pn->u.packer.buf, payload_len); - queue_entry_put(pn->output, out); - pn->u.packer.len = 0; -} -static void packer_handler(struct ll_queue* q, struct ll_entry* unused, void* arg) { - (void)unused; - struct pn_struct* pn = arg; - size_t max = (size_t)1400; - struct ll_entry* entry = queue_entry_get(q); - if (!entry) { - queue_resume_callback(q); - return; - } - size_t L = ll_entry_size(entry); - uint8_t* data = ll_entry_data(entry); - uint8_t header[2]; - int hsize = get_header(header, L); - size_t needed = (size_t)hsize + L; - if (hsize < 0 || needed > max) { - // Fragment - if (pn->u.packer.len > 0) { - send_buf(pn); - } - size_t remaining = L; - size_t pos = 0; - int fragment_count = 0; - while (remaining > 0) { - size_t chunk; - size_t payload_len; - struct ll_entry* fout; - uint8_t* fd; - uint8_t frag_header[2]; - int frag_hsize; - if (fragment_count == 0) { - // Первый фрагмент: FF + общая длина (2 байта) - chunk = remaining > (max - 5) ? (max - 5) : remaining; // 2+1+2+chunk <= max - payload_len = 1 + 2 + chunk; // FF + total_len + data - fout = queue_entry_new(2 + payload_len); - if (!fout) { - break; - } - fd = ll_entry_data(fout); - *(uint16_t*)fd = (uint16_t)payload_len; - fd += 2; - *fd++ = 0xFF; - *fd++ = (uint8_t)(L >> 8); // старший байт общей длины - *fd++ = (uint8_t)(L & 0xFF); // младший байт общей длины - } else { - // Не первый фрагмент - if (remaining <= max - 3) { - // Это последний возможный фрагмент (помещается в один пакет с префиксом FE) - // Пытаемся отправить как обычный блок - frag_hsize = get_header(frag_header, remaining); - if (frag_hsize > 0 && (size_t)frag_hsize + remaining + 2 <= max) { - // Успешно: обычный блок - payload_len = frag_hsize + remaining; - chunk = remaining; - fout = queue_entry_new(2 + payload_len); - if (!fout) { - break; - } - fd = ll_entry_data(fout); - *(uint16_t*)fd = (uint16_t)payload_len; - fd += 2; - memcpy(fd, frag_header, frag_hsize); - fd += frag_hsize; - } else { - // Не удалось отправить как обычный блок - разбиваем на 2 фрагмента - // 1. FE фрагмент с частью данных - // 2. Обычный блок с оставшимися данными - // Находим максимальный размер для FE фрагмента - size_t max_fe_data = max - 3; // 2 байта длины + 0xFE - if (max_fe_data > remaining) { - max_fe_data = remaining; - } - // Пробуем различные размеры, начиная с максимального - size_t fe_data_size = 0; - for (size_t try_fe = max_fe_data; try_fe > 0; try_fe--) { - size_t try_regular = remaining - try_fe; - if (try_regular == 0) continue; // Нужно отправить что-то как обычный блок - uint8_t test_header[2]; - int hsize = get_header(test_header, try_regular); - if (hsize <= 0) continue; - if ((size_t)hsize + try_regular + 2 <= max) { - fe_data_size = try_fe; - break; - } - } - if (fe_data_size == 0) { - // Не удалось найти разбиение - ошибка - pn->u.packer.error_count++; - // Отправляем как FE (нарушение спецификации, но это крайний случай) - chunk = remaining > (max - 3) ? (max - 3) : remaining; - payload_len = 1 + chunk; // FE + data - fout = queue_entry_new(2 + payload_len); - if (!fout) break; - fd = ll_entry_data(fout); - *(uint16_t*)fd = (uint16_t)payload_len; - fd += 2; - *fd++ = 0xFE; - } else { - // Отправляем FE фрагмент - chunk = fe_data_size; - payload_len = 1 + chunk; // FE + data - fout = queue_entry_new(2 + payload_len); - if (!fout) break; - fd = ll_entry_data(fout); - *(uint16_t*)fd = (uint16_t)payload_len; - fd += 2; - *fd++ = 0xFE; - memcpy(fd, data + pos, chunk); - queue_entry_put(pn->output, fout); - pos += chunk; - remaining -= chunk; - fragment_count++; - // Обновляем оставшиеся данные для обычного блока - // (цикл продолжит обработку на следующей итерации) - continue; - } - } - } else { - // Промежуточный фрагмент, отправляем как FE - chunk = remaining > (max - 3) ? (max - 3) : remaining; - payload_len = 1 + chunk; // FE + data - fout = queue_entry_new(2 + payload_len); - if (!fout) { - break; - } - fd = ll_entry_data(fout); - *(uint16_t*)fd = (uint16_t)payload_len; - fd += 2; - *fd++ = 0xFE; - } - } - memcpy(fd, data + pos, chunk); - queue_entry_put(pn->output, fout); - pos += chunk; - remaining -= chunk; - fragment_count++; - } - } else { - if (pn->u.packer.len + needed > max) { - send_buf(pn); - } - // Add to buffer - uint8_t* p = pn->u.packer.buf + pn->u.packer.len; - memcpy(p, header, (size_t)hsize); - memcpy(p + hsize, data, L); - pn->u.packer.len += needed; - } - queue_entry_free(entry); - if (pn->u.packer.len > 0) { - send_buf(pn); - } - queue_resume_callback(q); -} -void pkt_normalizer_set_service_callback(struct pn_struct* pn, pkt_normalizer_service_callback_t callback, void* user_data) { - if (!pn) return; - pn->service_callback = callback; - pn->service_callback_user_data = user_data; -} -void pkt_normalizer_reset_service_state(struct pn_struct* pn) { - if (!pn || pn->is_packer) return; - if (pn->u.unpacker.in_service) { - // Deliver pending service packet - if (pn->service_callback) { - pn->service_callback(pn->service_callback_user_data, - pn->u.unpacker.service_type, - pn->u.unpacker.service_buf, - pn->u.unpacker.service_len); - } - free(pn->u.unpacker.service_buf); - pn->u.unpacker.service_buf = NULL; - pn->u.unpacker.service_len = 0; - pn->u.unpacker.service_cap = 0; - pn->u.unpacker.in_service = 0; - } -} -void pkt_normalizer_reset_state(struct pn_struct* pn) { - if (!pn) return; - if (pn->is_packer) { - // Flush packer buffer - if (pn->u.packer.len > 0) { - send_buf(pn); - } - } else { - // Reset unpacker fragment state - reset_fragment_state(pn); - // Reset service state - pkt_normalizer_reset_service_state(pn); - } -} -int pkt_normalizer_send_service(struct pn_struct* pn, uint8_t type, const void* data, size_t len) { - if (!pn || !pn->is_packer) return -1; - // Service packet ограничен 256 байтами всего - if (len > 256 - 2) return -1; // 2 байта на заголовок (0xFC + тип) - size_t max = (size_t)1400; - if (max < 3) return -1; - // Размер сервисного пакета: 2 байта длины + 1 байт 0xFC + 1 байт тип + данные - // Если не помещается в один фрагмент - используем продолжение 0xFD - size_t total_service_len = 1 + 1 + len; // 0xFC + type + data - size_t pos = 0; - while (total_service_len > 0) { - // Определяем размер куска для этого пакета - size_t chunk; - uint8_t service_header; - if (pos == 0) { - // Первый пакет: 0xFC + тип + часть данных - // Максимум данных в первом пакете: max - 2 (длина) - 2 (0xFC+тип) - size_t max_first_data = max - 4; - if (max_first_data > len) max_first_data = len; - chunk = max_first_data; - service_header = 0xFC; - } else { - // Продолжение: 0xFD + данные - // Максимум данных: max - 2 (длина) - 1 (0xFD) - size_t max_cont_data = max - 3; - size_t remaining = len - pos; - if (max_cont_data > remaining) max_cont_data = remaining; - chunk = max_cont_data; - service_header = 0xFD; - } - if (chunk == 0) break; - size_t payload_len = 1 + chunk + (pos == 0 ? 1 : 0); // +1 байт типа для первого пакета - struct ll_entry* entry = queue_entry_new(2 + payload_len); - if (!entry) return -1; - uint8_t* d = ll_entry_data(entry); - *(uint16_t*)d = (uint16_t)payload_len; - d += 2; - *d++ = service_header; - if (pos == 0) { - *d++ = type; - } - memcpy(d, (const uint8_t*)data + pos, chunk); - queue_entry_put(pn->output, entry); - pos += chunk; - total_service_len -= chunk + (pos == chunk ? 2 : 1); // корректно вычитаем заголовки - } - return 0; -} -int pkt_normalizer_get_error_count(const struct pn_struct* pn) { - if (!pn) return 0; - if (pn->is_packer) { - return pn->u.packer.error_count; - } - return pn->u.unpacker.error_count; -} -void pkt_normalizer_reset_error_count(struct pn_struct* pn) { - if (!pn) return; - if (pn->is_packer) { - pn->u.packer.error_count = 0; - } else { - pn->u.unpacker.error_count = 0; - } -} -void pkt_normalizer_flush(struct pn_struct* pn) { - if (!pn || !pn->is_packer) return; - if (pn->u.packer.len > 0) { - send_buf(pn); - } -} -static void unpacker_handler(struct ll_queue* q, struct ll_entry* unused, void* arg) { - (void)unused; - struct pn_struct* pn = arg; - while (queue_entry_count(q) > 0) { - struct ll_entry* entry = queue_entry_get(q); - uint8_t* data = ll_entry_data(entry); - size_t total = ll_entry_size(entry); - uint16_t payload_len = *(uint16_t*)data; - if (total != 2 + (size_t)payload_len) { - queue_entry_free(entry); - continue; - } - uint8_t* cg = data + 2; - size_t cg_pos = 0; - size_t cg_len = (size_t)payload_len; - while (cg_pos < cg_len) { - uint8_t byte = cg[cg_pos++]; - if (byte == 0xFF) { - /* Начало нового фрагментированного пакета */ - if (pn->u.unpacker.in_fragment) { - /* Не завершен предыдущий фрагмент - ошибка */ - pn->u.unpacker.error_count++; - reset_fragment_state(pn); - } - /* Проверить, что есть 2 байта для общей длины */ - if (cg_pos + 2 > cg_len) { - pn->u.unpacker.error_count++; - goto err; - } - /* Прочитать общую длину */ - uint16_t total_len = ((uint16_t)cg[cg_pos] << 8) | cg[cg_pos + 1]; - cg_pos += 2; - size_t chunk_len = cg_len - cg_pos; - /* Выделить буфер при необходимости */ - size_t new_len = chunk_len; - if (new_len > pn->u.unpacker.cap) { - size_t new_cap = pn->u.unpacker.cap ? pn->u.unpacker.cap * 2 : 4096; - if (new_cap < new_len) new_cap = new_len; - pn->u.unpacker.buf = realloc(pn->u.unpacker.buf, new_cap); - pn->u.unpacker.cap = new_cap; - } - memcpy(pn->u.unpacker.buf, cg + cg_pos, chunk_len); - pn->u.unpacker.len = chunk_len; - pn->u.unpacker.total_len = total_len; - pn->u.unpacker.in_fragment = 1; - cg_pos += chunk_len; - /* Проверить, не собрали ли уже весь пакет */ - if (pn->u.unpacker.len >= pn->u.unpacker.total_len) { - if (pn->u.unpacker.len == pn->u.unpacker.total_len) { - struct ll_entry* out = queue_entry_new(pn->u.unpacker.total_len); - if (out) { - memcpy(ll_entry_data(out), pn->u.unpacker.buf, pn->u.unpacker.total_len); - queue_entry_put(pn->output, out); - } - } else { - /* Слишком много данных - ошибка */ - pn->u.unpacker.error_count++; - } - reset_fragment_state(pn); - } - continue; - } - if (byte == 0xFE) { - /* Продолжение фрагментированного пакета */ - if (!pn->u.unpacker.in_fragment) { - /* Не было начала фрагмента - ошибка */ - pn->u.unpacker.error_count++; - goto err; - } - size_t chunk_len = cg_len - cg_pos; - size_t new_len = pn->u.unpacker.len + chunk_len; - if (new_len > pn->u.unpacker.cap) { - size_t new_cap = pn->u.unpacker.cap ? pn->u.unpacker.cap * 2 : 4096; - if (new_cap < new_len) new_cap = new_len; - pn->u.unpacker.buf = realloc(pn->u.unpacker.buf, new_cap); - pn->u.unpacker.cap = new_cap; - } - memcpy(pn->u.unpacker.buf + pn->u.unpacker.len, cg + cg_pos, chunk_len); - pn->u.unpacker.len = new_len; - cg_pos += chunk_len; - /* Проверить, не собрали ли уже весь пакет */ - if (pn->u.unpacker.len >= pn->u.unpacker.total_len) { - if (pn->u.unpacker.len == pn->u.unpacker.total_len) { - struct ll_entry* out = queue_entry_new(pn->u.unpacker.total_len); - if (out) { - memcpy(ll_entry_data(out), pn->u.unpacker.buf, pn->u.unpacker.total_len); - queue_entry_put(pn->output, out); - } - } else { - /* Слишком много данных - ошибка */ - pn->u.unpacker.error_count++; - } - reset_fragment_state(pn); - } - continue; - } - if (byte == 0xFC || byte == 0xFD) { - /* Service packet */ - if (byte == 0xFC) { - /* Start of service packet */ - if (pn->u.unpacker.in_service) { - /* Previous service packet finished - deliver it */ - if (pn->service_callback) { - pn->service_callback(pn->service_callback_user_data, - pn->u.unpacker.service_type, - pn->u.unpacker.service_buf, - pn->u.unpacker.service_len); - } - free(pn->u.unpacker.service_buf); - pn->u.unpacker.service_buf = NULL; - pn->u.unpacker.service_len = 0; - pn->u.unpacker.service_cap = 0; - pn->u.unpacker.in_service = 0; - } - /* Read service type */ - if (cg_pos >= cg_len) goto err; - uint8_t service_type = cg[cg_pos++]; - pn->u.unpacker.service_type = service_type; - pn->u.unpacker.in_service = 1; - pn->u.unpacker.service_len = 0; - } else { - /* 0xFD - continuation */ - if (!pn->u.unpacker.in_service) { - /* No service packet started - error */ - pn->u.unpacker.error_count++; - goto err; - } - } - /* Read data */ - size_t data_len = cg_len - cg_pos; - if (data_len > 0) { - size_t new_len = pn->u.unpacker.service_len + data_len; - if (new_len > 256) { - /* Service packet too long - error */ - pn->u.unpacker.error_count++; - free(pn->u.unpacker.service_buf); - pn->u.unpacker.service_buf = NULL; - pn->u.unpacker.service_len = 0; - pn->u.unpacker.service_cap = 0; - pn->u.unpacker.in_service = 0; - goto err; - } - if (new_len > pn->u.unpacker.service_cap) { - size_t new_cap = pn->u.unpacker.service_cap ? pn->u.unpacker.service_cap * 2 : 256; - if (new_cap < new_len) new_cap = new_len; - if (new_cap > 256) new_cap = 256; - uint8_t* new_buf = realloc(pn->u.unpacker.service_buf, new_cap); - if (!new_buf) { - pn->u.unpacker.error_count++; - goto err; - } - pn->u.unpacker.service_buf = new_buf; - pn->u.unpacker.service_cap = new_cap; - } - memcpy(pn->u.unpacker.service_buf + pn->u.unpacker.service_len, cg + cg_pos, data_len); - pn->u.unpacker.service_len = new_len; - cg_pos += data_len; - } - /* Check if this is the end of service packet (end of payload) */ - if (cg_pos >= cg_len) { - /* End of current payload, but service packet may continue in next transport packet */ - continue; - } else { - /* There is more data in this payload after service packet - error */ - pn->u.unpacker.error_count++; - free(pn->u.unpacker.service_buf); - pn->u.unpacker.service_buf = NULL; - pn->u.unpacker.service_len = 0; - pn->u.unpacker.service_cap = 0; - pn->u.unpacker.in_service = 0; - goto err; - } - } - /* Обычная запись (не фрагмент) */ - size_t L; - if (byte <= 0xEF) { - L = byte; - } else if (byte >= 0xF0 && byte <= 0xF5) { - if (cg_pos >= cg_len) goto err; - uint8_t ext = cg[cg_pos++]; - L = ((size_t)(byte - 0xF0) << 8) | ext; - } else { - /* Недопустимый байт */ - goto err; - } - if (cg_pos + L > cg_len) goto err; - if (pn->u.unpacker.in_fragment) { - /* Это последний фрагмент в виде обычной записи */ - size_t new_len = pn->u.unpacker.len + L; - if (new_len > pn->u.unpacker.cap) { - size_t new_cap = pn->u.unpacker.cap ? pn->u.unpacker.cap * 2 : 4096; - if (new_cap < new_len) new_cap = new_len; - pn->u.unpacker.buf = realloc(pn->u.unpacker.buf, new_cap); - pn->u.unpacker.cap = new_cap; - } - memcpy(pn->u.unpacker.buf + pn->u.unpacker.len, cg + cg_pos, L); - pn->u.unpacker.len = new_len; - cg_pos += L; - /* Проверить, собрали ли весь пакет */ - if (pn->u.unpacker.len >= pn->u.unpacker.total_len) { - if (pn->u.unpacker.len == pn->u.unpacker.total_len) { - struct ll_entry* out = queue_entry_new(pn->u.unpacker.total_len); - if (out) { - memcpy(ll_entry_data(out), pn->u.unpacker.buf, pn->u.unpacker.total_len); - queue_entry_put(pn->output, out); - } - } else { - /* Слишком много данных - ошибка */ - pn->u.unpacker.error_count++; - } - reset_fragment_state(pn); - } - } else { - /* Обычная запись (не часть фрагмента) */ - struct ll_entry* out = queue_entry_new(L); - if (out) { - memcpy(ll_entry_data(out), cg + cg_pos, L); - queue_entry_put(pn->output, out); - } - cg_pos += L; - } - } - err: - queue_entry_free(entry); - } - queue_resume_callback(q); -} diff --git a/!/pkt_normalizer.h b/!/pkt_normalizer.h deleted file mode 100755 index f709bf52..00000000 --- a/!/pkt_normalizer.h +++ /dev/null @@ -1,75 +0,0 @@ -// pkt_normalizer.h -#ifndef PKT_NORMALIZER_H -#define PKT_NORMALIZER_H - -#include "ll_queue.h" -#include "../lib/u_async.h" -#include - -/* Default fragment reassembly timeout in uasync timebase units (0.1 ms) */ -#ifndef PKT_NORMALIZER_FRAGMENT_TIMEOUT -#define PKT_NORMALIZER_FRAGMENT_TIMEOUT 5000 /* 500 ms */ -#endif - -/* ETCP overhead for calculating fragment size from MTU */ -#define ETCP_OVERHEAD 100 // Reserve 100 bytes for headers, crypto, etc.*/ - -/* 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 { - struct ll_queue* input; - struct ll_queue* 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; -}; - -struct pkt_normalizer_pair { - struct pn_struct* packer; - struct pn_struct* unpacker; -}; - -struct pn_struct* pkt_normalizer_init(uasync_t* ua, int is_packer, int mtu); // 1 for packer, 0 for unpacker, mtu for fragment size calculation -void pkt_normalizer_deinit(struct pn_struct* pn); - -struct pkt_normalizer_pair* pkt_normalizer_pair_init(uasync_t* ua, int mtu); -void pkt_normalizer_pair_deinit(struct pkt_normalizer_pair* pair); - -/* Error handling */ -int pkt_normalizer_get_error_count(const struct pn_struct* pn); -void pkt_normalizer_reset_error_count(struct pn_struct* pn); - -/* Flush internal buffer (packer only) */ -void pkt_normalizer_flush(struct pn_struct* pn); - -int pkt_normalizer_send_service(struct pn_struct* pn, uint8_t type, const void* data, size_t len); -void pkt_normalizer_set_service_callback(struct pn_struct* pn, pkt_normalizer_service_callback_t callback, void* user_data); -void pkt_normalizer_reset_service_state(struct pn_struct* pn); -void pkt_normalizer_reset_state(struct pn_struct* pn); - -#endif // PKT_NORMALIZER_H diff --git a/!/routing.h b/!/routing.h deleted file mode 100755 index 3302e7e7..00000000 --- a/!/routing.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef ROUTING_H -#define ROUTING_H -#include -#include -#include - -// Forward declarations -struct ETCP_CONNECTIONS; - -// Типы маршрутов -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; - -// Расширенные метрики маршрута -struct route_metrics { - uint32_t bandwidth_kbps; - uint16_t packet_loss_rate; - uint16_t latency_ms; - uint8_t hop_count; - uint64_t last_updated; -}; - -// Расширенная запись маршрута -struct route_entry { - uint32_t network; - uint8_t prefix_length; - uint32_t next_hop_ip; - struct ETCP_SOCKET* next_hop; - route_type_t type; - uint8_t flags; - struct route_metrics metrics; - uint64_t created_time; - uint64_t last_update; - uint64_t last_used; -}; - -// Таблица маршрутизации -struct routing_table { - struct route_entry *entries; - size_t count; - size_t capacity; - uint32_t *dynamic_subnets; - size_t dynamic_subnet_count; - uint32_t *local_subnets; - size_t local_subnet_count; - struct { - uint64_t total_routes; - uint64_t static_routes; - uint64_t dynamic_routes; - uint64_t local_routes; - uint64_t learned_routes; - uint64_t routes_added; - uint64_t routes_deleted; - uint64_t lookup_count; - uint64_t hit_count; - uint64_t routes_lookup_hits; - uint64_t routes_lookup_misses; - uint64_t validation_failures; - } stats; -}; - -struct routing_table *routing_table_create(void); -void routing_table_destroy(struct routing_table *table); -bool routing_table_insert(struct routing_table *table, const struct route_entry *entry); -bool routing_table_delete(struct routing_table *table, uint32_t network, uint8_t prefix_length, uint32_t source_node_id); -bool routing_table_lookup(struct routing_table *table, uint32_t dest_ip, struct route_entry *best_route); -bool routing_validate_route(struct routing_table *table, uint32_t network, uint8_t prefix_length, route_type_t route_type); -bool routing_add_dynamic_subnet(struct routing_table *table, uint32_t network, uint8_t prefix_length); -bool routing_add_local_subnet(struct routing_table *table, uint32_t network, uint8_t prefix_length); -bool routing_get_all_routes(const struct routing_table *table, uint32_t network, uint8_t prefix_length, struct route_entry **routes, size_t *count); -void routing_table_print(const struct routing_table *table); -const char* route_type_to_string(route_type_t type); -char* ip_to_string(uint32_t ip, char *buffer); - -#endif // ROUTING_H diff --git a/!/secure_channel.c b/!/secure_channel.c deleted file mode 100755 index 4749a3a9..00000000 --- a/!/secure_channel.c +++ /dev/null @@ -1,388 +0,0 @@ -/* sc_lib.c - Secure Channel library implementation using TinyCrypt */ - -#include "secure_channel.h" -#include "../tinycrypt/lib/include/tinycrypt/ecc.h" -#include "../tinycrypt/lib/include/tinycrypt/ecc_dh.h" -#include "../tinycrypt/lib/include/tinycrypt/aes.h" -#include "../tinycrypt/lib/include/tinycrypt/ccm_mode.h" -#include "../tinycrypt/lib/include/tinycrypt/constants.h" -#include "../tinycrypt/lib/include/tinycrypt/ecc_platform_specific.h" -#include "../tinycrypt/lib/include/tinycrypt/sha256.h" -#include -#include -#include -#include -#include -#include - -// Simple debug macros -#define DEBUG_CATEGORY_CRYPTO 1 -#define DEBUG_ERROR(category, fmt, ...) fprintf(stderr, "ERROR: " fmt "\n", ##__VA_ARGS__) -#define DEBUG_INFO(category, fmt, ...) fprintf(stdout, "INFO: " fmt "\n", ##__VA_ARGS__) -#include -#include -#include "crc32.h" - -static const struct uECC_Curve_t *curve = NULL; -static uint8_t sc_urandom_seed[8] = {0}; -static int sc_urandom_initialized = 0; - -static void sc_init_random_seed(void) -{ - int fd = open("/dev/urandom", O_RDONLY); - if (fd >= 0) { - ssize_t ret = read(fd, sc_urandom_seed, 8); - close(fd); - if (ret == 8) { - sc_urandom_initialized = 1; - } - } -} - - -static int sc_rng(uint8_t *dest, unsigned size) -{ - int fd = open("/dev/urandom", O_RDONLY); - if (fd < 0) { - return 0; - } - - ssize_t ret = read(fd, dest, size); - close(fd); - if (ret != size) { - return 0; - } - - /* Mix in PID and microtime for additional entropy */ - pid_t pid = getpid(); - struct timeval tv; - gettimeofday(&tv, NULL); - - for (unsigned i = 0; i < size; i++) { - dest[i] ^= ((pid >> (i % (sizeof(pid) * 8))) & 0xFF); - dest[i] ^= ((tv.tv_sec >> (i % (sizeof(tv.tv_sec) * 8))) & 0xFF); - dest[i] ^= ((tv.tv_usec >> (i % (sizeof(tv.tv_usec) * 8))) & 0xFF); - } - - return 1; -} - -static int sc_validate_key(const uint8_t *public_key) -{ - if (!curve) { - curve = uECC_secp256r1(); - } - int result = uECC_valid_public_key(public_key, curve); - DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "sc_validate_key: uECC_valid_public_key returned %d", result); - return result; -} - -sc_status_t sc_generate_keypair(struct SC_MYKEYS *pk) -{ - if (!pk) { - return SC_ERR_INVALID_ARG; - } - - if (!curve) { - curve = uECC_secp256r1(); - } - - /* Set custom RNG function */ - uECC_set_rng(sc_rng); - - if (!uECC_make_key(pk->public_key, pk->private_key, curve)) { - return SC_ERR_CRYPTO; - } - return SC_OK; -} - -// Конвертация hex строки в бинарный формат -static int hex_to_binary(const char *hex_str, uint8_t *binary, size_t binary_len) { - if (!hex_str || !binary || strlen(hex_str) != binary_len * 2) return -1; - - for (size_t i = 0; i < binary_len; i++) { - unsigned int byte; - if (sscanf(hex_str + i * 2, "%2x", &byte) != 1) return -1; - binary[i] = (uint8_t)byte; - } - return 0; -} - -sc_status_t sc_init_local_keys(struct SC_MYKEYS *mykeys, const char *public_key, const char *private_key) { - if (!mykeys || !public_key || !private_key) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_init_local_keys: invalid arguments"); - return SC_ERR_INVALID_ARG; - } - - if (!curve) { - curve = uECC_secp256r1(); - } - - DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "sc_init_local_keys: public_key len=%zu, private_key len=%zu", - strlen(public_key), strlen(private_key)); - - /* Convert hex to binary first */ - if (hex_to_binary(public_key, mykeys->public_key, SC_PUBKEY_SIZE)) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_init_local_keys: failed to convert public key from hex"); - return SC_ERR_INVALID_ARG; - } - if (hex_to_binary(private_key, mykeys->private_key, SC_PRIVKEY_SIZE)) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_init_local_keys: failed to convert private key from hex"); - return SC_ERR_INVALID_ARG; - } - - /* Validate the converted binary public key */ - if (sc_validate_key(mykeys->public_key) != 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_init_local_keys: public key validation failed"); - return SC_ERR_INVALID_ARG; - } - - DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "sc_init_local_keys: keys initialized successfully"); - return SC_OK; -} - -sc_status_t sc_init_ctx(sc_context_t *ctx, struct SC_MYKEYS *mykeys) { - - ctx->pk=mykeys; - ctx->initialized = 1; - ctx->peer_key_set = 0; - ctx->session_ready = 0; - ctx->tx_counter = 0; - ctx->rx_counter = 0; - - return SC_OK; -} - -sc_status_t sc_set_peer_public_key(sc_context_t *ctx, const char *peer_public_key_h, int mode) { - uint8_t shared_secret[SC_SHARED_SECRET_SIZE]; - uint8_t peer_public_key[SC_PUBKEY_SIZE]; - - if (mode) { - if (hex_to_binary(peer_public_key_h, peer_public_key, SC_PUBKEY_SIZE)) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_set_peer_public_key: invalid hex key format"); - return SC_ERR_INVALID_ARG; - } - } - else memcpy(peer_public_key, peer_public_key_h, SC_PUBKEY_SIZE); - - if (!ctx) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_set_peer_public_key: invalid ctx"); - return SC_ERR_INVALID_ARG; - } - - if (!ctx->initialized) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_set_peer_public_key: ctx not initialized"); - return SC_ERR_NOT_INITIALIZED; - } - - if (!curve) { - curve = uECC_secp256r1(); - } - - /* Validate peer public key */ - if (sc_validate_key(peer_public_key) != 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_set_peer_public_key: invalid key"); - return SC_ERR_INVALID_ARG; - } - - /* Compute shared secret using ECDH */ - if (!ctx->pk) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_set_peer_public_key: no private key"); - return SC_ERR_NOT_INITIALIZED; - } - if (!uECC_shared_secret(peer_public_key, ctx->pk->private_key, - shared_secret, curve)) { - DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "sc_set_peer_public_key: shared secret error"); - return SC_ERR_CRYPTO; - } - - /* Derive session key from shared secret (simple copy for demo) */ - memcpy(ctx->session_key, shared_secret, SC_SESSION_KEY_SIZE); - - /* Store peer public key */ - memcpy(ctx->peer_public_key, peer_public_key, SC_PUBKEY_SIZE); - ctx->peer_key_set = 1; - - ctx->session_ready = 1; - - return SC_OK; -} - -static void sc_build_nonce(uint64_t counter, uint8_t *nonce_out) -{ - struct tc_sha256_state_struct sha_ctx; - uint8_t hash[32]; - struct timeval tv; - uint8_t data[8 + 8 + 4]; - - if (!sc_urandom_initialized) { - sc_init_random_seed(); - } - - gettimeofday(&tv, NULL); - - memcpy(data, sc_urandom_seed, 8); - data[8] = (counter >> 0) & 0xFF; - data[9] = (counter >> 8) & 0xFF; - data[10] = (counter >> 16) & 0xFF; - data[11] = (counter >> 24) & 0xFF; - data[12] = (counter >> 32) & 0xFF; - data[13] = (counter >> 40) & 0xFF; - data[14] = (counter >> 48) & 0xFF; - data[15] = (counter >> 56) & 0xFF; - data[16] = (tv.tv_sec >> 0) & 0xFF; - data[17] = (tv.tv_sec >> 8) & 0xFF; - data[18] = (tv.tv_sec >> 16) & 0xFF; - data[19] = (tv.tv_sec >> 24) & 0xFF; - - tc_sha256_init(&sha_ctx); - tc_sha256_update(&sha_ctx, data, 20); - tc_sha256_final(hash, &sha_ctx); - - memcpy(nonce_out, hash, SC_NONCE_SIZE); -} - -sc_status_t sc_encrypt(sc_context_t *ctx, - const uint8_t *plaintext, - size_t plaintext_len, - uint8_t *ciphertext, - size_t *ciphertext_len) -{ - uint8_t nonce[SC_NONCE_SIZE]; - struct tc_aes_key_sched_struct sched; - struct tc_ccm_mode_struct ccm_state; - size_t total_plaintext_len = plaintext_len + SC_CRC32_SIZE; - uint8_t plaintext_with_crc[total_plaintext_len]; - uint8_t combined_output[total_plaintext_len + SC_TAG_SIZE]; - - if (!ctx || !plaintext || !ciphertext || !ciphertext_len) { - return SC_ERR_INVALID_ARG; - } - - if (!ctx->session_ready) { - return SC_ERR_NOT_INITIALIZED; - } - - if (plaintext_len == 0) { - return SC_ERR_INVALID_ARG; - } - - /* Добавляем CRC32 к данным */ - memcpy(plaintext_with_crc, plaintext, plaintext_len); - uint32_t crc = crc32_calc(plaintext, plaintext_len); - plaintext_with_crc[plaintext_len] = (crc >> 0) & 0xFF; - plaintext_with_crc[plaintext_len + 1] = (crc >> 8) & 0xFF; - plaintext_with_crc[plaintext_len + 2] = (crc >> 16) & 0xFF; - plaintext_with_crc[plaintext_len + 3] = (crc >> 24) & 0xFF; - - /* Initialize AES key schedule */ - if (tc_aes128_set_encrypt_key(&sched, ctx->session_key) != TC_CRYPTO_SUCCESS) { - return SC_ERR_CRYPTO; - } - - /* Build nonce from counter */ - sc_build_nonce(ctx->tx_counter, nonce); - - /* Configure CCM mode */ - if (tc_ccm_config(&ccm_state, &sched, nonce, SC_NONCE_SIZE, SC_TAG_SIZE) != TC_CRYPTO_SUCCESS) { - return SC_ERR_CRYPTO; - } - - /* Encrypt and generate tag */ - if (tc_ccm_generation_encryption(combined_output, sizeof(combined_output), - NULL, 0, /* no associated data */ - plaintext_with_crc, total_plaintext_len, - &ccm_state) != TC_CRYPTO_SUCCESS) { - return SC_ERR_CRYPTO; - } - - /* Copy ciphertext + tag to output buffer */ - memcpy(ciphertext, combined_output, total_plaintext_len + SC_TAG_SIZE); - *ciphertext_len = total_plaintext_len + SC_TAG_SIZE; - - ctx->tx_counter++; - - return SC_OK; -} - -sc_status_t sc_decrypt(sc_context_t *ctx, - const uint8_t *ciphertext, - size_t ciphertext_len, - uint8_t *plaintext, - size_t *plaintext_len) -{ - uint8_t nonce[SC_NONCE_SIZE]; - struct tc_aes_key_sched_struct sched; - struct tc_ccm_mode_struct ccm_state; - TCCcmMode_t c = &ccm_state; - size_t total_plaintext_len = ciphertext_len - SC_TAG_SIZE; - uint8_t plaintext_with_crc[total_plaintext_len]; - - if (!ctx || !ciphertext || !plaintext || !plaintext_len) { - return SC_ERR_INVALID_ARG; - } - - if (!ctx->session_ready) { - return SC_ERR_NOT_INITIALIZED; - } - - if (ciphertext_len < SC_TAG_SIZE + SC_CRC32_SIZE) { - return SC_ERR_INVALID_ARG; - } - - /* Initialize AES key schedule */ - if (tc_aes128_set_encrypt_key(&sched, ctx->session_key) != TC_CRYPTO_SUCCESS) { - return SC_ERR_CRYPTO; - } - - /* Build nonce from counter */ - sc_build_nonce(ctx->rx_counter, nonce); - - /* Configure CCM mode */ - if (tc_ccm_config(c, &sched, nonce, SC_NONCE_SIZE, SC_TAG_SIZE) != TC_CRYPTO_SUCCESS) { - return SC_ERR_CRYPTO; - } - - /* Decrypt and verify tag */ - if (tc_ccm_decryption_verification(plaintext_with_crc, total_plaintext_len, - NULL, 0, /* no associated data */ - ciphertext, ciphertext_len, - c) != TC_CRYPTO_SUCCESS) { - return SC_ERR_AUTH_FAILED; - } - - /* Проверяем CRC32 */ - size_t data_len = total_plaintext_len - SC_CRC32_SIZE; - uint32_t expected_crc = crc32_calc(plaintext_with_crc, data_len); - uint32_t received_crc = (plaintext_with_crc[data_len] << 0) | - (plaintext_with_crc[data_len + 1] << 8) | - (plaintext_with_crc[data_len + 2] << 16) | - (plaintext_with_crc[data_len + 3] << 24); - - if (expected_crc != received_crc) { - return SC_ERR_CRC_FAILED; - } - - /* Копируем данные без CRC32 */ - memcpy(plaintext, plaintext_with_crc, data_len); - *plaintext_len = data_len; - - ctx->rx_counter++; - - return SC_OK; -} - -sc_status_t sc_compute_public_key_from_private(const uint8_t *private_key, uint8_t *public_key) { - if (!private_key || !public_key) { - return SC_ERR_INVALID_ARG; - } - - if (!curve) { - curve = uECC_secp256r1(); - } - - if (!uECC_compute_public_key(private_key, public_key, curve)) { - return SC_ERR_CRYPTO; - } - return SC_OK; -} diff --git a/!/secure_channel.h b/!/secure_channel.h deleted file mode 100755 index 4b8ea632..00000000 --- a/!/secure_channel.h +++ /dev/null @@ -1,68 +0,0 @@ -// secure_channel.h -#ifndef SECURE_CHANNEL_H -#define SECURE_CHANNEL_H - -#include -#include - -// Размеры ключей -#define SC_PRIVKEY_SIZE 32 -#define SC_PUBKEY_SIZE 64 -#define SC_HASH_SIZE 32 -#define SC_NONCE_SIZE 13 // CCM requires exactly 13 bytes -#define SC_SHARED_SECRET_SIZE SC_HASH_SIZE -#define SC_SESSION_KEY_SIZE 16 -#define SC_TAG_SIZE 8 -#define SC_CRC32_SIZE 4 - -// Коды возврата -#define SC_OK 0 -#define SC_ERR_INVALID_ARG -1 -#define SC_ERR_CRYPTO -2 -#define SC_ERR_NOT_INITIALIZED -3 -#define SC_ERR_AUTH_FAILED -4 -#define SC_ERR_CRC_FAILED -5 - -#define SC_PEER_PUBKEY_BIN 0 -#define SC_PEER_PUBKEY_HEX 1 - -// Типы -typedef int sc_status_t; -typedef struct secure_channel sc_context_t; - -struct SC_MYKEYS { - /* Локальные ключи */ - uint8_t private_key[SC_PRIVKEY_SIZE]; - uint8_t public_key[SC_PUBKEY_SIZE]; - }; - -// Контекст защищенного канала -struct secure_channel { - struct SC_MYKEYS* pk; - /* Ключи пира (после key exchange) */ - uint8_t peer_public_key[SC_PUBKEY_SIZE]; - uint8_t session_key[SC_SESSION_KEY_SIZE]; /* Derived session key */ - - /* Nonces для отправки и приема */ - uint8_t send_nonce[SC_NONCE_SIZE]; - uint8_t recv_nonce[SC_NONCE_SIZE]; - - uint8_t initialized; - uint8_t peer_key_set; - uint8_t session_ready; - uint64_t tx_counter; - uint64_t rx_counter; -}; - -// Функции инициализации -sc_status_t sc_init_ctx(sc_context_t *ctx, struct SC_MYKEYS *mykeys); -sc_status_t sc_generate_keypair(struct SC_MYKEYS *keys); -sc_status_t sc_init_local_keys(struct SC_MYKEYS *mykeys, const char *public_key, const char *private_key); -sc_status_t sc_set_peer_public_key(sc_context_t *ctx, const char *peer_public_key, int mode);// mode: 0-bin 1-hex key format -sc_status_t sc_compute_public_key_from_private(const uint8_t *private_key, uint8_t *public_key); - -// Криптографические операции -sc_status_t sc_encrypt(sc_context_t *ctx, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext, size_t *ciphertext_len); -sc_status_t sc_decrypt(sc_context_t *ctx, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext, size_t *plaintext_len); - -#endif // SECURE_CHANNEL_H diff --git a/!/test_udp_socket.c b/!/test_udp_socket.c deleted file mode 100755 index 2b538413..00000000 --- a/!/test_udp_socket.c +++ /dev/null @@ -1,342 +0,0 @@ -#include "test_udp_socket.h" -#include "../lib/debug_config.h" -#include -#include -#include -#include -#include -#include - -#ifndef DEBUG_CATEGORY_TEST -#define DEBUG_CATEGORY_TEST (1 << 30) -#endif - -// Global socket registry for fd-based operations -static struct test_udp_socket* g_socket_registry[1024] = {NULL}; -pthread_mutex_t g_registry_mutex = PTHREAD_MUTEX_INITIALIZER; // Make it non-static for external access -static int g_next_fd = 1000; // Start with high fd numbers to avoid conflicts - -// Helper function to allocate packet -static struct test_udp_packet* allocate_packet(const uint8_t* data, size_t len, - const struct sockaddr* addr, socklen_t addr_len) { - struct test_udp_packet* packet = calloc(1, sizeof(struct test_udp_packet)); - if (!packet) return NULL; - - packet->data = malloc(len); - if (!packet->data) { - free(packet); - return NULL; - } - - memcpy(packet->data, data, len); - packet->len = len; - - if (addr && addr_len > 0 && addr_len <= sizeof(struct sockaddr_storage)) { - memcpy(&packet->addr, addr, addr_len); - packet->addr_len = addr_len; - } else { - packet->addr_len = 0; - } - - return packet; -} - -// Helper function to free packet -static void free_packet(struct test_udp_packet* packet) { - if (!packet) return; - if (packet->data) free(packet->data); - free(packet); -} - -// Create virtual UDP socket -struct test_udp_socket* test_udp_socket_create(int family) { - if (family != AF_INET && family != AF_INET6) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Unsupported address family: %d", family); - return NULL; - } - - struct test_udp_socket* sock = calloc(1, sizeof(struct test_udp_socket)); - if (!sock) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to allocate UDP socket"); - return NULL; - } - - // Assign virtual file descriptor - pthread_mutex_lock(&g_registry_mutex); - sock->fd = g_next_fd++; - if (g_next_fd >= 2000) g_next_fd = 1000; // Wrap around - pthread_mutex_unlock(&g_registry_mutex); - - sock->family = family; - sock->bound = false; - sock->nonblocking = false; - sock->recv_queue_head = NULL; - sock->recv_queue_tail = NULL; - sock->recv_queue_size = 0; - - // Register socket - test_udp_socket_register(sock); - - DEBUG_INFO(DEBUG_CATEGORY_TEST, "Created virtual UDP socket: fd=%d, family=%d", sock->fd, family); - return sock; -} - -// Destroy virtual UDP socket -void test_udp_socket_destroy(struct test_udp_socket* sock) { - if (!sock) return; - - DEBUG_INFO(DEBUG_CATEGORY_TEST, "Destroying virtual UDP socket: fd=%d (stats: sent=%zu/%zu, recv=%zu/%zu, errors=%zu/%zu)", - sock->fd, sock->stats.packets_sent, sock->stats.bytes_sent, - sock->stats.packets_received, sock->stats.bytes_received, - sock->stats.send_errors, sock->stats.recv_errors); - - // Unregister socket - test_udp_socket_unregister(sock); - - // Free receive queue - struct test_udp_packet* packet = sock->recv_queue_head; - while (packet) { - struct test_udp_packet* next = packet->next; - free_packet(packet); - packet = next; - } - - free(sock); -} - -// Bind virtual socket -int test_udp_socket_bind(struct test_udp_socket* sock, const struct sockaddr* addr, socklen_t len) { - if (!sock || !addr || len == 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Invalid parameters for socket bind"); - return -1; - } - - if (sock->bound) { - DEBUG_WARN(DEBUG_CATEGORY_TEST, "Socket already bound"); - return 0; - } - - if (len > sizeof(struct sockaddr_storage)) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Address too large: %d", len); - return -1; - } - - memcpy(&sock->local_addr, addr, len); - sock->bound = true; - - DEBUG_INFO(DEBUG_CATEGORY_TEST, "Bound virtual UDP socket fd=%d", sock->fd); - return 0; -} - -// Set socket options (limited implementation for testing) -int test_udp_socket_setsockopt(struct test_udp_socket* sock, int level, int optname, - const void *optval, socklen_t optlen) { - if (!sock) return -1; - - // For testing purposes, just log the option setting - DEBUG_DEBUG(DEBUG_CATEGORY_TEST, "setsockopt on fd=%d: level=%d, optname=%d, optlen=%d", - sock->fd, level, optname, optlen); - - // Handle some common options - if (level == SOL_SOCKET) { - switch (optname) { - case SO_REUSEADDR: - case SO_REUSEPORT: - // Always allow for testing - return 0; - case SO_BROADCAST: - return 0; - default: - break; - } - } - - return 0; // Pretend success for most options -} - -// Get socket options -int test_udp_socket_getsockopt(struct test_udp_socket* sock, int level, int optname, - void *optval, socklen_t *optlen) { - if (!sock || !optval || !optlen) return -1; - - // For testing purposes, return reasonable defaults - if (level == SOL_SOCKET) { - switch (optname) { - case SO_ERROR: - *(int*)optval = 0; - *optlen = sizeof(int); - return 0; - default: - break; - } - } - - return -1; // Not implemented -} - -// Set non-blocking mode -int test_udp_socket_set_nonblocking(struct test_udp_socket* sock, bool nonblocking) { - if (!sock) return -1; - - sock->nonblocking = nonblocking; - DEBUG_DEBUG(DEBUG_CATEGORY_TEST, "Set nonblocking on fd=%d: %s", sock->fd, nonblocking ? "true" : "false"); - return 0; -} - -// Send packet using virtual socket -ssize_t test_udp_socket_sendto(struct test_udp_socket* sock, const void *buf, size_t len, int flags, - const struct sockaddr *dest_addr, socklen_t addr_len) { - if (!sock || !buf || len == 0) { - return -1; - } - - const uint8_t* data = (const uint8_t*)buf; - - // Call packet sent callback if available - if (sock->packet_sent) { - sock->packet_sent(data, len, dest_addr, addr_len, sock->context); - } - - sock->stats.packets_sent++; - sock->stats.bytes_sent += len; - - DEBUG_DEBUG(DEBUG_CATEGORY_TEST, "Sent packet on fd=%d: %zu bytes to family=%d", - sock->fd, len, dest_addr ? dest_addr->sa_family : -1); - return len; -} - -// Receive packet from virtual socket -ssize_t test_udp_socket_recvfrom(struct test_udp_socket* sock, void *buf, size_t len, int flags, - struct sockaddr *src_addr, socklen_t *addr_len) { - if (!sock || !buf || len == 0) { - return -1; - } - - uint8_t* buffer = (uint8_t*)buf; - - // Check if we have packets in queue - pthread_mutex_lock(&g_registry_mutex); - struct test_udp_packet* packet = sock->recv_queue_head; - if (!packet) { - pthread_mutex_unlock(&g_registry_mutex); - errno = EAGAIN; - return -1; - } - - // Remove packet from queue - sock->recv_queue_head = packet->next; - if (!sock->recv_queue_head) { - sock->recv_queue_tail = NULL; - } - sock->recv_queue_size--; - pthread_mutex_unlock(&g_registry_mutex); - - // Copy packet data - size_t copy_len = packet->len < len ? packet->len : len; - memcpy(buffer, packet->data, copy_len); - - // Copy source address if requested - if (src_addr && addr_len && packet->addr_len > 0) { - socklen_t copy_addr_len = packet->addr_len < *addr_len ? packet->addr_len : *addr_len; - memcpy(src_addr, &packet->addr, copy_addr_len); - *addr_len = copy_addr_len; - } - - sock->stats.packets_received++; - sock->stats.bytes_received += copy_len; - - DEBUG_DEBUG(DEBUG_CATEGORY_TEST, "Received packet on fd=%d: %zu bytes", sock->fd, copy_len); - - free_packet(packet); - return copy_len; -} - -// Inject packet into receive queue (simulates incoming packet) -int test_udp_socket_inject(struct test_udp_socket* sock, - const uint8_t* data, size_t len, - const struct sockaddr* src_addr, socklen_t addr_len) { - if (!sock || !data || len == 0) { - return -1; - } - - if (sock->recv_queue_size >= TEST_UDP_MAX_QUEUE_SIZE) { - DEBUG_WARN(DEBUG_CATEGORY_TEST, "Receive queue full on fd=%d", sock->fd); - return -1; - } - - struct test_udp_packet* packet = allocate_packet(data, len, src_addr, addr_len); - if (!packet) { - return -1; - } - - pthread_mutex_lock(&g_registry_mutex); - if (sock->recv_queue_tail) { - sock->recv_queue_tail->next = packet; - } else { - sock->recv_queue_head = packet; - } - sock->recv_queue_tail = packet; - sock->recv_queue_size++; - pthread_mutex_unlock(&g_registry_mutex); - - DEBUG_DEBUG(DEBUG_CATEGORY_TEST, "Injected packet into fd=%d: %zu bytes", sock->fd, len); - return 0; -} - -// Get virtual socket file descriptor -int test_udp_socket_get_fd(struct test_udp_socket* sock) { - return sock ? sock->fd : -1; -} - -// Get socket statistics -void test_udp_socket_get_stats(struct test_udp_socket* sock, size_t* packets_sent, - size_t* packets_received, size_t* bytes_sent, - size_t* bytes_received, size_t* send_errors, size_t* recv_errors) { - if (!sock) return; - - if (packets_sent) *packets_sent = sock->stats.packets_sent; - if (packets_received) *packets_received = sock->stats.packets_received; - if (bytes_sent) *bytes_sent = sock->stats.bytes_sent; - if (bytes_received) *bytes_received = sock->stats.bytes_received; - if (send_errors) *send_errors = sock->stats.send_errors; - if (recv_errors) *recv_errors = sock->stats.recv_errors; -} - -// Reset socket statistics -void test_udp_socket_reset_stats(struct test_udp_socket* sock) { - if (!sock) return; - - memset(&sock->stats, 0, sizeof(sock->stats)); - DEBUG_INFO(DEBUG_CATEGORY_TEST, "Reset statistics for virtual UDP socket fd=%d", sock->fd); -} - -// Global virtual socket registry for fd-based operations -struct test_udp_socket* test_udp_socket_find_by_fd(int fd) { - pthread_mutex_lock(&g_registry_mutex); - struct test_udp_socket* sock = NULL; - if (fd >= 0 && fd < 1024) { - sock = g_socket_registry[fd]; - } - pthread_mutex_unlock(&g_registry_mutex); - return sock; -} - -void test_udp_socket_register(struct test_udp_socket* sock) { - if (!sock) return; - - pthread_mutex_lock(&g_registry_mutex); - if (sock->fd >= 0 && sock->fd < 1024) { - g_socket_registry[sock->fd] = sock; - } - pthread_mutex_unlock(&g_registry_mutex); -} - -void test_udp_socket_unregister(struct test_udp_socket* sock) { - if (!sock) return; - - pthread_mutex_lock(&g_registry_mutex); - if (sock->fd >= 0 && sock->fd < 1024) { - g_socket_registry[sock->fd] = NULL; - } - pthread_mutex_unlock(&g_registry_mutex); -} \ No newline at end of file diff --git a/!/test_udp_socket.h b/!/test_udp_socket.h deleted file mode 100755 index e65436f0..00000000 --- a/!/test_udp_socket.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef TEST_UDP_SOCKET_H -#define TEST_UDP_SOCKET_H - -#include -#include -#include -#include - -#define TEST_UDP_MAX_PACKET_SIZE 65536 -#define TEST_UDP_MAX_QUEUE_SIZE 1000 - -// Test UDP packet structure -struct test_udp_packet { - uint8_t* data; - size_t len; - struct sockaddr_storage addr; - socklen_t addr_len; - struct test_udp_packet* next; -}; - -// Virtual UDP socket for testing -struct test_udp_socket { - int fd; // Virtual file descriptor - int family; // Address family (AF_INET or AF_INET6) - struct sockaddr_storage local_addr; - bool bound; - bool nonblocking; - - // Receive queue (packets waiting to be read) - struct test_udp_packet* recv_queue_head; - struct test_udp_packet* recv_queue_tail; - size_t recv_queue_size; - - // Statistics - struct { - size_t packets_sent; - size_t packets_received; - size_t bytes_sent; - size_t bytes_received; - size_t send_errors; - size_t recv_errors; - } stats; - - // Callback for outgoing packets - void (*packet_sent)(const uint8_t* data, size_t len, - const struct sockaddr* dest_addr, socklen_t addr_len, - void* context); - - void* context; -}; - -// Create virtual UDP socket -struct test_udp_socket* test_udp_socket_create(int family); - -// Destroy virtual UDP socket -void test_udp_socket_destroy(struct test_udp_socket* sock); - -// Bind virtual socket -int test_udp_socket_bind(struct test_udp_socket* sock, const struct sockaddr* addr, socklen_t len); - -// Set socket options (limited implementation for testing) -int test_udp_socket_setsockopt(struct test_udp_socket* sock, int level, int optname, - const void *optval, socklen_t optlen); - -// Get socket options -int test_udp_socket_getsockopt(struct test_udp_socket* sock, int level, int optname, - void *optval, socklen_t *optlen); - -// Set non-blocking mode -int test_udp_socket_set_nonblocking(struct test_udp_socket* sock, bool nonblocking); - -// Send packet using virtual socket -ssize_t test_udp_socket_sendto(struct test_udp_socket* sock, const void *buf, size_t len, int flags, - const struct sockaddr *dest_addr, socklen_t addr_len); - -// Receive packet from virtual socket -ssize_t test_udp_socket_recvfrom(struct test_udp_socket* sock, void *buf, size_t len, int flags, - struct sockaddr *src_addr, socklen_t *addr_len); - -// Inject packet into receive queue (simulates incoming packet) -int test_udp_socket_inject(struct test_udp_socket* sock, - const uint8_t* data, size_t len, - const struct sockaddr* src_addr, socklen_t addr_len); - -// Get virtual socket file descriptor -int test_udp_socket_get_fd(struct test_udp_socket* sock); - -// Get socket statistics -void test_udp_socket_get_stats(struct test_udp_socket* sock, size_t* packets_sent, - size_t* packets_received, size_t* bytes_sent, - size_t* bytes_received, size_t* send_errors, size_t* recv_errors); - -// Reset socket statistics -void test_udp_socket_reset_stats(struct test_udp_socket* sock); - -// Global virtual socket registry for fd-based operations -struct test_udp_socket* test_udp_socket_find_by_fd(int fd); -void test_udp_socket_register(struct test_udp_socket* sock); -void test_udp_socket_unregister(struct test_udp_socket* sock); - -#endif // TEST_UDP_SOCKET_H \ No newline at end of file diff --git a/!/test_virtual_tun.c b/!/test_virtual_tun.c deleted file mode 100755 index 5194227c..00000000 --- a/!/test_virtual_tun.c +++ /dev/null @@ -1,190 +0,0 @@ -#include "test_virtual_tun.h" -#include "../lib/debug_config.h" -#include -#include -#include -#include -#include -#include - -#ifndef DEBUG_CATEGORY_TEST -#define DEBUG_CATEGORY_TEST (1 << 30) -#endif - -// Create virtual TUN with bidirectional pipes -struct virtual_tun* virtual_tun_create(const char* ifname) { - if (!ifname) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "NULL interface name provided"); - return NULL; - } - - struct virtual_tun* vtun = calloc(1, sizeof(struct virtual_tun)); - if (!vtun) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to allocate virtual TUN"); - return NULL; - } - - // Copy interface name - strncpy(vtun->ifname, ifname, sizeof(vtun->ifname) - 1); - vtun->ifname[sizeof(vtun->ifname) - 1] = '\0'; - vtun->enabled = true; - - // Create pipes for bidirectional communication - // read_pipe: [0] = read end, [1] = write end (for packets from network) - // write_pipe: [0] = read end, [1] = write end (for packets to network) - if (pipe(vtun->read_pipe) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to create read pipe: %s", strerror(errno)); - free(vtun); - return NULL; - } - - if (pipe(vtun->write_pipe) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to create write pipe: %s", strerror(errno)); - close(vtun->read_pipe[0]); - close(vtun->read_pipe[1]); - free(vtun); - return NULL; - } - - // Set non-blocking mode on pipe ends - for (int i = 0; i < 2; i++) { - int flags = fcntl(vtun->read_pipe[i], F_GETFL, 0); - if (flags == -1 || fcntl(vtun->read_pipe[i], F_SETFL, flags | O_NONBLOCK) < 0) { - DEBUG_WARN(DEBUG_CATEGORY_TEST, "Failed to set non-blocking on read pipe[%d]: %s", i, strerror(errno)); - } - - flags = fcntl(vtun->write_pipe[i], F_GETFL, 0); - if (flags == -1 || fcntl(vtun->write_pipe[i], F_SETFL, flags | O_NONBLOCK) < 0) { - DEBUG_WARN(DEBUG_CATEGORY_TEST, "Failed to set non-blocking on write pipe[%d]: %s", i, strerror(errno)); - } - } - - DEBUG_INFO(DEBUG_CATEGORY_TEST, "Virtual TUN created: %s (read_fd=%d, write_fd=%d)", - vtun->ifname, vtun->read_pipe[0], vtun->write_pipe[1]); - - return vtun; -} - -// Cleanup virtual TUN -void virtual_tun_destroy(struct virtual_tun* vtun) { - if (!vtun) return; - - DEBUG_INFO(DEBUG_CATEGORY_TEST, "Destroying virtual TUN: %s (stats: sent=%zu packets/%zu bytes, recv=%zu packets/%zu bytes)", - vtun->ifname, vtun->stats.packets_sent, vtun->stats.bytes_sent, - vtun->stats.packets_received, vtun->stats.bytes_received); - - // Close all pipe file descriptors - if (vtun->read_pipe[0] >= 0) close(vtun->read_pipe[0]); - if (vtun->read_pipe[1] >= 0) close(vtun->read_pipe[1]); - if (vtun->write_pipe[0] >= 0) close(vtun->write_pipe[0]); - if (vtun->write_pipe[1] >= 0) close(vtun->write_pipe[1]); - - free(vtun); -} - -// Get file descriptor for reading (simulates TUN device read) -int virtual_tun_get_read_fd(struct virtual_tun* vtun) { - if (!vtun || !vtun->enabled) return -1; - return vtun->read_pipe[0]; // Read end of read pipe -} - -// Get file descriptor for writing (simulates TUN device write) -int virtual_tun_get_write_fd(struct virtual_tun* vtun) { - if (!vtun || !vtun->enabled) return -1; - return vtun->write_pipe[1]; // Write end of write pipe -} - -// Inject packet into virtual TUN (simulates packet from network) -int virtual_tun_inject_packet(struct virtual_tun* vtun, const uint8_t* packet, size_t len) { - if (!vtun || !vtun->enabled || !packet || len == 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Invalid parameters for packet injection"); - return -1; - } - - if (len > VIRTUAL_TUN_MAX_PACKET_SIZE) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Packet too large: %zu > %d", len, VIRTUAL_TUN_MAX_PACKET_SIZE); - return -1; - } - - // Write packet to read pipe (simulates packet arriving from network) - ssize_t written = write(vtun->read_pipe[1], packet, len); - if (written < 0) { - if (errno != EAGAIN && errno != EWOULDBLOCK) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to inject packet: %s", strerror(errno)); - } - return -1; - } - - vtun->stats.packets_received++; - vtun->stats.bytes_received += written; - - DEBUG_DEBUG(DEBUG_CATEGORY_TEST, "Injected packet into %s: %zu bytes", vtun->ifname, written); - return 0; -} - -// Read packet from virtual TUN (captures packets going to network) -ssize_t virtual_tun_read_packet(struct virtual_tun* vtun, uint8_t* buffer, size_t max_len) { - if (!vtun || !vtun->enabled || !buffer || max_len == 0) { - return -1; - } - - // Read from write pipe (captures packets going to network) - ssize_t bytes_read = read(vtun->write_pipe[0], buffer, max_len); - if (bytes_read < 0) { - if (errno != EAGAIN && errno != EWOULDBLOCK) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to read packet: %s", strerror(errno)); - } - return -1; - } - - if (bytes_read > 0) { - vtun->stats.packets_sent++; - vtun->stats.bytes_sent += bytes_read; - DEBUG_DEBUG(DEBUG_CATEGORY_TEST, "Read packet from %s: %zu bytes", vtun->ifname, bytes_read); - } - - return bytes_read; -} - -// Write packet to virtual TUN (sends packet to network) -ssize_t virtual_tun_write_packet(struct virtual_tun* vtun, const uint8_t* packet, size_t len) { - if (!vtun || !vtun->enabled || !packet || len == 0) { - return -1; - } - - if (len > VIRTUAL_TUN_MAX_PACKET_SIZE) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Packet too large: %zu > %d", len, VIRTUAL_TUN_MAX_PACKET_SIZE); - return -1; - } - - // Write packet to write pipe (sends to network) - ssize_t written = write(vtun->write_pipe[1], packet, len); - if (written < 0) { - if (errno != EAGAIN && errno != EWOULDBLOCK) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to write packet: %s", strerror(errno)); - } - return -1; - } - - DEBUG_DEBUG(DEBUG_CATEGORY_TEST, "Wrote packet to %s: %zu bytes", vtun->ifname, written); - return written; -} - -// Get virtual TUN statistics -void virtual_tun_get_stats(struct virtual_tun* vtun, size_t* packets_sent, size_t* packets_received, - size_t* bytes_sent, size_t* bytes_received) { - if (!vtun) return; - - if (packets_sent) *packets_sent = vtun->stats.packets_sent; - if (packets_received) *packets_received = vtun->stats.packets_received; - if (bytes_sent) *bytes_sent = vtun->stats.bytes_sent; - if (bytes_received) *bytes_received = vtun->stats.bytes_received; -} - -// Reset virtual TUN statistics -void virtual_tun_reset_stats(struct virtual_tun* vtun) { - if (!vtun) return; - - memset(&vtun->stats, 0, sizeof(vtun->stats)); - DEBUG_INFO(DEBUG_CATEGORY_TEST, "Reset statistics for virtual TUN: %s", vtun->ifname); -} \ No newline at end of file diff --git a/!/test_virtual_tun.h b/!/test_virtual_tun.h deleted file mode 100755 index 8f41b5a9..00000000 --- a/!/test_virtual_tun.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef TEST_VIRTUAL_TUN_H -#define TEST_VIRTUAL_TUN_H - -#include -#include -#include -#include - -#define VIRTUAL_TUN_MAX_PACKET_SIZE 65536 - -struct virtual_tun { - int read_pipe[2]; // [0] = read end, [1] = write end - int write_pipe[2]; // [0] = read end, [1] = write end - char ifname[32]; // Virtual interface name - bool enabled; - void* test_context; // For callbacks - - // Statistics - struct { - size_t packets_sent; - size_t packets_received; - size_t bytes_sent; - size_t bytes_received; - } stats; -}; - -// Create virtual TUN with bidirectional pipes -struct virtual_tun* virtual_tun_create(const char* ifname); - -// Cleanup virtual TUN -void virtual_tun_destroy(struct virtual_tun* vtun); - -// Get file descriptor for reading (simulates TUN device) -int virtual_tun_get_read_fd(struct virtual_tun* vtun); - -// Get file descriptor for writing (simulates TUN device) -int virtual_tun_get_write_fd(struct virtual_tun* vtun); - -// Inject packet into virtual TUN (simulates packet from network) -int virtual_tun_inject_packet(struct virtual_tun* vtun, const uint8_t* packet, size_t len); - -// Read packet from virtual TUN (captures packets going to network) -ssize_t virtual_tun_read_packet(struct virtual_tun* vtun, uint8_t* buffer, size_t max_len); - -// Write packet to virtual TUN (sends packet to network) -ssize_t virtual_tun_write_packet(struct virtual_tun* vtun, const uint8_t* packet, size_t len); - -// Get virtual TUN statistics -void virtual_tun_get_stats(struct virtual_tun* vtun, size_t* packets_sent, size_t* packets_received, - size_t* bytes_sent, size_t* bytes_received); - -// Reset virtual TUN statistics -void virtual_tun_reset_stats(struct virtual_tun* vtun); - -#endif // TEST_VIRTUAL_TUN_H \ No newline at end of file diff --git a/!/tun_if.c b/!/tun_if.c deleted file mode 100755 index 7e36fb58..00000000 --- a/!/tun_if.c +++ /dev/null @@ -1,339 +0,0 @@ -// tun_if.c - TUN interface management implementation -#define _POSIX_C_SOURCE 200809L -#include "tun_if.h" -#include "../lib/debug_config.h" -#include "routing.h" -#include "../lib/u_async.h" -#include "etcp_connections.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Create TUN device -static int create_tun_device(char *ifname, size_t ifname_len) { - struct ifreq ifr; - int fd; - - fd = open("/dev/net/tun", O_RDWR); - if (fd < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to open /dev/net/tun: %s", strerror(errno)); - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TUN | IFF_NO_PI; - - if (ifname && ifname_len > 0 && ifname[0] != '\0') { - strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); - } - - if (ioctl(fd, TUNSETIFF, &ifr) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to configure TUN device: %s", strerror(errno)); - close(fd); - return -1; - } - - if (ifname && ifname_len > 0) { - strncpy(ifname, ifr.ifr_name, ifname_len - 1); - ifname[ifname_len - 1] = '\0'; - } - - return fd; -} - -// Run system command -static int run_command(const char *cmd) { - int ret = system(cmd); - if (ret == -1) { - perror("system"); - return -1; - } - if (WIFEXITED(ret) && WEXITSTATUS(ret) != 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Command failed: %s", cmd); - return -1; - } - return 0; -} - -// Parse IP address and mask -static int parse_ip_mask(const char *ip_addr, char *ip, size_t ip_len, int *mask) { - if (!ip_addr || !ip || !mask) return -1; - - char *slash = strchr(ip_addr, '/'); - if (!slash) { - // Default mask /32 - *mask = 32; - strncpy(ip, ip_addr, ip_len - 1); - ip[ip_len - 1] = '\0'; - } else { - size_t ip_size = slash - ip_addr; - if (ip_size >= ip_len) return -1; - strncpy(ip, ip_addr, ip_size); - ip[ip_size] = '\0'; - - char *endptr; - long mask_val = strtol(slash + 1, &endptr, 10); - if (*endptr != '\0' || mask_val < 0 || mask_val > 32) return -1; - *mask = (int)mask_val; - } - - return 0; -} - -int tun_create(struct tun_config *config) { - if (!config) { - errno = EINVAL; - return -1; - } - - // Create TUN device - int fd = create_tun_device(config->ifname, sizeof(config->ifname)); - if (fd < 0) { - return -1; - } - - config->fd = fd; - - // Configure IP if specified - if (config->ip_addr[0] != '\0') { - if (tun_set_ip(config->ifname, config->ip_addr) < 0) { - close(fd); - return -1; - } - } - - // Set MTU if specified - if (config->mtu > 0) { - if (tun_set_mtu(config->ifname, config->mtu) < 0) { - DEBUG_WARN(DEBUG_CATEGORY_TUN, "Failed to set MTU %d on %s: %s", config->mtu, config->ifname, strerror(errno)); - } - } - - // Bring interface up - if (tun_set_up(config->ifname) < 0) { - close(fd); - return -1; - } - - config->is_up = 1; - return 0; -} - -int tun_set_ip(const char *ifname, const char *ip_addr) { - if (!ifname || !ip_addr) { - errno = EINVAL; - return -1; - } - - char ip[64]; - int mask; - if (parse_ip_mask(ip_addr, ip, sizeof(ip), &mask) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Invalid IP address format: %s", ip_addr); - errno = EINVAL; - return -1; - } - - char cmd[256]; - snprintf(cmd, sizeof(cmd), "ip addr add %s dev %s", ip_addr, ifname); - if (run_command(cmd) < 0) { - return -1; - } - - return 0; -} - -int tun_set_up(const char *ifname) { - if (!ifname) { - errno = EINVAL; - return -1; - } - - char cmd[256]; - snprintf(cmd, sizeof(cmd), "ip link set %s up", ifname); - if (run_command(cmd) < 0) { - return -1; - } - - return 0; -} - -int tun_set_mtu(const char *ifname, int mtu) { - if (!ifname || mtu <= 0) { - errno = EINVAL; - return -1; - } - - char cmd[256]; - snprintf(cmd, sizeof(cmd), "ip link set %s mtu %d", ifname, mtu); - if (run_command(cmd) < 0) { - return -1; - } - - return 0; -} - -ssize_t tun_read(int fd, uint8_t *buffer, size_t size) { - if (fd < 0 || !buffer || size == 0) { - errno = EINVAL; - return -1; - } - - ssize_t nread = read(fd, buffer, size); - if (nread < 0) { - perror("tun_read"); - } - - return nread; -} - -ssize_t tun_write(int fd, const uint8_t *buffer, size_t size) { - if (fd < 0 || !buffer || size == 0) { - errno = EINVAL; - return -1; - } - - ssize_t nwritten = write(fd, buffer, size); - if (nwritten < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to write to TUN device fd=%d: %s", fd, strerror(errno)); - } - - return nwritten; -} - -void tun_close(struct tun_config *config) { - if (!config) return; - - if (config->fd >= 0) { - close(config->fd); - config->fd = -1; - } - - config->is_up = 0; -} - -int tun_get_config(const char *ifname, struct tun_config *config) { - if (!ifname || !config) { - errno = EINVAL; - return -1; - } - - // TODO: Implement reading current interface configuration - // This would require parsing ip addr show output - - memset(config, 0, sizeof(*config)); - strncpy(config->ifname, ifname, sizeof(config->ifname) - 1); - config->fd = -1; - - return 0; -} - -// Extract destination IPv4 address from packet -static uint32_t tun_get_dest_ip(const uint8_t *packet, size_t len) { - if (len < 20) return 0; // Minimum IPv4 header size - // Check IP version (first nibble) - uint8_t version = (packet[0] >> 4) & 0x0F; - if (version != 4) return 0; - // Destination IP is at offset 16 - uint32_t dest_ip; - memcpy(&dest_ip, packet + 16, 4); - return dest_ip; -} - -// Extract destination IPv4 address from packet -static uint32_t get_dest_ip(const uint8_t *packet, size_t len) { - if (len < 20) return 0; // Minimum IPv4 header size - // Check IP version (first nibble) - uint8_t version = (packet[0] >> 4) & 0x0F; - if (version != 4) return 0; - // Destination IP is at offset 16 - uint32_t dest_ip; - memcpy(&dest_ip, packet + 16, 4); - return dest_ip; -} - - -// Callback for TUN device read events -void tun_read_callback(int fd, void* user_arg) { - struct UTUN_INSTANCE *instance = (struct UTUN_INSTANCE*)user_arg; - uint8_t buffer[MAX_PACKET_SIZE]; - - // Read from TUN device - ssize_t nread = tun_read(fd, buffer, sizeof(buffer)); - if (nread < 0) { - if (errno == EINTR) return; - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to read from TUN device %s: %s", instance->tun.ifname, strerror(errno)); - return; - } - - if (nread > 0) { - // Route packet based on destination IP - uint32_t dest_ip = get_dest_ip(buffer, nread); - struct route_entry route; - - if (routing_table_lookup(instance->routing_table, dest_ip, &route)) { - // Found route, send to next hop connection - if (route.next_hop) { - struct sockaddr_in dest_addr; - memset(&dest_addr, 0, sizeof(dest_addr)); - dest_addr.sin_family = AF_INET; - dest_addr.sin_addr.s_addr = route.next_hop_ip; -// todo: отправлять в модуль роутинга все входящие пакеты. когда этот модуль будет. модуль роутинга это не роутинг таблица (routing.h) -// if (etcp_connections_send(route.next_hop, buffer, nread, (struct sockaddr*)&dest_addr, sizeof(dest_addr)) < 0) { -// DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to send packet via route"); -// } - } else { - // Local route - no forwarding needed - DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "Local packet, no forwarding"); - } - } else { - // No route found, drop packet - char ip_str[16]; - ip_to_string(dest_ip, ip_str); - DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "No route for destination IP %s", ip_str); - } - } -} - -// Register sockets with uasync -int utun_instance_register_sockets(struct UTUN_INSTANCE *instance) { - if (!instance || !instance->ua || instance->tun.fd < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Invalid instance or TUN fd"); - return -1; - } - - // Register TUN file descriptor - instance->tun_socket_id = uasync_add_socket(instance->ua, instance->tun.fd, - tun_read_callback, NULL, NULL, instance); - if (!instance->tun_socket_id) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to register TUN socket"); - return -1; - } - - DEBUG_INFO(DEBUG_CATEGORY_TUN, "Registered TUN socket (fd=%d)", instance->tun.fd); - return 0; -} - -// Unregister sockets -void utun_instance_unregister_sockets(struct UTUN_INSTANCE *instance) { - if (!instance || !instance->ua) return; - - if (instance->tun_socket_id) { - uasync_remove_socket(instance->ua, instance->tun_socket_id); - instance->tun_socket_id = NULL; - DEBUG_INFO(DEBUG_CATEGORY_TUN, "Unregistered TUN socket: %s", instance->tun.ifname); - } -} - diff --git a/!/tun_if.h b/!/tun_if.h deleted file mode 100755 index 37f8954b..00000000 --- a/!/tun_if.h +++ /dev/null @@ -1,107 +0,0 @@ -// tun_if.h - TUN interface management for utun -#ifndef TUN_IF_H -#define TUN_IF_H - -#include -#include -#include - -// Forward declarations -struct UTUN_INSTANCE; - -#ifdef __cplusplus -extern "C" { -#endif - -#define MAX_PACKET_SIZE 1500 - -// TUN interface configuration -struct tun_config { - char ifname[16]; // Interface name (e.g., "tun12") - char ip_addr[64]; // IP address with mask (e.g., "10.0.0.1/24") - int mtu; // MTU size - int fd; // File descriptor - uint8_t is_up; // 1 if interface is up - // 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 -}; - -/** - * @brief Create and configure TUN interface - * @param config TUN configuration (ifname can be empty for auto) - * @return 0 on success, -1 on error - */ -int tun_create(struct tun_config *config); - -/** - * @brief Configure IP address on TUN interface - * @param ifname Interface name - * @param ip_addr IP address with mask (e.g., "10.0.0.1/24") - * @return 0 on success, -1 on error - */ -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(struct tun_config *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, struct tun_config *config); - -int utun_instance_register_sockets(struct UTUN_INSTANCE *instance); -void utun_instance_unregister_sockets(struct UTUN_INSTANCE *instance); - -// TUN callback function -void tun_read_callback(int fd, void* user_arg); - - -#ifdef __cplusplus -} -#endif - -#endif /* TUN_IF_H */ \ No newline at end of file diff --git a/!/utun.c b/!/utun.c deleted file mode 100755 index 13aa09c7..00000000 --- a/!/utun.c +++ /dev/null @@ -1,321 +0,0 @@ -// utun.c - Main application for utun VPN tunnel -#define _DEFAULT_SOURCE -#define _POSIX_C_SOURCE 200809L -#include "config_parser.h" -#include "etcp_connections.h" -#include "tun_if.h" -#include "secure_channel.h" -#include "routing.h" -#include "utun_instance.h" -#include "u_async.h" -#include "debug_config.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -/* - -Архитектура: -main -> init utun instnaces -> mainloop() - -utun instances: можно stop() - он ывзывает закрытие всех etcp (etcp_close) которые вызовут закрытие подключений), вызывает закрытие всех etcp сокетов - - - -*/ - - - -// Global wakeup pipe write fd for signal handler -static int g_wakeup_pipe_write_fd = -1; - -#define DEFAULT_CONFIG "utun.conf" -#define DEFAULT_PIDFILE "/var/run/utun.pid" - -// Command line arguments -typedef struct { - char *config_file; - char *pid_file; - char *log_file; - char *debug_config; - int foreground; - int help; -} cmd_args_t; - -// Global state - - - - - -// Parse subnet string -static int parse_subnet(const char *subnet_str, uint32_t *network, uint8_t *prefix_length) { - if (!subnet_str || !network || !prefix_length) return -1; - char ip[64]; - int prefix; - if (sscanf(subnet_str, "%[^/]/%d", ip, &prefix) != 2) return -1; - if (prefix < 0 || prefix > 32) return -1; - struct in_addr addr; - if (inet_pton(AF_INET, ip, &addr) != 1) return -1; - *network = addr.s_addr; - *prefix_length = (uint8_t)prefix; - return 0; -} - -// Extract destination IPv4 address from packet -static uint32_t get_dest_ip(const uint8_t *packet, size_t len) { - if (len < 20) return 0; // Minimum IPv4 header size - // Check IP version (first nibble) - uint8_t version = (packet[0] >> 4) & 0x0F; - if (version != 4) return 0; - // Destination IP is at offset 16 - uint32_t dest_ip; - memcpy(&dest_ip, packet + 16, 4); - return dest_ip; -} - - -// Parse command line arguments -static void parse_args(int argc, char *argv[], cmd_args_t *args) { - memset(args, 0, sizeof(*args)); - args->config_file = DEFAULT_CONFIG; - args->pid_file = DEFAULT_PIDFILE; - args->log_file = NULL; - args->debug_config = NULL; - args->foreground = 0; - args->help = 0; - - static struct option long_options[] = { - {"config", required_argument, 0, 'c'}, - {"pidfile", required_argument, 0, 'p'}, - {"log", required_argument, 0, 'l'}, - {"debug", required_argument, 0, 'd'}, - {"foreground", no_argument, 0, 'f'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0} - }; - - int opt; - int option_index = 0; - - while ((opt = getopt_long(argc, argv, "c:p:l:d:fh", - long_options, &option_index)) != -1) { - switch (opt) { - case 'c': - args->config_file = optarg; - break; - case 'p': - args->pid_file = optarg; - break; - case 'l': - args->log_file = optarg; - break; - case 'f': - args->foreground = 1; - break; - case 'd': - args->debug_config = optarg; - break; - case 'h': - args->help = 1; - break; - default: - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Unknown option: %c", opt); - exit(1); - } - } -} - -// Print usage -static void print_usage(const char *progname) { - printf("Usage: %s [OPTIONS]\n", progname); - printf("Secure VPN tunnel over UDP with TUN interface\n\n"); - printf("Options:\n"); - printf(" -c, --config FILE Configuration file (default: %s)\n", DEFAULT_CONFIG); - printf(" -p, --pidfile FILE PID file (default: %s)\n", DEFAULT_PIDFILE); - printf(" -l, --log FILE Log file (default: stderr)\n"); - printf(" -d, --debug CONFIG Debug configuration (e.g., \"etcp:debug,routing:info\")\n"); - printf(" -f, --foreground Run in foreground (don't daemonize)\n"); - printf(" -h, --help Show this help\n"); - printf("\nExamples:\n"); - printf(" %s -c myconfig.conf\n", progname); - printf(" %s --config server.conf --pidfile /var/run/utun.pid\n", progname); -} - -// Write PID file -static int write_pidfile(const char *pidfile) { - if (!pidfile) return -1; - - FILE *fp = fopen(pidfile, "w"); - if (!fp) { - perror("fopen pidfile"); - return -1; - } - - fprintf(fp, "%d\n", getpid()); - fclose(fp); - return 0; -} - -// Remove PID file -static void remove_pidfile(const char *pidfile) { - if (pidfile) { - unlink(pidfile); - } -} - -// Daemonize process -static int daemonize(void) { - pid_t pid = fork(); - if (pid < 0) { - perror("fork"); - return -1; - } - - if (pid > 0) { - // Parent exits - exit(0); - } - - // Child becomes session leader - if (setsid() < 0) { - perror("setsid"); - return -1; - } - - // Close standard file descriptors - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); - - // Redirect to /dev/null - int fd = open("/dev/null", O_RDWR); - if (fd >= 0) { - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - if (fd > 2) close(fd); - } - - return 0; -} - -// Open log file -static FILE* open_logfile(const char *logfile) { - if (!logfile) return stderr; - - FILE *fp = fopen(logfile, "a"); - if (!fp) { - perror("fopen logfile"); - return stderr; - } - - // Set line buffering - setlinebuf(fp); - return fp; -} - - -// Main function - -static volatile sig_atomic_t g_running = 1; -struct UASYNC* main_ua = NULL; - -static void signal_handler(int sig) { - (void)sig; - g_running = 0; - if (main_ua) { - uasync_wakeup(main_ua); - } -} - -int main(int argc, char *argv[]) { - cmd_args_t args; - parse_args(argc, argv, &args); - - if (args.help) { - print_usage(argv[0]); - return 0; - } - - // Initialize global debug system early if configured from command line - if (args.debug_config) { - debug_config_init(); - if (debug_parse_config(args.debug_config) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Invalid debug configuration: %s", args.debug_config); - return 1; - } - } - - // Create uasync instance - struct UASYNC* ua = uasync_create(); - main_ua=ua; - if (!ua) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to create uasync instance"); - return 1; - } - - // Create and initialize instance - struct UTUN_INSTANCE *instance = utun_instance_create(ua, args.config_file, args.log_file); - if (!instance) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to create UTUN instance"); - return 1; - } - - // Print config for debugging - if (args.foreground) { - print_config(instance->config); - } - - // Initialize all components (TUN, routing, connections) - if (utun_instance_init(instance) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to initialize instance"); - utun_instance_destroy(instance); - return 1; - } - - // Register sockets with uasync - if (utun_instance_register_sockets(instance) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to register sockets"); - utun_instance_destroy(instance); - return 1; - } - - // Setup signal handlers - signal(SIGINT, signal_handler); - signal(SIGTERM, signal_handler); - signal(SIGHUP, signal_handler); - - // Daemonize if not in foreground - if (!args.foreground) { - if (daemonize() < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to daemonize"); - utun_instance_destroy(instance); - return 1; - } - } - - // Write PID file - if (write_pidfile(args.pid_file) < 0) { - utun_instance_destroy(instance); - return 1; - } - - while (instance->running) uasync_poll(ua, 100); - - // Cleanup - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Shutdown"); - - utun_instance_unregister_sockets(instance); - utun_instance_destroy(instance); - remove_pidfile(args.pid_file); - - return 0; -} diff --git a/!/utun.conf b/!/utun.conf deleted file mode 100755 index 7c60c68b..00000000 --- a/!/utun.conf +++ /dev/null @@ -1,42 +0,0 @@ -[global] -tun_ip=10.0.0.1 -mtu=1500 # MTU for all connections (0 = use default 1500) -control_ip=127.0.0.1 -control_port=12345 -net_debug=0 - -my_node_id=61be9d4cd3c60c2d -my_private_key=1313912e5d34768983b0e06530a48c77816d228a5b5605e1ab3dc443d107a3dc -my_public_key= - - -[routing] -allowed_subnet=10.0.0.0/24 -allowed_subnet=10.22.0.0/16 -allowed_subnet=10.23.0.0/16 -my_subnet=10.23.5.0/24 -my_subnet=10.23.6.0/24 - -# мои адреса и каналы -[server: lo0_test] -addr=127.0.0.1:1330 -#so_mark=100 -#netif=eth0 -type=nat # public / nat / private - -[server: lan1] -addr=192.168.29.117:1333 -so_mark=100 -netif=eth0 -type=public # public / nat / private - -[client: client_test1] - -# линки -link=lo0_test:192.168.0.20:1234 -#link=wired1_fast:1.2.3.4:1234 -link=lan1:192.168.0.20:1234 -#link=wireless_bkp:1.2.3.4:1234 - -keepalive=1 -peer_public_key=deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbee \ No newline at end of file diff --git a/!/utun_instance.c b/!/utun_instance.c deleted file mode 100755 index fc29a12f..00000000 --- a/!/utun_instance.c +++ /dev/null @@ -1,388 +0,0 @@ -// utun_instance.c - Root instance implementation -#include "utun_instance.h" -#include "config_parser.h" -#include "config_updater.h" -#include "tun_if.h" -#include "routing.h" -#include "etcp_connections.h" -#include "etcp.h" -#include "utun_test_hooks.h" -#include "../lib/u_async.h" -#include "../lib/debug_config.h" -#include -#include -#include -#include -#include -#include - - - -// Forward declarations -static uint32_t get_dest_ip(const uint8_t *packet, size_t len); - - - -// Global instance for signal handlers -static struct UTUN_INSTANCE *g_instance = NULL; - -// Create and initialize root instance with extended flags -struct UTUN_INSTANCE* utun_instance_create_ex(struct UASYNC* ua, const char *config_file, const char *log_file, uint32_t flags) { - struct UTUN_INSTANCE *instance = calloc(1, sizeof(struct UTUN_INSTANCE)); - if (!instance) return NULL; - - // Initialize basic fields - instance->running = 0; - instance->log_fp = NULL; - instance->ua = ua; - - // Note: Global debug system is initialized from command line arguments if provided - // If not initialized via command line, instance-specific logging can be set up here - // The first initialization wins - either global (from main) or instance-specific - - // Ensure keys and node_id exist in config - if (config_ensure_keys_and_node_id(config_file) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to ensure keys and node_id in config: %s", config_file); - free(instance); - return NULL; - } - - // Load configuration - instance->config = parse_config(config_file); - if (!instance->config) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to load config from %s", config_file); - free(instance); - return NULL; - } - - // Open log file only if not using global debug system output - if (log_file && !g_debug_config.output_file) { - instance->log_fp = fopen(log_file, "a"); - if (!instance->log_fp) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to open log file %s: %s", log_file, strerror(errno)); - } - } - // Set node_id from config - instance->node_id = instance->config->global.my_node_id; - - // Set my keys - if (sc_init_local_keys(&instance->my_keys, instance->config->global.my_public_key_hex, instance->config->global.my_private_key_hex)) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to initialize local keys"); - } - - - instance->pkt_pool=memory_pool_init(PACKET_DATA_SIZE+100); - - // Conditional TUN initialization based on flags - if (!(flags & UTUN_CREATE_NO_TUN)) { - int tun_result; - - // Use test hook if available and in test mode - if ((flags & UTUN_CREATE_TEST_MODE) && g_utun_test_hooks && g_utun_test_hooks->tun_create_override) { - tun_result = g_utun_test_hooks->tun_create_override(&instance->tun); - DEBUG_INFO(DEBUG_CATEGORY_TUN, "TUN creation using test hook: result=%d", tun_result); - } else { - tun_result = tun_create(&instance->tun); - } - - if (tun_result < 0) { - if (flags & UTUN_CREATE_ALLOW_TUN_FAILURE) { - DEBUG_WARN(DEBUG_CATEGORY_TUN, "TUN creation failed, continuing without TUN (ALLOW_TUN_FAILURE flag)"); - instance->tun.fd = -1; // Mark as disabled - } else { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to create TUN device"); - free(instance); - return NULL; - } - } else { - // TUN created successfully, configure it - // Configure TUN device IP (BSD: use config IP as-is, Linux/Win: IP/32) - char tun_ip_str[64]; - char ip_buffer[64]; - - // Convert struct IP to string using inet_ntop - if (instance->config->global.tun_ip.family == AF_INET) { - inet_ntop(AF_INET, &instance->config->global.tun_ip.addr.v4, ip_buffer, sizeof(ip_buffer)); - } else { - inet_ntop(AF_INET6, &instance->config->global.tun_ip.addr.v6, ip_buffer, sizeof(ip_buffer)); - } - - #ifdef __linux__ - snprintf(tun_ip_str, sizeof(tun_ip_str), "%s/32", ip_buffer); - #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) - // BSD systems: use config IP as-is, peer IP will be 192.0.2.1 - snprintf(tun_ip_str, sizeof(tun_ip_str), "%s", ip_buffer); - #else - snprintf(tun_ip_str, sizeof(tun_ip_str), "%s/32", ip_buffer); // Default to /32 - #endif - - if (tun_set_ip(instance->tun.ifname, tun_ip_str) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to set TUN IP: %s", tun_ip_str); - tun_close(&instance->tun); - free(instance); - return NULL; - } - - // Set MTU (default 1500) - int mtu = instance->config->global.mtu > 0 ? instance->config->global.mtu : 1500; - if (tun_set_mtu(instance->tun.ifname, mtu) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to set TUN MTU: %d", mtu); - tun_close(&instance->tun); - free(instance); - return NULL; - } - - if (tun_set_up(instance->tun.ifname) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to bring up TUN interface"); - tun_close(&instance->tun); - free(instance); - return NULL; - } - - DEBUG_INFO(DEBUG_CATEGORY_TUN, "TUN interface initialized: %s with IP %s", - instance->tun.ifname, tun_ip_str); - } - } else { - DEBUG_INFO(DEBUG_CATEGORY_TUN, "TUN initialization skipped (NO_TUN flag)"); - instance->tun.fd = -1; // Explicitly disabled - } - - // Create routing table - instance->routing_table = routing_table_create(); - if (!instance->routing_table) { - DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to create routing table"); - tun_close(&instance->tun); - free(instance); - return NULL; - } - // Initialize connections from configuration - moved to utun_instance_init - // to avoid double initialization - /* - if (init_connections(instance) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to initialize connections"); - // Cleanup will be handled by utun_instance_destroy - return NULL; - } - */ - - return instance; -} - -// Destroy instance and cleanup resources -void utun_instance_destroy(struct UTUN_INSTANCE *instance) { - if (!instance) return; - - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Starting cleanup for instance %p", instance); - - // Диагностика ресурсов ДО cleanup - utun_instance_diagnose_leaks(instance, "BEFORE_CLEANUP"); - - // Stop running if not already - instance->running = 0; - - // Unregister all sockets from uasync BEFORE destroying ETCP components - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Unregistering sockets from uasync"); - utun_instance_unregister_sockets(instance); - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Socket unregistration complete"); - - - // Cleanup ETCP sockets and connections FIRST (before destroying uasync) - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Cleaning up ETCP sockets and connections"); - struct ETCP_SOCKET* sock = instance->etcp_sockets; - while (sock) { - struct ETCP_SOCKET* next = sock->next; - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Removing socket %p, fd=%d", sock, sock->fd); - etcp_socket_remove(sock); // Полный cleanup сокета - sock = next; - } - instance->etcp_sockets = NULL; - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] ETCP sockets cleanup complete"); - - struct ETCP_CONN* conn = instance->connections; - while (conn) { - struct ETCP_CONN* next = conn->next; - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Closing connection %p", conn); - etcp_connection_close(conn); // Закрыть соединение - conn = next; - } - instance->connections = NULL; - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] ETCP connections cleanup complete"); - - // Cleanup other components - if (instance->routing_table) { - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Destroying routing table"); - routing_table_destroy(instance->routing_table); - instance->routing_table = NULL; - } - - // Cleanup TUN - if (instance->tun.fd >= 0) { - DEBUG_INFO(DEBUG_CATEGORY_TUN, "Closing TUN interface: %s", instance->tun.ifname); - tun_close(&instance->tun); - } - - // Cleanup config - if (instance->config) { - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Freeing configuration"); - free_config(instance->config); - instance->config = NULL; - } - - // Close log file - if (instance->log_fp) { - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Closing log file"); - fclose(instance->log_fp); - instance->log_fp = NULL; - } - - // Cleanup packet pool (ensure no leak if stop wasn't called) - if (instance->pkt_pool) { - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Destroying packet pool"); - memory_pool_destroy(instance->pkt_pool); - instance->pkt_pool = NULL; - } - - // FINALLY destroy uasync (after all resources are cleaned up) - if (instance->ua) { - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Destroying uasync instance"); - uasync_destroy(instance->ua); - instance->ua = NULL; - } - - // Clear global instance - if (g_instance == instance) { - g_instance = NULL; - } - - // Free the instance memory - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Freeing instance memory"); - free(instance); - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Instance destroyed completely"); -} - -// Stop instance -void utun_instance_stop(struct UTUN_INSTANCE *instance) { - if (!instance) return; - instance->running = 0; - // Wakeup main loop using built-in uasync wakeup - if (instance->ua) { - memory_pool_destroy(instance->pkt_pool); - uasync_wakeup(instance->ua); - } - - -} - -int utun_instance_init(struct UTUN_INSTANCE *instance) { - if (!instance) return -1; - - // Register TUN socket with uasync - if (instance->tun.fd >= 0) { - instance->tun_socket_id = uasync_add_socket(instance->ua, instance->tun.fd, - tun_read_callback, NULL, NULL, instance); - if (!instance->tun_socket_id) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to register TUN socket with uasync"); - return -1; - } - DEBUG_INFO(DEBUG_CATEGORY_TUN, "TUN interface registered: %s (fd=%d)", - instance->tun.ifname, instance->tun.fd); - } - - // Initialize connections - if (init_connections(instance) < 0) { - return -1; - } - - return 0; -} - -// Диагностическая функция для анализа утечек -void utun_instance_diagnose_leaks(struct UTUN_INSTANCE *instance, const char *phase) { - if (!instance) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "[DIAGNOSE] NULL instance for phase: %s", phase); - return; - } - - struct { - int etcp_sockets_count; - int etcp_connections_count; - int etcp_links_count; - } report = {0}; - - // Подсчёт ETCP сокетов - struct ETCP_SOCKET *sock = instance->etcp_sockets; - while (sock) { - report.etcp_sockets_count++; - // Подсчёт линков в каждом сокете - for (size_t i = 0; i < sock->num_channels; i++) { - if (sock->links[i]) { - report.etcp_links_count++; - } - } - sock = sock->next; - } - - // Подсчёт ETCP соединений - struct ETCP_CONN *conn = instance->connections; - while (conn) { - report.etcp_connections_count++; - // Подсчёт линков в соединениях - struct ETCP_LINK *link = conn->links; - while (link) { - report.etcp_links_count++; - link = link->next; - } - conn = conn->next; - } - - printf("\n🔍 [UTUN_INSTANCE LEAK DIAGNOSIS] Phase: %s\n", phase); - printf(" Instance: %p\n", instance); - printf(" Node ID: %llu\n", (unsigned long long)instance->node_id); - printf(" UA instance: %p\n", instance->ua); - printf(" Running: %d\n", instance->running); - - printf("\n📊 STRUCTURE COUNTS:\n"); - printf(" ETCP Sockets: %d active\n", report.etcp_sockets_count); - printf(" ETCP Connections: %d active\n", report.etcp_connections_count); - printf(" ETCP Links: %d total\n", report.etcp_links_count); - - printf("\n🔧 RESOURCE STATUS:\n"); - printf(" Memory Pool: %s\n", instance->pkt_pool ? "ALLOCATED" : "NULL"); - printf(" TUN Socket ID: %p\n", instance->tun_socket_id); - printf(" TUN FD: %d\n", instance->tun.fd); - printf(" Connections list: %p\n", instance->connections); - printf(" ETCP Sockets list: %p\n", instance->etcp_sockets); - - printf("\n⚠️ POTENTIAL LEAKS:\n"); - if (instance->pkt_pool) { - printf(" ❌ Memory Pool not freed\n"); - } - if (instance->tun_socket_id) { - printf(" ❌ TUN socket not unregistered from uasync\n"); - } - if (report.etcp_sockets_count > 0) { - printf(" ❌ %d ETCP sockets still allocated\n", report.etcp_sockets_count); - } - if (report.etcp_connections_count > 0) { - printf(" ❌ %d ETCP connections still allocated\n", report.etcp_connections_count); - } - if (report.etcp_links_count > 0) { - printf(" ❌ %d ETCP links still allocated\n", report.etcp_links_count); - } - - printf("\n📋 RECOMMENDATIONS:\n"); - if (instance->pkt_pool) { - printf(" → Call memory_pool_destroy() before freeing instance\n"); - } - if (instance->tun_socket_id) { - printf(" → Call uasync_remove_socket() for TUN socket\n"); - } - if (report.etcp_sockets_count > 0) { - printf(" → Iterate and call etcp_socket_remove() for each socket\n"); - } - if (report.etcp_connections_count > 0) { - printf(" → Iterate and call etcp_connection_close() for each connection\n"); - } - - printf("\n"); -} diff --git a/!/utun_instance.c.backup b/!/utun_instance.c.backup deleted file mode 100755 index e0dae7ea..00000000 --- a/!/utun_instance.c.backup +++ /dev/null @@ -1,314 +0,0 @@ -// utun_instance.c - Root instance implementation -#include "utun_instance.h" -#include "config_parser.h" -#include "config_updater.h" -#include "tun_if.h" -#include "routing.h" -#include "etcp_connections.h" -#include "etcp.h" -#include "../lib/u_async.h" -#include "../lib/debug_config.h" -#include -#include -#include -#include -#include -#include - -// Forward declarations -static void tun_read_callback(int fd, void* user_arg); -static uint32_t get_dest_ip(const uint8_t *packet, size_t len); - -// Global instance for signal handlers -static struct UTUN_INSTANCE *g_instance = NULL; - -// Create and initialize root instance -struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char *config_file, const char *log_file) { - struct UTUN_INSTANCE *instance = calloc(1, sizeof(struct UTUN_INSTANCE)); - if (!instance) return NULL; - - // Initialize basic fields - instance->running = 0; - instance->log_fp = NULL; - instance->ua = ua; - - // Ensure keys and node_id exist in config - if (config_ensure_keys_and_node_id(config_file) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to ensure keys and node_id in config: %s", config_file); - free(instance); - return NULL; - } - - // Load configuration - instance->config = parse_config(config_file); - if (!instance->config) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to load config from %s", config_file); - free(instance); - return NULL; - } - - // Open log file - if (log_file) { - instance->log_fp = fopen(log_file, "a"); - if (!instance->log_fp) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to open log file %s: %s", log_file, strerror(errno)); - } - } - // Set node_id from config - instance->node_id = instance->config->global.my_node_id; - - // Set my keys - if (sc_init_local_keys(&instance->my_keys, instance->config->global.my_public_key_hex, instance->config->global.my_private_key_hex)) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to initialize local keys"); - } - - - instance->pkt_pool=memory_pool_init(PACKET_DATA_SIZE+100); -/* - // Initialize TUN device - if (tun_create(&instance->tun) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to create TUN device"); - return -1; - } - - // Configure TUN device - if (tun_set_ip(instance->tun.ifname, instance->config->global.tun_ip) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to set TUN IP"); - tun_close(&instance->tun); - return -1; - } - - if (instance->config->global.mtu > 0) { - if (tun_set_mtu(instance->tun.ifname, instance->config->global.mtu) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to set TUN MTU"); - tun_close(&instance->tun); - return -1; - } - } - - if (tun_set_up(instance->tun.ifname) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to bring up TUN interface"); - tun_close(&instance->tun); - return -1; - } - - // Create routing table - instance->routing_table = routing_table_create(); - if (!instance->routing_table) { - DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to create routing table"); - return -1; - } -*/ - // Initialize connections from configuration - moved to utun_instance_init - // to avoid double initialization - /* - if (init_connections(instance) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to initialize connections"); - // Cleanup will be handled by utun_instance_destroy - return NULL; - } - */ - - return instance; -} - -// Destroy instance and cleanup resources -void utun_instance_destroy(struct UTUN_INSTANCE *instance) { - if (!instance) return; - - printf("[INSTANCE_DESTROY] Starting cleanup for instance %p\n", instance); - - // Диагностика ресурсов ДО cleanup - utun_instance_diagnose_leaks(instance, "BEFORE_CLEANUP"); - - // Stop running if not already - instance->running = 0; - - // Cleanup ETCP sockets and connections FIRST (before destroying uasync) - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Cleaning up ETCP sockets and connections"); - struct ETCP_SOCKET* sock = instance->etcp_sockets; - while (sock) { - struct ETCP_SOCKET* next = sock->next; - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Removing socket %p, fd=%d", sock, sock->fd); - etcp_socket_remove(sock); // Полный cleanup сокета - sock = next; - } - instance->etcp_sockets = NULL; - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] ETCP sockets cleanup complete"); - - struct ETCP_CONN* conn = instance->connections; - while (conn) { - struct ETCP_CONN* next = conn->next; - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Closing connection %p", conn); - etcp_connection_close(conn); // Закрыть соединение - conn = next; - } - instance->connections = NULL; - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] ETCP connections cleanup complete"); - - // Cleanup other components - if (instance->routing_table) { - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Destroying routing table"); - routing_table_destroy(instance->routing_table); - instance->routing_table = NULL; - } - - // Cleanup TUN - if (instance->tun.fd >= 0) { - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Closing TUN interface"); - tun_close(&instance->tun); - } - - // Cleanup config - if (instance->config) { - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Freeing configuration"); - free_config(instance->config); - instance->config = NULL; - } - - // Close log file - if (instance->log_fp) { - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Closing log file"); - fclose(instance->log_fp); - instance->log_fp = NULL; - } - - // Cleanup packet pool (ensure no leak if stop wasn't called) - if (instance->pkt_pool) { - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Destroying packet pool"); - memory_pool_destroy(instance->pkt_pool); - instance->pkt_pool = NULL; - } - - // FINALLY destroy uasync (after all resources are cleaned up) - if (instance->ua) { - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Destroying uasync instance"); - uasync_destroy(instance->ua); - instance->ua = NULL; - } - - // Clear global instance - if (g_instance == instance) { - g_instance = NULL; - } - - // Free the instance memory - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Freeing instance memory"); - free(instance); - DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Instance destroyed completely"); -} - -// Stop instance -void utun_instance_stop(struct UTUN_INSTANCE *instance) { - if (!instance) return; - instance->running = 0; - // Wakeup main loop using built-in uasync wakeup - if (instance->ua) { - memory_pool_destroy(instance->pkt_pool); - uasync_wakeup(instance->ua); - } - - -} - -int utun_instance_init(struct UTUN_INSTANCE *instance) { - if (!instance) return -1; - - // Initialize connections - if (init_connections(instance) < 0) { - return -1; - } - - return 0; -} - -// Диагностическая функция для анализа утечек -void utun_instance_diagnose_leaks(struct UTUN_INSTANCE *instance, const char *phase) { - if (!instance) { - printf("[DIAGNOSE] NULL instance for phase: %s\n", phase); - return; - } - - struct { - int etcp_sockets_count; - int etcp_connections_count; - int etcp_links_count; - } report = {0}; - - // Подсчёт ETCP сокетов - struct ETCP_SOCKET *sock = instance->etcp_sockets; - while (sock) { - report.etcp_sockets_count++; - // Подсчёт линков в каждом сокете - for (size_t i = 0; i < sock->num_channels; i++) { - if (sock->links[i]) { - report.etcp_links_count++; - } - } - sock = sock->next; - } - - // Подсчёт ETCP соединений - struct ETCP_CONN *conn = instance->connections; - while (conn) { - report.etcp_connections_count++; - // Подсчёт линков в соединениях - struct ETCP_LINK *link = conn->links; - while (link) { - report.etcp_links_count++; - link = link->next; - } - conn = conn->next; - } - - printf("\n🔍 [UTUN_INSTANCE LEAK DIAGNOSIS] Phase: %s\n", phase); - printf(" Instance: %p\n", instance); - printf(" Node ID: %llu\n", (unsigned long long)instance->node_id); - printf(" UA instance: %p\n", instance->ua); - printf(" Running: %d\n", instance->running); - - printf("\n📊 STRUCTURE COUNTS:\n"); - printf(" ETCP Sockets: %d active\n", report.etcp_sockets_count); - printf(" ETCP Connections: %d active\n", report.etcp_connections_count); - printf(" ETCP Links: %d total\n", report.etcp_links_count); - - printf("\n🔧 RESOURCE STATUS:\n"); - printf(" Memory Pool: %s\n", instance->pkt_pool ? "ALLOCATED" : "NULL"); - printf(" TUN Socket ID: %p\n", instance->tun_socket_id); - printf(" TUN FD: %d\n", instance->tun.fd); - printf(" Connections list: %p\n", instance->connections); - printf(" ETCP Sockets list: %p\n", instance->etcp_sockets); - - printf("\n⚠️ POTENTIAL LEAKS:\n"); - if (instance->pkt_pool) { - printf(" ❌ Memory Pool not freed\n"); - } - if (instance->tun_socket_id) { - printf(" ❌ TUN socket not unregistered from uasync\n"); - } - if (report.etcp_sockets_count > 0) { - printf(" ❌ %d ETCP sockets still allocated\n", report.etcp_sockets_count); - } - if (report.etcp_connections_count > 0) { - printf(" ❌ %d ETCP connections still allocated\n", report.etcp_connections_count); - } - if (report.etcp_links_count > 0) { - printf(" ❌ %d ETCP links still allocated\n", report.etcp_links_count); - } - - printf("\n📋 RECOMMENDATIONS:\n"); - if (instance->pkt_pool) { - printf(" → Call memory_pool_destroy() before freeing instance\n"); - } - if (instance->tun_socket_id) { - printf(" → Call uasync_remove_socket() for TUN socket\n"); - } - if (report.etcp_sockets_count > 0) { - printf(" → Iterate and call etcp_socket_remove() for each socket\n"); - } - if (report.etcp_connections_count > 0) { - printf(" → Iterate and call etcp_connection_close() for each connection\n"); - } - - printf("\n"); -} diff --git a/!/utun_instance.c1 b/!/utun_instance.c1 deleted file mode 100755 index 2cb5bda3..00000000 --- a/!/utun_instance.c1 +++ /dev/null @@ -1,230 +0,0 @@ -// utun_instance.c - Root instance implementation -#include "utun_instance.h" -#include "config_parser.h" -#include "config_updater.h" -#include "tun_if.h" -#include "routing.h" -#include "etcp_connections.h" -#include "etcp.h" -#include "../lib/u_async.h" -#include "../lib/debug_config.h" -#include -#include -#include -#include -#include -#include - -// Forward declarations -static void tun_read_callback(int fd, void* user_arg); -static uint32_t get_dest_ip(const uint8_t *packet, size_t len); - -// Global instance for signal handlers -static struct UTUN_INSTANCE *g_instance = NULL; - -// Create and initialize root instance -struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char *config_file, const char *log_file) { - struct UTUN_INSTANCE *instance = calloc(1, sizeof(struct UTUN_INSTANCE)); - if (!instance) return NULL; - - // Initialize basic fields - instance->running = 0; - instance->log_fp = NULL; - instance->ua = ua; - - // Ensure keys and node_id exist in config - if (config_ensure_keys_and_node_id(config_file) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to ensure keys and node_id in config: %s", config_file); - free(instance); - return NULL; - } - - // Load configuration - instance->config = parse_config(config_file); - if (!instance->config) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to load config from %s", config_file); - free(instance); - return NULL; - } - - // Open log file - if (log_file) { - instance->log_fp = fopen(log_file, "a"); - if (!instance->log_fp) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to open log file %s: %s", log_file, strerror(errno)); - } - } - // Set node_id from config - instance->node_id = instance->config->global.my_node_id; - - // Set my keys - if (sc_init_local_keys(&instance->my_keys, instance->config->global.my_public_key_hex, instance->config->global.my_private_key_hex)) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to initialize local keys"); - } - - - instance->pkt_pool=memory_pool_init(PACKET_DATA_SIZE+100); -/* - // Initialize TUN device - if (tun_create(&instance->tun) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to create TUN device"); - return -1; - } - - // Configure TUN device - if (tun_set_ip(instance->tun.ifname, instance->config->global.tun_ip) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to set TUN IP"); - tun_close(&instance->tun); - return -1; - } - - if (instance->config->global.mtu > 0) { - if (tun_set_mtu(instance->tun.ifname, instance->config->global.mtu) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to set TUN MTU"); - tun_close(&instance->tun); - return -1; - } - } - - if (tun_set_up(instance->tun.ifname) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to bring up TUN interface"); - tun_close(&instance->tun); - return -1; - } - - // Create routing table - instance->routing_table = routing_table_create(); - if (!instance->routing_table) { - DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to create routing table"); - return -1; - } -*/ - // Initialize connections from configuration - moved to utun_instance_init - // to avoid double initialization - /* - if (init_connections(instance) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to initialize connections"); - // Cleanup will be handled by utun_instance_destroy - return NULL; - } - */ - - return instance; -} - -// Destroy instance and cleanup resources -void utun_instance_destroy(struct UTUN_INSTANCE *instance) { - if (!instance) return; - - printf("[INSTANCE_DESTROY] Starting cleanup for instance %p\n", instance); - - // Stop running - instance->running = 0; - - // Cleanup ETCP sockets and connections FIRST (before destroying uasync) - printf("[INSTANCE_DESTROY] Cleaning up ETCP sockets and connections\n"); - if (instance->etcp_sockets) { - printf("[INSTANCE_DESTROY] Found ETCP sockets to cleanup\n"); - struct ETCP_SOCKET* sock = instance->etcp_sockets; - while (sock) { - struct ETCP_SOCKET* next = sock->next; - printf("[INSTANCE_DESTROY] Removing socket %p, fd=%d\n", sock, sock->fd); - etcp_socket_remove(sock); // Полный cleanup сокета - sock = next; - } - instance->etcp_sockets = NULL; - printf("[INSTANCE_DESTROY] ETCP sockets cleanup complete\n"); - } - - if (instance->connections) { - printf("[INSTANCE_DESTROY] Found ETCP connections to cleanup\n"); - struct ETCP_CONN* conn = instance->connections; - while (conn) { - struct ETCP_CONN* next = conn->next; - printf("[INSTANCE_DESTROY] Closing connection %p\n", conn); - etcp_connection_close(conn); // Закрыть соединение - conn = next; - } - instance->connections = NULL; - printf("[INSTANCE_DESTROY] ETCP connections cleanup complete\n"); - } - - // Cleanup other components - if (instance->routing_table) { - routing_table_destroy(instance->routing_table); - } - - // Cleanup TUN - if (instance->tun.fd >= 0) { - tun_close(&instance->tun); - } - - // Cleanup config - if (instance->config) { - free_config(instance->config); - } - - // Close log file - if (instance->log_fp) { - fclose(instance->log_fp); - } - - // FINALLY destroy uasync (after all resources are cleaned up) - printf("[INSTANCE_DESTROY] Destroying uasync instance\n"); - if (instance->ua) { - uasync_destroy(instance->ua); - } - - // Free the instance memory - printf("[INSTANCE_DESTROY] Freeing instance memory\n"); - free(instance); - printf("[INSTANCE_DESTROY] Instance destroyed completely\n"); - - // Cleanup TUN - if (instance->tun.fd >= 0) { - tun_close(&instance->tun); - } - - // Cleanup config - if (instance->config) { - free_config(instance->config); - } - - // Close log file - if (instance->log_fp) { - fclose(instance->log_fp); - } - - // uasync cleanup will handle its built-in wakeup pipe - - // Clear global instance - if (g_instance == instance) { - g_instance = NULL; - } - - free(instance); -} - -// Stop instance -void utun_instance_stop(struct UTUN_INSTANCE *instance) { - if (!instance) return; - instance->running = 0; - // Wakeup main loop using built-in uasync wakeup - if (instance->ua) { - memory_pool_destroy(instance->pkt_pool); - uasync_wakeup(instance->ua); - } - - -} - -int utun_instance_init(struct UTUN_INSTANCE *instance) { - if (!instance) return -1; - - // Initialize connections - if (init_connections(instance) < 0) { - return -1; - } - - return 0; -} diff --git a/!/utun_instance.h b/!/utun_instance.h deleted file mode 100755 index 57b9e5d6..00000000 --- a/!/utun_instance.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef UTUN_INSTANCE_H -#define UTUN_INSTANCE_H - -#include -#include -#include -#include "../lib/memory_pool.h" -#include "secure_channel.h" -#include "tun_if.h" - -// Forward declarations -struct utun_config; -struct uasync_s; -struct routing_table; -struct ETCP_CONN; -struct ETCP_SOCKET; - -// uTun instance configuration -struct UTUN_INSTANCE { - // Configuration (moved from utun_state) - struct utun_config *config; - - // TUN interface - struct tun_config tun; - void *tun_socket_id; // Socket ID from uasync_add_socket - - // Identification - uint64_t node_id; - - struct SC_MYKEYS my_keys; - - // Main async context - struct UASYNC* ua; - - // State - int running; - FILE *log_fp; - - struct memory_pool* pkt_pool; - // Routing - struct routing_table *routing_table; - - // Connections - struct ETCP_CONN* connections;// linked-list - int connections_count; // Number of connections - - // Active sockets - struct ETCP_SOCKET* etcp_sockets;// linked-list -}; - -// Instance creation flags -#define UTUN_CREATE_ALLOW_TUN_FAILURE 0x0001 // Continue if TUN creation fails -#define UTUN_CREATE_NO_TUN 0x0002 // Skip TUN initialization entirely -#define UTUN_CREATE_TEST_MODE 0x0004 // Enable test hooks and virtual interfaces -#define UTUN_CREATE_NO_SOCKET_BIND 0x0008 // Skip socket binding (for test injection) - -// Functions -struct UTUN_INSTANCE* utun_instance_create_ex(struct UASYNC* ua, const char* config_file, const char* log_file, uint32_t flags); - -// Backward compatibility wrapper -static inline struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char* config_file, const char* log_file) { - return utun_instance_create_ex(ua, config_file, log_file, 0); -} -void utun_instance_destroy(struct UTUN_INSTANCE* instance); -int utun_instance_init(struct UTUN_INSTANCE *instance); -void utun_instance_run(struct UTUN_INSTANCE *instance); -void utun_instance_stop(struct UTUN_INSTANCE *instance); - -// Diagnostic function for memory leak analysis -void utun_instance_diagnose_leaks(struct UTUN_INSTANCE* instance, const char* phase); - -#endif // UTUN_INSTANCE_H diff --git a/!/utun_test_framework.c b/!/utun_test_framework.c deleted file mode 100755 index 6678f2dc..00000000 --- a/!/utun_test_framework.c +++ /dev/null @@ -1,586 +0,0 @@ -#include "utun_test_framework.h" -#include "utun_instance.h" -#include "../lib/u_async.h" -#include "../lib/debug_config.h" -#include "../lib/ll_queue.h" -#include "test_udp_socket.h" -#include -#include -#include -#include -#include -#include -#include - -// External mutex from test_udp_socket.c -extern pthread_mutex_t g_registry_mutex; - -#ifndef DEBUG_CATEGORY_TEST -#define DEBUG_CATEGORY_TEST (1 << 30) -#endif - -// Default test configurations -const struct test_instance_config TEST_SERVER_CONFIG = { - .config_file = "test_server.conf", - .node_id = 0x1111222233334444, - .port_base = 40000, - .enable_tun = false, - .enable_socket_hooks = true, - .enable_packet_capture = true, - .log_file = NULL -}; - -const struct test_instance_config TEST_CLIENT_CONFIG = { - .config_file = "test_client.conf", - .node_id = 0x8888777766665555, - .port_base = 40100, - .enable_tun = false, - .enable_socket_hooks = true, - .enable_packet_capture = true, - .log_file = NULL -}; - -// Forward declarations for internal functions -static int test_tun_create_hook(void* priv_data); -static ssize_t test_tun_read_hook(int fd, void *buf, size_t count, void* priv_data); -static ssize_t test_tun_write_hook(int fd, const void *buf, size_t count, void* priv_data); -static int test_socket_create_hook(int domain, int type, int protocol, void* context); -static void test_packet_capture_hook(struct UTUN_INSTANCE* instance, const uint8_t* packet, size_t len, - const char* direction, void* context); -static void test_cleanup_captured_packets(struct test_instance* test); - -// Create test instance with virtual components -struct test_instance* test_create_instance(const struct test_instance_config* config) { - if (!config) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "NULL configuration provided"); - return NULL; - } - - struct test_instance* test = calloc(1, sizeof(struct test_instance)); - if (!test) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to allocate test instance"); - return NULL; - } - - // Copy configuration - test->config = *config; - - // Create uasync instance - test->ua = uasync_create(); - if (!test->ua) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to create uasync instance"); - free(test); - return NULL; - } - - // Setup test hooks based on configuration - if (config->enable_tun || config->enable_socket_hooks || config->enable_packet_capture) { - test->hooks.test_context = test; - - if (config->enable_tun) { - // Create virtual TUN - char vtun_name[32]; - snprintf(vtun_name, sizeof(vtun_name), "vtun%ld", config->node_id & 0xFFFF); - test->vtun = virtual_tun_create(vtun_name); - if (!test->vtun) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to create virtual TUN"); - uasync_destroy(test->ua); - free(test); - return NULL; - } - - test->hooks.tun_create_override = test_tun_create_hook; - test->hooks.tun_read_override = test_tun_read_hook; - test->hooks.tun_write_override = test_tun_write_hook; - } - - if (config->enable_socket_hooks) { - test->hooks.socket_create_override = test_socket_create_hook; - test->hooks.sendto_override = NULL; // Will be handled by virtual UDP sockets - test->hooks.recvfrom_override = NULL; // Will be handled by virtual UDP sockets - } - - if (config->enable_packet_capture) { - test->hooks.packet_captured = test_packet_capture_hook; - } - - // Install hooks - #ifdef TEST_BUILD - utun_test_hooks_set(&test->hooks); - test->hooks_installed = true; - #endif - } - - // Allocate packet capture buffer - if (config->enable_packet_capture) { - test->captured_packets.capacity = 1000; - test->captured_packets.packets = calloc(test->captured_packets.capacity, sizeof(uint8_t*)); - test->captured_packets.lengths = calloc(test->captured_packets.capacity, sizeof(size_t)); - test->captured_packets.directions = calloc(test->captured_packets.capacity, sizeof(char*)); - - if (!test->captured_packets.packets || !test->captured_packets.lengths || !test->captured_packets.directions) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to allocate packet capture buffers"); - if (test->vtun) virtual_tun_destroy(test->vtun); - uasync_destroy(test->ua); - free(test); - return NULL; - } - } - - // Allocate UDP socket tracking - test->udp_socket_capacity = 16; - test->udp_sockets = calloc(test->udp_socket_capacity, sizeof(struct test_udp_socket*)); - if (!test->udp_sockets) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to allocate UDP socket tracking"); - test_cleanup_captured_packets(test); - if (test->vtun) virtual_tun_destroy(test->vtun); - uasync_destroy(test->ua); - free(test); - return NULL; - } - - DEBUG_INFO(DEBUG_CATEGORY_TEST, "Created test instance: node_id=0x%016lX, config=%s", - config->node_id, config->config_file); - return test; -} - -// Destroy test instance -void test_destroy_instance(struct test_instance* test) { - if (!test) return; - - DEBUG_INFO(DEBUG_CATEGORY_TEST, "Destroying test instance: node_id=0x%016lX", - test->config.node_id); - - // Stop instance if running - test_stop_instance(test); - - // Clear hooks if installed - if (test->hooks_installed) { - #ifdef TEST_BUILD - utun_test_hooks_clear(); - #endif - test->hooks_installed = false; - } - - // Destroy virtual components - if (test->vtun) { - virtual_tun_destroy(test->vtun); - } - - // Destroy UDP sockets - for (int i = 0; i < test->udp_socket_count; i++) { - if (test->udp_sockets[i]) { - test_udp_socket_destroy(test->udp_sockets[i]); - } - } - free(test->udp_sockets); - - // Cleanup captured packets - test_cleanup_captured_packets(test); - - // Destroy uasync - if (test->ua) { - uasync_destroy(test->ua); - } - - // Destroy UTUN instance - if (test->utun) { - utun_instance_destroy(test->utun); - } - - free(test); -} - -// Start test instance -int test_start_instance(struct test_instance* test) { - if (!test) return -1; - if (test->utun) return 0; // Already started - - DEBUG_INFO(DEBUG_CATEGORY_TEST, "Starting test instance: node_id=0x%016lX", test->config.node_id); - - // Determine flags for instance creation - uint32_t flags = 0; - if (!test->config.enable_tun) { - flags |= UTUN_CREATE_NO_TUN; - } - if (test->config.enable_socket_hooks || test->config.enable_packet_capture) { - flags |= UTUN_CREATE_TEST_MODE; - } - if (test->config.enable_socket_hooks) { - flags |= UTUN_CREATE_NO_SOCKET_BIND; - } - if (test->config.enable_tun) { - flags |= UTUN_CREATE_ALLOW_TUN_FAILURE; // Allow virtual TUN to fail gracefully - } - - // Create UTUN instance - test->utun = utun_instance_create_ex(test->ua, test->config.config_file, test->config.log_file, flags); - if (!test->utun) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to create UTUN instance"); - return -1; - } - - // Initialize instance - if (utun_instance_init(test->utun) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to initialize UTUN instance"); - utun_instance_destroy(test->utun); - test->utun = NULL; - return -1; - } - - DEBUG_INFO(DEBUG_CATEGORY_TEST, "Test instance started successfully"); - return 0; -} - -// Stop test instance -void test_stop_instance(struct test_instance* test) { - if (!test || !test->utun) return; - - DEBUG_INFO(DEBUG_CATEGORY_TEST, "Stopping test instance: node_id=0x%016lX", test->config.node_id); - - utun_instance_stop(test->utun); -} - -// Inject packet into TUN interface -int test_inject_tun_packet(struct test_instance* test, const uint8_t* packet, size_t len) { - if (!test || !test->vtun || !packet || len == 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Invalid parameters for TUN packet injection"); - return -1; - } - - return virtual_tun_inject_packet(test->vtun, packet, len); -} - -// Inject UDP packet -int test_inject_udp_packet(struct test_instance* test, int socket_fd, - const uint8_t* packet, size_t len, - const struct sockaddr* src_addr, socklen_t addr_len) { - if (!test || !packet || len == 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Invalid parameters for UDP packet injection"); - return -1; - } - - struct test_udp_socket* sock = test_udp_socket_find_by_fd(socket_fd); - if (!sock) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Socket fd=%d not found", socket_fd); - return -1; - } - - return test_udp_socket_inject(sock, packet, len, src_addr, addr_len); -} - -// Get captured packets -size_t test_get_captured_packets(struct test_instance* test, - const char* direction, - uint8_t*** packets, size_t** lengths) { - if (!test || !direction || !packets || !lengths) return 0; - - // Count packets matching direction - size_t count = 0; - for (size_t i = 0; i < test->captured_packets.count; i++) { - if (strcmp(test->captured_packets.directions[i], direction) == 0) { - count++; - } - } - - if (count == 0) return 0; - - // Allocate result arrays - *packets = calloc(count, sizeof(uint8_t*)); - *lengths = calloc(count, sizeof(size_t)); - if (!*packets || !*lengths) { - free(*packets); - free(*lengths); - return 0; - } - - // Fill result arrays - size_t result_idx = 0; - for (size_t i = 0; i < test->captured_packets.count; i++) { - if (strcmp(test->captured_packets.directions[i], direction) == 0) { - (*packets)[result_idx] = test->captured_packets.packets[i]; - (*lengths)[result_idx] = test->captured_packets.lengths[i]; - result_idx++; - } - } - - return count; -} - -// Get captured packet count -size_t test_get_captured_packet_count(struct test_instance* test, const char* direction) { - if (!test || !direction) return 0; - - size_t count = 0; - for (size_t i = 0; i < test->captured_packets.count; i++) { - if (strcmp(test->captured_packets.directions[i], direction) == 0) { - count++; - } - } - return count; -} - -// Clear captured packets -void test_clear_captured_packets(struct test_instance* test) { - if (!test) return; - - for (size_t i = 0; i < test->captured_packets.count; i++) { - if (test->captured_packets.packets[i]) { - free(test->captured_packets.packets[i]); - } - if (test->captured_packets.directions[i]) { - free(test->captured_packets.directions[i]); - } - } - test->captured_packets.count = 0; -} - -// Wait for packet with timeout -int test_wait_for_packet(struct test_instance* test, const char* direction, int timeout_ms) { - if (!test || !direction || timeout_ms <= 0) return -1; - - size_t initial_count = test_get_captured_packet_count(test, direction); - size_t current_count = initial_count; - - struct timeval start, current; - gettimeofday(&start, NULL); - - while (current_count == initial_count) { - gettimeofday(¤t, NULL); - int elapsed_ms = (current.tv_sec - start.tv_sec) * 1000 + (current.tv_usec - start.tv_usec) / 1000; - - if (elapsed_ms >= timeout_ms) { - DEBUG_WARN(DEBUG_CATEGORY_TEST, "Timeout waiting for %s packet after %dms", direction, timeout_ms); - return -1; - } - - usleep(10000); // Sleep 10ms - current_count = test_get_captured_packet_count(test, direction); - } - - DEBUG_INFO(DEBUG_CATEGORY_TEST, "Detected %s packet after %dms", direction, - (current.tv_sec - start.tv_sec) * 1000 + (current.tv_usec - start.tv_usec) / 1000); - return 0; -} - -// Two-instance test runner -int test_run_two_instances(const struct test_instance_config* server_config, - const struct test_instance_config* client_config, - void (*test_scenario)(struct test_instance* server, - struct test_instance* client), - int timeout_ms) { - if (!server_config || !client_config || !test_scenario) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Invalid parameters for two-instance test"); - return -1; - } - - DEBUG_INFO(DEBUG_CATEGORY_TEST, "Starting two-instance test"); - - // Create instances - struct test_instance* server = test_create_instance(server_config); - struct test_instance* client = test_create_instance(client_config); - - if (!server || !client) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to create test instances"); - test_destroy_instance(server); - test_destroy_instance(client); - return -1; - } - - // Start instances - if (test_start_instance(server) < 0 || test_start_instance(client) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to start test instances"); - test_destroy_instance(server); - test_destroy_instance(client); - return -1; - } - - // Give instances time to initialize - sleep(1); - - // Run test scenario - int result = 0; - if (timeout_ms > 0) { - // TODO: Implement timeout mechanism for test scenario - test_scenario(server, client); - } else { - test_scenario(server, client); - } - - // Cleanup - test_destroy_instance(server); - test_destroy_instance(client); - - DEBUG_INFO(DEBUG_CATEGORY_TEST, "Two-instance test completed: %s", result == 0 ? "SUCCESS" : "FAILED"); - return result; -} - -// Get test instance statistics -void test_get_instance_stats(struct test_instance* test, size_t* tun_packets_sent, - size_t* tun_packets_received, size_t* udp_packets_sent, - size_t* udp_packets_received) { - if (!test) return; - - if (test->vtun) { - virtual_tun_get_stats(test->vtun, tun_packets_sent, tun_packets_received, NULL, NULL); - } - - // Aggregate UDP socket statistics - size_t udp_sent = 0, udp_received = 0; - for (int i = 0; i < test->udp_socket_count; i++) { - if (test->udp_sockets[i]) { - size_t sent, recv; - test_udp_socket_get_stats(test->udp_sockets[i], &sent, &recv, NULL, NULL, NULL, NULL); - udp_sent += sent; - udp_received += recv; - } - } - - if (udp_packets_sent) *udp_packets_sent = udp_sent; - if (udp_packets_received) *udp_packets_received = udp_received; -} - -// Utility functions -const char* test_get_direction_name(const char* direction) { - if (!direction) return "unknown"; - - if (strcmp(direction, "tun_in") == 0) return "TUN incoming"; - if (strcmp(direction, "tun_out") == 0) return "TUN outgoing"; - if (strcmp(direction, "udp_in") == 0) return "UDP incoming"; - if (strcmp(direction, "udp_out") == 0) return "UDP outgoing"; - return direction; -} - -int test_compare_packets(const uint8_t* pkt1, size_t len1, const uint8_t* pkt2, size_t len2) { - if (!pkt1 || !pkt2) return -1; - if (len1 != len2) return -1; - return memcmp(pkt1, pkt2, len1); -} - -void test_dump_packet(const char* prefix, const uint8_t* packet, size_t len) { - if (!prefix || !packet || len == 0) return; - - printf("%s: %zu bytes\n", prefix, len); - for (size_t i = 0; i < len; i++) { - printf("%02X ", packet[i]); - if ((i + 1) % 16 == 0) printf("\n"); - } - if (len % 16 != 0) printf("\n"); -} - -// Internal hook implementations -static int test_tun_create_hook(void* priv_data) { - struct test_instance* test = (struct test_instance*)priv_data; - if (!test || !test->vtun) return -1; - - // Return the read fd as the TUN device fd - return virtual_tun_get_read_fd(test->vtun); -} - -static ssize_t test_tun_read_hook(int fd, void *buf, size_t count, void* priv_data) { - struct test_instance* test = (struct test_instance*)priv_data; - if (!test || !test->vtun) return -1; - - return virtual_tun_read_packet(test->vtun, buf, count); -} - -static ssize_t test_tun_write_hook(int fd, const void *buf, size_t count, void* priv_data) { - struct test_instance* test = (struct test_instance*)priv_data; - if (!test || !test->vtun) return -1; - - ssize_t result = virtual_tun_write_packet(test->vtun, buf, count); - - // Capture packet if enabled - if (test->config.enable_packet_capture && result > 0) { - test_packet_capture_hook(test->utun, buf, result, "tun_out", test); - } - - return result; -} - -static int test_socket_create_hook(int domain, int type, int protocol, void* context) { - struct test_instance* test = (struct test_instance*)context; - if (!test || !test->config.enable_socket_hooks) return -1; - - // Create virtual UDP socket - struct test_udp_socket* sock = test_udp_socket_create(domain); - if (!sock) return -1; - - // Add to tracking - pthread_mutex_lock(&g_registry_mutex); - if (test->udp_socket_count >= test->udp_socket_capacity) { - // Expand array - int new_capacity = test->udp_socket_capacity * 2; - struct test_udp_socket** new_sockets = realloc(test->udp_sockets, - new_capacity * sizeof(struct test_udp_socket*)); - if (!new_sockets) { - pthread_mutex_unlock(&g_registry_mutex); - test_udp_socket_destroy(sock); - return -1; - } - test->udp_sockets = new_sockets; - test->udp_socket_capacity = new_capacity; - } - test->udp_sockets[test->udp_socket_count++] = sock; - pthread_mutex_unlock(&g_registry_mutex); - - return test_udp_socket_get_fd(sock); -} - -static void test_packet_capture_hook(struct UTUN_INSTANCE* instance, const uint8_t* packet, size_t len, - const char* direction, void* context) { - struct test_instance* test = (struct test_instance*)context; - if (!test || !test->config.enable_packet_capture || !packet || len == 0) return; - - // Expand capture buffer if needed - if (test->captured_packets.count >= test->captured_packets.capacity) { - size_t new_capacity = test->captured_packets.capacity * 2; - uint8_t** new_packets = realloc(test->captured_packets.packets, - new_capacity * sizeof(uint8_t*)); - size_t* new_lengths = realloc(test->captured_packets.lengths, - new_capacity * sizeof(size_t)); - char** new_directions = realloc(test->captured_packets.directions, - new_capacity * sizeof(char*)); - - if (!new_packets || !new_lengths || !new_directions) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to expand packet capture buffer"); - return; - } - - test->captured_packets.packets = new_packets; - test->captured_packets.lengths = new_lengths; - test->captured_packets.directions = new_directions; - test->captured_packets.capacity = new_capacity; - } - - // Store packet - uint8_t* packet_copy = malloc(len); - if (!packet_copy) return; - - memcpy(packet_copy, packet, len); - test->captured_packets.packets[test->captured_packets.count] = packet_copy; - test->captured_packets.lengths[test->captured_packets.count] = len; - test->captured_packets.directions[test->captured_packets.count] = strdup(direction); - test->captured_packets.count++; - - DEBUG_DEBUG(DEBUG_CATEGORY_TEST, "Captured packet: %s, %zu bytes", direction, len); -} - -static void test_cleanup_captured_packets(struct test_instance* test) { - if (!test) return; - - for (size_t i = 0; i < test->captured_packets.count; i++) { - if (test->captured_packets.packets[i]) { - free(test->captured_packets.packets[i]); - } - if (test->captured_packets.directions[i]) { - free(test->captured_packets.directions[i]); - } - } - - free(test->captured_packets.packets); - free(test->captured_packets.lengths); - free(test->captured_packets.directions); - - memset(&test->captured_packets, 0, sizeof(test->captured_packets)); -} \ No newline at end of file diff --git a/!/utun_test_framework.h b/!/utun_test_framework.h deleted file mode 100755 index fc17025e..00000000 --- a/!/utun_test_framework.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef UTUN_TEST_FRAMEWORK_H -#define UTUN_TEST_FRAMEWORK_H - -#include -#include -#include -#include "utun_test_hooks.h" -#include "test_virtual_tun.h" -#include "test_udp_socket.h" - -// Forward declarations -struct UTUN_INSTANCE; -struct UASYNC; - -// Test instance configuration -struct test_instance_config { - const char* config_file; - uint64_t node_id; - int port_base; - bool enable_tun; - bool enable_socket_hooks; - bool enable_packet_capture; - const char* log_file; -}; - -// Test instance with virtual components -struct test_instance { - struct UTUN_INSTANCE* utun; - struct UASYNC* ua; - - // Virtual components - struct virtual_tun* vtun; - struct test_udp_socket** udp_sockets; - int udp_socket_count; - int udp_socket_capacity; - - // Packet capture - struct { - uint8_t** packets; - size_t* lengths; - char** directions; // "tun_in", "tun_out", "udp_in", "udp_out" - size_t count; - size_t capacity; - } captured_packets; - - // Test configuration - struct test_instance_config config; - - // Test context - void* user_context; - - // Test hooks (for internal use) - struct utun_test_hooks hooks; - bool hooks_installed; -}; - -// Create test instance with virtual components -struct test_instance* test_create_instance(const struct test_instance_config* config); - -// Destroy test instance -void test_destroy_instance(struct test_instance* test); - -// Start test instance (initialize and run) -int test_start_instance(struct test_instance* test); - -// Stop test instance -void test_stop_instance(struct test_instance* test); - -// Inject packet into TUN interface -int test_inject_tun_packet(struct test_instance* test, const uint8_t* packet, size_t len); - -// Inject UDP packet -int test_inject_udp_packet(struct test_instance* test, int socket_fd, - const uint8_t* packet, size_t len, - const struct sockaddr* src_addr, socklen_t addr_len); - -// Get captured packets -size_t test_get_captured_packets(struct test_instance* test, - const char* direction, // "tun_in", "tun_out", "udp_in", "udp_out" - uint8_t*** packets, size_t** lengths); - -// Get captured packet count -size_t test_get_captured_packet_count(struct test_instance* test, const char* direction); - -// Clear captured packets -void test_clear_captured_packets(struct test_instance* test); - -// Wait for packet with timeout (milliseconds) -int test_wait_for_packet(struct test_instance* test, - const char* direction, - int timeout_ms); - -// Two-instance test runner -int test_run_two_instances(const struct test_instance_config* server_config, - const struct test_instance_config* client_config, - void (*test_scenario)(struct test_instance* server, - struct test_instance* client), - int timeout_ms); - -// Get test instance statistics -void test_get_instance_stats(struct test_instance* test, size_t* tun_packets_sent, - size_t* tun_packets_received, size_t* udp_packets_sent, - size_t* udp_packets_received); - -// Utility functions -const char* test_get_direction_name(const char* direction); -int test_compare_packets(const uint8_t* pkt1, size_t len1, const uint8_t* pkt2, size_t len2); -void test_dump_packet(const char* prefix, const uint8_t* packet, size_t len); - -// Default test configurations -extern const struct test_instance_config TEST_SERVER_CONFIG; -extern const struct test_instance_config TEST_CLIENT_CONFIG; - -#endif // UTUN_TEST_FRAMEWORK_H \ No newline at end of file diff --git a/!/utun_test_hooks.c b/!/utun_test_hooks.c deleted file mode 100755 index 36a07b59..00000000 --- a/!/utun_test_hooks.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "utun_test_hooks.h" -#include "utun_instance.h" -#include "../lib/debug_config.h" - -// Add test category if not already defined -#ifndef DEBUG_CATEGORY_TEST -#define DEBUG_CATEGORY_TEST (1 << 30) // High bit for test category -#endif - -// Global test hooks - NULL in production -struct utun_test_hooks* g_utun_test_hooks = NULL; - -#ifdef TEST_BUILD -void utun_test_hooks_set(struct utun_test_hooks* hooks) { - if (!hooks) { - DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Attempt to set NULL test hooks"); - return; - } - - DEBUG_INFO(DEBUG_CATEGORY_TEST, "Setting test hooks: sendto=%p, recvfrom=%p, tun_create=%p", - hooks->sendto_override, hooks->recvfrom_override, hooks->tun_create_override); - - g_utun_test_hooks = hooks; -} - -void utun_test_hooks_clear(void) { - DEBUG_INFO(DEBUG_CATEGORY_TEST, "Clearing test hooks (was: %p)", g_utun_test_hooks); - g_utun_test_hooks = NULL; -} -#endif \ No newline at end of file diff --git a/!/utun_test_hooks.h b/!/utun_test_hooks.h deleted file mode 100755 index b487dad9..00000000 --- a/!/utun_test_hooks.h +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef UTUN_TEST_HOOKS_H -#define UTUN_TEST_HOOKS_H - -#include -#include -#include -#include -#include - -// Forward declarations -struct UTUN_INSTANCE; -struct ETCP_SOCKET; - -// UDP packet interception callbacks -typedef ssize_t (*utun_sendto_hook_t)(int sockfd, const void *buf, size_t len, int flags, - const struct sockaddr *dest_addr, socklen_t addrlen, - void* context); -typedef ssize_t (*utun_recvfrom_hook_t)(int sockfd, void *buf, size_t len, int flags, - struct sockaddr *src_addr, socklen_t *addrlen, - void* context); - -// TUN virtual interface callbacks -typedef int (*tun_create_hook_t)(void* priv_data); -typedef ssize_t (*tun_read_hook_t)(int fd, void *buf, size_t count, void* priv_data); -typedef ssize_t (*tun_write_hook_t)(int fd, const void *buf, size_t count, void* priv_data); - -// Socket creation callback -typedef int (*socket_create_hook_t)(int domain, int type, int protocol, void* context); - -// Test packet capture callback -typedef void (*packet_capture_hook_t)(struct UTUN_INSTANCE* instance, - const uint8_t* packet, size_t len, - const char* direction, // "tun_in", "tun_out", "udp_in", "udp_out" - void* context); - -struct utun_test_hooks { - // UDP socket hooks - utun_sendto_hook_t sendto_override; - utun_recvfrom_hook_t recvfrom_override; - - // TUN hooks - tun_create_hook_t tun_create_override; - tun_read_hook_t tun_read_override; - tun_write_hook_t tun_write_override; - - // Socket creation hook - socket_create_hook_t socket_create_override; - - // Packet capture - packet_capture_hook_t packet_captured; - - // Context for callbacks - void* test_context; -}; - -// Global test hooks - NULL in production, set only by test code -extern struct utun_test_hooks* g_utun_test_hooks; - -// Test-aware wrapper functions - inline for zero overhead when NULL -static inline ssize_t utun_sendto_hook(int sockfd, const void *buf, size_t len, int flags, - const struct sockaddr *dest_addr, socklen_t addrlen) { - if (g_utun_test_hooks && g_utun_test_hooks->sendto_override) { - return g_utun_test_hooks->sendto_override(sockfd, buf, len, flags, dest_addr, addrlen, - g_utun_test_hooks->test_context); - } - return sendto(sockfd, buf, len, flags, dest_addr, addrlen); -} - -static inline ssize_t utun_recvfrom_hook(int sockfd, void *buf, size_t len, int flags, - struct sockaddr *src_addr, socklen_t *addrlen) { - if (g_utun_test_hooks && g_utun_test_hooks->recvfrom_override) { - return g_utun_test_hooks->recvfrom_override(sockfd, buf, len, flags, src_addr, addrlen, - g_utun_test_hooks->test_context); - } - return recvfrom(sockfd, buf, len, flags, src_addr, addrlen); -} - -static inline int tun_create_hook(void* priv_data) { - if (g_utun_test_hooks && g_utun_test_hooks->tun_create_override) { - return g_utun_test_hooks->tun_create_override(priv_data); - } - return -1; // Default: no TUN available in test mode -} - -static inline ssize_t tun_read_hook(int fd, void *buf, size_t count, void* priv_data) { - if (g_utun_test_hooks && g_utun_test_hooks->tun_read_override) { - return g_utun_test_hooks->tun_read_override(fd, buf, count, priv_data); - } - return read(fd, buf, count); -} - -static inline ssize_t tun_write_hook(int fd, const void *buf, size_t count, void* priv_data) { - if (g_utun_test_hooks && g_utun_test_hooks->tun_write_override) { - return g_utun_test_hooks->tun_write_override(fd, buf, count, priv_data); - } - return write(fd, buf, count); -} - -static inline int socket_create_hook(int domain, int type, int protocol) { - if (g_utun_test_hooks && g_utun_test_hooks->socket_create_override) { - return g_utun_test_hooks->socket_create_override(domain, type, protocol, - g_utun_test_hooks->test_context); - } - return socket(domain, type, protocol); -} - -static inline void packet_capture_hook(struct UTUN_INSTANCE* instance, - const uint8_t* packet, size_t len, - const char* direction) { - if (g_utun_test_hooks && g_utun_test_hooks->packet_captured) { - g_utun_test_hooks->packet_captured(instance, packet, len, direction, - g_utun_test_hooks->test_context); - } -} - -// Functions to set/clear test hooks (only available in test builds) -#ifdef TEST_BUILD -void utun_test_hooks_set(struct utun_test_hooks* hooks); -void utun_test_hooks_clear(void); -#else -// In production builds, these are no-ops for safety -static inline void utun_test_hooks_set(struct utun_test_hooks* hooks) { (void)hooks; } -static inline void utun_test_hooks_clear(void) {} -#endif - -#endif // UTUN_TEST_HOOKS_H \ No newline at end of file diff --git a/!/utun_test_socket_api.c b/!/utun_test_socket_api.c deleted file mode 100644 index eb627145..00000000 --- a/!/utun_test_socket_api.c +++ /dev/null @@ -1,117 +0,0 @@ -#include "utun_test_socket_api.h" -#include -#include -#include - -void utun_test_packet_queue_init(struct utun_test_packet_queue* queue) { - if (!queue) return; - queue->head = NULL; - queue->tail = NULL; - queue->count = 0; -} - -void utun_test_packet_queue_cleanup(struct utun_test_packet_queue* queue) { - if (!queue) return; - - struct utun_test_packet* pkt = queue->head; - while (pkt) { - struct utun_test_packet* next = pkt->next; - free(pkt->data); - free(pkt); - pkt = next; - } - - queue->head = NULL; - queue->tail = NULL; - queue->count = 0; -} - -void utun_test_packet_queue_push(struct utun_test_packet_queue* queue, - const uint8_t* data, size_t len, - const struct sockaddr* addr, socklen_t addrlen) { - if (!queue || !data) return; - - struct utun_test_packet* pkt = calloc(1, sizeof(*pkt)); - if (!pkt) return; - - pkt->data = malloc(len); - if (!pkt->data) { - free(pkt); - return; - } - - memcpy(pkt->data, data, len); - pkt->len = len; - - if (addr && addrlen > 0 && addrlen <= sizeof(pkt->addr)) { - memcpy(&pkt->addr, addr, addrlen); - pkt->addrlen = addrlen; - } - - pkt->next = NULL; - - if (queue->tail) { - queue->tail->next = pkt; - } else { - queue->head = pkt; - } - queue->tail = pkt; - queue->count++; -} - -struct utun_test_packet* utun_test_packet_queue_pop(struct utun_test_packet_queue* queue) { - if (!queue || !queue->head) return NULL; - - struct utun_test_packet* pkt = queue->head; - queue->head = pkt->next; - - if (!queue->head) { - queue->tail = NULL; - } - - queue->count--; - pkt->next = NULL; - - return pkt; -} - -size_t utun_test_packet_queue_count(struct utun_test_packet_queue* queue) { - return queue ? queue->count : 0; -} - -ssize_t utun_test_default_on_send(const uint8_t* data, size_t len, - const struct sockaddr* dest_addr, socklen_t dest_addrlen, - void* user_data) { - struct utun_test_socket_api* api = (struct utun_test_socket_api*)user_data; - if (!api || !data || len == 0) return -1; - - utun_test_packet_queue_push(&api->send_queue, data, len, dest_addr, dest_addrlen); - return len; -} - -ssize_t utun_test_default_on_recv(uint8_t* buffer, size_t buffer_size, - struct sockaddr* src_addr, socklen_t* src_addrlen, - void* user_data) { - struct utun_test_socket_api* api = (struct utun_test_socket_api*)user_data; - if (!api || !buffer || buffer_size == 0) return -1; - - struct utun_test_packet* pkt = utun_test_packet_queue_pop(&api->recv_queue); - if (!pkt) { - errno = EAGAIN; - return -1; - } - - size_t to_copy = (pkt->len < buffer_size) ? pkt->len : buffer_size; - memcpy(buffer, pkt->data, to_copy); - - if (src_addr && src_addrlen && *src_addrlen > 0) { - socklen_t copy_len = (pkt->addrlen < *src_addrlen) ? pkt->addrlen : *src_addrlen; - memcpy(src_addr, &pkt->addr, copy_len); - *src_addrlen = copy_len; - } - - free(pkt->data); - free(pkt); - - return to_copy; -} \ No newline at end of file diff --git a/!/utun_test_socket_api.h b/!/utun_test_socket_api.h deleted file mode 100644 index ce0445c6..00000000 --- a/!/utun_test_socket_api.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef UTUN_TEST_SOCKET_API_H -#define UTUN_TEST_SOCKET_API_H - -#include -#include - -struct utun_test_packet { - uint8_t* data; - size_t len; - struct sockaddr_storage addr; - socklen_t addrlen; - struct utun_test_packet* next; -}; - -struct utun_test_packet_queue { - struct utun_test_packet* head; - struct utun_test_packet* tail; - size_t count; -}; - -struct utun_test_socket_api { - struct utun_test_packet_queue send_queue; - struct utun_test_packet_queue recv_queue; - - ssize_t (*on_send)(const uint8_t* data, size_t len, - const struct sockaddr* dest_addr, socklen_t dest_addrlen, - void* user_data); - - ssize_t (*on_recv)(uint8_t* buffer, size_t buffer_size, - struct sockaddr* src_addr, socklen_t* src_addrlen, - void* user_data); - - void* user_data; -}; - -void utun_test_packet_queue_init(struct utun_test_packet_queue* queue); -void utun_test_packet_queue_cleanup(struct utun_test_packet_queue* queue); -void utun_test_packet_queue_push(struct utun_test_packet_queue* queue, - const uint8_t* data, size_t len, - const struct sockaddr* addr, socklen_t addrlen); -struct utun_test_packet* utun_test_packet_queue_pop(struct utun_test_packet_queue* queue); -size_t utun_test_packet_queue_count(struct utun_test_packet_queue* queue); - -ssize_t utun_test_default_on_send(const uint8_t* data, size_t len, - const struct sockaddr* dest_addr, socklen_t dest_addrlen, - void* user_data); - -ssize_t utun_test_default_on_recv(uint8_t* buffer, size_t buffer_size, - struct sockaddr* src_addr, socklen_t* src_addrlen, - void* user_data); - -#endif \ No newline at end of file diff --git a/src/Makefile.am b/src/Makefile.am index 1f52817f..253753d1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,6 +6,7 @@ utun_CORE_SOURCES = \ utun_instance.c \ config_parser.c \ config_updater.c \ + route_lib.c \ routing.c \ tun_if.c \ etcp.c \ diff --git a/src/etcp.c b/src/etcp.c index be8f9c1c..1fb2ebd8 100644 --- a/src/etcp.c +++ b/src/etcp.c @@ -1,8 +1,9 @@ // etcp.c - ETCP Protocol Implementation (refactored and expanded based on etcp_protocol.txt) -#include "etcp.h" -#include "etcp_loadbalancer.h" -#include "../lib/u_async.h" +#include "etcp.h" +#include "etcp_loadbalancer.h" +#include "routing.h" +#include "../lib/u_async.h" #include "../lib/ll_queue.h" #include "../lib/debug_config.h" #include "crc32.h" // For potential hashing, though not used yet. @@ -93,13 +94,16 @@ struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance) { etcp_connection_close(etcp); return NULL; } - -// etcp->normalizer = pn_pair_init(instance->ua, etcp->mtu); -// if (!etcp->normalizer) { -// etcp_connection_close(etcp); -// return NULL; -// } - + + etcp->normalizer = pn_init(etcp); + if (!etcp->normalizer) { + etcp_connection_close(etcp); + return NULL; + } + + // Register with routing module (must be done after normalizer is assigned) + routing_add_conn(etcp); + etcp->mtu = 1500; // Default MTU // etcp->window_size = MAX_INFLIGHT_BYTES; // Not used etcp->next_tx_id = 1; @@ -129,7 +133,13 @@ struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance) { void etcp_connection_close(struct ETCP_CONN* etcp) { DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); if (!etcp) return; - + + // Deinitialize packet normalizer (this will call routing_del_conn) + if (etcp->normalizer) { + pn_deinit((struct PKTNORM*)etcp->normalizer); + etcp->normalizer = NULL; + } + // Drain and free input_queue (contains ETCP_FRAGMENT with pkt_data from data_pool) if (etcp->input_queue) { struct ETCP_FRAGMENT* pkt; diff --git a/src/etcp_connections.c b/src/etcp_connections.c index 3c851a81..303ebcbe 100644 --- a/src/etcp_connections.c +++ b/src/etcp_connections.c @@ -5,7 +5,7 @@ #include #include #include -#include "routing.h" +#include "route_lib.h" #include "utun_instance.h" #include "config_parser.h" #include "crc32.h" diff --git a/src/pkt_normalizer.c b/src/pkt_normalizer.c index 58d1fe59..471d35c9 100644 --- a/src/pkt_normalizer.c +++ b/src/pkt_normalizer.c @@ -1,6 +1,8 @@ // pkt_normalizer.c - Implementation of packet normalizer for ETCP #include "pkt_normalizer.h" #include "etcp.h" // For ETCP_CONN and related structures +#include "routing.h" // For routing_add_conn/routing_del_conn +#include "utun_instance.h" // For UTUN_INSTANCE #include "ll_queue.h" // For queue operations #include "u_async.h" // For UASYNC #include @@ -33,14 +35,14 @@ struct PKTNORM* pn_init(struct ETCP_CONN* etcp) { pn->input = queue_new(pn->ua, 0); // No hash needed if (!pn->input) { DEBUG_ERROR(DEBUG_CATEGORY_NORMALIZER, "pn_init: queue_new(input) failed"); - pn_pair_deinit(pn); + pn_deinit(pn); return NULL; } pn->output = queue_new(pn->ua, 0); // No hash needed if (!pn->output) { DEBUG_ERROR(DEBUG_CATEGORY_NORMALIZER, "pn_init: queue_new(output) failed"); - pn_pair_deinit(pn); + pn_deinit(pn); return NULL; } @@ -55,9 +57,14 @@ struct PKTNORM* pn_init(struct ETCP_CONN* etcp) { } // Deinitialization -void pn_pair_deinit(struct PKTNORM* pn) { +void pn_deinit(struct PKTNORM* pn) { if (!pn) return; + // Unregister from routing module + if (pn->etcp) { + routing_del_conn(pn->etcp); + } + // Drain and free queues if (pn->input) { struct ll_entry* entry; diff --git a/src/pkt_normalizer.h b/src/pkt_normalizer.h index 7d3bf9f4..48d0fcc3 100644 --- a/src/pkt_normalizer.h +++ b/src/pkt_normalizer.h @@ -40,7 +40,7 @@ struct PKTNORM { struct PKTNORM* pn_init(struct ETCP_CONN* etcp);// все что нужно (в т.ч. mtu и ua) берет из etcp // Деинициализация пары -void pn_pair_deinit(struct PKTNORM* pn); +void pn_deinit(struct PKTNORM* pn); // Сброс состояния (для unpacker) void pn_unpacker_reset_state(struct PKTNORM* pn); diff --git a/!/routing.c b/src/route_lib.c old mode 100755 new mode 100644 similarity index 78% rename from !/routing.c rename to src/route_lib.c index 80bf340b..1212df3a --- a/!/routing.c +++ b/src/route_lib.c @@ -1,9 +1,9 @@ /** - * @file enhanced_routing.c + * @file route_lib.c * @brief Enhanced routing system with bandwidth support and route types */ -#include "routing.h" +#include "route_lib.h" #include "etcp_connections.h" #include "../lib/debug_config.h" #include @@ -62,17 +62,17 @@ static int compare_routes(const void *a, const void *b) { return route_a->metrics.hop_count - route_b->metrics.hop_count; } -struct routing_table *routing_table_create(void) { - struct routing_table *table = calloc(1, sizeof(struct routing_table)); +struct route_table *route_table_create(void) { + struct route_table *table = calloc(1, sizeof(struct route_table)); if (!table) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "routing_table_create: failed to allocate memory for routing table"); + DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "route_table_create: failed to allocate memory for routing table"); return NULL; } table->capacity = INITIAL_ROUTE_CAPACITY; table->entries = calloc(table->capacity, sizeof(struct route_entry)); if (!table->entries) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "routing_table_create: failed to allocate memory for %d route entries", table->capacity); + DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "route_table_create: failed to allocate memory for %d route entries", table->capacity); free(table); return NULL; } @@ -82,7 +82,7 @@ struct routing_table *routing_table_create(void) { table->local_subnets = calloc(MAX_SUBNET_VALIDATION_RANGES, sizeof(uint32_t) * 2); if (!table->dynamic_subnets || !table->local_subnets) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "routing_table_create: failed to allocate memory for subnet validation arrays"); + DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "route_table_create: failed to allocate memory for subnet validation arrays"); free(table->entries); free(table->dynamic_subnets); free(table->local_subnets); @@ -93,7 +93,7 @@ struct routing_table *routing_table_create(void) { return table; } -void routing_table_destroy(struct routing_table *table) { +void route_table_destroy(struct route_table *table) { if (!table) return; // Free route entries @@ -106,11 +106,11 @@ void routing_table_destroy(struct routing_table *table) { free(table); } -bool routing_table_insert(struct routing_table *table, const struct route_entry *entry) { +bool route_table_insert(struct route_table *table, const struct route_entry *entry) { if (!table || !entry) return false; // Validate the route - if (!routing_validate_route(table, entry->network, entry->prefix_length, entry->type)) { + if (!route_validate_route(table, entry->network, entry->prefix_length, entry->type)) { char ip_str[16]; ip_to_string(entry->network, ip_str); DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "Ignoring invalid route: %s/%d (type: %s)", @@ -125,8 +125,8 @@ bool routing_table_insert(struct routing_table *table, const struct route_entry size_t new_capacity = table->capacity * ROUTE_EXPANSION_FACTOR; struct route_entry *new_entries = realloc(table->entries, new_capacity * sizeof(struct route_entry)); if (!new_entries) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "routing_table_insert: failed to expand routing table to %zu entries", new_capacity); - return false; + DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "route_table_insert: failed to expand routing table to %zu entries", new_capacity); + return false; } table->entries = new_entries; @@ -158,9 +158,9 @@ bool routing_table_insert(struct routing_table *table, const struct route_entry return false; } -bool routing_table_lookup(struct routing_table *table, uint32_t dest_ip, struct route_entry *best_route) { +bool route_table_lookup(struct route_table *table, uint32_t dest_ip, struct route_entry *best_route) { if (!table || !best_route) { - DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "routing_table_lookup: invalid parameters (table=%p, best_route=%p)", table, best_route); + DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_table_lookup: invalid parameters (table=%p, best_route=%p)", table, best_route); return false; } @@ -179,9 +179,8 @@ bool routing_table_lookup(struct routing_table *table, uint32_t dest_ip, struct char ip_str[16]; ip_to_string(dest_ip, ip_str); - DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Found route for %s: %s/%d -> %s", - ip_str, ip_to_string(entry->network, ip_str), entry->prefix_length, - ip_to_string(entry->next_hop_ip, ip_str)); + DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Found route for %s: %s/%d", + ip_str, ip_to_string(entry->network, ip_str), entry->prefix_length); table->stats.hit_count++; table->stats.routes_lookup_hits++; @@ -193,12 +192,12 @@ bool routing_table_lookup(struct routing_table *table, uint32_t dest_ip, struct // No route found char ip_str[16]; ip_to_string(dest_ip, ip_str); - DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "routing_table_lookup: no route found for destination IP %s", ip_str); + DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_table_lookup: no route found for destination IP %s", ip_str); return false; } -bool routing_validate_route(struct routing_table *table, uint32_t network, uint8_t prefix_length, route_type_t route_type) { +bool route_validate_route(struct route_table *table, uint32_t network, uint8_t prefix_length, route_type_t route_type) { if (!table) return false; uint32_t *validation_ranges = NULL; @@ -240,7 +239,7 @@ bool routing_validate_route(struct routing_table *table, uint32_t network, uint8 return false; } -bool enhanced_routing_add_subnet_range(struct routing_table *table, uint32_t network, uint8_t prefix_length, uint32_t **ranges, size_t *count) { +static bool enhanced_route_add_subnet_range(struct route_table *table, uint32_t network, uint8_t prefix_length, uint32_t **ranges, size_t *count) { if (!table || !ranges || !count) return false; if (*count >= MAX_SUBNET_VALIDATION_RANGES - 2) return false; @@ -266,15 +265,15 @@ bool enhanced_routing_add_subnet_range(struct routing_table *table, uint32_t net -bool routing_add_dynamic_subnet(struct routing_table *table, uint32_t network, uint8_t prefix_length) { - return enhanced_routing_add_subnet_range(table, network, prefix_length, &table->dynamic_subnets, &table->dynamic_subnet_count); +bool route_add_dynamic_subnet(struct route_table *table, uint32_t network, uint8_t prefix_length) { + return enhanced_route_add_subnet_range(table, network, prefix_length, &table->dynamic_subnets, &table->dynamic_subnet_count); } -bool routing_add_local_subnet(struct routing_table *table, uint32_t network, uint8_t prefix_length) { - return enhanced_routing_add_subnet_range(table, network, prefix_length, &table->local_subnets, &table->local_subnet_count); +bool route_add_local_subnet(struct route_table *table, uint32_t network, uint8_t prefix_length) { + return enhanced_route_add_subnet_range(table, network, prefix_length, &table->local_subnets, &table->local_subnet_count); } -bool routing_get_all_routes(const struct routing_table *table, uint32_t network, uint8_t prefix_length, +bool route_get_all_routes(const struct route_table *table, uint32_t network, uint8_t prefix_length, struct route_entry **routes, size_t *count) { if (!table || !routes || !count) return false; @@ -310,44 +309,40 @@ bool routing_get_all_routes(const struct routing_table *table, uint32_t network, return true; } -void routing_table_print(const struct routing_table *table) { +void route_table_print(const struct route_table *table) { if (!table) return; - printf("\n=== Routing Table ===\n"); - printf("Total routes: %zu\n", table->count); - printf("Dynamic subnets: %zu, Local subnets: %zu\n", + DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "=== Routing Table ==="); + DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Total routes: %zu", table->count); + DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Dynamic subnets: %zu, Local subnets: %zu", table->dynamic_subnet_count / 2, table->local_subnet_count / 2); if (table->count > 0) { - printf("\nRoutes:\n"); + DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Routes:"); for (size_t i = 0; i < table->count; i++) { const struct route_entry *entry = &table->entries[i]; char network_str[16], next_hop_str[16]; ip_to_string(entry->network, network_str); - ip_to_string(entry->next_hop_ip, next_hop_str); - printf(" %zu: %s/%d -> %s [%s]\n", + DEBUG_INFO(DEBUG_CATEGORY_ROUTING, " %zu: %s/%d -> %s [%s]", i + 1, network_str, entry->prefix_length, next_hop_str, route_type_to_string(entry->type)); - printf(" Bandwidth: %uK, Loss: %.2f%%, Latency: %ums, Hops: %d\n", + DEBUG_INFO(DEBUG_CATEGORY_ROUTING, " Bandwidth: %uK, Loss: %.2f%%, Latency: %ums, Hops: %d", entry->metrics.bandwidth_kbps, entry->metrics.packet_loss_rate / 100.0, entry->metrics.latency_ms, entry->metrics.hop_count); - - - printf(" Flags: %s%s%s%s\n", + DEBUG_INFO(DEBUG_CATEGORY_ROUTING, " Flags: %s%s%s%s", (entry->flags & ROUTE_FLAG_ACTIVE) ? "ACTIVE " : "", (entry->flags & ROUTE_FLAG_VALIDATED) ? "VALIDATED " : "", (entry->flags & ROUTE_FLAG_ADVERTISED) ? "ADVERTISED " : "", (entry->flags & ROUTE_FLAG_LEARNED) ? "LEARNED" : ""); - printf("\n"); } } else { - printf("\nNo routes configured.\n"); + DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "No routes configured."); } } @@ -369,4 +364,4 @@ char *ip_to_string(uint32_t ip, char *buffer) { strncpy(buffer, inet_ntoa(addr), 15); buffer[15] = '\0'; return buffer; -} \ No newline at end of file +} diff --git a/src/route_lib.h b/src/route_lib.h new file mode 100644 index 00000000..29fa879b --- /dev/null +++ b/src/route_lib.h @@ -0,0 +1,200 @@ +#ifndef ROUTE_LIB_H +#define ROUTE_LIB_H +#include +#include +#include + +// Forward declarations +struct ETCP_CONNECTIONS; + +/** + * @brief Типы маршрутов + */ +typedef enum { + ROUTE_TYPE_STATIC = 0, /**< Статический маршрут */ + ROUTE_TYPE_DYNAMIC = 1, /**< Динамический маршрут */ + ROUTE_TYPE_LOCAL = 2, /**< Локальный маршрут */ + ROUTE_TYPE_LEARNED = 3 /**< Изученный маршрут */ +} route_type_t; + +/** + * @brief Флаги маршрута + */ +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; + +/** + * @brief Расширенные метрики маршрута + * + * Структура содержит дополнительные метрики для оценки качества маршрута. + */ +struct route_metrics { + uint32_t bandwidth_kbps; /**< Пропускная способность в Кбит/с */ + uint16_t packet_loss_rate; /**< Уровень потери пакетов (в промилле) */ + uint16_t latency_ms; /**< Задержка в миллисекундах */ + uint8_t hop_count; /**< Количество прыжков */ + uint64_t last_updated; /**< Время последнего обновления (в микросекундах) */ +}; + +/** + * @brief Расширенная запись маршрута + * + * Структура представляет собой отдельную запись в таблице маршрутизации с детальной информацией о маршруте. + */ +struct route_entry { + uint32_t network; /**< Сетевой адрес */ + uint8_t prefix_length; /**< Длина префикса подсети */ + struct ETCP_SOCKET* next_hop; /**< Указатель на сокет следующего хопа */ + route_type_t type; /**< Тип маршрута */ + uint8_t flags; /**< Флаги маршрута */ + struct route_metrics metrics; /**< Метрики маршрута */ + uint64_t created_time; /**< Время создания (в микросекундах) */ + uint64_t last_update; /**< Время последнего обновления (в микросекундах) */ + uint64_t last_used; /**< Время последнего использования (в микросекундах) */ +}; + +/** + * @brief Таблица маршрутизации + * + * Структура представляет собой таблицу маршрутизации, содержащую записи маршрутов, подсети и статистику. + */ +struct route_table { + struct route_entry *entries; /**< Массив записей маршрутов */ + size_t count; /**< Текущее количество записей */ + size_t capacity; /**< Максимальная емкость таблицы */ + uint32_t *dynamic_subnets; /**< Динамические подсети (массив пар: сеть, префикс) */ + size_t dynamic_subnet_count; /**< Количество динамических подсетей */ + uint32_t *local_subnets; /**< Локальные подсети (массив пар: сеть, префикс) */ + size_t local_subnet_count; /**< Количество локальных подсетей */ + struct { + uint64_t total_routes; /**< Общее количество маршрутов */ + uint64_t static_routes; /**< Количество статических маршрутов */ + uint64_t dynamic_routes; /**< Количество динамических маршрутов */ + uint64_t local_routes; /**< Количество локальных маршрутов */ + uint64_t learned_routes; /**< Количество изученных маршрутов */ + uint64_t routes_added; /**< Количество добавленных маршрутов */ + uint64_t routes_deleted; /**< Количество удаленных маршрутов */ + uint64_t lookup_count; /**< Количество запросов поиска */ + uint64_t hit_count; /**< Количество успешных поисков */ + uint64_t routes_lookup_hits; /**< Количество попаданий в поиск маршрутов */ + uint64_t routes_lookup_misses; /**< Количество промахов в поиск маршрутов */ + uint64_t validation_failures; /**< Количество неудачных валидаций */ + } stats; /**< Статистика таблицы маршрутизации */ +}; + +/** + * @brief Создает новую таблицу маршрутизации + * + * @return Указатель на созданную таблицу или NULL в случае ошибки + */ +struct route_table *route_table_create(void); + +/** + * @brief Уничтожает таблицу маршрутизации и освобождает ресурсы + * + * @param table Указатель на таблицу маршрутизации + */ +void route_table_destroy(struct route_table *table); + +/** + * @brief Вставляет новую запись в таблицу маршрутизации + * + * @param table Указатель на таблицу маршрутизации + * @param entry Указатель на вставляемую запись маршрута + * @return true если вставка успешна, false иначе + */ +bool route_table_insert(struct route_table *table, const struct route_entry *entry); + +/** + * @brief Удаляет запись из таблицы маршрутизации + * + * @param table Указатель на таблицу маршрутизации + * @param network Сетевой адрес + * @param prefix_length Длина префикса + * @param source_node_id Идентификатор источника узла + * @return true если удаление успешно, false иначе + */ +bool route_table_delete(struct route_table *table, uint32_t network, uint8_t prefix_length, uint32_t source_node_id); + +/** + * @brief Выполняет поиск лучшего маршрута для заданного IP-адреса + * + * @param table Указатель на таблицу маршрутизации + * @param dest_ip Целевой IP-адрес + * @param best_route Указатель на структуру для хранения лучшего маршрута + * @return true если маршрут найден, false иначе + */ +bool route_table_lookup(struct route_table *table, uint32_t dest_ip, struct route_entry *best_route); + +/** + * @brief Валидирует маршрут на основе типа и подсетей + * + * @param table Указатель на таблицу маршрутизации + * @param network Сетевой адрес + * @param prefix_length Длина префикса + * @param route_type Тип маршрута + * @return true если маршрут валиден, false иначе + */ +bool route_validate_route(struct route_table *table, uint32_t network, uint8_t prefix_length, route_type_t route_type); + +/** + * @brief Добавляет динамическую подсеть в таблицу + * + * @param table Указатель на таблицу маршрутизации + * @param network Сетевой адрес + * @param prefix_length Длина префикса + * @return true если добавление успешно, false иначе + */ +bool route_add_dynamic_subnet(struct route_table *table, uint32_t network, uint8_t prefix_length); + +/** + * @brief Добавляет локальную подсеть в таблицу + * + * @param table Указатель на таблицу маршрутизации + * @param network Сетевой адрес + * @param prefix_length Длина префикса + * @return true если добавление успешно, false иначе + */ +bool route_add_local_subnet(struct route_table *table, uint32_t network, uint8_t prefix_length); + +/** + * @brief Получает все маршруты для заданной сети и префикса + * + * @param table Указатель на таблицу маршрутизации + * @param network Сетевой адрес + * @param prefix_length Длина префикса + * @param routes Указатель на массив маршрутов (будет выделен) + * @param count Указатель на количество найденных маршрутов + * @return true если операция успешна, false иначе + */ +bool route_get_all_routes(const struct route_table *table, uint32_t network, uint8_t prefix_length, struct route_entry **routes, size_t *count); + +/** + * @brief Печатает содержимое таблицы маршрутизации + * + * @param table Указатель на таблицу маршрутизации + */ +void route_table_print(const struct route_table *table); + +/** + * @brief Преобразует тип маршрута в строковое представление + * + * @param type Тип маршрута + * @return Строковое представление типа + */ +const char* route_type_to_string(route_type_t type); + +/** + * @brief Преобразует IP-адрес в строковое представление + * + * @param ip IP-адрес в сетевом формате + * @param buffer Буфер для хранения строки (минимум 16 байт) + * @return Указатель на буфер с строкой + */ +char* ip_to_string(uint32_t ip, char *buffer); + +#endif // ROUTE_LIB_H diff --git a/!/routing.txt b/src/route_lib.txt old mode 100755 new mode 100644 similarity index 100% rename from !/routing.txt rename to src/route_lib.txt diff --git a/src/routing.c b/src/routing.c index b038d0ca..f06b04bf 100644 --- a/src/routing.c +++ b/src/routing.c @@ -1,369 +1,245 @@ -/** - * @file enhanced_routing.c - * @brief Enhanced routing system with bandwidth support and route types - */ - +// routing.c - Centralized routing module for utun #include "routing.h" -#include "etcp_connections.h" +#include "route_lib.h" +#include "tun_if.h" +#include "etcp.h" +#include "pkt_normalizer.h" +#include "utun_instance.h" +#include "../lib/ll_queue.h" #include "../lib/debug_config.h" -#include -#include #include +#include #include -#include -#define INITIAL_ROUTE_CAPACITY 100 -#define ROUTE_EXPANSION_FACTOR 2 -#define MAX_SUBNET_VALIDATION_RANGES 50 - -// Parse subnet string -int parse_subnet(const char *subnet_str, uint32_t *network, uint8_t *prefix_length) { - if (!subnet_str || !network || !prefix_length) return -1; - char ip[64]; - int prefix; - if (sscanf(subnet_str, "%[^/]/%d", ip, &prefix) != 2) return -1; - if (prefix < 0 || prefix > 32) return -1; - struct in_addr addr; - if (inet_pton(AF_INET, ip, &addr) != 1) return -1; - *network = ntohl(addr.s_addr); - *prefix_length = (uint8_t)prefix; - return 0; -} +#define IPv4_VERSION 4 +#define IPv6_VERSION 6 +#define IP_HDR_VERSION_OFFSET 0 +#define IP_HDR_DST_ADDR_OFFSET 16 +#define IP_HDR_MIN_SIZE 20 - - -static int compare_routes(const void *a, const void *b) { - const struct route_entry *route_a = (const struct route_entry *)a; - const struct route_entry *route_b = (const struct route_entry *)b; - - // First compare by prefix length (longest prefix first) - if (route_b->prefix_length != route_a->prefix_length) { - return route_b->prefix_length - route_a->prefix_length; - } - - // Then by network - if (route_a->network != route_b->network) { - return route_a->network < route_b->network ? -1 : 1; +// Extract destination IP from IPv4 packet +// Returns 0 if not IPv4 or packet too small +static uint32_t extract_dst_ip(uint8_t* data, size_t len) { + if (!data || len < IP_HDR_MIN_SIZE) { + return 0; } - // Finally by metrics (best route first) - if (route_a->metrics.bandwidth_kbps != route_b->metrics.bandwidth_kbps) { - return route_b->metrics.bandwidth_kbps - route_a->metrics.bandwidth_kbps; - } - - if (route_a->metrics.latency_ms != route_b->metrics.latency_ms) { - return route_a->metrics.latency_ms - route_b->metrics.latency_ms; - } + // Check IP version (first nibble) + uint8_t version = (data[IP_HDR_VERSION_OFFSET] >> 4) & 0x0F; - if (route_a->metrics.packet_loss_rate != route_b->metrics.packet_loss_rate) { - return route_a->metrics.packet_loss_rate - route_b->metrics.packet_loss_rate; + if (version == IPv6_VERSION) { + // IPv6 - drop for now + DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "IPv6 packet detected, dropping"); + return 0; } - return route_a->metrics.hop_count - route_b->metrics.hop_count; -} - -struct routing_table *routing_table_create(void) { - struct routing_table *table = calloc(1, sizeof(struct routing_table)); - if (!table) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "routing_table_create: failed to allocate memory for routing table"); - return NULL; + if (version != IPv4_VERSION) { + DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "Unknown IP version: %d", version); + return 0; } - table->capacity = INITIAL_ROUTE_CAPACITY; - table->entries = calloc(table->capacity, sizeof(struct route_entry)); - if (!table->entries) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "routing_table_create: failed to allocate memory for %d route entries", table->capacity); - free(table); - return NULL; - } - - // Initialize subnet validation arrays - table->dynamic_subnets = calloc(MAX_SUBNET_VALIDATION_RANGES, sizeof(uint32_t) * 2); - table->local_subnets = calloc(MAX_SUBNET_VALIDATION_RANGES, sizeof(uint32_t) * 2); - - if (!table->dynamic_subnets || !table->local_subnets) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "routing_table_create: failed to allocate memory for subnet validation arrays"); - free(table->entries); - free(table->dynamic_subnets); - free(table->local_subnets); - free(table); - return NULL; - } - - return table; -} - -void routing_table_destroy(struct routing_table *table) { - if (!table) return; - - // Free route entries - free(table->entries); - - // Free validation ranges - free(table->dynamic_subnets); - free(table->local_subnets); + // Extract destination IP (offset 16, 4 bytes, network byte order) + uint32_t dst_ip; + memcpy(&dst_ip, data + IP_HDR_DST_ADDR_OFFSET, 4); - free(table); + return dst_ip; // Keep in network byte order } -bool routing_table_insert(struct routing_table *table, const struct route_entry *entry) { - if (!table || !entry) return false; - - // Validate the route - if (!routing_validate_route(table, entry->network, entry->prefix_length, entry->type)) { - char ip_str[16]; - ip_to_string(entry->network, ip_str); - DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "Ignoring invalid route: %s/%d (type: %s)", - ip_str, entry->prefix_length, route_type_to_string(entry->type)); - - return false; - } - - - // Check if we need to expand the table - if (table->count >= table->capacity) { - size_t new_capacity = table->capacity * ROUTE_EXPANSION_FACTOR; - struct route_entry *new_entries = realloc(table->entries, new_capacity * sizeof(struct route_entry)); - if (!new_entries) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "routing_table_insert: failed to expand routing table to %zu entries", new_capacity); - return false; +// Callback for packets from ETCP normalizer output queue +static void routing_pkt_from_etcp_cb(struct ll_queue* q, void* arg) { + struct ETCP_CONN* etcp = (struct ETCP_CONN*)arg; + if (!etcp || !etcp->instance) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_pkt_from_etcp_cb: invalid etcp or instance"); + return; + } + + struct UTUN_INSTANCE* instance = etcp->instance; + if (!instance->tun) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_pkt_from_etcp_cb: no TUN interface"); + return; + } + + struct ll_entry* entry = queue_data_get(q); + while (entry) { + if (entry->dgram && entry->len > 0) { + // Check MTU + if (entry->len > TUN_MAX_PACKET_SIZE) { + DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "Packet too large: %zu bytes (max %d)", + entry->len, TUN_MAX_PACKET_SIZE); + } else { + // Extract destination IP for future routing (currently ignored) + uint32_t dst_ip = extract_dst_ip(entry->dgram, entry->len); + if (dst_ip != 0) { + char ip_str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &dst_ip, ip_str, sizeof(ip_str)); + DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "Packet from ETCP to %s", ip_str); + } + + // Allocate ETCP_FRAGMENT for TUN input_queue + struct ETCP_FRAGMENT* pkt = (struct ETCP_FRAGMENT*)queue_entry_new_from_pool(instance->tun->pool); + if (!pkt) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to allocate ETCP_FRAGMENT for TUN"); + } else { + // Allocate packet data (TUN will free it) + uint8_t* packet_data = malloc(entry->len); + if (!packet_data) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to allocate packet data"); + memory_pool_free(instance->tun->pool, pkt); + } else { + memcpy(packet_data, entry->dgram, entry->len); + + pkt->seq = 0; + pkt->timestamp = 0; + pkt->ll.dgram = packet_data; + pkt->ll.len = entry->len; + + // Put to TUN input_queue + if (queue_data_put(instance->tun->input_queue, (struct ll_entry*)pkt, 0) != 0) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to put packet to TUN input_queue"); + free(packet_data); + memory_pool_free(instance->tun->pool, pkt); + } else { + DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "Forwarded %zu bytes from ETCP to TUN", entry->len); + } + } + } + } + + // Free original entry data + free(entry->dgram); } - table->entries = new_entries; - table->capacity = new_capacity; - } - - // Set timestamps and ensure route is active - struct route_entry new_entry = *entry; - new_entry.created_time = new_entry.last_update = (uint64_t)time(NULL) * 1000000; // Convert to microseconds - new_entry.last_used = 0; - - // Ensure route is active by default - if (!(new_entry.flags & ROUTE_FLAG_ACTIVE)) { - new_entry.flags |= ROUTE_FLAG_ACTIVE; + // Free entry structure + queue_entry_free(entry); + + // Get next packet + entry = queue_data_get(q); } + queue_resume_callback(q); +} - - // Insert and maintain sorted order - table->stats.routes_added++; - size_t insert_pos = table->count; - for (size_t i = 0; i < table->count; i++) { - if (compare_routes(&new_entry, &table->entries[i]) < 0) { - insert_pos = i; - break; +// Callback for packets from TUN output queue +static void routing_pkt_from_tun_cb(struct ll_queue* q, void* arg) { + (void)q; + struct UTUN_INSTANCE* instance = (struct UTUN_INSTANCE*)arg; + if (!instance) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_pkt_from_tun_cb: invalid instance"); + return; + } + + // For now, just drain the queue (routing to ETCP will be implemented later) + struct ETCP_FRAGMENT* pkt = (struct ETCP_FRAGMENT*)queue_data_get(instance->tun->output_queue); + while (pkt) { + if (pkt->ll.dgram && pkt->ll.len > 0) { + // Extract destination IP for future routing + uint32_t dst_ip = extract_dst_ip(pkt->ll.dgram, pkt->ll.len); + if (dst_ip != 0) { + char ip_str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &dst_ip, ip_str, sizeof(ip_str)); + DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "Packet from TUN to %s (dropped, routing not implemented yet)", ip_str); + } + + // Free packet data + free(pkt->ll.dgram); } + + // Free fragment structure + memory_pool_free(instance->tun->pool, pkt); + + // Get next packet + pkt = (struct ETCP_FRAGMENT*)queue_data_get(instance->tun->output_queue); } - - return false; } -bool routing_table_lookup(struct routing_table *table, uint32_t dest_ip, struct route_entry *best_route) { - if (!table || !best_route) { - DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "routing_table_lookup: invalid parameters (table=%p, best_route=%p)", table, best_route); - return false; +// Initialize routing module for instance +int routing_create(struct UTUN_INSTANCE* instance) { + if (!instance) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_create: instance is NULL"); + return -1; } - table->stats.lookup_count++; - - // Find longest prefix match - for (size_t i = 0; i < table->count; i++) { - const struct route_entry *entry = &table->entries[i]; - - // Check if route is valid and matches destination - if (entry->flags & ROUTE_FLAG_ACTIVE) { - uint32_t mask = (entry->prefix_length == 0) ? 0 : (0xFFFFFFFFU << (32 - entry->prefix_length)); - if ((dest_ip & mask) == (entry->network & mask)) { - *best_route = *entry; - best_route->last_update = (uint64_t)time(NULL) * 1000000; - - char ip_str[16]; - ip_to_string(dest_ip, ip_str); - DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Found route for %s: %s/%d -> %s", - ip_str, ip_to_string(entry->network, ip_str), entry->prefix_length, - ip_to_string(entry->next_hop_ip, ip_str)); - - table->stats.hit_count++; - table->stats.routes_lookup_hits++; - return true; - } - } + // Create route table + instance->rt = route_table_create(); + if (!instance->rt) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to create route table"); + return -1; } - // No route found - char ip_str[16]; - ip_to_string(dest_ip, ip_str); - DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "routing_table_lookup: no route found for destination IP %s", ip_str); + DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Routing module initialized for instance"); - return false; + return 0; } -bool routing_validate_route(struct routing_table *table, uint32_t network, uint8_t prefix_length, route_type_t route_type) { - if (!table) return false; - - uint32_t *validation_ranges = NULL; - size_t range_count = 0; +// Destroy routing module for instance +void routing_destroy(struct UTUN_INSTANCE* instance) { + if (!instance) return; - switch (route_type) { - case ROUTE_TYPE_STATIC: - case ROUTE_TYPE_LEARNED: - return true; // No validation for static or learned routes - case ROUTE_TYPE_DYNAMIC: - validation_ranges = table->dynamic_subnets; - range_count = table->dynamic_subnet_count; - break; - case ROUTE_TYPE_LOCAL: - validation_ranges = table->local_subnets; - range_count = table->local_subnet_count; - break; - default: - table->stats.routes_lookup_misses++; - return false; - } + DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Destroying routing module"); - if (range_count == 0) return true; // No validation ranges configured - - // Check if network falls within any validation range - for (size_t i = 0; i < range_count; i += 2) { - uint32_t range_network = validation_ranges[i]; - uint8_t range_prefix = (uint8_t)validation_ranges[i + 1]; - - uint32_t mask = (range_prefix == 0) ? 0 : (0xFFFFFFFFU << (32 - range_prefix)); - if ((network & mask) == (range_network & mask)) { - // Check if this route is more specific than or equal to the validation range - if (prefix_length >= range_prefix) { - return true; - } - } + // Clean up route table if exists + if (instance->rt) { + route_table_destroy(instance->rt); + instance->rt = NULL; } - - return false; } -bool enhanced_routing_add_subnet_range(struct routing_table *table, uint32_t network, uint8_t prefix_length, uint32_t **ranges, size_t *count) { - if (!table || !ranges || !count) return false; +// Register ETCP connection with routing +void routing_add_conn(struct ETCP_CONN* etcp) { + if (!etcp) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_add_conn: etcp is NULL"); + return; + } - if (*count >= MAX_SUBNET_VALIDATION_RANGES - 2) return false; + if (!etcp->instance) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_add_conn: etcp has no instance"); + return; + } - // Expand array if needed - if (*ranges == NULL) { - *ranges = calloc(MAX_SUBNET_VALIDATION_RANGES, sizeof(uint32_t)); - if (!*ranges) return false; - *count = 0; + if (!etcp->normalizer) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_add_conn: ETCP has no normalizer"); + return; } - // Add network and prefix length as a pair - (*ranges)[*count] = network; - (*ranges)[*count + 1] = prefix_length; - *count += 2; + struct PKTNORM* pn = (struct PKTNORM*)etcp->normalizer; - char ip_str[16]; - ip_to_string(network, ip_str); - DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Added subnet validation range: %s/%d", ip_str, prefix_length); + // Set callback on normalizer output queue - pass etcp as arg + queue_set_callback(pn->output, routing_pkt_from_etcp_cb, etcp); - return true; -} - - - -bool routing_add_dynamic_subnet(struct routing_table *table, uint32_t network, uint8_t prefix_length) { - return enhanced_routing_add_subnet_range(table, network, prefix_length, &table->dynamic_subnets, &table->dynamic_subnet_count); -} - -bool routing_add_local_subnet(struct routing_table *table, uint32_t network, uint8_t prefix_length) { - return enhanced_routing_add_subnet_range(table, network, prefix_length, &table->local_subnets, &table->local_subnet_count); + DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Added ETCP connection to routing"); } -bool routing_get_all_routes(const struct routing_table *table, uint32_t network, uint8_t prefix_length, - struct route_entry **routes, size_t *count) { - if (!table || !routes || !count) return false; - - *routes = NULL; - *count = 0; - - // Count matching routes - for (size_t i = 0; i < table->count; i++) { - if (table->entries[i].network == network && table->entries[i].prefix_length == prefix_length) { - (*count)++; - } +// Unregister ETCP connection from routing +void routing_del_conn(struct ETCP_CONN* etcp) { + if (!etcp) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_del_conn: etcp is NULL"); + return; } - if (*count == 0) return true; // No routes found, but not an error - - // Allocate result array - *routes = calloc(*count, sizeof(struct route_entry)); - if (!*routes) { - *count = 0; - return false; + if (!etcp->normalizer) { + return; // Nothing to do } - // Copy matching routes - size_t result_index = 0; - for (size_t i = 0; i < table->count; i++) { - if (table->entries[i].network == network && table->entries[i].prefix_length == prefix_length) { - (*routes)[result_index] = table->entries[i]; - - result_index++; - } - } + // Note: ll_queue doesn't have a direct way to clear callback + // The callback will be ignored when etcp is freed - return true; + DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Removed ETCP connection from routing"); } -void routing_table_print(const struct routing_table *table) { - if (!table) return; - - DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "=== Routing Table ==="); - DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Total routes: %zu", table->count); - DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Dynamic subnets: %zu, Local subnets: %zu", - table->dynamic_subnet_count / 2, table->local_subnet_count / 2); - - if (table->count > 0) { - DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Routes:"); - for (size_t i = 0; i < table->count; i++) { - const struct route_entry *entry = &table->entries[i]; - char network_str[16], next_hop_str[16]; - - ip_to_string(entry->network, network_str); - ip_to_string(entry->next_hop_ip, next_hop_str); - - DEBUG_INFO(DEBUG_CATEGORY_ROUTING, " %zu: %s/%d -> %s [%s]", - i + 1, network_str, entry->prefix_length, next_hop_str, - route_type_to_string(entry->type)); - - DEBUG_INFO(DEBUG_CATEGORY_ROUTING, " Bandwidth: %uK, Loss: %.2f%%, Latency: %ums, Hops: %d", - entry->metrics.bandwidth_kbps, - entry->metrics.packet_loss_rate / 100.0, - entry->metrics.latency_ms, - entry->metrics.hop_count); - - DEBUG_INFO(DEBUG_CATEGORY_ROUTING, " Flags: %s%s%s%s", - (entry->flags & ROUTE_FLAG_ACTIVE) ? "ACTIVE " : "", - (entry->flags & ROUTE_FLAG_VALIDATED) ? "VALIDATED " : "", - (entry->flags & ROUTE_FLAG_ADVERTISED) ? "ADVERTISED " : "", - (entry->flags & ROUTE_FLAG_LEARNED) ? "LEARNED" : ""); - } - } else { - DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "No routes configured."); +// Set TUN interface for routing +void routing_set_tun(struct UTUN_INSTANCE* instance) { + if (!instance) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_set_tun: instance is NULL"); + return; } -} - -const char *route_type_to_string(route_type_t type) { - switch (type) { - case ROUTE_TYPE_STATIC: return "STATIC"; - case ROUTE_TYPE_DYNAMIC: return "DYNAMIC"; - case ROUTE_TYPE_LOCAL: return "LOCAL"; - case ROUTE_TYPE_LEARNED: return "LEARNED"; - default: return "UNKNOWN"; + + if (!instance->tun) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_set_tun: instance has no TUN"); + return; } -} - -char *ip_to_string(uint32_t ip, char *buffer) { - if (!buffer) return NULL; - struct in_addr addr; - addr.s_addr = htonl(ip); - strncpy(buffer, inet_ntoa(addr), 15); - buffer[15] = '\0'; - return buffer; -} \ No newline at end of file + // Set callback on TUN output queue (packets from TUN to routing) + queue_set_callback(instance->tun->output_queue, routing_pkt_from_tun_cb, instance); + + DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "TUN interface registered in routing module"); +} diff --git a/src/routing.h b/src/routing.h index a3f25538..f17fcc62 100644 --- a/src/routing.h +++ b/src/routing.h @@ -1,201 +1,46 @@ +// routing.h - Centralized routing module for utun #ifndef ROUTING_H #define ROUTING_H + #include #include -#include // Forward declarations -struct ETCP_CONNECTIONS; - -/** - * @brief Типы маршрутов - */ -typedef enum { - ROUTE_TYPE_STATIC = 0, /**< Статический маршрут */ - ROUTE_TYPE_DYNAMIC = 1, /**< Динамический маршрут */ - ROUTE_TYPE_LOCAL = 2, /**< Локальный маршрут */ - ROUTE_TYPE_LEARNED = 3 /**< Изученный маршрут */ -} route_type_t; - -/** - * @brief Флаги маршрута - */ -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; - -/** - * @brief Расширенные метрики маршрута - * - * Структура содержит дополнительные метрики для оценки качества маршрута. - */ -struct route_metrics { - uint32_t bandwidth_kbps; /**< Пропускная способность в Кбит/с */ - uint16_t packet_loss_rate; /**< Уровень потери пакетов (в промилле) */ - uint16_t latency_ms; /**< Задержка в миллисекундах */ - uint8_t hop_count; /**< Количество прыжков */ - uint64_t last_updated; /**< Время последнего обновления (в микросекундах) */ -}; - -/** - * @brief Расширенная запись маршрута - * - * Структура представляет собой отдельную запись в таблице маршрутизации с детальной информацией о маршруте. - */ -struct route_entry { - uint32_t network; /**< Сетевой адрес */ - uint8_t prefix_length; /**< Длина префикса подсети */ - uint32_t next_hop_ip; /**< IP-адрес следующего хопа */ - struct ETCP_SOCKET* next_hop; /**< Указатель на сокет следующего хопа */ - route_type_t type; /**< Тип маршрута */ - uint8_t flags; /**< Флаги маршрута */ - struct route_metrics metrics; /**< Метрики маршрута */ - uint64_t created_time; /**< Время создания (в микросекундах) */ - uint64_t last_update; /**< Время последнего обновления (в микросекундах) */ - uint64_t last_used; /**< Время последнего использования (в микросекундах) */ -}; - -/** - * @brief Таблица маршрутизации - * - * Структура представляет собой таблицу маршрутизации, содержащую записи маршрутов, подсети и статистику. - */ -struct routing_table { - struct route_entry *entries; /**< Массив записей маршрутов */ - size_t count; /**< Текущее количество записей */ - size_t capacity; /**< Максимальная емкость таблицы */ - uint32_t *dynamic_subnets; /**< Динамические подсети (массив пар: сеть, префикс) */ - size_t dynamic_subnet_count; /**< Количество динамических подсетей */ - uint32_t *local_subnets; /**< Локальные подсети (массив пар: сеть, префикс) */ - size_t local_subnet_count; /**< Количество локальных подсетей */ - struct { - uint64_t total_routes; /**< Общее количество маршрутов */ - uint64_t static_routes; /**< Количество статических маршрутов */ - uint64_t dynamic_routes; /**< Количество динамических маршрутов */ - uint64_t local_routes; /**< Количество локальных маршрутов */ - uint64_t learned_routes; /**< Количество изученных маршрутов */ - uint64_t routes_added; /**< Количество добавленных маршрутов */ - uint64_t routes_deleted; /**< Количество удаленных маршрутов */ - uint64_t lookup_count; /**< Количество запросов поиска */ - uint64_t hit_count; /**< Количество успешных поисков */ - uint64_t routes_lookup_hits; /**< Количество попаданий в поиск маршрутов */ - uint64_t routes_lookup_misses; /**< Количество промахов в поиск маршрутов */ - uint64_t validation_failures; /**< Количество неудачных валидаций */ - } stats; /**< Статистика таблицы маршрутизации */ -}; - -/** - * @brief Создает новую таблицу маршрутизации - * - * @return Указатель на созданную таблицу или NULL в случае ошибки - */ -struct routing_table *routing_table_create(void); - -/** - * @brief Уничтожает таблицу маршрутизации и освобождает ресурсы - * - * @param table Указатель на таблицу маршрутизации - */ -void routing_table_destroy(struct routing_table *table); - -/** - * @brief Вставляет новую запись в таблицу маршрутизации - * - * @param table Указатель на таблицу маршрутизации - * @param entry Указатель на вставляемую запись маршрута - * @return true если вставка успешна, false иначе - */ -bool routing_table_insert(struct routing_table *table, const struct route_entry *entry); - -/** - * @brief Удаляет запись из таблицы маршрутизации - * - * @param table Указатель на таблицу маршрутизации - * @param network Сетевой адрес - * @param prefix_length Длина префикса - * @param source_node_id Идентификатор источника узла - * @return true если удаление успешно, false иначе - */ -bool routing_table_delete(struct routing_table *table, uint32_t network, uint8_t prefix_length, uint32_t source_node_id); - -/** - * @brief Выполняет поиск лучшего маршрута для заданного IP-адреса - * - * @param table Указатель на таблицу маршрутизации - * @param dest_ip Целевой IP-адрес - * @param best_route Указатель на структуру для хранения лучшего маршрута - * @return true если маршрут найден, false иначе - */ -bool routing_table_lookup(struct routing_table *table, uint32_t dest_ip, struct route_entry *best_route); - -/** - * @brief Валидирует маршрут на основе типа и подсетей - * - * @param table Указатель на таблицу маршрутизации - * @param network Сетевой адрес - * @param prefix_length Длина префикса - * @param route_type Тип маршрута - * @return true если маршрут валиден, false иначе - */ -bool routing_validate_route(struct routing_table *table, uint32_t network, uint8_t prefix_length, route_type_t route_type); - -/** - * @brief Добавляет динамическую подсеть в таблицу - * - * @param table Указатель на таблицу маршрутизации - * @param network Сетевой адрес - * @param prefix_length Длина префикса - * @return true если добавление успешно, false иначе - */ -bool routing_add_dynamic_subnet(struct routing_table *table, uint32_t network, uint8_t prefix_length); +struct ETCP_CONN; +struct UTUN_INSTANCE; /** - * @brief Добавляет локальную подсеть в таблицу - * - * @param table Указатель на таблицу маршрутизации - * @param network Сетевой адрес - * @param prefix_length Длина префикса - * @return true если добавление успешно, false иначе + * @brief Initialize routing module for instance + * @param instance UTUN instance + * @return 0 on success, -1 on error */ -bool routing_add_local_subnet(struct routing_table *table, uint32_t network, uint8_t prefix_length); +int routing_create(struct UTUN_INSTANCE* instance); /** - * @brief Получает все маршруты для заданной сети и префикса - * - * @param table Указатель на таблицу маршрутизации - * @param network Сетевой адрес - * @param prefix_length Длина префикса - * @param routes Указатель на массив маршрутов (будет выделен) - * @param count Указатель на количество найденных маршрутов - * @return true если операция успешна, false иначе + * @brief Destroy routing module for instance + * @param instance UTUN instance */ -bool routing_get_all_routes(const struct routing_table *table, uint32_t network, uint8_t prefix_length, struct route_entry **routes, size_t *count); +void routing_destroy(struct UTUN_INSTANCE* instance); /** - * @brief Печатает содержимое таблицы маршрутизации - * - * @param table Указатель на таблицу маршрутизации + * @brief Register ETCP connection with routing + * Called from pn_init() to register connection's normalizer output queue + * @param etcp ETCP connection */ -void routing_table_print(const struct routing_table *table); +void routing_add_conn(struct ETCP_CONN* etcp); /** - * @brief Преобразует тип маршрута в строковое представление - * - * @param type Тип маршрута - * @return Строковое представление типа + * @brief Unregister ETCP connection from routing + * Called from pn_deinit() to unregister connection's normalizer output queue + * @param etcp ETCP connection */ -const char* route_type_to_string(route_type_t type); +void routing_del_conn(struct ETCP_CONN* etcp); /** - * @brief Преобразует IP-адрес в строковое представление - * - * @param ip IP-адрес в сетевом формате - * @param buffer Буфер для хранения строки (минимум 16 байт) - * @return Указатель на буфер с строкой + * @brief Set TUN interface for routing + * Called from utun_instance_init() after tun_init() + * @param instance UTUN instance with configured tun */ -char* ip_to_string(uint32_t ip, char *buffer); +void routing_set_tun(struct UTUN_INSTANCE* instance); #endif // ROUTING_H diff --git a/src/routing.txt b/src/routing.txt deleted file mode 100644 index bc05dd2b..00000000 --- a/src/routing.txt +++ /dev/null @@ -1,7 +0,0 @@ -internal_routing.c/h: - -это модуль роутинга пакетов. -пакеты приходят: -1. из очередей ETCP (struct ETCP_CONN output_queue). - при добавлении подключения (из конфига)) в вызовы etcp_connection_create/close надо добавить -2. из tun интерфейса \ No newline at end of file diff --git a/src/tun_if.c b/src/tun_if.c index b924ce2b..bb535233 100644 --- a/src/tun_if.c +++ b/src/tun_if.c @@ -168,6 +168,44 @@ static int tun_set_mtu(const char *ifname, int mtu) { return 0; } +// Callback for input_queue - called when routing puts packet to send to TUN +static void tun_input_queue_callback(struct ll_queue* q, void* arg) { + (void)q; + struct tun_if* tun = (struct tun_if*)arg; + struct ETCP_FRAGMENT* pkt = (struct ETCP_FRAGMENT*)queue_data_get(tun->input_queue); + + while (pkt) { + if (pkt->ll.dgram && pkt->ll.len > 0) { + // Check MTU + if (pkt->ll.len > TUN_MAX_PACKET_SIZE) { + DEBUG_WARN(DEBUG_CATEGORY_TUN, "Packet too large for TUN: %zu bytes (max %d)", + pkt->ll.len, TUN_MAX_PACKET_SIZE); + } else { + ssize_t nwritten = write(tun->fd, pkt->ll.dgram, pkt->ll.len); + if (nwritten < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to write to TUN %s: %s", + tun->ifname, strerror(errno)); + tun->write_errors++; + } else { + tun->bytes_written += nwritten; + tun->packets_written++; + DEBUG_DEBUG(DEBUG_CATEGORY_TUN, "Wrote %zd bytes to TUN %s from input_queue", + nwritten, tun->ifname); + } + } + + // Free packet data + free(pkt->ll.dgram); + } + + // Free fragment structure + memory_pool_free(tun->pool, pkt); + + // Get next packet + pkt = (struct ETCP_FRAGMENT*)queue_data_get(tun->input_queue); + } +} + // Internal read callback - called by uasync when data available on TUN static void tun_read_callback(int fd, void* user_arg) { struct tun_if* tun = (struct tun_if*)user_arg; @@ -209,7 +247,7 @@ static void tun_read_callback(int fd, void* user_arg) { pkt->ll.len = nread; // Add to input queue - if (queue_data_put(tun->input_queue, (struct ll_entry*)pkt, 0) != 0) { + if (queue_data_put(tun->output_queue, (struct ll_entry*)pkt, 0) != 0) { DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to add packet to input queue"); free(packet_data); memory_pool_free(tun->pool, pkt); @@ -306,21 +344,35 @@ struct tun_if* tun_init(struct UASYNC* ua, struct utun_config* config) { return NULL; } - // Create input queue + // Create output queue (packets from TUN to routing) + tun->output_queue = queue_new(ua, 0); // hash_size=0 - no ID lookup needed + if (!tun->output_queue) { + DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to create output queue"); + memory_pool_destroy(tun->pool); + close(tun->fd); + free(tun); + return NULL; + } + + // Create input queue (packets from routing to TUN) tun->input_queue = queue_new(ua, 0); // hash_size=0 - no ID lookup needed if (!tun->input_queue) { DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to create input queue"); + queue_free(tun->output_queue); memory_pool_destroy(tun->pool); close(tun->fd); free(tun); return NULL; } + // Set callback for input_queue - routing will put packets here + queue_set_callback(tun->input_queue, tun_input_queue_callback, tun); + // Register TUN socket with uasync tun->socket_id = uasync_add_socket(ua, tun->fd, tun_read_callback, NULL, NULL, tun); if (!tun->socket_id) { DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to register TUN socket with uasync"); - queue_free(tun->input_queue); + queue_free(tun->output_queue); memory_pool_destroy(tun->pool); close(tun->fd); free(tun); @@ -344,7 +396,7 @@ void tun_close(struct tun_if* tun) { tun->socket_id = NULL; } - // Drain and free all packets from input queue + // Drain and free all packets from input_queue (packets from routing to TUN) if (tun->input_queue) { struct ETCP_FRAGMENT* pkt; while ((pkt = (struct ETCP_FRAGMENT*)queue_data_get(tun->input_queue)) != NULL) { @@ -357,6 +409,19 @@ void tun_close(struct tun_if* tun) { tun->input_queue = NULL; } + // Drain and free all packets from output_queue (packets from TUN to routing) + if (tun->output_queue) { + struct ETCP_FRAGMENT* pkt; + while ((pkt = (struct ETCP_FRAGMENT*)queue_data_get(tun->output_queue)) != NULL) { + if (pkt->ll.dgram) { + free(pkt->ll.dgram); + } + memory_pool_free(tun->pool, pkt); + } + queue_free(tun->output_queue); + tun->output_queue = NULL; + } + // Destroy memory pool if (tun->pool) { memory_pool_destroy(tun->pool); diff --git a/src/tun_if.h b/src/tun_if.h index a3478491..6edffab7 100644 --- a/src/tun_if.h +++ b/src/tun_if.h @@ -26,7 +26,8 @@ struct tun_if { struct UASYNC* ua; // uasync instance void* socket_id; // Socket ID from uasync_add_socket struct memory_pool* pool; // Pool for ETCP_FRAGMENT structures - struct ll_queue* input_queue; // Queue for incoming packets (ETCP_FRAGMENT) + struct ll_queue* output_queue; // Queue for incoming packets from TUN (to routing) + struct ll_queue* input_queue; // Queue for outgoing packets to TUN (from routing) // Statistics uint64_t bytes_read; // Bytes read from TUN uint64_t bytes_written; // Bytes written to TUN @@ -50,7 +51,7 @@ struct tun_if* tun_init(struct UASYNC* ua, struct utun_config* config); /** * @brief Close TUN interface and free resources * Unregisters socket from uasync, closes fd, drains and frees - * all packets from input_queue, destroys pool and queue. + * all packets from output_queue, destroys pool and queue. * @param tun TUN interface handle */ void tun_close(struct tun_if* tun); @@ -64,20 +65,6 @@ void tun_close(struct tun_if* tun); */ ssize_t tun_write(struct tun_if* tun, const uint8_t* buf, size_t len); -/** - * @brief Get input queue for reading packets - * User should call queue_data_get(tun->input_queue) to retrieve packets. - * Each packet is struct ETCP_FRAGMENT with: - * - ll.dgram: malloc'd packet data (user must free) - * - ll.len: packet length - * User must free dgram and return fragment to pool via memory_pool_free(). - * @param tun TUN interface handle - * @return Pointer to input queue - */ -static inline struct ll_queue* tun_get_input_queue(struct tun_if* tun) { - return tun ? tun->input_queue : NULL; -} - #ifdef __cplusplus } #endif diff --git a/src/utun.c b/src/utun.c index a6345c2c..ed8c074d 100644 --- a/src/utun.c +++ b/src/utun.c @@ -5,7 +5,7 @@ #include "etcp_connections.h" #include "tun_if.h" #include "secure_channel.h" -#include "routing.h" +#include "route_lib.h" #include "utun_instance.h" #include "u_async.h" #include "debug_config.h" diff --git a/src/utun_instance.c b/src/utun_instance.c index 8c16fea9..34292dae 100644 --- a/src/utun_instance.c +++ b/src/utun_instance.c @@ -3,6 +3,7 @@ #include "config_parser.h" #include "config_updater.h" #include "tun_if.h" +#include "route_lib.h" #include "routing.h" #include "etcp_connections.h" #include "etcp.h" @@ -79,6 +80,44 @@ struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char *config instance->data_pool=memory_pool_init(PACKET_DATA_SIZE); instance->pkt_pool=memory_pool_init(sizeof(struct ETCP_DGRAM) + PACKET_DATA_SIZE); + // Create routing module + if (routing_create(instance) != 0) { + DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to create routing module"); + free_config(instance->config); + free(instance); + return NULL; + } + DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Routing module created"); + + // Add local subnets from config as static routes + struct CFG_ROUTE_ENTRY* subnet = instance->config->my_subnets; + while (subnet) { + struct route_entry entry = {0}; + entry.network = subnet->ip.addr.v4.s_addr; // Network byte order + entry.prefix_length = subnet->netmask; + entry.next_hop = NULL; // Local route + entry.type = ROUTE_TYPE_LOCAL; + entry.flags = ROUTE_FLAG_ACTIVE | ROUTE_FLAG_VALIDATED; + entry.metrics.bandwidth_kbps = UINT32_MAX; // Unlimited + entry.metrics.latency_ms = 0; + entry.metrics.packet_loss_rate = 0; + entry.metrics.hop_count = 0; + + if (route_table_insert(instance->rt, &entry)) { + char ip_str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &entry.network, ip_str, sizeof(ip_str)); + DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Added local route: %s/%d", + ip_str, entry.prefix_length); + } else { + char ip_str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &entry.network, ip_str, sizeof(ip_str)); + DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "Failed to add local route: %s/%d (skipping)", + ip_str, entry.prefix_length); + } + + subnet = subnet->next; + } + // Initialize TUN device only if enabled if (g_tun_init_enabled) { instance->tun = tun_init(ua, instance->config); @@ -141,6 +180,9 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) { instance->tun = NULL; } + // Cleanup routing module + routing_destroy(instance); + // Cleanup config if (instance->config) { DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Freeing configuration"); @@ -200,6 +242,12 @@ void utun_instance_stop(struct UTUN_INSTANCE *instance) { int utun_instance_init(struct UTUN_INSTANCE *instance) { if (!instance) return -1; + // Set TUN interface in routing module + if (instance->tun) { + routing_set_tun(instance); + DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "TUN interface registered in routing module"); + } + // Note: TUN socket is already registered in tun_init() // Initialize connections diff --git a/src/utun_instance.h b/src/utun_instance.h index b613d6ef..c05a51bf 100644 --- a/src/utun_instance.h +++ b/src/utun_instance.h @@ -10,7 +10,7 @@ // Forward declarations struct utun_config; struct uasync_s; -struct routing_table; +struct route_table; struct ETCP_CONN; struct ETCP_SOCKET; struct tun_if; @@ -22,6 +22,8 @@ struct UTUN_INSTANCE { // TUN interface struct tun_if* tun; + + struct route_table* rt; // Identification uint64_t node_id; @@ -44,6 +46,7 @@ struct UTUN_INSTANCE { // Active sockets struct ETCP_SOCKET* etcp_sockets;// linked-list + }; // Functions diff --git a/tests/Makefile.am b/tests/Makefile.am index 1d846100..01c307d3 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -66,6 +66,7 @@ ETCP_CORE_OBJS = \ ETCP_FULL_OBJS = \ $(top_builddir)/src/utun-config_parser.o \ $(top_builddir)/src/utun-config_updater.o \ + $(top_builddir)/src/utun-route_lib.o \ $(top_builddir)/src/utun-routing.o \ $(top_builddir)/src/utun-tun_if.o \ $(top_builddir)/src/utun-utun_instance.o \ @@ -99,7 +100,7 @@ test_etcp_simple_traffic_LDADD = $(ETCP_FULL_OBJS) $(SECURE_CHANNEL_OBJS) $(CRYP # ETCP minimal test test_etcp_minimal_SOURCES = test_etcp_minimal.c test_etcp_minimal_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source -test_etcp_minimal_LDADD = $(ETCP_CORE_OBJS) $(SECURE_CHANNEL_OBJS) $(CRYPTO_LIBS) $(COMMON_LIBS) +test_etcp_minimal_LDADD = $(ETCP_FULL_OBJS) $(SECURE_CHANNEL_OBJS) $(CRYPTO_LIBS) $(COMMON_LIBS) # ETCP 100 packets test test_etcp_100_packets_SOURCES = test_etcp_100_packets.c @@ -114,7 +115,7 @@ test_pkt_normalizer_etcp_LDADD = $(ETCP_FULL_OBJS) $(SECURE_CHANNEL_OBJS) $(CRYP # Standalone pkt_normalizer test with mock ETCP loopback test_pkt_normalizer_standalone_SOURCES = test_pkt_normalizer_standalone.c test_pkt_normalizer_standalone_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source -test_pkt_normalizer_standalone_LDADD = $(top_builddir)/src/utun-pkt_normalizer.o $(TINYCRYPT_OBJS) $(COMMON_LIBS) +test_pkt_normalizer_standalone_LDADD = $(top_builddir)/src/utun-pkt_normalizer.o $(top_builddir)/src/utun-route_lib.o $(top_builddir)/src/utun-routing.o $(TINYCRYPT_OBJS) $(COMMON_LIBS) # Basic crypto test (TinyCrypt only - no secure_channel) test_crypto_SOURCES = test_crypto.c diff --git a/tests/test_etcp_100_packets b/tests/test_etcp_100_packets index aa685a14..2b329743 100755 Binary files a/tests/test_etcp_100_packets and b/tests/test_etcp_100_packets differ diff --git a/tests/test_etcp_100_packets.c b/tests/test_etcp_100_packets.c index d3c6945c..0a576b31 100644 --- a/tests/test_etcp_100_packets.c +++ b/tests/test_etcp_100_packets.c @@ -149,6 +149,9 @@ static void check_received_packets_fwd(void) { struct ETCP_CONN* conn = server_instance->connections; if (!conn || !conn->output_queue) return; + // Disable routing callback to keep packets in output_queue for test verification + queue_set_callback(conn->output_queue, NULL, NULL); + struct ETCP_FRAGMENT* pkt; while ((pkt = (struct ETCP_FRAGMENT*)queue_data_get(conn->output_queue)) != NULL) { if (pkt->ll.len >= PACKET_SIZE) { @@ -178,7 +181,10 @@ static void check_received_packets_back(void) { struct ETCP_CONN* conn = client_instance->connections; if (!conn || !conn->output_queue) return; - + + // Disable routing callback to keep packets in output_queue for test verification + queue_set_callback(conn->output_queue, NULL, NULL); + struct ETCP_FRAGMENT* pkt; while ((pkt = (struct ETCP_FRAGMENT*)queue_data_get(conn->output_queue)) != NULL) { if (pkt->ll.len >= PACKET_SIZE) { diff --git a/tests/test_etcp_minimal b/tests/test_etcp_minimal index 2a0cd31f..1624fe53 100755 Binary files a/tests/test_etcp_minimal and b/tests/test_etcp_minimal differ diff --git a/tests/test_etcp_simple_traffic b/tests/test_etcp_simple_traffic index 69835f67..6b12cd71 100755 Binary files a/tests/test_etcp_simple_traffic and b/tests/test_etcp_simple_traffic differ diff --git a/tests/test_etcp_simple_traffic.c b/tests/test_etcp_simple_traffic.c index 9e99ba61..4c2b0a8e 100644 --- a/tests/test_etcp_simple_traffic.c +++ b/tests/test_etcp_simple_traffic.c @@ -159,6 +159,9 @@ static void check_packet_received(void) { DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "check_packet_received: Checking server connection %p", conn); DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "check_packet_received: Server output_queue count: %d", queue_entry_count(conn->output_queue)); + // Disable routing callback to keep packets in output_queue for test verification + queue_set_callback(conn->output_queue, NULL, NULL); + // Check if there's any packet in output queue struct ETCP_FRAGMENT* pkt = (struct ETCP_FRAGMENT*)queue_data_get(conn->output_queue); if (pkt) { @@ -376,7 +379,7 @@ int main() { conn = conn->next; } printf("=== End Debug ===\n\n"); - + // Start monitoring and packet transmission printf("Starting packet transmission test...\n"); packet_timeout_id = uasync_set_timeout(ua, 500, NULL, monitor_and_send); diff --git a/tests/test_etcp_two_instances b/tests/test_etcp_two_instances index 6c1d7348..cc2c697c 100755 Binary files a/tests/test_etcp_two_instances and b/tests/test_etcp_two_instances differ diff --git a/tests/test_pkt_normalizer_etcp b/tests/test_pkt_normalizer_etcp index 45ce082b..4846475c 100755 Binary files a/tests/test_pkt_normalizer_etcp and b/tests/test_pkt_normalizer_etcp differ diff --git a/tests/test_pkt_normalizer_etcp.c b/tests/test_pkt_normalizer_etcp.c index 6ae6f403..1056c814 100644 --- a/tests/test_pkt_normalizer_etcp.c +++ b/tests/test_pkt_normalizer_etcp.c @@ -469,10 +469,10 @@ int main() { if (global_timeout_id) uasync_cancel_timeout(ua, global_timeout_id); if (server_pn) { - pn_pair_deinit(server_pn); + pn_deinit(server_pn); } if (client_pn) { - pn_pair_deinit(client_pn); + pn_deinit(client_pn); } if (server_instance) { diff --git a/tests/test_pkt_normalizer_standalone b/tests/test_pkt_normalizer_standalone index 7243fdc4..221b8ce1 100755 Binary files a/tests/test_pkt_normalizer_standalone and b/tests/test_pkt_normalizer_standalone differ diff --git a/tests/test_pkt_normalizer_standalone.c b/tests/test_pkt_normalizer_standalone.c index 499489dc..0cb0fd96 100644 --- a/tests/test_pkt_normalizer_standalone.c +++ b/tests/test_pkt_normalizer_standalone.c @@ -198,7 +198,7 @@ static int init_mock_etcp(void) { // Cleanup static void cleanup(void) { if (pn) { - pn_pair_deinit(pn); + pn_deinit(pn); } if (mock_etcp.input_queue) {