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.
191 lines
7.7 KiB
191 lines
7.7 KiB
/** |
|
* @file dummynet.h |
|
* @brief UDP dummynet эмулятор с задержкой, bandwidth limiting и случайными потерями |
|
* |
|
* Эмулирует сетевые условия: задержку (fixed + random), ограничение пропускной способности |
|
* и случайные потери пакетов. Работает как "человек посередине" - принимает пакеты на |
|
* listen_port и пересылает между port-1 и port+1 с эмуляцией условий канала. |
|
* |
|
* Архитектура: |
|
* [UDP recv] -> [delay timer] -> [check queue/drop] -> [ll_queue] -> [shaper timer] -> [UDP send] |
|
* ^ |
|
* loss check |
|
* |
|
* Поток данных: |
|
* - Слушаем на bind_ip:listen_port |
|
* - Пакеты от listen_port-1 -> отправляем на dest_forward (forward direction) |
|
* - Пакеты от listen_port+1 -> отправляем на dest_backward (backward direction) |
|
* - Каждое направление имеет свою очередь и параметры эмуляции |
|
*/ |
|
|
|
#ifndef DUMMYNET_H |
|
#define DUMMYNET_H |
|
|
|
#ifdef __cplusplus |
|
extern "C" { |
|
#endif |
|
|
|
|
|
#include <stdint.h> |
|
#include <stddef.h> |
|
|
|
// Forward declarations |
|
struct UASYNC; |
|
struct ll_queue; |
|
struct ll_entry; |
|
|
|
/* Направления передачи */ |
|
#define DUMMYNET_FORWARD 0 // port-1 -> port+1 |
|
#define DUMMYNET_BACKWARD 1 // port+1 -> port-1 |
|
#define DUMMYNET_DIR_COUNT 2 |
|
|
|
/* Максимальный размер UDP пакета */ |
|
#define DUMMYNET_MAX_PKT_SIZE 1500 |
|
|
|
/* Максимальное время задержки (10 секунд) */ |
|
#define DUMMYNET_MAX_DELAY_MS 10000 |
|
|
|
/* Максимальное значение loss_permille (1000 = 100%) */ |
|
#define DUMMYNET_MAX_LOSS_PERMILLE 1000 |
|
|
|
/** |
|
* @brief Статистика направления |
|
*/ |
|
struct dummynet_stats { |
|
uint64_t recv; // Принято пакетов |
|
uint64_t sent; // Отправлено пакетов |
|
uint64_t dropped; // Дропнуто (queue full) |
|
uint64_t lost; // Потеряно случайно (random loss) |
|
uint32_t queue_size; // Текущий размер очереди |
|
uint32_t queue_max; // Максимальный размер очереди (пиковый) |
|
}; |
|
|
|
/** |
|
* @brief Контекст dummynet |
|
*/ |
|
struct dummynet; |
|
|
|
/** |
|
* @brief Создаёт dummynet контекст |
|
* |
|
* @param ua Экземпляр uasync (обязателен) |
|
* @param bind_ip IP адрес для привязки (NULL или "0.0.0.0" для всех интерфейсов) |
|
* @param listen_port Порт для прослушивания (средний порт, port-1 и port+1 - клиенты) |
|
* @return Указатель на контекст или NULL при ошибке |
|
*/ |
|
struct dummynet* dummynet_create(struct UASYNC* ua, const char* bind_ip, uint16_t listen_port); |
|
|
|
/** |
|
* @brief Уничтожает dummynet контекст |
|
* |
|
* Освобождает все ресурсы, закрывает сокет, отменяет таймеры. |
|
* |
|
* @param dn Контекст dummynet |
|
*/ |
|
void dummynet_destroy(struct dummynet* dn); |
|
|
|
/** |
|
* @brief Настраивает параметры направления |
|
* |
|
* @param dn Контекст dummynet |
|
* @param direction Направление: DUMMYNET_FORWARD или DUMMYNET_BACKWARD |
|
* @param delay_fixed_ms Фиксированная задержка (мс) |
|
* @param delay_random_ms Случайная составляющая задержки (0..random_ms, мс) |
|
* @param bandwidth_kbps Пропускная способность (кбит/с, 0 = unlimited) |
|
* @param max_queue_pkts Максимальный размер очереди (пакетов) |
|
* @param loss_permille Вероятность потери пакета (0.1%, 0-1000) |
|
* @param dest_ip IP адрес назначения |
|
* @param dest_port Порт назначения |
|
* @return 0 при успехе, -1 при ошибке |
|
*/ |
|
int dummynet_set_direction(struct dummynet* dn, int direction, |
|
uint32_t delay_fixed_ms, uint32_t delay_random_ms, |
|
uint32_t bandwidth_kbps, uint32_t max_queue_pkts, |
|
uint32_t loss_permille, |
|
const char* dest_ip, uint16_t dest_port); |
|
|
|
/** |
|
* @brief Получает статистику направления |
|
* |
|
* @param dn Контекст dummynet |
|
* @param direction Направление |
|
* @return Указатель на статистику или NULL |
|
*/ |
|
const struct dummynet_stats* dummynet_get_stats(struct dummynet* dn, int direction); |
|
|
|
/** |
|
* @brief Сбрасывает статистику направления |
|
* |
|
* @param dn Контекст dummynet |
|
* @param direction Направление (-1 для всех направлений) |
|
*/ |
|
void dummynet_reset_stats(struct dummynet* dn, int direction); |
|
|
|
/** |
|
* @brief Возвращает файловый дескриптор сокета (для отладки) |
|
* |
|
* @param dn Контекст dummynet |
|
* @return socket_t или SOCKET_INVALID |
|
*/ |
|
int dummynet_get_socket(struct dummynet* dn); |
|
|
|
/** |
|
* @brief Возвращает listen_port |
|
* |
|
* @param dn Контекст dummynet |
|
* @return Порт или 0 |
|
*/ |
|
uint16_t dummynet_get_listen_port(struct dummynet *dn); |
|
|
|
/** |
|
* @brief Возвращает указатель на UASYNC (для запуска poll) |
|
* |
|
* @param dn Контекст dummynet |
|
* @return Указатель на UASYNC или NULL |
|
*/ |
|
struct UASYNC *dummynet_get_uasync(struct dummynet *dn); |
|
|
|
/** |
|
* @brief Возвращает размер очереди направления |
|
* |
|
* @param dn Контекст dummynet |
|
* @param direction Направление |
|
* @return Размер очереди или -1 |
|
*/ |
|
int dummynet_get_queue_size(struct dummynet *dn, int direction); |
|
|
|
/** |
|
* @brief Получает отладочные счетчики направления |
|
* |
|
* @param dn Контекст dummynet |
|
* @param direction Направление |
|
* @param delay_set Выход: число установок delay таймеров |
|
* @param delay_fire Выход: число срабатываний delay таймеров |
|
* @param shaper_set Выход: число установок shaper таймеров |
|
* @param shaper_fire Выход: число срабатываний shaper таймеров |
|
*/ |
|
void dummynet_get_debug_counters(struct dummynet *dn, int direction, |
|
uint64_t *delay_set, uint64_t *delay_fire, |
|
uint64_t *shaper_set, uint64_t *shaper_fire); |
|
|
|
// === Inline filter: встраивается в etcp_udp_send через link->send_hook === |
|
// Не создаёт свой сокет — перехватывает пакеты напрямую из пути отправки. |
|
|
|
struct ETCP_LINK; |
|
struct dummynet_filter; |
|
|
|
struct dummynet_filter* dummynet_filter_create(struct UASYNC* ua); |
|
void dummynet_filter_set_loss(struct dummynet_filter* df, uint32_t loss_permille); |
|
void dummynet_filter_set_delay(struct dummynet_filter* df, uint32_t delay_ms, uint32_t jitter_ms); |
|
void dummynet_filter_attach(struct dummynet_filter* df, struct ETCP_LINK* link); |
|
void dummynet_filter_detach(struct dummynet_filter* df); |
|
void dummynet_filter_destroy(struct dummynet_filter* df); |
|
const struct dummynet_stats* dummynet_filter_get_stats(struct dummynet_filter* df); |
|
void dummynet_filter_block_addr(struct dummynet_filter* df, uint32_t ip, uint16_t port); |
|
void dummynet_filter_unblock_addr(struct dummynet_filter* df, uint32_t ip, uint16_t port); |
|
|
|
|
|
#ifdef __cplusplus |
|
} |
|
#endif |
|
#endif // DUMMYNET_H
|
|
|