76 lines
8.3 KiB
Markdown
76 lines
8.3 KiB
Markdown
# Control Server (control_server)
|
||
|
||
## 1. Назначение
|
||
TCP-сервер для мониторинга ETCP-соединений. Принимает подключения от GUI-клиента `etcpmon`, отдаёт по запросу метрики соединений/каналов/TUN/роутера, список узлов BGP-топологии, позволяет менять уровни отладки на лету. Уведомляет подписанных клиентов об изменениях узлов через `control_server_notify_node_change()`.
|
||
|
||
## 2. Как пользоваться
|
||
1. Вызвать `control_server_init()` — создаёт слушающий TCP-сокет на адресе из конфига `control_sock`, регистрирует accept-колбэк в uasync.
|
||
2. Выполнять цикл uasync: read-колбэк сам принимает и разбирает команды. Периодический вызов
|
||
`control_server_process_updates()` не требуется; эта функция лишь повторно разбирает уже накопленные данные.
|
||
3. При изменении/удалении узла UTUN-группы вызывать `control_server_notify_node_change()` /
|
||
`control_server_notify_node_removed()` — сервер отметит ID и отправит актуальное состояние при освобождении TX.
|
||
4. При остановке вызвать `control_server_shutdown()`.
|
||
|
||
**Нюансы:**
|
||
- Доступ разрешён только IPv4-клиентам по `control_allow` в конфиге; без правил доступ запрещён. IPv6-клиенты отклоняются.
|
||
- В покое клиент отключается после 30 секунд без команд. При активной отправке тот же таймер
|
||
отсчитывает 30 секунд без положительного `send()`; поступление команд его не продлевает.
|
||
- Лог пишется в `control_server.log`: дампы содержат первые 256 байт каждого чтения RX и некоторых ответов TX.
|
||
- `control_server_process_updates()` разбирает команды; метрики отправляются только по `CMD_GET_METRICS`.
|
||
- Очередь отправки владеет исходными буферами до полной отправки или отключения; частичная отправка хранит отдельное смещение.
|
||
- В TX помещается один кадр до 32 КиБ. Следующий producer ждёт пустой очереди через deferred
|
||
`queue_waiter_wait()`. Чтение сокета и разбор уже принятого RX-буфера приостановлены до освобождения TX.
|
||
- Подписка сохраняет ID текущих узлов (`8 × N` байт), сериализует их по одному при освобождении TX.
|
||
Узлы повторно ищутся по ID; удалённые до своей очереди пропускаются. После начального списка
|
||
отправляется `NODE_INFO_END` с seq запроса, затем накопленные live-изменения.
|
||
- Live-изменения объединяются по ID (последнее обновление/удаление); предел — 256 различных ID.
|
||
При переполнении подписчик отключается с WARN. CHAT-узлы в эту подписку не входят.
|
||
- При stop/ошибке отменяются timer и waiter, включая уже запланированный callback, затем освобождаются
|
||
список ID и TX-буфер. `control_client_send()` сам клиента не освобождает: ошибку обрабатывает владелец callback.
|
||
- Если список сокетов превышает предел сообщения (32 768 байт; сейчас помещается 230 записей),
|
||
возвращается `RSP_ERROR` с кодом `SERVER_BUSY`. Список не усекается; сокеты `probe_only` не учитываются.
|
||
- `SET_DEBUG_CONFIG` требует ровно `2 + category_count` байт, не более 64 категорий.
|
||
Несоответствие длины закрывает соединение без применения настроек.
|
||
|
||
## 3. API
|
||
|
||
### Структуры
|
||
|
||
| Структура | Назначение |
|
||
|-----------|-----------|
|
||
| `struct control_server` | Состояние сервера: `listen_fd`, связный список `clients`, uasync-контекст, счётчик клиентов. |
|
||
| `struct control_client` | Состояние клиента: `fd`, буфер приёма (`recv_buffer`), `output_queue` для асинхронной отправки, `selected_peer_id`, флаг подписки на узлы. |
|
||
|
||
### Функции
|
||
|
||
| Функция | Назначение |
|
||
|---------|-----------|
|
||
| `control_server_init(server, ua, instance, bind_addr, max_clients)` | Создать слушающий сокет, зарегистрировать в uasync. Возвращает 0 / -1. |
|
||
| `control_server_shutdown(server)` | Закрыть всех клиентов, освободить слушающий сокет, закрыть лог-файл. |
|
||
| `control_server_process_updates(server)` | Повторно разобрать накопленные данные всех клиентов; вызов необязателен. |
|
||
| `control_server_get_client_count(server)` | Вернуть количество подключённых клиентов. |
|
||
| `control_server_notify_node_change(server, node)` | Разослать подписанным клиентам сериализованную информацию об узле. |
|
||
| `control_server_notify_node_removed(server, node_id)` | Разослать подписанным клиентам уведомление об удалении узла. |
|
||
|
||
### Поддерживаемые команды ETCPMON
|
||
|
||
| Команда | Ответ | Описание |
|
||
|---------|-------|----------|
|
||
| `CMD_LIST_CONN` | `RSP_CONN_LIST` | Список активных ETCP-соединений. |
|
||
| `CMD_SELECT_CONN` | — | Выбрать соединение по `peer_node_id` для метрик. |
|
||
| `CMD_GET_METRICS` | `RSP_METRICS` | Полные метрики: ETCP, TUN, router, все каналы с BBR. |
|
||
| `CMD_LIST_SOCKETS` | `RSP_SOCKET_LIST` | Список локальных сокетов с NAT-типом и NAT-адресом. |
|
||
| `CMD_ACTION` | `RSP_ACTION_RESULT` или `RSP_ERROR`, с seq запроса | Полные имена `"nodes"`/`"nat"`; `nat` подтверждает запуск проверки, неизвестное имя даёт ошибку. |
|
||
| `CMD_GET_DEBUG_CONFIG` | `RSP_DEBUG_CONFIG` | Текущие уровни отладки (глобальный + по категориям). |
|
||
| `CMD_SET_DEBUG_CONFIG` | — | Установить уровни отладки. |
|
||
| `CMD_SUBSCRIBE_NODES` | `RSP_NODE_INFO` (список) + `RSP_NODE_INFO_END` | Подписка на изменения узлов + текущий список. |
|
||
| `CMD_DISCONNECT` | — | Отключение клиента. |
|
||
|
||
Общий формат задаёт `tools/etcpmon/etcpmon_protocol.h`: 4-байтовый заголовок с `seq_id`, packed-структуры,
|
||
целые в порядке байтов хоста, без согласования версии/шифрования. Обычный ответ копирует `seq_id`
|
||
запроса; снимки `NODE_INFO` имеют `seq=0`, маркер `NODE_INFO_END` — seq запроса подписки.
|
||
`NODE_INFO` содержит префикс `01 04` и результат `topo_node_serialize()` для UTUN с подсетями.
|
||
|
||
Action требует ровно 32 байта payload с NUL внутри поля. Повреждённая команда закрывает соединение;
|
||
неизвестное корректное имя или недоступная служба возвращают `RSP_ERROR` без разрыва TCP.
|