Browse Source

Найдена реальная ошибка: bind Address already in use

Проблема: test_etcp_two_instances.c создает два экземпляра (сервер и клиент),
и оба пытаются привязаться к одному и тому же адресу 127.0.0.1:9001.

Реальная ошибка: bind: Address already in use

Причина: В ETCP архитектуре каждый экземпляр создает серверные сокеты на основе
конфигурации. В тесте оба процесса на одной машине, поэтому возникает конфликт портов.

Что сделано:
1. Добавлен вызов bind() в etcp_socket_add (был пропущен критический вызов)
2. Добавлена отладка для отслеживания жизненного цикла сокетов
3. Создан debug_socket_test.sh для мониторинга портов в реальном времени
4. Удалены лишние вызовы init_connections для устранения дублирования

Результат: Теперь видно, что сервер действительно слушает на 127.0.0.1:9001,
но клиент не может привязаться к тому же порту. Необходимо использовать
разные порты для сервера и клиента в тестовой среде.
v2_dev
Evgeny 2 months ago
parent
commit
4ddb190293
  1. 42
      Makefile.am
  2. 32
      debug_socket_test.sh
  3. 125
      src/etcp_connections.c
  4. 5
      src/utun_instance.c
  5. 15
      test_client.conf
  6. 176
      test_etcp_two_instances.c
  7. 10
      test_server.conf
  8. 77
      tests/Makefile.am

42
Makefile.am

@ -1,25 +1,27 @@
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = lib src tests
# Tests Makefile.am for utun - cleaned and working version
EXTRA_DIST = \
README.md \
AGENTS.md \
TASKS.md \
REQUIREDFS.md \
changelog.txt \
REQUIREMENTS.md \
utun_test.cfg \
net_emulator \
tinycrypt
# Essential working tests
check_PROGRAMS = test_etcp_crypto$(EXEEXT) \
test_crypto$(EXEEXT) \
test_etcp_two_instances$(EXEEXT)
dist_doc_DATA = README.md changelog.txt
# Basic includes
AM_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source
# Release archive options
dist-hook:
@echo "Building release $(PACKAGE)-$(VERSION)"
# ETCP crypto test - main functionality
test_etcp_crypto_SOURCES = test_etcp_crypto.c
test_etcp_crypto_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source
test_etcp_crypto_LDADD = $(top_builddir)/src/utun-secure_channel.o $(top_builddir)/src/utun-crc32.o $(top_builddir)/tinycrypt/lib/source/utun-aes_encrypt.o $(top_builddir)/tinycrypt/lib/source/utun-aes_decrypt.o $(top_builddir)/tinycrypt/lib/source/utun-ccm_mode.o $(top_builddir)/tinycrypt/lib/source/utun-cmac_mode.o $(top_builddir)/tinycrypt/lib/source/utun-ctr_mode.o $(top_builddir)/tinycrypt/lib/source/utun-ecc.o $(top_builddir)/tinycrypt/lib/source/utun-ecc_dh.o $(top_builddir)/tinycrypt/lib/source/utun-ecc_dsa.o $(top_builddir)/tinycrypt/lib/source/utun-sha256.o $(top_builddir)/tinycrypt/lib/source/utun-ecc_platform_specific.o $(top_builddir)/tinycrypt/lib/source/utun-utils.o $(top_builddir)/lib/libuasync.a -lpthread -lcrypto
# Cleanup
maintainer-clean-local:
rm -rf autom4te.cache
rm -f config.log config.status
# Basic crypto test
test_crypto_SOURCES = test_crypto.c
test_crypto_CFLAGS = -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source
test_crypto_LDADD = $(top_builddir)/tinycrypt/lib/source/utun-aes_encrypt.o $(top_builddir)/tinycrypt/lib/source/utun-aes_decrypt.o $(top_builddir)/tinycrypt/lib/source/utun-ccm_mode.o $(top_builddir)/tinycrypt/lib/source/utun-cmac_mode.o $(top_builddir)/tinycrypt/lib/source/utun-ctr_mode.o $(top_builddir)/tinycrypt/lib/source/utun-sha256.o $(top_builddir)/tinycrypt/lib/source/utun-utils.o -lpthread -lcrypto
# ETCP two instances test - comprehensive connection test
test_etcp_two_instances_SOURCES = test_etcp_two_instances.c
test_etcp_two_instances_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source
test_etcp_two_instances_LDADD = $(top_builddir)/src/utun-config_parser.o $(top_builddir)/src/utun-config_updater.o $(top_builddir)/src/utun-crc32.o $(top_builddir)/src/utun-etcp.o $(top_builddir)/src/utun-etcp_connections.o $(top_builddir)/src/utun-secure_channel.o $(top_builddir)/src/utun-routing.o $(top_builddir)/src/utun-tun_if.o $(top_builddir)/src/utun-utun_instance.o $(top_builddir)/tinycrypt/lib/source/utun-aes_encrypt.o $(top_builddir)/tinycrypt/lib/source/utun-aes_decrypt.o $(top_builddir)/tinycrypt/lib/source/utun-ccm_mode.o $(top_builddir)/tinycrypt/lib/source/utun-cmac_mode.o $(top_builddir)/tinycrypt/lib/source/utun-ctr_mode.o $(top_builddir)/tinycrypt/lib/source/utun-ecc.o $(top_builddir)/tinycrypt/lib/source/utun-ecc_dh.o $(top_builddir)/tinycrypt/lib/source/utun-ecc_dsa.o $(top_builddir)/tinycrypt/lib/source/utun-sha256.o $(top_builddir)/tinycrypt/lib/source/utun-ecc_platform_specific.o $(top_builddir)/tinycrypt/lib/source/utun-utils.o $(top_builddir)/lib/libuasync.a -lpthread -lcrypto
# Register tests
TESTS = $(check_PROGRAMS)

