|
|
|
|
@ -55,7 +55,8 @@ static struct CONN_MGR_HANDLE* cm_invite_handle_new(conn_mgr_cb_t cb, void* cb_a
|
|
|
|
|
|
|
|
|
|
static void cm_deliver_up_cb(void* arg) { |
|
|
|
|
struct CONN_MGR_HANDLE* h = (struct CONN_MGR_HANDLE*)arg; |
|
|
|
|
if (h->cb) h->cb(h, h->node_id, h->entry->mgr->group->group_id, CONN_EVENT_UP, h->cb_arg); |
|
|
|
|
h->deliver_up_token = NULL; |
|
|
|
|
if (h->cb) h->cb(h, h->node_id, h->group_id, CONN_EVENT_UP, h->cb_arg); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Рассылает событие ВСЕМ handle'ам entry. Одно соединение — много слушателей:
|
|
|
|
|
@ -88,7 +89,7 @@ int cm_nat_compatible(struct ETCP_SOCKET* our, uint8_t tcfg, uint8_t tnat) {
|
|
|
|
|
uint8_t tt = tnat >= NAT_VERIFIED_UNKNOWN ? CFG_SERVER_TYPE_PUBLIC : tcfg; |
|
|
|
|
uint8_t ot = our->type; |
|
|
|
|
if (ot == CFG_SERVER_TYPE_PUBLIC || ot == CFG_SERVER_TYPE_UNKNOWN) return 1; |
|
|
|
|
if (ot == CFG_SERVER_TYPE_NAT && our->nat_type == NAT_VERIFIED_EIM && tt == CFG_SERVER_TYPE_PUBLIC) return 1; |
|
|
|
|
if (tt == CFG_SERVER_TYPE_PUBLIC) return 1; /* цель публичная/проверенная — исходящее работает из-за любого NAT */ |
|
|
|
|
if (ot == CFG_SERVER_TYPE_NAT && our->nat_type == NAT_VERIFIED_EIM && tt == CFG_SERVER_TYPE_NAT) return 1; |
|
|
|
|
if ((ot == CFG_SERVER_TYPE_PRIVATE || ot == CFG_SERVER_TYPE_LOCAL) && tt == CFG_SERVER_TYPE_PRIVATE) return 2; |
|
|
|
|
return 0; |
|
|
|
|
@ -387,7 +388,7 @@ int conn_mgr_open(struct CONN_MGR* mgr, uint64_t node_id, uint32_t idle_timeout_
|
|
|
|
|
if (entry && entry->state == CONN_MGR_STATE_CONNECTED) { |
|
|
|
|
struct CONN_MGR_HANDLE* h = cm_handle_new(entry, gid, cb, cb_arg); |
|
|
|
|
if (!h) return -1; if (out_handle) *out_handle = h; |
|
|
|
|
uasync_call_soon(mgr->instance->ua, h, cm_deliver_up_cb); return 0; |
|
|
|
|
h->deliver_up_token = uasync_call_soon(mgr->instance->ua, h, cm_deliver_up_cb); return 0; |
|
|
|
|
} |
|
|
|
|
if (entry && entry->state == CONN_MGR_STATE_CONNECTING) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "node 0x%016llx already connecting, adding handle", (unsigned long long)node_id); |
|
|
|
|
@ -411,7 +412,7 @@ int conn_mgr_open(struct CONN_MGR* mgr, uint64_t node_id, uint32_t idle_timeout_
|
|
|
|
|
node_conn_direct_open_node(mgr->instance, node_id, cm_ncd_callback, entry, &entry->ncd_handle, &ni_e, NULL); } |
|
|
|
|
struct CONN_MGR_HANDLE* h = cm_handle_new(entry, gid, cb, cb_arg); |
|
|
|
|
if (!h) { cm_entry_cleanup(entry); return -1; } if (out_handle) *out_handle = h; |
|
|
|
|
cm_update_nodeinfo(entry); uasync_call_soon(mgr->instance->ua, h, cm_deliver_up_cb); return 0; |
|
|
|
|
cm_update_nodeinfo(entry); h->deliver_up_token = uasync_call_soon(mgr->instance->ua, h, cm_deliver_up_cb); return 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -433,6 +434,12 @@ void conn_mgr_close(struct CONN_MGR_HANDLE* h) {
|
|
|
|
|
if (!h) return; |
|
|
|
|
struct CONN_MGR_ENTRY* entry = h->entry; |
|
|
|
|
if (!entry) { u_free(h); return; } |
|
|
|
|
/* отменяем отложенный UP-коллбэк (cm_deliver_up_cb), иначе он дёрнется
|
|
|
|
|
* с освобождённым handle (use-after-free при быстром teardown соединения) */ |
|
|
|
|
if (h->deliver_up_token && entry->mgr && entry->mgr->instance) { |
|
|
|
|
uasync_call_soon_cancel(entry->mgr->instance->ua, h->deliver_up_token); |
|
|
|
|
h->deliver_up_token = NULL; |
|
|
|
|
} |
|
|
|
|
{ struct CONN_MGR_HANDLE** pp = &entry->handles; |
|
|
|
|
while (*pp) { if (*pp == h) { *pp = h->next; break; } pp = &(*pp)->next; } |
|
|
|
|
} |
|
|
|
|
@ -530,15 +537,19 @@ static void cm_ping_cb_impl(int success, uint16_t rtt, void* arg, uint64_t nonce
|
|
|
|
|
|
|
|
|
|
/* ═══════ DIRECT фаза (NCD + ручная NAT-фильтрация линков) ═══════ */ |
|
|
|
|
|
|
|
|
|
/* Добавляет IPv4/IPv6 линки к conn. db_loaded: все сокеты без фильтра.
|
|
|
|
|
* Обычный путь: NAT-фильтрация (cm_nat_compatible) + приоритет NAT > INTERFACE. |
|
|
|
|
* Если ни одного линка не создалось — закрывает NCD и переходит к REVERSE/INDIRECT. */ |
|
|
|
|
/* Добавляет IPv4/IPv6 линки к conn. Единый цикл для адресов из BGP и из базы:
|
|
|
|
|
* протокол из a->protocol (TCP — без NAT-фильтра, UDP — NAT-фильтрация), |
|
|
|
|
* приоритет NAT > INTERFACE. Если ни одного линка не создалось — закрывает NCD |
|
|
|
|
* и переходит к REVERSE/INDIRECT (для db_loaded — cleanup + TIMEOUT). */ |
|
|
|
|
static void cm_direct_add_links(struct ETCP_CONN* conn, struct CONN_MGR_ENTRY* entry, |
|
|
|
|
struct TOPO_NODE* ni, int db_loaded) { |
|
|
|
|
int any = 0, v4_cnt = 0, v6_cnt = 0, v4_tcp = 0, v6_tcp = 0; |
|
|
|
|
/* v4 */ |
|
|
|
|
if (db_loaded) { |
|
|
|
|
/* v4 — единый цикл для адресов из BGP и из базы: протокол из a->protocol,
|
|
|
|
|
* приоритет NAT > INTERFACE, NAT-фильтрация только для UDP */ |
|
|
|
|
uint8_t prio[] = {TOPO_ADDR_NAT, TOPO_ADDR_INTERFACE}; |
|
|
|
|
for (int pr = 0; pr < 2; pr++) { |
|
|
|
|
for (const struct TOPO_ADDR4* a = ni->v4_addrs; a; a = a->next) { |
|
|
|
|
if (a->type != prio[pr]) continue; |
|
|
|
|
struct sockaddr_in sin; memset(&sin,0,sizeof(sin)); sin.sin_family=AF_INET; |
|
|
|
|
memcpy(&sin.sin_addr.s_addr,a->addr,4); sin.sin_port=htons(a->port); |
|
|
|
|
struct sockaddr_storage sa; memcpy(&sa,&sin,sizeof(sin)); |
|
|
|
|
@ -550,23 +561,13 @@ static void cm_direct_add_links(struct ETCP_CONN* conn, struct CONN_MGR_ENTRY* e
|
|
|
|
|
} s = s->next; } |
|
|
|
|
} |
|
|
|
|
if (a->protocol & TOPO_PROTO_UDP) { |
|
|
|
|
struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets; |
|
|
|
|
while (s) { if (s->local_addr.ss_family == AF_INET) { |
|
|
|
|
if (etcp_link_new(conn,s,&sa,0)) any=1; } s=s->next; } |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
uint8_t prio[]={TOPO_ADDR_NAT,TOPO_ADDR_INTERFACE}; |
|
|
|
|
for (int pr=0;pr<2;pr++) for (const struct TOPO_ADDR4* a=ni->v4_addrs;a;a=a->next) { |
|
|
|
|
if (a->type!=prio[pr]) continue; |
|
|
|
|
for (const struct TOPO_SOCKMETA4* m=ni->v4_sock_meta;m;m=m->next) { |
|
|
|
|
if (m->id!=a->socket_id) continue; |
|
|
|
|
struct ETCP_SOCKET* s=entry->mgr->instance->etcp_sockets; |
|
|
|
|
while(s){if(cm_nat_compatible(s,m->config_type,m->nat_type)&&s->local_addr.ss_family==AF_INET){ |
|
|
|
|
struct sockaddr_in sin; memset(&sin,0,sizeof(sin)); sin.sin_family=AF_INET; |
|
|
|
|
memcpy(&sin.sin_addr.s_addr,a->addr,4); sin.sin_port=htons(a->port); |
|
|
|
|
struct sockaddr_storage sa; memcpy(&sa,&sin,sizeof(sin)); |
|
|
|
|
if(etcp_link_new(conn,s,&sa,0)) any=1;} s=s->next;} |
|
|
|
|
for (const struct TOPO_SOCKMETA4* m = ni->v4_sock_meta; m; m = m->next) { |
|
|
|
|
if (m->id != a->socket_id) continue; |
|
|
|
|
struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets; |
|
|
|
|
while (s) { if (cm_nat_compatible(s, m->config_type, m->nat_type) && s->local_addr.ss_family == AF_INET) { |
|
|
|
|
if (etcp_link_new(conn, s, &sa, 0)) { any = 1; v4_cnt++; } } s = s->next; } |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|