From f59f64ea480eadfa7f33c57d39505e108b6be9b8 Mon Sep 17 00:00:00 2001 From: evgeny Date: Wed, 21 Oct 2026 15:22:42 +0200 Subject: [PATCH] docs: remove reviewed header backup files --- lib/ll_queue.h1 | 444 ------------------------ src/call/call.h1 | 119 ------- src/call/call_video_port.h1 | 51 --- src/chat/chat_attachment.h1 | 46 --- src/chat/chat_core.h1 | 313 ----------------- src/chat/chat_event.h1 | 104 ------ src/chat/group_avatar.h1 | 32 -- src/media_delivery/media_delivery.h1 | 175 ---------- src/media_delivery/media_index.h1 | 67 ---- src/member_files/member_files.h1 | 56 --- src/routing_layer/multicast.h1 | 219 ------------ src/stream/stream.h1 | 125 ------- src/stream/stream_optimizer.h1 | 26 -- src/stream/stream_playback_clock.h1 | 49 --- src/transport_layer/auto_socket.h1 | 95 ----- src/transport_layer/etcp_connections.h1 | 430 ----------------------- src/transport_layer/etcp_padding.h1 | 36 -- src/transport_layer/node_conn_direct.h1 | 149 -------- src/transport_layer/reality_io.h1 | 40 --- 19 files changed, 2576 deletions(-) delete mode 100644 lib/ll_queue.h1 delete mode 100644 src/call/call.h1 delete mode 100644 src/call/call_video_port.h1 delete mode 100644 src/chat/chat_attachment.h1 delete mode 100644 src/chat/chat_core.h1 delete mode 100644 src/chat/chat_event.h1 delete mode 100644 src/chat/group_avatar.h1 delete mode 100644 src/media_delivery/media_delivery.h1 delete mode 100644 src/media_delivery/media_index.h1 delete mode 100644 src/member_files/member_files.h1 delete mode 100644 src/routing_layer/multicast.h1 delete mode 100644 src/stream/stream.h1 delete mode 100644 src/stream/stream_optimizer.h1 delete mode 100644 src/stream/stream_playback_clock.h1 delete mode 100644 src/transport_layer/auto_socket.h1 delete mode 100644 src/transport_layer/etcp_connections.h1 delete mode 100644 src/transport_layer/etcp_padding.h1 delete mode 100644 src/transport_layer/node_conn_direct.h1 delete mode 100644 src/transport_layer/reality_io.h1 diff --git a/lib/ll_queue.h1 b/lib/ll_queue.h1 deleted file mode 100644 index 971a63e3..00000000 --- a/lib/ll_queue.h1 +++ /dev/null @@ -1,444 +0,0 @@ -#ifndef LL_QUEUE_H -#define LL_QUEUE_H - -/* Очередь одного uasync-потока; наличие pthread-заголовков не делает её межпоточной. - * put может синхронно вызвать consumer/waiter. Держать владельцев живыми до завершения callbacks, - * waiter handle обнулять целиком и отменять до освобождения; entry и dgram освобождаются отдельно. */ - -#ifdef __cplusplus -extern "C" { -#endif - - -#include // для size_t -#include // для uint64_t -#include "memory_pool.h" // для struct memory_pool - -#ifdef _WIN32 - #include - #include -#else - #include -#endif - -//#define QUEUE_DEBUG 1 // раскомментировать для отладки очереди -//#define QUEUE_THREAD_CHECK 1 // 0 to disable - -/** - * @file ll_queue.h - * @brief Упрощённая двусвязная очередь с поддержкой автозабора элементов через callback, - * порогового ожидания освобождения места, поиска по ID и гибкого управления памятью. - * - * Основные особенности: - * - FIFO-очередь (с возможностью добавления в начало для приоритета) - * - Автоматический вызов callback при появлении элементов (один элемент за раз) - * - Обязательный вызов queue_resume_callback после обработки элемента - * - Поддержка пулов памяти для entry и отдельно для dgram - * - Хеш-таблица для быстрого поиска по ID (опционально) - * - Связный список waiters для backpressure c общим порогом (round-robin) - * - Использует uasync для отложенного возобновления callback'ов (без рекурсии в стеке) - * - * @note Важные правила использования автозабора (queue_set_callback): - * 1. Коллбэк получает управление только если в очереди есть элементы И !callback_suspended - * 2. Внутри коллбэка ОБЯЗАТЕЛЬНО: queue_data_get() → обработать элемент → queue_resume_callback() - * 3. Без вызова queue_resume_callback очередь навсегда застрянет - * 4. Не извлекайте элементы вручную вне коллбэка — это нарушит логику - * 5. queue_data_get() автоматически suspend'ит коллбэки для предотвращения рекурсии - * - * @note Память: - * - queue_free() освобождает структуру очереди, хеш-таблицу и список waiters - * (handle->internal каждого ожидающего сбрасывается в NULL) - * - Все элементы должны быть извлечены через queue_data_get() и освобождены через queue_entry_free() - * - dgram освобождается отдельно через queue_dgram_free() или кастомную dgram_free_fn - */ - -// Forward declarations -struct ll_queue; -struct queue_waiter_handle; - -/** - * @struct ll_entry - * @brief Элемент очереди (переменного размера). - * - * Память выделяется одним блоком: [struct ll_entry + data[size]]. - * Поле dgram — отдельный блок (malloc / пул / внешняя память). - */ -struct ll_entry { - char* name; - struct ll_queue* owner; // Владелец элемента; NULL после извлечения - struct ll_entry* next; // Следующий элемент в очереди - struct ll_entry* prev; // Предыдущий элемент в очереди - uint16_t size; // Размер пользовательского буфера data[] (байт) - uint16_t len; // Актуальная длина данных в dgram - uint16_t memlen; // Выделенный размер под dgram - uint16_t int_len; // Внутреннее (не использовать) - uint8_t* dgram; // Указатель на данные пакета - void (*dgram_free_fn)(uint8_t* data); // Кастомная функция освобождения dgram - struct memory_pool* dgram_pool; // Пул для dgram (если используется) - uint32_t index_hash; // Хеш по первым 4 байтам индекса - struct ll_entry* hash_next; // Следующий в хеш-цепочке - struct memory_pool* pool; // Пул, из которого выделен сам entry (NULL = malloc) - uint8_t data[0]; // Гибкий массив пользовательских данных (размер = size) -}; - -/** - * @typedef queue_callback_fn - * @brief Коллбэк автозабора элементов из очереди. - * @param q указатель на очередь - * @param arg пользовательский аргумент (из queue_set_callback) - * - * @note Внутри функции: - * - Вызвать queue_data_get(q) для получения элемента - * - Обработать элемент (можно асинхронно) - * - После завершения обработки вызвать queue_resume_callback(q) - */ -typedef void (*queue_callback_fn)(struct ll_queue* q, void* arg); - -/** - * @typedef queue_threshold_callback_fn - * @brief Одноразовый коллбэк при достижении порога очереди. - * @param q указатель на очередь - * @param arg пользовательский аргумент - */ -typedef void (*queue_threshold_callback_fn)(struct ll_queue* q, void* arg); - -/** - * @struct queue_waiter - * @brief Внутренний узел в связном списке ожидающих (очередь владеет, аллоцирует/освобождает сама). - */ -struct queue_waiter { - struct queue_waiter* next; ///< Следующий в списке ожидающих - struct queue_waiter_handle* handle; ///< Обратная ссылка на публичную структуру - queue_threshold_callback_fn callback; - void* callback_arg; -}; - -/** - * @struct queue_waiter_handle - * @brief Публичная управляющая структура (встраивается в структуру вызывающей стороны). - * - * Вызывающая сторона: - * 1. Объявляет поле struct queue_waiter_handle в своей структуре (= {0} или u_calloc) - * 3. Вызывает queue_waiter_wait() когда хочет дождаться освобождения очереди - * 4. Вызывает queue_waiter_cancel() при деинициализации для отмены ожидания - */ -struct queue_waiter_handle { - struct queue_waiter* internal; ///< NULL = не ждём; иначе — внутренний узел - struct ll_queue* defer_q; - queue_threshold_callback_fn defer_cb; - void* defer_arg; - void* call_soon_id; ///< хендл отложенного вызова (для отмены) - struct queue_waiter_handle* defer_next; ///< список отложенных уведомлений очереди -}; - -/** - * @struct ll_queue - * @brief Структура очереди. - */ -struct ll_queue { - char* name; - struct ll_entry* head; // Голова очереди (отсюда извлекаем) - struct ll_entry* tail; // Хвост очереди (сюда добавляем) - int count; // Текущее количество элементов - size_t total_bytes; // Суммарный объём данных (сумма int_len) - int size_limit; // Максимальное количество элементов (-1 = без лимита) - - queue_callback_fn callback; // Коллбэк автозабора - void* callback_arg; // Аргумент коллбэка - int callback_suspended; // 1 = коллбэки временно приостановлены - - void* resume_timeout_id; // ID таймера uasync для отложенного resume - struct UASYNC* ua; // Экземпляр uasync (обязателен для таймеров) - - struct queue_waiter* waiter_head; // Голова списка ожидающих - struct queue_waiter* waiter_tail; // Хвост списка ожидающих - struct queue_waiter_handle* deferred_waiters; // Уже запланированные уведомления - int threshold_max_packets; // Общий порог: макс. кол-во элементов (по умолчанию 0) - size_t threshold_max_bytes; // Общий порог: макс. объём данных (0 = не проверять) - int waiter_defer; // 0=immediate callback, 1=defer via uasync_call_soon - int callback_defer; // 0=immediate callback из put (default), 1=defer via uasync_call_soon (очистка стека) - - queue_callback_fn empty_callback; // одноразовый коллбэк при опустошении очереди - void* empty_callback_arg; - void* empty_call_soon_id; // handle от uasync_call_soon - - queue_callback_fn on_get; // коллбэк после каждого queue_data_get (deferred) - void* on_get_arg; - void* on_get_call_soon_id; - size_t on_get_pending; - - struct ll_entry** hash_table; // Хеш-таблица для поиска по id (если hash_size > 0) - size_t hash_size; // Размер хеш-таблицы - uint16_t index_offset; // Смещение индекса в data[] (для всех entry очереди) - uint16_t index_size; // Размер индекса (0 = без индекса) - -#ifdef QUEUE_THREAD_CHECK -#ifdef _WIN32 - DWORD owner_thread; -#else - pthread_t owner_thread; -#endif -#endif -}; - -/* ==================== Создание / уничтожение ==================== */ - -/** - * @brief Создаёт новую пустую очередь. - * @param ua экземпляр uasync (обязателен для отложенного resume коллбэков) - * @param hash_size размер хеш-таблицы (0 = поиск по id отключён) - * @param index_offset смещение ключа индекса в data[] каждого entry (0 если hash_size=0) - * @param index_size размер ключа индекса (0 если hash_size=0) - * @param name имя очереди для отладки - * @return указатель на очередь или NULL при ошибке выделения памяти - */ -struct ll_queue* queue_new(struct UASYNC* ua, size_t hash_size, uint16_t index_offset, uint16_t index_size, char* name); - -/** - * @brief Освобождает структуру очереди. - * @param q очередь - * - * @warning НЕ ОСВОБОЖДАЕТ элементы в очереди! - * Их нужно извлечь через queue_data_get() и освободить через queue_entry_free(). - */ -void queue_free(struct ll_queue* q); - -/* ==================== Конфигурация ==================== */ - -/** - * @brief Устанавливает максимальное количество элементов в очереди. - * @param q очередь - * @param lim лимит (-1 = без ограничения) - * - * При превышении лимита новые элементы автоматически освобождаются. - */ -void queue_set_size_limit(struct ll_queue* q, int lim); - -/* ==================== Автозабор элементов ==================== */ - -/** - * @brief Устанавливает коллбэк для автоматического извлечения элементов. - * @param q очередь - * @param cbk_fn функция-коллбэк - * @param arg пользовательский аргумент - * - * Коллбэк вызывается автоматически при наличии элементов и разрешённом состоянии. - */ -void queue_set_callback(struct ll_queue* q, queue_callback_fn cbk_fn, void* arg); - -/** - * @brief Возобновляет работу коллбэка после обработки элемента в следующем event loop. - * @param q очередь - * - * @warning ОБЯЗАТЕЛЬНО вызывать после завершения обработки элемента в коллбэке. - * Иначе автозабор элементов навсегда остановится. - */ -void queue_resume_callback(struct ll_queue* q); - -/* ==================== Пороговое ожидание (backpressure) ==================== */ - -/** - * @brief Устанавливает общий порог освобождения очереди. - * @param q очередь - * @param max_packets максимальное количество элементов (условие: count <= max_packets) - * @param max_bytes максимальный объём данных (0 = не проверять) - * - * Порог — общий на всю очередь. Все waiters в связном списке используют этот порог. - * При достижении порога вызывается следующий waiter из списка (FIFO / round-robin). - * По умолчанию: max_packets=0, max_bytes=0 (пустая очередь). - */ -void queue_set_threshold(struct ll_queue* q, int max_packets, size_t max_bytes); - -void queue_set_waiter_defer(struct ll_queue* q, int enable); - -/** - * @brief Управляет способом вызова коллбэка автозабора при добавлении элемента. - * @param q очередь - * @param enable 0 — первый запуск коллбэка из queue_data_put* вызывается синхронно (по умолчанию); - * 1 — первый запуск откладывается через uasync_call_soon (очищает стек вызывающего). - * - * @note Влияет только на первый запуск из put. Повторные запуски (queue_resume_callback) - * всегда идут через uasync_call_soon. - */ -void queue_set_callback_defer(struct ll_queue* q, int enable); - -/** - * @brief Устанавливает одноразовый коллбэк при опустошении очереди (count==0). - * @param q очередь - * @param cbk_fn коллбэк (NULL для отмены) - * @param arg пользовательский аргумент - * - * Коллбэк вызывается асинхронно (через uasync_call_soon) когда count становится 0. - * После вызова сбрасывается — для повторного использования нужно вызвать снова. - */ -void queue_set_empty_callback(struct ll_queue* q, queue_callback_fn cbk_fn, void* arg); - -/** - * @brief Устанавливает коллбэк вызываемый после каждого queue_data_get (deferred через call_soon). - * @param q очередь - * @param cbk_fn коллбэк (NULL для отмены) - * @param arg пользовательский аргумент - */ -void queue_set_on_get(struct ll_queue* q, queue_callback_fn cbk_fn, void* arg); - -/** - * @brief Регистрирует ожидание освобождения очереди до общего порога. - * @param q очередь - * @param h полностью обнулённый handle: `struct queue_waiter_handle h = {0}` - * @param callback функция, вызываемая при достижении порога - * @param arg аргумент коллбэка - * @return 1 — условие выполнено (callback вызван или отложен), 0 — ожидает порог, -1 — ошибка - * - * Если handle уже ожидает или имеет отложенный callback — старое ожидание отменяется. - * При queue_free отменяются также уже запланированные уведомления. - */ -int queue_waiter_wait(struct ll_queue* q, struct queue_waiter_handle* h, - queue_threshold_callback_fn callback, void* arg); - -/** - * @brief Отменяет ожидание (удаляет из списка, если зарегистрирован). - * @param q очередь - * @param h указатель на handle - * - * Безопасно вызывать в любом состоянии: если waiter не зарегистрирован — ничего не делает. - */ -void queue_waiter_cancel(struct ll_queue* q, struct queue_waiter_handle* h); - -/* ==================== Работа с данными ==================== */ - -/** - * @brief Добавляет элемент в конец очереди (FIFO). - * @param q очередь - * @param entry элемент - * @return 0 — успех, -1 — превышен лимит (элемент освобождён) - */ -int queue_data_put(struct ll_queue* q, struct ll_entry* entry); - -/** - * @brief Добавляет элемент в начало очереди (LIFO, высокий приоритет). - * @param q очередь - * @param entry элемент - * @return 0 — успех, -1 — превышен лимит (элемент освобождён) - */ -int queue_data_put_first(struct ll_queue* q, struct ll_entry* entry); - -/** - * @brief Добавляет элемент в конец очереди с хеш-индексом (использует index_offset/index_size из очереди). - * @param q очередь - * @param entry элемент - * @return 0 — успех, -1 — ошибка - */ -int queue_data_put_with_index(struct ll_queue* q, struct ll_entry* entry); - -/** - * @brief Добавляет элемент в начало очереди с хеш-индексом (использует index_offset/index_size из очереди). - * @param q очередь - * @param entry элемент - * @return 0 — успех, -1 — ошибка - */ -int queue_data_put_first_with_index(struct ll_queue* q, struct ll_entry* entry); - - -/** - * @brief Извлекает элемент из начала очереди. - * @param q очередь - * @return элемент или NULL, если очередь пуста - * - * @note Автоматически приостанавливает коллбэки (callback_suspended = 1) - * После обработки элемента необходимо вызвать queue_resume_callback(). - */ -struct ll_entry* queue_data_get(struct ll_queue* q); - -/** - * @brief Возвращает текущее количество элементов в очереди. - * @param q очередь - * @return количество элементов - */ -int queue_entry_count(struct ll_queue* q); - -/* ==================== Управление памятью элементов ==================== */ - -// проверить правильность очереди (корректность цепочки, счетчики элементов и байтов) -int queue_check_consistency(struct ll_queue* q); - -/** - * @brief Выделяет элемент с отдельным буфером dgram (malloc). - * @param len требуемый размер dgram - * @return элемент или NULL при ошибке - */ -struct ll_entry* ll_alloc_lldgram(uint16_t len); - -/** - * @brief Создаёт элемент с пользовательским буфером data[] (malloc одним блоком). - * @param data_size размер data[] - * @return элемент или NULL при ошибке - */ -struct ll_entry* queue_entry_new(size_t data_size); - -/** - * @brief Создаёт элемент из пула памяти. - * @param pool пул - * @return элемент или NULL, если пул пуст - */ -struct ll_entry* queue_entry_new_from_pool(struct memory_pool* pool); - -/** - * @brief Освобождает структуру элемента (возвращает в пул или free). - * @param entry элемент - * - * @note НЕ освобождает dgram! Используйте queue_dgram_free() отдельно. - */ -void queue_entry_free(struct ll_entry* entry); - -/** - * @brief Освобождает буфер dgram элемента. - * @param entry элемент - */ -void queue_dgram_free(struct ll_entry* entry); - -/* ==================== Поиск и удаление ==================== */ - -/** - * @brief Находит элемент по ключу индекса (требуется hash_size > 0 при создании). - * @param q очередь (размер ключа берётся из q->index_size) - * @param index_key искомый ключ - * @return элемент или NULL - */ -struct ll_entry* queue_find_data_by_index(struct ll_queue* q, - const void* index_key); - -/** - * @brief Находит следующий элемент с тем же ключом (продолжение поиска). - * @param q очередь (размер ключа берётся из q->index_size) - * @param index_key искомый ключ - * @param prev_entry предыдущий найденный элемент (от queue_find_data_by_index или предыдущего queue_find_next_by_index) - * @return следующий элемент с тем же ключом или NULL - */ -struct ll_entry* queue_find_next_by_index(struct ll_queue* q, - const void* index_key, - struct ll_entry* prev_entry); - -/** - * @brief Удаляет элемент из очереди (не освобождает память). - * @param q очередь - * @param entry элемент - * @return 0 — успех, -1 — элемент не найден в очереди - */ -int queue_remove_data(struct ll_queue* q, struct ll_entry* entry); - -/* ==================== Утилиты ==================== */ - -/** - * @brief Возвращает суммарный объём данных в очереди. - * @param q очередь - * @return количество байт - */ -static inline size_t queue_total_bytes(struct ll_queue* q) { - return q->total_bytes; -} - - -#ifdef __cplusplus -} -#endif -#endif // LL_QUEUE_H diff --git a/src/call/call.h1 b/src/call/call.h1 deleted file mode 100644 index b7fdfa90..00000000 --- a/src/call/call.h1 +++ /dev/null @@ -1,119 +0,0 @@ -// call.h — P2P аудио-звонок (сигналинг + медиа), per-instance -// -// Модуль оперирует (group_id, peer_node_id): звонок можно инициировать из -// CHAT-группы или из DM (group_id — группа маршрутизации, как в dm_core). -// Сигналинг, аудио и видео идут через etcp_router с обязательными ROUTE_CRYPTO_SIGN|ENCRYPT; соединение -// оптимизируется через параллельные пробы conn_mgr (DIRECT/REVERSE/INDIRECT). -// -// Все функции — в uasync-потоке. GUI/headless вызывают через trampoline -// (gui_bridge_post_uasync_fn / uasync_post). -#ifndef CALL_H -#define CALL_H - -#include -#include "call_jitter.h" -#include "call_clock.h" - -struct UTUN_INSTANCE; - -#ifdef __cplusplus -extern "C" { -#endif - -/* ── жизненный цикл ── */ - -int call_init(struct UTUN_INSTANCE* inst); /* из utun_instance.c после dm_core_init */ -void call_destroy(struct UTUN_INSTANCE* inst); /* перед dm_core_destroy */ - -/* ── сигналинг (uasync-поток) ── */ - -/* Caller: ch_id — группа либо "dm:" (BGP-группа выбирается при запуске). - * out_call_id — случайный uint64, генерит вызывающий. */ -void call_start (struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t peer_node_id, uint64_t out_call_id); - -/* Callee: ответить/отклонить. hangup — любая сторона в любой момент. */ -void call_accept (struct UTUN_INSTANCE* inst, uint64_t call_id); -void call_decline(struct UTUN_INSTANCE* inst, uint64_t call_id); -void call_hangup (struct UTUN_INSTANCE* inst, uint64_t call_id); -/* Проверка занятости обычным звонком; только uasync, включая входящий/исходящий. */ -int call_busy(struct UTUN_INSTANCE* inst); -/* Продолжить исходящий вызов после предупреждения о телефонной занятости. Только uasync. */ -void call_continue(struct UTUN_INSTANCE* inst, uint64_t call_id); -/* Независимые настройки входящих вызовов; запрет выбранного типа приоритетнее проверки занятости. */ -enum call_policy { - CALL_POLICY_PUBLISH_PHONE = 1, CALL_POLICY_WARN_PHONE = 2, CALL_POLICY_REJECT_PHONE = 4, - CALL_POLICY_BLOCK_CALLS = 8, CALL_POLICY_BLOCK_RADIO = 16 -}; -/* Живое состояние ОС: 0=неизвестно, 1=свободен, 2=занят; policy — маска call_policy. - * Только uasync. Изменение статуса публикуется в BGP, если включён PUBLISH_PHONE. */ -void call_set_phone_state(struct UTUN_INSTANCE* inst, int state, unsigned policy); -/* Флаги BGP PHONE_KNOWN/BUSY с учётом звонка приложения и разрешения публикации. - * Desktop без звонка свободен; у mobile состояние ОС может быть неизвестно. Только uasync. */ -uint8_t call_phone_status(struct UTUN_INSTANCE* inst); - -/* Read-only онлайн-проверка (GUI может звать из любого потока). */ -int call_is_online(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t peer_node_id); - -/* ── медиа (релей Opus-кадров, uasync-поток) ── */ - -/* Отправить закодированный Opus-кадр пиру (оборачивает в CALL_MEDIA). - * Только когда звонок ACTIVE. seq/ts выставляются автоматически. */ -int call_send_media(struct UTUN_INSTANCE* inst, uint64_t call_id, const uint8_t* opus, int len, - const struct call_capture_time* timing); - -/* Коллбэк приёма медиа: вызывается в uasync-потоке на каждый Opus-кадр пира. - * Используется headless-аудио-сокетом (и в фазе 3 — декодером GUI). */ -typedef void (*call_media_recv_fn)(struct UTUN_INSTANCE* inst, uint64_t call_id, - const uint8_t* opus, int len, void* arg); -void call_set_media_recv_cb(struct UTUN_INSTANCE* inst, call_media_recv_fn fn, void* arg); - -/* ── аудио-движок (опционально, GUI-сборки) ── - * Сервисный аудио-контур (codec + джиттер-буфер + тоны) регистрируется через - * call_set_audio_ops. call.c зовёт on_media на каждый принятый медиа-кадр (с seq/ts) - * и get_stats для события CALL_STATS. Демон без аудио (headless) — ops не ставит. */ - -struct call_audio_ops { - /* uasync-поток: принятый Opus-кадр пира (декод + jitter-буфер). */ - void (*on_media)(struct UTUN_INSTANCE* inst, uint64_t call_id, - uint16_t seq, uint32_t ts_ms, const uint8_t* opus, int len, const struct call_capture_time* timing); - /* uasync-поток: текущие метрики джиттер-буфера (buffer_ms, tempo_x100, - * dropped/underruns — опционально, NULL допустим). */ - int (*get_stats)(uint64_t call_id, int* buffer_ms, int* tempo_x100, - uint32_t* dropped, uint32_t* underruns, struct call_jitter_range* range); -}; -void call_set_audio_ops(struct UTUN_INSTANCE* inst, const struct call_audio_ops* ops); - -/* Отправить Opus-кадр из ДРУГОГО потока (GUI-аудио): post в uasync через trampoline. */ -struct call_media_arg { - struct UTUN_INSTANCE* inst; - uint64_t call_id; - uint16_t len; - struct call_capture_time timing; - uint8_t opus[256]; -}; -void call_send_media_trampoline(void* arg); - -/* ── trampoline-структуры для gui_bridge_post_uasync_fn / uasync_post ── */ - -struct call_start_arg { - struct UTUN_INSTANCE* inst; - char ch_id[64]; - uint64_t peer_node_id; - uint64_t call_id; -}; - -struct call_id_arg { - struct UTUN_INSTANCE* inst; - uint64_t call_id; -}; - -void call_start_trampoline (void* arg); -void call_accept_trampoline (void* arg); -void call_decline_trampoline(void* arg); -void call_hangup_trampoline (void* arg); -void call_continue_trampoline(void* arg); - -#ifdef __cplusplus -} -#endif -#endif /* CALL_H */ diff --git a/src/call/call_video_port.h1 b/src/call/call_video_port.h1 deleted file mode 100644 index d8701de2..00000000 --- a/src/call/call_video_port.h1 +++ /dev/null @@ -1,51 +0,0 @@ -/* Один платформенный видеозвонок процесса. Attach/detach — uasync; остальные API - * потокобезопасны. Detach отменяет post до уничтожения ядра. Worker не хранит inst. - * Один TX mailbox (до восьми кадров, каждый <=2MiB) + восемь RX кадров <=4MiB; - * владение pull.data передаётся через u_free. TX не ждёт накопления пачки. - * Никаких callbacks в UI: status/pull читает worker. Кодирование не блокирует uasync. */ -#ifndef CALL_VIDEO_PORT_H -#define CALL_VIDEO_PORT_H -#include "call_video.h" -struct UTUN_INSTANCE; -#ifdef __cplusplus -extern "C" { -#endif -struct call_video_port_status { - struct call_video_caps peer; - uint64_t key_serial, rate_generation, rate_request, configured_generation; - uint32_t rate_bps; - uint32_t minimum_bps, maximum_bps; - int have_peer, error; - int can_encode; // Новые raw входы допустимы; готовый TX всё равно сохраняется и повторяется. - int tx_idle; // Mailbox свободен; новый формат не обгонит кадры прежнего поколения в mailbox. - uint64_t decoded_generation; - int decoded_accepted; - unsigned rx_frames; // Полные encoded кадры порта; pending decoder/GUI учитывает RX worker. -}; -int call_video_port_attach(struct UTUN_INSTANCE *inst); -void call_video_port_detach(struct UTUN_INSTANCE *inst); -int call_video_port_open(uint64_t id, const struct call_video_caps *caps); -void call_video_port_close(uint64_t id); -int call_video_port_status(uint64_t id, struct call_video_port_status *out); -/* Неблокирующий накопительный счётчик полных принятых RX кадров текущего звонка. - * Pull не уменьшает его. Для общего запаса вычитаются показанные/отклонённые кадры. - * 0 для закрытого/другого звонка; новый open после остановки readers начинает с нуля. */ -uint64_t call_video_port_received(uint64_t id); -/* Уведомление RX без обращения к port API из callback; вызывается под mutex порта. - * 1 — установлен, 0 — звонок ещё не открыт/уже закрыт. NULL снимает callback до освобождения arg. */ -int call_video_port_set_wake(uint64_t id, void (*wake)(void *), void *arg); -int call_video_port_format(uint64_t id, const struct call_video_format *format, uint32_t bps); -int call_video_port_applied(uint64_t id, uint64_t generation, uint64_t request, uint32_t bps); -#define CALL_VIDEO_PORT_TX_FRAMES 8u -#define CALL_VIDEO_PORT_TX_BYTES (CALL_VIDEO_PORT_TX_FRAMES * CALL_VIDEO_MAX_FRAME) -/* Атомарно копирует готовую пачку одного звонка. 1 — принята целиком, 0 — mailbox занят, - * -1 — ошибка; на 0/-1 ни один кадр не принят. count: 1..CALL_VIDEO_PORT_TX_FRAMES. */ -int call_video_port_send(const struct call_video_frame *frames, unsigned count); -int call_video_port_pull(uint64_t id, struct call_video_frame *out); -void call_video_port_request_key(uint64_t id); -int call_video_port_range(uint64_t id, uint32_t minimum_bps, uint32_t maximum_bps); -int call_video_port_decoded(uint64_t id, uint64_t generation, int accepted); -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/chat/chat_attachment.h1 b/src/chat/chat_attachment.h1 deleted file mode 100644 index cd5c4ae2..00000000 --- a/src/chat/chat_attachment.h1 +++ /dev/null @@ -1,46 +0,0 @@ -/* Зашифрованные групповые вложения и ручная выдача ключей. - * Все API кроме identity — uasync-поток. Ключи, запросы и outbox локальны. - * init после media_async; quiesce до его destroy, destroy после workers. - * Отдельный router-сервис требует E2E-шифрование и подпись каждого пакета. - * Очереди переживают restart; для доставки нужен живой маршрут обеих сторон. */ -#ifndef CHAT_ATTACHMENT_H -#define CHAT_ATTACHMENT_H -#include "../media_async/attachment.h" -#include "../media_async/encrypted_file.h" -#ifdef __cplusplus -extern "C" { -#endif -struct UTUN_INSTANCE; -int chat_attachment_init(struct UTUN_INSTANCE* inst); -void chat_attachment_quiesce(struct UTUN_INSTANCE* inst); -void chat_attachment_destroy(struct UTUN_INSTANCE* inst); -/* source — собственный подготовленный файл приложения, передаётся во владение. */ -int chat_attachment_send(struct UTUN_INSTANCE* inst, const char* channel, const char* source, - const struct attachment_info* info, const char* type, const uint8_t reply[32], uint64_t request); -/* UUID из подписанного имени контейнера; принимает канонический base64-prefix тела медиа. */ -int chat_attachment_identity(const char* body, size_t length, uint8_t id[16]); -/* Связать заранее сохранённый авторский ключ с подписанным сообщением до публикации. */ -int chat_attachment_bind(struct UTUN_INSTANCE* inst, const char* channel, const uint8_t id[16], - const uint8_t message[32], const uint8_t hash[32]); -/* Учесть проверенное db_sync сообщение; обычные сообщения игнорируются. */ -int chat_attachment_observe(struct UTUN_INSTANCE* inst, const char* channel, const uint8_t message[32], - uint64_t author, const char* json, size_t length); -/* После проверенной загрузки: сохранить состояние, запросить ключ либо расшифровать. */ -void chat_attachment_downloaded(struct UTUN_INSTANCE* inst, const char* channel, const uint8_t message[32]); -/* Ручная загрузка на storage-узле также означает запрос пользовательского доступа. */ -void chat_attachment_want(struct UTUN_INSTANCE* inst, const char* channel, const uint8_t message[32]); -int chat_attachment_decide(struct UTUN_INSTANCE* inst, const char* channel, const uint8_t message[32], uint64_t peer, int approve); -struct chat_attachment_decision { - struct UTUN_INSTANCE* inst; - char channel[32]; - uint8_t message[32]; - uint64_t peer; - int approve; -}; -void chat_attachment_decision_trampoline(void* arg); -/* Канал удаляется локально: отменить очереди, стереть ключи и частные копии. */ -void chat_attachment_delete_channel(struct UTUN_INSTANCE* inst, const char* channel); -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/chat/chat_core.h1 b/src/chat/chat_core.h1 deleted file mode 100644 index 526e7fb1..00000000 --- a/src/chat/chat_core.h1 +++ /dev/null @@ -1,313 +0,0 @@ -/* - * chat_core — API каналов, сообщений, профиля и настроек одного узла. - * chat_service_start/stop управляют всем чат-сервисом поверх работающего ядра. - * Данные хранятся в общей SQLite; события для интерфейса доставляет chat_event. - * - * Все DB-операции и сетевые функции выполняются в uasync-потоке. - * Все функции per-instance: первым аргументом struct UTUN_INSTANCE*. - * GUI вызывает через gui_bridge_post_uasync() trampoline-функции, - * чей arg-структура несёт inst. - */ - -#ifndef CHAT_CORE_H -#define CHAT_CORE_H - -#include -#include -#include - -struct sqlite3; -struct UTUN_INSTANCE; - -/* ── Жизненный цикл ── */ - -/* Запустить чат поверх core_start; UTUN не требуется. Повтор допустим; 0/-1. */ -int chat_service_start(struct UTUN_INSTANCE* inst); -/* Остановить чат, сохранив ядро, UTUN и БД. Повтор допустим; вызывать вне callbacks чата. - * Отменяет доставку и ждёт native media workers; длительная задача может задержать stop. */ -void chat_service_stop(struct UTUN_INSTANCE* inst); - -/* Внутренняя часть запуска: открыть/подключить БД и загрузить каналы. 0/-1. - * Для запуска всего чат-сервиса использовать chat_service_start(). */ -int chat_core_init(struct UTUN_INSTANCE* inst, const char* db_path); -/* Освободить chat_core после остановки остальных частей чата; общая БД остаётся у ядра. */ -void chat_core_destroy(struct UTUN_INSTANCE* inst); - -/* Backfill: регистрирует уже скачанные медиафайлы (лежат на диске, но отсутствуют - * в media_files) — вызывается после загрузки каналов/сообщений при старте. */ -void chat_media_backfill(struct UTUN_INSTANCE* inst); - -/* Докачка недостающего медиа за последние storage_backfill_days дней. Проходит по - * медиасообщениям каналов и запускает загрузку для тех, чей файл отсутствует на диске. */ -void chat_media_autodownload_backfill(struct UTUN_INSTANCE* inst); - -/* Регистрирует триггер: после первого SYNC_DONE (+ дебаунс 2с) анонсирует локальные - * блоки суперузлам и запускает chat_media_autodownload_backfill. Один раз за запуск чата. */ -void chat_media_startup_backfill_init(struct UTUN_INSTANCE* inst); -void chat_media_startup_backfill_destroy(struct UTUN_INSTANCE* inst); - -/* Заимствованная БД текущего chat_core; NULL до init/после destroy. */ -struct sqlite3* chat_core_get_db(struct UTUN_INSTANCE* inst); -/* 1 — chat_core инициализирован, 0 — нет; не проверяет доступность сети. */ -int chat_core_is_initialized(struct UTUN_INSTANCE* inst); - -/* ── Отправка сообщения (GUI → uasync) ── */ - -struct chat_msg_submit { - struct UTUN_INSTANCE* inst; - char channel_id[64]; /* десятичный ID канала */ - char content_type[32]; /* тип содержимого сообщения */ - char media_src[1024]; /* исходный файл вложения */ - char media_dest[1024]; /* путь подготовленного локального файла */ - uint8_t media_copy; /* 1 = скопировать исходный файл при регистрации */ - uint8_t media_video; /* 1 = подготовить как видео (пробинг+транскод) */ - int duration_ms; /* видео: длительность (0 = неизвестно) */ - int width; /* видео: ширина */ - int height; /* видео: высота */ - uint8_t* data; /* содержимое сообщения, заимствовано обычным submit */ - uint32_t data_len; /* размер data в байтах */ - uint64_t timestamp; /* успешная отправка возвращает назначенное время */ - uint8_t message_id[32]; /* успешная обычная отправка возвращает общий ID */ - uint8_t reply_to[32]; /* общий ID оригинала в этом канале; нули = не ответ */ - uint64_t request_id; /* ненулевой ID: trampoline/media отправляет CHAT_EVT_MSG_SUBMITTED */ -}; - -/* Подписать, сохранить и разослать сообщение. req/data остаются у вызывающего. 0/-1. */ -int chat_core_submit_message(struct UTUN_INSTANCE* inst, struct chat_msg_submit* req); - -/* Отправка медиа-сообщения (вложение): src->dest (copy) или видео (transcode). */ -void chat_core_submit_media_message(struct UTUN_INSTANCE* inst, struct chat_msg_submit* req); -/* Ручная загрузка вложения; для зашифрованного файла также запрашивает ключ автора. */ -void chat_core_attachment_download(struct UTUN_INSTANCE* inst, const char* channel_id, int64_t msg_id); - -/* ── DB-операции (оставлены для интроспекции) ── */ - -/* Число локальных сообщений; 0 также при отсутствии БД или ошибке запроса. */ -uint32_t chat_core_count(struct UTUN_INSTANCE* inst, const char* ch_id); -/* Хеш записи по позиции с нуля в порядке (timestamp, node_id); hash_out — 32 байта. - * 0 = запрос выполнен (нет записи — нулевой хеш), -1 = ошибка. */ -int chat_core_chain_hash_at(struct UTUN_INSTANCE* inst, const char* ch_id, uint32_t pos, uint8_t* hash_out); -/* Список ID: count:u16, затем [длина:u8, строка]; buf_size >= 2. 0/-1. - * Списки ограничены буфером; out_len — записанные байты, числа в порядке байтов хоста. */ -int chat_core_list_channels(struct UTUN_INSTANCE* inst, uint8_t* buf, size_t buf_size, size_t* out_len); -/* Список участников: count:u16, затем node_id:u64; buf_size >= 2. 0/-1. */ -int chat_core_list_peers(struct UTUN_INSTANCE* inst, const char* ch_id, uint8_t* buf, size_t buf_size, size_t* out_len); -/* Ключи X25519/Ed25519 (по 32 байта) и список адресов из БД; buf_size >= 65. - * out_len — размер результата; 0 = прочитано, -1 = нет узла или ошибка. */ -int chat_core_load_nodeinfo(struct UTUN_INSTANCE* inst, uint64_t node_id, uint8_t* buf, size_t buf_size, size_t* out_len); - -/* ── Создание канала (GUI → uasync) ── */ - -struct chat_channel_create { - struct UTUN_INSTANCE* inst; - char channel_id[64]; - char name[128]; - uint64_t owner_node_id; - uint8_t x25519_pubkey[32]; - uint8_t x25519_privkey[32]; - uint8_t ed25519_pubkey[32]; - uint8_t ed25519_privkey[32]; - uint8_t signature[64]; -}; - -struct chat_create_auto_arg { struct UTUN_INSTANCE* inst; char name[128]; }; - -/* Подготовить локальные таблицы, группу и синхронизацию канала. Членства на других узлах не даёт. */ -void chat_core_ensure_channel_ready(struct UTUN_INSTANCE* inst, const char* ch_id); -/* Создать канал по готовым ключам и метаданным req; req остаётся у вызывающего. */ -void chat_core_create_channel(struct UTUN_INSTANCE* inst, struct chat_channel_create* req); -void chat_core_create_channel_trampoline(void* arg); -/* Сгенерировать ключи и создать канал, добавив себя владельцем. */ -void chat_core_create_channel_auto(struct UTUN_INSTANCE* inst, const char* name); -void chat_core_create_channel_auto_trampoline(void* arg); - -/* ── Локальное удаление канала (GUI → uasync) ── */ - -struct chat_delete_channel_req { - struct UTUN_INSTANCE* inst; - char ch_id[64]; -}; - -/* Удалить канал с этого устройства: отмена медиа-загрузок, удаление группы - * (соединения/синк), db_sync инстанса, таблиц msg_ и peers_, медиафайлов и - * merkle-хешей. Работает в uasync-потоке. Другие узлы канал не теряют. */ -void chat_core_delete_channel(struct UTUN_INSTANCE* inst, const char* ch_id); -void chat_core_delete_channel_trampoline(void* arg); - -/* ── Утилиты ── */ - -/* Задать локальный ID в контексте чата; ключи и идентичность ядра не меняет. */ -void chat_core_set_my_node_id(struct UTUN_INSTANCE* inst, uint64_t node_id); -/* Сохранить имя узла и обновить собственные member-записи каналов. */ -void chat_core_update_my_name(struct UTUN_INSTANCE* inst, const char* name); - -struct update_my_name_arg { struct UTUN_INSTANCE* inst; char name[128]; }; -void chat_core_update_my_name_trampoline(void* arg); -/* Обновить адреса topo_node и собственные member-записи каналов. */ -void chat_core_sync_my_addresses(struct UTUN_INSTANCE* inst); -/* При изменении своего userinfo в каналах увеличить update_ts, подписать и запустить sync. - * Адреса обновляются отдельно через topo_node; подпись member-блока их не содержит. */ -void chat_core_update_my_member(struct UTUN_INSTANCE* inst); - -/* Сохранение key-value в ui_state (вызывается из uasync-потока) */ -void chat_core_save_ui_state(struct UTUN_INSTANCE* inst, const char* key, const char* value); - -/* Per-channel «play sound on new message» (ui_state: ch__sound_on_message, default 1=on). - * set — сохраняет и рассылает пирам через chat_sync (троттлинг db_sync на сервере). */ -int chat_core_get_sound_on_message(struct UTUN_INSTANCE* inst, const char* ch_id); -void chat_core_set_sound_on_message(struct UTUN_INSTANCE* inst, const char* ch_id, int on); - -struct chat_sound_arg { struct UTUN_INSTANCE* inst; char ch_id[64]; int on; }; -void chat_core_set_sound_on_message_trampoline(void* arg); - -struct save_ui_state_arg { struct UTUN_INSTANCE* inst; char data[1024]; }; -void chat_core_save_ui_state_trampoline(void* arg); - -/* Установка chat-настройки (name=value) через chat_setting API (GUI → uasync) */ -void chat_core_set_setting(struct UTUN_INSTANCE* inst, const char* name, const char* value); - -struct chat_setting_arg { struct UTUN_INSTANCE* inst; char data[256]; }; -void chat_core_set_setting_trampoline(void* arg); - -/* Запуск подключения к узлам выбранного канала (GUI → uasync) */ -void chat_core_connect_channel(struct UTUN_INSTANCE* inst, const char* ch_id); -void chat_core_connect_channel_trampoline(void* arg); - -/* Однократная попытка подключения к конкретному узлу канала (GUI → uasync) */ -void chat_core_connect_node(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t node_id); -void chat_core_connect_node_trampoline(void* arg); - -struct chat_connect_node_req { - struct UTUN_INSTANCE* inst; - char ch_id[64]; - uint64_t node_id; -}; - -/* Трамплин для gui_bridge_post_uasync (GUI → uasync) */ -void chat_core_submit_trampoline(void* arg); - -/* Трамплин для ручного запуска загрузки медиа (JNI → uasync) */ -struct attachment_dl_req { - struct UTUN_INSTANCE* inst; - char channel_id[64]; - int64_t msg_id; -}; -void chat_core_attachment_download_trampoline(void* arg); - -/* Обновление local_attrs для записи (вызывается из uasync-потока) */ -int chat_core_update_local_attrs(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t ts, - const uint8_t* author_sig, - const char* local_attrs_json); - -/* Пометить голосовое сообщение как проигранное (добавляет "pl":1 в local_attrs) */ -void chat_core_mark_voice_played(struct UTUN_INSTANCE* inst, const char* channel_id, uint64_t ts, - uint64_t author_node_id); -void chat_core_mark_voice_played_trampoline(void* arg); - -struct voice_played_req { - struct UTUN_INSTANCE* inst; - char channel_id[64]; - uint64_t ts; - uint64_t author_node_id; -}; - -/* Сбор статуса (NTP + connections) и отправка в GUI. arg = struct UTUN_INSTANCE* (inst) */ -void chat_core_collect_status_trampoline(void* arg); - -/* Лёгкий запрос нагрузки uasync для GUI. arg = inst, ответ CHAT_EVT_CPU_LOAD. */ -void chat_core_collect_cpu_load_trampoline(void* arg); - -/* Сбор списка ETCP-соединений и отправка в GUI (binary packet). arg = inst */ -void chat_core_collect_conn_list_trampoline(void* arg); - -struct chat_node_arg { struct UTUN_INSTANCE* inst; uint64_t node_id; }; - -/* Сбор полных метрик одного соединения (arg = u_malloc struct chat_node_arg) */ -void chat_core_collect_conn_metrics_trampoline(void* arg); - -/* Сбор live-снапшота для панели деталей участника (arg = u_malloc struct chat_node_arg) */ -void chat_core_collect_member_detail_trampoline(void* arg); - -/* ── Headless CLI API ── */ - -/* Список каналов с метаданными в JSON: [{id,name,owner_id,owner_name,peers,msgs,online}] */ -int chat_core_get_channels_json(struct UTUN_INSTANCE* inst, char* buf, size_t buf_size, size_t* out_len); - -/* Сообщения канала в JSON: [{id,ts,author_id,author_name,content_type,data,local_attrs}]. - * От новых к старым; count<=0 — до 100 записей, offset — сколько пропустить. */ -int chat_core_get_messages_json(struct UTUN_INSTANCE* inst, const char* ch_id, int count, int offset, - char* buf, size_t buf_size, size_t* out_len); - -/* Мемберы в JSON: [{node_id,name,online,connected,adm_tags,x25519,ed25519,addrs}]. - * connected означает наличие транспорта в реестре, а не его UP или готовность группы. */ -int chat_core_get_members_json(struct UTUN_INSTANCE* inst, const char* ch_id, char* buf, size_t buf_size, size_t* out_len); - -/* Имя узла из таблицы nodes */ -int chat_core_get_node_name(struct UTUN_INSTANCE* inst, uint64_t node_id, char* out, size_t sz); - -/* Ссылка на описание avatars/.json внутри дерева своего UID/канала. server=0 удаляет ссылку. */ -int chat_core_set_my_avatar(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t server, const char* file); -int chat_core_name_userinfo(const char* name, char* out, size_t capacity); -int chat_core_get_my_profile(struct UTUN_INSTANCE* inst, const char* channel, char* out, size_t capacity, - uint8_t signature[64], uint64_t* timestamp); -/* Одно подписанное обновление нескольких собственных строковых опций. NULL value удаляет ключ. - * Остальные поля сохраняются; имя/аватар меняются своими API. Ошибка не меняет БД/Merkle. - * Вызов только в uasync-потоке, вне внешней SQLite-транзакции. */ -struct chat_profile_option { const char* key; const char* value; }; -int chat_core_set_my_profile_options(struct UTUN_INSTANCE* inst, const char* channel, - const struct chat_profile_option* options, size_t count); -struct chat_avatar_req { - struct UTUN_INSTANCE* inst; - uint64_t id, group, server; - char file[70]; -}; -void chat_core_set_my_avatar_trampoline(void* arg); - -/* ── Редактирование adm_tags (владелец канала) ── */ - -#define CHAT_MEMBER_TAGS_MAX_KEYS 16 -#define CHAT_MEMBER_TAGS_KEY_SZ 64 - -struct chat_member_tags; - -/* Загрузить текущие adm_tags мембера в память. Возвращает NULL если мембера нет. */ -struct chat_member_tags* chat_member_tags_load(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t node_id); - -/* Установить ключ. val=NULL → удалить ключ. ver — особый, автоинкремент при commit. */ -int chat_member_tags_set(struct chat_member_tags* t, const char* key, const char* val); - -/* Получить значение ключа. Возвращает NULL если ключ не найден. */ -const char* chat_member_tags_get(struct chat_member_tags* t, const char* key); - -/* Заменить все теги данными из JSON-строки (плоский, строковые значения). */ -int chat_member_tags_replace(struct chat_member_tags* t, const char* json); - -/* Сохранить: сериализовать в JSON, инкрементировать ver, подписать канальным Ed25519, - * записать через member_sync_put() → синхронизируется всем. */ -int chat_member_tags_commit(struct UTUN_INSTANCE* inst, struct chat_member_tags* t); - -/* Освободить без сохранения. */ -void chat_member_tags_free(struct chat_member_tags* t); - -/* Трамплин для gui_bridge: arg = struct chat_member_tags_req* (доверенная память). */ -struct chat_member_tags_req { - struct UTUN_INSTANCE* inst; - char ch_id[64]; - uint64_t node_id; - char json[512]; -}; -void chat_member_tags_commit_trampoline(void* arg); - -/* ── Передача прав админа (владелец → другому узлу) ── */ - -/* Передать оба канальных privkey выбранному узлу (encrypted+signed через etcp_router). */ -void chat_core_transfer_admin(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t target_node_id); -void chat_core_transfer_admin_trampoline(void* arg); - -struct chat_transfer_admin_req { - struct UTUN_INSTANCE* inst; - char ch_id[64]; - uint64_t target_node_id; -}; - -#endif /* CHAT_CORE_H */ diff --git a/src/chat/chat_event.h1 b/src/chat/chat_event.h1 deleted file mode 100644 index 143b58cf..00000000 --- a/src/chat/chat_event.h1 +++ /dev/null @@ -1,104 +0,0 @@ -/* - * chat_event.h — система нотификаций о событиях чата - * - * Производители (chat_core, chat_sync, ...) вызывают chat_event_post(). - * Потребители (chatgui, headless, будущий HTTP API) регистрируют один обработчик. - * - * Без обработчика — данные логируются через DEBUG_DEBUG + log_dump. - * Все вызовы — из uasync-потока. - */ - -#ifndef CHAT_EVENT_H -#define CHAT_EVENT_H - -#include -#include - -struct UTUN_INSTANCE; - -#ifdef __cplusplus -extern "C" { -#endif - -/* Типы событий (совпадают с GUI_EVT_* в gui_bridge.h для прямой совместимости) */ -#define CHAT_EVT_MSG_RECEIVED 1 /* [ch_id_len:1][ch_id:var][author_node_id:8][initial_sync:1] */ -#define CHAT_EVT_CONNECT_RESULT 2 /* [node_id:8][result:4][channel_id:8] */ -#define CHAT_EVT_NEW_PEER 3 /* [node_id:8] */ -#define CHAT_EVT_CHANNEL_UPDATED 4 /* [ch_id_len:1][ch_id:var] */ -#define CHAT_EVT_MEMBERS_CHANGED 5 /* [ch_id_len:1][ch_id:var] */ -#define CHAT_EVT_MY_NODE_ID 6 /* [node_id:8] */ -#define CHAT_EVT_AUTO_CONNECT_STATUS 7 /* [status:1][total_tried:2][node_count:2][success:2] */ -#define CHAT_EVT_CHANNEL_PEERS_ONLINE 8 /* [ch_id_len:1][ch_id:var][online_count:2] */ -#define CHAT_EVT_DB_READY 9 /* data: none */ -#define CHAT_EVT_STATUS_REFRESH 10 /* data: status text */ -#define CHAT_EVT_KEYS_GENERATED 11 /* [pub_hex:64] */ -#define CHAT_EVT_SERVICE_STARTED 12 /* data: none */ -#define CHAT_EVT_SERVICE_STOPPED 13 /* data: none */ -#define CHAT_EVT_ATTACHMENT_DOWNLOADED 14 /* [ch_id_len:1][ch_id:var][msg_id:8] */ -#define CHAT_EVT_DOWNLOAD_PROGRESS 15 /* [ch_id_len:1][ch_id:var][msg_id:8][blocks_done:4][num_blocks:4] */ -#define CHAT_EVT_NODEINFO_UPDATED 16 /* [node_id:8][conn_presence:1][conn_up:1][best_rtt:2][bgp_rtt:2][bgp_nodes:2] */ -#define CHAT_EVT_LINK_STATUS_CHANGED 17 /* [peer_id:8][link_id:1][state:1][status:1][links_up:1][initialized:1] */ -#define CHAT_EVT_INVITE_RECEIVED 18 /* [ch_id_len:1][ch_id][name_len:1][name][inviter_node_id:8][inviter_name_len:1][inviter_name] */ -#define CHAT_EVT_LOCAL_SOCKETS 19 /* JSON: [{"si":id,"nm":"...","ad":"...","po":port,"pt":"TCP|UDP","st":0|1|2,"lk":n},...] */ -#define CHAT_EVT_CONN_LIST 20 /* [count:2][entry:46B]* — список ETCP-соединений */ -#define CHAT_EVT_CONN_METRICS 21 /* текст — полный дамп метрик выбранного соединения */ -#define CHAT_EVT_MEMBER_DETAIL 22 /* [node_id:8][flags:1][own_tcp_active:2][links...][socks...] — live-снапшот для панели деталей участника */ -#define CHAT_EVT_MEMBER_LIST 23 /* [ch_id_len:1][ch_id:var][count:2][member:CHAT_MEMBER_DISPLAY_SIZE]* */ -#define CHAT_EVT_MEMBER_UPDATED 24 /* [ch_id_len:1][ch_id:var][count:1][member:CHAT_MEMBER_DISPLAY_SIZE] */ -#define CHAT_EVT_MEMBER_REMOVED 25 /* [ch_id_len:1][ch_id:var][node_id:8] — мембер удалён из канала */ -#define CHAT_EVT_BGP_INFO 26 /* текст: "rtt:XXms hop:X via bgp: [XXXX] name1 [XXXX] name2" */ -#define CHAT_EVT_CONNECTING_NODES 27 /* [ch_id_len:1][ch_id:var][count:2][node_id:8]* */ -#define CHAT_EVT_ADMIN_KEY_RECEIVED 28 /* [ch_id_len:1][ch_id:var][from_node_id:8] — получен канальный ключ (стал совладельцем) */ -#define CHAT_EVT_INVITE_LINK_READY 29 /* [ch_id_len:1][ch_id:var][request_id:8][link_len:2][link:var] — пустой link = ошибка */ -#define CHAT_EVT_INVITE_CANDIDATES 30 /* [ch_id_len:1][ch_id:var][auto_node_id:8][count:2][node_id:8]* — достижимые узлы для invite */ -#define CHAT_EVT_CHANNEL_DELETED 31 /* [ch_id_len:1][ch_id:var] — канал удалён локально */ -#define CHAT_EVT_DM_MSG_RECEIVED 32 /* [conv_id_len:1][conv_id:var][author_node_id:8] */ -#define CHAT_EVT_DM_CONV_UPDATED 33 /* [conv_id_len:1][conv_id:var][generation:8LE] — беседа создана/изменена */ -#define CHAT_EVT_CALL_INCOMING 34 /* [ch_id_len:1][ch_id:var][caller_node_id:8][call_id:8] */ -#define CHAT_EVT_CALL_RINGING 35 /* [call_id:8] */ -#define CHAT_EVT_CALL_ACCEPTED 36 /* [call_id:8] */ -#define CHAT_EVT_CALL_ENDED 37 /* [call_id:8][reason:1] */ -#define CHAT_EVT_CALL_DECLINED 38 /* [call_id:8][reason:1] */ -#define CHAT_EVT_CALL_STATS 39 /* [call_id:8][rtt:2][buffer:2][tempo:2][dropped:2][underruns:2][min:2][max:2][reserve:2] */ -#define CHAT_EVT_CALL_ERROR 40 /* [call_id:8][err:1][text:var] */ -#define CHAT_EVT_DM_MESSAGES 41 /* [conv_id_len:1][conv_id:var][JSON:utf8] — сообщения беседы и состояния доставки */ -#define CHAT_EVT_CALL_PATH 42 /* [call_id:8][text:var] — BGP-маршрут до пира звонка */ -#define CHAT_EVT_RADIO_TALK 43 /* [group_id:8][src_node_id:8][stream_id:2][on:1] — кто-то начал/закончил говорить */ -#define CHAT_EVT_CALL_CONNECTION 44 /* [call_id:8][CONN_TYPE:1][next_hop_node_id:8] — текущий путь отправки звонка */ -#define CHAT_EVT_DM_CONVERSATIONS 45 /* [JSON:utf8] — последние 200 личных бесед */ -#define CHAT_EVT_ATTACHMENT_PREPARATION 46 /* [target_len:1][target:var][job_uuid:16][state:1], 0=start 1=ready 2=failed */ - -#define CHAT_EVT_DM_CALL_ROUTE 47 /* [conv_id_len:1][conv_id:var][peer_node_id:8][group_id:8], 0 = нет BGP-пути */ -#define CHAT_EVT_DM_INVITE_RESULT 48 /* [request_id:8][result:4][peer_node_id:8][conv_id:8][generation:8], dm_invite_result */ -#define CHAT_EVT_MEMBER_FILES_RESPONSE 49 /* [group:8LE][server:8LE][mf wire response] */ -#define CHAT_EVT_MEMBER_FILES_TRANSFER 50 /* id/group/server/owner/done/total:8LE,status:2LE,state:1 */ -#define CHAT_EVT_AVATAR_RESULT 51 /* request_id/group:8LE, failed:1; результат публикации ссылки профиля */ -#define CHAT_EVT_GROUP_AVATAR_RESULT 52 /* request_id/group:8LE, failed:1; результат публикации аватарки группы */ -#define CHAT_EVT_FEEDBACK_CHANGED 53 /* [channel_len:1][channel][message_id:32][kind:1] — состояние после commit */ -#define CHAT_EVT_FEEDBACK_RESULT 54 /* [request_id:8LE][success:1][JSON] — результат команды интерфейса */ -#define CHAT_EVT_RADIO_MUTE_RESULT 55 /* [group_id:8LE][node_id:8LE][success:1] — локальный переключатель рации */ -#define CHAT_EVT_MSG_SUBMITTED 56 /* [request_id:8LE][success:1] — результат локального сохранения сообщения */ -#define CHAT_EVT_CPU_LOAD 57 /* [valid:1][average_percent:1] — CPU потока uasync, среднее за секунду, 0..100 */ -#define CHAT_EVT_STREAM_SOURCES 58 /* [group_id:8BE][valid:1][JSON:utf8] — доступные публикации выбранного канала */ -#define CHAT_EVT_DM_DELETE_RESULT 59 /* [request:8LE][conv:8LE][generation:8LE][success:1] — после транзакции */ -#define CHAT_EVT_ATTACHMENT_KEYS_CHANGED 60 /* [channel_len:1][channel][success?:1], без секретов; success — результат команды GUI */ - -#define CHAT_EVT_LOCAL_DEVICES 61 /* [count:2BE][node:8BE,name_len:1,name:UTF8]* */ -#define CHAT_EVT_LOCAL_INVITE 62 /* [node:8BE][name_len:1][name:UTF8][invite_link:UTF8], без NUL */ -#define CHAT_EVT_LOCAL_DELIVERY 63 /* [request:8BE][node:8BE][status:1], local_delivery_status, не результат JOIN */ -#define CHAT_EVT_LOCAL_DISCOVERY_ACTIVE 64 /* [active:1], Android MulticastLock */ -#define CHAT_EVT_RADIO_CALL 65 /* [id:8LE][group:8LE][peer:8LE][state:1][reason:1][incoming:1], radio_call.h */ -#define CHAT_EVT_CALL_PHONE_BUSY 66 /* [id:8LE][reserved:1]; вызывающий выбирает продолжить либо завершить */ - -typedef void (*chat_event_handler_fn)(struct UTUN_INSTANCE* inst, int type, const uint8_t* data, int len); - -void chat_event_set_handler(struct UTUN_INSTANCE* inst, chat_event_handler_fn handler); -void chat_event_post(struct UTUN_INSTANCE* inst, int type, const uint8_t* data, int len); -void chat_event_attachment(struct UTUN_INSTANCE* inst, int is_dm, const char* target, const uint8_t id[16], int state); -/* request_id=0 отключает подтверждение; вызывается один раз после сохранения либо ошибки подготовки. */ -void chat_event_submitted(struct UTUN_INSTANCE* inst, uint64_t request_id, int success); - -#ifdef __cplusplus -} -#endif -#endif /* CHAT_EVENT_H */ diff --git a/src/chat/group_avatar.h1 b/src/chat/group_avatar.h1 deleted file mode 100644 index 5237c4d0..00000000 --- a/src/chat/group_avatar.h1 +++ /dev/null @@ -1,32 +0,0 @@ -/* Подписанная аватарка канала: SQLite, максимум 16 КиБ, router-блоки до 4 КиБ. - * Все API/callbacks — uasync; данные публикуются только после полной проверки подписи. */ -#ifndef GROUP_AVATAR_H -#define GROUP_AVATAR_H -#include -#include -struct UTUN_INSTANCE; -struct sqlite3; -int group_avatar_schema_init(struct sqlite3* db); -#define GROUP_AVATAR_MAX 16384 -#define GROUP_AVATAR_BLOCK 4096 -struct group_avatar_record { - uint64_t version; - uint16_t size; - uint8_t hash[32], signature[64], data[GROUP_AVATAR_MAX]; -}; -int group_avatar_init(struct UTUN_INSTANCE* inst); -void group_avatar_destroy(struct UTUN_INSTANCE* inst); -void group_avatar_cancel_group(struct UTUN_INSTANCE* inst, uint64_t group); -int group_avatar_get(struct UTUN_INSTANCE* inst, uint64_t group, struct group_avatar_record* record); -/* 1=изменено, 0=прежняя/старая запись; <0 — ошибка. */ -int group_avatar_apply(struct UTUN_INSTANCE* inst, uint64_t group, const struct group_avatar_record* record); -/* Публикация своей картинки требует приватный Ed25519 ключ канала. size=0 — подписанное удаление. */ -int group_avatar_set(struct UTUN_INSTANCE* inst, uint64_t group, const uint8_t* data, size_t size); -struct group_avatar_gui_request { - struct UTUN_INSTANCE* inst; - uint64_t id, group; - uint16_t size; - uint8_t data[GROUP_AVATAR_MAX]; -}; -void group_avatar_gui_set(void* arg); -#endif diff --git a/src/media_delivery/media_delivery.h1 b/src/media_delivery/media_delivery.h1 deleted file mode 100644 index 665c1f62..00000000 --- a/src/media_delivery/media_delivery.h1 +++ /dev/null @@ -1,175 +0,0 @@ -/* media_delivery — канальные медиафайлы: поиск держателей блоков, выдача/relay и репликация доступности. - * Суперузлы обмениваются block_availability, держатели отдают подписанные блоки, media_download собирает файл. - * init создаёт per-instance состояние, bind подключает протокол к router; destroy отменяет сетевую работу. - * Все операции — uasync-поток; долгие файловые/crypto-задачи выполняет media_async. - * E2E-файлы личных бесед используют dm_media/file_transfer, а не канальную таблицу доступности. */ -#ifndef MEDIA_DELIVERY_H -#define MEDIA_DELIVERY_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include "../lib/ll_queue.h" -#include "../lib/sqlite3.h" - -struct UTUN_INSTANCE; - -/* ── константы ── */ - -#define MEDIA_MAX_REPL_INFLIGHT 4 -#define MEDIA_REPL_TIMEOUT_TB 20000 // начальный таймаут 2s (0.1ms) -#define MEDIA_REPL_TIMEOUT_MAX_TB 6000000 // макс 10 min -#define MEDIA_MAX_DOWNLOADS 10 -#define MEDIA_QUERY_TIMEOUT_TB 20000 // таймаут QUERY 2s -#define MEDIA_HAVE_BLOCK_TIMEOUT_TB 20000 // таймаут HAVE_BLOCK_ACK 2s -#define MEDIA_RECONNECT_COOLDOWN_TB 360000000 // 1 час (0.1ms) -#define MEDIA_HELLO_TIMEOUT_TB 20000 // таймаут SUPER_HELLO 2s -#define MEDIA_DL_STALL_TIMEOUT_TB 20000 // таймаут простоя загрузки 2s (0.1ms) -#define MEDIA_DL_MAX_ATTEMPTS 3 // попыток на блок до ошибки - -/* ── структуры ── */ - -struct media_super_peer { - struct ll_entry ll; // индекс по peer_node_id (8 байт) - uint64_t peer_node_id; - uint64_t group_id; // CHAT-группа, в которой установлена связь с пиром - uint64_t peer_last_recv_id; // что пир говорит он получил от нас (из SUPER_HELLO / SUPER_ACK) - uint32_t timeout_tb; // текущий таймаут (растёт при ошибках) - uint8_t inflight_count; // пакетов в полёте (макс 4) - uint8_t connected; // 1 = прямое подключение установлено - uint8_t hello_done; // 1 = SUPER_HELLO обмен завершён, можно реплицировать - void* timeout_timer; // таймер ретрансмита - struct CONN_MGR_HANDLE* connection; // собственное CM-владение; восстановлением пути управляет CM - struct media_delivery_ctx* md; // обратная ссылка -}; - -/* per-file download tracking (source node admission control) */ - -struct md_file_load { - struct ll_entry ll; // индекс по media_id (16 байт) - uint8_t media_id[16]; - int active_downloads; // текущее число исходящих стримов - uint64_t downloader_ids[10]; // кто сейчас качает (для редиректа) -}; - -/* - * block_availability: жизненный цикл записей и гарантия уникальности id - * - * Каждое событие создаёт новую запись с новым id (AUTOINCREMENT). - * Старая запись удаляется — id НЕ переиспользуется. - * Это критично для репликации: курсор super_sync.last_recv_id - * всегда монотонно растёт и не пропускает события. - * - * BLOCK_PROCESSING (subcmd 0x10): - * md_ba_insert(... , status=0) — чистый INSERT, новый id=X. - * - * HAVE_BLOCK (subcmd 0x06): - * md_ba_complete_block(): - * 1. DELETE FROM block_availability WHERE block_uuid=? AND node_id=? AND status=0 - * (удаляет processing-запись id=X, если была) - * 2. Если completed уже есть → no-op (возврат 0) - * 3. INSERT ... status=1 — новый id=Y. - * - * SUPER_REPL (subcmd 0x08): - * Принимающая сторона: - * - status=0: INSERT OR IGNORE (дубликаты при репликации — норма) - * - status=1: md_ba_complete_block() — та же логика что HAVE_BLOCK - * - * Итог: processing id=X удаляется, completed вставляется с новым id=Y>X. - * Репликация через md_ba_get_since(id > last_recv_id) всегда видит Y. - */ - -struct media_served_node { - struct ll_entry ll; // индекс по node_id (8 байт) - uint64_t node_id; - uint64_t group_id; - int64_t joined_at; // timestamp регистрации -}; - -#define MD_MAX_RELAY_DOWNSTREAM 5 - -struct relay_downstream { - uint64_t node_id; - uint64_t group_id; - uint64_t sent_offset; // сколько байт уже отправлено этому пиру - struct queue_waiter_handle waiter; -}; - -struct relay_block_ctx { - struct ll_entry ll; // индекс по block_id (16 байт) - uint8_t block_id[16]; - uint8_t media_id[16]; - uint32_t chunk; - uint64_t file_offset; // всего байт получено от апстрима (размер .chunk_N) - char chunk_file[2048]; // путь к .chunk_N файлу для relay-чтения - struct relay_downstream downstream[MD_MAX_RELAY_DOWNSTREAM]; - int downstream_count; - struct UTUN_INSTANCE* inst; -}; - -struct stream_ctx; -struct relay_fwd_ctx; -struct media_delivery_ctx { - struct stream_ctx* streams; - struct relay_fwd_ctx* forwards; - uint64_t self_node_id; - int initialized; - uint8_t is_supernode; // из adm_tags в peers_* - uint8_t active_streams; // текущее число исходящих стримов (admission) - uint8_t max_downloads_per_file; // лимит параллельных загрузок с одного файла (source node), default 3 - uint8_t stream_completed; // 1 = хотя бы один стрим завершился (для тестов) - uint8_t streams_started; // монотонный счётчик запущенных стримов (для тестов) - int dl_stall_timeout_tb; // таймаут простоя загрузки (по умолч. MEDIA_DL_STALL_TIMEOUT_TB) - int dl_max_attempts; // попыток на блок (по умолч. MEDIA_DL_MAX_ATTEMPTS) - sqlite3* db; // = inst->topo_sqlite_db (кешируем для удобства) - struct ll_queue* served_nodes; // media_served_node — только суперузел - struct ll_queue* super_peers; // media_super_peer — только суперузел - struct ll_queue* downloads; // media_download — активные загрузки - struct ll_queue* relay_blocks; // relay_block_ctx — relay в процессе загрузки - struct ll_queue* file_loads; // md_file_load — per-file download count (source node) - struct UTUN_INSTANCE* inst; -}; - -int media_delivery_init(struct UTUN_INSTANCE* inst); -void media_delivery_destroy(struct UTUN_INSTANCE* inst); -int media_delivery_bind(struct UTUN_INSTANCE* inst); -void media_delivery_set_supernode(struct UTUN_INSTANCE* inst, int is_supernode); -void media_delivery_stream_done(struct UTUN_INSTANCE* inst); - -/* Автор анонсирует свои блоки суперузлам CHAT-группы (HAVE_BLOCK), чтобы первый - * скачивающий мог найти держателя через QUERY. Вызывается после регистрации медиа. */ -void media_delivery_announce_media(struct UTUN_INSTANCE* inst, uint64_t group_id, - const uint8_t* media_id, const uint8_t* block_ids, - int num_blocks); - -/* Отправить один HAVE_BLOCK суперузлу (подпись Ed25519 + md_send). Общий helper - * для announce_media / announce_local_blocks / media_download. */ -void media_delivery_send_have_block(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst_node_id, - const uint8_t* media_id, const uint8_t* block_id, uint32_t chunk); - -/* Переанонсировать суперузлам ВСЕ локальные блоки (media_files WHERE node_id=self). - * Вызывается при старте после синхронизации, чтобы суперузел восстановил свой - * block_availability для уже скачанных ранее медиа. Идемпотентно на суперузле. */ -void media_delivery_announce_local_blocks(struct UTUN_INSTANCE* inst); - -/* Отменить всё активное, что связано с каналом (локальное удаление канала): - * загрузки с group_id, их relay-контексты и super_peers этой группы. */ -void media_delivery_cancel_channel(struct UTUN_INSTANCE* inst, uint64_t group_id); - -/* relay block context helpers (used by media_download.c) */ -struct relay_block_ctx* md_relay_find(struct media_delivery_ctx* md, const uint8_t* block_id); -struct relay_block_ctx* md_relay_add(struct media_delivery_ctx* md, - const uint8_t* block_id, const uint8_t* media_id, uint32_t chunk); -void md_relay_remove(struct media_delivery_ctx* md, const uint8_t* block_id); - -/* file_load helpers (per-file source download tracking) */ -struct md_file_load* md_file_load_find(struct media_delivery_ctx* md, const uint8_t* media_id); -int md_file_load_inc(struct media_delivery_ctx* md, const uint8_t* media_id, uint64_t node_id); -void md_file_load_dec(struct media_delivery_ctx* md, const uint8_t* media_id, uint64_t node_id); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/media_delivery/media_index.h1 b/src/media_delivery/media_index.h1 deleted file mode 100644 index b9cebadc..00000000 --- a/src/media_delivery/media_index.h1 +++ /dev/null @@ -1,67 +0,0 @@ -/* media_index — индекс блоков канального файла в SQLite media_files: UUID, SHA256, Ed25519-подписи и location. - * init создаёт таблицу; register_async копирует/хеширует/подписывает файл в worker, затем commit и callback в uasync. - * db/ma/ua заимствованы и должны жить до завершения; доступ к БД выполняется в потоке ядра. - * Результат callback заимствован только до возврата. result_free освобождает block_ids/block_sigs, но не саму структуру. */ -#ifndef MEDIA_INDEX_H -#define MEDIA_INDEX_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -struct media_async; -struct UASYNC; - -#define MEDIA_ID_SIZE 16 -#define MEDIA_HASH_SIZE 32 - -struct media_index_result { - uint8_t media_id[16]; - uint8_t content_hash[32]; - int64_t file_size; - int64_t block_size; - int num_blocks; - uint8_t* block_ids; // num_blocks * 16 - uint8_t* block_sigs; // num_blocks * 64 -}; - -int media_index_init(sqlite3* db); - -int media_index_commit( - sqlite3* db, const struct media_index_result* result, - uint64_t node_id, const uint8_t* ed25519_privkey, - const char* chat_id, const char* dest_path, const char* media_base); - -/* Зарегистрировать скачанный блок в media_files (location — путь к собранному файлу), - * чтобы узел мог отдавать его как держатель. node_sign = нули (при отдаче не проверяется). */ -int media_index_register_downloaded(sqlite3* db, const uint8_t* media_id, const uint8_t* block_id, - const uint8_t* content_hash, const char* chat_id, - const char* location, uint64_t node_id, - int64_t file_size, int64_t chunk_size, int chunk, int64_t offset); - -/* Callback может быть синхронным при отказе запуска. err=0 даёт result, иначе result=NULL. */ -void media_index_register_async( - struct media_async* ma, struct UASYNC* ua, sqlite3* db, - uint64_t node_id, const uint8_t* ed25519_privkey, - const char* chat_id, - const char* src_path, const char* dest_path, int copy_file, - const char* media_base, - void (*cb)(void* arg, int err, const struct media_index_result* result), - void* cb_arg); - -int media_index_generate_uuid(uint8_t uuid_out[16]); -void media_index_result_free(struct media_index_result* result); -int media_calc_block_size(uint64_t file_size); - -/* Удалить медиа канала (локальное удаление канала): стереть файлы на диске - * (media_base + location) и строки media_files с chat_id. Возвращает 0/ошибка. */ -int media_index_delete_channel(sqlite3* db, const char* chat_id, const char* media_base); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/member_files/member_files.h1 b/src/member_files/member_files.h1 deleted file mode 100644 index c1ce2f6b..00000000 --- a/src/member_files/member_files.h1 +++ /dev/null @@ -1,56 +0,0 @@ -/* Хранилище участников и асинхронный клиент поверх подписанного/зашифрованного router. - * Все API — uasync. callback получает заимствованный response ровно один раз; операция - * уже освобождена. NULL при отказе запуска, callback не вызывается. request копируется. - * quiesce запрещает новые команды и отменяет producers; destroy вне callbacks ждёт - * собственный дисковый поток до удаления CHAT-групп. Cancel не удаляет опубликованные файлы. - * GUI-команды используют trampolines; результат — CHAT_EVT_MEMBER_FILES_RESPONSE/TRANSFER. */ -#ifndef MEMBER_FILES_H -#define MEMBER_FILES_H -#include "protocol.h" -#ifdef __cplusplus -extern "C" { -#endif -struct UTUN_INSTANCE; -struct mf_pending; -typedef void (*mf_response_fn)(void* arg, const struct mf_message* response); -int member_files_init(struct UTUN_INSTANCE* inst); -void member_files_quiesce(struct UTUN_INSTANCE* inst); -void member_files_destroy(struct UTUN_INSTANCE* inst); -void member_files_cancel_group(struct UTUN_INSTANCE* inst, uint64_t group); -struct mf_pending* member_files_request(struct UTUN_INSTANCE* inst, uint64_t group, uint64_t server, - const struct mf_message* request, mf_response_fn callback, void* arg); -void member_files_cancel(struct mf_pending* pending); -void member_files_cancel_request_id(struct UTUN_INSTANCE* inst, uint64_t id); -/* 1 — действующий мембер; storage!=0 дополнительно требует подписанную роль хранителя. */ -int member_files_member(struct UTUN_INSTANCE* inst, uint64_t group, uint64_t node, int storage); - -struct mf_gui_request { struct UTUN_INSTANCE* inst; uint64_t group, server; struct mf_message message; }; -void member_files_gui_request(void* arg); - -struct mf_transfer_request { - struct UTUN_INSTANCE* inst; - uint64_t id, group, server, owner; - uint64_t max_bytes; // 0 — без лимита; проверяется до открытия локального файла и передачи данных. - int upload; - uint8_t version[16]; - char remote[MF_PATH_MAX + 1], local[MF_PATH_MAX + 1]; -}; - -struct mf_transfer; -struct mf_transfer_progress { uint64_t id, done, total; uint16_t status; uint8_t finished; }; -typedef void (*mf_transfer_fn)(void* arg, const struct mf_transfer_progress* progress); -// Один handle на файл; до 16 клиентских передач одновременно, включая upload/download к одному пиру. -// Все вызовы/callbacks — uasync. id=0 выбирает случайный ID. NULL: отказ запуска, callback не вызывается. -// finished приходит ровно один раз после закрытия/публикации; handle уже освобождён до callback. -// Прогресс заимствован на время callback. Cancel асинхронно ждёт свой I/O и не затрагивает другие handles. -struct mf_transfer* member_files_transfer_start(const struct mf_transfer_request* request, mf_transfer_fn callback, void* arg); -void member_files_transfer_cancel(struct mf_transfer* transfer); -/* id выбирает вызывающий. События: id/group/server/owner/done/total:8LE, status:2LE,state:1; - * state=1 progress, 2 finished. Загрузка/скачивание выполняет общий клиент, без Qt I/O. */ -void member_files_gui_transfer(void* arg); -struct mf_cancel_request { struct UTUN_INSTANCE* inst; uint64_t id; }; -void member_files_gui_cancel(void* arg); -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/routing_layer/multicast.h1 b/src/routing_layer/multicast.h1 deleted file mode 100644 index a0900568..00000000 --- a/src/routing_layer/multicast.h1 +++ /dev/null @@ -1,219 +0,0 @@ -/* multicast — отправка одного payload явно указанному списку узлов topo-группы. - * Общая часть пути передаётся одним пакетом; при расхождении маршрутов пакет - * разделяется на ветки с соответствующими подмножествами получателей. - * - * Как отправлять: - * 1. multicast_open(group, on_loss, arg) выделяет исходящий дескриптор. - * Номер 1..65535 уникален среди открытых дескрипторов данного ядра. - * Выдача последовательная: 1, 2, ... 65535, затем снова с 1, пропуская - * занятые номера. Счётчик общий для всех групп ядра; close его не откатывает. - * Группа и обработчик потерь закрепляются за ним до закрытия. - * 2. Передать получателям свой node_id и номер дескриптора через протокол - * использующего сервиса. Получатели должны установить подписки до DATA. - * 3. multicast_send(inst, descriptor, recipients, count, payload, len). - * Можно отправлять много пакетов; список адресатов задаётся для каждого. - * Список и payload копируются: после возврата их можно менять/освобождать. - * 4. Перегрузки и локальные ошибки приходят в on_loss этого дескриптора. - * loss->descriptor указывает исходящий дескриптор, loss->recipients — - * только пострадавшую часть списка. Решение о снижении нагрузки принимает сервис. - * 5. multicast_close(inst, descriptor) завершает использование дескриптора. - * - * Как принимать: - * 1. Получить node_id источника и ЕГО исходящий дескриптор от сервиса. - * 2. multicast_subscribe(group, src_node, src_descriptor, on_data, arg). - * Подписка локальная, ключ — (group_id, src_node, src_descriptor). - * Она не посылает JOIN и не добавляет нас в список адресатов у источника. - * Собственный исходящий дескриптор для приёма выделять не требуется. - * 3. on_data вызывается только для пакетов, где мы указаны получателем. - * Без подписки локальная доставка тихо отбрасывается, без лога и отчёта. - * Транзит другим получателям продолжается независимо от наших подписок. - * 4. multicast_unsubscribe(subscription) прекращает приём и освобождает handle. - * - * Минимальный порядок (на разных узлах; on_loss/on_data — callbacks сервиса): - * int fd = multicast_open(send_group, on_loss, sender_ctx); - * if (fd < 0) ...; // дескриптор не создан - * // сервис передаёт source_node_id и (uint16_t)fd получателю - * struct multicast_subscription* sub = - * multicast_subscribe(recv_group, source_node_id, (uint16_t)fd, on_data, receiver_ctx); - * if (!sub) ...; // подписка не создана - * // после готовности подписки, на источнике: - * int rc = multicast_send(send_inst, (uint16_t)fd, receivers, count, data, size); - * if (rc < 0) ...; // этот вызов не принят - * // при завершении, каждый на своём узле: - * multicast_unsubscribe(sub); - * multicast_close(send_inst, (uint16_t)fd); - * - * Условия использования: - * - Все вызовы и callbacks выполняются в uasync-потоке соответствующего ядра. - * - Callbacks отложены: open/subscribe/send/close/unsubscribe их не вызывают. - * В callback можно отправлять, закрывать свой дескриптор и отписывать себя. - * Уничтожать ядро/группу/модуль из callback нельзя. - * - payload, loss и loss->recipients заимствованы до возврата из callback. - * arg принадлежит сервису: он должен жить до close/unsubscribe и завершения - * уже выполняющегося callback. После закрытия новых callbacks не будет. - * - Подпиской владеет вызывающий: unsubscribe обязателен даже после удаления - * группы. Удаление группы/ядра деактивирует подписку, но handle остаётся - * валиден до unsubscribe; после unsubscribe использовать его нельзя. - * - Удаление группы автоматически закрывает её исходящие дескрипторы. - * - Успех send означает принятие к обработке, а не доставку. Возможны частичные - * потери; сквозных ACK/повторов нет, порядок при смене маршрута не гарантируется. - * Сам отчёт тоже может потеряться: отсутствие on_loss не подтверждает доставку. - * - * Локальные callbacks DATA тоже отложены; их общая очередь ограничена 256 КиБ - * памяти. Отказ её выделения/переполнение считается MULTICAST_INTERNAL_ERROR. - * Поколений нет: DATA, отчёты и подписки используют 16-битный номер дескриптора. - * Новое ядро начинает выдачу с 1. После повторной выдачи номера запоздалый - * сетевой пакет с тем же источником и номером неотличим от пакета нового владельца. - */ -#ifndef UTUN_MULTICAST_H -#define UTUN_MULTICAST_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct UTUN_INSTANCE; -struct TOPO_GROUP; -struct multicast_ctx; -struct multicast_subscription; /* непрозрачный handle локальной подписки; освобождает вызывающий */ - -#define MULTICAST_DESCRIPTOR_INVALID 0 -#define MULTICAST_QUEUE_BYTES (256u * 1024u) /* одна FIFO на ETCP-соединение для всех рассылок */ -#define MULTICAST_REPORT_BYTES (16u * 1024u) /* общий бюджет накопленных отчётов и окон троттлинга */ -#define MULTICAST_REPORT_INTERVAL_TB 3000 /* 300 мс; timebase = 0.1 мс */ - -/* Размеры служебной оболочки; payload вместе с ней должен помещаться в 16 КиБ ETCP. */ -#define MULTICAST_MAX_VISITED 64 -#define MULTICAST_HEADER_SIZE 21 -#define MULTICAST_PATH_RESERVE (8 * MULTICAST_MAX_VISITED + 1) -#define MULTICAST_REPORT_HEADER_SIZE 41 - -enum multicast_loss_reason { - MULTICAST_OVERLOAD = 1, /* очередь выбранного исходящего соединения заполнена */ - MULTICAST_NO_ROUTE, /* только локальное уведомление источнику */ - MULTICAST_PATH_LOOP, /* локальное уведомление; транзит логирует потерю */ - MULTICAST_INTERNAL_ERROR /* выделение памяти / отказ транспорта */ -}; - -struct multicast_loss { - uint64_t group_id; /* группа исходной рассылки */ - uint64_t source_node_id; /* источник исходного DATA */ - uint64_t src, dst; /* узел потери и выбранный next hop; dst=0 без маршрута */ - uint16_t descriptor; /* исходящий дескриптор, callback которого получает этот отчёт */ - uint16_t recipient_count; /* число ID в recipients */ - const uint64_t* recipients; /* заимствованный массив в host byte order */ - uint32_t packets; /* потери для каждого получателя этого списка */ - enum multicast_loss_reason reason; /* перегрузка либо локальная причина потери */ - uint8_t prefix_len; /* 0..16 значимых байт */ - uint8_t prefix[16]; /* начало payload первого потерянного пакета */ -}; - -/* Приём для конкретной подписки. len может быть 0; payload нельзя сохранять без копирования. - * subscription можно передать в unsubscribe прямо здесь; после этого handle недействителен. - * src_node/src_descriptor/group известны сервису из subscribe и могут храниться в arg. */ -typedef void (*multicast_recv_fn)(struct multicast_subscription* subscription, const uint8_t* payload, size_t len, void* arg); - -/* Уведомление конкретному исходящему дескриптору. loss->src/dst — перегруженный - * участок, не пара «исходный отправитель / конечный получатель». - * packets относится к каждому ID в recipients. При разделении отчёта на части - * нельзя складывать packets как число уникальных исходных пакетов. - * Допустим multicast_close(inst, loss->descriptor) из этого callback. */ -typedef void (*multicast_loss_fn)(struct UTUN_INSTANCE* inst, const struct multicast_loss* loss, void* arg); - -struct multicast_stats { - uint64_t sent; /* ветки DATA, переданные ETCP */ - uint64_t delivered; /* вызовы обработчиков входящих подписок */ - uint64_t unsubscribed; /* тихие отбрасывания локальной доставки без подписки */ - uint64_t overload_packets; /* ветки, отброшенные из-за лимита исходящей FIFO */ - uint64_t no_route_packets; /* ветки без доступного маршрута */ - uint64_t loop_packets; /* петли и превышения длины пройденного пути */ - uint64_t invalid_packets; /* некорректные DATA/отчёты */ - uint64_t internal_errors; /* отказы выделения памяти или передачи транспорту */ - uint64_t reports_sent; /* переданные части отчётов, включая локальные уведомления */ - uint64_t reports_received; /* принятые части отчётов */ - uint64_t reports_evicted; /* записи отчётов, вытесненные из бюджета 16 КиБ */ - size_t queued_bytes; /* DATA в FIFO модуля, без уже переданного ETCP */ - size_t report_bytes; /* память накопленных отчётов и окон, без переданного router */ - size_t delivery_bytes; /* память DATA, ожидающих локальные callbacks; максимум 256 КиБ */ - unsigned queues; /* лениво созданные FIFO, в том числе временно опустевшие */ - unsigned descriptors; /* открытые исходящие дескрипторы */ - unsigned subscriptions; /* активные входящие подписки */ -}; - -/* Открыть исходящий дескриптор в работающей group. on_loss обязателен; arg может быть NULL. - * Выдать следующий свободный номер по циклическому порядку 1..65535, начиная после - * последнего выданного; 0 не выдаётся. Закрытые номера используются только при обходе. - * Возврат: 1..65535 — выделенный номер, <0 — ошибка (включая отсутствие свободных номеров). - * До проверки результата не приводить его к uint16_t. Подписку на приём не создаёт. */ -int multicast_open(struct TOPO_GROUP* group, multicast_loss_fn on_loss, void* arg); - -/* Отправить через открытый descriptor, принадлежащий inst; группа берётся из дескриптора. - * recipients: count>0 ненулевых node_id; повторы удаляются, собственный ID допустим. - * len может быть 0; при len>0 payload обязателен. Размер payload, списка и полного - * резерва пройденного пути должен помещаться в 16 КиБ. - * 0=принято к обработке; <0=вызов не принят, ничего не отправлено. - * После принятия отдельные ветки могут потеряться; уведомления идут в on_loss. - * Обе входные области копируются и после возврата больше не используются. */ -int multicast_send(struct UTUN_INSTANCE* inst, uint16_t descriptor, const uint64_t* recipients, - uint16_t count, const void* payload, size_t len); - -/* Закрыть исходящий descriptor данного inst: убрать его из поиска, отменить - * ещё не переданные DATA и ожидающие локальные callbacks этого дескриптора. - * Уже переданное транспорту/другим узлам отозвать нельзя. Удалённые подписки - * автоматически не закрываются. Сохранённый номер после close не использовать. - * Для отсутствующего дескриптора — диагностируемая ошибка без побочных действий. */ -void multicast_close(struct UTUN_INSTANCE* inst, uint16_t descriptor); - -/* Подписаться на локальную доставку (group_id, src_node, src_descriptor). - * src_node!=0, src_descriptor!=0, on_data обязателен; arg может быть NULL. - * Возврат: принадлежащий вызывающему handle либо NULL с диагностикой ошибки. - * Повторная подписка на тот же ключ запрещена; сначала unsubscribe прежней. - * Никаких сетевых запросов не отправляет и пропущенные ранее DATA не воспроизводит. */ -struct multicast_subscription* multicast_subscribe(struct TOPO_GROUP* group, uint64_t src_node, uint16_t src_descriptor, - multicast_recv_fn on_data, void* arg); - -/* Прекратить доставку, отменить ожидающие callbacks и освободить handle. - * NULL допустим. Работает и для подписки, деактивированной удалением группы/ядра. - * После вызова handle недействителен; повторный вызов с тем же указателем запрещён. - * Из собственного on_data допускается; память освобождается после его завершения. */ -void multicast_unsubscribe(struct multicast_subscription* subscription); - -/* Снимок общих счётчиков ядра в *out. 0=успех, <0=неверный аргумент/модуль не создан. - * Не открывает дескрипторов или подписок, счётчики не сбрасывает. */ -int multicast_get_stats(struct UTUN_INSTANCE* inst, struct multicast_stats* out); - -/* Далее — интеграция с ядром; сервисы используют open/send/close и subscribe/unsubscribe. - * init вызывается ядром один раз после etcp_router_init; 0=успех, <0=ошибка. - * destroy отменяет работу, закрывает дескрипторы, деактивирует подписки; повтор допустим. - * Вызывать до уничтожения router/ETCP и вне callbacks модуля. */ -int multicast_init(struct UTUN_INSTANCE* inst); -void multicast_destroy(struct UTUN_INSTANCE* inst); -/* Запланировать пересмотр ожидающих DATA после изменения маршрутов; повторные вызовы объединяются. */ -void multicast_routes_changed(struct UTUN_INSTANCE* inst); -/* Перед удалением группы: закрыть её дескрипторы, деактивировать подписки, - * убрать её DATA/отчёты из общих очередей, сохранив работу остальных групп. */ -void multicast_close_group(struct UTUN_INSTANCE* inst, uint64_t group_id); - -/* Wire DATA, все числа little-endian: - * cmd:1 | group:8 | descriptor:2 | count:2 | source:8 | recipients:8*count | - * payload | visited:8*hops | hops:1. - * Получатели строго возрастают. Первый visited=source, последний=ETCP peer. - * Транзит добавляет себя один раз; повторное посещение запрещено. - * - * Wire OVERLOAD — payload отдельного router-сервиса: - * descriptor:2 | src:8 | dst:8 | packets:4 | count:2 | prefix_len:1 | - * prefix:16 | recipients:8*count. - * src/dst — концы перегруженного участка; router dst — исходный источник DATA. - * Разные наборы потерянных получателей не смешиваются. Префикс относится - * к первому потерянному пакету записи; для payload короче 16 байт остаток нулевой. - * Первая потеря сообщается сразу, последующие накапливаются до конца окна 300 мс. - * Таймер отправляет остаток независимо от поступления новых DATA. - */ - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/stream/stream.h1 b/src/stream/stream.h1 deleted file mode 100644 index 51227c9e..00000000 --- a/src/stream/stream.h1 +++ /dev/null @@ -1,125 +0,0 @@ -/* Стриминг CHAT-сервиса: локальные handles владеют общим экземпляром трансляции. - * Все API — uasync-поток. Последний reader close освобождает экземпляр; publisher close после FIN - * сохраняет кольцо для локальных readers, без FIN отсоединяет их. Отсоединённый handle также закрывает вызывающий. - * DATA/GAP/END/CLOSED/AVAILABLE callback отложен, data/описание заимствованы до его возврата. - * Close handles из callback допустим; остановка сервиса/группы и destroy ядра — вне callbacks. - * Источник и локальные подписки публикуются атомарно через опции собственного мембера. */ -#ifndef STREAM_H -#define STREAM_H - -#include "stream_buffer.h" -#include "stream_media_buffer.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct UTUN_INSTANCE; -struct STREAM_HANDLE; -struct stream_service; - -struct stream_parameters { uint8_t n, r; uint16_t block_size; }; /* block_size — максимум RS-части. */ - -enum stream_event_type { STREAM_EVENT_DATA, STREAM_EVENT_GAP, STREAM_EVENT_END, STREAM_EVENT_CLOSED, STREAM_EVENT_AVAILABLE }; -enum stream_close_reason { - STREAM_CLOSE_STOPPED, STREAM_CLOSE_GROUP, STREAM_CLOSE_SERVICE, STREAM_CLOSE_SOURCE_CHANGED, - STREAM_CLOSE_MEMBER, STREAM_CLOSE_FAILED -}; - -struct stream_event { - struct stream_descriptor descriptor; - enum stream_event_type type; - uint64_t first_seq, last_seq; - const uint8_t *data; - size_t length; - int reason; -}; -typedef void (*stream_event_fn)(struct UTUN_INSTANCE *inst, const struct stream_event *event, void *arg); - -struct stream_info { - struct stream_descriptor descriptor; - struct stream_buffer_stats buffer; - unsigned owners; - int publisher; - int finished; -}; - -struct stream_candidate { - uint64_t node_id; - uint8_t client_type; - uint8_t source; -}; - -struct stream_selection_settings { uint32_t migration_confirm_ms, minimum_hold_ms, score_hysteresis_ms; }; -struct stream_selection_info { - uint64_t probes_started, cycles, migrations, failures, restarts; - unsigned candidates, probes_active, subflows, overlaps, providers; - int automatic, protected_by_fec; -}; - -int stream_service_init(struct UTUN_INSTANCE *inst); -void stream_service_destroy(struct UTUN_INSTANCE *inst); -void stream_cancel_group(struct UTUN_INSTANCE *inst, uint64_t group_id); -void stream_set_event_callback(struct UTUN_INSTANCE *inst, stream_event_fn callback, void *arg); -/* Проверенные online-публикации: JSON с id(decimal string), epoch(hex string), name, self. - * Только uasync; *out заранее NULL, результат освобождается u_free(). WAIT — группа недоступна. */ -int stream_sources_json(struct UTUN_INSTANCE *inst, uint64_t group_id, char **out); -/* Независимое наблюдение owner: начальный снимок и изменения через CHAT_EVT_STREAM_SOURCES. - * group_id=0 снимает только этого owner; owner=0 разрешён для выбранного канала frontend. - * Недоступный каталог имеет valid=0 и не означает завершение источников. - * Не создаёт подписку/буфер и не удерживает ACTIVE. Только uasync. */ -int stream_watch_sources(struct UTUN_INSTANCE *inst, uint64_t group_id, uint64_t owner); -/* Локальный owner удерживает эффективный ACTIVE; желаемый frontend-режим ядро восстанавливает после последнего close. */ -int stream_service_needs_activity(const struct UTUN_INSTANCE *inst); -/* Только локальный viewer этой группы/эпохи подавляет рацию источника со включённым звуком. */ -int stream_radio_muted(struct UTUN_INSTANCE *inst, uint64_t group_id, uint64_t source_id); - -/* out заранее NULL. parameters=NULL — 6+2, часть до 1300 байт и одна подпись пачки внутри RS. - * Одна публикация этого узла в группе; новый запуск получает новый source_epoch. */ -int stream_publish_open(struct UTUN_INSTANCE *inst, uint64_t group_id, const struct stream_parameters *parameters, - struct STREAM_HANDLE **out); -/* Меняет подписанное состояние звука, не формат медиатреков. Только uasync; raw publisher начинает с 0. */ -int stream_publish_set_audio_enabled(struct STREAM_HANDLE *handle, int enabled); -/* Параметры берутся из подписанного профиля источника; дубликаты локальных владельцев делят один буфер. - * WAIT — источник ещё не объявил/не подтвердил трансляцию. Offline не создаёт ложного онлайн-кандидата. */ -int stream_subscribe_open(struct UTUN_INSTANCE *inst, uint64_t group_id, uint64_t source_id, struct STREAM_HANDLE **out); -/* Ручные выдачи для диагностики/явного управления; режим общий для всех owners экземпляра и не смешивается с automatic. */ -int stream_subscribe_manual_open(struct UTUN_INSTANCE *inst, uint64_t group_id, uint64_t source_id, struct STREAM_HANDLE **out); -/* По умолчанию: подтверждение улучшения 2000 мс, удержание 5000 мс, гистерезис интегральной оценки 20 мс. */ -int stream_selection_configure(struct STREAM_HANDLE *handle, const struct stream_selection_settings *settings); -int stream_selection_get_info(const struct STREAM_HANDLE *handle, struct stream_selection_info *info); -void stream_close(struct STREAM_HANDLE *handle); -int stream_handle_active(const struct STREAM_HANDLE *handle); -int stream_handle_reason(const struct STREAM_HANDLE *handle); -int stream_get_info(const struct STREAM_HANDLE *handle, struct stream_info *info); - -/* Медиаплеер использует тот же RS-buffer, но собственные позиции чтения. - * tracks=0 включает только общий индекс; VIDEO или VIDEO|AUDIO создаёт cursor этого handle. - * Все вызовы — uasync. Заимствованный packet действует до следующего read/close. - * LIVE DATA/GAP/END callbacks описывают сетевой прогресс; конец отложенного просмотра получает media_read. */ -int stream_media_enable(struct STREAM_HANDLE *handle, unsigned tracks); -/* Атомарно открыть viewer выбранной эпохи с собственным cursor. CONFLICT означает смену источника. - * tracks=VIDEO или VIDEO|AUDIO; out заранее NULL, при отказе остаётся NULL. Закрытие через stream_close. */ -int stream_media_open(struct UTUN_INSTANCE *inst, uint64_t group_id, uint64_t source_id, uint64_t epoch, - unsigned tracks, struct STREAM_HANDLE **out); -/* Один следующий видеокадр при want_video=1; звук ограничен position_us+audio_ahead_us. */ -int stream_media_read(struct STREAM_HANDLE *handle, int64_t position_us, int want_video, int64_t audio_ahead_us, - struct stream_media_packet *packet); -int stream_media_get_status(struct STREAM_HANDLE *handle, struct stream_media_status *status); -int stream_media_resync(struct STREAM_HANDLE *handle); - -size_t stream_publish_capacity(const struct STREAM_HANDLE *handle); -int stream_publish_write(struct STREAM_HANDLE *handle, const uint8_t *data, size_t length, size_t *accepted); -/* Публикует одну непустую FEC-пачку, без склейки/таймера. Не смешивать с publish_write в одном запуске. */ -int stream_publish_block(struct STREAM_HANDLE *handle, const uint8_t *data, size_t length); -/* Сбросить остаток, снять статус публикации; DATA перед END. Буфер живёт до close. */ -int stream_publish_finish(struct STREAM_HANDLE *handle); - -/* Только подходящие online-подписчики этой группы/эпохи; мобильные relay исключены, источник допускается. - * out заранее NULL; массив освобождается u_free(). Наличие кандидата не гарантирует прямой транспорт. */ -int stream_get_candidates(const struct STREAM_HANDLE *handle, struct stream_candidate **out, size_t *count); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/stream/stream_optimizer.h1 b/src/stream/stream_optimizer.h1 deleted file mode 100644 index cc11156b..00000000 --- a/src/stream/stream_optimizer.h1 +++ /dev/null @@ -1,26 +0,0 @@ -/* Один планировщик на локальный экземпляр; handles владельцев не размножают пробы/выдачи. - * tick вызывается отложенным stream network проходом и таймером, destroy отменяет все свои receive/probe handles. */ -#ifndef STREAM_OPTIMIZER_H -#define STREAM_OPTIMIZER_H - -#include "stream.h" - -struct stream_optimizer; -struct stream_receive_info; -/* Меньшая оценка лучше: chain RTT + 2 * peer RTT + 3 мс/hop + штраф 0..1000 мс; неизвестный RTT = UINT64_MAX. */ -uint64_t stream_supplier_score(const struct stream_receive_info *info, const struct stream_metric_snapshot *metrics, int valid); -/* Только монотонное расписание; pending/active — незавершённый обход/пробы текущего цикла. - * Возвращает допустимое число новых узлов, не адресов/субпотоков: 32 один раз, затем 0/1. */ -struct stream_probe_schedule { uint64_t cycle, started_ms, next_ms; }; -unsigned stream_probe_schedule_tick(struct stream_probe_schedule *schedule, uint64_t now_ms, unsigned pending, unsigned active); -int stream_optimizer_create(struct UTUN_INSTANCE *inst, const struct stream_descriptor *descriptor, struct stream_optimizer **out); -void stream_optimizer_destroy(struct stream_optimizer *optimizer); -void stream_optimizer_tick(struct stream_optimizer *optimizer, struct STREAM_HANDLE *subscription, uint64_t now_ms); -int stream_optimizer_configure(struct stream_optimizer *optimizer, const struct stream_selection_settings *settings); -void stream_optimizer_info(struct stream_optimizer *optimizer, struct stream_selection_info *info); -/* Merkle/BGP помечает список поставщиков устаревшим; пробы/цикл/backoff сохраняются до отложенной сверки. */ -void stream_optimizer_roster_changed(struct stream_optimizer *optimizer, uint64_t peer); -/* Подтверждённая помощь немедленно обновляет кандидатов и снимает старый backoff конкретного пира. */ -void stream_optimizer_refresh(struct stream_optimizer *optimizer, uint64_t peer); - -#endif diff --git a/src/stream/stream_playback_clock.h1 b/src/stream/stream_playback_clock.h1 deleted file mode 100644 index 531dfa34..00000000 --- a/src/stream/stream_playback_clock.h1 +++ /dev/null @@ -1,49 +0,0 @@ -/* Общая адаптация воспроизведения desktop/Android, без сетевых ресурсов и очередей медиа. - * Один поток либо внешняя блокировка. position_us — фактические общие часы исходного материала; - * ready_us — непрерывная готовая граница, включая данные в кольце/кодеке/устройстве. - * Минимумы короткого окна нормализованы по смещению wall-clock относительно media-clock: - * простой увеличивает все прежние запасы, догон уменьшает их без переписывания истории. - * После 200 мс без фактической недостачи избыток погашается плавным ускорением до 1.6. - * guard_us и уже поставленный устройству pending_gain_us защищают остаток при снижении темпа. - * reset нужен при новой эпохе/реальном GAP/смене позиции; временная нехватка историю сохраняет. */ -#ifndef STREAM_PLAYBACK_CLOCK_H -#define STREAM_PLAYBACK_CLOCK_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define STREAM_PLAYBACK_HISTORY 4 -#define STREAM_PLAYBACK_BUCKET_US 50000 -#define STREAM_PLAYBACK_SETTLE_US 200000 -#define STREAM_PLAYBACK_MAX_TEMPO 1600 -#define STREAM_PLAYBACK_RAMP_US 500000 - -struct stream_playback_bucket { int64_t period, minimum_us; }; -struct stream_playback_clock { - struct stream_playback_bucket history[STREAM_PLAYBACK_HISTORY]; - uint64_t id, pauses; - int64_t first_us, last_us, last_position_us, correction_us, last_bad_us, pause_us, report_us; - int64_t ramp_remainder; - int tempo_milli, initialized, waiting; -}; - -struct stream_playback_state { - int64_t position_us, reserve_us, minimum_us, correction_us, stable_us, removable_us; - int tempo_milli, waiting, history_ready; -}; - -void stream_playback_clock_reset(struct stream_playback_clock *clock, uint64_t id); -/* Результат не меняется при ошибке. starved отмечает фактическую остановку подготовки/вывода. - * Временное уменьшение фактического position_us запрещено; после перемотки вызывают reset. - * Возврат 0 — успех, отрицательный — неверные аргументы/часы. */ -int stream_playback_clock_update(struct stream_playback_clock *clock, int64_t now_us, int64_t position_us, - int64_t ready_us, int64_t guard_us, int64_t pending_gain_us, - int starved, struct stream_playback_state *state); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/transport_layer/auto_socket.h1 b/src/transport_layer/auto_socket.h1 deleted file mode 100644 index d97d4171..00000000 --- a/src/transport_layer/auto_socket.h1 +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef AUTO_SOCKET_H -#define AUTO_SOCKET_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * auto_socket.h — автоматическое управление сокетами при изменении сетевых интерфейсов - * - * === Зачем нужен модуль === - * При auto_sockets=yes не нужно вручную прописывать секции [server] в конфиге. - * Модуль сам создаёт UDP+TCP сокеты на всех не-loopback интерфейсах с IP-адресами, - * и сразу добавляет линки ко всем активным ETCP-соединениям. При пропадании - * интерфейса линки удаляются, сокеты закрываются. - * - * === Что делает === - * - Для каждого интерфейса (UP, с v4/v6 адресами) создаёт пару сокетов: - * UDP (случайный порт) + TCP (stcp_server на случайном порту) - * - Тип сокета: PUBLIC если на интерфейсе есть глобальный адрес, иначе NAT - * - Порт сохраняется в SQLite для переиспользования при перезапуске - * - Для каждого нового сокета: etcp_link_new ко всем соединениям (inst->connections), - * случайно выбирая один совместимый адрес пира (отдельно для v4 и v6) - * - При изменении адреса на интерфейсе — обновляет interface_addr и оповещает - * подписчиков (ETCP_SOCKET_EVENT_ADDR_CHANGED) - * - При смене типа (NAT↔PUBLIC) — пересоздаёт сокет с новым типом - * - При пропадании интерфейса — удаляет линки, закрывает сокет, чистит БД - * - * === Слои === - * 1. Platform-agnostic API: auto_socket_init / auto_socket_destroy - * auto_socket_add_interface / auto_socket_remove_interface - * (можно вызывать из любого платформенного мониторинга: netlink, JNI и т.д.) - * 2. Platform monitoring: встроенные обработчики netlink (Linux), - * route socket (BSD), IP Helper (Windows) — работают автоматически - */ - -#include - -struct UTUN_INSTANCE; -struct ETCP_SOCKET; -struct utun_config; - -/* Внутреннее состояние модуля — хранится в inst->auto_socket_state. - * Содержит связный список отслеживаемых интерфейсов (ifaces) и платформенные - * handle'ы для мониторинга (netlink fd, route socket fd, IP Helper handles). */ -struct AUTO_SOCKET; - -/* ─── Жизненный цикл ─── */ - -/* Инициализирует модуль: создаёт таблицу портов в БД, запускает платформенный - * мониторинг интерфейсов, сканирует все текущие UP-интерфейсы и создаёт сокеты. - * Если auto_sockets=no в конфиге — ничего не делает, возвращает 0. */ -int auto_socket_init(struct UTUN_INSTANCE* inst); - -/* Останавливает мониторинг, удаляет все созданные сокеты и линки, освобождает память. */ -void auto_socket_destroy(struct UTUN_INSTANCE* inst); - -/* Вызвать при изменении сетевых интерфейсов из любого потока (JNI, ConnectivityManager). - * Откладывает полное сканирование (auto_socket_scan_all) в uasync-поток. */ -void auto_socket_on_network_change(struct UTUN_INSTANCE* inst); - -/* Android-режим (auto_sockets=android): обновить сокеты из [server] секций нового - * конфига. new_cfg — уже распарсенный конфиг; его список servers переносится в - * inst->config, остальное освобождается. Должен вызываться в uasync-потоке. */ -void auto_socket_reload_config(struct UTUN_INSTANCE* inst, struct utun_config* new_cfg); - -/* ─── Platform-agnostic API: управление сокетами на конкретном интерфейсе ─── */ - -/* - * Создать UDP+TCP сокеты для интерфейса и добавить линки ко всем активным соединениям. - * ifindex — индекс интерфейса (0 = автоопределение по ifname) - * ifname — имя интерфейса для SO_BINDTODEVICE - * has_v4 — есть ли IPv4 адреса на интерфейсе - * has_v6 — есть ли IPv6 адреса на интерфейсе - * v4_type — CFG_SERVER_TYPE_PUBLIC или CFG_SERVER_TYPE_NAT - * v6_type — CFG_SERVER_TYPE_PUBLIC или CFG_SERVER_TYPE_NAT - * Возвращает количество созданных сокетов (0, 1, 2, 3 или 4 — до 4: v4 UDP+TCP, v6 UDP+TCP). - * Если сокеты для этого интерфейса уже есть — ничего не делает, возвращает 0. - */ -int auto_socket_add_interface(struct UTUN_INSTANCE* inst, uint32_t ifindex, - const char* ifname, int has_v4, int has_v6, - uint8_t v4_type, uint8_t v6_type); - -/* - * Удалить все сокеты и линки для интерфейса. - * Закрывает UDP/TCP сокеты, удаляет etcp-линки через ncd_remove_socket_links, - * чистит запись порта в БД. - * ifindex — индекс интерфейса, сокеты которого удаляем - */ -void auto_socket_remove_interface(struct UTUN_INSTANCE* inst, uint32_t ifindex); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/transport_layer/etcp_connections.h1 b/src/transport_layer/etcp_connections.h1 deleted file mode 100644 index 39f8cb83..00000000 --- a/src/transport_layer/etcp_connections.h1 +++ /dev/null @@ -1,430 +0,0 @@ -#ifndef ETCP_CONNECTIONS_H -#define ETCP_CONNECTIONS_H - -#ifdef __cplusplus -extern "C" { -#endif - - -// подмодуль ETCP который обслуживает сокеты ETCP для приёма-передачи пакетов и одно ETCP подключение через несколько каналов связи (failover) - -#include "secure_channel.h" -#include "etcp_session.h" -#include "reality.h" -#include "utun_instance.h" -#include "etcp_bbr.h" -#include "../routing_layer/address_profile.h" -#include "../lib/socket_compat.h" -#include "../lib/ll_queue.h" -#include -#include - -#define IP_UDP_OVERHEAD_V4 (20 + 8) // IP(20)+UDP(8) -#define IP_UDP_OVERHEAD_V6 (40 + 8) // IP(40)+UDP(8) -#define SC_ENCRYPT_OVERHEAD (ETCP_ENCRYPTED_HDR_SIZE + ETCP_SESSION_HEADER_SIZE + SC_NONCE_SIZE + SC_CRC32_SIZE + SC_TAG_SIZE) -#define UDP_SC_HDR_SIZE (SC_NONCE_SIZE + SC_TAG_SIZE + SC_CRC32_SIZE + 5) -#define ACK_REZERV 100// сколько байт резервировать под ack и прочие заголовки -#define WIRE_OVERHEAD(fam) ((fam) == AF_INET6 ? IP_UDP_OVERHEAD_V6 + SC_ENCRYPT_OVERHEAD : IP_UDP_OVERHEAD_V4 + SC_ENCRYPT_OVERHEAD) - -#define INFLIGHT_LIM_MIN 8192 // 8K -#define INFLIGHT_LIM_MAX 1048576 // 1M - -#define PACKET_DATA_SIZE 2048 -// Wire-MTU кап: пакет на проводе не должен превышать 1500 (согласовано с TUN_MAX_PACKET_SIZE). -// PACKET_DATA_SIZE (2048) — это внутренний буфер аллокации/приёма, а не wire-MTU. -#define PACKET_DATA_MAX_MTU 1500 -#define ETCP_MAX_PAYLOAD_SIZE (PACKET_DATA_SIZE - ETCP_ACK_BASE_SIZE - 5) /* 2035 */ -#define ETCP_RFC791_MIN_MTU 576 - -// Типы кодограмм протокола -#define ETCP_INIT_REQUEST 0x02 -#define ETCP_INIT_RESPONSE 0x03 -#define ETCP_INIT_REQUEST_NOINIT 0x04 -#define ETCP_INIT_RESPONSE_NOINIT 0x05 -#define ETCP_PING 0x06 -#define ETCP_PONG 0x07 -#define ETCP_KEEPALIVE 0x08 -#define ETCP_TCP_ADDRESS 0x0d // STCP control: code + family(4/6) + observed IP(16), без порта - -#define ETCP_PING_FLAG_WANT_RTT 0x01 // в PONG: хочу получить RTT от пингера -#define ETCP_PING_FLAG_SEND_RTT 0x02 // в PING: несу RTT для получателя -#define ETCP_PING_FLAG_OBSERVE 0x04 // PONG несёт фактически наблюдаемый IP:port -#define ETCP_PING_FLAG_ADDRESS_CHECK 0x08 // прямое входящее испытание endpoint -#define ETCP_PING_FLAG_NO_REPLY 0x10 // NAT-проба: результат через router, без автоматического UDP-ответа - -/* Адаптивный keepalive */ -#define KA_PERIOD_MIN_MS 200 -#define KA_PERIOD_MAX_MS 10000 -#define KA_TIMEOUT_MULT 10 /* timeout = period * mult */ - - -#pragma pack(push, 1) -struct ETCP_DGRAM {// пакет (незашифрованный) - struct ETCP_LINK* link;// откуда получена или куда отправялем - uint16_t data_len;// общий размер пакета не включая timestamp - uint16_t noencrypt_len;// число байт (с конца) которые не надо шифровать. для передачи pubkey - uint16_t timestamp;// timestamp отправляющего узла при отправке пакета - uint8_t flag_up:1;// bit0 = up/down (recv_keepalive) - uint8_t data[];// данные пакета (без timestamp) -}; -#pragma pack(pop) - -/* Размер зашифрованного заголовка ETCP_DGRAM (timestamp + flag_up + padding) */ -#define ETCP_ENCRYPTED_HDR_SIZE (offsetof(struct ETCP_DGRAM, data) - offsetof(struct ETCP_DGRAM, timestamp)) - -/* Размер базового ACK: type(1) + count(1) + last_delivered_id(4) + rx_dup_count(2) */ -#define ETCP_ACK_BASE_SIZE (2 + 4 + 2) - -// --- INIT packet wire formats (inside encrypted payload, before padding) --- - -// INIT REQUEST: client → server -struct ETCP_INIT_REQUEST_PKT { - uint8_t code; // 0: ETCP_INIT_REQUEST (0x02) или ETCP_INIT_REQUEST_NOINIT (0x04) - uint8_t node_id[8]; // 1: sender node_id (big-endian) - uint8_t reset_id[8]; // 9: reset epoch id (big-endian) - uint8_t mtu[2]; // 17: client MTU (big-endian) - uint8_t keepalive[2]; // 19: keepalive interval (big-endian) - uint8_t recovery[2]; // 21: recovery interval/100 (big-endian) - uint8_t link_id; // 23: client's local link id - uint8_t socket_id; // 24: client's socket id - uint8_t only_local; // 25: client only_local flag - uint8_t type; // 26: client socket type (CFG_SERVER_TYPE_*) - // V2 fields (NAT_DIRECT detection): - uint8_t src_ipv4[4]; // 27: client interface_addr IPv4 (big-endian, 0 if N/A) - uint8_t src_port[2]; // 31: client interface_addr port (big-endian) - uint8_t collision; // 33: 1 = cross-connect, remote claims master - uint8_t ed25519_pubkey[SC_PUBKEY_SIZE]; // 34: client Ed25519 pubkey (32 bytes) - // V4 fields: - uint8_t device_type; // 66: CLIENT_TYPE_SERVER/DESKTOP/MOBILE -} __attribute__((packed)); -#define ETCP_INIT_REQ_SIZE sizeof(struct ETCP_INIT_REQUEST_PKT) - -// INIT RESPONSE: server → client -struct ETCP_INIT_RESPONSE_PKT { - uint8_t code; // 0: ETCP_INIT_RESPONSE (0x03) или ETCP_INIT_RESPONSE_NOINIT (0x05) - uint8_t node_id[8]; // 1: server node_id (big-endian) - uint8_t reset_id[8]; // 9: reset epoch id (big-endian) - uint8_t mtu[2]; // 17: server MTU (big-endian) - uint8_t link_id; // 19: server's local link id - uint8_t remote_socket_id; // 20: echo of client's socket_id - uint8_t only_local; // 21: server only_local flag - uint8_t type; // 22: server socket type (CFG_SERVER_TYPE_*) - // V2 fields: - uint8_t peer_ipv4[4]; // 23: client's external NAT address (big-endian) - uint8_t peer_port[2]; // 27: client's external NAT port (big-endian) - // V3 fields: - uint8_t ed25519_pubkey[SC_PUBKEY_SIZE]; // 29: server Ed25519 pubkey (32 bytes) - // V4 fields: - uint8_t device_type; // 61: CLIENT_TYPE_SERVER/DESKTOP/MOBILE - uint8_t keepalive[2]; // 62: server keepalive interval (big-endian) -} __attribute__((packed)); -#define ETCP_INIT_RESP_SIZE sizeof(struct ETCP_INIT_RESPONSE_PKT) - -typedef void (*etcp_ping_callback_t)(int success, uint16_t rtt, void* arg, uint64_t nonce, - const uint8_t* resp_data, size_t resp_data_len); -struct PING_CONTEXT { - struct PING_CONTEXT* next; - struct UTUN_INSTANCE* instance; - etcp_ping_callback_t cb; - void* arg; - uint64_t nonce; - void* timeout_timer; - uint64_t send_time; // время отправки пинга в 0.1ms - uint8_t peer_pubkey[SC_PUBKEY_SIZE]; - uint8_t socket_id; - uint64_t socket_generation; - struct sockaddr_storage peer_addr; - uint8_t* user_data; - size_t user_data_len; -}; - -#define LINK_ADDR_KEY_SIZE 19 // port(2) + addr(16) + family(1) - -struct link_queue_entry { - uint8_t key[LINK_ADDR_KEY_SIZE]; - struct ETCP_LINK* link; -}; - -// список активных подключений которые обслуживает сокет. каждый сокет может обслуживать много подключений -struct ETCP_SOCKET { - struct ETCP_SOCKET* next; // Linked list для всех соединений - struct UTUN_INSTANCE* instance; - char name[MAX_CONN_NAME_LEN]; - socket_t fd; // UDP socket / TCP listen socket - int mtu; - - uint8_t type; // CFG_SERVER_TYPE_* - uint8_t sock_id; // unique id (0-255) for NAT matching - uint8_t is_tcp; // 1=TCP (STCP), 0=UDP - uint8_t probe_only; // вспомогательный UDP-порт наблюдателя, не транспорт NCD - uint64_t generation; // случайная эпоха endpoint; sock_id может переиспользоваться - uint8_t reality_enabled; // 1=TCP-порт с REALITY-камуфляжем - uint8_t only_local; // 1 = only local, no forwarding (UDP) - uint32_t netif_index; // для sin6_scope_id - struct sockaddr_storage local_addr; - struct sockaddr_storage interface_addr; - struct sockaddr_storage nat_addr; - - /* ── uasync handle (UDP read_cb / TCP accept_cb) ── */ - void* socket_id; - - /* ── UDP-only ── */ - struct ll_queue* links_queue; // hash-очередь линков - int errorcode; - size_t pkt_format_errors; - struct address_profile address_profile; - uint32_t local_defaultroute_ip; // auto-detected IPv4 (network byte order) - uint8_t local_defaultroute_ip6[16]; - struct socks_udp* socks_udp; // SOCKS5 UDP ASSOCIATE (NULL = напрямую) -}; - -#define LINK_STATE_HANDSHAKE 1 -#define LINK_STATE_TRY_RECONNECT 2 -#define LINK_STATE_CONNECTED 3 - -// Тип функции-перехватчика отправки UDP. -// Если link->send_hook != NULL, etcp_udp_send вызывает её вместо socket_sendto. -struct ETCP_LINK; -typedef ssize_t (*etcp_udp_send_fn_t)(socket_t fd, const void* buf, size_t len, - const struct sockaddr* addr, socklen_t addr_len, - struct ETCP_LINK* link, void* context); - -struct socks_udp; - - -// ETCP Link - одно динамическое соединение (один путь) -struct ETCP_LINK { - struct ll_entry* link_queue_entry; // элемент в socket->links_queue - struct ETCP_LINK* next; // Linked list подключений для ETCP_CONN (каждое подключение это child для ETCP_CONN) - - struct ETCP_CONN* etcp; // подключение (parent) - struct ETCP_SOCKET* conn; // сокет через который работаем - // Путь соединения - struct sockaddr_storage remote_addr; // Удалённый адрес - - // Параметры соединения - uint16_t mtu; // MTU общий - uint16_t mtu_local; // MTU моего зла - uint16_t mtu_remote; // MTU удаленного узла - uint16_t keepalive_interval; // Keepalive интервал (x1ms) - uint32_t recovery_interval; // recovery интервал (x0.1ms) - uint8_t is_server; // инициирует подключение клиент - uint8_t initialized; // Флаг инициализации (1=подтверждено или получен request) - uint8_t local_link_id; // id моего линка - uint8_t remote_link_id; // id этого линка на peer (устанавливается в момент initialized) - uint8_t remote_socket_id; // socket id peer - uint8_t remote_only_local; // only_local flag from peer - uint8_t remote_type; // CFG_SERVER_TYPE_* (type of peer's socket) - uint8_t recv_keepalive; // 1 - up, 0 - down (принимаются ли пакеты) - uint8_t remote_keepalive; // 1 - up, 0 - down (удаленная сторона сообщает - принимаются ли у нее пакеты) - uint8_t link_status; // 1 - up, 0 - down (итоговый статус - если есть проблемы на любой стороне - линк down) - uint8_t link_state; // 0 - just init, 1 - handshake, 2 - try reconnect, 3 - connected - - // Состояние установки соединения (только для клиентов) - void* init_timer; // Таймер для повторов INIT (NULL=не подключается) - uint16_t init_timeout; // Текущий таймаут в мс - uint16_t init_retry_count; // Счетчик попыток - -// uint64_t last_activity; // Время последней активности - uint64_t last_recv_local_time; // x0.1 ms - uint64_t rx_deadline_tb; // конечный срок ожидания RX, включая объявленный сон - void* rx_timeout_timer; // проверка жизни независимо от отправки keepalive - uint16_t last_recv_timestamp; - uint8_t last_recv_updated; // =1 при обновлении timestamp, =0 при отправке (чтобы не дублировать отправки при отсутствии обновлений) - - uint64_t shaper_load_time_tb; // основной в 0.1 мс units - uint64_t shaper_sub_nanotime; // sub 0-999999 для 0.1 нс - 0.1 мс - uint8_t shaper_state; - void* shaper_timer; - - uint32_t inflight_bytes; - uint32_t inflight_packets; - uint32_t inflight_lim_bytes; - - // statistics - size_t encrypt_errors; - size_t decrypt_errors; - size_t send_errors; - size_t recv_errors; - size_t total_encrypted; - size_t total_decrypted; - uint32_t total_retransmissions; - uint64_t acked_bytes; // подтверждённых байт на этом линке - uint64_t acked_packets; // подтверждённых пакетов на этом линке - - uint16_t rtt_last; // round trip (время отправки + приёма) - uint32_t jitter; // Current jitter [>>16] x0.1 ms - // rtt_avg10 удалён — заменён BBR (bbr->min_rtt_us/100) - uint32_t recv_dt_avg_tx; // дельта времени для отправленных пакетов (относительное время отправки) x256 - uint32_t recv_dt_avg_rx; // дельта времени для принятых пакетов (относительное время отправки) x256 - - uint16_t tt_last; // transmit time (время доставки отправленных пакетов) - uint16_t rt_last; // recv time (время доставки принятых пакетов) - uint32_t bandwidth; // Link bandwidth in Kbits/sec - - // NAT address tracking (from INIT_RESPONSE) - struct sockaddr_storage local_as_seen_by_peer; // только наш endpoint, наблюдаемый удалённым пиром - uint32_t nat_changes_count; // Counter of NAT address changes - uint32_t nat_hits_count; // Counter of NAT address matches (new init response with same IP:port) - - // Keepalive state - void* keepalive_timer; // Таймер обычного keepalive (только в normal-режиме) - uint32_t keepalive_timeout; // таймаут (ms) - uint16_t ka_period_ms; // текущий период отправки keepalive - uint16_t ka_sleep_period_ms; // период keepalive в спячке (мс; настройка клиента / ka_period_ms пира) - uint8_t ka_my_sleeping; // 1 = я объявил сон (standby) - uint8_t ka_peer_sleeping; // 1 = пир объявил сон - uint8_t ka_sleep_acked; // получен ACK моего анонса сна - uint16_t ka_active_remaining; // сколько до SLEEP-фазы (x0.1с), 0 = уже спим - uint16_t ka_sleep_duration; // длительность SLEEP-фазы (x0.1с) - void* ka_sleep_announce_timer; // таймер ретрая анонса спячки (ACTIVE-окно) - uint8_t ka_announce_attempts; // попыток анонса в текущем окне - uint8_t ka_announce_max_attempts; // лимит попыток на окно (сколько влезет, но ≥ min) - uint8_t ka_fail_count; // кумулятивные провалы (сброс по ACK), ≥ KA_SLEEP_MAX_FAILS → down - uint8_t pkt_sent_since_keepalive; // Флаг: был ли отправлен пакет с последнего keepalive тика - uint32_t keepalive_sent_count; // Счётчик отправленных keepalive - uint32_t keepalive_recv_count; // Счётчик полученных keepalive - uint8_t peer_device_type; // CLIENT_TYPE_* удалённой стороны (из handshake) - uint16_t handshake_minsize; // минимальный размер udp при handshake - uint16_t handshake_maxsize; // мax размер udp при handshake (выбирает рандом) - - // === Burst-измерение bandwidth === - // Sender-сторона - uint16_t burst_id; // монотонно возрастающий ID burst - uint8_t burst_active; // 1 = burst в процессе отправки - uint8_t burst_seq; // текущий номер пакета в burst (0..burst_count-1) - uint8_t burst_count; // общее число пакетов в burst - uint64_t burst_last_time_tb; // время последнего burst (0.1ms), для MIN_BURST_INTERVAL - void* burst_resp_timer; // таймер ожидания ответа на burst - uint32_t burst_target_bdp; // BDP из последнего успешного burst (байты) - uint16_t burst_pkt_size; // сохранённый размер пакета для вычисления BW - - // Receiver-сторона - uint16_t burst_recv_id; // ID отслеживаемого burst - uint8_t burst_recv_count; // ожидаемое число пакетов в burst - uint8_t burst_recv_next_seq; // следующий ожидаемый seq - uint8_t burst_recv_valid; // 1 = порядок пакетов не нарушен - uint8_t burst_recv_received; // сколько пакетов уже принято - uint64_t burst_recv_times[16]; // время прихода каждого пакета (µs) - uint16_t burst_recv_pkt_size; // размер пакета из MEAS_TS (для ответа) - uint8_t burst_resp_pending; // 1 = есть готовый ответ для piggyback - uint32_t burst_resp_gap_avg; // средний inter-packet gap (µs) - uint32_t burst_resp_gap_min; // минимальный inter-packet gap (µs) - uint8_t burst_resp_pkt_count; // число пакетов в измерении - uint8_t burst_resp_valid; // валидность измерения - - // === BBR congestion control === - struct bbr* bbr; // BBR state (per-link, создаётся в etcp_link_new) - uint64_t delivered_bytes; // кумулятивно delivered bytes на линке (для round detection) - uint64_t last_ack_time_tb; // 0.1ms timestamp последнего ACK (для interval_us) - uint32_t bbr_pacing_rate; // bytes/sec output BBR → shaper - uint32_t bbr_loss_since_ack; // счётчик потерь на линке с последнего ACK (для rs->lost) - - etcp_udp_send_fn_t send_hook; // NULL = socket_sendto напрямую - void* send_hook_ctx; - - struct sockaddr_storage local_bound_addr; // локальный адрес к которому привязан линк (interface_addr на момент создания) - uint8_t is_tcp; // 1 = TCP транспорт (STCP) - uint8_t reality_set; // 1 = link->reality валиден (реклама пира из BGP) - struct reality_client_config reality; // reality-параметры пира (для исходящего TCP) - struct stcp_link *tcp_link; // STCP линк (для TCP) - void *tcp_reconnect_timer; // таймер реконнекта (TCP клиент) - uint32_t tcp_reconnect_delay_ms; // задержка реконнекта (экспоненциальный backoff) -}; - -// Единая точка отправки всех ETCP-пакетов. -ssize_t etcp_udp_send(struct ETCP_LINK* link, socket_t fd, const void* buf, size_t len, - const struct sockaddr* addr, socklen_t addr_len); - -// INITIALIZATION -// Создаёт только listen-сокеты из конфига (серверы для incoming connections) -int init_sockets(struct UTUN_INSTANCE* instance); -// Создаёт listen-сокеты и client connections из конфига -int init_connections(struct UTUN_INSTANCE* instance); - -// Заменяет принадлежащие конфигурации NCD handles. Новые приобретаются до освобождения старых. -int init_client_connections(struct UTUN_INSTANCE* instance, struct CFG_CLIENT* clients); - -// SOCKET FUNCTIONS -// добавляет новый версер (сокет для приёма и отправки кодограмм. обслуживает много подключений) -struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SERVER* server); -// удаляет сокет и освобождает ресурсы (грохает все его подключения и сокет) -void etcp_socket_remove(struct ETCP_SOCKET* conn); - -// TCP socket functions (uses unified ETCP_SOCKET with is_tcp=1) -struct ETCP_SOCKET* tcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SERVER* server); -void tcp_socket_remove(struct ETCP_SOCKET* sock); - -// Создаёт один серверный сокет (UDP или TCP) из CFG_SERVER. Линки не добавляет. -int etcp_create_server_socket(struct UTUN_INSTANCE* instance, struct CFG_SERVER* server, struct ETCP_SOCKET** out_sock); - -struct stcp_link; -struct stcp_client; -void tcp_server_on_link(struct stcp_link *link, struct ETCP_SOCKET *tcp_sock); - -// connection functions -// создает новый канал связи для etcp подключения (ETCP_CONN) -struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn, - const struct sockaddr_storage* remote_addr, uint8_t is_server); -void etcp_link_update_inflight_lim(struct ETCP_LINK* link, uint32_t new_lim); -void etcp_link_close(struct ETCP_LINK* link); -//int etcp_input_cbk(struct packet_buffer* pkt, struct ETCP_SOCKET* conn);// получает расшифрованный пакет -int etcp_encrypt_send(struct ETCP_DGRAM* dgram);// зашифровывает и отправляет пакет -// find link by address -struct ETCP_LINK* etcp_link_find_by_addr(struct ETCP_SOCKET* e_sock, const struct sockaddr_storage* addr, int is_tcp); - -// Выбор исходящего линка для collision INIT по принимающему сокету и адресу отправителя. -// Линк через другой локальный сокет не подходит. NULL — встречной попытки на этой паре нет. -struct ETCP_LINK* etcp_select_collision_link(struct ETCP_CONN* conn, struct ETCP_SOCKET* e_sock, - const struct sockaddr_storage* addr); - -// find free local_link_id for connection -// scans all links in connection, marks used ids in bit array -// returns first free id (0-255) or -1 if all occupied -int etcp_find_free_local_link_id(struct ETCP_CONN* etcp); - -// Burst measurement functions -void etcp_link_burst_start(struct ETCP_LINK* link); -void etcp_link_burst_check(struct ETCP_LINK* link); -void etcp_link_burst_finish(struct ETCP_LINK* link); - -void etcp_link_enter_init(struct ETCP_LINK *link); -void etcp_link_enter_reinit(struct ETCP_LINK *link); -void etcp_link_enter_ready_tcp(struct ETCP_LINK *link); -void etcp_tcp_link_start_connect(struct ETCP_LINK *link, struct sockaddr_storage *addr, uint16_t port); -void etcp_tcp_link_start_reconnect(struct ETCP_LINK *link); - -int etcp_packet_decrypted(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, - struct ETCP_LINK* link, size_t pkt_len); - -int etcp_send_ping(struct UTUN_INSTANCE* instance, const uint8_t* peer_pubkey_bin, - const struct sockaddr_storage* addr, int timeout_ms, - etcp_ping_callback_t cb, void* user_arg, - const uint8_t* user_data, size_t user_data_len); - -// шлёт пинг на addr используя pubkey. в пакет помещает user_data[user_len]. при получении ответа или таймауте вызывает callback. -// flags: ETCP_PING_FLAG_SEND_RTT — user_data содержит RTT для peer -int etcp_send_ping_to_socket(struct UTUN_INSTANCE* instance, struct ETCP_SOCKET* e_sock, - const uint8_t* peer_pubkey_bin, const struct sockaddr_storage* addr, - int timeout_ms, etcp_ping_callback_t cb, void* user_arg, - const uint8_t* user_data, size_t user_data_len, - uint8_t flags); - -/* Отмена без callback: вызывающий владеет arg и освобождает его после отмены. */ -void etcp_cancel_pings(struct UTUN_INSTANCE *instance, etcp_ping_callback_t callback, void *arg); - -// TCP-ping: подключение к TCP-адресу peer + хендшейк с флагом PING. RTT меряется -// по хендшейку (send→response). cb вызывается один раз (success=1/rtt или success=0). -// out_cli (опционально) — возвращает хендл stcp_client для досрочной отмены (stcp_client_destroy). -int etcp_send_tcp_ping(struct UTUN_INSTANCE* instance, const uint8_t* peer_pubkey_bin, - const struct sockaddr_storage* addr, int timeout_ms, - etcp_ping_callback_t cb, void* user_arg, - struct stcp_client** out_cli, const struct reality_client_config *reality); - -void etcp_connections_read_callback_socket(socket_t sock, void* arg); - - -#ifdef __cplusplus -} -#endif -#endif // ETCP_CONNECTIONS_H diff --git a/src/transport_layer/etcp_padding.h1 b/src/transport_layer/etcp_padding.h1 deleted file mode 100644 index ddc8a991..00000000 --- a/src/transport_layer/etcp_padding.h1 +++ /dev/null @@ -1,36 +0,0 @@ -/* Независимый диапазон padding владельца; таймер и выбор длины работают в его uasync-потоке. */ -#ifndef ETCP_PADDING_H -#define ETCP_PADDING_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct UASYNC; -struct UTUN_INSTANCE; - -#define ETCP_PADDING_MAX 158 - -struct ETCP_PADDING { - uint16_t min, max; - void* timer; - struct UASYNC* ua; - const char* name; // заимствованное имя владельца для диагностики - uint64_t next_refresh_tb; -}; - -int etcp_padding_start(struct ETCP_PADDING* padding, struct UASYNC* ua, const char* name); -void etcp_padding_stop(struct ETCP_PADDING* padding); -/* NULL допустим только для автономного STCP без instance: диапазон генерируется на операцию. */ -int etcp_padding_size(const struct ETCP_PADDING* padding, size_t available); -/* Существующий незакрываемый ETCP_CONN владеет своим диапазоном; иначе используется instance. */ -const struct ETCP_PADDING* etcp_padding_for_peer(struct UTUN_INSTANCE* inst, const uint8_t* public_key); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/transport_layer/node_conn_direct.h1 b/src/transport_layer/node_conn_direct.h1 deleted file mode 100644 index 89d4f194..00000000 --- a/src/transport_layer/node_conn_direct.h1 +++ /dev/null @@ -1,149 +0,0 @@ -/* - * node_conn_direct — общий прямой мультиадресный транспорт к узлу по node_id для BGP/topo_group. - * Адреса узла используются для создания и обновления линков общего ETCP-соединения. - * - * Архитектурная роль NODE_CONN_DIRECT (NCD handle): - * - выражает владение прямым транспортом, в том числе во время установления связи; - * - группа удерживает его для своей BGP/topo_group-сессии; - * - временный handle попытки подключения после установления связи должен перейти группе - * либо быть закрыт; передачу владения выполняют через node_conn_direct_transfer(); - * - не выражает длительность звонка или передачи файла: эту потребность хранит CONN_MGR_HANDLE. - * CM подбирает оптимальный P2P-путь для больших объёмов данных (медиа, файлы, звонки), - * а NCD управляет прямым транспортом и его адресами независимо от конкретной медиа-операции. - * - * Модуль управляет ETCP-соединениями через непрозрачные handle'ы (NODE_CONN_DIRECT). - * Каждый владелец открывает свой handle; несколько handle разделяют ETCP_CONN. - * close снимает только своё владение. Последний handle работающего транспорта начинает - * CLOSE/KEEP_ALIVE (5 s либо срок пробуждения пира); DOWN удаляется по таймауту ETCP. - * - * Кто использует: - * - conn_mgr (Connection Manager) — временные handle'ы попыток установления прямого транспорта - * - topo_group — владеет транспортом групповой сессии с начала CONNECTING - * - протокол join — временный транспорт до добавления участника - * - любой модуль, кому нужно надёжное ETCP-соединение с конкретным node_id - * - * Переходы UP/DOWN/TIMEOUT/CLOSED доставляются синхронно. Закрытие любого handle - * из callback безопасно. Начальное UP при open готового conn откладывается через uasync_call_soon. - * Все операции — в потоке uasync. NCD не проверяет членство и готовность группы. - */ -#ifndef NODE_CONN_DIRECT_H -#define NODE_CONN_DIRECT_H - -#include - -struct UTUN_INSTANCE; -struct ETCP_CONN; -struct TOPO_NODE; -struct ETCP_SOCKET; - -/* Привязать CLOSE/KEEP_ALIVE при запуске ядра, в том числе без исходящих handles. */ -int node_conn_direct_init(struct UTUN_INSTANCE* inst); - -/* Число локальных владельцев конкретного транспорта; внешние ETCP refs сюда не входят. */ -int node_conn_direct_handle_count(const struct ETCP_CONN* conn); - -/* ─── Return codes ─── */ -#define NCD_NEW 0 /* создано новое соединение */ -#define NCD_REUSED 1 /* переиспользовано существующее */ -#define NCD_ERR -1 /* ошибка */ - -/* ─── Opaque handle ─── */ -struct NODE_CONN_DIRECT; - -/* Рабочий ETCP, совместимая исходящая пара либо возможность reverse на наш опубликованный адрес. - * Без линков/handles/таймеров/проб. Исходящие пары — тот же обход, что open; reverse — sock_match/публикуемые адреса. - * Учитывает IPv6 и исходящий TCP fallback; возможность попытки не доказывает достижимость. */ -int node_conn_direct_compatible(struct UTUN_INSTANCE* inst, uint64_t node_id); - -/* ─── Callback events (единый callback на handle) ─── */ -enum ncd_event { - NCD_EVENT_UP = 0, /* соединение поднялось (линки работают) */ - NCD_EVENT_DOWN = 1, /* соединение упало */ - NCD_EVENT_CLOSED = 3, /* транспорт окончательно удалён; get_conn=NULL, владелец закрывает handle */ - NCD_EVENT_TIMEOUT = 2, /* срок первой попытки истёк; удерживаемый handle может получить поздний UP */ -}; - -typedef void (*ncd_callback)(struct NODE_CONN_DIRECT* h, enum ncd_event event, void* arg); - -/* - * Открыть handle к узлу по node_id. - * Node info ищется через node_registry, fallback — SQLite. - * cb вызывается при изменении статуса / таймауте. - * Если conn уже готов — cb(NCD_EVENT_UP) через uasync_call_soon (не синхронно). - * До первой отправки дождаться UP. Результат: NCD_NEW/NCD_REUSED или NCD_ERR. - * При успехе вызывающий обязан закрыть *out_handle, в том числе после CLOSED. - */ -int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id, - ncd_callback cb, void* cb_arg, - struct NODE_CONN_DIRECT** out_handle, - struct ETCP_SOCKET* specific_sock); /* NULL — авто-подбор всех совместимых сокетов для линков */ - -/* - * То же, но с уже загруженным TOPO_NODE (ni не владеем — можно передать временный на стеке). - * ni должен содержать public_key, v4_addrs/v6_addrs для создания линков. - */ -int node_conn_direct_open_node(struct UTUN_INSTANCE* inst, uint64_t node_id, - ncd_callback cb, void* cb_arg, - struct NODE_CONN_DIRECT** out_handle, - struct TOPO_NODE* ni, /* публичный ключ + адреса пира (не владеем) */ - struct ETCP_SOCKET* specific_sock); /* NULL — авто-подбор */ - -/* Освободить handle и отменить его callbacks; другие владельцы сохраняют транспорт. */ -void node_conn_direct_close(struct NODE_CONN_DIRECT* h); - -/* Применить принятую запись из общего реестра к уже существующему соединению. - * Не создаёт соединение и не приобретает handle. Число новых линков или -1 при ошибке. */ -int node_conn_direct_update_node(struct UTUN_INSTANCE* inst, uint64_t node_id); - -/* Как close, но последний handle закрывает транспорт сразу, без fin_wait. - * При наличии других handle общий транспорт и их callbacks сохраняются. */ -void node_conn_direct_force_close(struct NODE_CONN_DIRECT* h); - -/* Сменить или сбросить (cb=NULL) callback на уже открытом handle. - * Не влияет на refcounting и состояние conn. */ -void node_conn_direct_set_callback(struct NODE_CONN_DIRECT* h, ncd_callback cb, void* cb_arg); - -/* Передать владение handle новому владельцу (смена callback + arg). - * После вызова handle принадлежит new_cb_arg, прежний владелец - * должен забыть указатель. Соединение не трогается. */ -void node_conn_direct_transfer(struct NODE_CONN_DIRECT* h, ncd_callback new_cb, void* new_cb_arg); - -/* Идентификатор узла; 0 для NULL. */ -uint64_t node_conn_direct_node_id(const struct NODE_CONN_DIRECT* h); - -/* Заимствованный транспорт, в том числе до UP; NULL после CLOSED. Не закрывать напрямую. */ -struct ETCP_CONN* node_conn_direct_get_conn(struct NODE_CONN_DIRECT* h); - -/* ─── Протокол CLOSE / KEEP_ALIVE (ETCP_ID_NCD_CONTROL = 0x12) ─── */ - -#define NCD_SUBCMD_CLOSE 0x01 -#define NCD_SUBCMD_KEEP_ALIVE 0x02 - -#pragma pack(push, 1) -struct ncd_control_msg { - uint8_t cmd; /* ETCP_ID_NCD_CONTROL */ - uint8_t subcmd; /* NCD_SUBCMD_CLOSE / KEEP_ALIVE */ - uint64_t node_id; /* node_id отправителя */ -}; -#pragma pack(pop) - -#define NCD_CONTROL_MSG_SIZE sizeof(struct ncd_control_msg) - -/* ─── Управление линками на конкретном сокете ─── */ -/* - * ncd_add_socket_links — итерирует все активные NCD-соединения (ncd_registry), - * для каждого загружает TOPO_NODE с адресами пира и создаёт линки (etcp_link_new) - * на переданном сокете (только совместимые family: v4/v6). Аналог ncd_create_links - * но вызывается извне (auto_socket) при добавлении нового интерфейса. - * Возвращает количество созданных линков (0 если нечего добавить или ошибка). - */ -int ncd_add_socket_links(struct UTUN_INSTANCE* inst, struct ETCP_SOCKET* sock); - -/* - * ncd_remove_socket_links — итерирует все активные NCD-соединения, - * для каждого закрывает линки (etcp_link_close) привязанные к переданному сокету. - * Вызывается при удалении сокета (интерфейс пропал). Возвращает количество закрытых линков. - */ -int ncd_remove_socket_links(struct UTUN_INSTANCE* inst, struct ETCP_SOCKET* sock); - -#endif diff --git a/src/transport_layer/reality_io.h1 b/src/transport_layer/reality_io.h1 deleted file mode 100644 index f6c80cda..00000000 --- a/src/transport_layer/reality_io.h1 +++ /dev/null @@ -1,40 +0,0 @@ -/* Поток записей отделён от внутреннего буфера STCP; все вызовы — в uasync-потоке владельца. - * CH -> SH + CCS + encrypted(EE/cover Certificate/cover CertificateVerify/Server Finished) - * -> CCS + encrypted(Client Finished) -> encrypted(STCP handshake и последующий поток). - * Проверка стороны использует Finished, cover Certificate/CertificateVerify не являются PKI. - * Root = HKDF-SHA256(AuthKey || X25519(client_ephemeral, server_ephemeral), SHA256(CH || SH), - * "uTun-reality-record-v2"); в transcript входят handshake-заголовки, но не record-заголовки. - * От root раздельно выводятся client-traffic/server-traffic и их key/iv/finished-ключи. - * После собственного SH fallback запрещён. До него relay получает весь исходный буфер без нормализации. - * Таймеры/списки/кеш replay принадлежат instance; destroy принудительно закрывает I/O без ожидания callbacks. */ -#ifndef REALITY_IO_H -#define REALITY_IO_H -#include "reality.h" -#include "etcp_padding.h" -#ifdef __cplusplus -extern "C" { -#endif -struct stcp_conn; -struct reality_io; -struct reality_replay_cache; -struct reality_relay; -struct reality_owner { - struct reality_replay_cache *replay; - struct reality_relay *relays; - unsigned relay_count; -}; -int reality_io_client_start(struct stcp_conn *c, const struct reality_client_config *cfg, uint32_t now, - const struct ETCP_PADDING *padding, void (*ready)(struct stcp_conn *)); -int reality_io_server_start(struct stcp_conn *c, void (*ready)(struct stcp_conn *)); -size_t reality_io_buffered(const struct stcp_conn *c); -const char* reality_io_state_name(const struct stcp_conn *c); -int reality_io_read(struct stcp_conn *c); -void reality_io_resume(struct stcp_conn *c); -int reality_io_send(struct stcp_conn *c, uint8_t *data, size_t len); -int reality_io_close_notify(struct stcp_conn *c); -void reality_io_cleanup(struct stcp_conn *c); -void reality_owner_cleanup(struct reality_owner *owner); -#ifdef __cplusplus -} -#endif -#endif