@ -66,6 +66,11 @@ static void ncd_deferred_close(void* arg);
static void ncd_deferred_close_conn ( void * arg ) ;
/* ═══════════ реестр ═══════════ */
/*
* Р е е с т р ncd_entry п о node_id — с о б с т в е н н ы й с в я з н ы й с п и с о к ( н е inst - > connections ) .
* ncd_entry х р а н и т с о с т о я н и е , к о т о р о г о н е т в ETCP_CONN : handles , т а й м е р ы , fin_wait .
* Н у ж е н ч т о б ы п р и п о в т о р н о м open н е с о з д а в а т ь д у б л и р у ю щ и й conn д л я т о г о ж е node_id .
*/
static struct ncd_entry * ncd_registry_find ( struct UTUN_INSTANCE * inst , uint64_t node_id ) {
struct ncd_entry * e = ( struct ncd_entry * ) inst - > ncd_registry ;
@ -81,6 +86,12 @@ static void ncd_registry_remove(struct UTUN_INSTANCE* inst, struct ncd_entry* en
}
/* ═══════════ поиск узла ═══════════ */
/*
* З а г р у ж а е т и н ф о р м а ц и ю о б у з л е ( а д р е с а , pubkey ) д л я с о з д а н и я л и н к о в .
* С н а ч а л а и щ е т в п а м я т и ( node_registry — т у д а п о п а д а ю т у з л ы и з BGP / topo ) ,
* е с л и н е т в п а м я т и — п о д г р у ж а е т и з SQLite и п о м е щ а е т в р е е с т р .
* В о з в р а щ а е т в л а д е ю щ у ю с с ы л к у ( ref + + ) , в ы з ы в а ю щ и й о б я з а н с д е л а т ь topo_node_registry_unref .
*/
static struct TOPO_NODE * ncd_lookup_node ( struct UTUN_INSTANCE * inst , uint64_t node_id ) {
if ( inst - > topo_groups & & inst - > topo_groups - > node_registry ) {
@ -99,6 +110,20 @@ static struct TOPO_NODE* ncd_lookup_node(struct UTUN_INSTANCE* inst, uint64_t no
}
/* ═══════════ создание линков (round‑robin, все сокеты кроме PRIVATE) ═══════════ */
/*
* С о з д а ё т п о о д н о м у ETCP_LINK н а к а ж д ы й а д р е с п и р а ( IPv4 и IPv6 ) .
*
* В с е а д р е с а п и р а р а с п р е д е л я ю т с я round - robin п о л о к а л ь н ы м с о к е т а м .
* Е с л и specific_sock з а д а н — и с п о л ь з у е т т о л ь к о е г о . PRIVATE - с о к е т ы п р о п у с к а ю т с я .
*
* О с о б ы е с л у ч а и :
* - Н у л е в ы е а д р е с а и н у л е в ы е п о р т ы п р о п у с к а ю т с я
* - Н е - UDP п р о т о к о л ы п р о п у с к а ю т с я
* - IPv6 link - local : а в т о м а т и ч е с к и в ы с т а в л я е т с я scope_id п о netif_index с о к е т а
* - Stale - л и н к и : е с л и н а т о м ж е addr : port в и с и т с т а р ы й conn с д р у г и м pubkey
* и с т а р ы й conn е щ ё н е п о д н я л с я — stale - л и н к в ы т е с н я е т с я ( у з е л п е р е с о з д а л с я
* с н о в ы м к л ю ч о м , с т а р ы й conn б о л ь ш е н е н у ж е н )
*/
static int ncd_create_links ( struct ncd_entry * entry , struct TOPO_NODE * ni ,
struct ETCP_SOCKET * specific_sock ) {
@ -130,6 +155,7 @@ static int ncd_create_links(struct ncd_entry* entry, struct TOPO_NODE* ni,
struct ETCP_SOCKET * use_sock = socks [ rr + + % sock_count ] ;
{
struct ETCP_LINK * stale = etcp_link_find_by_addr ( use_sock , & sa ) ;
if ( stale & & stale - > etcp = = conn ) continue ;
if ( stale & & stale - > etcp ! = conn
& & memcmp ( conn - > crypto_ctx . peer_public_key , stale - > etcp - > crypto_ctx . peer_public_key , SC_PUBKEY_SIZE ) )
{
@ -178,6 +204,7 @@ static int ncd_create_links(struct ncd_entry* entry, struct TOPO_NODE* ni,
struct sockaddr_storage sa ; memcpy ( & sa , & sin6 , sizeof ( sin6 ) ) ;
{
struct ETCP_LINK * stale = etcp_link_find_by_addr ( use_sock , & sa ) ;
if ( stale & & stale - > etcp = = conn ) continue ;
if ( stale & & stale - > etcp ! = conn
& & memcmp ( conn - > crypto_ctx . peer_public_key , stale - > etcp - > crypto_ctx . peer_public_key , SC_PUBKEY_SIZE ) )
{
@ -203,6 +230,14 @@ static int ncd_create_links(struct ncd_entry* entry, struct TOPO_NODE* ni,
}
/* ═══════════ единая диспетчеризация событий ═══════════ */
/*
* Ц е н т р а л ь н ы й д и с п е т ч е р : п р и н и м а е т с о б ы т и е ( UP / DOWN / TIMEOUT ) , п р о в е р я е т ч т о о н о
* д е й с т в и т е л ь н о м е н я е т с о с т о я н и е ( п о в т о р н ы й UP к о г д а у ж е up — и г н о р и р у е т с я ) ,
* о б н о в л я е т entry - > up / timed_out и р а с с ы л а е т callback в с е м handle ' а м .
*
* И м е н н о ч е р е з э т у ф у н к ц и ю в с е п о т р е б и т е л и у з н а ю т о б и з м е н е н и и с о с т о я н и я с о е д и н е н и я .
* О д и н в ы з о в — о д и н п р о х о д п о в с е м handle ' а м .
*/
static void ncd_event_dispatch ( struct ncd_entry * entry , enum ncd_event event ) {
if ( ! entry ) return ;
@ -230,17 +265,32 @@ static void ncd_event_dispatch(struct ncd_entry* entry, enum ncd_event event) {
}
/* ═══════════ ETCP коллбэки (прокидывают в ncd_event_dispatch) ═══════════ */
/*
* ETCP с о о б щ и л ч т о с о е д и н е н и е р а б о т а е т : INIT — handshake з а в е р ш ё н ,
* UP — л и н к и в о с с т а н о в и л и с ь п о с л е DOWN . Т р а н с л и р у е м в NCD_EVENT_UP .
* Н е т р а н с л и р у е м е с л и у ж е с р а б о т а л т а й м а у т п о д к л ю ч е н и я ( timed_out )
* и л и conn в с о с т о я н и и fin_wait ( ж д ё м з а к р ы т и я ) .
* Е с л и INIT п р и ш ё л а л и н к о в н е т — UP н е д о с т а в л я е м : ncd_up_cb с а м
* д о с т а в и т к о г д а л и н к и п о д н и м у т с я . Т а к г а р а н т и р у е м ч т о п о л ь з о в а т е л ь
* п о л у ч а е т UP т о л ь к о к о г д а conn р е а л ь н о г о т о в о т п р а в л я т ь д а н н ы е .
*/
static void ncd_init_cb ( struct ETCP_CONN * conn , int event , void * arg ) { ( void ) event ;
struct ncd_entry * entry = ( struct ncd_entry * ) arg ;
if ( ! entry | | entry - > timed_out | | conn - > fin_wait ) return ;
ncd_event_dispatch ( entry , NCD_EVENT_UP ) ;
if ( conn - > links_up > 0 ) ncd_event_dispatch ( entry , NCD_EVENT_UP ) ;
}
static void ncd_up_cb ( struct ETCP_CONN * conn , int event , void * arg ) { ( void ) event ;
struct ncd_entry * entry = ( struct ncd_entry * ) arg ;
if ( ! entry | | conn - > fin_wait ) return ;
ncd_event_dispatch ( entry , NCD_EVENT_UP ) ;
}
/*
* О т л о ж е н н о е ( uasync_call_soon ) у н и ч т о ж е н и е ncd_entry в м е с т е с conn .
* Н е л ь з я в ы з ы в а т ь н а п р я м у ю и з ETCP - к о л л б э к а : conn м о ж е т и с п о л ь з о в а т ь с я
* п о с л е в о з в р а т а и з к о л л б э к а . П о э т о м у о ч и с т к а о т к л а д ы в а е т с я н а с л е д у ю щ и й ц и к л с о б ы т и й .
* С н и м а е т в с е ETCP - к о л л б э к и , у д а л я е т и з р е е с т р а , з а к р ы в а е т conn , о с в о б о ж д а е т п а м я т ь .
*/
static void ncd_deferred_close ( void * arg ) {
struct ncd_entry * entry = ( struct ncd_entry * ) arg ;
struct ETCP_CONN * conn = entry - > conn ;
@ -253,10 +303,20 @@ static void ncd_deferred_close(void* arg) {
}
u_free ( entry ) ;
}
/*
* О т л о ж е н н о е з а к р ы т и е conn б е з ncd_entry .
* И с п о л ь з у е т с я к о г д а п р и ш ё л CLOSE о т п и р а , а ncd_entry д л я э т о г о п и р а у ж е н е т
* ( з а к р ы л и р а н ь ш е — н а п р и м е р д р у г о й м о д у л ь у ж е у д а л и л в с е handle ' ы ) .
*/
static void ncd_deferred_close_conn ( void * arg ) {
struct ETCP_CONN * conn = ( struct ETCP_CONN * ) arg ;
if ( conn ) etcp_connection_close ( conn ) ;
}
/*
* ETCP с о о б щ и л ч т о в с е л и н к и у п а л и .
* Е с л и conn в fin_wait и handle ' о в н е т — peer п о д т в е р д и л з а к р ы т и е ,
* д е л а е м н е м е д л е н н у ю о ч и с т к у . И н а ч е т р а н с л и р у е м NCD_EVENT_DOWN п о т р е б и т е л я м .
*/
static void ncd_down_cb ( struct ETCP_CONN * conn , int event , void * arg ) { ( void ) event ;
struct ncd_entry * entry = ( struct ncd_entry * ) arg ;
if ( ! entry ) return ;
@ -271,6 +331,11 @@ static void ncd_down_cb(struct ETCP_CONN* conn, int event, void* arg) { (void)ev
}
/* ═══════════ таймер подключения ═══════════ */
/*
* Т а й м е р п е р в о г о п о д к л ю ч е н и я и с т ё к — с о е д и н е н и е н е у с т а н о в и л о с ь з а etcp_connect_timeout_tb .
* Т р а н с л и р у е т NCD_EVENT_TIMEOUT в с е м handle ' а м . П о с л е э т о г о init / up к о л л б э к и
* б о л ь ш е н е т р а н с л и р у ю т с я ( entry - > timed_out = 1 ) .
*/
static void ncd_connect_timeout_cb ( void * arg ) {
struct ncd_entry * entry = ( struct ncd_entry * ) arg ;
@ -282,6 +347,12 @@ static void ncd_connect_timeout_cb(void* arg) {
}
/* ═══════════ асинхронная доставка UP ═══════════ */
/*
* Д о с т а в л я е т NCD_EVENT_UP о д н о м у к о н к р е т н о м у handle ' у ( н е в с е м ) .
* И с п о л ь з у е т с я к о г д а handle д о б а в л я е т с я к у ж е р а б о т а ю щ е м у conn : д о с т а в к а о т л о ж е н н а я
* ( uasync_call_soon ) , ч т о б ы в ы з ы в а ю щ и й у с п е л с о х р а н и т ь у к а з а т е л ь handle
* д о в ы з о в а callback ' а . С и н х р о н н а я д о с т а в к а п р и в е л а б ы к г о н к е .
*/
static void ncd_deliver_up_cb ( void * arg ) {
struct NODE_CONN_DIRECT * h = ( struct NODE_CONN_DIRECT * ) arg ;
@ -289,13 +360,29 @@ static void ncd_deliver_up_cb(void* arg) {
}
/* ═══════════ FIN_WAIT ═══════════ */
/*
* fin_wait — с о с т о я н и е о ж и д а н и я п о д т в е р ж д е н и я з а к р ы т и я о т п и р а .
* В ы з ы в а ю щ а я с т о р о н а : м ы о т п р а в и л и CLOSE и ж д ё м о т в е т а ( KEEP_ALIVE и л и DOWN ) .
* М а к с и м а л ь н о е в р е м я о ж и д а н и я — NCD_FIN_WAIT_TIMEOUT_TB ( 5 с е к ) , п о с л е ч е г о
* с о е д и н е н и е ф о р с и р о в а н н о з а к р ы в а е т с я .
*/
/*
* ETCP о т м е н я е т н а ш fin_wait — peer п е р е п о д к л ю ч и л с я и п р и с л а л н о в ы й INIT
* ( и л и д р у г а я п р и ч и н а о т м е н ы н а у р о в н е ETCP ) . О т м е н я е м л о к а л ь н ы й т а й м е р ,
* с о е д и н е н и е п р о д о л ж а е т р а б о т а т ь .
*/
static void ncd_fin_wait_cancelled ( struct ETCP_CONN * conn , void * arg ) {
struct ncd_entry * entry = ( struct ncd_entry * ) arg ;
DEBUG_INFO ( DEBUG_CATEGORY_NCD , " [ncd] fin_wait cancelled node=0x%016llx " , ( unsigned long long ) entry - > node_id ) ;
if ( entry - > fin_wait_timer ) { uasync_cancel_timeout ( entry - > ua , entry - > fin_wait_timer ) ; entry - > fin_wait_timer = NULL ; }
}
/*
* Т а й м а у т fin_wait : peer н е о т в е т и л н а CLOSE з а NCD_FIN_WAIT_TIMEOUT_TB ( 5 с е к ) .
* Ф о р с и р о в а н н о з а к р ы в а е м conn и о с в о б о ж д а е м entry — с о е д и н е н и е р а з о р в а н о
* б е з п о д т в е р ж д е н и я о т п и р а .
*/
static void ncd_fin_wait_timeout_cb ( void * arg ) {
struct ncd_entry * entry = ( struct ncd_entry * ) arg ;
if ( ! entry | | ! entry - > conn ) return ;
@ -312,6 +399,17 @@ static void ncd_fin_wait_timeout_cb(void* arg) {
}
/* ═══════════ приём CLOSE / KEEP_ALIVE ═══════════ */
/*
* О б р а б а т ы в а е т у п р а в л я ю щ и е с о о б щ е н и я о т п и р а п о п р о т о к о л у graceful shutdown .
*
* CLOSE ( п и р х о ч е т з а к р ы т ь conn — у н е г о з а к о н ч и л и с ь handle ' ы ) :
* - Е с л и у н а с е щ ё е с т ь handle ' ы — о т к а з ы в а е м : ш л ё м KEEP_ALIVE , conn ж и в ё т .
* - Е с л и handle ' о в н е т — с о г л а ш а е м с я , з а к р ы в а е м conn .
*
* KEEP_ALIVE ( п и р п р о с и т н е з а к р ы в а т ь conn — у н е г о е щ ё е с т ь handle ' ы ) :
* - Е с л и м ы в fin_wait — о т м е н я е м е г о , conn п р о д о л ж а е т р а б о т а т ь .
* - Е с л и у н а с handle ' о в н е т — п е р е з а п у с к а е м fin_wait ( ж д ё м е щ ё 5 с е к ) .
*/
static void ncd_recv_control_handler ( struct ETCP_CONN * conn , struct ll_entry * e ) {
if ( ! conn | | ! e | | e - > len < NCD_CONTROL_MSG_SIZE ) {
@ -363,6 +461,11 @@ static void ncd_recv_control_handler(struct ETCP_CONN* conn, struct ll_entry* e)
}
/* ═══════════ инициализация глобального обработчика ═══════════ */
/*
* О д н о к р а т н а я п р и в я з к а о б р а б о т ч и к а NCD control - с о о б щ е н и й к ETCP ( etcp_bind ) .
* В ы з ы в а е т с я п р и п е р в о м node_conn_direct_open , п о в т о р н ы е в ы з о в ы б е з в р е д н ы
* ( з а щ и т а ч е р е з inst - > ncd_control_bound ) .
*/
static void ncd_init_control_binding ( struct UTUN_INSTANCE * inst ) {
if ( inst - > ncd_control_bound ) return ;
@ -373,6 +476,20 @@ static void ncd_init_control_binding(struct UTUN_INSTANCE* inst) {
/* ═══════════ API ═══════════ */
/*
* О т к р ы т ь handle д л я с в я з и с у д а л ё н н ы м у з л о м .
*
* Т р и с ц е н а р и я ( п р о з р а ч н о д л я в ы з ы в а ю щ е г о ) :
* 1. У з е л у ж е в NCD - р е е с т р е — д р у г о й м о д у л ь у ж е о т к р ы л с о е д и н е н и е .
* Д о б а в л я е м е щ ё о д и н handle . Е с л и conn р а б о т а е т — с р а з у ш л ё м UP .
* 2. ETCP - с о е д и н е н и е с у щ е с т в у е т ( в х о д я щ е е / etcp_connect ) , н о NCD о н ё м н е з н а е т .
* О б о р а ч и в а е м в ncd_entry , п о д п и с ы в а е м с я н а с о б ы т и я .
* 3. Н и ч е г о н е т — з а г р у ж а е м а д р е с а / pupkey у з л а , с о з д а ё м н о в ы й ETCP_CONN ,
* и н и ц и а л и з и р у е м ш и ф р о в а н и е , с о з д а ё м л и н к и , з а п у с к а е м т а й м е р п о д к л ю ч е н и я .
*
* В о з в р а щ а е т NCD_NEW ( н о в о е ) , NCD_REUSED ( п е р е и с п о л ь з о в а н о ) и л и NCD_ERR .
* specific_sock = NULL — а в т о - п о д б о р в с е х л о к а л ь н ы х с о к е т о в .
*/
int node_conn_direct_open ( struct UTUN_INSTANCE * inst , uint64_t node_id ,
ncd_callback cb , void * cb_arg ,
struct NODE_CONN_DIRECT * * out_handle ,
@ -435,6 +552,9 @@ int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id,
uasync_call_soon ( inst - > ua , h , ncd_deliver_up_cb ) ;
DEBUG_INFO ( DEBUG_CATEGORY_NCD , " [ncd] open REUSED new-entry (ready) node=0x%016llx conn=%p " , ( unsigned long long ) node_id , ( void * ) conn ) ;
} else {
{ struct TOPO_NODE * ni = ncd_lookup_node ( inst , node_id ) ;
if ( ni ) { ncd_create_links ( entry , ni , specific_sock ) ; topo_node_registry_unref ( inst - > topo_groups , ni - > node_id ) ; }
}
entry - > connect_timer = uasync_set_timeout ( inst - > ua , ( int ) inst - > etcp_connect_timeout_tb , entry , ncd_connect_timeout_cb , " ncd_connect " ) ;
DEBUG_INFO ( DEBUG_CATEGORY_NCD , " [ncd] open REUSED new-entry (pending) node=0x%016llx conn=%p " , ( unsigned long long ) node_id , ( void * ) conn ) ;
}
@ -514,6 +634,12 @@ int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id,
return NCD_NEW ;
}
/*
* Т о ж е ч т о open , н о TOPO_NODE ( а д р е с а + pubkey ) у ж е з а г р у ж е н в ы з ы в а ю щ и м .
* Э к о н о м и т п о и с к у з л а ( ncd_lookup_node ) — п о л е з н о к о г д а а д р е с а / pupkey
* и з в е с т н ы з а р а н е е ( н а п р и м е р и з BGP - а н о н с а ) . ni н е в л а д е е м — м о ж н о
* п е р е д а т ь в р е м е н н у ю с т р у к т у р у , к о п и я н е д е л а е т с я .
*/
int node_conn_direct_open_node ( struct UTUN_INSTANCE * inst , uint64_t node_id ,
ncd_callback cb , void * cb_arg ,
struct NODE_CONN_DIRECT * * out_handle ,
@ -575,6 +701,7 @@ int node_conn_direct_open_node(struct UTUN_INSTANCE* inst, uint64_t node_id,
uasync_call_soon ( inst - > ua , h , ncd_deliver_up_cb ) ;
DEBUG_INFO ( DEBUG_CATEGORY_NCD , " [ncd] open_node REUSED new-entry (ready) node=0x%016llx conn=%p " , ( unsigned long long ) node_id , ( void * ) conn ) ;
} else {
ncd_create_links ( entry , ni , specific_sock ) ;
entry - > connect_timer = uasync_set_timeout ( inst - > ua , ( int ) inst - > etcp_connect_timeout_tb , entry , ncd_connect_timeout_cb , " ncd_connect_node " ) ;
DEBUG_INFO ( DEBUG_CATEGORY_NCD , " [ncd] open_node REUSED new-entry (pending) node=0x%016llx conn=%p " , ( unsigned long long ) node_id , ( void * ) conn ) ;
}
@ -645,6 +772,18 @@ int node_conn_direct_open_node(struct UTUN_INSTANCE* inst, uint64_t node_id,
}
}
/*
* З а к р ы т ь handle ( graceful shutdown ) .
*
* Е с л и о с т а л и с ь д р у г и е handle ' ы — п р о с т о у д а л я е т с я и з с п и с к а , conn п р о д о л ж а е т р а б о т у .
*
* Е с л и э т о б ы л п о с л е д н и й handle ( handle_count с т а л 0 ) :
* - З а п у с к а е т с я п р о т о к о л graceful shutdown : п и р у о т п р а в л я е т с я CLOSE , conn
* п е р е в о д и т с я в fin_wait , с т а в и т с я т а й м е р н а 5 с е к .
* - Е с л и п и р о т в е т и т KEEP_ALIVE ( у н е г о е щ ё е с т ь handle ' ы ) — conn о с т а н е т с я ж и в ,
* п р о с т о б е з н а ш и х handle ' о в .
* - Е с л и п и р н е о т в е т и т — conn з а к р ы в а е т с я ф о р с и р о в а н н о п о т а й м а у т у .
*/
void node_conn_direct_close ( struct NODE_CONN_DIRECT * h ) {
if ( ! h ) return ;
struct ncd_entry * entry = h - > entry ;
@ -658,9 +797,21 @@ void node_conn_direct_close(struct NODE_CONN_DIRECT* h) {
while ( * pp ) { if ( * pp = = h ) { * pp = h - > next ; break ; } pp = & ( * pp ) - > next ; }
entry - > handle_count - - ;
if ( entry - > handle_count < 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_NCD , " [ncd] FATAL: handle_count=%d < 0 node=0x%016llx " ,
entry - > handle_count , ( unsigned long long ) node_id ) ;
h - > entry = NULL ; u_free ( h ) ; return ;
}
DEBUG_INFO ( DEBUG_CATEGORY_NCD , " [ncd] close node=0x%016llx remaining=%d " , ( unsigned long long ) node_id , entry - > handle_count ) ;
if ( entry - > handle_count < = 0 ) {
if ( entry - > handle_count = = 0 ) {
if ( entry - > handles ) {
DEBUG_ERROR ( DEBUG_CATEGORY_NCD , " [ncd] FATAL: handle_count=0 but handles non-empty node=0x%016llx " ,
( unsigned long long ) node_id ) ;
entry - > handles = NULL ;
}
h - > cb = NULL ; h - > cb_arg = NULL ;
if ( entry - > connect_timer ) { uasync_cancel_timeout ( entry - > ua , entry - > connect_timer ) ; entry - > connect_timer = NULL ; }
if ( conn & & conn - > state ! = 2 ) {
/* устанавливаем fin_wait, отправляем CLOSE, ставим таймер */
@ -694,6 +845,73 @@ void node_conn_direct_close(struct NODE_CONN_DIRECT* h) {
u_free ( h ) ;
}
/*
* Н е м е д л е н н о е ж ё с т к о е з а к р ы т и е handle . Н и к а к о г о CLOSE / KEEP_ALIVE — с р а з у
* с н и м а е т ETCP - к о л л б э к и и ( е с л и п о с л е д н и й handle ) з а к р ы в а е т conn .
*
* И с п о л ь з у е т с я п р и р а з р у ш е н и и CM entry ч т о б ы г а р а н т и р о в а т ь ч т о к о л л б э к и
* н е в ы з о в у т с я в у ж е о с в о б о ж д ё н н у ю п а м я т ь . П о с л е force_close н и к а к и е
* NCD - с о б ы т и я н е б у д у т д о с т а в л е н ы .
*/
void node_conn_direct_force_close ( struct NODE_CONN_DIRECT * h ) {
if ( ! h ) return ;
struct ncd_entry * entry = h - > entry ;
if ( ! entry ) { u_free ( h ) ; return ; }
uint64_t node_id = entry - > node_id ;
struct ETCP_CONN * conn = entry - > conn ;
struct NODE_CONN_DIRECT * * pp = & entry - > handles ;
while ( * pp ) { if ( * pp = = h ) { * pp = h - > next ; break ; } pp = & ( * pp ) - > next ; }
entry - > handle_count - - ;
if ( entry - > handle_count < 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_NCD , " [ncd] FATAL: force_close handle_count=%d < 0 node=0x%016llx " ,
entry - > handle_count , ( unsigned long long ) node_id ) ;
h - > entry = NULL ; u_free ( h ) ; return ;
}
DEBUG_INFO ( DEBUG_CATEGORY_NCD , " [ncd] force_close node=0x%016llx remaining=%d " ,
( unsigned long long ) node_id , entry - > handle_count ) ;
if ( entry - > handle_count = = 0 ) {
if ( entry - > handles ) {
DEBUG_ERROR ( DEBUG_CATEGORY_NCD , " [ncd] FATAL: force_close handle_count=0 but handles non-empty node=0x%016llx " ,
( unsigned long long ) node_id ) ;
entry - > handles = NULL ;
}
h - > cb = NULL ; h - > cb_arg = NULL ;
if ( entry - > connect_timer ) { uasync_cancel_timeout ( entry - > ua , entry - > connect_timer ) ; entry - > connect_timer = NULL ; }
if ( entry - > fin_wait_timer ) { uasync_cancel_timeout ( entry - > ua , entry - > fin_wait_timer ) ; entry - > fin_wait_timer = NULL ; }
if ( conn ) {
conn - > fin_wait = 0 ; conn - > fin_wait_clear_cb = NULL ; conn - > fin_wait_clear_arg = NULL ;
etcp_conn_remove_cbk ( conn , ncd_init_cb , entry ) ;
etcp_conn_remove_cbk ( conn , ncd_up_cb , entry ) ;
etcp_conn_remove_cbk ( conn , ncd_down_cb , entry ) ;
if ( conn - > state ! = 2 ) uasync_call_soon ( entry - > ua , conn , ncd_deferred_close_conn ) ;
ncd_registry_remove ( conn - > instance , entry ) ;
}
u_free ( entry ) ;
}
h - > entry = NULL ;
u_free ( h ) ;
}
/*
* С м е н и т ь и л и с б р о с и т ь ( cb = NULL ) callback н а у ж е о т к р ы т о м handle .
* Н е в л и я е т н а refcounting и с о с т о я н и е conn .
*/
void node_conn_direct_set_callback ( struct NODE_CONN_DIRECT * h , ncd_callback cb , void * cb_arg ) {
if ( ! h | | ! h - > entry ) return ;
h - > cb = cb ;
h - > cb_arg = cb_arg ;
}
/*
* П р я м о й д о с т у п к ETCP_CONN и з handle .
* Н у ж е н д л я о т п р а в к и д а н н ы х ( etcp_send ) , п р о в е р к и с т а т у с а , и т . д .
*/
struct ETCP_CONN * node_conn_direct_get_conn ( struct NODE_CONN_DIRECT * h ) {
if ( ! h | | ! h - > entry ) return NULL ;
return h - > entry - > conn ;