#include /** * @file test_dummynet_simple.c * @brief Упрощённый тест модуля dummynet */ #include #include #include #include #include #include #include #include "../lib/u_async.h" #include "../lib/socket_compat.h" #include "../lib/debug_config.h" #include "../src/dummynet.h" #define LISTEN_PORT 17000 #define PKT_COUNT 100 #define MAX_PKT_SIZE 1500 struct test_header { uint32_t seq_num; uint64_t send_time_us; } __attribute__((packed)); static int tests_passed = 0; static int tests_failed = 0; static inline uint64_t get_time_us(void) { struct timeval tv; gettimeofday(&tv, NULL); return (uint64_t)tv.tv_sec * 1000000ULL + tv.tv_usec; } static socket_t create_bound_socket(uint16_t port) { socket_t sock = socket_create_udp(AF_INET); if (sock == SOCKET_INVALID) return SOCKET_INVALID; struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_port = htons(port); int reuse = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) != 0) { socket_close_wrapper(sock); return SOCKET_INVALID; } return sock; } /* Функция для запуска uasync в отдельном потоке */ static void* uasync_thread(void* arg) { struct UASYNC* ua = (struct UASYNC*)arg; printf(" [uasync] Event loop started\n"); /* Запускаем цикл на 5 секунд */ for (int i = 0; i < 500; i++) { uasync_poll(ua, 10); /* 10 timebase = 1ms */ usleep(1000); /* 1ms */ } printf(" [uasync] Event loop finished\n"); return NULL; } int main(void) { printf("========================================\n"); printf("Dummynet Simple Test\n"); printf("========================================\n\n"); srand((unsigned int)time(NULL)); debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN); socket_platform_init(); struct UASYNC* ua = uasync_create(); if (!ua) { printf("[FAIL] Failed to create uasync\n"); return 1; } /* Создаём сокеты */ socket_t sock_a = create_bound_socket(LISTEN_PORT - 1); socket_t sock_b = create_bound_socket(LISTEN_PORT + 1); if (sock_a == SOCKET_INVALID || sock_b == SOCKET_INVALID) { printf("[FAIL] Failed to create sockets\n"); return 1; } /* Создаём dummynet с задержкой 50ms и jitter 20ms */ struct dummynet* dn = dummynet_create(ua, "127.0.0.1", LISTEN_PORT); if (!dn) { printf("[FAIL] Failed to create dummynet\n"); return 1; } dummynet_set_direction(dn, DUMMYNET_FORWARD, 50, 20, /* delay: 50ms + 0..20ms */ 0, /* unlimited bandwidth */ 100, /* max queue */ 0, /* no loss */ "127.0.0.1", LISTEN_PORT + 1); dummynet_set_direction(dn, DUMMYNET_BACKWARD, 50, 20, 0, 100, 0, "127.0.0.1", LISTEN_PORT - 1); printf("Configuration:\n"); printf(" Listen port: %d\n", LISTEN_PORT); printf(" Delay: 50ms + 0-20ms\n"); printf(" Bandwidth: unlimited\n"); printf(" Queue size: 100 packets\n"); printf(" Loss: 0%%\n\n"); /* Запускаем uasync в отдельном потоке */ pthread_t thread; pthread_create(&thread, NULL, uasync_thread, ua); /* Отправляем пакеты */ printf("Sending %d packets A->B and B->A...\n", PKT_COUNT); uint8_t buf[sizeof(struct test_header) + 100]; struct test_header* hdr = (struct test_header*)buf; for (int i = 0; i < PKT_COUNT; i++) { /* A -> B */ hdr->seq_num = i; hdr->send_time_us = get_time_us(); struct sockaddr_in dest; memset(&dest, 0, sizeof(dest)); dest.sin_family = AF_INET; dest.sin_addr.s_addr = inet_addr("127.0.0.1"); dest.sin_port = htons(LISTEN_PORT); socket_sendto(sock_a, buf, sizeof(buf), (struct sockaddr*)&dest, sizeof(dest)); /* B -> A */ hdr->seq_num = i + 1000; hdr->send_time_us = get_time_us(); socket_sendto(sock_b, buf, sizeof(buf), (struct sockaddr*)&dest, sizeof(dest)); usleep(1000); /* 1ms между пакетами */ } printf("Waiting for packets...\n"); /* Ждём завершения потока uasync */ pthread_join(thread, NULL); /* Получаем статистику */ const struct dummynet_stats* stats_fw = dummynet_get_stats(dn, DUMMYNET_FORWARD); const struct dummynet_stats* stats_bw = dummynet_get_stats(dn, DUMMYNET_BACKWARD); printf("\nResults:\n"); printf(" Forward (A->B): recv=%llu, sent=%llu, dropped=%llu\n", stats_fw->recv, stats_fw->sent, stats_fw->dropped); printf(" Backward (B->A): recv=%llu, sent=%llu, dropped=%llu\n", stats_bw->recv, stats_bw->sent, stats_bw->dropped); /* Проверяем результаты */ int passed = 1; if (stats_fw->recv < PKT_COUNT * 0.9 || stats_bw->recv < PKT_COUNT * 0.9) { printf("\n[FAIL] Expected >90%% packets received\n"); printf(" Forward: %llu/%d, Backward: %llu/%d\n", stats_fw->recv, PKT_COUNT, stats_bw->recv, PKT_COUNT); passed = 0; tests_failed++; } else { printf("\n[PASS] >90%% packets received successfully\n"); tests_passed++; } /* Очистка */ dummynet_destroy(dn); socket_close_wrapper(sock_a); socket_close_wrapper(sock_b); uasync_destroy(ua, 1); socket_platform_cleanup(); printf("\n========================================\n"); printf("Results: %d passed, %d failed\n", tests_passed, tests_failed); printf("========================================\n"); return tests_failed > 0 ? 1 : 0; }