You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
337 lines
18 KiB
337 lines
18 KiB
// etcp.h - ETCP Protocol Header (refactored based on etcp_protocol.txt) |
|
#ifndef ETCP_H |
|
#define ETCP_H |
|
|
|
#include "etcp_connections.h" |
|
#include "secure_channel.h" |
|
#include "../lib/ll_queue.h" |
|
#include <stdint.h> |
|
|
|
#ifdef __cplusplus |
|
extern "C" { |
|
#endif |
|
|
|
#include "pkt_normalizer.h" |
|
|
|
struct stcp_link; // forward declaration |
|
// In struct ETCP_CONN, add: |
|
//struct pn_pair* normalizer; |
|
|
|
// Forward declarations |
|
struct UTUN_INSTANCE; |
|
struct ETCP_CONN; |
|
struct etcp_cbk_entry; // defined in etcp_api.h |
|
struct UASYNC; |
|
|
|
uint16_t get_current_timestamp(void); |
|
|
|
// ETCP packet section types (from protocol spec) |
|
#define ETCP_SECTION_PAYLOAD 0x00 // Data payload |
|
#define ETCP_SECTION_ACK 0x01 // ACK section |
|
#define ETCP_SECTION_TIMESTAMP 0x06 // Channel timestamp (example, adjust if needed) |
|
#define ETCP_SECTION_MEAS_TS 0x07 // Measurement timestamp for bandwidth (burst packet) |
|
#define ETCP_SECTION_MEAS_RESP 0x08 // Measurement response (burst result) |
|
#define ETCP_SECTION_FILLER 0x09 // Filler/dummy data (discarded by receiver) |
|
#define ETCP_SECTION_METRICS 0x0A // Metrics CSV exchange (ed25519 signed) |
|
|
|
// Burst measurement constants |
|
#define BURST_PACKET_COUNT 12 // число пакетов в burst |
|
#define BURST_SKIP_COUNT 3 // сколько первых пакетов пропустить при замере gap |
|
#define MIN_BURST_INTERVAL_TB 5000 // минимальный интервал между burst (500ms в 0.1ms) |
|
#define BURST_RESP_TIMEOUT_TB 20000 // таймаут ожидания ответа на burst (2s в 0.1ms) |
|
|
|
// Inflight phases |
|
#define INFLIGHT_PHASE_SLOW_START 0 |
|
#define INFLIGHT_PHASE_CONG_AVOIDANCE 1 |
|
|
|
// Section sizes |
|
#define MEAS_TS_SECTION_SIZE 9 // type(1) + burst_id(2) + flags(1) + seq(1) + ts_us(2) + pkt_sz(2) |
|
#define MEAS_RESP_SECTION_SIZE 13 // type(1) + burst_id(2) + valid(1) + gap_avg(4) + gap_min(4) + pkt_count(1) |
|
#define FILLER_HDR_SIZE 3 // type(1) + len(2) |
|
|
|
// MEAS_TS flags |
|
#define MEAS_FLAG_IS_FILLER 0x01 // пакет содержит FILLER вместо PAYLOAD |
|
#define MEAS_FLAG_IS_LAST 0x02 // последний пакет в burst |
|
#define MEAS_FLAG_IS_FIRST 0x04 // первый пакет в burst |
|
|
|
// MEAS_RESP valid |
|
#define MEAS_RESP_VALID 1 |
|
// Метрики: гистограммы RTT и потерь с 10-мин снимками |
|
#define ETCP_METRICS_RTT_BUCKETS 12 // 0-1,1-2,2-3,3-5,5-8,8-13,13-21,21-34,34-55,55-90,90-150,150+ ms |
|
#define ETCP_METRICS_LOSS_BUCKETS 11 // 0%,1%,...,10%+ |
|
#define ETCP_METRICS_INTERVAL_TB 6000000 // 10 мин в 0.1ms |
|
#define ETCP_METRICS_MIN_PACKETS 200 // мин пакетов для обновления гистограмм |
|
|
|
struct etcp_metrics { |
|
uint32_t rtt_hist[ETCP_METRICS_RTT_BUCKETS]; // рабочая RTT-гистограмма |
|
uint32_t loss_hist[ETCP_METRICS_LOSS_BUCKETS]; // рабочая loss-гистограмма |
|
uint32_t work_samples; // RTT замеров в окне |
|
uint32_t work_sent; // пакетов отправлено в окне |
|
uint32_t work_rcvd; // пакетов принято в окне |
|
uint32_t work_bytes_sent; // байт отправлено в окне |
|
uint32_t work_bytes_rcvd; // байт принято в окне |
|
uint32_t work_lost; // потеряно в окне |
|
|
|
uint32_t rtt_hist_final[ETCP_METRICS_RTT_BUCKETS]; // финальная RTT-гистограмма |
|
uint32_t loss_hist_final[ETCP_METRICS_LOSS_BUCKETS]; // финальная loss-гистограмма |
|
uint32_t samples_final; |
|
uint32_t sent_final; |
|
uint32_t rcvd_final; |
|
uint32_t bytes_sent_final; |
|
uint32_t bytes_rcvd_final; |
|
uint32_t lost_final; |
|
|
|
uint64_t total_sent; |
|
uint64_t total_rcvd; |
|
uint64_t total_bytes_sent; |
|
uint64_t total_bytes_rcvd; |
|
uint64_t total_lost; |
|
|
|
void* timer; |
|
uint64_t last_snapshot_tb; |
|
}; |
|
|
|
#define INFLIGHT_STATE_WAIT_ACK 0 |
|
#define INFLIGHT_STATE_WAIT_SEND 1 |
|
#define INFLIGHT_INITIAL_HASH_SIZE 1024 |
|
|
|
#define MAX_INFLIGHT_SIZE 16384 // максимальное число элементов в inflight приёмной очереди (для предотвращения атак) |
|
#define ASM_BUF_MAX_SIZE (64 * 1024) // максимальный размер буфера сборки фрагментов |
|
|
|
// в этот список пакет добавляется когда перемещается из input_queue в input_send_q, при этом к пакету добавляется struct INFLIGHT_PACKET из inflight_pool. |
|
// пакет полностью удаляется когда приходит ACK (либо conn_reset/close) |
|
struct INFLIGHT_PACKET {// выделяется из etcp->inflight_pool |
|
struct ll_entry ll; |
|
uint32_t seq; // packet seq (ID по документации) |
|
struct ETCP_LINK* last_link; // Last sent link |
|
uint64_t last_timestamp; // Last send timestamp |
|
uint8_t send_count; // Number of sends |
|
uint8_t retrans_req_count; // Number of retrans requests |
|
uint8_t state; // WAIT_ACK or WAIT_SEND |
|
uint8_t send_hist[8]; // через какие каналы передавался пакет (NEW). send_count - head ptr |
|
uint64_t delivered_at_send; // link->delivered_bytes на момент отправки (для BBR prior_delivered) |
|
uint32_t inflight_at_send; // link->inflight_bytes на момент отправки (для BBR tx_in_flight) |
|
uint8_t is_app_limited; // данные ограничены приложением на момент отправки |
|
}; |
|
|
|
// Список пакетов для сборки. собирается в ll_queue (используем быстрый поиск с хешем) |
|
struct ETCP_FRAGMENT {// выделяется из пула etcp->rx_pool |
|
struct ll_entry ll; |
|
uint32_t seq; |
|
uint16_t timestamp; |
|
}; |
|
|
|
struct ACK_PACKET { |
|
struct ll_entry ll; |
|
uint32_t seq;// sequence number |
|
uint16_t pkt_timestamp;// timestamp пакета (часы уладенной стороны) |
|
uint32_t recv_timestamp;// время приема (локальное) |
|
}; |
|
|
|
#define ETCP_TX_STATE_DATA_WAIT 1 |
|
#define ETCP_TX_STATE_LINK_WAIT 2 |
|
|
|
// ETCP connection structure (refactored) |
|
struct ETCP_CONN { |
|
// State: 0=not ready, 1=ready (indexed in instance->connections), 2=deleted |
|
int state; // 0=pending, 1=ready, 2=deleted (phase 1 of close done) |
|
int ref_count; // External reference count. >0 blocks deferred resource free. |
|
// Take/free via etcp_conn_ref_take()/etcp_conn_ref_free(). |
|
|
|
int mtu; |
|
|
|
struct UTUN_INSTANCE* instance; |
|
|
|
// Queue entries in instance->connections or instance->pending_connections |
|
struct ll_entry* conn_queue_entry; // entry в очереди instance |
|
struct ll_queue* conn_queue; // указатель на очередь где лежим (pending или connections) |
|
|
|
// Links (channels) - linked list |
|
struct ETCP_LINK* links; |
|
struct ETCP_LINK* last_rr_link; // последний линк, выбранный round-robin |
|
struct stcp_link *transport_link; // non-NULL for TCP connections |
|
|
|
// Crypto and state |
|
struct secure_channel crypto_ctx; |
|
struct PKTNORM* normalizer; |
|
|
|
// Peer info |
|
uint64_t peer_node_id; // Peer node ID |
|
uint8_t peer_ed25519_pubkey[SC_PUBKEY_SIZE]; // Ed25519 pubkey пира (из INIT) |
|
|
|
// ============ Processing incoming data to be sent by ETCP |
|
struct ll_queue* input_queue; // Incoming packets to send (rx_pool -> ETCP_FRAGMENT) |
|
|
|
// Inflight очереди (2 шт) - пока пакет в статусе inflight - к нему прикрепляется struct INFLIGHT_PACKET |
|
struct memory_pool* inflight_pool; // память для inflight очередей |
|
struct memory_pool* io_pool; // память для rx очередей |
|
|
|
struct ll_queue* input_send_q; // очередь на отправку (inflight_pool -> INFLIGHT_PACKET) |
|
struct ll_queue* input_wait_ack; // очередь ожидающих подтверждение (inflight_pool -> struct INFLIGHT_PACKET) |
|
struct ll_queue* ack_q; // неотправленные подтверждения приема пакетов (instance.ack_pool -> struct ACK_PACKET) + index [+0 SEQ] |
|
|
|
struct ll_queue* recv_q; // очередь на сборку фрагментированных пакетов(rx_pool -> struct ETCP_FRAGMENT) + index [+0 SEQ] |
|
|
|
void (*link_ready_for_send_fn)(struct ETCP_CONN*);// функцию которую должен вызвать драйвер линка при готовности линка принимать данные |
|
|
|
struct ll_queue* output_queue; // Assembled outgoing packets (storage: ETCP_FRAGMENT / rx_pool) |
|
struct ll_queue* transit_queues; // hash по (src_node_id:8, dst_node_id:8) — транзитные очереди |
|
struct ll_queue* send_input_q; // единая входная очередь отправки (normalizer->input или tx_queue) |
|
|
|
|
|
// IDs and state |
|
uint32_t next_tx_id; // ID для добавления в очередь отправки (с этим id будет добавлен следующий пакет) |
|
uint32_t last_rx_id; // Last received ID |
|
uint32_t last_delivered_id; // Last delivered to output_queue |
|
|
|
uint32_t rx_ack_till;// из ack пакета - по какой пакет получено и собрано на удаленной стороне |
|
|
|
// Metrics (RTT, jitter, etc.) |
|
// uint16_t retrans_delay; // Not used |
|
uint16_t rtt_last;// round-trip time |
|
uint16_t tt_last;// transmission time (время пакета до меня) |
|
// uint16_t rxt_last;// recv relative time (бустро регаирует на изменение задержки rx и медленно на изменение задержки tx) |
|
uint16_t rtt_avg_10; |
|
uint16_t jitter; |
|
uint64_t last_rtt_cb_time; // время последнего вызова ping_update_rtt (0.1ms) |
|
uint32_t bytes_sent_total; |
|
// uint32_t bytes_received_total; // Not used |
|
uint32_t retransmissions_count; |
|
uint32_t reinit_count; |
|
uint64_t setup_start_tb; // время начала/рестарта подключения (0.1ms) |
|
uint32_t reset_count; |
|
// uint32_t bytes_sent_norx; // сколько отправили байт без единого ответного пакета (для детекции запроса реконнекта) |
|
|
|
// Window and inflight management |
|
uint32_t unacked_bytes; // Current inflight bytes |
|
uint32_t max_inflight; // Max inflight cap from config (bbr_max_cwnd) |
|
uint32_t optimal_inflight; // Sum over links |
|
|
|
// Timers |
|
void* retrans_timer; // Retrans check timer |
|
void* ack_resp_timer; // ACK send timer |
|
|
|
// Bandwidth measurement state |
|
// uint8_t burst_in_progress; // Burst transmission flag - Not used |
|
// uint16_t burst_start_id; // Start ID for burst - Not used |
|
|
|
// Statistics counters |
|
uint32_t ack_packets_count; // Count of ACK packets received |
|
// uint16_t last_rx_ack_id; // Last ACK ID received - Not used |
|
uint16_t rtt_history[10]; // RTT history for jitter calculation (RTT_HISTORY_SIZE=10) |
|
uint8_t rtt_history_idx; // Current index in RTT history |
|
// uint32_t total_packets_sent; // Total packets sent counter - Not used |
|
|
|
// Flags |
|
uint8_t routing_exchange_active; // 0-не активен, 1-надо инициировать (клиент), 2-обмен идёт, 3-завершён, 4-пропущен (нет BGP) |
|
uint8_t got_initial_pkt; // |
|
uint8_t initialized; // 0 - только созданный ETCP, 1 - хотя бы один линк проинициалзирован (обмен ключами произведен) |
|
uint32_t session_id; // случайный ID сессии (генерируется клиентом) для защиты от ложного reinit |
|
uint8_t tx_state; // 0 - n/a, 1 - data_wait (queues empty), 2 - link_wait (link busy) |
|
uint8_t links_up; // 0 - канал не готов для передачи, 1 - канал готов для передачи (хотя бы один линк не down) |
|
uint8_t reset_done; // 0 - рукопожатие не завершено (реинит разрешён), 1 - соединение стабильно (реинит заблокирован) |
|
uint8_t callbacks_running; // 1 - внутри итерации колбэк-цепочек, etcp_connection_close запрещён |
|
|
|
// Unified callback chain with event mask (init/reinit/up/down/node_changed) |
|
struct etcp_cbk_entry* cbks; |
|
uint8_t reinit_pending; // 1 = reinit в процессе, ждём завершения |
|
void (*bgp_ready_cbk)(struct ETCP_CONN* conn); // вызывается когда BGP готов (завершён или пропущен) |
|
|
|
uint8_t fin_wait : 1; // close-pending: ожидаем подтверждение закрытия от remote |
|
void (*fin_wait_clear_cb)(struct ETCP_CONN* conn, void* arg); // вызывается при сбросе fin_wait |
|
void* fin_wait_clear_arg; |
|
|
|
uint32_t cnt_ack_hit_inf; // счетчик удлений из inflight |
|
uint32_t cnt_ack_hit_sndq; // счетчик удалений inflight пакетов из sndq |
|
uint32_t cnt_ack_miss; // счетчик не найденных ack |
|
uint32_t cnt_link_wait; // счетчик переходов в ожидание когда link busy |
|
uint32_t rx_dup_count; // счетчик принятых дубликатов (локальные) |
|
uint32_t tx_dup_count; // счетчик дубликатов удаленной стороны (из ACK) |
|
uint32_t debug[8]; // 8 значений для дебага (live watch) |
|
|
|
struct etcp_metrics metrics; // гистограммы RTT/потерь, тотальные счётчики |
|
|
|
// Logging identifier (format: "XXXX→XXXX [name]" - last 4 digits of local and peer node_id + optional name) |
|
char log_name[256]; |
|
char* name; // Connection name from config (e.g., "client_test1"), or NULL/empty |
|
}; |
|
|
|
#define RTT_CB_PERIOD_TB 600000 // 1 минута в 0.1ms |
|
|
|
// Functions |
|
struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance, char* name); |
|
void etcp_connection_close(struct ETCP_CONN* etcp); |
|
void etcp_conn_queue_set_ready(struct ETCP_CONN* conn); // move pending->connections, fire ready cbks |
|
|
|
/** |
|
* @brief Take a reference on the connection (blocks deferred resource free). |
|
* @param conn connection |
|
* @return 0 on success, -1 if conn is NULL or already in state 2 (deleted). |
|
* |
|
* Increments ref_count. While ref_count > 0, etcp_connection_close() |
|
* will detach but defer resource cleanup until all references are released. |
|
* Always pair with etcp_conn_ref_free(). |
|
*/ |
|
int etcp_conn_ref_take(struct ETCP_CONN* conn); |
|
|
|
/** |
|
* @brief Release a reference. Triggers deferred resource free if last ref and state==2. |
|
* @param conn connection |
|
* |
|
* Decrements ref_count. If ref_count reaches 0 and the connection has been closed |
|
* (state == 2), schedules deferred resource cleanup via uasync_call_soon. |
|
* Safe to call on NULL. |
|
*/ |
|
void etcp_conn_ref_free(struct ETCP_CONN* conn); |
|
|
|
void etcp_conn_reset(struct ETCP_CONN* etcp); |
|
void etcp_links_reset(struct ETCP_CONN* etcp); |
|
|
|
void etcp_conn_reinit(struct ETCP_CONN* etcp, const char* reason); |
|
|
|
void etcp_connection_ready(struct ETCP_CONN* etcp);// вызывается когда подключение инициализировано |
|
|
|
// Отправка: используем api ll_queue для очереди ETCP_CONN.input_queue |
|
// Прием: используем api ll_queue для очереди ETCP_CONN.output_queue |
|
// для очередей используется формат |
|
|
|
// Input from etcp_connections (decrypted packet) |
|
void etcp_conn_input(struct ETCP_DGRAM* pkt); |
|
|
|
// Send data through ETCP connection |
|
// Allocates memory from data_pool and places in input queue |
|
// Returns: 0 on success, -1 on failure |
|
int etcp_int_send(struct ETCP_CONN* etcp, const void* data, uint16_t len); |
|
|
|
// Request next packet for load balancer |
|
struct ETCP_DGRAM* etcp_request_pkt(struct ETCP_CONN* etcp); |
|
|
|
// Process ACK receipt - remove acknowledged packet from inflight queues |
|
void etcp_ack_recv(struct ETCP_CONN* etcp, uint32_t seq, uint16_t ts, uint16_t dts); |
|
|
|
// Recalculate optimal_inflight and resume input queue after link inflight_lim change |
|
void etcp_conn_on_inflight_lim_changed(struct ETCP_CONN* etcp); |
|
|
|
// Update log_name when peer_node_id becomes known |
|
void etcp_update_log_name(struct ETCP_CONN* etcp); |
|
|
|
// Вызывается стеком etcp когда соединение установлено (можно передавать данные) |
|
void etcp_conn_ready(struct ETCP_CONN* conn); |
|
|
|
void etcp_on_link_down(struct ETCP_CONN* etcp); |
|
|
|
void etcp_update_mtu(struct ETCP_CONN* etcp); |
|
|
|
void etcp_metrics_init(struct etcp_metrics* m); |
|
void etcp_metrics_add_rtt(struct ETCP_CONN* etcp, uint16_t rtt_tb); |
|
void etcp_metrics_add_sent(struct ETCP_CONN* etcp, uint32_t len); |
|
void etcp_metrics_add_rcvd(struct ETCP_CONN* etcp, uint32_t len); |
|
void etcp_metrics_add_loss(struct ETCP_CONN* etcp, uint32_t count); |
|
void etcp_metrics_start_timer(struct ETCP_CONN* etcp); |
|
void etcp_metrics_stop_timer(struct ETCP_CONN* etcp); |
|
|
|
#ifdef __cplusplus |
|
} |
|
#endif |
|
|
|
#endif // ETCP_H
|