docs: clarify core, group and chat header contracts
This commit is contained in:
1 parent
72fee9e245
commit
01fcefdec5
19 files changed
+396
-414
No files matched your search
@@ -1,3 +1,8 @@
|
||||
/* conn_mgr — соединение с узлом группы напрямую, в обратную сторону или через посредника.
|
||||
* Один менеджер принадлежит одной группе; open выдаёт отдельный handle владельцу.
|
||||
* DIRECT использует NCD, REVERSE просит пира подключиться, INDIRECT выбирает посредника.
|
||||
* Используется сервисами для доставки данных. Групповые сессии открывают через
|
||||
* topo_group_peer_open(). Все операции — в потоке uasync; handle закрывает вызывающий. */
|
||||
#ifndef CONN_MGR_H
|
||||
#define CONN_MGR_H
|
||||
|
||||
@@ -15,44 +20,9 @@ struct UTUN_INSTANCE;
|
||||
struct ETCP_CONN;
|
||||
struct TOPO_GROUP;
|
||||
|
||||
/**
|
||||
* @file conn_mgr.h
|
||||
* @brief Подключение к узлам P2P-сети. Handle-based API.
|
||||
*
|
||||
* Подключает к удалегному узлу либо напрямую, либо через посредника с прямыми адресами.
|
||||
* При открытии выдаёт handle. и держит подключение открытым пока не закроешь handle.
|
||||
* Отправлять можно обычным send через роутер - он сам разберётся как отправить,
|
||||
* либо send этого моделя - он точно отправит через этот мост.
|
||||
*
|
||||
* Один CONN_MGR = одна TOPO_GROUP. Создаётся conn_mgr_init(group), живёт пока
|
||||
* существует группа. Внутри: кеш entries (по одной на целевой узел), список
|
||||
* handle'ов (по одному на каждый вызов open), фоновые ping/idle/мониторинг.
|
||||
*
|
||||
* === Единая точка входа: conn_mgr_open ===
|
||||
*
|
||||
* 3-фазное подключение (DIRECT→REVERSE→INDIRECT).
|
||||
* Коллбэк: CONN_EVENT_UP (успех) или CONN_EVENT_TIMEOUT (провал).
|
||||
*
|
||||
* === 3 фазы ===
|
||||
*
|
||||
* 1. DIRECT: node_conn_direct на все адреса, NAT-фильтрация, LAN broadcast ping.
|
||||
* 2. REVERSE: у нас прямой IP — шлём DIRECT_REQ цели через BGP.
|
||||
* 3. INDIRECT: через посредника с минимальной суммой RTT (etcp_router).
|
||||
*
|
||||
* === Фоновые процессы ===
|
||||
*
|
||||
* bg_ping: раз в ~100ms один узел группы за тик. Поддерживает свежие RTT.
|
||||
* candidate_ping: раз в ~2с, удаляет протухших кандидатов.
|
||||
*
|
||||
* === Refcounting и закрытие ===
|
||||
*
|
||||
* Несколько handle на один ETCP_CONN. conn_mgr_close удаляет ОДИН handle.
|
||||
* Последний handle: DIRECT/REVERSE — DISCONNECT + NCD CLOSE.
|
||||
*/
|
||||
|
||||
enum conn_mgr_event {
|
||||
CONN_EVENT_UP = 0, /* связь есть. handle жив, можно отправлять данные */
|
||||
CONN_EVENT_DOWN = 1, /* временный обрыв. handle жив, само восстановится. НЕ закрывать */
|
||||
CONN_EVENT_DOWN = 1, /* связь потеряна; handle остаётся у владельца, успех восстановления не гарантирован */
|
||||
CONN_EVENT_TIMEOUT = 2, /* подключение не удалось. handle жив, закройте сами */
|
||||
};
|
||||
|
||||
@@ -69,19 +39,20 @@ typedef void (*conn_mgr_cb_t)(struct CONN_MGR_HANDLE* h,
|
||||
|
||||
/* ═══════ lifecycle ═══════ */
|
||||
|
||||
/* Создать менеджер группы и его фоновые проверки; NULL при ошибке. */
|
||||
struct CONN_MGR* conn_mgr_init(struct TOPO_GROUP* group);
|
||||
/* Остановить проверки и освободить менеджер. Все клиентские handles закрыть ДО destroy. */
|
||||
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);
|
||||
|
||||
/* ═══════ единая точка входа ═══════ */
|
||||
|
||||
/**
|
||||
* Единственная публичная функция подключения — 3-фазное (DIRECT→REVERSE→INDIRECT).
|
||||
* Используется медиа-доставкой. Пиры/группы подключаются через node_conn_direct,
|
||||
* invite — через topo_group_invite.
|
||||
*
|
||||
* Ошибка/таймаут: CONN_EVENT_TIMEOUT.
|
||||
* node_id и group_id ВСЕГДА валидны в коллбэке (даже при TIMEOUT).
|
||||
* Возврат 0 — запрос принят, -1 — ошибка запуска. cb обязателен.
|
||||
* Ошибка до запуска может возвращаться без callback. В callback h может быть NULL.
|
||||
* Успешно выданный handle закрывает вызывающий, в том числе после TIMEOUT.
|
||||
*/
|
||||
int conn_mgr_open(struct UTUN_INSTANCE* inst,
|
||||
uint64_t group_id,
|
||||
@@ -89,15 +60,16 @@ int conn_mgr_open(struct UTUN_INSTANCE* inst,
|
||||
conn_mgr_cb_t cb, void* cb_arg,
|
||||
struct CONN_MGR_HANDLE** out_handle);
|
||||
|
||||
/** Закрыть handle. Последний handle рвёт соединение. */
|
||||
/** Закрыть свой handle. Последний освобождает ресурсы CM; чужие NCD-владельцы сохраняют транспорт. */
|
||||
void conn_mgr_close(struct CONN_MGR_HANDLE* h);
|
||||
|
||||
/* ═══════ доступ к соединению ═══════ */
|
||||
|
||||
/** ETCP_CONN для DIRECT/REVERSE, NULL для INDIRECT. */
|
||||
/** Заимствованный ETCP_CONN от NCD, если он есть; NULL для INDIRECT или отсоединённого handle. */
|
||||
struct ETCP_CONN* conn_mgr_get_conn(struct CONN_MGR_HANDLE* h);
|
||||
|
||||
/** Отправить данные (для INDIRECT — через посредников). Забирает владение e. */
|
||||
/** Передать e->dgram через маршрутизатор CM. Освобождает entry при ненулевом h;
|
||||
* буфер dgram отдельно не освобождает. При h==NULL entry остаётся у вызывающего. */
|
||||
int conn_mgr_send(struct CONN_MGR_HANDLE* h, struct ll_entry* e);
|
||||
|
||||
/* ═══════ мониторинг (вызывается извне) ═══════ */
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
// Маршрутизирует сервисные пакеты до целевой ноды, на промежуточных нодах ретранслирует
|
||||
// Упрощённый TCP поверх ETCP: восстановление порядка, дедупликация, ретрансмиты, inflight-контроль.
|
||||
// Подпись/шифрование вынесены в автономный модуль route_crypto (encode/decode).
|
||||
// Логический канал задаётся (group_id, node_id, svc_id), физический транспорт берётся у топологии.
|
||||
// Сервисы регистрируют приём через bind, отправляют через route_send и соблюдают backpressure.
|
||||
// Все операции и callbacks — в потоке uasync. Закрытие группы удаляет её каналы и ожидающий транзит.
|
||||
//
|
||||
// Формат SVC_ROUTE пакета:
|
||||
// [cmd:1] [group_id:8] [dst_node_id:8] [src_node_id:8] [seq:4] [svc_id:1] [flags:1] [timestamp:2] [reset_id:8]
|
||||
@@ -77,8 +80,8 @@ struct TRANSIT_QUEUE {
|
||||
uint64_t group_id; // = data[0..7]
|
||||
uint64_t src_node_id; // = data[8..15]
|
||||
uint64_t dst_node_id; // = data[16..23]
|
||||
struct ll_queue* q; // FIFO транзитных пакетов (ll_entry с dgram), начиная с data[16]
|
||||
struct queue_waiter_handle waiter; // backpressure waiter на bp-очередь (normalizer->input или tx_queue)
|
||||
struct ll_queue* q; // FIFO ещё не переданных транспорту пакетов
|
||||
struct queue_waiter_handle waiter; // ожидание свободной conn->send_input_q
|
||||
struct ETCP_CONN* conn; // next_hop (для etcp_send в drain_cb)
|
||||
};
|
||||
|
||||
@@ -133,9 +136,9 @@ struct ETCP_ROUTER_CONN {
|
||||
uint64_t reset_id; // собственный идентификатор; не меняется при рестарте пира
|
||||
uint64_t peer_reset_id; // подтверждённый идентификатор пира (0 = handshake не завершён)
|
||||
uint64_t pending_peer_id; // кандидат, ещё не имеющий права менять состояние сессии
|
||||
uint64_t pending_challenge;
|
||||
uint64_t challenge_sent_tb;
|
||||
void* handshake_timer;
|
||||
uint64_t pending_challenge; // случайный запрос подтверждения кандидату
|
||||
uint64_t challenge_sent_tb; // время отправки запроса, 0.1 ms
|
||||
void* handshake_timer; // таймер повторов согласования
|
||||
uint8_t start_sent; // получен первый ACK данных
|
||||
uint8_t peer_sync_done; // 1 = завершено подтверждение peer ID
|
||||
|
||||
@@ -203,41 +206,48 @@ struct ETCP_ROUTER_BINDINGS {
|
||||
// Инициализация: etcp_bind(ETCP_ID_SVC_ROUTE) + очистка bindings + создание router_conns
|
||||
int etcp_router_init(struct UTUN_INSTANCE* inst);
|
||||
|
||||
// Деинициализация
|
||||
// Закрыть каналы, снять обработчик и освободить маршрутизатор.
|
||||
void etcp_router_destroy(struct UTUN_INSTANCE* inst);
|
||||
|
||||
// Зарегистрировать обработчик сервиса
|
||||
int etcp_router_bind(struct UTUN_INSTANCE* inst, uint8_t svc_id, etcp_recv_fn callback);
|
||||
// Снять обработчик; само по себе не закрывает логические каналы сервиса.
|
||||
int etcp_router_unbind(struct UTUN_INSTANCE* inst, uint8_t svc_id);
|
||||
|
||||
// Отправить сервисный пакет (авто-conn, seq, inflight-контроль через send_q).
|
||||
// Принимает владение entry во всех исходах, включая ошибку.
|
||||
// entry->dgram = svc_id[1] || payload; 0=принято в очередь, <0=ошибка, не подтверждение доставки.
|
||||
// force разрешает превысить лимит числа пакетов в send_q.
|
||||
// mode — битовая маска ROUTE_CRYPTO_SIGN / ROUTE_CRYPTO_ENCRYPT (см. route_crypto.h), 0 = обычный пакет.
|
||||
int etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst_node_id, struct ll_entry* entry, int force, int mode);
|
||||
|
||||
// Найти/создать состояние seq-подключения по (group_id, remote_node_id, svc_id)
|
||||
// Найти/создать логический канал. Указатель заимствован до close/destroy, NULL при ошибке.
|
||||
struct ETCP_ROUTER_CONN* etcp_router_conn_get(struct UTUN_INSTANCE* inst,
|
||||
uint64_t group_id, uint64_t remote_node_id, uint8_t svc_id);
|
||||
|
||||
// Есть ли сейчас физический маршрут до узла (прямой, indirect-посредник или глобальный).
|
||||
// 1 = есть ETCP-соединение для отправки, 0 = нет (передача встанет в no_route).
|
||||
// 1 = найден транспорт (для self всегда 1); это не гарантия UP/готовности логического канала.
|
||||
int etcp_router_has_route(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst_node_id);
|
||||
|
||||
// Отправить данные с авто-seq и контролем inflight
|
||||
// data: payload без svc_id, mode: ROUTE_CRYPTO_SIGN / ROUTE_CRYPTO_ENCRYPT (0 = обычный)
|
||||
// Копирует data; 0=принято в очередь, <0=ошибка. Доставка подтверждается отдельно протоколом.
|
||||
int etcp_router_conn_send(struct ETCP_ROUTER_CONN* rconn,
|
||||
const uint8_t* data, size_t len, int mode);
|
||||
|
||||
// Закрыть seq-подключение
|
||||
// Закрыть канал и уведомить сервис. После вызова rconn использовать нельзя.
|
||||
void etcp_router_conn_close(struct ETCP_ROUTER_CONN* rconn);
|
||||
|
||||
// Установить рабочий max_inflight, пересчитывает inflight_limit и state machine
|
||||
void etcp_router_set_max_inflight(struct ETCP_ROUTER_CONN* rconn, uint16_t new_max);
|
||||
|
||||
// Backpressure: зарегистрировать/отменить waiter на send_q очереди
|
||||
// Дождаться порога send_q. h должен быть обнулён и жить до callback/отмены.
|
||||
// Callback может выполниться внутри вызова. Повторная регистрация отменяет прежнюю.
|
||||
// Если канала нет, ожидание не регистрируется. Перед освобождением arg отменить waiter.
|
||||
void etcp_router_on_send_ready(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t node_id, uint8_t svc_id,
|
||||
struct queue_waiter_handle* h,
|
||||
queue_threshold_callback_fn callback, void* arg);
|
||||
// Отмена относится к исходной очереди, даже если логический канал уже перезапущен.
|
||||
void etcp_router_cancel_send_ready(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t node_id, uint8_t svc_id,
|
||||
struct queue_waiter_handle* h);
|
||||
|
||||
@@ -252,8 +262,9 @@ int etcp_router_send_q_has_room(struct UTUN_INSTANCE* inst, uint64_t group_id, u
|
||||
// Используется при etcp_conn_reinit чтобы избежать гонки с очисткой ETCP-очередей
|
||||
void etcp_router_pause_retrans_for_node(struct UTUN_INSTANCE* inst, uint64_t remote_node_id);
|
||||
|
||||
// Закрыть все router_conn для указанного (group_id, remote_node_id) (peer умер)
|
||||
// Закрыть все каналы и ожидающий транзит группы. Сначала сервисы отменяют свои producers/waiters.
|
||||
void etcp_router_close_group(struct UTUN_INSTANCE* inst, uint64_t group_id);
|
||||
// Закрыть логические каналы одного пира в группе.
|
||||
void etcp_router_conn_close_all_for_node(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t remote_node_id);
|
||||
|
||||
// Начать новую локальную сессию для конкретного peer+svc в группе и уведомить сервис.
|
||||
|
||||
@@ -1,32 +1,13 @@
|
||||
/**
|
||||
* @file topo_group.h
|
||||
* @brief BGP-подобный обмен топологией узлов между пирами через ETCP.
|
||||
* @brief Групповые сессии и обмен маршрутами поверх общего транспорта NCD.
|
||||
*
|
||||
* Идея: модуль автоматически выстраивает карту маршрутизации между узлами,
|
||||
* используя только пассивное наблюдение (подписка на события)
|
||||
* Можно иметь много групп узлов. Группа - это список узлов.
|
||||
* Для каждой группы выстраивается своя независимая таблица маршрутизации.
|
||||
* Один узел может входить в любое число групп.
|
||||
|
||||
* Механика:
|
||||
* - Узлы обмениваются информацией друг о друге (pubkey, адреса, подсети)
|
||||
* через NODEINFO/WITHDRAW сообщения, маршрутизируемые по ETCP.
|
||||
* - Каждый узел хранит полную таблицу известных узлов (структура TOPO_NODEQ).
|
||||
* - При подключении нового пира — полная синхронизация таблицы.
|
||||
* - При отключении пира — withdraw всех узлов, достижимых только через него.
|
||||
*
|
||||
* Группы (TOPO_GROUP):
|
||||
* - TOPO_GROUP_TYPE_UTUN — основная VPN-сеть (обмен маршрутами, подсетями)
|
||||
* - TOPO_GROUP_TYPE_CHAT — чат-группа (только узлы, без подсетей)
|
||||
* - Каждая группа изолирована: узлы из utun-группы не видны в чат-группе и наоборот
|
||||
*
|
||||
* Дополнительные функции:
|
||||
* - NAT-детекция: выделена в отдельный модуль nat_detection.h
|
||||
* - Поиск оптимального маршрута до узла (topo_group_find_conn_for_node)
|
||||
*
|
||||
* Хранение: все узлы сохраняются в SQLite (таблицы nodes, node_addresses,
|
||||
* channels, peers_<channel_id>). База открывается в topo_groups_init()
|
||||
* если в конфиге задан db_path.
|
||||
* У каждой группы своя топология; идентичности и адреса узлов общие (topo_node.h).
|
||||
* UTUN обменивается также подсетями, CHAT допускает только локально известных участников.
|
||||
* Для подключения используйте peer_open/close: группа владеет NCD с начала попытки.
|
||||
* JOIN/ACCEPT согласует сессию, NODEINFO/WITHDRAW поддерживают её маршруты.
|
||||
* Потерю путей обрабатывает topo_recovery, выбор CHAT-пиров — topo_group_connect.
|
||||
* Все операции — в потоке uasync. Сервисы создают и удаляют свои группы явно.
|
||||
*/
|
||||
#ifndef TOPO_GROUP_H
|
||||
#define TOPO_GROUP_H
|
||||
@@ -170,19 +151,19 @@ struct TOPOMSG_ERR_GROUP_MISMATCH {
|
||||
} __attribute__((packed));
|
||||
|
||||
struct TOPO_GROUP_CONN_ITEM {
|
||||
struct TOPO_GROUP* group;
|
||||
uint64_t node_id;
|
||||
struct TOPO_GROUP* group; // владелец сессии
|
||||
uint64_t node_id; // идентичность пира, включая CONNECTING
|
||||
struct ETCP_CONN* conn; // NULL до UP, в состоянии CONNECTING
|
||||
struct NODE_CONN_DIRECT* handle; // владение BGP этим conn (NCD-handle)
|
||||
struct TOPO_PEER_REQUEST* requests;
|
||||
struct TOPO_PEER_REQUEST* requests; // запросы инициаторов; каждый закрывает свой
|
||||
uint64_t progress; // время последнего прогресса обмена (timebase)
|
||||
uint8_t retained; // участие запрошено постоянным владельцем или достигло READY
|
||||
uint64_t local_epoch, peer_epoch; // поколения сторон текущего присоединения
|
||||
uint8_t accepted; // JOIN_ACCEPT подтвердил local_epoch
|
||||
uint8_t tx_failed, transport_down;
|
||||
struct topo_tx_item *tx_head, *tx_tail;
|
||||
struct queue_waiter_handle tx_waiter;
|
||||
void* tx_wake;
|
||||
uint8_t tx_failed, transport_down; // ошибка отправки / потеря транспорта
|
||||
struct topo_tx_item *tx_head, *tx_tail; // FIFO команд, ещё не переданных транспорту
|
||||
struct queue_waiter_handle tx_waiter; // ожидание свободной send_input_q
|
||||
void* tx_wake; // отложенный запуск отправки
|
||||
uint8_t table_received; // TABLE_COMPLETE текущей сессии принят
|
||||
uint8_t table_sent; // ответ на запрос пира целиком передан транспорту
|
||||
};
|
||||
@@ -206,7 +187,7 @@ struct TOPO_GROUP {
|
||||
struct ll_queue* senders_list; // ll_entry.data = TOPO_GROUP_CONN_ITEM; включает CONNECTING с conn=NULL
|
||||
struct ll_queue* nodes; // TOPO_GROUP_NODE{ll_entry,node_id,paths,...} — per-group узлы, хеш-индекс по node_id(8B)
|
||||
struct TOPO_GROUP_NODE* local_node; // свой узел в этой группе
|
||||
uint8_t ed25519_public_key[SC_PUBKEY_SIZE];
|
||||
uint8_t ed25519_public_key[SC_PUBKEY_SIZE]; // публичный ключ локального узла
|
||||
char channel_id[64]; // channel_id для групп типа CHAT
|
||||
struct CONN_MGR* conn_mgr; // менеджер соединений для этой группы
|
||||
struct TOPO_RECOVERY_CTX* recovery; // один последовательный recovery на группу
|
||||
@@ -215,7 +196,7 @@ struct TOPO_GROUP {
|
||||
struct radio_ctx* radio; // radio (PTT walkie-talkie) per-group context
|
||||
uint8_t radio_active; // 1 = я слушаю рацию этого канала (TOPO_FLAG_RADIO в NODEINFO)
|
||||
struct topo_node_cbk_entry* node_cbks; // цепочка подписчиков на события узлов
|
||||
uint8_t stopping;
|
||||
uint8_t stopping; // teardown начат; новые попытки запрещены
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -235,7 +216,8 @@ struct TOPO_GROUPS {
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Создаёт контейнер групп и группу utun по умолчанию (group_id=1).
|
||||
* @brief Создаёт реестр и локальную идентичность; сервисных групп пока нет.
|
||||
* Открывает общую SQLite: db_path/chats.db, без db_path — :memory:.
|
||||
*
|
||||
* @param instance экземпляр utun с node_id и конфигом
|
||||
* @return TOPO_GROUPS или NULL при ошибке
|
||||
@@ -257,12 +239,12 @@ void topo_group_on_activity_change(struct UTUN_INSTANCE* instance, int active, v
|
||||
void topo_groups_destroy(struct UTUN_INSTANCE* instance);
|
||||
|
||||
/**
|
||||
* @brief Возвращает группу по умолчанию (group_id=TOPO_GROUP_UTUN=0x8000000000000000).
|
||||
* @brief Возвращает UTUN-группу или NULL, если сервис не запущен. Указатель заимствован.
|
||||
*/
|
||||
struct TOPO_GROUP* topo_groups_get_default(struct TOPO_GROUPS* g);
|
||||
|
||||
/**
|
||||
* @brief Находит группу по id.
|
||||
* @brief Заимствованный указатель на группу по id; NULL, если её нет.
|
||||
*/
|
||||
struct TOPO_GROUP* topo_groups_find(struct TOPO_GROUPS* g, uint64_t group_id);
|
||||
|
||||
@@ -287,9 +269,9 @@ struct TOPO_GROUP* topo_groups_create_group(struct TOPO_GROUPS* g, uint64_t grou
|
||||
void topo_groups_remove_group(struct TOPO_GROUPS* g, uint64_t group_id);
|
||||
|
||||
/**
|
||||
* @brief Добавляет conn в senders_list (если нет), отправляет запрос таблицы (nodeinfo).
|
||||
*
|
||||
* Вызывается при ETCP on_up.
|
||||
* @brief Присоединяет существующий транспорт к группе и начинает JOIN/ACCEPT.
|
||||
* Группа приобретает собственный NCD handle; повтор не сбрасывает сессию. 0/-1.
|
||||
* Для обычного инициатора используйте отменяемый topo_group_peer_open().
|
||||
*/
|
||||
int topo_group_new_conn(struct TOPO_GROUP* group, struct ETCP_CONN* conn);
|
||||
|
||||
@@ -311,19 +293,20 @@ enum topo_peer_phase { TOPO_PEER_FAILED, TOPO_PEER_CONNECTING, TOPO_PEER_SYNCING
|
||||
* CLOSED/leave/удаление группы отсоединяет запрос окончательно.
|
||||
* Запрос остаётся валиден после удаления группы (phase=FAILED), caller обязан
|
||||
* закрыть его. Все операции выполняются в потоке единственного uasync.
|
||||
* progress — timebase последнего принятого NODEINFO/шага обмена, не polling time. */
|
||||
* progress — timebase последнего принятого NODEINFO/шага обмена, не polling time.
|
||||
* open: 0 = запрос создан в *out, -1 = ошибка. */
|
||||
int topo_group_peer_open(struct TOPO_GROUP* group, uint64_t node_id, struct TOPO_PEER_REQUEST** out);
|
||||
/* Освободить свой запрос; после вызова request недействителен. NULL допустим. */
|
||||
void topo_group_peer_close(struct TOPO_PEER_REQUEST* request);
|
||||
struct ETCP_CONN* topo_group_peer_conn(const struct TOPO_PEER_REQUEST* request); /* borrowed, including CONNECTING */
|
||||
/* Завершить всю сессию этой пары: LEAVE, удаление путей, отсоединение всех запросов. */
|
||||
void topo_group_peer_leave(struct TOPO_GROUP* group, uint64_t node_id);
|
||||
/* Текущая фаза; NULL или отсоединённый запрос дают FAILED. */
|
||||
enum topo_peer_phase topo_group_peer_phase(const struct TOPO_PEER_REQUEST* request);
|
||||
/* Время последнего прогресса в единицах 0.1 ms; 0, если сессии нет. */
|
||||
uint64_t topo_group_peer_progress(const struct TOPO_PEER_REQUEST* request);
|
||||
|
||||
/**
|
||||
* @brief Удаляет conn из senders_list, очищает paths во всех nodes, отправляет withdraw если node unreachable.
|
||||
*
|
||||
* Вызывается при ETCP on_down.
|
||||
*/
|
||||
/* Причина завершения групповой сессии определяет необходимость recovery. */
|
||||
enum topo_group_remove_reason {
|
||||
TOPO_REMOVE_TRANSPORT_DOWN,
|
||||
TOPO_REMOVE_LOCAL_LEAVE,
|
||||
@@ -331,25 +314,29 @@ enum topo_group_remove_reason {
|
||||
TOPO_REMOVE_MEMBER_INVALID,
|
||||
TOPO_REMOVE_REJECTED
|
||||
};
|
||||
/* Только потеря транспорта запускает recovery каскадно потерянных маршрутов. */
|
||||
/* Сбросить сессию и удалить пути через conn, разослать WITHDRAW для потерянных узлов.
|
||||
* При DOWN живые запросы сохраняют NCD для повторного UP. Только потеря транспорта
|
||||
* запускает recovery каскадно потерянных маршрутов. */
|
||||
void topo_group_remove_conn(struct TOPO_GROUP* group, struct ETCP_CONN* conn, enum topo_group_remove_reason reason);
|
||||
|
||||
/**
|
||||
* @brief Обрабатывает пакет NODEINFO.
|
||||
*
|
||||
* Проверка версии, обновление или создание TOPO_NODEQ, добавление пути,
|
||||
* Проверка подписи и timestamp, обновление TOPO_GROUP_NODE, добавление пути,
|
||||
* вставка в роутинг, broadcast если не max hops.
|
||||
*
|
||||
* @return 0 при успехе
|
||||
*/
|
||||
int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from, const uint8_t* data, size_t len);
|
||||
/* Присоединить UP-транспорт; переданный handle остаётся у вызывающего. 0/-1. */
|
||||
int topo_group_join_peer(struct TOPO_GROUP* group, struct NODE_CONN_DIRECT* handle);
|
||||
/* Отсоединить пира и запланировать LEAVE. Чужой handle не забирает. 0/-1. */
|
||||
int topo_group_leave_peer(struct TOPO_GROUP* group, struct NODE_CONN_DIRECT* handle);
|
||||
|
||||
/**
|
||||
* @brief Обрабатывает WITHDRAW.
|
||||
*
|
||||
* Удаляет node из роутинга и nodes, broadcast withdraw.
|
||||
* Удаляет затронутые пути; узел удаляется только без оставшихся путей.
|
||||
*
|
||||
* @return 0 при успехе
|
||||
*/
|
||||
@@ -369,11 +356,12 @@ void topo_group_send_withdraw(struct TOPO_GROUP* group, uint64_t node_id);
|
||||
/**
|
||||
* @brief Поиск оптимального ETCP соединения для указанного node_id.
|
||||
*
|
||||
* Перебирает paths узла, выбирает путь с минимальным hop_count.
|
||||
* Выбирает минимум hop_count среди живых путей. Если живых нет, возвращает
|
||||
* лучший сохранённый путь: ненулевой результат сам по себе не гарантирует UP.
|
||||
*
|
||||
* @param group указатель на TOPO_GROUP
|
||||
* @param node_id целевой узел
|
||||
* @return оптимальный ETCP_CONN* или NULL
|
||||
* @return заимствованный ETCP_CONN* или NULL
|
||||
*/
|
||||
struct ETCP_CONN* topo_group_find_conn_for_node(struct TOPO_GROUP* group, uint64_t node_id);
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
/* CHAT connection policy over cancellable group requests.
|
||||
* Phase 1: historical connected peers in parallel (up to 128).
|
||||
* Phase 2: sequential supernode/public peers. Phase 3: local peers.
|
||||
* Each node is tried once per cycle. CONNECTING: 2s; SYNCING: 5s without progress.
|
||||
* Goal: one READY supernode or three READY nonmobile peers. After exhaustion,
|
||||
* retry after 1s (or standby burst). Existing READY group sessions survive
|
||||
* planner restart/stop. Manual attempts are tracked and cancelled with the group.
|
||||
* active_count is derived from the current group sessions, not a separate counter.
|
||||
/* topo_group_connect — выбор пиров и попытки подключения CHAT-группы.
|
||||
* Сначала ранее подключённые пиры (до 128 параллельно), затем по одному
|
||||
* суперузлы/публичные узлы, затем локальные. Цель — READY суперузел или три
|
||||
* READY немобильных пира. CONNECTING: 2 s; SYNCING: 5 s без прогресса.
|
||||
* После исчерпания кандидатов новый цикл через 1 s или следующий standby burst.
|
||||
* Планировщик владеет запросами, группа — NCD. Остановка отменяет попытки,
|
||||
* включая ручные, но сохраняет готовые сессии. Все вызовы — в потоке uasync.
|
||||
*/
|
||||
#ifndef TOPO_GROUP_CONNECT_H
|
||||
#define TOPO_GROUP_CONNECT_H
|
||||
@@ -15,15 +14,22 @@
|
||||
struct TOPO_GROUP;
|
||||
struct ETCP_CONN;
|
||||
|
||||
/* Запустить новый автоматический цикл вместо прежнего. 0/-1. */
|
||||
int topo_group_connect_init(struct TOPO_GROUP* group);
|
||||
/* Отменить запросы, таймеры и отложенные вызовы планировщика. */
|
||||
void topo_group_connect_destroy(struct TOPO_GROUP* group);
|
||||
/* Запланировать проверку изменившихся сессий. */
|
||||
void topo_group_connect_changed(struct TOPO_GROUP* group);
|
||||
/* Учесть появление пира; для READY записать connected в БД. */
|
||||
void topo_group_connect_on_up(struct TOPO_GROUP* group, struct ETCP_CONN* conn);
|
||||
/* Учесть потерю пира и продолжить подбор кандидатов. */
|
||||
void topo_group_connect_on_down(struct TOPO_GROUP* group, struct ETCP_CONN* conn);
|
||||
/* Число текущих READY-пиров группы. */
|
||||
int topo_group_connect_active_count(struct TOPO_GROUP* group);
|
||||
/* Перезапустить автоматический цикл, только если нет READY-пиров. */
|
||||
void topo_group_connect_restart(struct TOPO_GROUP* group);
|
||||
|
||||
/* One manual request; shares the group session, no NCD ownership handoff on UP. */
|
||||
/* Одна ручная попытка, общий запрос к сессии группы. 0=принято, -1=ошибка. */
|
||||
int topo_group_connect_node_once(struct TOPO_GROUP* group, uint64_t node_id);
|
||||
|
||||
#endif
|
||||
@@ -1,23 +1,11 @@
|
||||
/**
|
||||
* @file topo_group_invite.h
|
||||
* @brief Invite/join к каналу через прямое (ncd) подключение.
|
||||
* @brief Получение описания канала по прямому NCD-транспорту (INVITE_INFO).
|
||||
*
|
||||
* Модуль содержит всю логику работы с invite-ссылками: прямое подключение к
|
||||
* приглашающему узлу через node_conn_direct (ncd) и проверку членства
|
||||
* (INVITE_INFO_REQ/RESP) с бутстрапом криптографической идентичности канала.
|
||||
*
|
||||
* Поток джойнера (topo_group_invite_join):
|
||||
* 1. Создаёт/находит группу, сохраняет TOPO_NODE приглашающего.
|
||||
* 2. Открывает прямое соединение (ncd) и шлёт INVITE_INFO_REQ.
|
||||
* 3. Получает INVITE_INFO_RESP — проверяет ch_sig, сохраняет канал в БД,
|
||||
* поднимает инфраструктуру группы (chat_core_ensure_channel_ready).
|
||||
* 4. Доставляет TGI_EVENT_JOIN.
|
||||
*
|
||||
* Инвайтера сторона: tgi_handle_info_req отвечает на INVITE_INFO_REQ —
|
||||
* проверяет членство в БД и возвращает полную информацию о канале.
|
||||
*
|
||||
* conn_mgr при этом используется ТОЛЬКО для медиа — invite больше от него
|
||||
* не зависит.
|
||||
* Запрашивает и проверяет подписанные сведения канала, готовит локальную группу.
|
||||
* Успешный ответ не добавляет участника на других узлах и не означает READY группы.
|
||||
* Вход по пользовательской ссылке и добавление участника описаны в chat_sync.h/chat_join.h.
|
||||
* Все операции — в потоке uasync; временные запросы отменяются при остановке чата.
|
||||
*/
|
||||
#ifndef TOPO_GROUP_INVITE_H
|
||||
#define TOPO_GROUP_INVITE_H
|
||||
@@ -37,8 +25,8 @@ struct NODE_CONN_DIRECT;
|
||||
#define TGI_SUBCMD_INFO_RESP 0x02
|
||||
|
||||
/* события коллбэка джойнера */
|
||||
#define TGI_EVENT_JOIN 0
|
||||
#define TGI_EVENT_TIMEOUT 1
|
||||
#define TGI_EVENT_JOIN 0 /* описание канала принято, локальная инфраструктура готова */
|
||||
#define TGI_EVENT_TIMEOUT 1 /* попытка завершилась ошибкой или таймаутом */
|
||||
|
||||
typedef void (*tgi_cb_t)(uint64_t node_id, uint64_t group_id, int event, void* arg);
|
||||
|
||||
@@ -48,17 +36,18 @@ void topo_group_invite_init(struct UTUN_INSTANCE* inst);
|
||||
/**
|
||||
* Джойнер: прямое подключение (ncd) к приглашающему + проверка членства.
|
||||
* ni — TOPO_NODE приглашающего (pubkey + адреса), не владеем.
|
||||
* При успехе вызывается cb(TGI_EVENT_JOIN), при провале cb(TGI_EVENT_TIMEOUT).
|
||||
* 0 — попытка начата, -1 — ошибка. До создания попытки ошибка не вызывает cb;
|
||||
* после создания ошибки дают TGI_EVENT_TIMEOUT, иногда до возврата функции.
|
||||
* Успешный обмен даёт TGI_EVENT_JOIN; cancel_all завершает ожидание без cb.
|
||||
*/
|
||||
int topo_group_invite_join(struct UTUN_INSTANCE* inst, uint64_t group_id,
|
||||
struct TOPO_NODE* ni, uint64_t node_id,
|
||||
tgi_cb_t cb, void* cb_arg);
|
||||
|
||||
/**
|
||||
* Инвайтера сторона: прямое подключение (ncd) к целевому узлу для последующей
|
||||
* отправки CHANNEL_INVITE (через chat_sync, по ETCP_CONN_STATUS_UP).
|
||||
* Без INVITE_INFO-проверки членства. ni может быть NULL — тогда адреса грузятся
|
||||
* из БД. Группа владеет NCD; инициатор держит отменяемый групповой запрос.
|
||||
* Запустить групповую попытку к уже известному участнику, при необходимости
|
||||
* передав адреса ni (заимствованы; NULL — взять известные). 0/-1.
|
||||
* Применяется обычная проверка CHAT-членства. Сам CHANNEL_INVITE не отправляет.
|
||||
*/
|
||||
int topo_group_invite_to_channel(struct UTUN_INSTANCE* inst, uint64_t group_id,
|
||||
struct TOPO_NODE* ni, uint64_t node_id);
|
||||
|
||||
@@ -2,21 +2,11 @@
|
||||
* @file topo_node.h
|
||||
* @brief Модель данных узла сети — структуры, сериализация, wire-формат.
|
||||
*
|
||||
* Этот модуль определяет:
|
||||
* - Как узел представлен в памяти (TOPO_NODE, TOPO_GROUP_NODE, адреса, подсети)
|
||||
* - Как узел передаётся по сети (packed-структуры TOPOMSG_*)
|
||||
* - Как узел сериализуется/десериализуется (topo_node_serialize/deserialize)
|
||||
*
|
||||
* Хранение:
|
||||
* - Идентичность узла (pubkeys, адреса, имя) — в глобальном реестре TOPO_GROUPS->node_registry
|
||||
* Единственный экземпляр TOPO_NODE, разделяется между группами через group_ref_count.
|
||||
* - Per-group данные (node_id, paths, subnets, connectivity) — в TOPO_GROUP->nodes (очередь TOPO_GROUP_NODE)
|
||||
*
|
||||
* Основные понятия:
|
||||
* TOPO_NODE — глобальная идентичность узла. Встроен в node_registry как queue entry.
|
||||
* TOPO_GROUP_NODE — узел в контексте группы: node_id + paths, hop_list, связность
|
||||
* TOPO_NODEPATH — путь до узла через конкретное ETCP-соединение
|
||||
* TOPOMSG_NODE — wire-формат, передаваемый по NODEINFO
|
||||
* TOPO_NODE — общие ключи, имя и адреса; реестр хранит указатель с подсчётом ссылок.
|
||||
* Подписанная запись заменяется целиком при более свежем timestamp, вместе с подписью.
|
||||
* TOPO_GROUP_NODE — пути, подсети и состояние узла в конкретной группе.
|
||||
* TOPOMSG_NODE — сетевой формат. Модуль сериализует, подписывает и проверяет записи.
|
||||
* Работа с реестром и группами выполняется в потоке uasync экземпляра.
|
||||
*/
|
||||
#ifndef TOPO_NODE_H
|
||||
#define TOPO_NODE_H
|
||||
@@ -87,9 +77,11 @@ struct UTUN_INSTANCE;
|
||||
#define TOPO_GROUP_TYPE_UTUN 1
|
||||
#define TOPO_GROUP_TYPE_CHAT 2
|
||||
|
||||
/* Результаты проб адресов. *_time — timebase (0.1 ms), *_rtt — те же единицы;
|
||||
* *_status — PROBE_RESULT_*, probe_status — PROBE_STATUS_*. */
|
||||
struct TOPO_CONNECTIVITY {
|
||||
uint8_t probe_status;
|
||||
uint8_t pending_count;
|
||||
uint8_t pending_count; // незавершённые пробы
|
||||
uint64_t probe_start_time;
|
||||
uint16_t interface_min_rtt;
|
||||
uint16_t nat_min_rtt;
|
||||
@@ -103,7 +95,7 @@ struct TOPO_CONNECTIVITY {
|
||||
uint64_t real_probe_time;
|
||||
uint64_t ping_req_time;
|
||||
uint64_t last_ping_time;
|
||||
void* probe_list;
|
||||
void* probe_list; // принадлежащие узлу контексты текущих проб
|
||||
void* probe_deferred_wait; /* контекст отложенной пробы (standby_wait, Android) */
|
||||
};
|
||||
|
||||
@@ -171,17 +163,17 @@ struct TOPO_ADDR_REALITY_OPTS {
|
||||
struct _topo_head { struct _topo_head* next; };
|
||||
static inline int topo_list_count(struct _topo_head* head) { int n = 0; while (head) { n++; head = head->next; } return n; }
|
||||
|
||||
/** Глобальная идентичность узла. Встроен в TOPO_GROUPS->node_registry как queue entry. */
|
||||
/** Общая запись узла; node_registry хранит указатель на неё в отдельном ll_entry. */
|
||||
struct TOPO_NODE {
|
||||
struct ll_entry ll;
|
||||
uint32_t group_ref_count;
|
||||
uint32_t group_ref_count; // ссылки групп, ядра и временных пользователей
|
||||
uint64_t node_id; uint8_t ver;
|
||||
uint64_t timestamp; // 0 = неподписанные bootstrap-сведения
|
||||
uint8_t public_key[SC_PUBKEY_SIZE], ed25519_public_key[SC_PUBKEY_SIZE];
|
||||
uint8_t x25519_self_sig[64];
|
||||
uint8_t x25519_self_sig[64]; // Ed25519-подпись общей записи
|
||||
uint8_t client_type; // CLIENT_TYPE_SERVER/DESKTOP/MOBILE
|
||||
uint8_t client_activity; // CLIENT_ACTIVITY_STANDBY/ACTIVE
|
||||
char* node_name;
|
||||
char* node_name; // собственная строка; освобождается с записью
|
||||
struct TOPO_SOCKMETA4* v4_sock_meta;
|
||||
struct TOPO_ADDR4* v4_addrs;
|
||||
struct TOPO_SOCKMETA6* v6_sock_meta;
|
||||
@@ -196,9 +188,9 @@ struct TOPO_NODESUBNETS {
|
||||
|
||||
struct TOPO_NODEPATH {
|
||||
struct ll_entry ll;
|
||||
struct ETCP_CONN* conn;
|
||||
uint8_t hop_count;
|
||||
uint16_t cumulative_rtt;
|
||||
struct ETCP_CONN* conn; // заимствованный next-hop; транспорт удерживает сессия
|
||||
uint8_t hop_count; // число node_id в массиве сразу после структуры
|
||||
uint16_t cumulative_rtt; // RTT оставшейся цепочки, без локального линка (0.1 ms)
|
||||
};
|
||||
|
||||
/** Узел в контексте группы (per-group данные). Хранится в TOPO_GROUP->nodes (ll_queue). */
|
||||
@@ -213,52 +205,74 @@ struct TOPO_GROUP_NODE {
|
||||
uint64_t conn_mgr_intermediaries[CONN_MGR_MAX_INTERMEDIARIES]; // посредники для INDIRECT
|
||||
uint8_t conn_mgr_intermediariy_count; // количество посредников
|
||||
struct TOPO_CONNECTIVITY connectivity; // результаты ping-проб (interface/nat/real)
|
||||
uint8_t conn_presence; // NODE_CONN_* — какие подключения есть в принципе
|
||||
uint8_t conn_up; // NODE_CONN_* — какие из них подняты
|
||||
uint8_t conn_presence; // маска NCONN_*: известные виды подключения
|
||||
uint8_t conn_up; // маска NCONN_*: работающие виды подключения
|
||||
uint8_t radio; // 1 = узел слушает рацию канала (TOPO_FLAG_RADIO)
|
||||
struct NODE_CONN_DIRECT* handle; // активный ncd-handle прямого соединения к узлу
|
||||
struct NODE_CONN_DIRECT* handle; // не владеет транспортом; NCD принадлежит сессии группы
|
||||
};
|
||||
|
||||
// API — глобальный реестр TOPO_NODE
|
||||
/* Заимствованный указатель; ref нужен, если запись должна пережить удаление из группы. */
|
||||
struct TOPO_NODE* topo_node_registry_find(struct TOPO_GROUPS* groups, uint64_t node_id);
|
||||
/* Принять ni и вернуть запись с одной новой ссылкой. Может вернуть существующий объект.
|
||||
* При NULL входной ni остаётся у вызывающего. Подписанные записи сравниваются по timestamp. */
|
||||
struct TOPO_NODE* topo_node_registry_store(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni);
|
||||
/* Добавить/снять ссылку; последняя unref удаляет запись из реестра и освобождает её. */
|
||||
void topo_node_registry_ref(struct TOPO_GROUPS* groups, uint64_t node_id);
|
||||
void topo_node_registry_unref(struct TOPO_GROUPS* groups, uint64_t node_id);
|
||||
/* Освободить отдельную запись и её списки; зарегистрированную запись отпускать через unref. */
|
||||
void topo_node_destroy(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni);
|
||||
|
||||
// API — per-group
|
||||
/* Заимствованный узел группы, NULL если не найден. */
|
||||
struct TOPO_GROUP_NODE* topo_node_find_by_id(struct TOPO_GROUP* group, uint64_t node_id);
|
||||
/* Отпустить ссылку реестра и подсети; nq и paths не освобождает. */
|
||||
void topo_nodeq_free_group_fields(struct TOPO_GROUPS* groups, struct TOPO_GROUP_NODE* nq);
|
||||
/* Полное удаление узла из группы: отменяет влётные пробы, освобождает paths/subnets,
|
||||
* убирает из group->nodes и освобождает сам nq. Единственный корректный способ удаления узла. */
|
||||
void topo_nodeq_remove_node(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* nq);
|
||||
|
||||
/* Размер переменной части NODEINFO по счётчикам заголовка. */
|
||||
int topo_node_dyn_size(const struct TOPOMSG_NODE* msg);
|
||||
/* Собрать NODEINFO в out; длина или -1. Входные структуры остаются у вызывающего. */
|
||||
int topo_node_serialize(struct TOPO_NODE* ni, struct TOPO_GROUP_NODE* nq,
|
||||
uint64_t group_id, uint8_t flags,
|
||||
uint8_t* out, size_t out_max, uint16_t cumulative_rtt);
|
||||
/* Разобрать NODEINFO; 0/-1. Выходные объекты выделены отдельно и передаются вызывающему. */
|
||||
int topo_node_deserialize(struct TOPO_GROUP* group, const uint8_t* data, size_t len, struct TOPO_NODE** out_ni, struct TOPO_NODESUBNETS** out_subnets,
|
||||
uint64_t** out_hop_list, uint8_t* out_hop_count,
|
||||
uint16_t* out_cumulative_rtt);
|
||||
/* Заимствованный список hops: кратчайший живой путь, иначе первый сохранённый.
|
||||
* out_count обязателен; NULL означает отсутствие пути. */
|
||||
uint64_t* topo_node_best_hop_list(struct TOPO_GROUP_NODE* nq, uint8_t* out_count, uint16_t* out_rtt);
|
||||
|
||||
/* Обновить локальный узел группы и его анонс. 0/-1. */
|
||||
int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GROUP* group);
|
||||
/* Создать подписанную локальную идентичность с отдельной ссылкой ядра. 0/-1. */
|
||||
int topo_node_init_self(struct UTUN_INSTANCE* instance);
|
||||
int topo_node_update_my_addresses(struct UTUN_INSTANCE* instance); /* 1=changed, 0=unchanged, -1=error */
|
||||
/* Обработчик изменений локального сокета: обновляет адреса узла. */
|
||||
void topo_node_on_socket_changed(struct ETCP_SOCKET* sock, int event, void* arg);
|
||||
/* Вывести диагностику узлов группы в лог / текстовый буфер. */
|
||||
void topo_node_dump_all(struct TOPO_GROUP* group);
|
||||
int topo_node_format_all(struct TOPO_GROUP* group, char* buf, size_t buf_size);
|
||||
/* 1, если хотя бы в одной группе пора повторить ping этого узла; иначе 0. */
|
||||
int topo_node_ping_request_cbk(struct TOPO_GROUPS* groups, uint64_t node_id);
|
||||
/* Обновить время ping и минимальные RTT во всех группах и БД; rtt в единицах 0.1 ms. */
|
||||
void topo_node_ping_update_rtt(struct TOPO_GROUPS* groups, uint64_t node_id, uint16_t rtt);
|
||||
/* Минимальный суммарный RTT живого пути в единицах 0.1 ms; UINT16_MAX, если неизвестен. */
|
||||
uint16_t topo_get_chain_rtt(struct TOPO_GROUP_NODE* nq);
|
||||
|
||||
/** Build canonical message for Ed25519 signature: x25519_pubkey || name || client_type || client_activity || addresses */
|
||||
/* Лимиты буфера подписываемых данных и полного сетевого NODEINFO. */
|
||||
#define TOPO_SIG_MSG_MAX_SIZE 2048
|
||||
#define TOPO_NODE_WIRE_MAX_SIZE 16384
|
||||
/* Канонические байты подписи: node_id, ver, timestamp, X25519-ключ, имя,
|
||||
* тип/активность и полные списки сокетов/адресов/Reality. Длина или -1. */
|
||||
int topo_node_build_sig_msg(struct TOPO_NODE* ni, uint8_t* buf, size_t buf_size);
|
||||
|
||||
/** Sign self NODEINFO with Ed25519: build_sig_msg + sc_ed25519_sign → ni->x25519_self_sig */
|
||||
/* Увеличить timestamp, подписать локальный NODEINFO и сохранить снимок в SQLite. 0/-1. */
|
||||
int topo_node_sign_self(struct UTUN_INSTANCE* instance, struct TOPO_NODE* ni);
|
||||
/* Проверить timestamp, привязку node_id к ключу и подпись. 0/-1. */
|
||||
int topo_node_verify(const struct TOPO_NODE* ni);
|
||||
|
||||
static inline const struct TOPO_SOCKMETA4* topo_v4_sock_meta(const struct TOPO_NODE* ni) { return ni->v4_sock_meta; }
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/* topo_recovery — восстановление путей группы после потери транспорта.
|
||||
* Собирает потерянные узлы, пробует кандидатов через групповые запросы и ждёт
|
||||
* нужных маршрутов через READY-пиров. Контекст принадлежит группе; работа — в uasync. */
|
||||
#ifndef TOPO_RECOVERY_H
|
||||
#define TOPO_RECOVERY_H
|
||||
|
||||
@@ -30,9 +33,13 @@ struct TOPO_RECOVERY_CTX;
|
||||
* NODEINFO/смена состояния лишь планируют проверку через call_soon: текущий
|
||||
* BGP callback завершается до изменения попытки или освобождения контекста.
|
||||
* Остановка группы отменяет recovery до освобождения сессий и таблицы узлов. */
|
||||
/* Добавить потерянную цель до освобождения её записи; rtt — в единицах 0.1 ms. */
|
||||
void topo_recovery_add_node(struct TOPO_GROUP* group, uint64_t node_id, uint64_t next_hop, uint16_t rtt);
|
||||
/* Запустить собранные попытки после удаления нерабочих путей. */
|
||||
void topo_recovery_start(struct TOPO_GROUP* group);
|
||||
/* Отложить проверку прогресса; повторные уведомления объединяются. */
|
||||
void topo_recovery_changed(struct TOPO_GROUP* group);
|
||||
/* Отменить попытку и освободить контекст; готовые сессии остаются у группы. */
|
||||
void topo_recovery_cancel_all(struct TOPO_GROUP* group);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
Reference in new issue
Block a user