diff --git a/net_emulator/net_emulator.c b/net_emulator/net_emulator.c index 775edcb5..02d53d00 100644 --- a/net_emulator/net_emulator.c +++ b/net_emulator/net_emulator.c @@ -3,6 +3,7 @@ #include "net_emulator.h" #include "u_async.h" #include "mem.h" +#include "debug_config.h" #include #include #include @@ -79,7 +80,7 @@ static int parse_ip_port(const char *str, struct sockaddr_in *addr) { static int parse_delay_range(const char *str, delay_range_t *range) { if (!str || !range) return -1; - char *dash = strchr(str, '-'); + const char *dash = strchr(str, '-'); if (!dash) { // Single value range->min_ms = atoi(str); @@ -103,10 +104,10 @@ static int parse_delay_range(const char *str, delay_range_t *range) { static int parse_rule(const char *line, rule_t *rule) { if (!line || !rule) return -1; - char *prob_start = strstr(line, "prob="); + const char *prob_start = strstr(line, "prob="); if (!prob_start) return -1; - char *comma = strchr(prob_start, ','); + const char *comma = strchr(prob_start, ','); if (!comma) return -1; // Parse probability @@ -117,7 +118,7 @@ static int parse_rule(const char *line, rule_t *rule) { if (rule->probability_percent < 0 || rule->probability_percent > 100) return -1; // Parse delay - char *delay_start = strstr(comma, "delay="); + const char *delay_start = strstr(comma, "delay="); if (!delay_start) return -1; char delay_str[64]; @@ -179,6 +180,7 @@ int parse_emulator_config(const char *filename, net_emulator_t *emulator) { current_endpoint = &emulator->endpoints[emulator->endpoint_count]; memset(current_endpoint, 0, sizeof(endpoint_t)); + current_endpoint->sockfd = -1; // Parse listen address if (parse_ip_port(endpoint_str, ¤t_endpoint->listen_addr) < 0) { @@ -417,7 +419,7 @@ int net_emulator_init(net_emulator_t *emulator) { if (create_endpoint_socket(ep) < 0) { fprintf(stderr, "Failed to create socket for endpoint %s:%u\n", inet_ntoa(ep->listen_addr.sin_addr), ntohs(ep->listen_addr.sin_port)); - uasync_destroy(emulator->ua); + uasync_destroy(emulator->ua, 0); emulator->ua = NULL; return -1; } @@ -425,7 +427,11 @@ int net_emulator_init(net_emulator_t *emulator) { ep->emulator = emulator; // Add socket to u_async - uasync_add_socket(emulator->ua, ep->sockfd, socket_callback, NULL, NULL, "emulator", ep); + if (!uasync_add_socket(emulator->ua, ep->sockfd, socket_callback, NULL, NULL, "emulator", ep)) { + DEBUG_ERROR(DEBUG_CATEGORY_SYS, "net_emulator_init: socket registration failed fd=%d endpoint=%d", ep->sockfd, i); + net_emulator_cleanup(emulator); + return -1; + } printf("[INIT] Listening on %s:%u\n", inet_ntoa(ep->listen_addr.sin_addr), ntohs(ep->listen_addr.sin_port)); } @@ -439,7 +445,7 @@ void net_emulator_run(net_emulator_t *emulator) { if (!emulator || !emulator->running || !emulator->ua) return; printf("[EMULATOR] Starting main loop. Press Ctrl+C to stop.\n"); - uasync_mainloop(emulator->ua); // This never returns + uasync_mainloop(emulator->ua); // Возвращается после uasync_stop. } // Clean up emulator resources @@ -455,7 +461,7 @@ void net_emulator_cleanup(net_emulator_t *emulator) { } if (emulator->ua) { - uasync_destroy(emulator->ua); + uasync_destroy(emulator->ua, 0); emulator->ua = NULL; } @@ -466,6 +472,7 @@ void net_emulator_cleanup(net_emulator_t *emulator) { int main(int argc, char *argv[]) { setbuf(stdout, NULL); setbuf(stderr, NULL); + debug_config_init(); if (argc != 2) { fprintf(stderr, "Usage: %s \n", argv[0]); @@ -500,4 +507,4 @@ int main(int argc, char *argv[]) { // Cleanup (never reached) net_emulator_cleanup(&g_emulator); return 0; -} \ No newline at end of file +} diff --git a/net_emulator/net_emulator.h b/net_emulator/net_emulator.h index 7afd1a34..bebc1f25 100644 --- a/net_emulator/net_emulator.h +++ b/net_emulator/net_emulator.h @@ -1,4 +1,8 @@ -// net_emulator.h - Network emulator for testing utun with delay, loss, reordering +/* IPv4 UDP-эмулятор одного потока uasync: правила случайной задержки и остаточная вероятность потерь. + * Обнулить состояние → parse_emulator_config → init → run → cleanup после возврата из run. + * Конфиг: [IPv4:port], строки prob=N,delay=min-max (мс); до 100 endpoint, до 10 правил на endpoint. + * Для каждого пакета выбирается одно правило по накопленной вероятности; остаток до 100% означает drop. + * Разные задержки могут менять порядок пакетов; отдельного механизма перестановки по reorder_probability нет. */ #ifndef NET_EMULATOR_H #define NET_EMULATOR_H @@ -22,8 +26,8 @@ typedef struct net_emulator_s net_emulator_t; // Delay range (milliseconds) typedef struct { - int min_ms; - int max_ms; + int min_ms; // Минимальная задержка >=0 + int max_ms; // Верхняя граница включительно; max >= min, значение <= INT_MAX/10 для timebase } delay_range_t; // Rule: probability and delay @@ -35,16 +39,15 @@ typedef struct { // Network endpoint configuration typedef struct { struct sockaddr_in listen_addr; // Address to listen on - struct sockaddr_in target_addr; // Address to forward to (port - 10000) + struct sockaddr_in target_addr; // Тот же IP; порт listen-10000 при listen>=10000, иначе исходный порт rule_t rules[MAX_RULES_PER_ENDPOINT]; int rule_count; - int total_probability; // Sum of probabilities (should be <= 100) + int total_probability; // Сумма 0..100%; вероятность потери — 100-total_probability - // For reordering simulation - int reorder_probability; // Probability to reorder with next packet (0-100) + int reorder_probability; // Не используется и не читается из конфигурации // Socket descriptor - int sockfd; + int sockfd; // Созданный endpoint-сокет; -1 до создания/после cleanup net_emulator_t* emulator; // Parent emulator instance } endpoint_t; @@ -52,34 +55,39 @@ typedef struct { struct net_emulator_s { endpoint_t endpoints[MAX_ENDPOINTS]; int endpoint_count; - int running; - uasync_t* ua; // uasync instance + int running; // init завершён; сам флаг не останавливает mainloop, нужен uasync_stop(ua) + uasync_t* ua; // Принадлежит эмулятору, создаётся init и уничтожается cleanup }; /** - * @brief Parse configuration file - * @param filename Configuration file path - * @param emulator Emulator state to fill - * @return 0 on success, -1 on error + * @brief Читает endpoint и правила; перед первым вызовом обнулить emulator, живой экземпляр не перенастраивать. + * @param filename путь к конфигу; строки с ';' и пустые пропускаются + * @param emulator состояние, в которое добавляются endpoint; прежние записи не очищаются + * @return 0 после разбора; -1 при NULL, ошибке открытия, неверном endpoint, превышении лимитов/суммы вероятностей + * Ошибочное правило логируется и пропускается без -1; прочие нераспознанные строки игнорируются. + * При -1 уже разобранная часть сохраняется. Диапазон задержек должен помещаться в INT_MAX/10 мс. */ int parse_emulator_config(const char *filename, net_emulator_t *emulator); /** - * @brief Initialize network emulator - * @param emulator Emulator state - * @return 0 on success, -1 on error + * @brief Создаёт собственный uasync и неблокирующие UDP-сокеты настроенных endpoint. + * @param emulator состояние после parse, без живого ua; endpoint/rule counts должны помещаться в массивы + * @return 0 — сокеты созданы и зарегистрированы, -1 — NULL/ошибка ресурсов; после ошибки вызвать cleanup + * При ручном заполнении endpoint до init установить sockfd=-1. Ошибка init может оставить созданные сокеты до cleanup. */ int net_emulator_init(net_emulator_t *emulator); /** - * @brief Run network emulator main loop - * @param emulator Emulator state + * @brief Запускает блокирующий mainloop, возвращается после uasync_stop(emulator->ua). + * @param emulator успешно инициализированное состояние; NULL/нет ua/running=0 ничего не делает + * Остановка и cleanup выполняются при согласованном времени жизни состояния, cleanup — вне callbacks. */ void net_emulator_run(net_emulator_t *emulator); /** - * @brief Clean up emulator resources - * @param emulator Emulator state + * @brief Закрывает созданные endpoint-сокеты и уничтожает собственный ua, сбрасывает running. + * @param emulator состояние после init (в том числе неудачного); NULL и повторный cleanup допустимы + * Перед cleanup завершить отложенные отправки: уничтожение таймеров uasync само не освобождает их packet-аргументы. */ void net_emulator_cleanup(net_emulator_t *emulator); @@ -87,4 +95,4 @@ void net_emulator_cleanup(net_emulator_t *emulator); } #endif -#endif /* NET_EMULATOR_H */ \ No newline at end of file +#endif /* NET_EMULATOR_H */