diff --git a/src/routing_layer/conn_mgr.h b/src/routing_layer/conn_mgr.h index 787af9ac..89e3ff06 100644 --- a/src/routing_layer/conn_mgr.h +++ b/src/routing_layer/conn_mgr.h @@ -48,9 +48,10 @@ typedef void (*conn_mgr_cb_t)(struct CONN_MGR_HANDLE* h, /* ═══════ lifecycle ═══════ */ -/* Создать менеджер группы и его фоновые проверки; NULL при ошибке. */ +/* Создать менеджер группы с обоими фоновыми таймерами; NULL с очисткой ресурсов при ошибке. */ struct CONN_MGR* conn_mgr_init(struct TOPO_GROUP* group); -/* Остановить проверки и освободить менеджер. Все клиентские handles закрыть ДО destroy. */ +/* Остановить проверки и освободить менеджер вне его callbacks. + * Живые клиентские handles отсоединяются, callbacks отменяются; владельцы закрывают их сами. */ void conn_mgr_destroy(struct CONN_MGR* mgr); /* Приём управляющего пакета от etcp_router; забирает entry. */ void conn_mgr_router_recv_handler(struct ETCP_CONN* conn, struct ll_entry* entry); @@ -60,9 +61,14 @@ void conn_mgr_router_recv_handler(struct ETCP_CONN* conn, struct ll_entry* entry /** * Параллельные пробы: DIRECT сразу, REVERSE через 0/500мс, INDIRECT через 0/1000мс от общего старта. * Посредник используется сразу после проверки; поздний прямой путь заменяет его без повторного UP. - * Возврат 0 — запрос принят, -1 — ошибка запуска. cb обязателен. + * Возврат 0 — запрос принят, -1 — ошибка запуска. cb обязателен, cb_arg заимствован. + * Отсутствующая группа создаётся как CHAT с десятичным channel_id=group_id. + * При отсутствии узла загружает запись из общей SQLite во временный групповой узел; + * отказ запуска очищает приобретённые ссылки. Последний CM-владелец убирает такой + * узел, если у него не появились BGP-пути. * Ошибка до запуска может возвращаться без callback. В callback h может быть NULL. - * Успешно выданный handle закрывает вызывающий, в том числе после TIMEOUT. + * out_handle необязателен: иначе вызывающий получает handle из callback. + * При ошибке *out_handle=NULL. Успешный handle закрывает вызывающий, в том числе после TIMEOUT. */ int conn_mgr_open(struct UTUN_INSTANCE* inst, uint64_t group_id, @@ -73,7 +79,9 @@ int conn_mgr_open(struct UTUN_INSTANCE* inst, /** Закрыть свой handle и отменить его callbacks, в том числе отложенный UP. * Допустимо из callback (также закрытие другого handle). После close указатель больше не использовать. * Очистка внутренней записи CM отсоединяет handles, но владельцы всё равно обязаны вызвать close. - * Последний handle освобождает ресурсы CM; чужие NCD-владельцы сохраняют транспорт. */ + * Последний handle снимает запись CM; чужие NCD-владельцы сохраняют транспорт. + * Освобождение памяти закрытых объектов выполняют фоновые callbacks/destroy менеджера, + * без новых выделений памяти в close. После destroy отсоединённый handle допускает только close. */ void conn_mgr_close(struct CONN_MGR_HANDLE* h); /* ═══════ доступ к соединению ═══════ */ @@ -81,13 +89,13 @@ void conn_mgr_close(struct CONN_MGR_HANDLE* h); /** Заимствованный READY прямой ETCP_CONN; NULL для INDIRECT, ожидания или отсоединённого handle. */ struct ETCP_CONN* conn_mgr_get_conn(struct CONN_MGR_HANDLE* h); -/** Передать e->dgram через маршрутизатор CM. Освобождает entry при ненулевом h; - * буфер dgram отдельно не освобождает. При h==NULL entry остаётся у вызывающего. */ -int conn_mgr_send(struct CONN_MGR_HANDLE* h, struct ll_entry* e); +/* Данные сервиса отправляются через etcp_route_send/etcp_router_conn_send с его svc_id. + * CM handle всё это время сохраняет потребность в доставке; политика сервиса задаёт шифрование. */ /* ═══════ мониторинг (вызывается извне) ═══════ */ -/** Обновить RTT кандидата-посредника (≤3, сортировка по возрастанию). */ +/** Обновить кандидата (≤3, сортировка по RTT, затем node_id); self/0 и RTT=0/FFFF игнорируются. + * При заполнении списка READY-кандидаты вытесняют недоступных независимо от прежнего RTT. */ void conn_mgr_update_best_candidates(struct CONN_MGR* mgr, uint64_t node_id, uint16_t rtt); /** Запланировать перепроверку путей после изменения маршрутов или READY групповых сессий. */ diff --git a/src/routing_layer/conn_mgr_core.c b/src/routing_layer/conn_mgr_core.c index 4909a8fd..f19df4de 100644 --- a/src/routing_layer/conn_mgr_core.c +++ b/src/routing_layer/conn_mgr_core.c @@ -642,16 +642,6 @@ struct ETCP_CONN* conn_mgr_get_conn(struct CONN_MGR_HANDLE* h) { return cm_direct_conn(h->entry->mgr, h->entry->node_id); } -int conn_mgr_send(struct CONN_MGR_HANDLE* h, struct ll_entry* e) { - if (!h || !e) return -1; - struct CONN_MGR_ENTRY* entry = h->entry; - if (!entry || entry->state != CONN_MGR_STATE_CONNECTED) { queue_entry_free(e); return -1; } - entry->last_traffic_tb = get_time_tb(); - struct ETCP_ROUTER_CONN* r = etcp_router_conn_get(entry->mgr->instance, entry->mgr->group->group_id, entry->node_id, ETCP_RT_ID_CONN_MGR); - if (!r) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "conn_mgr: no route to 0x%016llx, dropping %u bytes", (unsigned long long)entry->node_id, (unsigned)e->len); queue_entry_free(e); return -1; } - int ret = etcp_router_conn_send(r, e->dgram, e->len, 0); queue_entry_free(e); return ret; -} - /* Локальные пробы уже созданы DIRECT через NCD. Проверяем все LAN-адреса, * не дублируя handshake и не создавая отдельные ping-контексты. */ void cm_start_local_scan(struct CONN_MGR_ENTRY* entry) { @@ -702,6 +692,7 @@ void cm_start_phase_reverse(struct CONN_MGR_ENTRY* entry) { uint64_t now = get_time_tb(); if (!entry->reverse_started) { entry->reverse_started = 1; entry->reverse_request_id = ++entry->mgr->next_request_id; + if (!entry->reverse_request_id) entry->reverse_request_id = ++entry->mgr->next_request_id; entry->reverse_deadline_tb = now + CONN_MGR_CONNECT_REVERSE_TIMEOUT_MS * 10; DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: REVERSE start peer=%016llx elapsed=%llums", (unsigned long long)entry->node_id, (unsigned long long)((now - entry->start_tb) / 10)); @@ -718,6 +709,10 @@ void cm_handle_direct_req(uint64_t src, struct CONN_MGR* mgr, const uint8_t* dat return; } struct CM_DIRECT_REQ req; memcpy(&req, data, sizeof(req)); + if (!req.request_id || !src || src == mgr->instance->node_id) { + DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "conn_mgr: invalid DIRECT_REQ peer=%016llx request=%u", + (unsigned long long)src, req.request_id); return; + } struct TOPO_NODE* ni = topo_node_registry_find(mgr->instance->topo_groups, src); if (!ni) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "conn_mgr: REVERSE unknown peer=%016llx", (unsigned long long)src); return; } struct CONN_MGR_ENTRY* entry = cm_ensure_entry(mgr, src); @@ -738,12 +733,6 @@ void cm_handle_direct_req(uint64_t src, struct CONN_MGR* mgr, const uint8_t* dat /* ═══════ disconnect / recv ═══════ */ -void cm_handle_disconnect(struct CONN_MGR* mgr, uint64_t node_id) { - struct CONN_MGR_ENTRY* entry = cm_find_entry(mgr, node_id); if (!entry) return; - cm_clear_nodeinfo(mgr, node_id); cm_entry_cleanup(entry); - DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: remote disconnect from 0x%016llx", (unsigned long long)node_id); -} - void conn_mgr_router_recv_handler(struct ETCP_CONN* conn, struct ll_entry* entry) { if (!entry || !entry->dgram || entry->len < ROUTER_SVC_PAYLOAD_OFF + 2) { if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } @@ -770,7 +759,6 @@ void conn_mgr_router_recv_handler(struct ETCP_CONN* conn, struct ll_entry* entry if (mgr) { struct CONN_MGR_ENTRY* e = cm_find_entry(mgr, src); if (e && e->state == CONN_MGR_STATE_CONNECTED) e->last_traffic_tb = get_time_tb(); } switch (sub) { case CM_SUBCMD_DIRECT_REQ: cm_handle_direct_req(src, mgr, d, len); break; - case CM_SUBCMD_DIRECT_RESP: break; case CM_SUBCMD_INTERM_EXCHANGE_REQ: if (len == CM_EXCHANGE_REQ_SIZE) cm_handle_interm_exchange_req(src, mgr, (struct CM_EXCHANGE_REQ*)d); else DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "conn_mgr: malformed EXCHANGE_REQ peer=%016llx len=%zu", (unsigned long long)src, len); @@ -778,10 +766,6 @@ void conn_mgr_router_recv_handler(struct ETCP_CONN* conn, struct ll_entry* entry case CM_SUBCMD_INTERM_EXCHANGE_RESP: if (mgr) cm_handle_interm_exchange_resp(mgr, src, d, len); break; case CM_SUBCMD_INTERM_SELECTED: if (mgr) cm_handle_interm_selected(mgr, src, d, len); break; case CM_SUBCMD_INTERM_ACK: if (mgr) cm_handle_interm_ack(mgr, src, d, len); break; - case CM_SUBCMD_DISCONNECT: - if (len == CM_DISCONNECT_SIZE && ((struct CM_DISCONNECT*)d)->node_id == src) cm_handle_disconnect(mgr, src); - else DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "conn_mgr: malformed DISCONNECT peer=%016llx len=%zu", (unsigned long long)src, len); - break; default: DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "conn_mgr: unknown command=%u peer=%016llx", sub, (unsigned long long)src); break; } queue_dgram_free(entry); queue_entry_free(entry); diff --git a/src/routing_layer/conn_mgr_priv.h b/src/routing_layer/conn_mgr_priv.h index 63b0a2a7..75c64dfe 100644 --- a/src/routing_layer/conn_mgr_priv.h +++ b/src/routing_layer/conn_mgr_priv.h @@ -61,11 +61,9 @@ enum CM_TRY_STATE { enum { CM_SUBCMD_DIRECT_REQ = 0x01, - CM_SUBCMD_DIRECT_RESP = 0x02, CM_SUBCMD_INTERM_EXCHANGE_REQ = 0x03, CM_SUBCMD_INTERM_EXCHANGE_RESP= 0x04, CM_SUBCMD_INTERM_SELECTED = 0x05, - CM_SUBCMD_DISCONNECT = 0x06, CM_SUBCMD_INTERM_ACK = 0x07, }; @@ -73,19 +71,15 @@ struct CONN_MGR_CANDIDATE { uint64_t node_id; uint16_t rtt; } __attribute__((pac #pragma pack(push, 1) struct CM_DIRECT_REQ { uint8_t cmd, subcmd; uint32_t request_id; }; -struct CM_DIRECT_RESP { uint8_t cmd, subcmd; uint32_t request_id; uint8_t accepted; }; struct CM_EXCHANGE_REQ { uint8_t cmd, subcmd; uint32_t request_id; uint8_t candidate_count; struct CONN_MGR_CANDIDATE candidates[CONN_MGR_MAX_CANDIDATES]; }; struct CM_EXCHANGE_RESP { uint8_t cmd, subcmd; uint32_t request_id; uint8_t my_count, your_count; struct CONN_MGR_CANDIDATE my_candidates[CONN_MGR_MAX_CANDIDATES], your_candidates[CONN_MGR_MAX_CANDIDATES]; }; struct CM_INTERM_SEL { uint8_t cmd, subcmd; uint32_t request_id; uint8_t count; struct CONN_MGR_CANDIDATE selected[3]; }; -struct CM_DISCONNECT { uint8_t cmd, subcmd; uint64_t node_id; }; #pragma pack(pop) #define CM_DIRECT_REQ_H_SIZE (sizeof(struct CM_DIRECT_REQ)) -#define CM_DIRECT_RESP_HDR_SIZE (sizeof(struct CM_DIRECT_RESP)) #define CM_EXCHANGE_REQ_SIZE (sizeof(struct CM_EXCHANGE_REQ)) #define CM_EXCHANGE_RESP_SIZE (sizeof(struct CM_EXCHANGE_RESP)) #define CM_INTERM_SEL_SIZE (sizeof(struct CM_INTERM_SEL)) -#define CM_DISCONNECT_SIZE (sizeof(struct CM_DISCONNECT)) /* ═══════ внутренние структуры ═══════ */ @@ -154,7 +148,6 @@ void cm_start_phase_reverse(struct CONN_MGR_ENTRY* entry); void cm_start_phase_indirect(struct CONN_MGR_ENTRY* entry); void cm_start_local_scan(struct CONN_MGR_ENTRY* entry); void cm_handle_direct_req(uint64_t src, struct CONN_MGR* mgr, const uint8_t* data, size_t len); -void cm_handle_disconnect(struct CONN_MGR* mgr, uint64_t node_id); void cm_finalize_indirect(struct CONN_MGR_ENTRY* entry); void cm_refresh_path(struct CONN_MGR_ENTRY* entry); void cm_arm_timer(struct CONN_MGR_ENTRY* entry);