// etcp.h - Расширенный протокол управления передачей (Extended Transmission Control Protocol) #ifndef ETCP_H #define ETCP_H #include #include #include "ll_queue.h" // Отладочное логирование #ifdef ETCP_DEBUG #include #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; // Таймер для повторных передач // Обратный вызов 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 * @return Указатель на новый экземпляр или NULL в случае ошибки */ epkt_t* etcp_init(void); /** * @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