Update emulator uasync lifecycle and document forwarding rules
This commit is contained in:
1 parent
56d5fcd75a
commit
ff3eb02bff
2 files changed
+46
-31
No files matched your search
@@ -3,6 +3,7 @@
|
||||
#include "net_emulator.h"
|
||||
#include "u_async.h"
|
||||
#include "mem.h"
|
||||
#include "debug_config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -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 <config_file>\n", argv[0]);
|
||||
@@ -500,4 +507,4 @@ int main(int argc, char *argv[]) {
|
||||
// Cleanup (never reached)
|
||||
net_emulator_cleanup(&g_emulator);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+30
-22
@@ -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 */
|
||||
#endif /* NET_EMULATOR_H */
|
||||
Reference in new issue
Block a user