@ -13,16 +13,18 @@
# include "../lib/memory_pool.h"
# include "../lib/memory_pool.h"
# include "../lib/u_async.h"
# include "../lib/u_async.h"
# include <stdlib.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>
# include <time.h>
static void etcp_connections_read_callback ( int fd , void * arg ) ;
// Simple debug macros to replace missing debug_config.h
// 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
// 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 ) ;
memcpy ( dgram - > data + offset , link - > etcp - > instance - > my_keys . public_key , SC_PUBKEY_SIZE ) ;
dgram - > data_len = offset + SC_PUBKEY_SIZE ;
dgram - > data_len = offset + SC_PUBKEY_SIZE ;
// ВАЖНО: Публичный ключ передается незашифрованным согласно спецификации ETCP
// Не изменять без обновления спецификации и тестов
DEBUG_INFO ( DEBUG_CATEGORY_CONNECTION , " Sending INIT request to link, node_id=%llu, retry=%d " , ( unsigned long long ) node_id , link - > init_retry_count ) ;
dgram - > noencrypt_len = SC_PUBKEY_SIZE ;
// 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 ) ;
etcp_encrypt_send ( dgram ) ;
free ( dgram ) ;
free ( dgram ) ;
@ -111,6 +120,7 @@ static int etcp_link_send_reset(struct ETCP_LINK* link) {
dgram - > noencrypt_len = 0 ;
dgram - > noencrypt_len = 0 ;
dgram - > data [ 0 ] = 0x06 ;
dgram - > data [ 0 ] = 0x06 ;
DEBUG_INFO ( DEBUG_CATEGORY_CONNECTION , " Sending RESET to link " ) ;
int ret = etcp_encrypt_send ( dgram ) ;
int ret = etcp_encrypt_send ( dgram ) ;
free ( dgram ) ;
free ( dgram ) ;
return ret ;
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 ) ) ;
struct ETCP_SOCKET * e_sock = calloc ( 1 , sizeof ( struct ETCP_SOCKET ) ) ;
if ( ! e_sock ) {
if ( ! e_sock ) {
DEBUG_ERROR ( DEBUG_CATEGORY_MEMORY , " Failed to allocate connection " ) ;
return NULL ;
return NULL ;
}
}
@ -216,6 +227,7 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct socka
if ( ip ) {
if ( ip ) {
family = ip - > ss_family ;
family = ip - > ss_family ;
if ( family ! = AF_INET & & family ! = AF_INET6 ) {
if ( family ! = AF_INET & & family ! = AF_INET6 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTION , " Unsupported address family: %d " , family ) ;
free ( e_sock ) ;
free ( e_sock ) ;
return NULL ;
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 ) ;
e_sock - > fd = socket ( family , SOCK_DGRAM , 0 ) ;
if ( e_sock - > fd < 0 ) {
if ( e_sock - > fd < 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTION , " Failed to create socket: %s " , strerror ( errno ) ) ;
free ( e_sock ) ;
free ( e_sock ) ;
return NULL ;
return NULL ;
}
}
@ -234,6 +247,7 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct socka
if ( so_mark > 0 ) {
if ( so_mark > 0 ) {
# ifdef SO_MARK
# ifdef SO_MARK
if ( setsockopt ( e_sock - > fd , SOL_SOCKET , SO_MARK , & so_mark , sizeof ( so_mark ) ) < 0 ) {
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
# endif
}
}
@ -244,23 +258,50 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct socka
char ifname [ IF_NAMESIZE ] ;
char ifname [ IF_NAMESIZE ] ;
if ( if_indextoname ( netif_index , ifname ) ) {
if ( if_indextoname ( netif_index , ifname ) ) {
if ( setsockopt ( e_sock - > fd , SOL_SOCKET , SO_BINDTODEVICE , ifname , strlen ( ifname ) ) < 0 ) {
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
# endif
}
}
// Store the local address and instance reference
// Store the local address and bind socket if provided
if ( ip ) {
if ( ip ) {
memcpy ( & e_sock - > local_addr , ip , sizeof ( struct sockaddr_storage ) ) ;
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 - > 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
// Register socket with uasync for receiving packets
e_sock - > socket_id = uasync_add_socket ( instance - > ua , e_sock - > fd ,
e_sock - > socket_id = uasync_add_socket ( instance - > ua , e_sock - > fd ,
etcp_connections_read_callback ,
etcp_connections_read_callback ,
NULL , NULL , e_sock ) ;
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 ;
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 ) {
void etcp_socket_remove ( struct ETCP_SOCKET * conn ) {
if ( ! conn ) return ;
if ( ! conn ) return ;
printf ( " [ETCP] Removing socket %p, fd=%d \n " , conn , conn - > fd ) ;
if ( conn - > fd > = 0 ) {
if ( conn - > fd > = 0 ) {
close ( conn - > fd ) ;
close ( conn - > fd ) ;
printf ( " [ETCP] Closed fd=%d \n " , conn - > fd ) ;
}
}
for ( size_t i = 0 ; i < conn - > num_channels ; i + + ) {
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 ) {
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 ;
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 ) ) ;
struct ETCP_LINK * link = calloc ( 1 , sizeof ( struct ETCP_LINK ) ) ;
if ( ! link ) return NULL ;
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 ( l ) l - > next = link ; else etcp - > links = link ;
if ( is_server = = 0 ) {
if ( is_server = = 0 ) {
printf ( " [LINK] Client link, calling etcp_link_send_init \n " ) ;
etcp_link_send_init ( link ) ;
etcp_link_send_init ( link ) ;
}
}
@ -351,10 +392,19 @@ int etcp_encrypt_send(struct ETCP_DGRAM* dgram) {
size_t enc_buf_len ;
size_t enc_buf_len ;
sc_encrypt ( sc , dgram - > data , len , enc_buf , & 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 ; }
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 ;
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 ) ;
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 ) ;
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 ;
if ( sent < 0 ) dgram - > link - > send_errors + + ; else dgram - > link - > total_encrypted + = sent ;
return ( int ) 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 ;
struct ETCP_SOCKET * e_sock = ( struct ETCP_SOCKET * ) arg ;
if ( ! e_sock ) return ;
if ( ! e_sock ) return ;
printf ( " [ETCP] Read callback triggered for fd=%d, socket=%p \n " , fd , e_sock ) ;
struct sockaddr_storage addr ;
struct sockaddr_storage addr ;
uint8_t data [ PACKET_DATA_SIZE ] ;
uint8_t data [ PACKET_DATA_SIZE ] ;
socklen_t addr_len = sizeof ( addr ) ;
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 ) ;
ssize_t recv_len = recvfrom ( fd , data , PACKET_DATA_SIZE , 0 , ( struct sockaddr * ) & addr , & addr_len ) ;
if ( recv_len < = 0 ) {
if ( recv_len < = 0 ) {
printf ( " [ETCP] recvfrom failed or no data, recv_len=%zd, errno=%d \n " , recv_len , errno ) ;
return ;
return ;
}
}
printf ( " [ETCP] Received packet: %zd bytes from address \n " , recv_len ) ;
struct ETCP_DGRAM * pkt = memory_pool_alloc ( e_sock - > instance - > pkt_pool ) ;
struct ETCP_DGRAM * pkt = memory_pool_alloc ( e_sock - > instance - > pkt_pool ) ;
if ( ! pkt ) return ;
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 ) ;
struct ETCP_LINK * link = etcp_link_find_by_addr ( e_sock , & addr ) ;
if ( link = = NULL ) { // пробуем расшифровать, возможно это init
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 ;
struct secure_channel sc ;
if ( recv_len < = SC_PUBKEY_SIZE ) { errorcode = 1 ; goto ec_fr ; }
if ( recv_len < = SC_PUBKEY_SIZE ) { errorcode = 1 ; goto ec_fr ; }
sc_init_ctx ( & sc , & e_sock - > instance - > my_keys ) ;
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 ) ;
if ( ack_hdr - > code = = 0x02 ) etcp_conn_reset ( conn ) ;
// send response - подключение создано
// send response - подключение создано
struct {
struct {
uint8_t main_id [ 2 ] ;
uint8_t timestamp [ 2 ] ;
uint8_t code ;
uint8_t code ;
uint8_t id [ 8 ] ;
uint8_t id [ 8 ] ;
uint8_t mtu [ 2 ] ;
uint8_t mtu [ 2 ] ;
} * ack_repl_hdr = ( void * ) & pkt - > data [ 0 ] ;
} * 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 ) ;
memcpy ( & ack_repl_hdr - > id [ 0 ] , & e_sock - > instance - > node_id , 8 ) ;
int mtu = e_sock - > instance - > config - > global . mtu ;
int mtu = e_sock - > instance - > config - > global . mtu ;
ack_repl_hdr - > mtu [ 0 ] = mtu > > 8 ;
ack_repl_hdr - > mtu [ 0 ] = mtu > > 8 ;
ack_repl_hdr - > mtu [ 1 ] = mtu ;
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 - > noencrypt_len = 0 ;
pkt - > link = link ;
etcp_encrypt_send ( pkt ) ;
etcp_encrypt_send ( pkt ) ;
memory_pool_free ( e_sock - > instance - > pkt_pool , 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 - > noencrypt_len = 0 ;
pkt - > link = link ;
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 ) ;
etcp_conn_input ( pkt ) ;
return ;
return ;
@ -484,6 +522,7 @@ int init_connections(struct UTUN_INSTANCE* instance) {
// Create socket for this 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 ) ;
struct ETCP_SOCKET * e_sock = etcp_socket_add ( instance , & server - > ip , server - > netif_index , server - > so_mark , server - > type ) ;
if ( ! e_sock ) {
if ( ! e_sock ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ETCP , " Failed to create socket for server %s " , server - > name ) ;
server = server - > next ;
server = server - > next ;
continue ;
continue ;
}
}
@ -511,6 +550,7 @@ int init_connections(struct UTUN_INSTANCE* instance) {
// Create ETCP connection for this client
// Create ETCP connection for this client
struct ETCP_CONN * etcp_conn = etcp_connection_create ( instance ) ;
struct ETCP_CONN * etcp_conn = etcp_connection_create ( instance ) ;
if ( ! etcp_conn ) {
if ( ! etcp_conn ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ETCP , " Failed to create ETCP connection for client %s " , client - > name ) ;
client = client - > next ;
client = client - > next ;
continue ;
continue ;
}
}
@ -557,6 +597,7 @@ int init_connections(struct UTUN_INSTANCE* instance) {
}
}
if ( ! e_sock ) {
if ( ! e_sock ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ETCP , " No socket found for client %s link " , client - > name ) ;
client_link = client_link - > next ;
client_link = client_link - > next ;
continue ;
continue ;
}
}
@ -564,6 +605,7 @@ int init_connections(struct UTUN_INSTANCE* instance) {
// Create link for this client connection
// 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
struct ETCP_LINK * link = etcp_link_new ( etcp_conn , e_sock , & client_link - > remote_addr , 0 ) ; // 0 = client initiates
if ( ! link ) {
if ( ! link ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ETCP , " Failed to create link for client %s " , client - > name ) ;
client_link = client_link - > next ;
client_link = client_link - > next ;
continue ;
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 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 there are no clients (server-only mode), 0 connections is OK (server will accept incoming)
if ( instance - > connections_count = = 0 & & config - > clients ! = NULL ) {
if ( instance - > connections_count = = 0 & & config - > clients ! = NULL ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ETCP , " Clients configured but no connections initialized " ) ;
return - 1 ;
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 ) ;
struct ETCP_LINK * link = etcp_link_find_by_addr ( e_sock , & remote_addr ) ;
if ( ! link ) {
if ( ! link ) {
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTION , " No link found for address " ) ;
return - 1 ;
return - 1 ;
}
}
if ( ! link - > initialized & & link - > is_server = = 0 ) {
if ( ! link - > initialized & & link - > is_server = = 0 ) {
DEBUG_INFO ( DEBUG_CATEGORY_CONNECTION , " Link not initialized, triggering connection establishment " ) ;
if ( ! link - > init_timer ) {
if ( ! link - > init_timer ) {
etcp_link_send_init ( link ) ;
etcp_link_send_init ( link ) ;
}
}