14 KiB
Connection Manager
conn_mgr подбирает путь для медиа, файлов и звонков. Один менеджер принадлежит
одной группе. Несколько сервисов могут удерживать свои handles к одному узлу:
транспорт и пробы общие, callbacks и отмена принадлежат каждому владельцу.
Все операции выполняются в uasync-потоке.
Расписание подключения
Все сроки отсчитываются от одного start_tb, а не от таймаута предыдущей пробы.
| Доступность извне | DIRECT | LOCAL | REVERSE | INDIRECT |
|---|---|---|---|---|
| Мы доступны, пир нет | Сразу | В составе DIRECT | Сразу | 1000 мс |
| Оба доступны | Сразу | В составе DIRECT | 500 мс | 1000 мс |
| Мы недоступны, пир доступен | Сразу | В составе DIRECT | 500 мс | 1000 мс |
| Оба недоступны | Сразу | Сразу | 500 мс | Сразу |
Доступность определяется по опубликованным адресам и общей классификации
sock_match: публичный IPv4, EIM/прямой NAT, пригодный глобальный IPv6.
Приватные адреса EIM-интерфейса не считаются внешними.
DIRECT использует NCD, который создаёт UDP/TCP-линки по известной записи узла, включая IPv4/IPv6, LAN и Reality-параметры. LOCAL — те же локальные handshake-пробы: отдельные ping-контексты и повторные линки не создаются. REVERSE просит получателя открыть/дополнить NCD к отправителю по уже известному подписанному снимку. Запрос обрабатывается и при CONNECTING, и при работе через посредника. Повторы запроса идут раз в секунду в течение трёх секунд.
Запуск нового способа не закрывает NCD и не удаляет предыдущие линки. NCD TIMEOUT по умолчанию через две секунды завершает только ожидание первой прямой попытки; удерживаемый handle продолжает получать поздний UP.
Рабочий путь
Состояние доставки (state, conn_type) отделено от состояния проб.
Посредник используется сразу после успешного согласования, пока прямой путь
ещё устанавливается. Прямой транспорт становится рабочим после READY сессии
нужной группы. Тогда он имеет приоритет независимо от порядка ответов INDIRECT.
Переходы между посредником и прямым путём не сбрасывают состояние ETCP_ROUTER_CONN,
его очереди, seq и неподтверждённые пакеты. Список подтверждённых посредников
сохраняется как резерв. Для выбора посредника проверяются READY первого плеча
и наличие объявления маршрута к получателю именно от этого посредника.
DIRECT/REVERSE определяются по текущим живым линкам: наличие исходящего означает
DIRECT, только входящие — REVERSE. Метка первого UP не используется как постоянный тип.
Окно звонка показывает фактический путь router, включая BGP fallback до готовности CM:
DIRECT/REVERSE/INDIRECT/NONE. Событие CHAT_EVT_CALL_CONNECTION содержит call_id,
тип и next hop; публикуется при изменении. Проверка идёт раз в секунду общим таймером
звонка, сразу при начале/принятии и при событиях CM. Завершение сбрасывает статус
и отменяет таймер. Отображение одинаково в Qt и Android.
Один timer на entry обслуживает ближайшее запланированное действие, повторы и
общий предел ожидания. READY и изменение маршрутов перепроверяют пути через
conn_mgr_routes_changed(), без периодического опроса работающих соединений.
Начальное ожидание ограничено 15 секундами от срока запуска INDIRECT, даже если
нет кандидатов/RTT/ответа. Получение ответа не отменяет этот предел.
Входящие записи без сервисных handles удаляются по этому сроку; групповые владельцы
сохраняют общий транспорт.
После готовности прямого пути новые дополнительные пробы не запускаются. Уже начатое согласование INDIRECT может завершиться и сохранить резерв.
Восстановление
Потребность в доставке живёт столько же, сколько сервисные handles. Начальный TIMEOUT и срок очередного цикла проб независимы: начальный TIMEOUT приходит один раз, если до начального дедлайна ни один путь не заработал. Он не прекращает поиск.
При потере прямого пути сразу используется пригодный подтверждённый резерв. Если потеряны все пути, сервис получает DOWN. Затем новый цикл запускает DIRECT и LOCAL сразу, REVERSE через 0/500 мс; при отсутствии пригодного резерва INDIRECT запускается сразу независимо от NAT. Рабочий посредник сохраняется во время проб. Каждый цикл ограничен 15 секундами. Между неудачными циклами пауза растёт: 1 → 2 → 4 → 8 → 15 секунд, далее остаётся 15 секунд. Подтверждённый прямой READY останавливает поиск и сбрасывает паузу.
Свежая версия записи пира или изменение локальных сокетов обходят паузу и запускают
новую пробу. Изменения сокетов передаются через conn_mgr_network_changed().
Работающие прямые соединения дополнительных проб не требуют. NCD сохраняется
между циклами; новый handle создаётся только после CLOSED. Существующие UDP-пробы
и TCP reconnect продолжаются; отсутствующие адресные линки добавляются без дублей.
Каждый исходящий цикл имеет новые request_id. Ответы старых/завершённых циклов игнорируются. Входящие запросы имеют отдельный срок обработки: новый request_id начинает новый срок, повтор того же запроса его не продлевает. Входящая запись без сервисного владельца обслуживает запрос, затем освобождается и сама постоянное восстановление не запускает. Закрытие последнего сервисного handle отменяет таймеры и отложенные callbacks; групповые владельцы транспорта продолжают жить независимо.
Восстановление зависит от доступных адресов, маршрутов и READY-сессий. Оно не меняет порог обнаружения транспортного обрыва ETCP и таймаут завершения звонка без медиа.
INDIRECT
- Инициатор отправляет EXCHANGE_REQ со своими кандидатами.
- Получатель отвечает EXCHANGE_RESP: свои кандидаты и RTT до кандидатов инициатора.
- Инициатор объединяет кандидатов без дублей, исключает себя/получателя, неизвестные RTT и узлы без прямой READY-сессии. Выбирает до трёх по сумме RTT обоих плеч; при равных RTT — по node_id.
- INTERM_SELECTED отправляется через выбранный next hop. Пока нет подтверждения, сервис ещё не получает UP.
- Получатель проверяет своё плечо и возвращает INTERM_ACK через выбранного посредника. Инициатор принимает только узлы из собственного выбора.
Пустой список и RTT=0/UINT16_MAX не дают успеха. Реальный нулевой текущий RTT
после уже выполненного замера округляется до 1, чтобы отличать его от отсутствия
замера. При отсутствии пригодных кандидатов EXCHANGE повторяется раз в секунду
до общего дедлайна; новые кандидаты могут появиться благодаря фоновым проверкам.
Запрос работает и при одностороннем conn_mgr_open().
Ответы привязаны одновременно к отправителю и request_id. Повторы идемпотентны;
поздний ответ не может вытеснить рабочий прямой путь.
Wire-структуры описаны в conn_mgr_priv.h. DIRECT_REQ содержит только request_id.
INTERM_SELECTED и INTERM_ACK содержат request_id и до трёх {node_id, rtt}.
Совместимость с прежним адресным DIRECT_REQ не поддерживается.
API и владение
conn_mgr_open()создаёт отдельный handle. Если попытка уже идёт, добавляет ожидающего; если путь готов, доставляет UP отложенно. Первый сервисный handle входящего пути запускает своё расписание проб, сохраняя уже работающий путь через посредника.- UP означает появление пригодного пути. Улучшение пути не повторяет UP.
- DOWN означает потерю рабочих путей; при живом резерве DOWN не доставляется.
- TIMEOUT означает, что начальное подключение не получило ни одного рабочего пути. При живом handle поиск продолжается. Ошибка отдельной пробы при живом посреднике не становится TIMEOUT для сервиса; после первого UP начального TIMEOUT уже не будет.
- DOWN/TIMEOUT не освобождают handle. Владелец обязан вызвать
conn_mgr_close(). - Закрытие последнего handle отменяет CM timer и callbacks и закрывает только NCD-владение CM. Группа и другие NCD-владельцы сохраняют транспорт.
conn_mgr_get_conn()возвращает заимствованный прямой транспорт либо NULL при INDIRECT/отсоединённом handle. Данные следует отправлять через router.
Диагностика CM — категория general: INFO показывает расписание, выбор и смену
пути с временем от старта, новые циклы и паузы; DEBUG — события NCD, RTT и обработку ответов; WARN/ERROR —
ошибки, недоступные пути и некорректные пакеты. Создание адресных линков NCD —
категория connection.
Проверки: test_conn_mgr, test_conn_mgr_handles, test_conn_mgr_already_connected,
test_conn_mgr_phases. Последний проверяет расписание, LAN, односторонний INDIRECT,
поздний DIRECT после NCD TIMEOUT, резерв, реальные данные и обработку кандидатов,
обрыв после начального срока, повторные циклы с реальными паузами 1/2/4с, смену адресов
и локальных сокетов, потерю маршрута посредника, устаревший ACK, начальный TIMEOUT
с последующим UP и закрытие последнего handle из TIMEOUT callback.