- u_async.c: process immediate_queue BEFORE epoll_wait in uasync_poll - stcp_link.c: defensive NULL etcp_conn/etcp_link in stcp_link_close - utun_instance.c: move stcp_server_list_destroy_all to Phase J (before ETCP), add deferred drain in both Phase J and L - stcp.h/c: STCP_HS_ENC_CLIENT 6→38, STCP_HS_ENC_SERVER 7→39, exchange ed25519_pubkey in both handshake directions - etcp_connections.c: copy peer_ed25519 from STCP to ETCP_CONN in etcp_link_enter_ready_tcp; guard link->etcp in tcp_link_close_cb - chat_sync.c: fix lk->conn NULL dereference for TCP links - test_stcp.c: update stcp_server_create/stcp_client_connect callsites - tools/chat_tcp_test: change transport udp→tcp
282 lines
16 KiB
Markdown
282 lines
16 KiB
Markdown
# chatgui-android — Архитектура
|
||
|
||
## 1. Обзор
|
||
|
||
Android-версия чатгуи: P2P чат на базе STCP (Secure TCP) вместо ETCP/UDP.
|
||
Весь UDP-стек (ETCP, BBR, loadbalancer, pkt_normalizer, NAT, routing, TUN) исключён.
|
||
Сетевой транспорт: только STCP (X25519 + AES-CCM поверх TCP).
|
||
|
||
Приложение работает в двух режимах:
|
||
- **Headless** — без UI, с управляющим TCP-сокетом (для отладки сетевого стека)
|
||
- **Full UI** — Android приложение с Jetpack Compose интерфейсом
|
||
|
||
## 2. Уровни приложения
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────┐
|
||
│ Android App (Kotlin / Jetpack Compose) │
|
||
│ ├─ UI Layer (Compose) │
|
||
│ │ ├─ ChannelListScreen │
|
||
│ │ ├─ ChatScreen (MessageList + InputBar) │
|
||
│ │ ├─ CreateChannelDialog │
|
||
│ │ └─ JoinChannelDialog │
|
||
│ ├─ ViewModel Layer │
|
||
│ │ └─ ChatViewModel (StateFlow, Coroutines) │
|
||
│ ├─ Repository Layer │
|
||
│ │ ├─ ChatRepository (JNI → native) │
|
||
│ │ └─ DbRepository (Room, read-only) │
|
||
│ └─ NativeLib.kt (JNI declarations) │
|
||
├─────────────────────────────────────────────────┤
|
||
│ JNI Bridge (C: android_jni_bridge.c) │
|
||
│ ├─ Kotlin → C: init/send/create/connect │
|
||
│ └─ C → Kotlin: callbacks via JNI CallVoidMethod │
|
||
├─────────────────────────────────────────────────┤
|
||
│ Headless Control (встроен в libutun_lite) │
|
||
│ ├─ TCP control socket (текстовый протокол) │
|
||
│ ├─ Команды: connect, send, status, debug, ... │
|
||
│ └─ Events: MSG, PEER_ONLINE/OFFLINE, ... │
|
||
├─────────────────────────────────────────────────┤
|
||
│ libutun_lite.so │
|
||
│ ├─ Core: uasync, ll_queue, memory_pool, │
|
||
│ │ debug_config, timeout_heap │
|
||
│ ├─ Crypto: secure_channel (X25519+AES-CCM), │
|
||
│ │ crc32, sha256 │
|
||
│ ├─ Transport: STCP (server/client/link) │
|
||
│ ├─ Chat: chat_core, chat_event, chat_sync, │
|
||
│ │ member_sync, merkle_sync │
|
||
│ ├─ DB: sqlite3 (WAL, чтение из GUI, запись │
|
||
│ │ из uasync) │
|
||
│ └─ Platform: socket_compat, platform_compat │
|
||
│ (Linux/Android) │
|
||
└─────────────────────────────────────────────────┘
|
||
```
|
||
|
||
## 3. Потоковая модель (Android)
|
||
|
||
- **Main thread (UI)** — Compose rendering, ViewModel state
|
||
- **uasync thread** — event loop (один на процесс, как и в desktop-версии)
|
||
- STCP соединения: каждое = одно TCP-соединение в uasync
|
||
- chat_core: все DB-записи из этого потока
|
||
- chat_sync: P2P синхронизация через STCP
|
||
- **DB:** SQLite WAL mode
|
||
- uasync thread: INSERT/UPDATE/DELETE (через chat_core)
|
||
- Main thread: SELECT (через Room/DbRepository, read-only)
|
||
|
||
## 4. Потоковая модель (Headless, Linux)
|
||
|
||
Один процесс, один uasync-поток. Всё в одном потоке, включая control socket.
|
||
Дополнительный поток для control socket не нужен — uasync обрабатывает и сеть и control-команды.
|
||
|
||
## 5. STCP вместо ETCP — изменения
|
||
|
||
### 5.1. Что уходит
|
||
|
||
| Модуль | Причина |
|
||
|--------|---------|
|
||
| ETCP (etcp.c, etcp_api.c, etcp_connections.c, etcp_router.c, etcp_loadbalancer.c, etcp_bbr.c, etcp_connect.c) | Заменено на STCP link |
|
||
| BBR (bbr_v3.c) | Congestion control для ETCP |
|
||
| pkt_normalizer.c | Фрагментация/сборка — не нужна для потокового STCP |
|
||
| dummynet.c | Эмулятор сети для отладки ETCP |
|
||
| tun_if/tun_linux/tun_windows/tun_route | Нет VPN-туннеля |
|
||
| routing, route_lib, route6_lib, route_ping, route_connectivity | Нет роутинга трафика |
|
||
| eim_nat, nat_transport | Нет NAT-транспорта |
|
||
| topo_group, topo_node, topo_node_lmdb | BGP-топология — прямые P2P |
|
||
| conn_mgr | Менеджер ETCP-соединений |
|
||
| firewall, proxy/*, lwip_tcp/*, uip/* | Не нужны |
|
||
| ntp_time, ntp_node_time | Пока не нужны (можно добавить позже) |
|
||
| packet_dump, etcp_debug, etcp_dump | Отладочные утилиты ETCP |
|
||
|
||
### 5.2. chat_sync — адаптация
|
||
|
||
Десктопная версия chat_sync использует ETCP-роутер: множество каналов мультиплексируется
|
||
через одно ETCP-соединение. В Android-версии каждое P2P-соединение — отдельный STCP линк.
|
||
|
||
Замены в chat_sync.c:
|
||
- `etcp_send(conn, svc_id, data)` → `stcp_link_send(link, data)`
|
||
- `etcp_api_bind(svc_id, callback)` → приём из `stcp_link` rx_queue
|
||
- Каждый peer = одно `stcp_link` соединение
|
||
- Сервер: `stcp_server_listen()` принимает входящие
|
||
|
||
### 5.3. merkle_sync — адаптация
|
||
|
||
merkle_sync — универсальный протокол синхронизации на Merkle-деревьях.
|
||
В десктопе работает поверх ETCP-сервиса. В Android-версии:
|
||
- Вместо etcp_send в рамках ETCP-сервиса → отправка напрямую через stcp_link
|
||
- Формат wire-сообщений не меняется (MSG_HASHES, MSG_REQUEST, MSG_BATCH)
|
||
- Изменяется только транспорт: вместо ETCP datagram → STCP stream
|
||
|
||
## 6. Control Socket (Headless)
|
||
|
||
Управляющий TCP-сокет для отладки и управления без UI.
|
||
Аналог `control_server` из utun, но с текстовым протоколом для простоты ручного тестирования.
|
||
|
||
Порт: настраивается в конфиге (по умолчанию 9999).
|
||
|
||
### Команды (клиент → сервер)
|
||
|
||
```
|
||
connect <addr> <port> [pubkey_hex] — STCP-подключение к пиру
|
||
disconnect <node_id> — отключиться от пира
|
||
connections — список активных STCP-соединений
|
||
create_channel <name> — создать канал
|
||
invite <channel_id> — invite-ссылка (utun://...)
|
||
join <invite_string> — подключиться по invite
|
||
send <channel_id> <text> — отправить сообщение
|
||
messages <channel_id> [limit] — последние сообщения
|
||
channels — список каналов
|
||
status — статус (соединения, каналы, ключи)
|
||
debug <cat>=<level> — debug level на лету
|
||
debug_level — показать уровни отладки
|
||
subscribe <events> — подписаться на push-события
|
||
help — список команд
|
||
quit — отключиться от control (не остановка сервера)
|
||
```
|
||
|
||
### Unsolicited events (сервер → клиент, только после subscribe)
|
||
|
||
```
|
||
EVENT MSG <channel_id> <author_hex> — новое сообщение
|
||
EVENT PEER_ONLINE <node_id_hex> — пир подключился
|
||
EVENT PEER_OFFLINE <node_id_hex> — пир отключился
|
||
EVENT CHANNEL_CREATED <channel_id> — канал создан (локально)
|
||
EVENT CHANNEL_JOINED <channel_id> — канал принят (по invite)
|
||
EVENT CONN_RESULT <node_id_hex> <ok|err> — результат connect
|
||
EVENT DB_READY — БД открыта и готова
|
||
EVENT STATUS <text> — периодический статус
|
||
```
|
||
|
||
## 7. База данных (SQLite)
|
||
|
||
Схема та же, что в десктопной версии chatgui (см. `tools/chatgui/doc/desc.txt`).
|
||
БД открывается в WAL-режиме. Записи — из uasync-потока, чтение — из любого.
|
||
|
||
Таблицы:
|
||
- `channels` — каналы (channel_id, name, ключи X25519/Ed25519, подписи)
|
||
- `msg_<channel_id>` — сообщения per-channel (id, author, content_type, data, timestamp, chain_hash, signature)
|
||
- `peers_<channel_id>` — участники канала (node_id, online, x25519, ed25519, join_sig, адреса)
|
||
- `nodes` — узлы (node_id, x25519_pubkey, ed25519_pubkey, name, online)
|
||
- `node_addresses` — адреса узлов (node_id, family, address, port)
|
||
- `accounts` — локальные аккаунты/контакты
|
||
- `ui_state` — key-value для UI состояния
|
||
- `merkle_tree_hash` — сохранённые хеши Merkle-дерева
|
||
- `local_identity` — локальные ключи узла
|
||
|
||
## 8. Структура каталогов
|
||
|
||
```
|
||
tools/chatgui-android/
|
||
├── doc/
|
||
│ ├── ARCHITECTURE.md # этот документ
|
||
│ └── IMPL_PLAN.md # план реализации с этапами
|
||
├── libutun_lite/ # урезанное C-ядро (статическая библиотека)
|
||
│ ├── CMakeLists.txt
|
||
│ └── utun_lite.h # публичное API
|
||
├── headless/ # CLI для Linux (тестирование без Android)
|
||
│ ├── CMakeLists.txt
|
||
│ ├── headless_main.c # точка входа
|
||
│ └── headless_control.c/h # управляющий TCP-сокет
|
||
├── jni_bridge/ # JNI прослойка
|
||
│ ├── CMakeLists.txt # (только для Android NDK)
|
||
│ └── android_jni_bridge.c # JNI-функции + коллбэки
|
||
├── app/ # Android приложение
|
||
│ ├── build.gradle.kts
|
||
│ └── src/main/
|
||
│ ├── AndroidManifest.xml
|
||
│ ├── cpp/ # NDK: jni_bridge + линковка libutun_lite
|
||
│ │ └── CMakeLists.txt
|
||
│ ├── java/com/utun/chat/
|
||
│ │ ├── ChatApplication.kt
|
||
│ │ ├── MainActivity.kt
|
||
│ │ ├── ui/screens/ # Compose экраны
|
||
│ │ ├── ui/components/# Compose компоненты
|
||
│ │ ├── viewmodel/ # ViewModels
|
||
│ │ ├── data/ # Repository, NativeLib.kt, Room DAOs
|
||
│ │ └── headless/ # HeadlessService.kt (фоновый сервис)
|
||
│ └── res/
|
||
└── CMakeLists.txt # корневой (для headless + libutun_lite)
|
||
```
|
||
|
||
## 9. Минимальный набор C-файлов (libutun_lite)
|
||
|
||
### lib/ (infrastructure)
|
||
- `u_async.c/h` — event loop (epoll на Linux, poll/select fallback)
|
||
- `ll_queue.c/h` — lock-free очередь с хеш-индексом
|
||
- `memory_pool.c/h` — пулы объектов
|
||
- `debug_config.c/h` — логирование (уровни, категории, файл/консоль)
|
||
- `timeout_heap.c/h` — min-heap таймеров
|
||
- `sha256.c/h` — SHA256 (fallback; приоритет OpenSSL)
|
||
- `mem.c/h` — u_malloc/u_free/u_calloc (wrappers)
|
||
- `platform_compat.c/h` — кроссплатформенность (byte order, time, random)
|
||
- `socket_compat.c/h` — кроссплатформенные сокеты
|
||
- `serialize.c/h` — бинарная сериализация
|
||
|
||
### src/transport_layer/ (crypto + STCP)
|
||
- `secure_channel.c/h` — AES-CCM + X25519 key exchange + pubkey obfuscation
|
||
- `crc32.c/h` — CRC32 checksum
|
||
- `stcp.c/h` — STCP connection lifecycle (session keys, buffers, state machine)
|
||
- `stcp_server.c/h` — STCP server (listen, accept, handshake)
|
||
- `stcp_client.c/h` — STCP client (connect, handshake)
|
||
- `stcp_link.c/h` — STCP link management (обёртка над stcp_conn для etcp-подобного API)
|
||
|
||
### src/chat/ (чатовая логика)
|
||
- `chat_core.c/h` + `chat_core_priv.h` — центральный API чата (send, create channel, connect)
|
||
- `chat_event.c/h` — система нотификаций (MSG_RECEIVED, PEER_ONLINE, ...)
|
||
- `chat_channel.c` — операции с каналами (создание, invite, join)
|
||
- `chat_msg.c` — приём/отправка/сохранение сообщений
|
||
- `chat_status.c` — сбор статуса для control socket / UI
|
||
- `chat_profile.c` — профиль узла (имя, ключи)
|
||
- `chat_sync.c/h` — P2P синхронизация (адаптирована под STCP)
|
||
- `member_sync.c/h` — синхронизация мемберов
|
||
- `merkle_sync.c/h` — Merkle-дерево синхронизации
|
||
- `db_sync.c/h` — DB синхронизация (вставка/обновление записей синхронизации)
|
||
|
||
### Упрощённый вариант src/ (без TUN/ETCP/BGP)
|
||
- `utun_instance_lite.c/h` — облегчённый instance (только ua, my_keys, db, stcp_server, control_socket)
|
||
- `config_parser.c/h` — парсинг конфига (без ETCP/TUN/BGP-секций)
|
||
|
||
### Внешние
|
||
- `lib/sqlite3.c/h` — SQLite amalgamation
|
||
- OpenSSL (Crypto) — SHA256, AES-CCM, X25519, Ed25519
|
||
|
||
## 10. Конфиг (chatgui-android.cfg)
|
||
|
||
Формат INI, упрощённый относительно десктопной версии:
|
||
|
||
```ini
|
||
[node]
|
||
private_key = hex...
|
||
public_key = hex...
|
||
node_name = My Node
|
||
listen_port = 12345 ; STCP server port
|
||
|
||
[control]
|
||
port = 9999 ; управляющий сокет
|
||
bind_ip = 127.0.0.1
|
||
|
||
[db]
|
||
path = chat_data/chats.db
|
||
|
||
[debug]
|
||
console_level = info
|
||
file_level = debug
|
||
log_file = utun.log
|
||
debug_categories = stcp=debug,chat_core=info
|
||
```
|
||
|
||
## 11. Отличие от десктопной версии
|
||
|
||
| Аспект | Desktop (chatgui) | Android (chatgui-android) |
|
||
|--------|------------------|--------------------------|
|
||
| UI | Qt 6 Widgets (C++) | Jetpack Compose (Kotlin) |
|
||
| Bridge | gui_bridge (Qt signals) | JNI callbacks + StateFlow |
|
||
| Core сборка | CMake → libutun.a (все src/) | CMake → libutun_lite.a (выборочно) |
|
||
| Транспорт | ETCP (UDP) + STCP (TCP) | STCP только (TCP) |
|
||
| VPN | TUN + routing + BGP | Нет |
|
||
| NAT | EIM NAT engine | Нет |
|
||
| Аудио | miniaudio + opus | Нет (пока) |
|
||
| Эмодзи/анимации | rlottie + TGS | Нет (пока) |
|
||
| QR | zxing-cpp | Нет (пока) |
|
||
| FFmpeg | Да | Нет |
|
||
| Control | control_server (binary protocol) | headless_control (text protocol) |
|
||
| Платформы | Linux, FreeBSD, Windows | Linux (headless), Android (app) |
|