Files
utun2/tests/test_tcp_proxy_server.c
T
Evgeny 0dd942be63 fix: стабилизация тестов test_tcp_io и test_bbr_integration
- test_bbr_integration: bbr_max_cwnd=100KB (16×BDP) — устранён overshoot очереди
- test_tcp_io: адаптирован под EPOLLHUP на socketpair (send до poll, error_cb вместо fin)
- tcp_io: расширенная диагностика error_cb с состоянием сокета
2026-06-11 13:16:48 +03:00

122 lines
4.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// test_tcp_proxy_server.c — Test tcp_conn с реальным TCP соединением (echo сервер)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include "../lib/tcp_io.h"
#include "../lib/u_async.h"
#include "../lib/ll_queue.h"
#include "../lib/debug_config.h"
#include "../lib/mem.h"
#define ECHO_PORT 19991
#define TIMEOUT_MS 8000
#define PAYLOAD_SIZE 64
static int g_ok = 0, g_done = 0;
static pid_t echo_pid = 0;
static uint8_t send_buf[PAYLOAD_SIZE];
static void* timeout_id = NULL;
static void echo_server(void) {
int srv = socket(AF_INET, SOCK_STREAM, 0);
if (srv < 0) _exit(1);
int opt = 1; setsockopt(srv, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in a = {.sin_family = AF_INET, .sin_port = htons(ECHO_PORT), .sin_addr.s_addr = inet_addr("127.0.0.1")};
if (bind(srv, (struct sockaddr*)&a, sizeof(a)) < 0 || listen(srv, 1) < 0) { close(srv); _exit(1); }
int cli = accept(srv, NULL, NULL);
if (cli < 0) { close(srv); _exit(1); }
uint8_t buf[8192]; ssize_t n;
while ((n = recv(cli, buf, sizeof(buf), 0)) > 0) {
ssize_t s = 0;
while (s < n) { ssize_t r = send(cli, buf + s, n - s, 0); if (r < 0) goto done; s += r; }
}
done: close(cli); close(srv);
}
static void on_fin_cb(struct tcp_conn* tc, void* arg) { (void)tc; (void)arg; }
static void on_error_cb(struct tcp_conn* tc, int err, void* arg) { (void)tc; (void)arg; (void)err; }
static int push_write(struct tcp_conn* tc, const uint8_t* data, size_t len) {
struct ll_entry* e = queue_entry_new_from_pool(tc->entry_pool);
uint8_t* buf = memory_pool_alloc(tc->data_pool);
if (!e || !buf) { if (e) queue_entry_free(e); if (buf) memory_pool_free(tc->data_pool, buf); return -1; }
memcpy(buf, data, len);
e->dgram = buf; e->len = (uint16_t)len;
queue_data_put(tc->write_queue, e);
return 0;
}
static void timeout_cb(void* arg) {
(void)arg;
printf("[FAIL] timeout\n");
g_done = -1;
}
int main(void) {
debug_config_init();
debug_set_level(DEBUG_LEVEL_WARN);
echo_pid = fork();
if (echo_pid == 0) { echo_server(); _exit(0); }
usleep(50000); // даём серверу запуститься
struct UASYNC* ua = uasync_create();
if (!ua) return 1;
timeout_id = uasync_set_timeout(ua, TIMEOUT_MS * 10, NULL, timeout_cb, "timeout");
socket_t sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == SOCKET_INVALID) return 1;
socket_set_nonblocking(sock);
struct tcp_conn* tc = tcp_conn_create(ua, sock, 1500, 8192, 32, 8, 0, on_fin_cb, on_error_cb, NULL);
if (!tc) return 1;
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(ECHO_PORT);
int ret = connect(sock, (struct sockaddr*)&addr, sizeof(addr));
if (ret < 0 && errno != EINPROGRESS) { printf("[FAIL] connect: %s\n", strerror(errno)); g_done = -1; }
int phase = 0;
while (!g_done) {
uasync_poll(ua, 10);
if (phase == 0 && tc->connected) {
phase = 1;
for (int i = 0; i < PAYLOAD_SIZE; i++) send_buf[i] = (uint8_t)(rand() & 0xFF);
push_write(tc, send_buf, PAYLOAD_SIZE);
}
if (phase == 1 && !tc->error) {
struct ll_entry* e = queue_data_get(tc->read_queue);
if (e) {
if (e->len == (uint16_t)PAYLOAD_SIZE && memcmp(send_buf, e->dgram, e->len) == 0) {
printf("[PASS] test_tcp_proxy_server — %u bytes echoed via tcp_conn\n", e->len); g_ok = 1;
} else {
printf("[FAIL] echo mismatch: got %u expected %d\n", e->len, PAYLOAD_SIZE);
}
memory_pool_free(tc->data_pool, e->dgram);
queue_entry_free(e);
queue_resume_callback(tc->read_queue);
g_done = 1;
}
}
}
tcp_conn_destroy(tc);
uasync_destroy(ua, 0);
kill(echo_pid, SIGKILL);
waitpid(echo_pid, NULL, 0);
return g_ok ? 0 : 1;
}