You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
686 lines
21 KiB
686 lines
21 KiB
#include "etcp_connections.h" |
|
#include <arpa/inet.h> |
|
#include "debug_config.h" |
|
#include "routing.h" |
|
#include "utun_instance.h" |
|
#include "config_parser.h" |
|
#include "crc32.h" |
|
#include "etcp.h" |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <time.h> |
|
|
|
// Бинарный поиск линка по 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(struct ETCP_SOCKET* 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, struct ETCP_SOCKET* socket, |
|
const struct sockaddr* remote_addr, socklen_t addr_len) { |
|
if (!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_calc(addr_bytes, addr_len); |
|
|
|
return link; |
|
} |
|
|
|
void etcp_link_close(struct ETCP_LINK* link) { |
|
if (!link) return; |
|
free(link); |
|
} |
|
|
|
int etcp_input(struct packet_buffer* pkt, struct ETCP_SOCKET* socket, struct ETCP_CONNECTIONS* conns) { |
|
if (!pkt || !socket || !conns) return -1; |
|
|
|
if (pkt->metadata.data_len < 1) return -1; |
|
|
|
uint8_t* data = pkt->data; |
|
uint8_t cmd = data[0]; |
|
|
|
struct sockaddr* src_addr = packet_remote_addr(pkt); |
|
socklen_t addr_len = sizeof(struct sockaddr_storage); |
|
|
|
if (cmd == ETCP_INIT_REQUEST) { |
|
if (pkt->metadata.data_len < 1 + 8 + SC_PUBKEY_SIZE + 2 + 2) { |
|
return -1; |
|
} |
|
|
|
struct ETCP_LINK* link = etcp_link_find_by_addr(conns, src_addr, addr_len); |
|
if (link) { |
|
if (link->initialized) { |
|
etcp_conn_reset(link->etcp); |
|
} |
|
etcp_link_remove_from_connections(conns, link); |
|
etcp_link_close(link); |
|
} |
|
|
|
link = etcp_link_new(NULL, socket, src_addr, addr_len); |
|
if (!link) return -1; |
|
|
|
uint8_t* p = &data[1]; |
|
link->peer_node_id = 0; |
|
memcpy(&link->peer_node_id, p, 8); |
|
p += 8; |
|
|
|
memcpy(link->peer_public_key, p, SC_PUBKEY_SIZE); |
|
link->has_peer_key = 1; |
|
p += SC_PUBKEY_SIZE; |
|
|
|
uint16_t peer_mtu = ntohs(*(uint16_t*)p); |
|
p += 2; |
|
uint16_t peer_keepalive = ntohs(*(uint16_t*)p); |
|
|
|
link->mtu = peer_mtu; |
|
link->keepalive_interval = peer_keepalive; |
|
|
|
etcp_link_add_to_connections(conns, link); |
|
|
|
return etcp_link_send_init_response(link, 1500, 30); |
|
} |
|
|
|
struct ETCP_LINK* link = etcp_link_find_by_addr(conns, src_addr, addr_len); |
|
if (!link) { |
|
struct ETCP_LINK* temp_link = etcp_link_new(NULL, socket, src_addr, addr_len); |
|
if (temp_link) { |
|
etcp_link_send_reset(temp_link); |
|
etcp_link_close(temp_link); |
|
} |
|
return -1; |
|
} |
|
|
|
if (!link->initialized) { |
|
switch (cmd) { |
|
case ETCP_INIT_RESPONSE: |
|
if (pkt->metadata.data_len < 1 + 8 + 2 + 2) return -1; |
|
|
|
link->peer_node_id = 0; |
|
memcpy(&link->peer_node_id, &data[1], 8); |
|
|
|
link->mtu = ntohs(*(uint16_t*)&data[1 + 8]); |
|
link->keepalive_interval = ntohs(*(uint16_t*)&data[1 + 8 + 2]); |
|
link->initialized = 1; |
|
break; |
|
|
|
case ETCP_CHANNEL_INIT: |
|
if (pkt->metadata.data_len < 1 + 8 + 2) return -1; |
|
|
|
link->peer_node_id = 0; |
|
memcpy(&link->peer_node_id, &data[1], 8); |
|
link->keepalive_interval = ntohs(*(uint16_t*)&data[1 + 8]); |
|
|
|
return etcp_link_send_channel_response(link); |
|
|
|
case ETCP_CHANNEL_RESPONSE: |
|
if (pkt->metadata.data_len < 1 + 8) return -1; |
|
|
|
link->peer_node_id = 0; |
|
memcpy(&link->peer_node_id, &data[1], 8); |
|
link->initialized = 1; |
|
break; |
|
|
|
case ETCP_RESET: |
|
etcp_link_remove_from_connections(conns, link); |
|
etcp_link_close(link); |
|
break; |
|
|
|
default: |
|
etcp_link_send_reset(link); |
|
return -1; |
|
} |
|
} else { |
|
if (cmd >= 0x02 && cmd <= 0x06) { |
|
etcp_link_send_reset(link); |
|
return -1; |
|
} |
|
} |
|
|
|
link->last_activity = time(NULL); |
|
|
|
return 0; |
|
} |
|
|
|
int etcp_link_init(struct ETCP_CONN* etcp, struct ETCP_LINK* link) { (void)etcp; (void)link; |
|
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((struct ETCP_SOCKET*)link->socket, data, len, |
|
(struct sockaddr*)&link->remote_addr); |
|
} |
|
|
|
int etcp_link_send_init(struct ETCP_LINK* link, int mtu, uint16_t keepalive_interval) { |
|
if (!link || mtu <= 0 || mtu > 65535) return -1; |
|
|
|
uint8_t packet[1 + 8 + SC_PUBKEY_SIZE + 2 + 2]; |
|
uint8_t* p = packet; |
|
|
|
*p++ = ETCP_INIT_REQUEST; |
|
|
|
uint64_t node_id = link->etcp->node_id; |
|
memcpy(p, &node_id, 8); |
|
p += 8; |
|
|
|
sc_context_t* sc = link->etcp->crypto_ctx; |
|
if (!sc || !sc->initialized) return -1; |
|
|
|
memcpy(p, sc->public_key, SC_PUBKEY_SIZE); |
|
p += SC_PUBKEY_SIZE; |
|
|
|
uint16_t mtu_be = htons(mtu); |
|
memcpy(p, &mtu_be, 2); |
|
p += 2; |
|
|
|
uint16_t keepalive_be = htons(keepalive_interval); |
|
memcpy(p, &keepalive_be, 2); |
|
p += 2; |
|
|
|
link->mtu = mtu; |
|
link->keepalive_interval = keepalive_interval; |
|
|
|
return etcp_socket_send((struct ETCP_SOCKET*)link->socket, packet, sizeof(packet), |
|
(struct sockaddr*)&link->remote_addr); |
|
} |
|
|
|
int etcp_link_send_init_response(struct ETCP_LINK* link, int mtu, uint16_t keepalive_interval) { |
|
if (!link || mtu <= 0 || mtu > 65535) return -1; |
|
|
|
uint8_t packet[1 + 8 + 2 + 2]; |
|
uint8_t* p = packet; |
|
|
|
*p++ = ETCP_INIT_RESPONSE; |
|
|
|
uint64_t node_id = link->etcp->node_id; |
|
memcpy(p, &node_id, 8); |
|
p += 8; |
|
|
|
uint16_t mtu_be = htons(mtu); |
|
memcpy(p, &mtu_be, 2); |
|
p += 2; |
|
|
|
uint16_t keepalive_be = htons(keepalive_interval); |
|
memcpy(p, &keepalive_be, 2); |
|
p += 2; |
|
|
|
link->mtu = mtu; |
|
link->keepalive_interval = keepalive_interval; |
|
link->initialized = 1; |
|
|
|
return etcp_socket_send((struct ETCP_SOCKET*)link->socket, packet, sizeof(packet), |
|
(struct sockaddr*)&link->remote_addr); |
|
} |
|
|
|
int etcp_link_send_channel_init(struct ETCP_LINK* link, uint16_t keepalive_interval) { |
|
if (!link) return -1; |
|
|
|
uint8_t packet[1 + 8 + 2]; |
|
uint8_t* p = packet; |
|
|
|
*p++ = ETCP_CHANNEL_INIT; |
|
|
|
uint64_t node_id = link->etcp->node_id; |
|
memcpy(p, &node_id, 8); |
|
p += 8; |
|
|
|
uint16_t keepalive_be = htons(keepalive_interval); |
|
memcpy(p, &keepalive_be, 2); |
|
p += 2; |
|
|
|
link->keepalive_interval = keepalive_interval; |
|
|
|
return etcp_socket_send((struct ETCP_SOCKET*)link->socket, packet, sizeof(packet), |
|
(struct sockaddr*)&link->remote_addr); |
|
} |
|
|
|
int etcp_link_send_channel_response(struct ETCP_LINK* link) { |
|
if (!link) return -1; |
|
|
|
uint8_t packet[1 + 8]; |
|
uint8_t* p = packet; |
|
|
|
*p++ = ETCP_CHANNEL_RESPONSE; |
|
|
|
uint64_t node_id = link->etcp->node_id; |
|
memcpy(p, &node_id, 8); |
|
p += 8; |
|
|
|
link->initialized = 1; |
|
|
|
return etcp_socket_send((struct ETCP_SOCKET*)link->socket, packet, sizeof(packet), |
|
(struct sockaddr*)&link->remote_addr); |
|
} |
|
|
|
int etcp_link_send_reset(struct ETCP_LINK* link) { |
|
if (!link) return -1; |
|
|
|
uint8_t packet[1] = {ETCP_RESET}; |
|
|
|
return etcp_socket_send((struct ETCP_SOCKET*)link->socket, packet, sizeof(packet), |
|
(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_calc((const 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) |
|
#include <unistd.h> |
|
#include <fcntl.h> |
|
#include <errno.h> |
|
#include <arpa/inet.h> |
|
|
|
struct ETCP_SOCKET* etcp_socket_create(struct ETCP_CONN* etcp, const char* bind_addr, uint16_t port) { |
|
if (!etcp) return NULL; |
|
|
|
struct ETCP_SOCKET* sock = calloc(1, sizeof(struct ETCP_SOCKET)); |
|
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(struct ETCP_SOCKET* sock) { |
|
if (!sock) return; |
|
|
|
if (sock->fd >= 0) { |
|
close(sock->fd); |
|
} |
|
|
|
free(sock); |
|
} |
|
|
|
int etcp_socket_send(struct ETCP_SOCKET* 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 struct ETCP_SOCKET* sock) { |
|
if (!sock) return -1; |
|
return sock->fd; |
|
} |
|
|
|
void etcp_socket_get_local_addr(const struct ETCP_SOCKET* 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(struct ETCP_SOCKET* 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); |
|
} |
|
|
|
// Helper function to parse IP:port address |
|
static int parse_ip_port(const char* addr_str, struct sockaddr_storage* addr, socklen_t* addr_len) { |
|
if (!addr_str || !addr || !addr_len) return -1; |
|
|
|
char* colon = strchr(addr_str, ':'); |
|
if (!colon) return -1; |
|
|
|
char ip_str[INET6_ADDRSTRLEN]; |
|
size_t ip_len = colon - addr_str; |
|
if (ip_len >= sizeof(ip_str)) return -1; |
|
|
|
strncpy(ip_str, addr_str, ip_len); |
|
ip_str[ip_len] = '\0'; |
|
|
|
char* port_str = colon + 1; |
|
int port = atoi(port_str); |
|
if (port <= 0 || port > 65535) return -1; |
|
|
|
struct sockaddr_in* sin = (struct sockaddr_in*)addr; |
|
memset(sin, 0, sizeof(struct sockaddr_in)); |
|
sin->sin_family = AF_INET; |
|
sin->sin_port = htons(port); |
|
|
|
if (inet_pton(AF_INET, ip_str, &sin->sin_addr) != 1) { |
|
return -1; |
|
} |
|
|
|
*addr_len = sizeof(struct sockaddr_in); |
|
return 0; |
|
} |
|
|
|
// Initialize connections from configuration |
|
int init_connections(struct UTUN_INSTANCE* instance) { |
|
if (!instance || !instance->config) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Invalid instance or config"); |
|
return -1; |
|
} |
|
|
|
struct utun_config* config = instance->config; |
|
int total_servers = config->server_count; |
|
|
|
if (total_servers == 0) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "No servers found in configuration"); |
|
return -1; |
|
} |
|
|
|
instance->connections = calloc(total_servers, sizeof(conn_handle_t*)); |
|
if (!instance->connections) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to allocate connections array"); |
|
return -1; |
|
} |
|
|
|
instance->connection_count = 0; |
|
|
|
for (int i = 0; i < total_servers; i++) { |
|
struct server_config* server = &config->servers[i]; |
|
|
|
// Parse server bind address |
|
struct sockaddr_storage bind_addr; |
|
socklen_t bind_addr_len; |
|
if (parse_ip_port(server->addr, &bind_addr, &bind_addr_len) < 0) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Invalid server address '%s'", server->addr); |
|
continue; |
|
} |
|
|
|
// Get bind IP and port |
|
struct sockaddr_in* sin = (struct sockaddr_in*)&bind_addr; |
|
char bind_ip_str[INET_ADDRSTRLEN]; |
|
if (!inet_ntop(AF_INET, &sin->sin_addr, bind_ip_str, sizeof(bind_ip_str))) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to convert bind address"); |
|
continue; |
|
} |
|
uint16_t bind_port = ntohs(sin->sin_port); |
|
|
|
// Create ETCP instance |
|
struct ETCP_CONN* etcp = etcp_create(instance); |
|
if (!etcp) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create ETCP for server %s", server->name); |
|
continue; |
|
} |
|
|
|
// Create socket |
|
struct ETCP_SOCKET* sock = etcp_socket_create(etcp, bind_ip_str, bind_port); |
|
if (!sock) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create socket for %s", server->name); |
|
etcp_destroy(etcp); |
|
continue; |
|
} |
|
|
|
// Create connections manager |
|
struct ETCP_CONNECTIONS* conns = etcp_connections_init(sock); |
|
if (!conns) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create connections for %s", server->name); |
|
etcp_socket_destroy(sock); |
|
etcp_destroy(etcp); |
|
continue; |
|
} |
|
|
|
// Create connection handle |
|
conn_handle_t* handle = calloc(1, sizeof(conn_handle_t)); |
|
if (!handle) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to allocate connection handle"); |
|
etcp_connections_destroy(conns); |
|
etcp_socket_destroy(sock); |
|
etcp_destroy(etcp); |
|
continue; |
|
} |
|
|
|
handle->etcp = etcp; |
|
handle->conns = conns; |
|
|
|
// Set first listen socket |
|
if (i == 0) { |
|
instance->first_listen_socket = (struct ETCP_SOCKET*)sock; |
|
} |
|
|
|
// Process clients that connect to this server |
|
for (int j = 0; j < config->client_count; j++) { |
|
struct client_config* client = &config->clients[j]; |
|
|
|
// Check if this client is for current server |
|
if (strcmp(client->from, server->name) != 0) { |
|
continue; |
|
} |
|
|
|
// Parse client address |
|
struct sockaddr_storage client_addr; |
|
socklen_t client_addr_len; |
|
if (parse_ip_port(client->to_addr, &client_addr, &client_addr_len) < 0) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Invalid client address '%s'", client->to_addr); |
|
continue; |
|
} |
|
|
|
// Create link for this client |
|
struct ETCP_LINK* link = etcp_link_new(etcp, sock, |
|
(struct sockaddr*)&client_addr, |
|
client_addr_len); |
|
if (!link) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create link for client %s", client->name); |
|
continue; |
|
} |
|
|
|
// Add link to connections |
|
if (etcp_link_add_to_connections(conns, link) < 0) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to add link for client %s", client->name); |
|
etcp_link_close(link); |
|
continue; |
|
} |
|
|
|
printf(" Added client %s -> %s\n", client->name, client->to_addr); |
|
} |
|
|
|
instance->connections[instance->connection_count++] = handle; |
|
printf("Initialized server %s on %s (links: %zu)\n", |
|
server->name, server->addr, conns->num_channels); |
|
} |
|
|
|
if (instance->connection_count == 0) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "No connections initialized"); |
|
free(instance->connections); |
|
instance->connections = NULL; |
|
return -1; |
|
} |
|
|
|
printf("Initialized %d connections\n", instance->connection_count); |
|
return 0; |
|
} |
|
|
|
void conn_destroy(conn_handle_t* handle) { |
|
if (!handle) return; |
|
|
|
if (handle->conns) { |
|
etcp_socket_destroy((struct ETCP_SOCKET*)&handle->conns->socket); |
|
etcp_connections_destroy(handle->conns); |
|
} |
|
|
|
if (handle->etcp) { |
|
etcp_destroy(handle->etcp); |
|
} |
|
|
|
free(handle); |
|
} |
|
|
|
int conn_send(conn_handle_t* conn, const uint8_t* data, size_t len) { |
|
if (!conn || !conn->etcp || !data || len == 0) { |
|
return -1; |
|
} |
|
|
|
struct ETCP_CONN* etcp = conn->etcp; |
|
struct packet_buffer* pkt = packet_pool_get(&etcp->packet_pool); |
|
if (!pkt) { |
|
return -1; |
|
} |
|
|
|
if (len > 1500) { |
|
len = 1500; |
|
} |
|
|
|
memcpy(packet_data(pkt), data, len); |
|
pkt->metadata.data_len = len; |
|
|
|
etcp_conn_input(etcp, pkt); |
|
return 0; |
|
} |
|
|
|
|
|
|
|
size_t etcp_connections_get_channel_count(const struct ETCP_CONNECTIONS* conns) { |
|
if (!conns) return 0; |
|
return conns->num_channels; |
|
} |
|
|
|
|
|
|