|
|
|
@ -13,178 +13,427 @@ struct ETCP_CONN; |
|
|
|
struct NODEINFO_Q; |
|
|
|
struct NODEINFO_Q; |
|
|
|
struct ROUTE_BGP; |
|
|
|
struct ROUTE_BGP; |
|
|
|
|
|
|
|
|
|
|
|
#define CONN_MGR_MAX_CANDIDATES 3 |
|
|
|
/**
|
|
|
|
#define CONN_MGR_CANDIDATE_CACHE_MS 20000 |
|
|
|
* @file conn_mgr.h |
|
|
|
#define CONN_MGR_CANDIDATE_STALE_TB 300000 |
|
|
|
* @brief Менеджер установки соединений. Трёхфазная машина подключения к нодам |
|
|
|
#define CONN_MGR_CANDIDATE_PING_TB 20000 |
|
|
|
* с выбором оптимального пути: прямой → обратный → через посредников. |
|
|
|
#define CONN_MGR_BG_PING_INTERVAL_TB 1000 |
|
|
|
* |
|
|
|
#define CONN_MGR_BG_PING_CYCLE_MIN_TB 100000 |
|
|
|
* Основные возможности: |
|
|
|
#define CONN_MGR_IDLE_CHECK_INTERVAL_TB 10000 |
|
|
|
* - Автоматический выбор лучшего способа подключения к целевой ноде |
|
|
|
#define CONN_MGR_LOCAL_SCAN_ATTEMPTS 3 |
|
|
|
* - Фаза 1 (DIRECT): попытка прямого INIT-рукопожатия на все известные IPv4-адреса цели. |
|
|
|
#define CONN_MGR_LOCAL_SCAN_TIMEOUT_MS 100 |
|
|
|
* Итерация по парам (наш сокет, целевой адрес) с проверкой NAT-совместимости. |
|
|
|
#define CONN_MGR_CONNECT_DIRECT_TIMEOUT_MS 5000 |
|
|
|
* Таймаут: CONN_MGR_CONNECT_DIRECT_TIMEOUT_MS |
|
|
|
#define CONN_MGR_CONNECT_REVERSE_TIMEOUT_MS 15000 |
|
|
|
* - Фаза 2 (REVERSE): если у нас есть прямой IP, а у цели нет — отправляем DIRECT_REQ |
|
|
|
#define CONN_MGR_INTERM_EXCHANGE_TIMEOUT_MS 15000 |
|
|
|
* с нашими адресами через BGP-маршрут. Цель сама инициирует INIT в нашу сторону. |
|
|
|
|
|
|
|
* Таймаут: CONN_MGR_CONNECT_REVERSE_TIMEOUT_MS |
|
|
|
#define CONN_MGR_OK 0 |
|
|
|
* - Фаза 3 (INDIRECT): если DIRECT и REVERSE не сработали — обмениваемся через BGP |
|
|
|
#define CONN_MGR_ERR_NOT_FOUND -1 |
|
|
|
* списками лучших промежуточных узлов-кандидатов с RTT, выбираем общих с минимальным |
|
|
|
#define CONN_MGR_ERR_NO_ADDRESSES -2 |
|
|
|
* суммарным RTT. Трафик идёт через etcp_router (транзитная ретрансляция). |
|
|
|
#define CONN_MGR_ERR_TIMEOUT -3 |
|
|
|
* Таймаут: CONN_MGR_INTERM_EXCHANGE_TIMEOUT_MS |
|
|
|
#define CONN_MGR_ERR_UNREACHABLE -4 |
|
|
|
* - Фоновое сканирование локальной сети (broadcast/multicast UDP-ping) |
|
|
|
#define CONN_MGR_ERR_REFUSED -5 |
|
|
|
* - Фоновое поддержание списка лучших кандидатов-посредников (периодический ping, |
|
|
|
#define CONN_MGR_ERR_ALREADY_CONNECTED -6 |
|
|
|
* удаление stale-кандидатов) |
|
|
|
#define CONN_MGR_ERR_INTERNAL -7 |
|
|
|
* - Фоновый обход всех известных BGP-нод для поддержания RTT-замеров |
|
|
|
|
|
|
|
* - Управление idle-таймаутом с автоматическим разрывом неактивных соединений |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @note Правила использования: |
|
|
|
|
|
|
|
* 1. conn_mgr_init() вызывается один раз при старте экземпляра utun |
|
|
|
|
|
|
|
* 2. conn_mgr_connect_node() — асинхронный вызов, результат приходит в callback |
|
|
|
|
|
|
|
* 3. Повторный вызов conn_mgr_connect_node для уже подключённой ноды вернёт |
|
|
|
|
|
|
|
* CONN_MGR_ERR_ALREADY_CONNECTED; для ноды в состоянии CONNECTING добавит |
|
|
|
|
|
|
|
* дополнительный callback в список |
|
|
|
|
|
|
|
* 4. conn_mgr_disconnect_node() отправляет DISCONNECT-пакет целевой ноде и |
|
|
|
|
|
|
|
* сбрасывает conn_mgr_type в NODEINFO_Q |
|
|
|
|
|
|
|
* 5. Для alien-нод (подключившихся к нам самостоятельно) используется |
|
|
|
|
|
|
|
* conn_mgr_add_alien_node() вместо conn_mgr_connect_node() |
|
|
|
|
|
|
|
* 6. conn_mgr_update_best_candidates() вызывается извне (обычно из route_connectivity) |
|
|
|
|
|
|
|
* для обновления RTT кандидатов |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @note Внутренние таймеры (всё в timebase-единицах, 1 tb = 0.1 мс): |
|
|
|
|
|
|
|
* - bg_ping_timer: фоновый ping нод (CONN_MGR_BG_PING_INTERVAL_TB) |
|
|
|
|
|
|
|
* - candidate_ping_timer: обновление RTT кандидатов (CONN_MGR_CANDIDATE_PING_TB) |
|
|
|
|
|
|
|
* - idle_timer: проверка неактивности подключённых нод (CONN_MGR_IDLE_CHECK_INTERVAL_TB) |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ==================== Константы и лимиты ==================== */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define CONN_MGR_MAX_CANDIDATES 3 ///< Макс. число лучших кандидатов-посредников
|
|
|
|
|
|
|
|
#define CONN_MGR_CANDIDATE_CACHE_MS 20000 ///< Время жизни кандидата в кеше (мс) — не используется напрямую в .h
|
|
|
|
|
|
|
|
#define CONN_MGR_CANDIDATE_STALE_TB 300000 ///< Порог устаревания кандидата (tb), после которого удаляется из списка
|
|
|
|
|
|
|
|
#define CONN_MGR_CANDIDATE_PING_TB 20000 ///< Интервал фонового ping кандидатов (tb, ~2 сек)
|
|
|
|
|
|
|
|
#define CONN_MGR_BG_PING_INTERVAL_TB 1000 ///< Интервал фонового ping BGP-нод (tb, ~100 мс)
|
|
|
|
|
|
|
|
#define CONN_MGR_BG_PING_CYCLE_MIN_TB 100000 ///< Минимальная длительность полного цикла обхода нод (tb, ~10 сек)
|
|
|
|
|
|
|
|
#define CONN_MGR_IDLE_CHECK_INTERVAL_TB 10000 ///< Интервал проверки idle-таймаута (tb, ~1 сек)
|
|
|
|
|
|
|
|
#define CONN_MGR_LOCAL_SCAN_ATTEMPTS 3 ///< Число попыток локального сканирования
|
|
|
|
|
|
|
|
#define CONN_MGR_LOCAL_SCAN_TIMEOUT_MS 100 ///< Таймаут локального сканирования (мс)
|
|
|
|
|
|
|
|
#define CONN_MGR_CONNECT_DIRECT_TIMEOUT_MS 5000 ///< Таймаут фазы DIRECT (мс)
|
|
|
|
|
|
|
|
#define CONN_MGR_CONNECT_REVERSE_TIMEOUT_MS 15000 ///< Таймаут фазы REVERSE (мс)
|
|
|
|
|
|
|
|
#define CONN_MGR_INTERM_EXCHANGE_TIMEOUT_MS 15000 ///< Таймаут фазы INDIRECT (мс)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ==================== Коды возврата ==================== */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define CONN_MGR_OK 0 ///< Успех
|
|
|
|
|
|
|
|
#define CONN_MGR_ERR_NOT_FOUND -1 ///< Нода не найдена в BGP
|
|
|
|
|
|
|
|
#define CONN_MGR_ERR_NO_ADDRESSES -2 ///< Нет известных адресов для подключения
|
|
|
|
|
|
|
|
#define CONN_MGR_ERR_TIMEOUT -3 ///< Таймаут соединения
|
|
|
|
|
|
|
|
#define CONN_MGR_ERR_UNREACHABLE -4 ///< Нода недостижима (все фазы провалились)
|
|
|
|
|
|
|
|
#define CONN_MGR_ERR_REFUSED -5 ///< Соединение отклонено (зарезервировано)
|
|
|
|
|
|
|
|
#define CONN_MGR_ERR_ALREADY_CONNECTED -6 ///< Уже подключены
|
|
|
|
|
|
|
|
#define CONN_MGR_ERR_INTERNAL -7 ///< Внутренняя ошибка
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ==================== Состояния ==================== */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @enum CONN_MGR_STATE |
|
|
|
|
|
|
|
* @brief Состояние подключения к ноде. |
|
|
|
|
|
|
|
*/ |
|
|
|
enum CONN_MGR_STATE { |
|
|
|
enum CONN_MGR_STATE { |
|
|
|
CONN_MGR_STATE_DISCONNECTED = 0, |
|
|
|
CONN_MGR_STATE_DISCONNECTED = 0, ///< Не подключены
|
|
|
|
CONN_MGR_STATE_CONNECTING = 1, |
|
|
|
CONN_MGR_STATE_CONNECTING = 1, ///< В процессе установки соединения
|
|
|
|
CONN_MGR_STATE_CONNECTED = 2, |
|
|
|
CONN_MGR_STATE_CONNECTED = 2, ///< Подключены
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @enum CM_TRY_STATE |
|
|
|
|
|
|
|
* @brief Состояние отдельной попытки (локальное сканирование / основное подключение). |
|
|
|
|
|
|
|
*/ |
|
|
|
enum CM_TRY_STATE { |
|
|
|
enum CM_TRY_STATE { |
|
|
|
CM_TRY_NONE = 0, |
|
|
|
CM_TRY_NONE = 0, ///< Попытка не начиналась
|
|
|
|
CM_TRY_PENDING = 1, |
|
|
|
CM_TRY_PENDING = 1, ///< Попытка в процессе
|
|
|
|
CM_TRY_OK = 2, |
|
|
|
CM_TRY_OK = 2, ///< Попытка успешна
|
|
|
|
CM_TRY_FAILED = 3, |
|
|
|
CM_TRY_FAILED = 3, ///< Попытка провалилась
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
#define CONN_MGR_SUBCMD_DIRECT_REQ 0x01 |
|
|
|
/* ==================== Протокол CONN_MGR (ETCP_RT_ID_CONN_MGR = 0x11) ==================== */ |
|
|
|
#define CONN_MGR_SUBCMD_DIRECT_RESP 0x02 |
|
|
|
|
|
|
|
#define CONN_MGR_SUBCMD_INTERM_EXCHANGE_REQ 0x03 |
|
|
|
/**
|
|
|
|
#define CONN_MGR_SUBCMD_INTERM_EXCHANGE_RESP 0x04 |
|
|
|
* @defgroup conn_mgr_subcmd Подкоманды протокола CONN_MGR |
|
|
|
#define CONN_MGR_SUBCMD_INTERM_SELECTED 0x05 |
|
|
|
* @{ |
|
|
|
#define CONN_MGR_SUBCMD_DISCONNECT 0x06 |
|
|
|
*/ |
|
|
|
|
|
|
|
#define CONN_MGR_SUBCMD_DIRECT_REQ 0x01 ///< "Я за NAT, подключись ко мне" — передача наших адресов цели
|
|
|
|
|
|
|
|
#define CONN_MGR_SUBCMD_DIRECT_RESP 0x02 ///< Ответ на DIRECT_REQ (зарезервирован, не реализован)
|
|
|
|
|
|
|
|
#define CONN_MGR_SUBCMD_INTERM_EXCHANGE_REQ 0x03 ///< Запрос обмена кандидатами-посредниками
|
|
|
|
|
|
|
|
#define CONN_MGR_SUBCMD_INTERM_EXCHANGE_RESP 0x04 ///< Ответ с нашими кандидатами + замеры RTT до кандидатов инициатора
|
|
|
|
|
|
|
|
#define CONN_MGR_SUBCMD_INTERM_SELECTED 0x05 ///< Выбранные посредники (финальный шаг INDIRECT-фазы)
|
|
|
|
|
|
|
|
#define CONN_MGR_SUBCMD_DISCONNECT 0x06 ///< Уведомление о разрыве соединения
|
|
|
|
|
|
|
|
/** @} */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @struct CONN_MGR_CANDIDATE |
|
|
|
|
|
|
|
* @brief Запись о кандидате-посреднике: идентификатор ноды + RTT до неё. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* Используется в списке best_candidates и во всех пакетах обмена кандидатами. |
|
|
|
|
|
|
|
*/ |
|
|
|
struct CONN_MGR_CANDIDATE { |
|
|
|
struct CONN_MGR_CANDIDATE { |
|
|
|
uint64_t node_id; |
|
|
|
uint64_t node_id; ///< Идентификатор ноды-кандидата
|
|
|
|
uint16_t rtt; |
|
|
|
uint16_t rtt; ///< RTT до кандидата (мс)
|
|
|
|
} __attribute__((packed)); |
|
|
|
} __attribute__((packed)); |
|
|
|
|
|
|
|
|
|
|
|
#pragma pack(push, 1) |
|
|
|
#pragma pack(push, 1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @struct CONN_MGR_DIRECT_REQ |
|
|
|
|
|
|
|
* @brief Пакет фазы REVERSE: "подключись ко мне". |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* Отправляется когда мы имеем прямой IP, но цель за NAT. |
|
|
|
|
|
|
|
* Содержит наши адреса, по которым цель должна инициировать INIT. |
|
|
|
|
|
|
|
*/ |
|
|
|
struct CONN_MGR_DIRECT_REQ { |
|
|
|
struct CONN_MGR_DIRECT_REQ { |
|
|
|
uint8_t cmd; |
|
|
|
uint8_t cmd; ///< ETCP_RT_ID_CONN_MGR
|
|
|
|
uint8_t subcmd; |
|
|
|
uint8_t subcmd; ///< CONN_MGR_SUBCMD_DIRECT_REQ
|
|
|
|
uint32_t request_id; |
|
|
|
uint32_t request_id; ///< Идентификатор запроса для сопоставления ответа
|
|
|
|
uint8_t addr_count; |
|
|
|
uint8_t addr_count; ///< Количество адресов, следующих за заголовком
|
|
|
|
|
|
|
|
/* далее: addr_count записей по 8 байт каждая (type:1, ip:4, port:2, sock_id:1) */ |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @struct CONN_MGR_DIRECT_RESP |
|
|
|
|
|
|
|
* @brief Ответ на DIRECT_REQ (зарезервирован, не отправляется). |
|
|
|
|
|
|
|
*/ |
|
|
|
struct CONN_MGR_DIRECT_RESP { |
|
|
|
struct CONN_MGR_DIRECT_RESP { |
|
|
|
uint8_t cmd; |
|
|
|
uint8_t cmd; ///< ETCP_RT_ID_CONN_MGR
|
|
|
|
uint8_t subcmd; |
|
|
|
uint8_t subcmd; ///< CONN_MGR_SUBCMD_DIRECT_RESP
|
|
|
|
uint32_t request_id; |
|
|
|
uint32_t request_id; ///< Идентификатор запроса
|
|
|
|
uint8_t accepted; |
|
|
|
uint8_t accepted; ///< 1 — принято, 0 — отклонено
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @struct CONN_MGR_INTERM_EXCHANGE_REQ |
|
|
|
|
|
|
|
* @brief Запрос обмена списками кандидатов-посредников (фаза INDIRECT, инициатор). |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* Инициатор отправляет свой топ-4 кандидатов. Цель должна ответить |
|
|
|
|
|
|
|
* CONN_MGR_INTERM_EXCHANGE_RESP со своими кандидатами и замерами RTT до наших. |
|
|
|
|
|
|
|
*/ |
|
|
|
struct CONN_MGR_INTERM_EXCHANGE_REQ { |
|
|
|
struct CONN_MGR_INTERM_EXCHANGE_REQ { |
|
|
|
uint8_t cmd; |
|
|
|
uint8_t cmd; ///< ETCP_RT_ID_CONN_MGR
|
|
|
|
uint8_t subcmd; |
|
|
|
uint8_t subcmd; ///< CONN_MGR_SUBCMD_INTERM_EXCHANGE_REQ
|
|
|
|
uint32_t request_id; |
|
|
|
uint32_t request_id; ///< Идентификатор запроса
|
|
|
|
uint8_t candidate_count; |
|
|
|
uint8_t candidate_count; ///< Количество кандидатов в массиве (≤4)
|
|
|
|
struct CONN_MGR_CANDIDATE candidates[4]; |
|
|
|
struct CONN_MGR_CANDIDATE candidates[4]; ///< Наши лучшие кандидаты с RTT
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @struct CONN_MGR_INTERM_EXCHANGE_RESP |
|
|
|
|
|
|
|
* @brief Ответ на INTERM_EXCHANGE_REQ (фаза INDIRECT, цель). |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* Содержит два списка: |
|
|
|
|
|
|
|
* - my_candidates: лучшие кандидаты цели с RTT до них (измеренным целью) |
|
|
|
|
|
|
|
* - your_candidates: кандидаты инициатора, но с RTT, измеренным со стороны цели |
|
|
|
|
|
|
|
*/ |
|
|
|
struct CONN_MGR_INTERM_EXCHANGE_RESP { |
|
|
|
struct CONN_MGR_INTERM_EXCHANGE_RESP { |
|
|
|
uint8_t cmd; |
|
|
|
uint8_t cmd; ///< ETCP_RT_ID_CONN_MGR
|
|
|
|
uint8_t subcmd; |
|
|
|
uint8_t subcmd; ///< CONN_MGR_SUBCMD_INTERM_EXCHANGE_RESP
|
|
|
|
uint32_t request_id; |
|
|
|
uint32_t request_id; ///< Идентификатор запроса
|
|
|
|
uint8_t my_count; |
|
|
|
uint8_t my_count; ///< Количество наших кандидатов (≤4)
|
|
|
|
uint8_t your_count; |
|
|
|
uint8_t your_count; ///< Количество кандидатов инициатора (≤4)
|
|
|
|
struct CONN_MGR_CANDIDATE my_candidates[4]; |
|
|
|
struct CONN_MGR_CANDIDATE my_candidates[4]; ///< Наши кандидаты + наш RTT до них
|
|
|
|
struct CONN_MGR_CANDIDATE your_candidates[4]; |
|
|
|
struct CONN_MGR_CANDIDATE your_candidates[4]; ///< Кандидаты инициатора + наш RTT до них
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @struct CONN_MGR_INTERM_SELECTED |
|
|
|
|
|
|
|
* @brief Финальный выбор посредников (фаза INDIRECT). |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* Инициатор вычисляет лучших общих посредников по сумме RTT |
|
|
|
|
|
|
|
* и отправляет выбранный список цели. |
|
|
|
|
|
|
|
*/ |
|
|
|
struct CONN_MGR_INTERM_SELECTED { |
|
|
|
struct CONN_MGR_INTERM_SELECTED { |
|
|
|
uint8_t cmd; |
|
|
|
uint8_t cmd; ///< ETCP_RT_ID_CONN_MGR
|
|
|
|
uint8_t subcmd; |
|
|
|
uint8_t subcmd; ///< CONN_MGR_SUBCMD_INTERM_SELECTED
|
|
|
|
uint32_t request_id; |
|
|
|
uint32_t request_id; ///< Идентификатор запроса (всегда 0 для извещения)
|
|
|
|
uint8_t count; |
|
|
|
uint8_t count; ///< Количество выбранных посредников (≤3)
|
|
|
|
struct CONN_MGR_CANDIDATE selected[3]; |
|
|
|
struct CONN_MGR_CANDIDATE selected[3]; ///< Выбранные посредники (node_id + RTT от нас до них)
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @struct CONN_MGR_DISCONNECT |
|
|
|
|
|
|
|
* @brief Уведомление о разрыве соединения. |
|
|
|
|
|
|
|
*/ |
|
|
|
struct CONN_MGR_DISCONNECT { |
|
|
|
struct CONN_MGR_DISCONNECT { |
|
|
|
uint8_t cmd; |
|
|
|
uint8_t cmd; ///< ETCP_RT_ID_CONN_MGR
|
|
|
|
uint8_t subcmd; |
|
|
|
uint8_t subcmd; ///< CONN_MGR_SUBCMD_DISCONNECT
|
|
|
|
uint64_t node_id; |
|
|
|
uint64_t node_id; ///< Идентификатор ноды, с которой разрываем соединение
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
#pragma pack(pop) |
|
|
|
#pragma pack(pop) |
|
|
|
|
|
|
|
|
|
|
|
#define CONN_MGR_DIRECT_REQ_HDR_SIZE sizeof(struct CONN_MGR_DIRECT_REQ) |
|
|
|
/* ==================== Размеры пакетов протокола ==================== */ |
|
|
|
#define CONN_MGR_DIRECT_RESP_HDR_SIZE sizeof(struct CONN_MGR_DIRECT_RESP) |
|
|
|
|
|
|
|
#define CONN_MGR_INTERM_EXCHANGE_REQ_SIZE sizeof(struct CONN_MGR_INTERM_EXCHANGE_REQ) |
|
|
|
|
|
|
|
#define CONN_MGR_INTERM_EXCHANGE_RESP_SIZE sizeof(struct CONN_MGR_INTERM_EXCHANGE_RESP) |
|
|
|
|
|
|
|
#define CONN_MGR_INTERM_SELECTED_SIZE sizeof(struct CONN_MGR_INTERM_SELECTED) |
|
|
|
|
|
|
|
#define CONN_MGR_DISCONNECT_SIZE sizeof(struct CONN_MGR_DISCONNECT) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define CONN_MGR_DIRECT_REQ_HDR_SIZE sizeof(struct CONN_MGR_DIRECT_REQ) ///< Размер заголовка DIRECT_REQ (без addr_count адресов)
|
|
|
|
|
|
|
|
#define CONN_MGR_DIRECT_RESP_HDR_SIZE sizeof(struct CONN_MGR_DIRECT_RESP) ///< Размер DIRECT_RESP
|
|
|
|
|
|
|
|
#define CONN_MGR_INTERM_EXCHANGE_REQ_SIZE sizeof(struct CONN_MGR_INTERM_EXCHANGE_REQ) ///< Размер INTERM_EXCHANGE_REQ
|
|
|
|
|
|
|
|
#define CONN_MGR_INTERM_EXCHANGE_RESP_SIZE sizeof(struct CONN_MGR_INTERM_EXCHANGE_RESP) ///< Размер INTERM_EXCHANGE_RESP (макс.)
|
|
|
|
|
|
|
|
#define CONN_MGR_INTERM_SELECTED_SIZE sizeof(struct CONN_MGR_INTERM_SELECTED) ///< Размер INTERM_SELECTED
|
|
|
|
|
|
|
|
#define CONN_MGR_DISCONNECT_SIZE sizeof(struct CONN_MGR_DISCONNECT) ///< Размер DISCONNECT
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ==================== Callback-типы и внутренние структуры ==================== */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @typedef conn_mgr_connect_callback_t |
|
|
|
|
|
|
|
* @brief Callback результата подключения. |
|
|
|
|
|
|
|
* @param result код возврата (CONN_MGR_OK или CONN_MGR_ERR_*) |
|
|
|
|
|
|
|
* @param node_id идентификатор ноды |
|
|
|
|
|
|
|
* @param arg пользовательский аргумент |
|
|
|
|
|
|
|
*/ |
|
|
|
typedef void (*conn_mgr_connect_callback_t)(int result, uint64_t node_id, void* arg); |
|
|
|
typedef void (*conn_mgr_connect_callback_t)(int result, uint64_t node_id, void* arg); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @struct cm_cb_node |
|
|
|
|
|
|
|
* @brief Узел связного списка callback'ов для одной ноды. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* Позволяет регистрировать несколько callback'ов на одно подключение. |
|
|
|
|
|
|
|
* Новые callback'и добавляются в начало списка. |
|
|
|
|
|
|
|
*/ |
|
|
|
struct cm_cb_node { |
|
|
|
struct cm_cb_node { |
|
|
|
conn_mgr_connect_callback_t cb; |
|
|
|
conn_mgr_connect_callback_t cb; ///< Функция-callback
|
|
|
|
void* arg; |
|
|
|
void* arg; ///< Пользовательский аргумент
|
|
|
|
struct cm_cb_node* next; |
|
|
|
struct cm_cb_node* next; ///< Следующий callback в списке
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @struct CONN_MGR_ENTRY |
|
|
|
|
|
|
|
* @brief Запись о подключении к одной ноде. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* Хранит состояние трёхфазной машины, список выбранных посредников, |
|
|
|
|
|
|
|
* idle-таймер и список ожидающих callback'ов. |
|
|
|
|
|
|
|
*/ |
|
|
|
struct CONN_MGR_ENTRY { |
|
|
|
struct CONN_MGR_ENTRY { |
|
|
|
uint64_t node_id; |
|
|
|
uint64_t node_id; ///< Идентификатор целевой ноды
|
|
|
|
uint8_t state; |
|
|
|
uint8_t state; ///< Текущее состояние (enum CONN_MGR_STATE)
|
|
|
|
uint8_t conn_type; |
|
|
|
uint8_t conn_type; ///< Тип соединения (CONN_TYPE_DIRECT/REVERSE/INDIRECT)
|
|
|
|
uint8_t alien; |
|
|
|
uint8_t alien; ///< 1 — alien-нода (сама подключилась к нам), 0 — мы инициаторы
|
|
|
|
uint32_t idle_timeout_ms; |
|
|
|
uint32_t idle_timeout_ms; ///< Таймаут неактивности (мс), 0 — без таймаута
|
|
|
|
uint64_t last_traffic_tb; |
|
|
|
uint64_t last_traffic_tb; ///< Время последнего трафика (tb) для idle-проверки
|
|
|
|
void* idle_timer; |
|
|
|
void* idle_timer; ///< Хендл таймера idle-проверки
|
|
|
|
|
|
|
|
|
|
|
|
struct cm_cb_node* cb_list; |
|
|
|
struct cm_cb_node* cb_list; ///< Связный список callback'ов результата
|
|
|
|
|
|
|
|
|
|
|
|
uint64_t intermediaries[CONN_MGR_MAX_INTERMEDIARIES]; |
|
|
|
uint64_t intermediaries[CONN_MGR_MAX_INTERMEDIARIES]; ///< Выбранные посредники (node_id)
|
|
|
|
uint8_t intermediariy_count; |
|
|
|
uint8_t intermediariy_count; ///< Количество выбранных посредников
|
|
|
|
uint8_t rr_idx; |
|
|
|
uint8_t rr_idx; ///< Round-robin индекс для выбора посредника при отправке
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t local_scan_state; |
|
|
|
uint8_t local_scan_state; ///< Состояние локального сканирования (enum CM_TRY_STATE)
|
|
|
|
uint8_t main_connect_state; |
|
|
|
uint8_t main_connect_state; ///< Состояние основного подключения (enum CM_TRY_STATE)
|
|
|
|
struct { |
|
|
|
struct { |
|
|
|
uint8_t phase; |
|
|
|
uint8_t phase; ///< Текущая фаза: 1=DIRECT, 2=REVERSE, 3=INDIRECT
|
|
|
|
void* timer; |
|
|
|
void* timer; ///< Хендл таймера текущей фазы
|
|
|
|
uint32_t request_id; |
|
|
|
uint32_t request_id; ///< request_id для INDIRECT-обмена
|
|
|
|
void* conn_ctx; |
|
|
|
void* conn_ctx; ///< Контекст ETCP-соединения (для REVERSE)
|
|
|
|
} main; |
|
|
|
} main; |
|
|
|
|
|
|
|
|
|
|
|
struct CONN_MGR* mgr; |
|
|
|
struct CONN_MGR* mgr; ///< Обратная ссылка на менеджер
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @struct CONN_MGR |
|
|
|
|
|
|
|
* @brief Корневая структура менеджера соединений. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* Создаётся один раз в conn_mgr_init(), хранится в UTUN_INSTANCE. |
|
|
|
|
|
|
|
* Содержит динамический массив entries, список лучших кандидатов, |
|
|
|
|
|
|
|
* таймеры фонового ping и список ожидающих обменов (reverse/exchange pending). |
|
|
|
|
|
|
|
*/ |
|
|
|
struct CONN_MGR { |
|
|
|
struct CONN_MGR { |
|
|
|
struct UTUN_INSTANCE* instance; |
|
|
|
struct UTUN_INSTANCE* instance; ///< Родительский экземпляр utun
|
|
|
|
struct CONN_MGR_ENTRY* entries; |
|
|
|
|
|
|
|
size_t entry_count; |
|
|
|
|
|
|
|
size_t entry_capacity; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void* bg_ping_timer; |
|
|
|
struct CONN_MGR_ENTRY* entries; ///< Динамический массив записей о подключениях
|
|
|
|
size_t bg_ping_cursor; |
|
|
|
size_t entry_count; ///< Текущее количество записей
|
|
|
|
uint64_t bg_ping_cycle_start_tb; |
|
|
|
size_t entry_capacity; ///< Выделенная ёмкость массива entries
|
|
|
|
|
|
|
|
|
|
|
|
void* candidate_ping_timer; |
|
|
|
void* bg_ping_timer; ///< Хендл таймера фонового ping BGP-нод
|
|
|
|
|
|
|
|
size_t bg_ping_cursor; ///< Курсор текущей ноды в цикле обхода
|
|
|
|
|
|
|
|
uint64_t bg_ping_cycle_start_tb; ///< Время старта текущего цикла обхода (tb)
|
|
|
|
|
|
|
|
|
|
|
|
struct CONN_MGR_CANDIDATE best_candidates[CONN_MGR_MAX_CANDIDATES]; |
|
|
|
void* candidate_ping_timer; ///< Хендл таймера обновления RTT кандидатов
|
|
|
|
uint8_t best_candidate_count; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t next_request_id; |
|
|
|
struct CONN_MGR_CANDIDATE best_candidates[CONN_MGR_MAX_CANDIDATES]; ///< Топ кандидатов-посредников, отсортированных по RTT
|
|
|
|
uint8_t initialized; |
|
|
|
uint8_t best_candidate_count; ///< Количество актуальных кандидатов (≤CONN_MGR_MAX_CANDIDATES)
|
|
|
|
|
|
|
|
|
|
|
|
struct cm_reverse_pending* reverse_pending; |
|
|
|
uint32_t next_request_id; ///< Счётчик request_id для INTERM_EXCHANGE
|
|
|
|
struct cm_exchange_pending* exchange_pending; |
|
|
|
uint8_t initialized; ///< Флаг инициализации
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct cm_reverse_pending* reverse_pending; ///< Связный список ожидающих REVERSE-подключений
|
|
|
|
|
|
|
|
struct cm_exchange_pending* exchange_pending; ///< Связный список ожидающих INDIRECT-обменов
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ==================== Жизненный цикл ==================== */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @brief Инициализирует менеджер соединений. |
|
|
|
|
|
|
|
* @param instance родительский экземпляр utun |
|
|
|
|
|
|
|
* @return указатель на CONN_MGR или NULL при ошибке |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* Регистрирует обработчик в etcp_router для ETCP_RT_ID_CONN_MGR, |
|
|
|
|
|
|
|
* запускает фоновые таймеры (bg_ping, candidate_ping). |
|
|
|
|
|
|
|
*/ |
|
|
|
struct CONN_MGR* conn_mgr_init(struct UTUN_INSTANCE* instance); |
|
|
|
struct CONN_MGR* conn_mgr_init(struct UTUN_INSTANCE* instance); |
|
|
|
void conn_mgr_destroy(struct CONN_MGR* mgr); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int conn_mgr_connect_node(struct CONN_MGR* mgr, uint64_t node_id, |
|
|
|
|
|
|
|
uint32_t idle_timeout_ms, |
|
|
|
|
|
|
|
conn_mgr_connect_callback_t cb, void* cb_arg); |
|
|
|
|
|
|
|
int conn_mgr_disconnect_node(struct CONN_MGR* mgr, uint64_t node_id); |
|
|
|
|
|
|
|
int conn_mgr_set_idle_timeout(struct CONN_MGR* mgr, uint64_t node_id, uint32_t timeout_ms); |
|
|
|
|
|
|
|
int conn_mgr_get_status(struct CONN_MGR* mgr, uint64_t node_id, |
|
|
|
|
|
|
|
uint8_t* out_state, uint8_t* out_conn_type); |
|
|
|
|
|
|
|
int conn_mgr_add_alien_node(struct CONN_MGR* mgr, const uint8_t* nodeinfo_data, size_t len); |
|
|
|
|
|
|
|
int conn_mgr_send(struct CONN_MGR* mgr, uint64_t node_id, struct ll_entry* entry); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @brief Уничтожает менеджер соединений. |
|
|
|
|
|
|
|
* @param mgr менеджер |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* Освобождает все записи, таймеры, pending-структуры. |
|
|
|
|
|
|
|
* Вызывает cm_clear_nodeinfo для каждой записи. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
void conn_mgr_destroy(struct CONN_MGR* mgr); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ==================== Подключение / отключение ==================== */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @brief Запускает асинхронное подключение к ноде. |
|
|
|
|
|
|
|
* @param mgr менеджер |
|
|
|
|
|
|
|
* @param node_id идентификатор целевой ноды |
|
|
|
|
|
|
|
* @param idle_timeout_ms таймаут неактивности (мс), 0 = без таймаута |
|
|
|
|
|
|
|
* @param cb callback результата (CONN_MGR_OK, CONN_MGR_ERR_TIMEOUT, CONN_MGR_ERR_UNREACHABLE и т.д.) |
|
|
|
|
|
|
|
* @param cb_arg пользовательский аргумент для callback |
|
|
|
|
|
|
|
* @return CONN_MGR_OK если процесс запущен, CONN_MGR_ERR_* при ошибке |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @note Если нода уже подключена — сразу вызывает callback с CONN_MGR_OK и возвращает CONN_MGR_OK. |
|
|
|
|
|
|
|
* @note Если нода в процессе подключения — добавляет callback в список ожидания. |
|
|
|
|
|
|
|
* @note Автоматически определяет наличие BGP-соединения (уже существующий ETCP-линк). |
|
|
|
|
|
|
|
* @note Для alien-нод используйте conn_mgr_add_alien_node(). |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
int conn_mgr_connect_node(struct CONN_MGR* mgr, uint64_t node_id, |
|
|
|
|
|
|
|
uint32_t idle_timeout_ms, |
|
|
|
|
|
|
|
conn_mgr_connect_callback_t cb, void* cb_arg); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @brief Разрывает подключение к ноде. |
|
|
|
|
|
|
|
* @param mgr менеджер |
|
|
|
|
|
|
|
* @param node_id идентификатор ноды |
|
|
|
|
|
|
|
* @return CONN_MGR_OK или CONN_MGR_ERR_NOT_FOUND |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* Отправляет DISCONNECT-пакет целевой ноде, сбрасывает conn_mgr_type в NODEINFO_Q, |
|
|
|
|
|
|
|
* уничтожает запись entry. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
int conn_mgr_disconnect_node(struct CONN_MGR* mgr, uint64_t node_id); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ==================== Управление idle-таймаутом ==================== */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @brief Устанавливает idle-таймаут для подключённой ноды. |
|
|
|
|
|
|
|
* @param mgr менеджер |
|
|
|
|
|
|
|
* @param node_id идентификатор ноды |
|
|
|
|
|
|
|
* @param timeout_ms таймаут неактивности (мс), 0 = отключить проверку |
|
|
|
|
|
|
|
* @return CONN_MGR_OK или CONN_MGR_ERR_NOT_FOUND / CONN_MGR_ERR_INTERNAL |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* Если таймаут > 0 и нода в состоянии CONNECTED — запускает периодический таймер. |
|
|
|
|
|
|
|
* При отсутствии трафика в течение timeout_ms соединение автоматически разрывается. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
int conn_mgr_set_idle_timeout(struct CONN_MGR* mgr, uint64_t node_id, uint32_t timeout_ms); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @brief Получает текущий статус подключения к ноде. |
|
|
|
|
|
|
|
* @param mgr менеджер |
|
|
|
|
|
|
|
* @param node_id идентификатор ноды |
|
|
|
|
|
|
|
* @param out_state [out] состояние (enum CONN_MGR_STATE) |
|
|
|
|
|
|
|
* @param out_conn_type [out] тип соединения (CONN_TYPE_DIRECT/REVERSE/INDIRECT) |
|
|
|
|
|
|
|
* @return CONN_MGR_OK |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
int conn_mgr_get_status(struct CONN_MGR* mgr, uint64_t node_id, |
|
|
|
|
|
|
|
uint8_t* out_state, uint8_t* out_conn_type); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ==================== Alien-ноды ==================== */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @brief Регистрирует alien-ноду (подключившуюся к нам самостоятельно). |
|
|
|
|
|
|
|
* @param mgr менеджер |
|
|
|
|
|
|
|
* @param nodeinfo_data сырые данные NODEINFO (BGP-пакет) |
|
|
|
|
|
|
|
* @param len длина данных |
|
|
|
|
|
|
|
* @return CONN_MGR_OK или CONN_MGR_ERR_INTERNAL |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* Alien-нода — это нода, которая сама инициировала INIT-подключение к нам. |
|
|
|
|
|
|
|
* Для неё не запускаются фазы подключения, сразу устанавливается CONN_MGR_STATE_CONNECTED. |
|
|
|
|
|
|
|
* Создаёт entry с флагом alien=1. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
int conn_mgr_add_alien_node(struct CONN_MGR* mgr, const uint8_t* nodeinfo_data, size_t len); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @brief Отправляет данные подключённой ноде через etcp_router. |
|
|
|
|
|
|
|
* @param mgr менеджер |
|
|
|
|
|
|
|
* @param node_id идентификатор целевой ноды |
|
|
|
|
|
|
|
* @param entry ll_entry с данными для отправки (освобождается после отправки) |
|
|
|
|
|
|
|
* @return CONN_MGR_OK или CONN_MGR_ERR_NOT_FOUND |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* Для INDIRECT-соединений пакет автоматически маршрутизируется через |
|
|
|
|
|
|
|
* выбранного посредника (round-robin по intermediaries[]). |
|
|
|
|
|
|
|
* Обновляет last_traffic_tb для idle-проверки. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
int conn_mgr_send(struct CONN_MGR* mgr, uint64_t node_id, struct ll_entry* entry); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ==================== Управление кандидатами ==================== */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @brief Обновляет RTT кандидата в списке лучших посредников. |
|
|
|
|
|
|
|
* @param mgr менеджер |
|
|
|
|
|
|
|
* @param node_id идентификатор ноды-кандидата |
|
|
|
|
|
|
|
* @param rtt RTT до кандидата (мс) |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* Если кандидат уже в списке — обновляет RTT. Если нет — вставляет с сортировкой |
|
|
|
|
|
|
|
* по возрастанию RTT. Если список заполнен и новый кандидат имеет худший RTT — |
|
|
|
|
|
|
|
* игнорируется. Список всегда отсортирован: best_candidates[0] — наименьший RTT. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @note Обычно вызывается из route_connectivity после успешного probe. |
|
|
|
|
|
|
|
*/ |
|
|
|
void conn_mgr_update_best_candidates(struct CONN_MGR* mgr, uint64_t node_id, uint16_t rtt); |
|
|
|
void conn_mgr_update_best_candidates(struct CONN_MGR* mgr, uint64_t node_id, uint16_t rtt); |
|
|
|
|
|
|
|
|
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|