Browse Source

Implements connection establishment (init + init response) for ETCP protocol

- Added connection state tracking (initialized, init_timer, timeout, retry_count)
- Implemented etcp_link_send_init() with proper packet formatting
- Configured retry timeouts (initial 50ms, double every 10, max 5000ms)
- Auto-start connection establishment for client links in etcp_link_new()
- Implemented etcp_connections_send() with connection initiation logic
- Created test_etcp_connection_init.c for testing handshake process
v2_dev
Evgeny 2 months ago
parent
commit
ec66a80492
  1. 140
      src/etcp_connections.c
  2. 7
      src/etcp_connections.h
  3. 198
      tests/test_etcp_connection_init.c

140
src/etcp_connections.c

@ -32,8 +32,87 @@ static void etcp_link_remove_from_connections(struct ETCP_SOCKET* conn, struct E
// Отправка кодограмм протокола (!!!это всё должно быть static!!!) // Отправка кодограмм протокола (!!!это всё должно быть static!!!)
static int etcp_link_send_init(struct ETCP_LINK* link, int mtu, uint16_t keepalive_interval); static void etcp_link_send_init(struct ETCP_LINK* link);
static int etcp_link_send_reset(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);
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) { 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); socklen_t addr_len = (addr->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
@ -224,22 +303,40 @@ struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn
link->conn = conn; link->conn = conn;
link->etcp = etcp; link->etcp = etcp;
link->is_server = is_server; 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)); memcpy(&link->remote_addr, remote_addr, sizeof(struct sockaddr_storage));
link->last_activity = time(NULL); link->last_activity = time(NULL);
link->ip_port_hash = sockaddr_hash(remote_addr); link->ip_port_hash = sockaddr_hash(remote_addr);
insert_link(conn, link);// вставим в bind 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);
}
struct ETCP_LINK* l=etcp->links;// и вставим в link
while (l->next) l=l->next;
l->next = link;
return link; return link;
} }
void etcp_link_close(struct ETCP_LINK* link) { void etcp_link_close(struct ETCP_LINK* link) {
if (!link || !link->etcp) return; 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; struct ETCP_LINK **pp = &link->etcp->links;
while (*pp) { while (*pp) {
@ -483,3 +580,36 @@ int init_connections(struct UTUN_INSTANCE* instance) {
printf("Initialized %d connections\n", instance->connections_count); printf("Initialized %d connections\n", instance->connections_count);
return 0; 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;
}

7
src/etcp_connections.h

@ -55,7 +55,12 @@ struct ETCP_LINK {
uint16_t mtu; // MTU соединения uint16_t mtu; // MTU соединения
uint16_t keepalive_interval; // Keepalive интервал uint16_t keepalive_interval; // Keepalive интервал
uint8_t is_server; // инициирует подключение клиент uint8_t is_server; // инициирует подключение клиент
uint8_t initialized; // Флаг инициализации 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_activity; // Время последней активности

198
tests/test_etcp_connection_init.c

@ -0,0 +1,198 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include "../lib/crc32.h"
#include "../lib/memory_pool.h"
#include "../lib/u_async.h"
#include "../lib/ll_queue.h"
#include "../tinycrypt/lib/include/tinycrypt/aes.h"
#include "../tinycrypt/lib/include/tinycrypt/ccm_mode.h"
#include "../tinycrypt/lib/include/tinycrypt/ecc.h"
#include "../tinycrypt/lib/include/tinycrypt/ecc_dh.h"
#include "../tinycrypt/lib/include/tinycrypt/constants.h"
#include "../tinycrypt/lib/include/tinycrypt/sha256.h"
#include "../src/utun_instance.h"
#include "../src/config_parser.h"
#include "../src/routing.h"
#include "../src/etcp.h"
#include "../src/etcp_connections.h"
#include "../src/secure_channel.h"
#include "../src/crc32.h"
struct test_context {
struct UTUN_INSTANCE* server;
struct UTUN_INSTANCE* client;
int init_received_server;
int init_received_client;
int response_received_server;
int response_received_client;
int test_completed;
};
static void print_hex(const char* label, const uint8_t* data, size_t len) {
printf("%s: ", label);
for (size_t i = 0; i < len && i < 32; i++) {
printf("%02x", data[i]);
}
printf("\n");
}
static int wait_for_init_completion(struct test_context* ctx, int timeout_ms) {
int elapsed = 0;
while (elapsed < timeout_ms && !ctx->test_completed) {
uasync_poll(ctx->client->ua, 10);
uasync_poll(ctx->server->ua, 10);
usleep(10000);
elapsed += 10;
}
return ctx->test_completed;
}
static void check_connections(struct test_context* ctx) {
struct ETCP_CONN* conn = ctx->client->connections;
while (conn) {
struct ETCP_LINK* link = conn->links;
while (link) {
if (link->is_server == 0) {
printf("Client link: initialized=%d, retry_count=%d, timer=%s\n",
link->initialized, link->init_retry_count,
link->init_timer ? "active" : "null");
if (link->initialized) {
printf("SUCCESS: Client connection established!\n");
ctx->test_completed = 1;
}
}
link = link->next;
}
conn = conn->next;
}
conn = ctx->server->connections;
while (conn) {
struct ETCP_LINK* link = conn->links;
while (link) {
if (link->is_server == 1) {
printf("Server link: initialized=%d\n", link->initialized);
}
link = link->next;
}
conn = conn->next;
}
}
int main() {
printf("=== ETCP Connection Establishment Test ===\n\n");
struct test_context ctx = {0};
ctx.server = calloc(1, sizeof(struct UTUN_INSTANCE));
ctx.client = calloc(1, sizeof(struct UTUN_INSTANCE));
if (!ctx.server || !ctx.client) {
printf("Failed to allocate instances\n");
return 1;
}
ctx.server->ua = uasync_create();
ctx.client->ua = uasync_create();
if (!ctx.server->ua || !ctx.client->ua) {
printf("Failed to create uasync instances\n");
return 1;
}
ctx.server->node_id = 0x1111111111111111ULL;
ctx.client->node_id = 0x2222222222222222ULL;
// Generate keypairs
sc_generate_keypair(&ctx.server->my_keys);
sc_generate_keypair(&ctx.client->my_keys);
printf("Server node_id: 0x%llx\n", (unsigned long long)ctx.server->node_id);
printf("Client node_id: 0x%llx\n", (unsigned long long)ctx.client->node_id);
print_hex("Server public key", ctx.server->my_keys.public_key, SC_PUBKEY_SIZE);
print_hex("Client public key", ctx.client->my_keys.public_key, SC_PUBKEY_SIZE);
// Configure server socket (listen on localhost:9001)
struct ETCP_SOCKET* server_sock = etcp_socket_add(ctx.server, NULL, 0, 0, 0);
if (!server_sock) {
printf("Failed to create server socket\n");
return 1;
}
struct sockaddr_in server_addr = {0};
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(9001);
if (bind(server_sock->fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
printf("Failed to bind server socket\n");
return 1;
}
// Create server ETCP connection
struct ETCP_CONN* server_conn = etcp_connection_create(ctx.server);
if (!server_conn) {
printf("Failed to create server ETCP connection\n");
return 1;
}
sc_init_ctx(&server_conn->crypto_ctx, &ctx.server->my_keys);
printf("\n=== Starting connection test ===\n");
// Create client socket
struct ETCP_SOCKET* client_sock = etcp_socket_add(ctx.client, NULL, 0, 0, 0);
if (!client_sock) {
printf("Failed to create client socket\n");
return 1;
}
// Create client ETCP connection
struct ETCP_CONN* client_conn = etcp_connection_create(ctx.client);
if (!client_conn) {
printf("Failed to create client ETCP connection\n");
return 1;
}
sc_init_ctx(&client_conn->crypto_ctx, &ctx.client->my_keys);
// Set peer public key for both sides
sc_set_peer_public_key(&server_conn->crypto_ctx, ctx.server->my_keys.public_key, 0);
sc_set_peer_public_key(&client_conn->crypto_ctx, ctx.client->my_keys.public_key, 0);
// Create client link (this will auto-start init)
struct sockaddr_storage server_remote_addr = {0};
memcpy(&server_remote_addr, &server_addr, sizeof(server_addr));
server_remote_addr.ss_family = AF_INET;
struct ETCP_LINK* client_link = etcp_link_new(client_conn, client_sock, &server_remote_addr, 0);
if (!client_link) {
printf("Failed to create client link\n");
return 1;
}
printf("\nClient link created, is_server=%d, init_timer=%s\n",
client_link->is_server, client_link->init_timer ? "active" : "null");
// Poll for 5 seconds to allow handshake
printf("\nWaiting for connection establishment (5 seconds)...\n");
int completed = wait_for_init_completion(&ctx, 5000);
check_connections(&ctx);
if (completed) {
printf("\n=== TEST PASSED ===\n");
printf("Connection established successfully!\n");
return 0;
} else {
printf("\n=== TEST FAILED ===\n");
printf("Connection not established within timeout\n");
return 1;
}
}
Loading…
Cancel
Save