diff --git a/src/utun_instance.h b/src/utun_instance.h index 2ec74fa0..39924b58 100644 --- a/src/utun_instance.h +++ b/src/utun_instance.h @@ -1,8 +1,9 @@ /* utun_instance — владелец ядра и сервисов одного узла. * Ядро содержит транспорт, маршрутизатор, идентичность и общую БД. * create → core_start; UTUN и чат запускаются отдельно через service_start/stop. - * Все операции жизненного цикла — в потоке переданного uasync, вне callbacks сервисов. - * destroy останавливает сервисы и освобождает ядро, но не сам uasync. */ + * Все операции — в потоке переданного UASYNC; stop/reload/destroy вне callbacks останавливаемых модулей. + * Цикл uasync_poll запускает вызывающий; один UASYNC можно разделять между несколькими instance. + * destroy останавливает сервисы и освобождает ядро, но не UASYNC. Подробности: utun_instance_doc.md. */ #ifndef UTUN_INSTANCE_H #define UTUN_INSTANCE_H @@ -34,8 +35,6 @@ extern "C" { #include "ntp_time.h" #include "ntp_node_time.h" -#include "etcp_api.h" -#include "config_parser.h" #include "topo_group.h" #include "chat/chat_setting.h" #include "chat/chat_event.h" @@ -77,16 +76,16 @@ struct STUN_NAT; struct merkle_sync; struct NETWORK_ENTRY { - uint64_t id; // 56-bit (offset 0 = index key) - uint8_t pubkey[SC_PUBKEY_SIZE]; // 32 bytes binary - uint8_t signing_key[SC_PRIVKEY_SIZE]; // 32 bytes binary - char name[64]; + uint64_t id; // 56-битный ID сети; первые 7 байт — ключ индекса + uint8_t pubkey[SC_PUBKEY_SIZE]; // бинарный публичный ключ сети + uint8_t signing_key[SC_PRIVKEY_SIZE]; // бинарный ключ подписи сети + char name[64]; // имя [network:name], ASCIIZ }; // Queue entry for instance->connections (indexed by peer_node_id) struct conn_queue_entry { - uint64_t peer_node_id; - struct ETCP_CONN* conn; + uint64_t peer_node_id; // ключ индекса, 0 до определения пира + struct ETCP_CONN* conn; // живой транспорт; удаляется при close }; /* Постоянный транспорт ядра к пиру [client]; UTUN приобретает отдельный групповой запрос. @@ -112,9 +111,9 @@ struct tcp_conn_entry { // подписчикам (topo_group, keepalive и т.д.) при каждом изменении активности. typedef void (*utun_activity_cbk_fn)(struct UTUN_INSTANCE* instance, int active, void* arg); struct utun_activity_cbk_entry { - utun_activity_cbk_fn fn; - void* arg; - struct utun_activity_cbk_entry* next; + utun_activity_cbk_fn fn; // синхронный обработчик эффективной активности + void* arg; // заимствованный контекст обработчика + struct utun_activity_cbk_entry* next; // следующая подписка uint8_t removed; // tombstone до выхода из внешней рассылки }; @@ -123,16 +122,16 @@ struct utun_activity_cbk_entry { // sleeping=1 — пир ушёл в спячку (в фон), 0 — проснулся (дедлайн истёк / обычный keepalive). typedef void (*peer_sleep_cbk_fn)(struct UTUN_INSTANCE* instance, uint64_t peer_node_id, int sleeping, void* arg); struct peer_sleep_cbk_entry { - peer_sleep_cbk_fn fn; - void* arg; - struct peer_sleep_cbk_entry* next; + peer_sleep_cbk_fn fn; // синхронный обработчик sleep/wake пира + void* arg; // заимствованный контекст обработчика + struct peer_sleep_cbk_entry* next; // следующая подписка uint8_t removed; // снятая подписка не вызывается, память удерживает текущая рассылка }; // Состояние одного узла. Вложенные модули освобождаются через их lifecycle API. struct UTUN_INSTANCE { - struct etcp_tx_history tx_history; - struct reality_owner reality_owner; + struct etcp_tx_history tx_history; // секундное окно ACK всех транспортов ядра + struct reality_owner reality_owner; // relay и replay-кеш REALITY данного ядра uint8_t core_started, utun_started, chat_started; // успешный запуск ядра / UTUN / чата uint8_t destroying; // запрещает повторный запуск ядра/повторное destroy во время очистки @@ -150,7 +149,7 @@ struct UTUN_INSTANCE { struct ROUTE_TABLE* rt; // таблица маршрутов подсетей struct TOPO_GROUPS* topo_groups; // Groups module for topology exchange - sqlite3* topo_sqlite_db; // Shared SQLite DB (nodes/channels/peers) + sqlite3* topo_sqlite_db; // собственная общая SQLite; открывается при create с топологией struct NAT_DETECTION* nat_det; // NAT detection module struct STUN_NAT* stun_nat; // независимая локальная STUN-диагностика UDP struct stun_ports* stun_port_history; // ранее использованные STUN-порты; переживает reload config @@ -164,17 +163,17 @@ struct UTUN_INSTANCE { uint8_t my_ed25519_pubkey[SC_PUBKEY_SIZE]; // свой Ed25519 pubkey (для подписи метрик) uint8_t my_ed25519_privkey[SC_PRIVKEY_SIZE]; // свой Ed25519 privkey (derived from X25519) - uint8_t next_socket_id; // Counter for unique socket IDs (0-255) + uint8_t next_socket_id; // начало поиска свободного ID 0..255; поколение различает повторное использование // Заимствованный цикл событий: создаёт и уничтожает вызывающий. struct UASYNC* ua; // State - int running; // продолжать utun_instance_run; не флаг готовности сервисов + int running; // продолжать цикл приложения; готовность задают отдельные *_started // Connections (очередь всех подключений для instance) struct ll_queue* connections; // indexed by peer_node_id (0=pending), data=conn_queue_entry - struct ll_queue* tcp_connections; // indexed by node_id, data=tcp_conn_entry [TCP-only] + struct ll_queue* tcp_connections; // старый TCP-реестр tcp_conn_entry, fallback instance_find_conn; обычный STCP живёт в links // Callback chain for new ETCP connections struct etcp_inst_cbk_entry* new_conn_cbks; @@ -224,7 +223,7 @@ struct UTUN_INSTANCE { // Media async engine (thread-per-task for crypto/file ops) struct media_async* media_async; - // Socket initialization status: 0=OK, 1=partial (some sockets failed), -1=error (none created) + // Последний результат init/reload endpoint: 0=успех, -1=ошибка хотя бы одного обязательного endpoint. int socket_init_status; // TCP proxy client (optional, NULL if not enabled) @@ -301,47 +300,71 @@ struct UTUN_INSTANCE { uint8_t ncd_control_bound; // 1 = etcp_bind(ETCP_ID_NCD_CONTROL) сделан }; -// Создать ядро по файлу конфигурации; NULL при ошибке. Сервисы ещё не запущены. +/* Создать ядро: ua заимствован, config_file — обязательный путь. Файл может создаваться/нормализоваться updater. + * Уже открывает listeners, SQLite/топологию, router/proxy и мониторинг; core/UTUN/chat ещё не запущены. + * Возвращает instance либо NULL с освобождением частично созданных ресурсов. */ struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char* config_file); -// При успехе забирает config; при ошибке config остаётся у вызывающего. +/* Как create, но без updater и файлового parse: config должен содержать корректные ключи. + * Успех передаёт владение config ядру; при NULL config остаётся caller (node_id мог быть исправлен). + * log_file и debug меняют общий logger процесса даже при последующем отказе создания. */ struct UTUN_INSTANCE* utun_instance_create_from_config(struct UASYNC* ua, struct utun_config* config); -// Как create, но конфигурация передана строкой; строку не сохраняет. +/* Как create из ASCIIZ config_text; строка заимствована лишь на вызов. Использует mkstemp в /tmp, + * updater и файловый parse, затем unlink. Нужна доступная ФС; ошибки дают NULL. */ struct UTUN_INSTANCE* utun_instance_create_from_str(struct UASYNC* ua, const char* config_text); -// Остановить сервисы и освободить instance. Переданный uasync остаётся у вызывающего. +/* Остановить сервисы/транспорт и освободить instance/config; NULL допустим. UASYNC остаётся caller. + * Выполняет drain отложенных callbacks и join media workers; вызывать вне callbacks и без параллельных обращений. + * Заимствованные SQLite statements/backup должны быть закрыты caller; BUSY логируется и переводится в close_v2. */ void utun_instance_destroy(struct UTUN_INSTANCE* instance); -/* Запустить общие сетевые службы и постоянные транспорты [client], без членства в группах. Повтор допустим; 0/-1. */ +/* Запустить репликацию, NCD/keepalive, [client], control и время; без вступления в группы. Успех: running=core_started=1. + * Повтор успешного start — 0. Ошибка — -1; уже подготовленные ресурсы остаются для retry/destroy. + * Отказ NTP/STUN не фатален. NULL/разрушаемый instance отклоняется. */ int utun_core_start(struct UTUN_INSTANCE* instance); -/* Запустить UTUN-группу, TUN/NAT по конфигу и групповые запросы к настроенным пирам. Нужен core_start; 0/-1. */ +/* Запустить UTUN-группу, TUN/NAT по конфигу и отдельные запросы к [client]. Нужны core_start и топология. + * 0 — успех/уже запущен; -1 — откат ресурсов UTUN, ядро и чат сохраняются. */ int utun_service_start(struct UTUN_INSTANCE* instance); /* Остановить UTUN, сохранив ядро и чат. Повтор допустим. */ void utun_service_stop(struct UTUN_INSTANCE* instance); -/* Запустить ядро, UTUN и включённый в конфиге чат. 0/-1. */ +/* Последовательно core_start → UTUN (при наличии топологии) → чат (chatserver_enabled). + * 0/-1; ошибка позднего сервиса сохраняет ранее запущенные сервисы. */ int utun_instance_init(struct UTUN_INSTANCE *instance); -/* Перечитать конфигурацию, при необходимости пересоздать экземпляр; использовать возвращённый указатель. */ +/* Перечитать config_file через updater; ua должен совпадать с instance->ua. Всегда использовать результат. + * Ошибка подготовки сохраняет прежний указатель. Смена негорячих global/подсетей либо automatic servers + * пересоздаёт ядро с прежними core/UTUN/chat/running; ошибка после destroy возвращает NULL. + * Ручные endpoints обновляются по имени и всем параметрам, неизменённые сохраняются (включая port=0). + * Частичный reload не транзакционный: отказ endpoint логируется, новый config сохраняется для следующего retry. */ struct UTUN_INSTANCE *utun_instance_reload(struct UTUN_INSTANCE *instance, struct UASYNC *ua, const char *config_file); -/* Выполнять цикл событий до stop(). */ -void utun_instance_run(struct UTUN_INSTANCE *instance); /* Снять running и разбудить цикл; ресурсы освобождает destroy(), а не stop(). */ void utun_instance_stop(struct UTUN_INSTANCE *instance); -/* Глобальные переключатели создания TUN/топологии для тестов и встраивания. */ +/* Общий переключатель TUN (по умолчанию 0): влияет на последующий UTUN start и proxy test mode при create. */ void utun_instance_set_tun_init_enabled(int enabled); +/* Общий переключатель топологии (по умолчанию 1): влияет на последующие create, включая открытие SQLite. */ void utun_instance_set_topo_group_enabled(int enabled); /* Сохраняет желаемый режим frontend; stream owners удерживают ACTIVE до последнего close. * Применяет эффективную активность и мобильный standby до уведомления подписчиков; выполнять в uasync-потоке. - * Повторная команда согласует фактический режим без повторного BGP-события. 0 — успех, <0 — ошибка. */ + * Повторная команда согласует фактический режим без повторного BGP-события. SERVER — успешный no-op. + * 0 — успех, -1 — NULL/ошибка standby с откатом режима. phone_state не меняется. */ int utun_set_client_activity(struct UTUN_INSTANCE* instance, int active); +/* Подписки уникальны по fn+arg, новые идут в голову; arg заимствован. NULL instance/fn — no-op, + * OOM логируется без добавления. Remove из callback безопасен; память удерживается до конца внешней рассылки. + * Новая подписка не получает уже начатое событие, но участвует во вложенном. Destroy внутри callback запрещён. */ void utun_add_activity_cbk(struct UTUN_INSTANCE* instance, utun_activity_cbk_fn fn, void* arg); +/* Удалить подписку fn+arg; отсутствие — no-op. Вложенная новая активность отменяет остаток старого события. */ void utun_remove_activity_cbk(struct UTUN_INSTANCE* instance, utun_activity_cbk_fn fn, void* arg); +/* Аналогичная подписка на peer_node_id/sleeping; nesting исполняется синхронно до продолжения внешней рассылки. */ void utun_add_peer_sleep_cbk(struct UTUN_INSTANCE* instance, peer_sleep_cbk_fn fn, void* arg); +/* Удалить peer-sleep подписку fn+arg; отсутствие/NULL — no-op. */ void utun_remove_peer_sleep_cbk(struct UTUN_INSTANCE* instance, peer_sleep_cbk_fn fn, void* arg); +/* Синхронно передать подписчикам node_id и sleeping (1 сон, 0 пробуждение); NULL instance — no-op. */ void utun_fire_peer_sleep_cbk(struct UTUN_INSTANCE* instance, uint64_t peer_node_id, int sleeping); -// Diagnostic function for memory leak analysis +/* Вывести sys/info счётчики ресурсов и простые sanity-проверки списков с меткой phase. + * Живые ресурсы сами по себе не означают утечку; функция ничего не освобождает. */ void utun_instance_diagnose_leaks(struct UTUN_INSTANCE* instance, const char* phase); /* Найти транспорт по node_id в реестрах ETCP/TCP. Указатель заимствован. * NULL — не найден; ненулевой результат не гарантирует UP или готовность группы. */ static inline struct ETCP_CONN* instance_find_conn(struct UTUN_INSTANCE* inst, uint64_t node_id) { + if (!inst) return NULL; if (inst->connections) { struct ll_entry* e = queue_find_data_by_index(inst->connections, (const uint8_t*)&node_id); if (e) return ((struct conn_queue_entry*)e->data)->conn;