356 lines
30 KiB
C
356 lines
30 KiB
C
// etcp_router.h — Сервисный слой маршрутизации поверх ETCP
|
||
// Маршрутизирует сервисные пакеты до целевой ноды, на промежуточных нодах ретранслирует
|
||
// Упрощённый TCP поверх ETCP: восстановление порядка, дедупликация, ретрансмиты, inflight-контроль.
|
||
// Подпись/шифрование вынесены в автономный модуль route_crypto (encode/decode).
|
||
// Логический канал задаётся (group_id, node_id, svc_id), физический транспорт берётся у топологии.
|
||
// Сервисы регистрируют приём через bind, отправляют через route_send и соблюдают backpressure.
|
||
// Все операции и callbacks — в потоке uasync. Закрытие группы удаляет её каналы и ожидающий транзит.
|
||
//
|
||
// Построение маршрутов описано в topo_group.h. Роутер берёт текущий живой next hop
|
||
// из таблицы группы; при ожидании свободной очереди проверяет выбор повторно.
|
||
// Во время сходимости BGP возможны временные петли. Источник записывает свой ID,
|
||
// каждый транзитный узел проверяет список пройденных узлов и дописывает свой ID.
|
||
// Повторное посещение запрещено для всех пакетов, включая ACK и handshake.
|
||
// Ожидание в очереди не добавляет ID повторно; ретрансмит источника начинает новый список.
|
||
//
|
||
// Формат SVC_ROUTE пакета:
|
||
// [cmd:1] [group_id:8] [dst_node_id:8] [src_node_id:8] [seq:4] [svc_id:1] [flags:1] [timestamp:2] [reset_id:8]
|
||
// [peer_reset_id:8] [challenge:8] [payload...] [signature?:64] [visited_ids:8*count] [count:1]
|
||
// count=1..ROUTER_MAX_VISITED; IDs идут от источника до отправителя текущего хопа.
|
||
// Изменяемый список находится вне end-to-end подписи/шифрования. Получатель
|
||
// проверяет его границы, уникальность, первый ID=src и последний ID=ETCP peer.
|
||
// Это защита от ошибок маршрутизации, а не доказательство пути от недоверенного пира.
|
||
// flags: bit7=START, bit6=RST, bit3=SIGNED, bit2=ENCRYPTED, bit1=CLOSE, bit0=RECEIVE_BUSY (ACK)
|
||
// reset_id/peer_reset_id — идентификаторы отправителя/получателя во всех пакетах.
|
||
// START=HELLO, RST=CHALLENGE, START|RST=CONFIRM; challenge используется только в handshake.
|
||
// ACK-пакет: тот же заголовок, seq=rx_seq, payload_len=0; RECEIVE_BUSY поддерживает ожидание без продвижения seq.
|
||
// Локальная доставка через etcp_route_send выполняется синхронно без сетевого канала/crypto/receive_ready.
|
||
#ifndef ETCP_ROUTER_H
|
||
#define ETCP_ROUTER_H
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
|
||
#include <stdint.h>
|
||
#include "etcp_api.h"
|
||
#include "route_tx_stats.h"
|
||
|
||
// ====================================================================
|
||
// 1. Протокол SVC_ROUTE (wire-формат и формат доставки в сервис)
|
||
// ====================================================================
|
||
|
||
#pragma pack(push, 1)
|
||
struct SVC_ROUTE_HDR {
|
||
uint8_t cmd; // ETCP_ID_SVC_ROUTE (0x03)
|
||
uint64_t group_id; // идентификатор группы
|
||
uint64_t dst_node_id;
|
||
uint64_t src_node_id;
|
||
uint32_t seq; // data: tx_seq; ACK: rx_seq (ожидаемый seq)
|
||
uint8_t svc_id; // идентификатор сервиса
|
||
uint8_t flags; // ROUTER_FLAG_*; RECEIVE_BUSY допустим только в ACK без payload
|
||
uint16_t timestamp; // часы отправителя (0.1ms), для RTT; ACK: эхо последнего data-пакета
|
||
uint64_t reset_id; // случайный идентификатор локального экземпляра router_conn
|
||
uint64_t peer_reset_id; // идентификатор экземпляра получателя (0 только в HELLO)
|
||
uint64_t challenge; // случайный запрос/эхо для подтверждения актуальности пира
|
||
};
|
||
#pragma pack(pop)
|
||
#define SVC_ROUTE_HDR_SIZE sizeof(struct SVC_ROUTE_HDR) // 57
|
||
#define SVC_ROUTE_MAX_BINDINGS 256
|
||
#define ROUTER_MAX_VISITED 64 // предел размера списка, не замена проверки повторных ID
|
||
#define ROUTER_PATH_MAX_SIZE (8 * ROUTER_MAX_VISITED + 1)
|
||
|
||
// Единый формат доставки сервисной кодограммы (router → сервис):
|
||
// [svc_id:1][src_node_id:8][dst_node_id:8][rx_flags:1][group_id:8][payload...]
|
||
// src/dst — реальные end-to-end узлы из SVC_ROUTE заголовка (не промежуточные).
|
||
// rx_flags — биты ROUTER_FLAG_ENCRYPTED/SIGNED, бывшие на wire (статус для сервиса).
|
||
// group_id — группа SVC_ROUTE-пакета (для per-group сервисов вроде conn_mgr).
|
||
#define ROUTER_SVC_SRC_OFF 1
|
||
#define ROUTER_SVC_DST_OFF 9
|
||
#define ROUTER_SVC_FLAGS_OFF 17
|
||
#define ROUTER_SVC_GROUP_OFF 18
|
||
#define ROUTER_SVC_PAYLOAD_OFF 26
|
||
#define ROUTER_SVC_HDR_SIZE 26 // svc_id(1) + src_node_id(8) + dst_node_id(8) + rx_flags(1) + group_id(8)
|
||
|
||
// Биты в flags
|
||
#define ROUTER_FLAG_START 0x80
|
||
#define ROUTER_FLAG_RST 0x40
|
||
#define ROUTER_FLAG_ENCRYPTED 0x04 // payload зашифрован AES-128-CCM (nonce+tag+crc)
|
||
#define ROUTER_FLAG_SIGNED 0x08 // пакет содержит Ed25519 подпись (64 байта после payload)
|
||
#define ROUTER_FLAG_CLOSE 0x02 // нормальное закрытие conn
|
||
#define ROUTER_FLAG_RECEIVE_BUSY 0x01 // ACK: сервис приостановил приём, seq не подтверждает отложенные пакеты
|
||
|
||
// ====================================================================
|
||
// 2. Внутренние структуры и константы (etcp_router.c, control_server.c)
|
||
// ====================================================================
|
||
|
||
#define TRANSIT_QUEUE_HASH 256
|
||
|
||
// Очередь транзитных пакетов для пары (group_id, src_node_id, dst_node_id)
|
||
// Создаётся когда не получается отправить пакет в ETCP напрямую,
|
||
// удаляется когда очередь становится пустой.
|
||
// ll.data[0..23] = group_id:8 + src:8 + dst:8 — совпадает с полями ниже по памяти
|
||
struct TRANSIT_QUEUE {
|
||
struct ll_entry ll; // data[0..23] = group_id:8 + src_node_id:8 + dst_node_id:8 (24-byte hash index)
|
||
uint64_t group_id; // = data[0..7]
|
||
uint64_t src_node_id; // = data[8..15]
|
||
uint64_t dst_node_id; // = data[16..23]
|
||
struct ll_queue* q; // FIFO ещё не переданных транспорту пакетов
|
||
struct queue_waiter_handle waiter; // ожидание свободной conn->send_input_q
|
||
struct ETCP_CONN* conn; // владелец очереди и waiter; текущий маршрут проверяется при выгрузке
|
||
void* route_timer; // повторный выбор пути, даже если прежняя очередь остаётся занятой
|
||
};
|
||
|
||
// Состояние одного логического подключения (group_id + remote_node_id + svc_id)
|
||
struct ETCP_ROUTER_CONN {
|
||
struct ll_entry ll; // data[0..15]=group_id:8+remote_node_id:8, data[16]=svc_id — хеш-индекс
|
||
uint64_t group_id; // = data[0..7]
|
||
uint64_t remote_node_id; // = data[8..15]
|
||
uint8_t svc_id; // = data[16]
|
||
uint16_t last_dgram_ts; // последний timestamp датаграммы (rx или tx, timebase 0.1ms)
|
||
uint16_t rtt; // измеренный RTT (0.1ms)
|
||
uint32_t rtt_jitter; // EWMA |ΔRTT|, беззнаковый fixed-point *65536; монитор показывает удвоенный EWMA
|
||
uint16_t max_inflight; // настраиваемый рабочий максимум (default=ROUTER_MAX_INFLIGHT)
|
||
uint16_t inflight_limit; // текущий эффективный лимит (=max_inflight или MINRTT_PROBE_MAX_INFLIGHT)
|
||
uint16_t minrtt; // скользящее среднее minRTT (0.1ms), default=100 (10ms)
|
||
uint16_t minrtt_window[10]; // окно 10 последних замеров minRTT
|
||
uint64_t minrtt_window_tb[10];// таймстемпы замеров (timebase 0.1ms)
|
||
uint8_t minrtt_window_idx; // cyclic index 0..9
|
||
uint8_t minrtt_window_count; // активных записей в окне (0..10)
|
||
uint8_t minrtt_probe; // режим измерения (inflight capped at 4)
|
||
uint64_t last_inflight_loaded_tb; // когда inflight >= threshold
|
||
uint64_t last_inflight_unloaded_tb; // когда inflight < threshold
|
||
uint8_t inflight_was_loaded; // 1=канал загружен
|
||
uint16_t last_recv_pkt_ts; // timestamp пира из последнего data-пакета
|
||
uint64_t last_recv_pkt_local_tb; // наше время приёма последнего data-пакета (0.1ms timebase)
|
||
uint8_t last_recv_updated; // флаг: есть данные для эха в ACK
|
||
|
||
uint32_t tx_seq; // следующий seq для отправки
|
||
uint32_t tx_sent; // граница фактически отправленных пакетов (ACK <= tx_sent)
|
||
uint32_t rx_seq; // ожидаемый seq для сборки (next expected)
|
||
uint32_t tx_acked; // следующий seq после подтверждённых пакетов, модульный uint32, не накопленный счётчик
|
||
uint32_t last_sent_ack_seq; // последний отправленный ACK (= rx_seq на момент отправки)
|
||
uint64_t last_ack_sent_tb; // время отправки последнего ACK (timebase 0.1ms)
|
||
|
||
struct UTUN_INSTANCE* inst;
|
||
struct ETCP_CONN* recv_conn; // заимствованный транспорт последнего DATA; NULL после reset/уничтожения транспорта
|
||
struct ll_queue* recv_q; // reorder очередь: hash по seq (4 байта, offset 0)
|
||
void* ack_timer; // периодический таймер (10ms при consumer_ack)
|
||
void* idle_ack_timer; // idle таймер (дослать последний ack)
|
||
|
||
struct ll_queue* send_q; // очередь ожидающих отправки (inflight полон)
|
||
struct queue_waiter_handle send_waiter; // waiter на send_input_q (по 1 пакету, round-robin)
|
||
struct ll_queue* send_waiter_q; // очередь регистрации, не результат повторного поиска маршрута
|
||
uint32_t retrans_seq; // следующий seq текущего прохода ретрансмитов
|
||
uint32_t retrans_end; // конец прохода (исключительно)
|
||
void* watchdog_timer; // DEBUG-watchdog: медленная проверка инварианта drain
|
||
uint8_t send_blocked; // 1 = inflight полон, ждём ack
|
||
uint8_t no_route; // 1 = нет BGP-маршрута, передача приостановлена
|
||
void* no_route_timer; // таймер 20ms проверки появления маршрута
|
||
uint8_t no_ack_count; // счётчик последовательных ретрансмиссий без ACK
|
||
uint8_t closed; // 1 = в процессе закрытия, таймеры игнорируют
|
||
uint64_t reset_id; // собственный идентификатор; не меняется при рестарте пира
|
||
uint64_t peer_reset_id; // подтверждённый идентификатор пира (0 = handshake не завершён)
|
||
uint64_t pending_peer_id; // кандидат, ещё не имеющий права менять состояние сессии
|
||
uint64_t pending_challenge; // случайный запрос подтверждения кандидату
|
||
uint64_t challenge_sent_tb; // время отправки запроса, 0.1 ms
|
||
void* handshake_timer; // таймер повторов согласования
|
||
uint8_t start_sent; // получен первый ACK данных
|
||
|
||
// Ретрансмиты: inflight очередь
|
||
struct ll_queue* inflight_q; // хеш по seq (4 байта), непрерывный блок без SACK
|
||
void* retrans_timer; // таймер проверки застоя ACK
|
||
uint64_t last_ack_changed_tb; // отсчёт RTO: продвижение ACK, принятый RECEIVE_BUSY или начало повторного прохода (0.1ms)
|
||
|
||
// Очередь приёма входящего трафика (между сетью и recv_q)
|
||
struct ll_queue* incoming_q; // FIFO очередь входящих пакетов
|
||
uint8_t receive_blocked; // сервис временно не принимает следующую кодограмму
|
||
uint8_t peer_receive_blocked; // последний ACK пира объявил паузу приёма
|
||
void* receive_pump; // отложенное продолжение приёма
|
||
|
||
uint32_t c_pkts_sent; // успешные отправки данных
|
||
uint32_t c_pkts_send_err; // ошибки отправки
|
||
uint32_t c_pkts_rcvd; // получено и доставлено данных
|
||
uint32_t c_ack_sent; // отправлено ACK
|
||
uint32_t c_ack_recv; // получено ACK (последовательных)
|
||
uint32_t c_retrans_done; // число выполненых ретрансмитов
|
||
uint32_t c_dup_dropped; // дропнуто дубликатов seq
|
||
uint32_t c_oob_dropped; // дропнуто out-of-bounds seq
|
||
uint32_t c_stale_ack; // ACK вне диапазона или без продвижения seq, включая допустимый повтор RECEIVE_BUSY
|
||
uint32_t c_sign_fail; // signature verification failures
|
||
struct route_tx_meter delivery; // первые подтверждения исходного payload, без wire overhead
|
||
};
|
||
|
||
/* Заимствований нет. queued/inflight — исходный payload, а не размер криптограммы.
|
||
* ACK подтверждает доставку callback сервиса; декодирование/показ сервис отслеживает отдельно. */
|
||
struct ETCP_ROUTER_TX_STATS {
|
||
uint64_t local_epoch, peer_epoch, queued_bytes, inflight_bytes, acked_bytes, acked_packets;
|
||
uint32_t queued_packets, inflight_packets;
|
||
struct route_tx_window window;
|
||
uint32_t rtt_us, baseline_rtt_us;
|
||
int ready, no_route, receive_busy, probing;
|
||
};
|
||
|
||
/* Только uasync. 0 — снимок, 1 — канал отсутствует/закрыт (out обнулён), -1 — неверные аргументы/время.
|
||
* now_us — монотонные микросекунды, не раньше последнего учтённого ACK. При -1 out не меняется; канал не создаётся.
|
||
* ready означает подтверждённый peer_reset_id, отдельно от READY топологии или готовности физического транспорта. */
|
||
int etcp_router_tx_stats(struct UTUN_INSTANCE *inst, uint64_t group, uint64_t peer, uint8_t svc,
|
||
uint64_t now_us, struct ETCP_ROUTER_TX_STATS *out);
|
||
|
||
#define ROUTER_CONN_HASH_SIZE 256
|
||
#define ROUTER_RECVQ_HASH_SIZE 1024
|
||
#define ROUTER_MAX_INFLIGHT 256 // макс пакетов в полёте (для контроля inflight)
|
||
#define ROUTER_ACK_INTERVAL_TB 100 // интервал ACK: 10ms в timebase (0.1ms)
|
||
#define ROUTER_ACK_IDLE_TB 5000 // idle таймаут: 500ms
|
||
#define ROUTER_ACK_BUSY_TB 1000 // 100ms: живой приёмник ждёт диск, а не потерял транспорт
|
||
#define ROUTER_MAX_SEND_Q_PACKETS 64 // порог backpressure на send_q
|
||
#define ROUTER_SEND_WATCHDOG_TB 5000 // DEBUG-watchdog: 500ms проверка инварианта drain
|
||
|
||
// Ретрансмиты
|
||
#define ROUTER_RETRANS_TIMEOUT_TB 3000 // 300ms в timebase (0.1ms)
|
||
#define ROUTER_INFLIGHT_HASH_SIZE 1024
|
||
#define ROUTER_NO_ROUTE_RETRY_TB 200 // 20ms проверка появления маршрута
|
||
#define ROUTER_CALL_NO_ACK_MAX_RETRANS 67 // 20с: запас для 10с перебоя звонка и восстановления
|
||
#define ROUTER_NO_ACK_MAX_RETRANS 17 // 17 × 300ms ≈ 5s таймаут без ACK
|
||
|
||
// minRTT measurement
|
||
#define MINRTT_UNLOADED_MIN_TB 500 // 50ms минимальное время разгрузки канала
|
||
#define MINRTT_PROBE_TIMEOUT_TB 100000 // 10 сек без свежих замеров → probe
|
||
#define MINRTT_PROBE_MAX_INFLIGHT 4 // лимит inflight в режиме probe
|
||
#define MINRTT_WINDOW_SIZE 10
|
||
#define MINRTT_DEFAULT_TB 100 // default minRTT = 10ms (заменяется первым RTT)
|
||
|
||
// Inflight хранит подписанное/зашифрованное тело. Каждый ретрансмит добавляет новый список переходов.
|
||
struct ROUTER_INFLIGHT {
|
||
struct ll_entry ll; // индекс по seq (4 байта, offset 0)
|
||
uint32_t seq;
|
||
uint64_t last_sent_tb; // время последней отправки (0.1ms)
|
||
uint8_t send_count; // успешные отправки, включая первую; диагностический циклический счётчик
|
||
uint8_t* dgram; // неизменяемое тело [SVC_ROUTE_HDR][payload][sig?], без visited_ids/count
|
||
size_t dgram_len;
|
||
};
|
||
|
||
// Bindings для сервисов внутри etcp_router (аналогично ETCP_BINDINGS)
|
||
struct ETCP_ROUTER_BINDINGS {
|
||
etcp_recv_fn callbacks[SVC_ROUTE_MAX_BINDINGS];
|
||
int (*receive_ready[SVC_ROUTE_MAX_BINDINGS])(struct UTUN_INSTANCE*, uint64_t, uint64_t, const uint8_t*, size_t);
|
||
uint8_t required_crypto[SVC_ROUTE_MAX_BINDINGS]; // Обязательные ENCRYPTED/SIGNED для сервисных данных; 0 — без требования.
|
||
};
|
||
|
||
// ====================================================================
|
||
// 3. Публичное API (для сервисов)
|
||
// ====================================================================
|
||
|
||
// Первичная инициализация ядра: очистить bindings, создать router_conns, etcp_bind(ETCP_ID_SVC_ROUTE); 0/-1.
|
||
// Вызывать один раз до запуска сервисов; после destroy можно инициализировать заново.
|
||
int etcp_router_init(struct UTUN_INSTANCE* inst);
|
||
|
||
// Снять обработчик, закрыть каналы и очистить все транзитные очереди/таймеры на живых ETCP. Повторный destroy допустим.
|
||
// До вызова остановить производителей/ожидания сервисов; из callback останавливаемого сервиса ядро не уничтожать.
|
||
void etcp_router_destroy(struct UTUN_INSTANCE* inst);
|
||
|
||
// Зарегистрировать/заменить callback; 0/-1. Замена сохраняет receive_ready/crypto policy.
|
||
// callback=NULL снимает callback, receive_ready и policy, даже если сервиса не было; каналы не закрывает.
|
||
// Сервис получает владение entry: [26-byte ROUTER_SVC header][payload]. Пустой payload — уведомление close/reset.
|
||
// conn заимствован на время callback; при локальных событиях синтетический (instance, peer=self), отправлять через него нельзя.
|
||
// End-to-end src/dst/group читать из заголовка через memcpy; conn может обозначать промежуточного пира.
|
||
int etcp_router_bind(struct UTUN_INSTANCE* inst, uint8_t svc_id, etcp_recv_fn callback);
|
||
// Снять обработчик; само по себе не закрывает логические каналы сервиса.
|
||
int etcp_router_unbind(struct UTUN_INSTANCE* inst, uint8_t svc_id);
|
||
|
||
// Задать обязательные ROUTER_FLAG_ENCRYPTED/SIGNED для зарегистрированного сервиса, в обе стороны сетевого обмена.
|
||
// Входящие данные проверяются до состояния/очередей/receive_ready, на конечном узле; header-only control исключён.
|
||
// Доверенная синхронная доставка dst=self обходит crypto policy и даёт rx_flags=0.
|
||
// Работает в uasync; unbind очищает требование. Возвращает 0 при успехе, -1 при неверном instance/сервисе/маске.
|
||
int etcp_router_require_crypto(struct UTUN_INSTANCE* inst, uint8_t svc_id, uint8_t flags);
|
||
|
||
// Проверяется до доставки/ACK. 0 оставляет пакет в recv_q, сохраняя порядок; CLOSE не блокируется.
|
||
// ready получает заимствованный plaintext, работает в uasync без I/O и изменения состояния/закрытия роутера.
|
||
// NULL снимает ограничение; для уже приостановленных каналов вызвать resume_receive отдельно. Локальная доставка не проверяется.
|
||
void etcp_router_set_receive_ready(struct UTUN_INSTANCE* inst, uint8_t svc_id,
|
||
int (*ready)(struct UTUN_INSTANCE*, uint64_t, uint64_t, const uint8_t*, size_t));
|
||
// Продолжение отложено; канал не создаётся, waiter/arg сервиса не сохраняются.
|
||
void etcp_router_resume_receive(struct UTUN_INSTANCE* inst, uint64_t group, uint64_t peer, uint8_t svc_id);
|
||
|
||
// Отправить сервисный пакет (авто-conn, seq, inflight-контроль через send_q).
|
||
// Принимает владение entry во всех исходах, включая ошибку.
|
||
// entry->dgram = svc_id[1] || непустой payload; mode должен содержать только допустимые биты.
|
||
// Для удалённого узла 0=принято в send_q, не подтверждение доставки. Предел включает wire-header, crypto и полный visited-list.
|
||
// Для dst=self callback вызывается синхронно, 0=доставлено callback, -1=размер/нет обработчика/ошибка памяти.
|
||
// В self-ветке нет канала, inflight, receive_ready и crypto; rx_flags=0, payload до UINT16_MAX-ROUTER_SVC_HDR_SIZE байт.
|
||
// force разрешает превысить лимит числа пакетов сетевой send_q; для self не используется.
|
||
// mode — битовая маска ROUTE_CRYPTO_SIGN / ROUTE_CRYPTO_ENCRYPT (см. route_crypto.h), 0 = обычный пакет.
|
||
int etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst_node_id, struct ll_entry* entry, int force, int mode);
|
||
|
||
// Найти/создать логический канал. Указатель заимствован до close/destroy, NULL при ошибке.
|
||
struct ETCP_ROUTER_CONN* etcp_router_conn_get(struct UTUN_INSTANCE* inst,
|
||
uint64_t group_id, uint64_t remote_node_id, uint8_t svc_id);
|
||
|
||
// Есть ли сейчас физический маршрут до узла (прямой, indirect-посредник или глобальный).
|
||
// 1 = найден транспорт (для self всегда 1); это не гарантия UP/готовности логического канала.
|
||
int etcp_router_has_route(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst_node_id);
|
||
|
||
// Снимок текущего пути отправки сервиса, только uasync-поток; без создания канала/изменения очередей.
|
||
// type — CONN_TYPE_*; отсутствие живого пути: NONE и next_hop_node_id=0.
|
||
struct ETCP_ROUTER_PATH { uint8_t type; uint64_t next_hop_node_id; };
|
||
struct ETCP_ROUTER_PATH etcp_router_get_path(struct UTUN_INSTANCE* inst, uint64_t group_id,
|
||
uint64_t dst_node_id, uint8_t svc_id);
|
||
|
||
// Отправить данные с авто-seq и контролем inflight
|
||
// data: payload без svc_id, mode: ROUTE_CRYPTO_SIGN / ROUTE_CRYPTO_ENCRYPT (0 = обычный)
|
||
// Копирует непустой data; 0=принято в очередь, <0=ошибка. Доставка подтверждается отдельно протоколом.
|
||
// Это сетевой API rconn; для синхронной локальной доставки использовать etcp_route_send.
|
||
int etcp_router_conn_send(struct ETCP_ROUTER_CONN* rconn,
|
||
const uint8_t* data, size_t len, int mode);
|
||
|
||
// Снять канал с реестра, затем синхронно уведомить сервис и очистить ресурсы; память освобождается отложенно.
|
||
// Callback может закрывать другие каналы/группу или открыть замену с тем же ключом. После close rconn использовать нельзя.
|
||
void etcp_router_conn_close(struct ETCP_ROUTER_CONN* rconn);
|
||
|
||
// Установить max_inflight (минимум 4), пересчитать inflight_limit и state machine.
|
||
// В minRTT probe лимит равен 4; reset сессии возвращает default=256.
|
||
void etcp_router_set_max_inflight(struct ETCP_ROUTER_CONN* rconn, uint16_t new_max);
|
||
|
||
// Дождаться порога send_q. h должен быть обнулён и жить до callback/отмены.
|
||
// Callback может выполниться внутри вызова. Повторная регистрация отменяет прежнюю.
|
||
// Если канала нет, ожидание не регистрируется. Перед освобождением arg отменить waiter.
|
||
void etcp_router_on_send_ready(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t node_id, uint8_t svc_id,
|
||
struct queue_waiter_handle* h,
|
||
queue_threshold_callback_fn callback, void* arg);
|
||
// Отмена относится к исходной очереди, даже если логический канал уже перезапущен.
|
||
void etcp_router_cancel_send_ready(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t node_id, uint8_t svc_id,
|
||
struct queue_waiter_handle* h);
|
||
|
||
// Есть ли место в send_q существующего канала; 1/0. Канал не создаёт, его отсутствие даёт 0.
|
||
int etcp_router_send_q_has_room(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t node_id, uint8_t svc_id);
|
||
|
||
// ====================================================================
|
||
// 4. Служебные функции (для каркаса: etcp.c, topo_group.c)
|
||
// ====================================================================
|
||
|
||
// Отвязать отправку от сбрасываемого транспорта; сохранить inflight и ретрансмиты
|
||
// Используется при etcp_conn_reinit чтобы избежать гонки с очисткой ETCP-очередей
|
||
void etcp_router_pause_retrans_for_node(struct UTUN_INSTANCE* inst, uint64_t remote_node_id);
|
||
|
||
// Закрыть все каналы и ожидающий транзит группы. Сначала сервисы отменяют свои producers/waiters.
|
||
void etcp_router_close_group(struct UTUN_INSTANCE* inst, uint64_t group_id);
|
||
// Закрыть логические каналы одного пира в группе.
|
||
void etcp_router_conn_close_all_for_node(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t remote_node_id);
|
||
|
||
// Сбросить существующий peer+svc: новая локальная эпоха, пустые очереди/seq/метрики, затем уведомление сервиса и HELLO.
|
||
// Отсутствующий канал не создаётся. Данные, отправленные сервисом из уведомления, относятся к новой сессии.
|
||
void etcp_router_conn_restart(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t remote_node_id, uint8_t svc_id);
|
||
|
||
// Удалить все транзитные очереди соединения (вызывается при закрытии ETCP_CONN)
|
||
void etcp_router_transit_queues_destroy(struct ETCP_CONN* conn);
|
||
|
||
// Сбросить recv_conn у всех ROUTER_CONN, ссылающихся на уничтожаемый ETCP_CONN.
|
||
void etcp_router_conn_destroyed(struct ETCP_CONN* conn);
|
||
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
#endif // ETCP_ROUTER_H
|