|
|
|
@ -41,6 +41,8 @@ struct ncd_entry { |
|
|
|
struct UTUN_INSTANCE* inst; |
|
|
|
struct UTUN_INSTANCE* inst; |
|
|
|
unsigned dispatch_depth; |
|
|
|
unsigned dispatch_depth; |
|
|
|
uint8_t closed; |
|
|
|
uint8_t closed; |
|
|
|
|
|
|
|
uint8_t node_ref; |
|
|
|
|
|
|
|
uint64_t node_timestamp; |
|
|
|
int handle_count; |
|
|
|
int handle_count; |
|
|
|
|
|
|
|
|
|
|
|
struct NODE_CONN_DIRECT* handles; /* связный список всех handle'ов */ |
|
|
|
struct NODE_CONN_DIRECT* handles; /* связный список всех handle'ов */ |
|
|
|
@ -154,6 +156,7 @@ static int ncd_add_udp_link(struct ETCP_CONN* conn, struct ETCP_SOCKET* use_sock |
|
|
|
(unsigned long long)conn->peer_node_id, *(const uint64_t*)conn->crypto_ctx.peer_public_key); |
|
|
|
(unsigned long long)conn->peer_node_id, *(const uint64_t*)conn->crypto_ctx.peer_public_key); |
|
|
|
etcp_link_close(stale); |
|
|
|
etcp_link_close(stale); |
|
|
|
etcp_cbk_fire(old, ETCP_CBK_EVENT_NODE_CHANGED); |
|
|
|
etcp_cbk_fire(old, ETCP_CBK_EVENT_NODE_CHANGED); |
|
|
|
|
|
|
|
stale = NULL; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "[ncd] addr conflict: port already used by live conn 0x%016llx for node 0x%016llx", |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "[ncd] addr conflict: port already used by live conn 0x%016llx for node 0x%016llx", |
|
|
|
(unsigned long long)stale->etcp->peer_node_id, (unsigned long long)conn->peer_node_id); |
|
|
|
(unsigned long long)stale->etcp->peer_node_id, (unsigned long long)conn->peer_node_id); |
|
|
|
@ -174,10 +177,50 @@ static int ncd_add_udp_link(struct ETCP_CONN* conn, struct ETCP_SOCKET* use_sock |
|
|
|
return etcp_link_new(conn, use_sock, sa, 0) ? 1 : 0; |
|
|
|
return etcp_link_new(conn, use_sock, sa, 0) ? 1 : 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int ncd_same_address(const struct sockaddr_storage* a, const struct sockaddr_storage* b) { |
|
|
|
|
|
|
|
if (a->ss_family != b->ss_family) return 0; |
|
|
|
|
|
|
|
if (a->ss_family == AF_INET) { |
|
|
|
|
|
|
|
const struct sockaddr_in* x = (const struct sockaddr_in*)a; |
|
|
|
|
|
|
|
const struct sockaddr_in* y = (const struct sockaddr_in*)b; |
|
|
|
|
|
|
|
return x->sin_port == y->sin_port && x->sin_addr.s_addr == y->sin_addr.s_addr; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (a->ss_family == AF_INET6) { |
|
|
|
|
|
|
|
const struct sockaddr_in6* x = (const struct sockaddr_in6*)a; |
|
|
|
|
|
|
|
const struct sockaddr_in6* y = (const struct sockaddr_in6*)b; |
|
|
|
|
|
|
|
return x->sin6_port == y->sin6_port && x->sin6_scope_id == y->sin6_scope_id && |
|
|
|
|
|
|
|
!memcmp(&x->sin6_addr, &y->sin6_addr, sizeof(x->sin6_addr)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int ncd_add_tcp_link(struct ETCP_CONN* conn, struct ETCP_SOCKET* sock, |
|
|
|
|
|
|
|
struct sockaddr_storage* addr, const struct TOPO_REALITY_SOCK* reality) { |
|
|
|
|
|
|
|
for (struct ETCP_LINK* link = conn->links; link; link = link->next) |
|
|
|
|
|
|
|
if (link->is_tcp && !link->is_server && link->conn == sock && ncd_same_address(&link->remote_addr, addr)) return 0; |
|
|
|
|
|
|
|
struct ETCP_LINK* link = etcp_link_new(conn, sock, addr, 0); |
|
|
|
|
|
|
|
if (!link) { DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] TCP link allocation failed"); return -1; } |
|
|
|
|
|
|
|
topo_node_apply_reality(link, reality); |
|
|
|
|
|
|
|
etcp_tcp_link_start_connect(link, addr, 0); |
|
|
|
|
|
|
|
return 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int ncd_create_links(struct ncd_entry* entry, struct TOPO_NODE* ni, |
|
|
|
static int ncd_create_links(struct ncd_entry* entry, struct TOPO_NODE* ni, |
|
|
|
struct ETCP_SOCKET* specific_sock) { |
|
|
|
struct ETCP_SOCKET* specific_sock) { |
|
|
|
|
|
|
|
if (!ni || ni->timestamp < entry->node_timestamp) { |
|
|
|
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_NCD, "[ncd] ignore stale addresses node=%016llx current=%llu incoming=%llu", |
|
|
|
|
|
|
|
(unsigned long long)entry->node_id, (unsigned long long)entry->node_timestamp, |
|
|
|
|
|
|
|
(unsigned long long)(ni ? ni->timestamp : 0)); return 0; |
|
|
|
|
|
|
|
} |
|
|
|
struct ETCP_CONN* conn = entry->conn; |
|
|
|
struct ETCP_CONN* conn = entry->conn; |
|
|
|
struct UTUN_INSTANCE* inst = conn->instance; |
|
|
|
struct UTUN_INSTANCE* inst = conn->instance; |
|
|
|
|
|
|
|
if (memcmp(ni->public_key, conn->crypto_ctx.peer_public_key, SC_PUBKEY_SIZE)) { |
|
|
|
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] address update key mismatch node=%016llx", (unsigned long long)entry->node_id); |
|
|
|
|
|
|
|
return -1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!entry->node_ref && topo_node_registry_find(inst->topo_groups, entry->node_id) == ni) { |
|
|
|
|
|
|
|
topo_node_registry_ref(inst->topo_groups, entry->node_id); entry->node_ref = 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
entry->node_timestamp = ni->timestamp; |
|
|
|
int link_count = 0, v4_skip = 0, v6_skip = 0, v4_addrs = 0, v6_addrs = 0; |
|
|
|
int link_count = 0, v4_skip = 0, v6_skip = 0, v4_addrs = 0, v6_addrs = 0; |
|
|
|
uint64_t nid = entry->node_id; |
|
|
|
uint64_t nid = entry->node_id; |
|
|
|
|
|
|
|
|
|
|
|
@ -202,9 +245,9 @@ static int ncd_create_links(struct ncd_entry* entry, struct TOPO_NODE* ni, |
|
|
|
if (a->protocol & TOPO_PROTO_TCP) { |
|
|
|
if (a->protocol & TOPO_PROTO_TCP) { |
|
|
|
for (int vi = 0; vi < nviews; vi++) { |
|
|
|
for (int vi = 0; vi < nviews; vi++) { |
|
|
|
const struct sock_view* v = &views[vi]; |
|
|
|
const struct sock_view* v = &views[vi]; |
|
|
|
if (!v->is_tcp || !sock_match(v, a->type, tcfg, tnat, tip)) continue; |
|
|
|
if (!v->is_tcp || (specific_sock && v->sock != specific_sock) || !sock_match(v, a->type, tcfg, tnat, tip)) continue; |
|
|
|
struct ETCP_LINK* tlink = etcp_link_new(conn, v->sock, &sa, 0); |
|
|
|
int added = ncd_add_tcp_link(conn, v->sock, &sa, topo_node_find_reality_sock(ni, a->socket_id)); |
|
|
|
if (tlink) { tlink->is_tcp = 1; topo_node_apply_reality(tlink, topo_node_find_reality_sock(ni, a->socket_id)); etcp_tcp_link_start_connect(tlink, &sa, a->port); link_count++; } |
|
|
|
if (added > 0) link_count += added; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (a->protocol & TOPO_PROTO_UDP) { |
|
|
|
if (a->protocol & TOPO_PROTO_UDP) { |
|
|
|
@ -235,9 +278,11 @@ static int ncd_create_links(struct ncd_entry* entry, struct TOPO_NODE* ni, |
|
|
|
while (sv) { if (sv->local_addr.ss_family == AF_INET6 && sv->netif_index) { sin6.sin6_scope_id = sv->netif_index; break; } sv = sv->next; } } |
|
|
|
while (sv) { if (sv->local_addr.ss_family == AF_INET6 && sv->netif_index) { sin6.sin6_scope_id = sv->netif_index; break; } sv = sv->next; } } |
|
|
|
struct sockaddr_storage sa; memcpy(&sa, &sin6, sizeof(sin6)); |
|
|
|
struct sockaddr_storage sa; memcpy(&sa, &sin6, sizeof(sin6)); |
|
|
|
for (struct ETCP_SOCKET* s = inst->etcp_sockets; s; s = s->next) { |
|
|
|
for (struct ETCP_SOCKET* s = inst->etcp_sockets; s; s = s->next) { |
|
|
|
if (!s->is_tcp || s->local_addr.ss_family != AF_INET6 || s->type == CFG_SERVER_TYPE_PRIVATE) continue; |
|
|
|
if (!s->is_tcp || (specific_sock && s != specific_sock) || s->local_addr.ss_family != AF_INET6 || |
|
|
|
struct ETCP_LINK* tlink = etcp_link_new(conn, s, &sa, 0); |
|
|
|
s->type == CFG_SERVER_TYPE_PRIVATE) continue; |
|
|
|
if (tlink) { tlink->is_tcp = 1; topo_node_apply_reality(tlink, topo_node_find_reality_sock(ni, a->socket_id)); etcp_tcp_link_start_connect(tlink, &sa, a->port); link_count++; } |
|
|
|
if (is_ll) { sin6.sin6_scope_id = s->netif_index; memcpy(&sa, &sin6, sizeof(sin6)); } |
|
|
|
|
|
|
|
int added = ncd_add_tcp_link(conn, s, &sa, topo_node_find_reality_sock(ni, a->socket_id)); |
|
|
|
|
|
|
|
if (added > 0) link_count += added; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (a->protocol & TOPO_PROTO_UDP) { |
|
|
|
if (a->protocol & TOPO_PROTO_UDP) { |
|
|
|
@ -256,13 +301,24 @@ static int ncd_create_links(struct ncd_entry* entry, struct TOPO_NODE* ni, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (link_count == 0) { |
|
|
|
if (link_count > 0) { |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] create_links: node=0x%016llx v4=%d/skp=%d v6=%d/skp=%d → %d links (UDP+TCP)", |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] create_links: node=0x%016llx v4=%d/skp=%d v6=%d/skp=%d → %d new links (UDP+TCP)", |
|
|
|
(unsigned long long)nid, v4_addrs, v4_skip, v6_addrs, v6_skip, link_count); |
|
|
|
(unsigned long long)nid, v4_addrs, v4_skip, v6_addrs, v6_skip, link_count); |
|
|
|
} |
|
|
|
} |
|
|
|
return link_count; |
|
|
|
return link_count; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int node_conn_direct_update_node(struct UTUN_INSTANCE* inst, uint64_t node_id) { |
|
|
|
|
|
|
|
if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] update without instance"); return -1; } |
|
|
|
|
|
|
|
struct ncd_entry* entry = ncd_registry_find(inst, node_id); |
|
|
|
|
|
|
|
struct TOPO_NODE* ni = topo_node_registry_find(inst->topo_groups, node_id); |
|
|
|
|
|
|
|
if (!entry || !ni) return 0; |
|
|
|
|
|
|
|
int added = ncd_create_links(entry, ni, NULL); |
|
|
|
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_NCD, "[ncd] apply node=%016llx timestamp=%llu up=%d added=%d", |
|
|
|
|
|
|
|
(unsigned long long)node_id, (unsigned long long)ni->timestamp, entry->up, added); |
|
|
|
|
|
|
|
return added; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* ═══════════ единая диспетчеризация событий ═══════════ */ |
|
|
|
/* ═══════════ единая диспетчеризация событий ═══════════ */ |
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Центральный диспетчер: принимает событие (UP/DOWN/TIMEOUT), проверяет что оно |
|
|
|
* Центральный диспетчер: принимает событие (UP/DOWN/TIMEOUT), проверяет что оно |
|
|
|
@ -355,6 +411,9 @@ static void ncd_finish(struct ncd_entry* entry, int close_conn) { |
|
|
|
if (entry->closed) return; |
|
|
|
if (entry->closed) return; |
|
|
|
entry->closed = 1; |
|
|
|
entry->closed = 1; |
|
|
|
ncd_registry_remove(entry->inst, entry); |
|
|
|
ncd_registry_remove(entry->inst, entry); |
|
|
|
|
|
|
|
if (entry->node_ref) { |
|
|
|
|
|
|
|
topo_node_registry_unref(entry->inst->topo_groups, entry->node_id); entry->node_ref = 0; |
|
|
|
|
|
|
|
} |
|
|
|
if (entry->connect_timer) { uasync_cancel_timeout(entry->ua, entry->connect_timer); entry->connect_timer = 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 (entry->fin_wait_timer) { uasync_cancel_timeout(entry->ua, entry->fin_wait_timer); entry->fin_wait_timer = NULL; } |
|
|
|
struct ETCP_CONN* conn = entry->conn; entry->conn = NULL; |
|
|
|
struct ETCP_CONN* conn = entry->conn; entry->conn = NULL; |
|
|
|
@ -638,7 +697,7 @@ int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id, |
|
|
|
|
|
|
|
|
|
|
|
/* 2. Ищем conn через instance_find_conn (входящее / созданное etcp_connect) */ |
|
|
|
/* 2. Ищем conn через instance_find_conn (входящее / созданное etcp_connect) */ |
|
|
|
struct ETCP_CONN* conn = instance_find_conn(inst, node_id); |
|
|
|
struct ETCP_CONN* conn = instance_find_conn(inst, node_id); |
|
|
|
if (conn && conn->state == 1 && !conn->close_requested) { |
|
|
|
if (conn && conn->state != 2 && !conn->close_requested) { |
|
|
|
/* снять fin_wait если был */ |
|
|
|
/* снять fin_wait если был */ |
|
|
|
if (conn->fin_wait) { |
|
|
|
if (conn->fin_wait) { |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open REUSED clearing fin_wait (existing conn) node=0x%016llx", (unsigned long long)node_id); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open REUSED clearing fin_wait (existing conn) node=0x%016llx", (unsigned long long)node_id); |
|
|
|
@ -760,7 +819,7 @@ int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id, |
|
|
|
* известны заранее (например из BGP-анонса). ni не владеем — можно |
|
|
|
* известны заранее (например из BGP-анонса). ni не владеем — можно |
|
|
|
* передать временную структуру, копия не делается. |
|
|
|
* передать временную структуру, копия не делается. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
int node_conn_direct_open_node(struct UTUN_INSTANCE* inst, uint64_t node_id, |
|
|
|
static int ncd_open_node(struct UTUN_INSTANCE* inst, uint64_t node_id, |
|
|
|
ncd_callback cb, void* cb_arg, |
|
|
|
ncd_callback cb, void* cb_arg, |
|
|
|
struct NODE_CONN_DIRECT** out_handle, |
|
|
|
struct NODE_CONN_DIRECT** out_handle, |
|
|
|
struct TOPO_NODE* ni, |
|
|
|
struct TOPO_NODE* ni, |
|
|
|
@ -784,12 +843,14 @@ int node_conn_direct_open_node(struct UTUN_INSTANCE* inst, uint64_t node_id, |
|
|
|
entry->handle_count++; |
|
|
|
entry->handle_count++; |
|
|
|
*out_handle = h; |
|
|
|
*out_handle = h; |
|
|
|
if (entry->conn && entry->conn->state == 1 && entry->up) { |
|
|
|
if (entry->conn && entry->conn->state == 1 && entry->up) { |
|
|
|
|
|
|
|
ncd_create_links(entry, ni, specific_sock); |
|
|
|
ncd_schedule_deliver_up(inst->ua, h); |
|
|
|
ncd_schedule_deliver_up(inst->ua, h); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open_node REUSED (ready) node=0x%016llx handles=%d", (unsigned long long)node_id, entry->handle_count); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open_node REUSED (ready) node=0x%016llx handles=%d", (unsigned long long)node_id, entry->handle_count); |
|
|
|
} else if (entry->timed_out) { |
|
|
|
} else if (entry->timed_out) { |
|
|
|
ncd_revive_entry(entry, inst, ni, specific_sock); |
|
|
|
ncd_revive_entry(entry, inst, ni, specific_sock); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open_node REUSED (revived) node=0x%016llx handles=%d", (unsigned long long)node_id, entry->handle_count); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open_node REUSED (revived) node=0x%016llx handles=%d", (unsigned long long)node_id, entry->handle_count); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
|
|
|
|
ncd_create_links(entry, ni, specific_sock); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open_node REUSED (pending) node=0x%016llx handles=%d", (unsigned long long)node_id, entry->handle_count); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open_node REUSED (pending) node=0x%016llx handles=%d", (unsigned long long)node_id, entry->handle_count); |
|
|
|
} |
|
|
|
} |
|
|
|
return NCD_REUSED; |
|
|
|
return NCD_REUSED; |
|
|
|
@ -821,6 +882,7 @@ int node_conn_direct_open_node(struct UTUN_INSTANCE* inst, uint64_t node_id, |
|
|
|
etcp_conn_add_cbk(conn, ncd_down_cb, entry, ETCP_CBK_EVENT_DOWN); |
|
|
|
etcp_conn_add_cbk(conn, ncd_down_cb, entry, ETCP_CBK_EVENT_DOWN); |
|
|
|
|
|
|
|
|
|
|
|
if (conn->state == 1 && entry->up) { |
|
|
|
if (conn->state == 1 && entry->up) { |
|
|
|
|
|
|
|
ncd_create_links(entry, ni, specific_sock); |
|
|
|
ncd_schedule_deliver_up(inst->ua, h); |
|
|
|
ncd_schedule_deliver_up(inst->ua, h); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open_node REUSED new-entry (ready) node=0x%016llx conn=%p", (unsigned long long)node_id, (void*)conn); |
|
|
|
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 { |
|
|
|
} else { |
|
|
|
@ -888,7 +950,7 @@ int node_conn_direct_open_node(struct UTUN_INSTANCE* inst, uint64_t node_id, |
|
|
|
int link_count = ncd_create_links(entry, ni, specific_sock); |
|
|
|
int link_count = ncd_create_links(entry, ni, specific_sock); |
|
|
|
|
|
|
|
|
|
|
|
if (link_count == 0) |
|
|
|
if (link_count == 0) |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open_node (UDP only, TCP added by conn_mgr) node=0x%016llx links=%d", (unsigned long long)node_id, link_count); |
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_NCD, "[ncd] open_node: no new compatible links node=0x%016llx", (unsigned long long)node_id); |
|
|
|
|
|
|
|
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_TIMERS, "[ncd] connect timer SET: node=0x%016llx value_tb=%u now_tb=%llu path=NEW_node_conn_direct_open_node", |
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_TIMERS, "[ncd] connect timer SET: node=0x%016llx value_tb=%u now_tb=%llu path=NEW_node_conn_direct_open_node", |
|
|
|
(unsigned long long)node_id, inst->etcp_connect_timeout_tb, (unsigned long long)get_time_tb()); |
|
|
|
(unsigned long long)node_id, inst->etcp_connect_timeout_tb, (unsigned long long)get_time_tb()); |
|
|
|
@ -899,6 +961,45 @@ int node_conn_direct_open_node(struct UTUN_INSTANCE* inst, uint64_t node_id, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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, |
|
|
|
|
|
|
|
struct TOPO_NODE* ni, struct ETCP_SOCKET* specific_sock) { |
|
|
|
|
|
|
|
if (out_handle) *out_handle = NULL; |
|
|
|
|
|
|
|
if (!inst || !out_handle || !ni || node_id != ni->node_id || |
|
|
|
|
|
|
|
node_id != sc_derive_node_id_from_pubkey(ni->public_key) || (ni->timestamp && topo_node_verify(ni) < 0)) { |
|
|
|
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] invalid node passed to open"); return NCD_ERR; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
struct TOPO_NODE* known = ncd_lookup_node(inst, node_id); |
|
|
|
|
|
|
|
if (ni->timestamp && (!known || ni->timestamp > known->timestamp)) { |
|
|
|
|
|
|
|
uint8_t wire[4096]; |
|
|
|
|
|
|
|
struct TOPO_GROUP_NODE nq = {0}; |
|
|
|
|
|
|
|
struct TOPO_GROUP group = { .instance = inst }; |
|
|
|
|
|
|
|
struct TOPO_NODE* copy = NULL; |
|
|
|
|
|
|
|
int len = topo_node_serialize(ni, &nq, 0, 0, wire, sizeof(wire), 0); |
|
|
|
|
|
|
|
if (len < 0 || !inst->topo_groups || |
|
|
|
|
|
|
|
topo_node_deserialize(&group, wire, (size_t)len, ©, NULL, NULL, NULL, NULL) < 0) { |
|
|
|
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] cannot copy node snapshot"); |
|
|
|
|
|
|
|
if (known) topo_node_registry_unref(inst->topo_groups, node_id); |
|
|
|
|
|
|
|
return NCD_ERR; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
struct TOPO_NODE* stored = topo_node_registry_store(inst->topo_groups, copy); |
|
|
|
|
|
|
|
if (known) topo_node_registry_unref(inst->topo_groups, node_id); |
|
|
|
|
|
|
|
known = stored; |
|
|
|
|
|
|
|
if (!stored) { topo_node_destroy(inst->topo_groups, copy); return NCD_ERR; } |
|
|
|
|
|
|
|
if (inst->topo_sqlite_db && topo_node_sqlite_snapshot_put(inst->topo_sqlite_db, stored) < 0) |
|
|
|
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] cannot persist received node snapshot"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (known && ni->timestamp && known->timestamp == ni->timestamp && |
|
|
|
|
|
|
|
memcmp(known->x25519_self_sig, ni->x25519_self_sig, 64)) { |
|
|
|
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_NCD, "[ncd] conflicting node snapshot node=%016llx", (unsigned long long)node_id); |
|
|
|
|
|
|
|
topo_node_registry_unref(inst->topo_groups, node_id); return NCD_ERR; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
struct TOPO_NODE* selected = known && known->timestamp ? known : ni; |
|
|
|
|
|
|
|
int result = ncd_open_node(inst, node_id, cb, cb_arg, out_handle, selected, specific_sock); |
|
|
|
|
|
|
|
if (known) topo_node_registry_unref(inst->topo_groups, node_id); |
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Закрыть handle (graceful shutdown). |
|
|
|
* Закрыть handle (graceful shutdown). |
|
|
|
* |
|
|
|
* |
|
|
|
|