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.
 
 
 
 
 
 

308 lines
17 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)
// 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
#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 ETCP_ACK_GAP_MAX_PACKETS 8192 // предел кумулятивного ACK за приём: 8192 × PACKET_DATA_SIZE(2048) = 16 MB (защита от DoS)
#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
uint8_t tcp_link_count; // количество UP TCP линков
uint8_t last_assigned_link_id; // последний выданный link_id (для циклического перебора)
// 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)
uint8_t peer_sleep_phase; // 1 = пир в SLEEP-фазе (троттлить), 0 = ACTIVE-окно (обмен)
uint16_t peer_active_remaining; // до SLEEP-фазы (x0.1с), из keepalive
uint16_t peer_sleep_duration; // длительность SLEEP-фазы (x0.1с), из keepalive
void* peer_phase_timer; // таймер смены фазы троттлинга
// ============ 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 - хотя бы один линк проинициалзирован (обмен ключами произведен)
uint64_t reset_id; // метка эпохи ресета (генерируется при локальном ресете, master авторитет)
uint64_t peer_reset_id; // последняя увиденная эпоха ресета пира
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)
// 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);
// Реинит с конкретным reset_id (для adopt чужой эпохи) — без генерации нового id
void etcp_conn_reinit_id(struct ETCP_CONN* etcp, const char* reason, uint64_t reset_id);
// Фатальный ресет (normalizer desync / bad fragment size): генерит новую эпоху reset_id
void etcp_conn_fatal_reinit(struct ETCP_CONN* etcp, const char* reason);
// Применение чужого reset_id: при отличии — slave принимает эпоху пира и ресетится, master пересылает свою
void etcp_conn_apply_peer_reset_id(struct ETCP_CONN* conn, uint64_t peer_reset_id);
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);
// Fire connection status callback on instance's conn_status_cbks chain
void etcp_fire_conn_status(struct ETCP_CONN* conn, int status);
// 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, struct ETCP_LINK* down_link);
void etcp_update_mtu(struct ETCP_CONN* etcp);
#ifdef __cplusplus
}
#endif
#endif // ETCP_H