129 lines
12 KiB
Plaintext
129 lines
12 KiB
Plaintext
Chat: исправление приглашений и проверка контрактов — 26.10.2026
|
||
|
||
Граница работы
|
||
|
||
В начале аудита по /home/user/utun-doc-audit-checklist.txt установлены два дефекта:
|
||
успех invite_link_decode без узла подключения и разыменование непроверенного
|
||
выделения cm_invite_wrap. После согласования архитектуры исправлен весь путь
|
||
команды JOIN; добавлены тесты контрактов, отказов и жизненного цикла.
|
||
Полный аудит всех модулей src/chat не завершён. chat_sync.h остаётся [~].
|
||
|
||
Реализация
|
||
|
||
1. invite_link.c/.h — единый C-кодек для headless, Qt и Kotlin/JNI.
|
||
Только версия 0x03, строгий канонический base64 с padding, полный разбор,
|
||
одинаковый ключ во всех блоках, 1..32 адреса, family=4/6, proto=1/2/6,
|
||
ненулевой порт, согласованный REALITY. Канал — 1..INT64_MAX, join_key —
|
||
любой ненулевой uint64. Нулевой первый байт публичного ключа допустим.
|
||
Строки ограничены, превышение длины отклоняется; скрытый NUL не принимается.
|
||
Успех decode полностью определяет InviteData; ошибка оставляет out прежним.
|
||
Encode и сериализация адресов также не меняют выход при отказе.
|
||
Максимум с NUL — INVITE_LINK_MAX=1552: 32 IPv6, REALITY и пароль127 байт.
|
||
Из frontend удалены отдельные реализации декодирования; Qt/Kotlin только
|
||
преобразуют результат C-кодека в своё представление.
|
||
|
||
2. chat_sync_join_link/offer_link выполняются только в uasync и принимают ссылку.
|
||
Промежуточные chat_invite/addrs_data/cm_invite_wrap удалены. NCD bootstrap
|
||
строится целиком, включая REALITY; ошибка освобождает все временные адреса.
|
||
Общий объект локальной операции хранит роль, фазу, request/attempt, NCD и deadline.
|
||
PREPARE не реагирует на UP до установки handle; затем уже работающий транспорт
|
||
запускает обмен без ожидания повторного UP. Другой владелец сохраняет свой NCD.
|
||
BUSY относится к локальной операции; чужие JOIN обслуживаются независимо.
|
||
|
||
3. INFO_REQ/RESP, REQUEST, READY и ERROR несут attempt_id:8BE сразу после type.
|
||
JOIN_READY содержит также ровно8 байт ожидаемого group_id. Ответ сопоставляется
|
||
с peer/group/attempt/phase; повторное использование ссылки создаёт новый attempt.
|
||
Connection-узел хранит отдельные waiters попыток; повторный запрос не затирает
|
||
токен прежнего waiter. Есть deadline и ограничение8 waiters на peer; просроченные
|
||
удаляются при новых запросах и штатном обновлении кеша.
|
||
CHANNEL_INVITE переносит предложение и join_key; принимающий создаёт свой attempt.
|
||
Регистрация ключа A↔C и подписанные записи участников не используют attempt_id.
|
||
Сетевой формат JOIN изменён без поддержки старых узлов, согласно devel-контракту.
|
||
|
||
4. chat_join_port — отдельная удерживаемая ссылка frontend на вход команд.
|
||
Submit копирует ссылку, резервирует весь posted_task до принятия команды и
|
||
публикует без дополнительного выделения памяти. Закрытие и публикация защищены
|
||
mutex. Закрытый порт не содержит instance/uasync и не оживает при restart.
|
||
Close отменяет ожидающие команды; уже извлечённый uasync batch исполнит только
|
||
освобождение. Arg встроен в выделение task, повторного освобождения нет.
|
||
Qt и instance_lite публикуют/удерживают порт под собственным mutex; GUI/JNI
|
||
не читают chat_sync из внешнего потока. Chat stop закрывает приём до workers.
|
||
Request интерфейса не равен сетевому attempt. Headless использует request=0,
|
||
сохраняя собственную корреляцию JSON-команд отдельно от GUI.
|
||
|
||
5. Завершение: отделение локальной операции, снятие таймеров, освобождение своего
|
||
handle, затем единое событие peer:8/result:4/channel:8/request:8 (native).
|
||
Обработчик события может сразу начать новую попытку. Ранний отказ core не даёт
|
||
события; мост завершает свою уже принятую команду этим отказом. Принятая core
|
||
попытка получает один результат, включая cancel/delete/stop.
|
||
Cancel не откатывает членство, которое уже сохранил другой узел, и не удаляет
|
||
принятый NCD snapshot или рабочие линки других владельцев.
|
||
|
||
6. JOIN_INFO_RESP: подписанное описание и member/Merkle записываются в одной SQL
|
||
транзакции. Проверяется привязка connection-member к транспортному peer и
|
||
неизменность уже известных канальных ключей. Ошибка откатывает SQL и не создаёт
|
||
CHAT-группу. После commit публикуются runtime-ресурсы и уведомления member_sync.
|
||
Предыдущая семантика отложенной проверки неизвестного родителя сохранена;
|
||
успешный apply не называется подтверждением всей цепочки приглашений.
|
||
Ensure_channel_ready возвращает ошибку и сохраняет необходимый порядок:
|
||
группа → подписка → db_sync. При отказе убираются только новые runtime-ресурсы.
|
||
Проверенные данные после commit сохраняются для повторной подготовки.
|
||
Ключи приглашения, пароль и исходная ссылка не печатаются в новых логах.
|
||
|
||
Тесты
|
||
|
||
- test_invite_codec: 116342 проверки. Roundtrip1..32 адресов IPv4/IPv6/mixed/REALITY,
|
||
пароль127, SNI63, максимальная ссылка1551 байт; точный буфер и буфер на байт меньше,
|
||
сохранность выходов, усечения, алфавит всех256 байтов, старые версии, конфликт
|
||
ключей блоков, неизвестные/отсутствующие поля и границы значений.
|
||
- test_chat_join_faults: настоящий controller/NCD/SQLite, перехват только доставки
|
||
пакетов и точек отказа. Каждая аллокация подготовки, включая REALITY, отказы
|
||
transport/info/ready deadlines, send и NCD; повтор после отказа и чужое владение.
|
||
Запоздавшие ERROR/READY, чужой group/короткий READY, повтор результата, BUSY,
|
||
вложенный UP во время PREPARE и новый JOIN из обработчика завершения.
|
||
SQL-trigger и неверная подпись member откатывают канал; отказы group/db_sync/
|
||
подписки после commit сохраняют проверенные данные и убирают runtime-ресурсы.
|
||
Узел обслуживает чужой JOIN во время своей попытки. Проверены queued/active
|
||
дубликаты request, producer другого потока, старый порт после restart,
|
||
stop между копированием аргументов и публикацией (condvar-барьер), stop внутри
|
||
уже извлечённого batch. После teardown число u_malloc-блоков возвращается к исходному.
|
||
- test_chat_join_e2e: настоящий обмен A!=C, A==C, неверный ключ.
|
||
- test_dm_invite: приглашение из DM и реальное вступление.
|
||
- test_services: независимый lifecycle сервисов.
|
||
- test_chat_sync_schedule: фикстуры приведены к наличию активной попытки/waiter;
|
||
подтверждается синхронизация пары после JOIN_READY без нового транспортного UP.
|
||
- Qt test_invite_links/test_local_invite_ui: ссылки и UI на общем кодеке.
|
||
|
||
Результаты окончательных прогонов и ограничения приводятся ниже.
|
||
|
||
Итоговые результаты
|
||
|
||
Linux check.sh: 196/196 PASS, 0 failed, 0 skipped; proxy9/9, burst1/1,
|
||
load8/8, 134217728 проверенных байт, 190 секунд.
|
||
Лог: /tmp/chat-join-complete-check.log.
|
||
Отдельный финальный test_chat_join_faults с condvar-гонкой и вложенным UP PASS;
|
||
лог: /tmp/chat-join-race-final.log. Тот же вариант включён в окончательный check.sh.
|
||
|
||
ASAN/UBSan/LSan: 6/6 PASS, detect_leaks=1, halt_on_error=1.
|
||
Кодек, отказы JOIN, настоящий E2E, DM invite, services и планировщик.
|
||
В изолированной копии /tmp/utun-chat-join-sanitizers согласованно инструментированы
|
||
lib/src/Opus. Правка флагов Opus выполнена только в копии: рабочая сборка не смешивается
|
||
с sanitizer-объектами. Сводка: /tmp/chat-join-sanitizer-results.log;
|
||
по каждому набору: /tmp/chat-join-sanitizer-test_*.log.
|
||
|
||
Desktop CMake build PASS: /tmp/chat-join-desktop-verified-build.log.
|
||
Qt invite/local_invite: 2/2 PASS, /tmp/chat-join-desktop-verified-tests.log.
|
||
Android assembleDebug --offline PASS (JNI, Kotlin и APK; без установки на устройства):
|
||
/tmp/chat-join-android-verified-build.log.
|
||
Дополнительный старый Linux CMake-каркас Android headless не собрался из-за отсутствия
|
||
include speex/speex_echo.h в его собственном списке путей; этот отдельный каркас
|
||
не заменяет успешную APK-сборку и native Linux-фикстуры основного набора.
|
||
Windows/FreeBSD native build/runtime не выполнялись. git diff --check PASS.
|
||
|
||
Промежуточные отказы проверок устранены: размер size_t и порядок _GNU_SOURCE в
|
||
instance_lite, старое объявление InviteDataC в JNI; затем фикстура планировщика
|
||
обновлена под обязательные waiter/активную попытку. Тесты runtime-отката выявили
|
||
зависимость db_sync от группы; требуемый порядок восстановлен, добавлена очистка
|
||
новой группы при отказе истории/подписки. Это покрыто отрицательными сценариями.
|
||
Исходные изменения аудита и итоговые правки не коммитились и не публиковались.
|