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

// 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