# route_ping — удалённый пинг через BGP (NAT-детекция, проверка живости) ## 1. Назначение Механизм запроса удалённого пинга через BGP-канал. Узел A отправляет узлу B TOPO_PING_REQ с IP:port цели, узел B выполняет серию пингов (`etcp_send_ping_to_socket`) и возвращает TOPO_PING_RESP с результатами (count_ok, avg_rtt). Используется: - `route_connectivity` — для зондирования связности (прямые пинги, без BGP) - `topo_group` — для NAT-детекции через промежуточный узел (third-party ping) - Общий механизм проверки живости адресов ## 2. Как пользоваться ```c // Отправить запрос пинга адреса target_ip:target_port через промежуточный узел to_conn int ret = route_ping_send_req_addr(group, to_conn, target_ip, target_port, count=2, interval_ms=100, timeout_ms=500, wait_timeout_ms=2000, callback, arg, pubkey); ``` Промежуточный узел (to_conn) получает запрос → выполняет серию `etcp_send_ping_to_socket()` → собирает статистику → отправляет ответ. Ключевой нюанс: `wait_timeout_ms` задаёт таймаут ожидания ответа на локальной стороне. Если ответ не приходит вовремя, `route_ping_pending_timeout` вызывает callback с `success=0`. ## 3. API ### Протокольные структуры (packed, wire-format) | Структура | Поля | |-----------|------| | `TOPO_PING_REQ` | `cmd=ETCP_ID_TOPO_ENTRY`, `subcmd=0x07`, `request_id`, `count`, `interval_ms`, `timeout_ms`, `target_ipv4`, `target_port`, `pubkey` (опционально) | | `TOPO_PING_RESP` | `cmd`, `subcmd=0x08`, `request_id`, `count_sent`, `count_ok`, `avg_rtt` (0.1ms) | ### Внутренние структуры | Структура | Назначение | |-----------|------------| | `route_ping_series_ctx` | Контекст серии пингов (на отвечающей стороне): `reply_conn`, `request_id`, `target_addr`, `local_sock`, счётчики, статистика | | `route_ping_pending` | Ожидающий запрос (на запрашивающей стороне): `request_id`, `callback`, `timeout_timer`, `via_conn` | ### Функции | Функция | Назначение | |---------|------------| | `route_ping_send_req_addr(group, to_conn, target_ip, target_port, count, interval, timeout, wait_timeout, cb, arg, pubkey)` | Отправить TOPO_PING_REQ через BGP, зарегистрировать callback | | `route_ping_handle_req(group, from_conn, data, len)` | Обработать входящий PING_REQ: найти локальный IPv4-сокет, запустить серию `etcp_send_ping_to_socket()`, по завершении отправить PING_RESP | | `route_ping_handle_resp(group, from_conn, data, len)` | Обработать PING_RESP: найти pending по `request_id`, отменить таймер, вызвать callback | | `route_ping_destroy_pending(group)` | Очистить весь список pending (при уничтожении BGP) | | `route_ping_cancel_for_conn(group, conn)` | Отменить pending запросы, связанные с конкретным `ETCP_CONN` (при разрыве) | ### Callback ```c typedef void (*route_ping_callback_t)(int success, uint16_t avg_rtt, uint8_t count_sent, uint8_t count_ok, void* arg); ``` Вызывается при получении ответа или по таймауту (`success=0`). ### Зависимости - `src/topo_group.h` — BGP-канал (список `ping_pending`, `next_ping_req_id`) - `src/etcp_api.h` — `etcp_send()` для отправки через BGP - `src/etcp_connections.h` — `etcp_send_ping_to_socket()` для собственно пинга - `src/topo_node.h` — `topo_node_find_by_id()`