tests: hold OS-assigned HTTP and SOCKS listener ports

This commit is contained in:
evgeny committed 2026-10-10 16:04:19 +02:00
1 parent 08865b2909
commit 4e2cc0e35a
4 files changed
+53 -51

No files matched your search

+32 -39
View File
@@ -20,6 +20,9 @@
#include <time.h>
#include "../lib/platform_compat.h"
#include "test_utils.h"
#include "test_net.h"
#include "../src/proxy/socks_proxy.h"
#include "../src/proxy/tcp_proxy_client.h"
#include "../lib/u_async.h"
#include "../lib/debug_config.h"
#include "../lib/ll_queue.h"
@@ -58,18 +61,6 @@ static char g_cert[512], g_key[512];
static void* g_mon_id = NULL;
static int g_file_seed = 0;
static int alloc_port(void) {
int s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) return -1;
struct sockaddr_in a; memset(&a, 0, sizeof(a));
a.sin_family = AF_INET; a.sin_addr.s_addr = inet_addr("127.0.0.1");
for (int i = 0; i < 200; i++) {
a.sin_port = htons((uint16_t)(20000 + (rand() % 40000)));
if (bind(s, (struct sockaddr*)&a, sizeof(a)) == 0) { close(s); return ntohs(a.sin_port); }
}
close(s); return -1;
}
static void gen_file(const char* path, int size, int seed) {
FILE* f = fopen(path, "wb");
if (!f) { fprintf(stderr, "gen_file: fopen(%s) failed\n", path); return; }
@@ -83,7 +74,7 @@ static void gen_file(const char* path, int size, int seed) {
}
// Сервер сообщает готовность после listen и настройки TLS; EOF обнаруживает ошибку запуска без паузы.
static int wait_server_ready(int fd, int port, const char* name) {
static int wait_server_ready(int fd, int* port, const char* name) {
uint64_t start = get_time_us(), deadline = start + 5000000;
struct pollfd pfd = {.fd = fd, .events = POLLIN};
int result;
@@ -91,21 +82,23 @@ static int wait_server_ready(int fd, int port, const char* name) {
uint64_t now = get_time_us();
result = poll(&pfd, 1, now < deadline ? (int)((deadline - now + 999) / 1000) : 0);
} while (result < 0 && errno == EINTR);
char marker = 0;
ssize_t bytes = result > 0 ? read(fd, &marker, 1) : -1;
uint8_t assigned[2] = {0};
ssize_t bytes = result > 0 ? read(fd, assigned, sizeof(assigned)) : -1;
int error = result < 0 || (result > 0 && bytes < 0) ? errno : 0;
close(fd);
if (result <= 0 || bytes != 1 || marker != 'R') {
DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test %s server startup failed: port=%d poll=%d events=%x bytes=%ld marker=%d errno=%d",
name, port, result, pfd.revents, (long)bytes, marker, error);
int actual = ((int)assigned[0] << 8) | assigned[1];
if (result <= 0 || bytes != sizeof(assigned) || !actual) {
DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test %s server startup failed: poll=%d events=%x bytes=%ld port=%d errno=%d",
name, result, pfd.revents, (long)bytes, actual, error);
return -1;
}
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "test %s server ready: port=%d elapsed=%lluus", name, port,
*port = actual;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "test %s server ready: port=%d elapsed=%lluus", name, *port,
(unsigned long long)(get_time_us() - start));
return 0;
}
static int start_http_server(int port, const char* dir) {
static int start_http_server(int* port, const char* dir) {
char script[512]; snprintf(script, sizeof(script), "%s/_srv.py", dir);
FILE* sf = fopen(script, "w");
if (!sf) return -1;
@@ -130,7 +123,7 @@ static int start_http_server(int port, const char* dir) {
"port=int(sys.argv[1])\n"
"os.chdir(sys.argv[2])\n"
"httpd=HTTPServer(('127.0.0.1',port),H)\n"
"ready=int(sys.argv[3]);os.write(ready,b'R');os.close(ready)\n"
"ready=int(sys.argv[3]);os.write(ready,httpd.server_port.to_bytes(2,'big'));os.close(ready)\n"
"httpd.serve_forever()\n"
);
fclose(sf);
@@ -144,9 +137,8 @@ static int start_http_server(int port, const char* dir) {
}
if (pid == 0) {
close(ready[0]);
char port_str[16], ready_str[16];
snprintf(port_str, sizeof(port_str), "%d", port); snprintf(ready_str, sizeof(ready_str), "%d", ready[1]);
execlp("python3", "python3", script, port_str, dir, ready_str, (char*)NULL);
char ready_str[16]; snprintf(ready_str, sizeof(ready_str), "%d", ready[1]);
execlp("python3", "python3", script, "0", dir, ready_str, (char*)NULL);
DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test HTTP python exec: %s", strerror(errno));
_exit(1);
}
@@ -155,7 +147,7 @@ static int start_http_server(int port, const char* dir) {
return wait_server_ready(ready[0], port, "HTTP");
}
static int start_https_server(int port, const char* dir, const char* cert, const char* key) {
static int start_https_server(int* port, const char* dir, const char* cert, const char* key) {
char script[512]; snprintf(script, sizeof(script), "%s/_srv_https.py", dir);
FILE* sf = fopen(script, "w");
if (!sf) return -1;
@@ -187,7 +179,7 @@ static int start_https_server(int port, const char* dir, const char* cert, const
"httpd=HTTPServer(('127.0.0.1',int(sys.argv[4])),H)\n"
"httpd.socket=ctx.wrap_socket(httpd.socket,server_side=True)\n"
"httpd.timeout=None\n"
"ready=int(sys.argv[5]);os.write(ready,b'R');os.close(ready)\n"
"ready=int(sys.argv[5]);os.write(ready,httpd.server_port.to_bytes(2,'big'));os.close(ready)\n"
"httpd.serve_forever()\n"
);
fclose(sf);
@@ -201,9 +193,8 @@ static int start_https_server(int port, const char* dir, const char* cert, const
}
if (pid == 0) {
close(ready[0]);
char port_str[16], ready_str[16];
snprintf(port_str, sizeof(port_str), "%d", port); snprintf(ready_str, sizeof(ready_str), "%d", ready[1]);
execlp("python3", "python3", script, cert, key, dir, port_str, ready_str, (char*)NULL);
char ready_str[16]; snprintf(ready_str, sizeof(ready_str), "%d", ready[1]);
execlp("python3", "python3", script, cert, key, dir, "0", ready_str, (char*)NULL);
DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test HTTPS python exec: %s", strerror(errno));
_exit(1);
}
@@ -487,14 +478,6 @@ int main(void) {
utun_instance_set_tun_init_enabled(0);
srand((unsigned)time(NULL));
g_http_port = alloc_port(); g_https_port = alloc_port();
g_cli_port = alloc_port(); g_srv_port = alloc_port();
g_socks_port = alloc_port(); g_http_proxy_port = alloc_port();
if (g_http_port < 0 || g_https_port < 0 || g_cli_port < 0 || g_srv_port < 0 || g_socks_port < 0 || g_http_proxy_port < 0) {
printf("[FAIL] port allocation\n"); return 1;
}
printf(" ports: http=%d https=%d socks=%d http_proxy=%d\n", g_http_port, g_https_port, g_socks_port, g_http_proxy_port);
strcpy(g_tmpdir, "/tmp/utun_test_XXXXXX");
if (test_mkdtemp(g_tmpdir) < 0) { printf("[FAIL] mkdtemp: %s\n", strerror(errno)); return 1; }
@@ -509,8 +492,8 @@ int main(void) {
}
printf(" test files: 1KB, 100KB, 1MB, 10MB (total %.1fMB)\n", total_mb / (1024.0*1024.0)); fflush(stdout);
if (start_http_server(g_http_port, g_tmpdir) < 0) { printf("[FAIL] start http server\n"); goto cleanup; }
if (start_https_server(g_https_port, g_tmpdir, g_cert, g_key) < 0) { printf("[FAIL] start https server\n"); goto cleanup; }
if (start_http_server(&g_http_port, g_tmpdir) < 0) { printf("[FAIL] start http server\n"); goto cleanup; }
if (start_https_server(&g_https_port, g_tmpdir, g_cert, g_key) < 0) { printf("[FAIL] start https server\n"); goto cleanup; }
printf(" HTTP/HTTPS servers started\n");
g_ua = uasync_create();
@@ -519,6 +502,16 @@ int main(void) {
g_srv = utun_instance_create_from_str(g_ua, make_cfg_server());
g_cli = utun_instance_create_from_str(g_ua, make_cfg_client());
if (!g_srv || !g_cli) { printf("[FAIL] instance create\n"); goto cleanup; }
test_etcp_set_peer(g_cli, "c1", g_srv, "s1");
g_srv_port = ss_get_port(&test_etcp_bound_socket(g_srv, "s1")->local_addr);
g_cli_port = ss_get_port(&test_etcp_bound_socket(g_cli, "s1")->local_addr);
struct tcp_proxy_client* proxy = g_cli->tcp_proxy_client;
if (!proxy) { DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test: proxy client missing"); goto cleanup; }
g_socks_port = socks_proxy_get_port(proxy->socks_listen);
g_http_proxy_port = socks_proxy_get_port(proxy->http_listen);
if (!g_socks_port || !g_http_proxy_port) { DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test: proxy listeners missing"); goto cleanup; }
printf(" ports: http=%d https=%d socks=%d http_proxy=%d udp_client=%d udp_server=%d\n",
g_http_port, g_https_port, g_socks_port, g_http_proxy_port, g_cli_port, g_srv_port);
if (utun_instance_init(g_srv) < 0 || utun_instance_init(g_cli) < 0) { printf("[FAIL] instance init\n"); goto cleanup; }
printf(" waiting for ETCP...\n"); fflush(stdout);