Files
utun2/tests/test_tcp_proxy_server.c
T
jeka 7139969acd fix: Windows/MSYS2 build compatibility
- proxy/icmp_proxy.c: define struct icmp/ip + ICMP constants for _WIN32
- lwip_tcp_priv.h: use #include <winsock2.h> instead of #define htonl/htons
- lwip_tcp.h/c: rename poll field to pollfn (avoid WSAPoll macro conflict)
- tests: guard Unix-only headers with #ifndef _WIN32, skip fork/socketpair tests
2026-07-05 20:57:44 +03:00

136 lines
4.4 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>
#ifndef _WIN32
#include <unistd.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#endif
#include "../lib/platform_compat.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;
#ifndef _WIN32
static pid_t echo_pid = 0;
#endif
static uint8_t send_buf[PAYLOAD_SIZE];
static void* timeout_id = NULL;
#ifndef _WIN32
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);
}
#endif
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);
#ifdef _WIN32
printf("[SKIP] test_tcp_proxy_server — fork() not available on Windows\n");
return 0;
#else
echo_pid = fork();
if (echo_pid == 0) { echo_server(); _exit(0); }
usleep(50000); // даём серверу запуститься
#endif
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);
#ifndef _WIN32
kill(echo_pid, SIGKILL);
waitpid(echo_pid, NULL, 0);
#endif
return g_ok ? 0 : 1;
}