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.
 
 
 
 
 
 

198 lines
6.1 KiB

#include <inttypes.h>
/**
* @file test_dummynet_simple.c
* @brief Упрощённый тест модуля dummynet
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
#include <pthread.h>
#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;
}