@ -34,12 +34,12 @@ static void keepalive_timer_cb(void* arg);
static void etcp_link_send_init ( struct ETCP_LINK * link , uint8_t reset ) {
DEBUG_TRACE ( DEBUG_CATEGORY_CONNECTION , " " ) ;
DEBUG_INFO ( DEBUG_CATEGORY_CONNECTION , " etcp_link_send_init link=%p, is_server=%d, reset=%d" , link , link ? link - > is_server : - 1 , reset ) ;
DEBUG_INFO ( DEBUG_CATEGORY_CONNECTION , " link=%p, is_server=%d, reset=%d " , link , link ? link - > is_server : - 1 , reset ) ;
if ( ! link | | ! link - > etcp | | ! link - > etcp - > instance ) return ;
struct ETCP_DGRAM * dgram = u_malloc ( sizeof ( struct ETCP_DGRAM ) + 100 ) ;
if ( ! dgram ) {
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTION , " etcp_link_send_init: malloc failed" ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTION , " malloc failed " ) ;
return ;
}
@ -96,29 +96,55 @@ static void etcp_link_send_init(struct ETCP_LINK* link, uint8_t reset) {
u_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 ) {
DEBUG_TRACE ( DEBUG_CATEGORY_CONNECTION , " " ) ;
struct ETCP_LINK * link = ( struct ETCP_LINK * ) arg ;
if ( ! link | | link - > initialized | | link - > is_server ! = 0 ) return ;
if ( ! link ) return ;
link - > init_timer = NULL ;
etcp_link_send_init ( link , 1 ) ;
if ( ( link - > init_retry_count % 10 ) = = 0 & & link - > init_timeout < INIT_TIMEOUT_MAX ) {
link - > init_timeout + = link - > init_timeout / 4 + 1 ;
if ( link - > init_timeout > INIT_TIMEOUT_MAX ) link - > init_timeout = INIT_TIMEOUT_MAX ;
}
link - > init_timer = uasync_set_timeout ( link - > etcp - > instance - > ua , link - > init_timeout , link , etcp_link_init_timer_cbk ) ;
if ( link - > link_state = = 1 ) etcp_link_send_init ( link , 1 ) ; // init (with etcp reset)
else etcp_link_send_init ( link , 0 ) ; // no etcp reset (reinit)
}
void etcp_link_restart_init_timer ( struct ETCP_LINK * link ) {
DEBUG_TRACE ( DEBUG_CATEGORY_CONNECTION , " " ) ;
if ( link - > init_timer ) uasync_cancel_timeout ( link - > etcp - > instance - > ua , link - > init_timer ) ;
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 ) ;
}
void etcp_link_enter_init ( struct ETCP_LINK * link ) { //
DEBUG_TRACE ( DEBUG_CATEGORY_CONNECTION , " " ) ;
if ( ! link ) return ;
link - > link_state = 1 ; // handshake
if ( link - > is_server ! = 0 ) return ;
etcp_link_send_init ( link , 1 ) ; // init with reset
etcp_link_restart_init_timer ( link ) ;
}
void etcp_link_enter_reinit ( struct ETCP_LINK * link ) {
DEBUG_TRACE ( DEBUG_CATEGORY_CONNECTION , " " ) ;
if ( ! link ) return ;
link - > link_state = 2 ; // reconnect
if ( link - > is_server ! = 0 ) return ;
etcp_link_send_init ( link , 0 ) ; // init without reset
if ( link - > keepalive_timer ) { // keepalive заменяяется reinit запросами
uasync_cancel_timeout ( link - > etcp - > instance - > ua , link - > keepalive_timer ) ;
link - > keepalive_timer = NULL ;
}
etcp_link_restart_init_timer ( link ) ;
}
// Send empty keepalive packet (only timestamp, no sections)
static void etcp_link_send_keepalive ( struct ETCP_LINK * link ) {
DEBUG_TRACE ( DEBUG_CATEGORY_CONNECTION , " " ) ;
@ -159,22 +185,6 @@ static int etcp_all_links_down(struct ETCP_CONN* etcp) {
return 1 ; // All links are down
}
// Start link recovery process - send CHANNEL_INIT (0x04) on all links
static void etcp_start_link_recovery ( struct ETCP_LINK * link ) {
if ( ! link ) return ;
DEBUG_INFO ( DEBUG_CATEGORY_CONNECTION , " [%s] Starting link recovery - all links are down " , link - > etcp - > log_name ? link - > etcp - > log_name : " ????→???? " ) ;
struct ETCP_CONN * etcp = link - > etcp ;
if ( link - > is_server = = 0 ) { // Only client links
// Send CHANNEL_INIT (0x04) without reset
etcp_link_send_init ( link , 0 ) ;
DEBUG_INFO ( DEBUG_CATEGORY_CONNECTION , " [%s] Sent CHANNEL_INIT on link %p for recovery " ,
etcp - > log_name , link ) ;
}
link = link - > next ;
}
// Cancel init_timer for all links of an ETCP_CONN
static void etcp_cancel_all_init_timers ( struct ETCP_CONN * etcp ) {
if ( ! etcp ) return ;
@ -195,16 +205,17 @@ static void etcp_cancel_all_init_timers(struct ETCP_CONN* etcp) {
static void keepalive_timer_cb ( void * arg ) {
DEBUG_TRACE ( DEBUG_CATEGORY_CONNECTION , " " ) ;
struct ETCP_LINK * link = ( struct ETCP_LINK * ) arg ;
if ( ! link | | ! link - > etcp | | ! link - > etcp - > instance ) return ;
if ( ! link | | ! link - > etcp | | ! link - > etcp - > instance ) {
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTION , " KEEPALIVE NULL !!!!!!!! " ) ;
return ;
}
link - > keepalive_timer = NULL ;
// Check if all links are down and start recovery if needed (client only)
if ( link - > is_server = = 0 & & etcp_all_links_down ( link - > etcp ) ) {
DEBUG_WARN ( DEBUG_CATEGORY_CONNECTION , " [%s] All links are down, starting recovery " , link - > etcp - > log_name ) ;
etcp_start_link_recovery ( link ) ;
if ( link - > recovery_interval = = 0 ) link - > recovery_interval = link - > keepalive_interval * 10 ;
link - > keepalive_timer = uasync_set_timeout ( link - > etcp - > instance - > ua , link - > recovery_interval , link , keepalive_timer_cb ) ;
etcp_link_enter_reinit ( link ) ; // keepalive timr после reinit не нужен
return ;
}
@ -238,14 +249,7 @@ static void keepalive_timer_cb(void* arg) {
}
// Send keepalive only if no packets were sent since last tick
if ( ! link - > pkt_sent_since_keepalive ) {
etcp_link_send_keepalive ( link ) ;
} else {
// DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] Keepalive skipped - packet sent since last tick", link->etcp->log_name);
link - > recovery_interval = 0 ;
}
// Reset flag for next interval
if ( ! link - > pkt_sent_since_keepalive ) etcp_link_send_keepalive ( link ) ;
link - > pkt_sent_since_keepalive = 0 ;
restart_timer :
@ -598,7 +602,7 @@ struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn
if ( is_server = = 0 ) {
DEBUG_INFO ( DEBUG_CATEGORY_CONNECTION , " etcp_link_new: client link, calling etcp_link_send_init " ) ;
etcp_link_send _init ( link , 1 ) ;
etcp_link_enter _init ( link ) ;
}
return link ;
@ -1078,10 +1082,23 @@ process_decrypted:
link - > etcp - > peer_node_id = server_node_id ; // If not set
etcp_update_log_name ( link - > etcp ) ; // Update log_name with peer_node_id
// Cancel init timer if exists
if ( link - > init_timer ) {
uasync_cancel_timeout ( link - > etcp - > instance - > ua , link - > init_timer ) ;
link - > init_timer = NULL ;
}
if ( link - > keepalive_timer ) {
uasync_cancel_timeout ( link - > etcp - > instance - > ua , link - > keepalive_timer ) ;
link - > keepalive_timer = NULL ;
}
// Mark link as initialized
// DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "Setting link->initialized=1, link=%p, is_server=%d", link, link->is_server);
link - > initialized = 1 ; // получен init response (client)
// link->link_status = 1; // Link is up after successful initialization
link - > link_state = 3 ; // connected
if ( link - > etcp - > initialized = = 0 ) {
etcp_conn_ready ( link - > etcp ) ;
}
@ -1092,24 +1109,16 @@ process_decrypted:
// Start keepalive timer
etcp_link_send_keepalive ( link ) ;
if ( ! link - > keepalive_timer & & link - > keepalive_interval > 0 ) {
DEBUG_DEBUG ( DEBUG_CATEGORY_CONNECTION , " [%s] Keepalive timer started on link %p (interval=%d ms) " ,
link - > etcp - > log_name , link , link - > keepalive_interval ) ;
link - > keepalive_timer = uasync_set_timeout ( link - > etcp - > instance - > ua ,
link - > keepalive_interval * 10 ,
link , keepalive_timer_cb ) ;
if ( link - > keepalive_interval > 0 ) {
DEBUG_DEBUG ( DEBUG_CATEGORY_CONNECTION , " [%s] Keepalive timer started on link %p (interval=%d ms) " , link - > etcp - > log_name , link , link - > keepalive_interval ) ;
link - > keepalive_timer = uasync_set_timeout ( link - > etcp - > instance - > ua , link - > keepalive_interval * 10 , link , keepalive_timer_cb ) ;
}
loadbalancer_link_ready ( link ) ;
DEBUG_INFO ( DEBUG_CATEGORY_CONNECTION , " etcp client: Link initialized successfully! Server node_id=%016llx, mtu=%d, local_link_id=%d, remote_link_id=%d " , ( unsigned long long ) server_node_id , link - > mtu , link - > local_link_id , link - > remote_link_id ) ;
// Cancel init timer if exists
if ( link - > init_timer ) {
uasync_cancel_timeout ( link - > etcp - > instance - > ua , link - > init_timer ) ;
link - > init_timer = NULL ;
}
memory_pool_free ( e_sock - > instance - > pkt_pool , pkt ) ;
return ; // INIT_RESPONSE is handled, no further processing needed
}