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.
234 lines
11 KiB
234 lines
11 KiB
// etcp.h - Расширенный протокол управления передачей (Extended Transmission Control Protocol) |
|
#ifndef ETCP_H |
|
#define ETCP_H |
|
|
|
#include <stdint.h> |
|
#include <stddef.h> |
|
#include "ll_queue.h" |
|
#include "u_async.h" |
|
|
|
// Отладочное логирование |
|
#ifdef ETCP_DEBUG |
|
#include <stdio.h> |
|
#define ETCP_LOG(fmt, ...) printf("[ETCP] " fmt, ##__VA_ARGS__) |
|
#ifdef ETCP_DEBUG_EXT |
|
#define ETCP_DEBUG_LOG(fmt, ...) printf("[ETCP_DEBUG] " fmt, ##__VA_ARGS__) |
|
#else |
|
#define ETCP_DEBUG_LOG(fmt, ...) ((void)0) |
|
#endif |
|
#else |
|
#define ETCP_LOG(fmt, ...) ((void)0) |
|
#define ETCP_DEBUG_LOG(fmt, ...) ((void)0) |
|
#endif |
|
|
|
#ifdef __cplusplus |
|
extern "C" { |
|
#endif |
|
|
|
// Предварительные объявления |
|
typedef struct epkt epkt_t; |
|
|
|
// Тип обратного вызова для отправки пакетов через UDP |
|
typedef void (*etcp_tx_callback_t)(epkt_t* epkt, uint8_t* pkt, uint16_t len, void* arg); |
|
|
|
// Основная структура ETCP |
|
struct epkt { |
|
// Очереди |
|
ll_queue_t* tx_queue; // Очередь данных для отправки |
|
ll_queue_t* output_queue; // Выходная очередь (собранные данные) |
|
|
|
// Список полученных пакетов (отсортированный связанный список) |
|
struct rx_packet* rx_list; |
|
|
|
// Отправленные пакеты (для повторной передачи) |
|
struct sent_packet* sent_list; |
|
|
|
// Метрики |
|
uint16_t rtt_last; // Последнее RTT (в единицах времени 0.1 мкс) |
|
uint16_t rtt_avg_10; // Среднее RTT за последние 10 пакетов |
|
uint16_t rtt_avg_100; // Среднее RTT за последние 100 пакетов |
|
uint16_t jitter; // Джиттер (усредненный) |
|
uint16_t bandwidth; // Текущая пропускная способность (байты за единицу времени) |
|
uint32_t bytes_sent_total; // Общее количество отправленных байт |
|
uint16_t last_sent_timestamp; // Временная метка последнего отправленного пакета |
|
uint32_t bytes_allowed; // Рассчитанное количество разрешенных к отправке байт |
|
|
|
// Статистика |
|
uint32_t retransmissions_count; // Количество ретрансмиссий |
|
uint32_t ack_packets_count; // Количество отправленных пакетов подтверждения |
|
uint32_t control_packets_count; // Количество отправленных управляющих пакетов (ACK + запросы ретрансмиссии) |
|
uint32_t total_packets_sent; // Общее количество отправленных пакетов (включая ретрансмиссии) |
|
uint32_t unique_packets_sent; // Количество уникальных отправленных пакетов (без ретрансмиссий) |
|
uint32_t bytes_received_total; // Общее количество полученных байт |
|
|
|
// Состояние |
|
uint16_t next_tx_id; // Следующий ID для передачи |
|
uint16_t last_sent_id; // Последний отправленный ID (для ретрансмиссии самого нового пакета) |
|
uint16_t last_rx_id; // Последний полученный ID (для подтверждения) |
|
uint16_t last_delivered_id; // Последний ID, переданный в output_queue |
|
|
|
// Таймеры |
|
void* next_tx_timer; // Таймер для следующей передачи |
|
void* retransmit_timer; // Таймер для повторных передач |
|
uasync_t* ua; // Экземпляр uasync для таймеров |
|
|
|
// Обратный вызов |
|
etcp_tx_callback_t tx_callback; |
|
void* tx_callback_arg; |
|
|
|
// История RTT для усреднения |
|
uint16_t rtt_history[100]; |
|
uint8_t rtt_history_idx; |
|
uint8_t rtt_history_count; |
|
|
|
// Ожидающие подтверждения |
|
uint16_t pending_ack_ids[32]; |
|
uint16_t pending_ack_timestamps[32]; |
|
uint8_t pending_ack_count; |
|
|
|
// Ожидающие запросы на повторную передачу |
|
uint16_t pending_retransmit_ids[32]; |
|
uint8_t pending_retransmit_count; |
|
|
|
// Управление окном |
|
uint32_t unacked_bytes; // Количество байт, отправленных но еще не подтвержденных |
|
uint32_t window_size; // Текущий размер окна в байтах (рассчитывается) |
|
uint16_t last_acked_id; // Последний подтвержденный ID пакета |
|
uint16_t last_rx_ack_id; // Последний полученный ID подтверждения от получателя |
|
uint16_t retrans_timer_period; // Текущий период таймера повторной передачи (в единицах времени) |
|
uint16_t next_retrans_time; // Время следующей проверки повторной передачи |
|
uint8_t window_blocked; // Флаг: передача заблокирована из-за ограничения окна |
|
|
|
// Forward progress tracking |
|
uint16_t oldest_missing_id; // Oldest missing packet ID |
|
uint16_t missing_since_time; // Time when oldest missing packet was first detected |
|
|
|
// Reset state |
|
uint8_t reset_pending; // Reset packet sent, waiting for ACK |
|
uint8_t reset_ack_received; // Reset ACK received |
|
void* reset_timer; // Timer for reset retransmission |
|
uint16_t reset_retry_count; // Number of reset retries |
|
}; |
|
|
|
// Функции API |
|
|
|
/** |
|
* @brief Инициализировать новый экземпляр ETCP |
|
* @param ua Экземпляр uasync для таймеров (обязательный параметр) |
|
* @return Указатель на новый экземпляр или NULL в случае ошибки |
|
*/ |
|
epkt_t* etcp_init(uasync_t* ua); |
|
|
|
/** |
|
* @brief Освободить экземпляр ETCP и все связанные ресурсы |
|
* @param epkt Экземпляр для освобождения |
|
*/ |
|
void etcp_free(epkt_t* epkt); |
|
|
|
/** |
|
* @brief Установить обратный вызов для отправки пакетов через UDP |
|
* @param epkt Экземпляр ETCP |
|
* @param cb Функция обратного вызова |
|
* @param arg Пользовательский аргумент, передаваемый в обратный вызов |
|
*/ |
|
void etcp_set_callback(epkt_t* epkt, etcp_tx_callback_t cb, void* arg); |
|
|
|
/** |
|
* @brief Обработать полученный UDP пакет |
|
* @param epkt Экземпляр ETCP |
|
* @param pkt Данные пакета |
|
* @param len Длина пакета |
|
* @return 0 при успехе, -1 при ошибке |
|
*/ |
|
int etcp_rx_input(epkt_t* epkt, uint8_t* pkt, uint16_t len); |
|
|
|
/** |
|
* @brief Получить общее количество пакетов, ожидающих в очередях передачи |
|
* @param epkt Экземпляр ETCP |
|
* @return Количество пакетов |
|
*/ |
|
int etcp_tx_queue_size(epkt_t* epkt); |
|
|
|
/** |
|
* @brief Поместить данные в очередь передачи |
|
* @param epkt Экземпляр ETCP |
|
* @param data Данные для отправки |
|
* @param len Длина данных |
|
* @return 0 при успехе, -1 при ошибке |
|
*/ |
|
int etcp_tx_put(epkt_t* epkt, uint8_t* data, uint16_t len); |
|
|
|
/** |
|
* @brief Получить выходную очередь для чтения полученных данных |
|
* @param epkt Экземпляр ETCP |
|
* @return Указатель на выходную очередь (ll_queue_t*) |
|
*/ |
|
ll_queue_t* etcp_get_output_queue(epkt_t* epkt); |
|
|
|
/** |
|
* @brief Установить ограничение пропускной способности |
|
* @param epkt Экземпляр ETCP |
|
* @param bandwidth Байты за единицу времени (0.1 мкс) |
|
*/ |
|
void etcp_set_bandwidth(epkt_t* epkt, uint16_t bandwidth); |
|
|
|
/** |
|
* @brief Обновить размер окна на основе текущего RTT и пропускной способности |
|
* @param epkt Экземпляр ETCP |
|
* Размер окна = RTT * пропускная способность * 2 (байт в пути) |
|
*/ |
|
void etcp_update_window(epkt_t* epkt); |
|
|
|
/** |
|
* @brief Получить текущее RTT |
|
* @param epkt Экземпляр ETCP |
|
* @return RTT в единицах времени |
|
*/ |
|
uint16_t etcp_get_rtt(epkt_t* epkt); |
|
|
|
/** |
|
* @brief Получить текущий джиттер |
|
* @param epkt Экземпляр ETCP |
|
* @return Джиттер в единицах времени |
|
*/ |
|
uint16_t etcp_get_jitter(epkt_t* epkt); |
|
|
|
/** |
|
* @brief Сбросить состояние соединения (очистить очереди, метрики, таймеры) |
|
* @param epkt Экземпляр ETCP |
|
* Примечание: Сохраняет настройки пропускной способности и обратного вызова |
|
*/ |
|
void etcp_reset(epkt_t* epkt); |
|
|
|
/** |
|
* @brief Инициировать сброс соединения через служебные пакеты |
|
* @param epkt Экземпляр ETCP |
|
* Отправляет пакет сброса (0x02) и ждет подтверждения (0x03) с повторными попытками каждые 100мс |
|
*/ |
|
void etcp_reset_connection(epkt_t* epkt); |
|
|
|
/** |
|
* @brief Получить статистику ETCP |
|
* @param epkt Экземпляр ETCP |
|
* @param retransmissions Указатель для возврата количества ретрансмиссий |
|
* @param total_packets_sent Указатель для возврата общего количества отправленных пакетов |
|
* @param unique_packets_sent Указатель для возврата количества уникальных отправленных пакетов |
|
* @param bytes_sent_total Указатель для возврата общего количества отправленных байт |
|
* @param bytes_received_total Указатель для возврата общего количества полученных байт |
|
* @param ack_packets_count Указатель для возврата количества отправленных пакетов подтверждения |
|
* @param control_packets_count Указатель для возврата количества отправленных управляющих пакетов |
|
*/ |
|
void etcp_get_stats(epkt_t* epkt, |
|
uint32_t* retransmissions, |
|
uint32_t* total_packets_sent, |
|
uint32_t* unique_packets_sent, |
|
uint32_t* bytes_sent_total, |
|
uint32_t* bytes_received_total, |
|
uint32_t* ack_packets_count, |
|
uint32_t* control_packets_count); |
|
|
|
#ifdef __cplusplus |
|
} |
|
#endif |
|
|
|
#endif // ETCP_H
|
|
|