#include "etcp_connections.h" #include #include "routing.h" #include "utun_instance.h" #include "crc32.h" #include "etcp.h" #include #include #include // Forward declaration struct utun_instance; // Бинарный поиск линка по ip_port_hash static int find_link_index(struct ETCP_CONNECTIONS* conns, uint32_t hash) { if (!conns || conns->num_channels == 0) return -1; int left = 0; int right = conns->num_channels - 1; while (left <= right) { int mid = left + (right - left) / 2; if (conns->links[mid]->ip_port_hash == hash) { return mid; } else if (conns->links[mid]->ip_port_hash < hash) { left = mid + 1; } else { right = mid - 1; } } return -(left + 1); } // Реалокация массива линков с увеличением в 2 раза static int realloc_links(struct ETCP_CONNECTIONS* conns) { size_t new_max = conns->max_channels == 0 ? 8 : conns->max_channels * 2; struct ETCP_LINK** new_links = realloc(conns->links, new_max * sizeof(struct ETCP_LINK*)); if (!new_links) return -1; conns->links = new_links; conns->max_channels = new_max; return 0; } // Вставка линка в отсортированный массив static int insert_link(struct ETCP_CONNECTIONS* conns, struct ETCP_LINK* link) { if (!conns || !link) return -1; if (conns->num_channels >= conns->max_channels) { if (realloc_links(conns) < 0) return -1; } int idx = find_link_index(conns, link->ip_port_hash); if (idx >= 0) return -1; idx = -(idx + 1); if (idx < (int)conns->num_channels) { memmove(&conns->links[idx + 1], &conns->links[idx], (conns->num_channels - idx) * sizeof(struct ETCP_LINK*)); } conns->links[idx] = link; conns->num_channels++; return 0; } // Удаление линка из массива static void remove_link(struct ETCP_CONNECTIONS* conns, uint32_t hash) { if (!conns || conns->num_channels == 0) return; int idx = find_link_index(conns, hash); if (idx < 0) return; if (idx < (int)conns->num_channels - 1) { memmove(&conns->links[idx], &conns->links[idx + 1], (conns->num_channels - idx - 1) * sizeof(struct ETCP_LINK*)); } conns->num_channels--; } struct ETCP_CONNECTIONS* etcp_connections_init(etcp_socket_t* socket) { if (!socket) return NULL; struct ETCP_CONNECTIONS* conns = calloc(1, sizeof(struct ETCP_CONNECTIONS)); if (!conns) return NULL; memcpy(&conns->socket, socket, sizeof(struct ETCP_SOCKET)); return conns; } void etcp_connections_destroy(struct ETCP_CONNECTIONS* conns) { if (!conns) return; for (size_t i = 0; i < conns->num_channels; i++) { etcp_link_close(conns->links[i]); } free(conns->links); free(conns); } struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, etcp_socket_t* socket, const struct sockaddr* remote_addr, socklen_t addr_len) { if (!etcp || !socket || !remote_addr || addr_len == 0) return NULL; struct ETCP_LINK* link = calloc(1, sizeof(struct ETCP_LINK)); if (!link) return NULL; link->socket = (struct ETCP_SOCKET*)socket; link->etcp = etcp; memcpy(&link->remote_addr, remote_addr, addr_len); link->remote_addr_len = addr_len; link->last_activity = time(NULL); uint8_t* addr_bytes = (uint8_t*)remote_addr; link->ip_port_hash = crc32(0, addr_bytes, addr_len); return link; } void etcp_link_close(struct ETCP_LINK* link) { if (!link) return; free(link); } int etcp_input(packet_buffer_t* pkt, etcp_socket_t* socket, struct ETCP_CONNECTIONS* conns) { if (!pkt || !socket || !conns) return -1; return 0; } int etcp_link_send(struct ETCP_CONN* etcp, struct ETCP_LINK* link, const uint8_t* data, size_t len) { if (!etcp || !link || !data || len == 0) return -1; link->last_activity = time(NULL); return etcp_socket_send((etcp_socket_t*)link->socket, data, len, (struct sockaddr*)&link->remote_addr); } struct ETCP_LINK* etcp_link_find_by_addr(struct ETCP_CONNECTIONS* conns, const struct sockaddr* addr, socklen_t addr_len) { if (!conns || !addr || addr_len == 0) return NULL; uint32_t hash = crc32(0, (uint8_t*)addr, addr_len); int idx = find_link_index(conns, hash); if (idx >= 0) { return conns->links[idx]; } return NULL; } int etcp_link_add_to_connections(struct ETCP_CONNECTIONS* conns, struct ETCP_LINK* link) { if (!conns || !link) return -1; return insert_link(conns, link); } void etcp_link_remove_from_connections(struct ETCP_CONNECTIONS* conns, struct ETCP_LINK* link) { if (!conns || !link) return; remove_link(conns, link->ip_port_hash); } // SOCKET FUNCTIONS (moved from etcp_sockets.c) #include #include #include #include etcp_socket_t* etcp_socket_create(struct ETCP_CONN* etcp, const char* bind_addr, uint16_t port) { if (!etcp) return NULL; etcp_socket_t* sock = calloc(1, sizeof(etcp_socket_t)); if (!sock) return NULL; sock->etcp = etcp; sock->socket_id = (uint32_t)(uintptr_t)sock; sock->fd = socket(AF_INET, SOCK_DGRAM, 0); if (sock->fd < 0) { free(sock); return NULL; } int flags = fcntl(sock->fd, F_GETFL, 0); fcntl(sock->fd, F_SETFL, flags | O_NONBLOCK); struct sockaddr_in* addr = (struct sockaddr_in*)&sock->local_addr; addr->sin_family = AF_INET; addr->sin_port = htons(port); sock->local_addr_len = sizeof(struct sockaddr_in); if (bind_addr) { inet_pton(AF_INET, bind_addr, &addr->sin_addr); } else { addr->sin_addr.s_addr = INADDR_ANY; } if (bind(sock->fd, (struct sockaddr*)addr, sock->local_addr_len) < 0) { close(sock->fd); free(sock); return NULL; } if (getsockname(sock->fd, (struct sockaddr*)addr, &sock->local_addr_len) < 0) { close(sock->fd); free(sock); return NULL; } return sock; } void etcp_socket_destroy(etcp_socket_t* sock) { if (!sock) return; if (sock->fd >= 0) { close(sock->fd); } free(sock); } int etcp_socket_send(etcp_socket_t* sock, const uint8_t* data, size_t len, const struct sockaddr* to_addr) { if (!sock || sock->fd < 0 || !data || !to_addr) { return -1; } socklen_t addr_len = (to_addr->sa_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); return sendto(sock->fd, data, len, 0, to_addr, addr_len); } int etcp_socket_get_fd(const etcp_socket_t* sock) { if (!sock) return -1; return sock->fd; } void etcp_socket_get_local_addr(const etcp_socket_t* sock, struct sockaddr_storage* addr, socklen_t* addr_len) { if (!sock || !addr || !addr_len) return; memcpy(addr, &sock->local_addr, sock->local_addr_len); *addr_len = sock->local_addr_len; } int etcp_socket_set_option(etcp_socket_t* sock, int level, int optname, const void* optval, socklen_t optlen) { if (!sock || sock->fd < 0) return -1; return setsockopt(sock->fd, level, optname, optval, optlen); } // Connection management functions void conn_destroy(conn_handle_t* handle) { if (!handle) return; if (handle->conns) { etcp_socket_destroy((etcp_socket_t*)&handle->conns->socket); etcp_connections_destroy(handle->conns); } if (handle->etcp) { etcp_destroy(handle->etcp); } free(handle); } int conn_send(conn_handle_t* handle, const uint8_t* data, size_t len) { if (!handle || !handle->conns || handle->conns->num_channels == 0 || !data || len == 0) { return -1; } struct ETCP_LINK* link = handle->conns->links[0]; if (!link || !link->etcp) return -1; return etcp_link_send(link->etcp, link, data, len); } // Parse address in format "IP:port" or "[IPv6]:port" and fill sockaddr static int parse_addr_port(const char* addr_str, struct sockaddr_storage* addr, socklen_t* addr_len) { if (!addr_str || !addr || !addr_len) return -1; char addr_copy[MAX_ADDR_LEN]; strncpy(addr_copy, addr_str, MAX_ADDR_LEN - 1); addr_copy[MAX_ADDR_LEN - 1] = '\0'; // Check for IPv6 format: [address]:port if (addr_copy[0] == '[') { char* closing_bracket = strchr(addr_copy, ']'); if (!closing_bracket) return -1; // Find port after ']:' char* colon = strchr(closing_bracket + 1, ':'); if (!colon) return -1; *closing_bracket = '\0'; uint16_t port = (uint16_t)atoi(colon + 1); struct sockaddr_in6* sin6 = (struct sockaddr_in6*)addr; memset(sin6, 0, sizeof(struct sockaddr_in6)); sin6->sin6_family = AF_INET6; sin6->sin6_port = htons(port); // Extract IP string and port from sockaddr_storage static int sockaddr_to_ip_port(const struct sockaddr_storage* addr, char* ip_out, size_t ip_out_len, uint16_t* port_out) { if (!addr || !ip_out || !port_out) return -1; if (addr->ss_family == AF_INET) { struct sockaddr_in* sin = (struct sockaddr_in*)addr; *port_out = ntohs(sin->sin_port); if (inet_ntop(AF_INET, &sin->sin_addr, ip_out, ip_out_len) == NULL) return -1; } else if (addr->ss_family == AF_INET6) { struct sockaddr_in6* sin6 = (struct sockaddr_in6*)addr; *port_out = ntohs(sin6->sin6_port); if (inet_ntop(AF_INET6, &sin6->sin6_addr, ip_out, ip_out_len) == NULL) return -1; } else { return -1; } return 0; } for (int i = 0; i < config->server_count; i++) { server_config_t* server = &config->servers[i]; char bind_addr[INET_ADDRSTRLEN]; struct sockaddr_storage server_addr; socklen_t server_addr_len; if (parse_addr_port(server->addr, &server_addr, &server_addr_len) < 0) { fprintf(stderr, "Invalid server address '%s'\n", server->addr); goto cleanup; } char bind_addr_str[INET6_ADDRSTRLEN]; uint16_t bind_port; if (sockaddr_to_ip_port(&server_addr, bind_addr_str, sizeof(bind_addr_str), &bind_port) < 0) { etcp_destroy(etcp); goto cleanup; } } etcp_socket_t* sock = etcp_socket_create(etcp, bind_addr, bind_port); if (!sock) { fprintf(stderr, "Failed to create socket for %s\n", server->name); etcp_destroy(etcp); goto cleanup; } if (i == 0) { instance->first_listen_socket = (struct ETCP_SOCKET*)sock; } struct ETCP_CONNECTIONS* conns = etcp_connections_init(sock); if (!conns) { etcp_socket_destroy(sock); etcp_destroy(etcp); goto cleanup; } conn_handle_t* handle = calloc(1, sizeof(conn_handle_t)); if (!handle) { etcp_connections_destroy(conns); etcp_socket_destroy(sock); etcp_destroy(etcp); goto cleanup; } handle->etcp = etcp; handle->conns = conns; for (int j = 0; j < config->client_count; j++) { client_config_t* client = &config->clients[j]; if (strcmp(client->from, server->name) != 0) continue; struct sockaddr_storage client_addr; socklen_t client_addr_len; if (parse_addr_port(client->to_addr, &client_addr, &client_addr_len) < 0) { fprintf(stderr, "Invalid client address '%s'\n", client->to_addr); continue; } memcpy(&addr, &client_addr, client_addr_len); addr_len = client_addr_len; struct sockaddr_in* sin = (struct sockaddr_in*)&addr; memset(sin, 0, sizeof(struct sockaddr_in)); sin->sin_family = AF_INET; sin->sin_port = htons(client_port); if (inet_pton(AF_INET, client_addr, &sin->sin_addr) != 1) continue; addr_len = sizeof(struct sockaddr_in); struct ETCP_LINK* link = etcp_link_new(etcp, sock, (struct sockaddr*)&addr, addr_len); if (link) { etcp_link_add_to_connections(conns, link); } } instance->connections[i] = handle; } instance->connection_count = config->server_count; return 0; cleanup: if (instance->connections) { for (int j = 0; j < 0; j++) { if (instance->connections[j]) { conn_destroy(instance->connections[j]); } } free(instance->connections); instance->connections = NULL; } instance->first_listen_socket = NULL; instance->connection_count = 0; return -1; } #include "etcp_connections.h" #include "etcp.h" #include "config_parser.h" #include "utun_instance.h" #include #include #include // Parse address in format "IP:port" or "[IPv6]:port" and fill sockaddr if (!addr || !ip_out || !port_out) return -1; if (addr->ss_family == AF_INET) { struct sockaddr_in* sin = (struct sockaddr_in*)addr; *port_out = ntohs(sin->sin_port); if (inet_ntop(AF_INET, &sin->sin_addr, ip_out, ip_out_len) == NULL) return -1; } else if (addr->ss_family == AF_INET6) { struct sockaddr_in6* sin6 = (struct sockaddr_in6*)addr; *port_out = ntohs(sin6->sin6_port); if (inet_ntop(AF_INET6, &sin6->sin6_addr, ip_out, ip_out_len) == NULL) return -1; } else { return -1; } return 0; int init_connections(utun_instance_t* instance) { if (!instance || !instance->config) { fprintf(stderr, "Invalid instance or config\n"); return -1; } utun_config_t* config = instance->config; int total_connections = config->server_count, i = 0; if (total_connections == 0) { fprintf(stderr, "No servers found in configuration\n"); return -1; } instance->connections = calloc(total_connections, sizeof(conn_handle_t*)); if (!instance->connections) { fprintf(stderr, "Failed to allocate connections array\n"); return -1; } for (i = 0; i < config->server_count; i++) { server_config_t* server = &config->servers[i]; struct sockaddr_storage server_addr; socklen_t server_addr_len; if (parse_addr_port(server->addr, &server_addr, &server_addr_len) < 0) { fprintf(stderr, "Invalid server address '%s'\n", server->addr); goto cleanup; } struct ETCP_CONN* etcp = etcp_create(instance); if (!etcp) { fprintf(stderr, "Failed to create ETCP for server %s\n", server->name); goto cleanup; } char bind_addr_str[INET6_ADDRSTRLEN]; } conn_handle_t* handle = calloc(1, sizeof(conn_handle_t)); if (!handle) { etcp_connections_destroy(conns); etcp_socket_destroy(sock); etcp_destroy(etcp); goto cleanup; } handle->etcp = etcp; handle->conns = conns; for (int j = 0; j < config->client_count; j++) { client_config_t* client = &config->clients[j]; if (strcmp(client->from, server->name) != 0) continue; struct sockaddr_storage client_addr; socklen_t client_addr_len; if (parse_addr_port(client->to_addr, &client_addr, &client_addr_len) < 0) { fprintf(stderr, "Invalid client address '%s'\n", client->to_addr); continue; } struct sockaddr_storage addr; socklen_t addr_len = client_addr_len; struct ETCP_LINK* link = etcp_link_new(etcp, sock, (struct sockaddr*)&addr, addr_len); if (link) { etcp_link_add_to_connections(conns, link); } } instance->connections[i] = handle; } instance->connection_count = config->server_count; return 0; cleanup: if (instance->connections) { for (int j = 0; j < i; j++) { if (instance->connections[j]) { conn_destroy(instance->connections[j]); } } free(instance->connections); instance->connections = NULL; } instance->first_listen_socket = NULL; instance->connection_count = 0; return -1;