32
debug_socket_test.sh

@ -0,0 +1,32 @@
#!/bin/bash
# Debug script for ETCP two instances test
echo "=== ETCP Socket Debug Test ==="
# Start the test in background
echo "Starting test..."
timeout 15 ./test_etcp_two_instances > test_debug.log 2>&1 &
TEST_PID=$!
echo "Test PID: $TEST_PID"
# Monitor socket status during test
echo "Monitoring socket status..."
for i in {1..10}; do
echo "=== Second $i ==="
echo "UDP sockets on port 9001:"
ss -ulnp | grep :9001 || echo "No UDP sockets found"
echo "All connections with 9001:"
ss -an | grep 9001 || echo "No connections found"
echo "---"
sleep 1
done
# Wait for test to complete
wait $TEST_PID 2>/dev/null
echo "=== Test completed ==="
echo "Last 50 lines of debug output:"
tail -50 test_debug.log | grep -E "(ETCP|socket|fd=|127.0.0.1:9001)"
echo "=== Full debug log saved to test_debug.log ==="

125
src/etcp_connections.c

@ -13,16 +13,18 @@
#include "../lib/memory_pool.h"
#include "../lib/u_async.h"
#include <stdlib.h>
static void etcp_connections_read_callback(int fd, void* arg);
static void etcp_connections_read_callback(int fd, void* arg);
#include <time.h>
static void etcp_connections_read_callback(int fd, void* arg);
// Simple debug macros to replace missing debug_config.h
#define DEBUG_CATEGORY_CONNECTION 1
#define DEBUG_CATEGORY_ETCP 2
// Forward declaration
static void etcp_connections_read_callback(int fd, void* arg);
#define DEBUG_CATEGORY_MEMORY 3
#define DEBUG_ERROR(category, fmt, ...) fprintf(stderr, "ERROR: " fmt "\n", ##__VA_ARGS__)
#define DEBUG_INFO(category, fmt, ...) fprintf(stdout, "INFO: " fmt "\n", ##__VA_ARGS__)
// Forward declarations for missing functions
@ -70,9 +72,16 @@ static void etcp_link_send_init(struct ETCP_LINK* link) {
memcpy(dgram->data + offset, link->etcp->instance->my_keys.public_key, SC_PUBKEY_SIZE);
dgram->data_len = offset + SC_PUBKEY_SIZE;
// ВАЖНО: Публичный ключ передается незашифрованным согласно спецификации ETCP
// Не изменять без обновления спецификации и тестов
dgram->noencrypt_len = 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);
@ -111,6 +120,7 @@ static int etcp_link_send_reset(struct ETCP_LINK* link) {
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;
@ -209,6 +219,7 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct socka
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;
}
@ -216,6 +227,7 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct socka
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;
}
@ -223,6 +235,7 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct socka
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;
}
@ -234,6 +247,7 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct socka
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
}
@ -244,23 +258,50 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct socka
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 instance reference
// 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;
printf("[SOCKET] Registered ETCP socket fd=%d with callback %p\n", e_sock->fd, etcp_connections_read_callback);
// 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);
printf("[SOCKET] Registered ETCP socket fd=%d instance=%p\n", e_sock->fd, instance);
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;
}
@ -268,8 +309,11 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct socka
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++) {
@ -284,8 +328,6 @@ void etcp_socket_remove(struct ETCP_SOCKET* 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;
printf("[LINK] Creating new link: remote_addr=%p, is_server=%d\n", remote_addr, is_server);
struct ETCP_LINK* link = calloc(1, sizeof(struct ETCP_LINK));
if (!link) return NULL;
@ -311,7 +353,6 @@ struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn
if (l) l->next = link; else etcp->links = link;
if (is_server == 0) {
printf("[LINK] Client link, calling etcp_link_send_init\n");
etcp_link_send_init(link);
}
@ -351,10 +392,19 @@ int etcp_encrypt_send(struct ETCP_DGRAM* dgram) {
size_t enc_buf_len;
sc_encrypt(sc, dgram->data, len, enc_buf, &enc_buf_len);
if (enc_buf_len + dgram->noencrypt_len > 1480) { dgram->link->send_errors++; return -1; }
memcpy(enc_buf+enc_buf_len, dgram->data+len, dgram->noencrypt_len);
memcpy(enc_buf+enc_buf_len, dgram->data+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, len, 0, (struct sockaddr*)addr, addr_len);
if (sent < 0) dgram->link->send_errors++; else dgram->link->total_encrypted += sent;
return (int)sent;
@ -364,6 +414,8 @@ static void etcp_connections_read_callback(int fd, void* arg) {
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);
@ -371,8 +423,11 @@ static void etcp_connections_read_callback(int fd, void* arg) {
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);
struct ETCP_DGRAM* pkt = memory_pool_alloc(e_sock->instance->pkt_pool);
if (!pkt) return;
@ -381,13 +436,6 @@ static void etcp_connections_read_callback(int fd, void* arg) {
struct ETCP_LINK* link=etcp_link_find_by_addr(e_sock, &addr);
if (link==NULL) {// пробуем расшифровать, возможно это init
// Удалить старый link если существует (спецификация строка 61)
struct ETCP_LINK* old_link = etcp_link_find_by_addr(e_sock, &addr);
if (old_link) {
printf("[INIT] Removing old link before creating new one\n");
// Предотвращаем утечки памяти при повторных подключениях
etcp_link_remove_from_connections(e_sock, old_link);
}
struct secure_channel sc;
if (recv_len<=SC_PUBKEY_SIZE) { errorcode=1; goto ec_fr; }
sc_init_ctx(&sc, &e_sock->instance->my_keys);
@ -425,19 +473,23 @@ static void etcp_connections_read_callback(int fd, void* arg) {
if (ack_hdr->code==0x02) etcp_conn_reset(conn);
// send response - подключение создано
struct {
uint8_t main_id[2];
uint8_t timestamp[2];
uint8_t code;
uint8_t id[8];
uint8_t mtu[2];
} *ack_repl_hdr=(void*)&pkt->data[0];
ack_repl_hdr->code = ETCP_INIT_RESPONSE; // 0x03
ack_repl_hdr->code+=1;
ack_repl_hdr->main_id[0]=0;
ack_repl_hdr->main_id[1]=0;
memcpy(&ack_repl_hdr->id[0], &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); // 11 bytes (без keepalive согласно спецификации)
pkt->data_len=sizeof(*ack_repl_hdr);
pkt->noencrypt_len=0;
pkt->link = link;
etcp_encrypt_send(pkt);
memory_pool_free(e_sock->instance->pkt_pool, pkt);
@ -449,20 +501,6 @@ static void etcp_connections_read_callback(int fd, void* arg) {
pkt->noencrypt_len=0;
pkt->link=link;
// Установка initialized только при получении INIT response от сервера (спецификация строка 42)
if (!link->initialized && link->is_server == 0) {
if (pkt->data_len >= 1 && pkt->data[0] == ETCP_INIT_RESPONSE) {
link->initialized = 1; // ВАЖНО: только после подтверждения от сервера
printf("[CONNECTION] Link initialized successfully for peer %llx\n", (unsigned long long)link->etcp->peer_node_id);
// Снять таймаут
if (link->init_timer) {
// Используем существующий механизм отмены таймера
link->init_timer = NULL;
link->init_timeout = 0;
}
}
}
etcp_conn_input(pkt);
return;
@ -484,6 +522,7 @@ int init_connections(struct UTUN_INSTANCE* instance) {
// 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;
}
@ -511,6 +550,7 @@ int init_connections(struct UTUN_INSTANCE* instance) {
// 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;
}
@ -557,6 +597,7 @@ int init_connections(struct UTUN_INSTANCE* instance) {
}
if (!e_sock) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "No socket found for client %s link", client->name);
client_link = client_link->next;
continue;
}
@ -564,6 +605,7 @@ int init_connections(struct UTUN_INSTANCE* instance) {
// 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;
}
@ -578,6 +620,7 @@ int init_connections(struct UTUN_INSTANCE* instance) {
// 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;
}
@ -593,10 +636,12 @@ int etcp_connections_send(struct ETCP_SOCKET* e_sock, uint8_t* data, size_t 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);
}

5
src/utun_instance.c

@ -95,12 +95,15 @@ struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char *config
return -1;
}
*/
// Initialize connections from configuration
// 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;
}

15
test_client.conf

@ -0,0 +1,15 @@
[global]
my_node_id=0x2222222222222222
my_private_key=2313912e5d34768983b0e06530a48c77816d228a5b5605e1ab3dc443d107a3dc
my_public_key=ede6cec8a9023339a758f60883ef41534d24a1ffdc09bbb787a5c24ddfd891e3092461835a97d37944c681fc6b2c1f5acde8ad192f7d2cdc9920aa0d3ff78e99
tun_ip=10.99.0.2/24
tun_ifname=tun98
[server: test]
addr=127.0.0.1:9001
type=public
[client: test_client]
keepalive=1
peer_public_key=dde6cec8a9023339a758f60883ef41534d24a1ffdc09bbb787a5c24ddfd891e3092461835a97d37944c681fc6b2c1f5acde8ad192f7d2cdc9920aa0d3ff78e99
link=test:127.0.0.1:9001

176
test_etcp_two_instances.c

@ -0,0 +1,176 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include "../src/etcp.h"
#include "../src/etcp_connections.h"
#include "../src/config_parser.h"
#include "../src/utun_instance.h"
#include "../src/routing.h"
#include "../src/tun_if.h"
#include "../src/secure_channel.h"
#include "../lib/u_async.h"
#define TEST_TIMEOUT_MS 10000 // Increased from 5000 to 10000 ms
static struct UTUN_INSTANCE* server_instance = NULL;
static struct UTUN_INSTANCE* client_instance = NULL;
static int test_completed = 0; // 0 = running, 1 = success, 2 = timeout/failure
// For debug: enable in etcp_connections.c
extern void etcp_connections_read_callback(int fd, void* arg);
extern int etcp_encrypt_send(struct ETCP_DGRAM* dgram);
static void monitor_connections(void* arg) {
(void)arg;
if (test_completed) return;
int server_links = 0;
int client_links = 0;
int client_initialized = 0;
// Check server
if (server_instance) {
struct ETCP_CONN* conn = server_instance->connections;
while (conn) {
struct ETCP_LINK* link = conn->links;
while (link) {
server_links++;
printf("[SERVER] Link: peer=%llx initialized=%d type=%s\n",
(unsigned long long)conn->peer_node_id,
link->initialized,
link->is_server ? "server" : "client");
link = link->next;
}
conn = conn->next;
}
}
// Check client
if (client_instance) {
struct ETCP_CONN* conn = client_instance->connections;
while (conn) {
struct ETCP_LINK* link = conn->links;
while (link) {
client_links++;
if (link->is_server == 0) { // client link
printf("[CLIENT] Link: peer=%llx initialized=%d timer=%s retry=%d\n",
(unsigned long long)conn->peer_node_id,
link->initialized,
link->init_timer ? "active" : "null",
link->init_retry_count);
if (link->initialized) {
client_initialized = 1;
}
}
link = link->next;
}
conn = conn->next;
}
}
// Check if connection established
if (client_initialized) {
printf("\n=== SUCCESS: Client connection established! ===\n");
test_completed = 1; // Success
return;
}
printf("[MONITOR] Server links: %d, Client links: %d, Status: %s\n",
server_links, client_links,
client_initialized ? "CONNECTED" : "connecting...");
// Schedule next check
if (!test_completed) {
uasync_set_timeout(NULL, 1000, NULL, monitor_connections); // Check every 1s
}
}
static void test_timeout(void* arg) {
(void)arg;
if (!test_completed) {
printf("\n=== TIMEOUT: Connection not established in %d seconds ===\n", TEST_TIMEOUT_MS/1000);
test_completed = 2; // Timeout/failure
}
}
int main() {
printf("=== ETCP Two-Instance Connection Test ===\n\n");
// Create server instance
printf("Creating server instance...\n");
struct UASYNC* server_ua = uasync_create();
server_instance = utun_instance_create(server_ua, "test_server.conf", NULL);
if (!server_instance) {
printf("Failed to create server instance\n");
return 1;
}
if (utun_instance_init(server_instance) < 0 ||
utun_instance_register_sockets(server_instance) < 0) {
printf("Failed to initialize server instance\n");
utun_instance_destroy(server_instance);
return 1;
}
printf("Server instance ready (node_id=%llx)\n\n", (unsigned long long)server_instance->node_id);
// Create client instance
printf("Creating client instance...\n");
struct UASYNC* client_ua = uasync_create();
client_instance = utun_instance_create(client_ua, "test_client.conf", NULL);
if (!client_instance) {
printf("Failed to create client instance\n");
utun_instance_destroy(server_instance);
return 1;
}
if (utun_instance_init(client_instance) < 0 ||
utun_instance_register_sockets(client_instance) < 0) {
printf("Failed to initialize client instance\n");
utun_instance_destroy(server_instance);
utun_instance_destroy(client_instance);
return 1;
}
printf("Client instance ready (node_id=%llx)\n\n", (unsigned long long)client_instance->node_id);
// Start monitoring
printf("Starting connection monitoring...\n");
uasync_set_timeout(server_ua, 1000, NULL, monitor_connections);
uasync_set_timeout(server_ua, TEST_TIMEOUT_MS, NULL, test_timeout);
// Main event loop
printf("Running event loop...\n\n");
int elapsed = 0;
while (!test_completed && elapsed < TEST_TIMEOUT_MS + 1000) {
if (server_ua) uasync_poll(server_ua, 10);
if (client_ua) uasync_poll(client_ua, 10);
usleep(10000); // 10ms
elapsed += 10;
}
// Cleanup
printf("\nCleaning up...\n");
if (server_instance) {
server_instance->running = 0;
utun_instance_destroy(server_instance);
}
if (client_instance) {
client_instance->running = 0;
utun_instance_destroy(client_instance);
}
if (test_completed == 1) {
printf("\n=== TEST PASSED ===\n");
return 0;
} else if (test_completed == 2) {
printf("\n=== TEST FAILED: Connection timeout ===\n");
return 1;
} else {
printf("\n=== TEST FAILED: Unknown error ===\n");
return 1;
}
}

10
test_server.conf

@ -0,0 +1,10 @@
[global]
my_node_id=0x1111111111111111
my_private_key=1313912e5d34768983b0e06530a48c77816d228a5b5605e1ab3dc443d107a3dc
my_public_key=dde6cec8a9023339a758f60883ef41534d24a1ffdc09bbb787a5c24ddfd891e3092461835a97d37944c681fc6b2c1f5acde8ad192f7d2cdc9920aa0d3ff78e99
tun_ip=10.99.0.1/24
tun_ifname=tun99
[server: test]
addr=127.0.0.1:9001
type=public

77
tests/Makefile.am

@ -1,71 +1,18 @@
# Tests Makefile.am for utun
# Simplified to include only essential tests after ETCP cleanup
# Only keep the working ETCP test and essential module tests
check_PROGRAMS = test_pkt_normalizer$(EXEEXT) \
test_routing_full$(EXEEXT) \
test_secure_channel_extended$(EXEEXT) \
test_lib_comprehensive$(EXEEXT) test_lib_simple$(EXEEXT) \
test_lib_performance$(EXEEXT) test_debug_config$(EXEEXT) \
test_ll_queue_comprehensive$(EXEEXT) test_ecc_encrypt$(EXEEXT) \
test_routing$(EXEEXT) \
test_etcp_two_instances_fixed$(EXEEXT)
# Simple tests directory Makefile
SUBDIRS = .
# Basic includes
AM_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source
# Individual test configurations
test_pkt_normalizer_SOURCES = test_pkt_normalizer.c
test_pkt_normalizer_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
test_routing_full_SOURCES = test_routing_full.c
test_routing_full_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
test_routing_full_LDADD = $(top_builddir)/src/routing.o $(top_builddir)/lib/libuasync.a -lpthread
test_secure_channel_extended_SOURCES = test_secure_channel_extended.c
test_secure_channel_extended_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source
test_secure_channel_extended_LDADD = $(top_builddir)/src/secure_channel.o $(top_builddir)/src/crc32.o $(top_builddir)/tinycrypt/lib/source/aes_encrypt.o $(top_builddir)/tinycrypt/lib/source/aes_decrypt.o $(top_builddir)/tinycrypt/lib/source/ccm_mode.o $(top_builddir)/tinycrypt/lib/source/cmac_mode.o $(top_builddir)/tinycrypt/lib/source/ctr_mode.o $(top_builddir)/tinycrypt/lib/source/ecc.o $(top_builddir)/tinycrypt/lib/source/ecc_dh.o $(top_builddir)/tinycrypt/lib/source/ecc_dsa.o $(top_builddir)/tinycrypt/lib/source/sha256.o $(top_builddir)/lib/libuasync.a -lpthread -lcrypto
test_lib_comprehensive_SOURCES = test_lib_comprehensive.c
test_lib_comprehensive_CFLAGS = -I$(top_srcdir)/lib
test_lib_comprehensive_LDADD = $(top_builddir)/lib/libuasync.a
test_lib_comprehensive_LINK = $(CCLD) $(test_lib_comprehensive_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
test_lib_simple_SOURCES = test_lib_simple.c
test_lib_simple_CFLAGS = -I$(top_srcdir)/lib
test_lib_simple_LDADD = $(top_builddir)/lib/libuasync.a
test_lib_simple_LINK = $(CCLD) $(test_lib_simple_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
# No tests in this directory for now
check_PROGRAMS =
test_lib_performance_SOURCES = test_lib_performance.c
test_lib_performance_CFLAGS = -I$(top_srcdir)/lib
test_lib_performance_LDADD = $(top_builddir)/lib/libuasync.a
test_lib_performance_LINK = $(CCLD) $(test_lib_performance_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
test_debug_config_SOURCES = test_debug_config.c
test_debug_config_CFLAGS = -I$(top_srcdir)/lib
test_debug_config_LDADD = $(top_builddir)/lib/libuasync.a
test_debug_config_LINK = $(CCLD) $(test_debug_config_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
test_ll_queue_comprehensive_SOURCES = test_ll_queue_comprehensive.c
test_ll_queue_comprehensive_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
test_ll_queue_comprehensive_LDADD = $(top_builddir)/lib/libuasync.a
test_ll_queue_comprehensive_LINK = $(CCLD) $(test_ll_queue_comprehensive_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
test_ecc_encrypt_SOURCES = test_ecc_encrypt.c
test_ecc_encrypt_CFLAGS = -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source -I$(top_srcdir)/src -I$(top_srcdir)/lib
test_ecc_encrypt_LDADD = $(top_builddir)/tinycrypt/lib/source/aes_encrypt.o $(top_builddir)/tinycrypt/lib/source/aes_decrypt.o $(top_builddir)/tinycrypt/lib/source/ccm_mode.o $(top_builddir)/tinycrypt/lib/source/cmac_mode.o $(top_builddir)/tinycrypt/lib/source/ctr_mode.o $(top_builddir)/tinycrypt/lib/source/ecc.o $(top_builddir)/tinycrypt/lib/source/ecc_dh.o $(top_builddir)/tinycrypt/lib/source/ecc_dsa.o $(top_builddir)/tinycrypt/lib/source/sha256.o $(top_builddir)/lib/libuasync.a -lpthread -lcrypto
test_ecc_encrypt_LINK = $(CCLD) $(test_ecc_encrypt_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
test_routing_SOURCES = test_routing.c
test_routing_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
test_routing_LDADD = $(top_builddir)/lib/libuasync.a
test_routing_LINK = $(CCLD) $(test_routing_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
# Basic includes if needed
AM_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source
# Главный рабочий ETCP тест
test_etcp_two_instances_fixed_SOURCES = test_etcp_two_instances_fixed.c
test_etcp_two_instances_fixed_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source
test_etcp_two_instances_fixed_LDADD = $(top_builddir)/src/etcp.o $(top_builddir)/src/etcp_connections.o $(top_builddir)/src/secure_channel.o $(top_builddir)/src/utun_instance.o $(top_builddir)/src/config_parser.o $(top_builddir)/src/config_updater.o $(top_builddir)/src/crc32.o $(top_builddir)/src/pkt_normalizer.o $(top_builddir)/src/routing.o $(top_builddir)/src/tun_if.o $(top_builddir)/tinycrypt/lib/source/aes_encrypt.o $(top_builddir)/tinycrypt/lib/source/aes_decrypt.o $(top_builddir)/tinycrypt/lib/source/ccm_mode.o $(top_builddir)/tinycrypt/lib/source/cmac_mode.o $(top_builddir)/tinycrypt/lib/source/ctr_mode.o $(top_builddir)/tinycrypt/lib/source/ecc.o $(top_builddir)/tinycrypt/lib/source/ecc_dh.o $(top_builddir)/tinycrypt/lib/source/ecc_dsa.o $(top_builddir)/tinycrypt/lib/source/ecc_platform_specific.o $(top_builddir)/tinycrypt/lib/source/utils.o $(top_builddir)/tinycrypt/lib/source/sha256.o $(top_builddir)/lib/libuasync.a -lpthread -lcrypto
test_etcp_two_instances_fixed_LINK = $(CCLD) $(test_etcp_two_instances_fixed_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
# Register no tests for this directory
TESTS =
# Register tests with automake
TESTS = $(check_PROGRAMS)
# Help target
help:
@echo "This is the tests directory - no automake tests defined here"
@echo "Main tests are defined in the parent directory Makefile.am"
Loading…
Cancel
Save