diff --git a/src/transport_layer/etcp_connect.c b/src/transport_layer/etcp_connect.c deleted file mode 100644 index ac2c28f1..00000000 --- a/src/transport_layer/etcp_connect.c +++ /dev/null @@ -1,419 +0,0 @@ -#include "etcp_api.h" -#include "etcp.h" -#include "etcp_connect.h" -#include "utun_instance.h" -#include "topo_node.h" -#include "stcp_link.h" -#include "../lib/debug_config.h" -#include "../lib/mem.h" -#include "../lib/u_async.h" -#include "../lib/socket_compat.h" -#include - -#define DEBUG_CATEGORY_ETCP_CONNECT DEBUG_CATEGORY_ETCP - -struct etcp_connect_cb_node { - etcp_connect_callback_t cb; - void* arg; - uint8_t flags; - struct etcp_connect_cb_node* next; -}; - -struct ETCP_CONNECT { - struct ETCP_CONNECT* next; - struct UTUN_INSTANCE* instance; - uint64_t node_id; - struct ETCP_CONN* conn; - struct etcp_connect_cb_node* cb_list; - void* initial_timer; - void* settle_timer; - uint16_t min_rtt; - uint8_t early_delivered : 1; - uint8_t done : 1; -}; -static void connect_init_cb(struct ETCP_CONN* conn, int event, void* arg); - -static struct ETCP_CONNECT* connect_find(struct UTUN_INSTANCE* inst, uint64_t node_id) { - struct ETCP_CONNECT* ctx = inst->pending_connects; - while (ctx) { if (ctx->node_id == node_id) return ctx; ctx = ctx->next; } - return NULL; -} - -static void connect_deliver(struct ETCP_CONNECT* ctx, int type, int free_nodes) { - struct etcp_connect_cb_node** pp = &ctx->cb_list; - while (*pp) { - struct etcp_connect_cb_node* node = *pp; - if (type == 0 || (node->flags & (uint8_t)type)) { - node->cb(node->arg, (type == 0) ? NULL : ctx->conn, type); - if (free_nodes) { *pp = node->next; u_free(node); } else { pp = &node->next; } - } else { - pp = &node->next; - } - } -} - -static void connect_cancel(struct ETCP_CONNECT* ctx) { - if (!ctx) return; - struct UTUN_INSTANCE* inst = ctx->instance; - if (inst) { - struct ETCP_CONNECT** pp = &inst->pending_connects; - while (*pp && *pp != ctx) pp = &(*pp)->next; - if (*pp) *pp = ctx->next; - if (ctx->initial_timer) { uasync_cancel_timeout(inst->ua, ctx->initial_timer); ctx->initial_timer = NULL; } - if (ctx->settle_timer) { uasync_cancel_timeout(inst->ua, ctx->settle_timer); ctx->settle_timer = NULL; } - } - u_free(ctx); -} - -static void connect_create_links_v4(struct ETCP_CONNECT* ctx, struct TOPO_GROUP_NODE* node) { - if (!node) return; - struct TOPO_NODE* ni = topo_node_registry_find(ctx->instance->topo_groups, node->node_id); - if (!ni) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[etcp_connect] links_v4: ni NOT in registry for node=%016llx", (unsigned long long)node->node_id); return; } - int addr_count = 0, sock_count = 0, link_count = 0; - { struct ETCP_SOCKET* s = ctx->instance->etcp_sockets; while (s) { sock_count++; s = s->next; } } - for (const struct TOPO_ADDR4* a = ni->v4_addrs; a; a = a->next) { - addr_count++; - if (a->port == 0) continue; - { int zero = 1; for (int j = 0; j < 4; j++) if (a->addr[j] != 0) { zero = 0; break; } if (zero) 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)); - int addr_links = 0; - if (a->protocol & TOPO_PROTO_UDP) { - struct ETCP_SOCKET* s = ctx->instance->etcp_sockets; - while (s) { if (s->local_addr.ss_family == AF_INET && etcp_link_new(ctx->conn, s, &sa, 0)) { link_count++; addr_links++; } s = s->next; } - } - if (a->protocol & TOPO_PROTO_TCP) { - struct ETCP_SOCKET* s = ctx->instance->etcp_sockets; - while (s) { if (s->is_tcp && s->local_addr.ss_family == AF_INET) { - struct ETCP_LINK *tlink = etcp_link_new(ctx->conn, s, &sa, 0); - 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++; addr_links++; } - } s = s->next; } - } - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[etcp_connect] link_v4: %d.%d.%d.%d:%d proto=%d links=%d conn=[%s]", - a->addr[0], a->addr[1], a->addr[2], a->addr[3], a->port, a->protocol, addr_links, ctx->conn->log_name); - } - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[etcp_connect] links_v4: TOTAL addrs=%d socks=%d links=%d%s for node=%016llx", - addr_count, sock_count, link_count, addr_count == 0 ? " (v4_addrs EMPTY)" : "", (unsigned long long)node->node_id); -} - -static void connect_create_links_v6(struct ETCP_CONNECT* ctx, struct TOPO_GROUP_NODE* node) { - if (!node) return; - struct TOPO_NODE* ni = topo_node_registry_find(ctx->instance->topo_groups, node->node_id); - if (!ni) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[etcp_connect] links_v6: ni NOT in registry for node=%016llx", (unsigned long long)node->node_id); return; } - int addr_count = 0, sock_count = 0, link_count = 0; - { struct ETCP_SOCKET* s = ctx->instance->etcp_sockets; while (s) { sock_count++; s = s->next; } } - for (const struct TOPO_ADDR6* a = ni->v6_addrs; a; a = a->next) { - addr_count++; - if (a->port == 0) { DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[etcp_connect] link_v6: skip port==0 node=%016llx", (unsigned long long)node->node_id); continue; } - int zero = 1; for (int j = 0; j < 16; j++) if (a->addr[j] != 0) { zero = 0; break; } if (zero) { DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[etcp_connect] link_v6: skip zero addr node=%016llx", (unsigned long long)node->node_id); continue; } - struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; - memcpy(&sin6.sin6_addr, a->addr, 16); sin6.sin6_port = htons(a->port); - int is_ll = (a->addr[0] == 0xfe && (a->addr[1] & 0xc0) == 0x80); - int addr_links = 0; - if (a->protocol & TOPO_PROTO_UDP) { - struct ETCP_SOCKET* s = ctx->instance->etcp_sockets; - while (s) { if (s->local_addr.ss_family == AF_INET6) { - if (is_ll) sin6.sin6_scope_id = s->netif_index; - struct sockaddr_storage sa; memcpy(&sa, &sin6, sizeof(sin6)); - if (etcp_link_new(ctx->conn, s, &sa, 0)) { link_count++; addr_links++; } - } s = s->next; } - } - if (a->protocol & TOPO_PROTO_TCP) { - if (is_ll) { struct ETCP_SOCKET* sv = ctx->instance->etcp_sockets; - 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 ETCP_SOCKET* s = ctx->instance->etcp_sockets; - while (s) { if (s->is_tcp && s->local_addr.ss_family == AF_INET6) { - struct ETCP_LINK *tlink = etcp_link_new(ctx->conn, s, &sa, 0); - 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++; addr_links++; } - } s = s->next; } - } - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[etcp_connect] link_v6: %s:%d proto=%d links=%d conn=[%s]", - ip_to_str(a->addr, AF_INET6).str, a->port, a->protocol, addr_links, ctx->conn->log_name); - } - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[etcp_connect] links_v6: TOTAL addrs=%d socks=%d links=%d%s for node=%016llx", - addr_count, sock_count, link_count, addr_count == 0 ? " (v6_addrs EMPTY)" : "", (unsigned long long)node->node_id); -} - - -static void connect_initial_timeout_cb(void* arg) { - struct ETCP_CONNECT* ctx = (struct ETCP_CONNECT*)arg; - if (!ctx || ctx->done) return; - ctx->done = 1; - ctx->initial_timer = NULL; - DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] timeout for node 0x%016llx", (unsigned long long)ctx->node_id); - struct ETCP_CONN* conn = ctx->conn; ctx->conn = NULL; - connect_deliver(ctx, 0, 1); - if (conn) etcp_connection_close(conn); - connect_cancel(ctx); -} - -static void connect_settle_timeout_cb(void* arg) { - struct ETCP_CONNECT* ctx = (struct ETCP_CONNECT*)arg; - if (!ctx || ctx->done) return; - ctx->done = 1; - ctx->settle_timer = NULL; - DEBUG_INFO(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] settle for node 0x%016llx, min_rtt=%u", - (unsigned long long)ctx->node_id, ctx->min_rtt); - struct ETCP_LINK* link = ctx->conn->links; - while (link) { - struct ETCP_LINK* next = link->next; - if (!link->initialized) { - DEBUG_INFO(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] settle: removing link=%d is_tcp=%d state=%d addr=%s for node 0x%016llx", - link->local_link_id, link->is_tcp, link->link_state, - sockaddr_storage_to_str(&link->remote_addr).str, (unsigned long long)ctx->node_id); - etcp_link_close(link); - } - link = next; - } - etcp_conn_remove_cbk(ctx->conn, connect_init_cb, ctx); - connect_deliver(ctx, ETCP_CONNECT_LATE, 1); - connect_cancel(ctx); -} - -static void connect_init_cb(struct ETCP_CONN* conn, int event, void* arg) { (void)event; - struct ETCP_CONNECT* ctx = (struct ETCP_CONNECT*)arg; - if (!ctx || ctx->done) return; - - int total_links = 0, up_links = 0; - struct ETCP_LINK* link = conn->links; - while (link) { - total_links++; - if (link->initialized && link->rtt_last && link->rtt_last < ctx->min_rtt) - ctx->min_rtt = link->rtt_last; - if (link->link_state == LINK_STATE_CONNECTED) up_links++; - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[etcp_connect] init_cb: link=%d state=%d init=%d is_tcp=%d rtt=%u addr=%s", - link->local_link_id, link->link_state, link->initialized, link->is_tcp, link->rtt_last, - sockaddr_storage_to_str(&link->remote_addr).str); - link = link->next; - } - - if (total_links == 1 || up_links == total_links || (total_links == 0 && conn->tcp_link_count > 0)) { - if (!ctx->early_delivered) { - ctx->early_delivered = 1; - if (ctx->initial_timer) { uasync_cancel_timeout(ctx->instance->ua, ctx->initial_timer); ctx->initial_timer = NULL; } - } - DEBUG_INFO(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] init_cb: node 0x%016llx links=%d up=%d tcp=%d → immediate LATE", - (unsigned long long)ctx->node_id, total_links, up_links, conn->tcp_link_count); - { struct etcp_connect_cb_node* n = ctx->cb_list; while (n) { struct etcp_connect_cb_node* next = n->next; if (n->flags & ETCP_CONNECT_EARLY) n->cb(n->arg, ctx->conn, ETCP_CONNECT_EARLY); if (n->flags & ETCP_CONNECT_LATE) n->cb(n->arg, ctx->conn, ETCP_CONNECT_LATE); u_free(n); n = next; } ctx->cb_list = NULL; } - connect_cancel(ctx); - return; - } - - if (ctx->early_delivered) return; - ctx->early_delivered = 1; - DEBUG_INFO(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] init_cb: node 0x%016llx links=%d up=%d tcp=%d → EARLY, settle", - (unsigned long long)ctx->node_id, total_links, up_links, conn->tcp_link_count); - connect_deliver(ctx, ETCP_CONNECT_EARLY, 0); - if (ctx->initial_timer) { uasync_cancel_timeout(ctx->instance->ua, ctx->initial_timer); ctx->initial_timer = NULL; } - uint32_t settle_tb; - if (ctx->min_rtt == 0xFFFF) settle_tb = 20000; - else { - settle_tb = (uint32_t)ctx->min_rtt * 8; - if (settle_tb < 5000) settle_tb = 5000; - if (settle_tb > 20000) settle_tb = 20000; - } - ctx->settle_timer = uasync_set_timeout(ctx->instance->ua, (int)settle_tb, ctx, - connect_settle_timeout_cb, "etcp_connect_settle"); -} - -int etcp_connect(struct UTUN_INSTANCE* inst, struct TOPO_GROUP_NODE* node, - etcp_connect_callback_t cb, void* arg, uint8_t flags) { - if (!inst || !node || !cb || !flags || (flags & ~(ETCP_CONNECT_EARLY | ETCP_CONNECT_LATE))) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "invalid connect arguments/flags=%u", flags); return -1; - } - - struct TOPO_NODE* ni = topo_node_registry_find(inst->topo_groups, node->node_id); - if (!ni) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] node not in registry"); return -1; } - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[etcp_connect] registry OK node=%016llx pub=%016llx v4addrs=%d v6addrs=%d", - (unsigned long long)node->node_id, *(uint64_t*)ni->public_key, - topo_list_count((struct _topo_head*)ni->v4_addrs), - topo_list_count((struct _topo_head*)ni->v6_addrs)); - - uint64_t node_id = ni->node_id; - if (node_id == 0) { - if (!ni->public_key) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] node_id=0 and public_key is NULL"); - return -1; - } - int zero = 1; - for (int i = 0; i < SC_PUBKEY_SIZE; i++) - if (ni->public_key[i]) { zero = 0; break; } - if (zero) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] node_id=0 and public_key is all zeros"); - return -1; - } - node_id = sc_derive_node_id_from_pubkey(ni->public_key); - ni->node_id = node_id; - } - - struct ETCP_CONN* conn = instance_find_conn(inst, node_id); - struct ETCP_CONNECT* ctx = connect_find(inst, node_id); - - // Case 1: conn && ctx — already connecting - if (conn && ctx) { - if (ctx->done) { - DEBUG_INFO(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] node 0x%016llx: existing ctx timed out, cb(NULL,0)", - (unsigned long long)node_id); - cb(arg, NULL, 0); - return 0; - } - struct etcp_connect_cb_node* cn = u_calloc(1, sizeof(struct etcp_connect_cb_node)); - if (!cn) return -1; - cn->cb = cb; cn->arg = arg; cn->flags = flags; cn->next = ctx->cb_list; ctx->cb_list = cn; - DEBUG_INFO(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] node 0x%016llx already connecting, added cb", - (unsigned long long)node_id); - return 0; - } - - // Case 2: !conn && ctx — context exists but conn was removed (rare) - if (!conn && ctx) { - struct etcp_connect_cb_node* cn = u_calloc(1, sizeof(struct etcp_connect_cb_node)); - if (!cn) return -1; - cn->cb = cb; cn->arg = arg; cn->flags = flags; cn->next = ctx->cb_list; ctx->cb_list = cn; - return 0; - } - - // Case 3: conn && !ctx — existing connection, no context - if (conn && !ctx) { - if (conn->state == 0) { - // Pending conn from another path (e.g. incoming INIT before etcp_connect) - ctx = u_calloc(1, sizeof(struct ETCP_CONNECT)); - if (!ctx) return -1; - ctx->instance = inst; ctx->node_id = node_id; ctx->conn = conn; - ctx->min_rtt = 0xFFFF; - struct etcp_connect_cb_node* cn = u_calloc(1, sizeof(struct etcp_connect_cb_node)); - if (!cn) { u_free(ctx); return -1; } - cn->cb = cb; cn->arg = arg; cn->flags = flags; ctx->cb_list = cn; - etcp_conn_add_cbk(conn, connect_init_cb, ctx, ETCP_CBK_EVENT_INIT); - ctx->initial_timer = uasync_set_timeout(inst->ua, (int)inst->etcp_connect_timeout_tb, ctx, - connect_initial_timeout_cb, "etcp_connect_init"); - ctx->next = inst->pending_connects; inst->pending_connects = ctx; - DEBUG_INFO(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] node 0x%016llx: existing pending conn, waiting for init", - (unsigned long long)node_id); - return 0; - } - - // conn->state == 1: already ready — deliver EARLY+LATE immediately (via direct loop to deliver both phases) - ctx = u_calloc(1, sizeof(struct ETCP_CONNECT)); - if (!ctx) return -1; - ctx->instance = inst; ctx->node_id = node_id; ctx->conn = conn; - ctx->early_delivered = 1; - { - struct etcp_connect_cb_node* cn = u_calloc(1, sizeof(struct etcp_connect_cb_node)); - if (!cn) { u_free(ctx); return -1; } - cn->cb = cb; cn->arg = arg; cn->flags = flags; - ctx->cb_list = cn; - } - - DEBUG_INFO(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] node 0x%016llx: existing ready conn, delivering EARLY+LATE", - (unsigned long long)node_id); - struct etcp_connect_cb_node* n = ctx->cb_list; - while (n) { - struct etcp_connect_cb_node* next = n->next; - if (n->flags & ETCP_CONNECT_EARLY) n->cb(n->arg, ctx->conn, ETCP_CONNECT_EARLY); - if (n->flags & ETCP_CONNECT_LATE) n->cb(n->arg, ctx->conn, ETCP_CONNECT_LATE); - u_free(n); n = next; - } - u_free(ctx); - return 0; - } - - // Case 4: !conn && !ctx — new connection - conn = etcp_connection_create(inst, NULL); - if (!conn) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] failed to create ETCP_CONN for node 0x%016llx", - (unsigned long long)node_id); - cb(arg, NULL, 0); - return -1; - } - conn->peer_node_id = node_id; - etcp_update_log_name(conn); - if (conn->conn_queue && conn->conn_queue_entry) { - queue_remove_data(conn->conn_queue, conn->conn_queue_entry); - queue_entry_free(conn->conn_queue_entry); - } - { struct ll_entry* qe = queue_entry_new(sizeof(struct conn_queue_entry)); if (qe) { struct conn_queue_entry* ce = (struct conn_queue_entry*)qe->data; ce->peer_node_id = node_id; ce->conn = conn; conn->conn_queue_entry = qe; conn->conn_queue = inst->connections; queue_data_put_with_index(inst->connections, qe); } } - - if (sc_init_ctx(&conn->crypto_ctx, &inst->my_keys) != SC_OK) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] sc_init_ctx failed for node 0x%016llx", (unsigned long long)node_id); - etcp_connection_close(conn); cb(arg, NULL, 0); return -1; - } - if (sc_set_peer_public_key(&conn->crypto_ctx, ni->public_key, 0) != SC_OK) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] sc_set_peer_public_key failed for node 0x%016llx", (unsigned long long)node_id); - etcp_connection_close(conn); cb(arg, NULL, 0); return -1; - } - - ctx = u_calloc(1, sizeof(struct ETCP_CONNECT)); - if (!ctx) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] alloc failed"); - etcp_connection_close(conn); cb(arg, NULL, 0); return -1; - } - ctx->instance = inst; ctx->node_id = node_id; ctx->conn = conn; - ctx->min_rtt = 0xFFFF; - { - struct etcp_connect_cb_node* cn = u_calloc(1, sizeof(struct etcp_connect_cb_node)); - if (!cn) { u_free(ctx); etcp_connection_close(conn); cb(arg, NULL, 0); return -1; } - cn->cb = cb; cn->arg = arg; cn->flags = flags; ctx->cb_list = cn; - } - - etcp_conn_add_cbk(conn, connect_init_cb, ctx, ETCP_CBK_EVENT_INIT); - - connect_create_links_v4(ctx, node); - connect_create_links_v6(ctx, node); - - if (!conn->links && conn->tcp_link_count == 0) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] no links created for node 0x%016llx (links=%p tcp_links=%d)", - (unsigned long long)node_id, (void*)conn->links, conn->tcp_link_count); - connect_deliver(ctx, 0, 1); - etcp_connection_close(conn); u_free(ctx); return -1; - } - - ctx->initial_timer = uasync_set_timeout(inst->ua, (int)inst->etcp_connect_timeout_tb, ctx, connect_initial_timeout_cb, "etcp_connect_init"); - ctx->next = inst->pending_connects; inst->pending_connects = ctx; - DEBUG_INFO(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] started for node 0x%016llx", (unsigned long long)node_id); - return 0; -} - -void etcp_connect_cancel_for_conn(struct UTUN_INSTANCE* inst, struct ETCP_CONN* conn) { - if (!inst || !conn) return; - struct ETCP_CONNECT** pp = &inst->pending_connects; - while (*pp) { - struct ETCP_CONNECT* ctx = *pp; - if (ctx->conn == conn) { - *pp = ctx->next; - ctx->done = 1; - ctx->conn = NULL; - if (ctx->initial_timer) { uasync_cancel_timeout(inst->ua, ctx->initial_timer); ctx->initial_timer = NULL; } - if (ctx->settle_timer) { uasync_cancel_timeout(inst->ua, ctx->settle_timer); ctx->settle_timer = NULL; } - u_free(ctx); - } else { - pp = &(*pp)->next; - } - } -} - -/* Полная отмена pending-коннекта по node_id: снимает connect_init_cb - * с conn (conn остаётся жив, например, переиспользуется ncd), отменяет таймеры, - * вынимает ctx из pending_connects и освобождает. Безопасно вызывать, если ctx нет. */ -void etcp_connect_cancel_by_node(struct UTUN_INSTANCE* inst, uint64_t node_id) { - if (!inst) return; - struct ETCP_CONNECT** pp = &inst->pending_connects; - while (*pp) { - struct ETCP_CONNECT* ctx = *pp; - if (ctx->node_id == node_id) { - *pp = ctx->next; - if (ctx->conn) { - etcp_conn_remove_cbk(ctx->conn, connect_init_cb, ctx); - } - if (ctx->initial_timer) { uasync_cancel_timeout(inst->ua, ctx->initial_timer); ctx->initial_timer = NULL; } - if (ctx->settle_timer) { uasync_cancel_timeout(inst->ua, ctx->settle_timer); ctx->settle_timer = NULL; } - u_free(ctx); - } else { - pp = &(*pp)->next; - } - } -} diff --git a/src/transport_layer/etcp_connect.h b/src/transport_layer/etcp_connect.h deleted file mode 100644 index 817c5715..00000000 --- a/src/transport_layer/etcp_connect.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef ETCP_CONNECT_H -#define ETCP_CONNECT_H - -#include - -struct UTUN_INSTANCE; -struct ETCP_CONN; -struct TOPO_GROUP_NODE; -typedef void (*etcp_connect_callback_t)(void* arg, struct ETCP_CONN* conn, int type); - -/* Внутренний установщик прямого ETCP-транспорта; владельцы используют node_conn_direct.h. - * node->node_id должен находиться в node_registry: оттуда берутся ключ и IPv4/IPv6 адреса. - * Подключение создаёт UDP/STCP-линки либо подписывает callback на текущую попытку к тому же узлу. - * Все вызовы/callbacks — в uasync. flags — непустая маска ETCP_CONNECT_EARLY/LATE (etcp_api.h). - * EARLY означает появление транспорта; LATE — завершение выбора линков. Они не означают READY группы. - * При одном/полностью готовом наборе линков обе запрошенные фазы выдаются подряд; - * иначе после EARLY ждём settle 0.5..2с и удаляем неинициализированные линки. - * Для уже готового соединения callback вызывается внутри etcp_connect, до возврата. - * conn в callback заимствован. type=0/conn=NULL — отказ; initial timeout закрывает соединение. - * Возврат 0 означает принятую попытку/выданный результат; -1 — ошибка, причём некоторые - * ошибки создания также вызывают cb(NULL,0). Обработчик должен учитывать оба способа отказа. */ -int etcp_connect(struct UTUN_INSTANCE* instance, struct TOPO_GROUP_NODE* node, - etcp_connect_callback_t cb, void* arg, uint8_t flags); - -/* Снять таймеры/контекст по conn без уведомления callbacks. Только teardown соединения, - * когда connect_init_cb больше не может быть вызван; транспорт освобождает вызывающий слой. */ -void etcp_connect_cancel_for_conn(struct UTUN_INSTANCE* inst, struct ETCP_CONN* conn); - -/* Полная отмена pending-коннекта по node_id: снимает коллбэки с conn (conn остаётся - * жив — переиспользуется, напр. ncd), отменяет таймеры, освобождает ctx. */ -void etcp_connect_cancel_by_node(struct UTUN_INSTANCE* inst, uint64_t node_id); - -#endif diff --git a/src/transport_layer/etcp_connect_doc.md b/src/transport_layer/etcp_connect_doc.md deleted file mode 100644 index 646eeecc..00000000 --- a/src/transport_layer/etcp_connect_doc.md +++ /dev/null @@ -1,71 +0,0 @@ -# ETCP Connect (etcp_connect) - -## 1. Назначение -Управление исходящими ETCP-соединениями. Предоставляет асинхронный API `etcp_connect()` для установки соединения с удалённым узлом: создаёт ETCP_CONN, настраивает криптографию, поднимает UDP-линки и опционально TCP/STCP-транспорт, отслеживает прогресс установки с таймерами. Доставляет коллбэки о фазах готовности (EARLY, LATE). - -## 2. Как пользоваться - -```c -// Запуск подключения к узлу -etcp_connect(inst, node, my_connect_cb, my_arg, ETCP_CONNECT_EARLY | ETCP_CONNECT_LATE); -``` - -Коллбэк вызывается на разных фазах: -```c -void my_connect_cb(void* arg, struct ETCP_CONN* conn, int type) { - if (!conn) { - // type == 0 — таймаут/ошибка подключения - return; - } - if (type & ETCP_CONNECT_EARLY) - // первый линк готов (можно начинать обмен) - if (type & ETCP_CONNECT_LATE) - // settle-фаза завершена (все линки проверены, неудачные удалены) -} -``` - -**Жизненный цикл:** -1. `etcp_connect()` — создаёт ETCP_CONN, crypto_ctx, UDP-линки и TCP/STCP -2. `connect_ready_cb()` — первый линк стал ready → EARLY-коллбэк → запуск settle-таймера -3. `connect_settle_timeout_cb()` — settle (min_rtt × 8, clamp 500..2000ms) → удаление неудачных линков → LATE-коллбэк -4. При таймауте (`connect_initial_timeout_cb`) — type=0 (conn=NULL), все ресурсы освобождаются - -**Нюансы:** -- Если соединение уже установлено — коллбэки вызываются немедленно -- Если соединение в процессе — коллбэк добавляется в список ожидающих (поддержка нескольких подписчиков) -- `etcp_connect_cancel_for_conn()` — только для deferred cleanup (фаза 2 закрытия), НЕ из mainloop -- При таймауте `etcp_connect()` может доставить type=0 с conn=NULL — нужно обрабатывать - -## 3. API - -### Структуры -**ETCP_CONNECT** — контекст одного исходящего соединения: -- `conn` — целевой ETCP_CONN -- `tcp_link` — STCP-транспорт (опционально) -- `cb_list` — цепочка коллбэков (несколько подписчиков) -- `initial_timer`, `settle_timer` — таймеры контроля прогресса -- `min_rtt` — минимальный RTT среди готовых линков (для расчёта settle-времени) -- `early_delivered` — флаг однократного вызова EARLY -- `tcp_ready` — TCP-линк поднят -- `done` — соединение завершено (ошибка/успех), дальнейшая обработка игнорируется - -### Константы коллбэков (etcp_api.h) -| Константа | Описание | -|---|---| -| `ETCP_CONNECT_EARLY` (1) | Первый линк готов | -| `ETCP_CONNECT_LATE` (2) | Settle-фаза завершена | - -### Функции -| Функция | Описание | -|---|---| -| `etcp_connect(inst, node, cb, arg, flags)` | Запустить асинхронное подключение к узлу. Возвращает 0 при успехе | -| `etcp_connect_cancel_for_conn(inst, conn)` | Отменить ожидание для conn. Только из etcp_connection_free_resources (фаза 2) | - -### Пути завершения -1. **Таймаут установки** (`connect_initial_timeout_cb`): stcp_link_close → etcp_connection_close → connect_cancel → type=0 -2. **Settle-таймаут** (`connect_settle_timeout_cb`): удаление неудачных линков/stcp → LATE → connect_cancel -3. **Штатное закрытие** (`utun_instance_destroy`): фаза 1 (detach) → фаза 2 (deferred: `etcp_connect_cancel_for_conn`) - -Готовность BGP проверяется для конкретной группы через `topo_group_peer_ready(group, peer_id)`. -Общий транспорт не имеет состояния завершения группового обмена. Для владения -соединениями используйте NCD; создание транспорта само по себе не вступает в группу.