From aec9536522e1e629c6c5f60ecc7baa3fb38df961 Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 10 Oct 2026 15:10:09 +0200 Subject: [PATCH] tests: await proxy server readiness and retain worker failures --- tests/test_socks_http_proxy.c | 79 ++++++++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 14 deletions(-) diff --git a/tests/test_socks_http_proxy.c b/tests/test_socks_http_proxy.c index ac9235f8..85cf8b36 100644 --- a/tests/test_socks_http_proxy.c +++ b/tests/test_socks_http_proxy.c @@ -13,6 +13,7 @@ #include #include #include +#include #endif #include #include @@ -46,6 +47,7 @@ static struct UTUN_INSTANCE* g_cli = NULL; static struct UTUN_INSTANCE* g_srv = NULL; static struct UASYNC* g_ua = NULL; static int g_ok = 0, g_done = 0, g_phase = 0; +static int g_worker_failures; static pid_t g_http_pid = 0, g_https_pid = 0; static pid_t g_workers[WORKERS]; static pid_t g_workers_orig[WORKERS]; @@ -80,6 +82,29 @@ static void gen_file(const char* path, int size, int seed) { fclose(f); } +// Сервер сообщает готовность после listen и настройки TLS; EOF обнаруживает ошибку запуска без паузы. +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; + do { + 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; + 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); + return -1; + } + 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) { char script[512]; snprintf(script, sizeof(script), "%s/_srv.py", dir); FILE* sf = fopen(script, "w"); @@ -104,20 +129,30 @@ static int start_http_server(int port, const char* dir) { " self.end_headers()\n" "port=int(sys.argv[1])\n" "os.chdir(sys.argv[2])\n" - "HTTPServer(('127.0.0.1',port),H).serve_forever()\n" + "httpd=HTTPServer(('127.0.0.1',port),H)\n" + "ready=int(sys.argv[3]);os.write(ready,b'R');os.close(ready)\n" + "httpd.serve_forever()\n" ); fclose(sf); + int ready[2]; + if (pipe(ready) < 0) { DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test HTTP ready pipe: %s", strerror(errno)); return -1; } pid_t pid = fork(); - if (pid < 0) return -1; + if (pid < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test HTTP server fork: %s", strerror(errno)); + close(ready[0]); close(ready[1]); return -1; + } if (pid == 0) { - char port_str[16]; snprintf(port_str, sizeof(port_str), "%d", port); - execlp("python3", "python3", script, port_str, dir, (char*)NULL); + 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); + DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test HTTP python exec: %s", strerror(errno)); _exit(1); } + close(ready[1]); g_http_pid = pid; - usleep(300000); - return 0; + return wait_server_ready(ready[0], port, "HTTP"); } static int start_https_server(int port, const char* dir, const char* cert, const char* key) { @@ -152,20 +187,29 @@ 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" "httpd.serve_forever()\n" ); fclose(sf); + int ready[2]; + if (pipe(ready) < 0) { DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test HTTPS ready pipe: %s", strerror(errno)); return -1; } pid_t pid = fork(); - if (pid < 0) return -1; + if (pid < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test HTTPS server fork: %s", strerror(errno)); + close(ready[0]); close(ready[1]); return -1; + } if (pid == 0) { - char port_str[16]; snprintf(port_str, sizeof(port_str), "%d", port); - execlp("python3", "python3", script, cert, key, dir, port_str, (char*)NULL); + 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); + DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test HTTPS python exec: %s", strerror(errno)); _exit(1); } + close(ready[1]); g_https_pid = pid; - usleep(300000); - return 0; + return wait_server_ready(ready[0], port, "HTTPS"); } static int gen_self_signed_cert(const char* tmpdir, char* cert_out, size_t cert_sz, char* key_out, size_t key_sz) { @@ -329,6 +373,7 @@ static int worker_main(int wtype, const char* socks_proxy, const char* http_prox static void monitor(void* arg) { (void)arg; + g_mon_id = NULL; if (g_done) return; if (g_phase == 0) { @@ -373,16 +418,21 @@ static void monitor(void* arg) { } if (g_phase == 1) { - int done_count = 0, fail = 0; + int done_count = 0; for (int i = 0; i < WORKERS; i++) { if (g_workers[i] <= 0) { done_count++; continue; } int status; pid_t r = waitpid(g_workers[i], &status, WNOHANG); if (r == 0) continue; + if (r < 0 && errno == EINTR) continue; + if (r < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) { + DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test worker=%d pid=%d failed: waitpid=%d status=%d errno=%d", + i, (int)g_workers[i], (int)r, r > 0 ? status : -1, r < 0 ? errno : 0); + g_worker_failures++; + } g_workers[i] = 0; done_count++; - if (WIFEXITED(status) && WEXITSTATUS(status) != 0) fail++; } if (done_count >= WORKERS) { - if (fail) { printf("[FAIL] %d/%d workers failed\n", fail, WORKERS); g_done = -1; } + if (g_worker_failures) { printf("[FAIL] %d/%d workers failed\n", g_worker_failures, WORKERS); g_done = -1; } else { g_ok = 1; g_done = 1; } printf("\n=== PROFILING ===\n"); @@ -433,6 +483,7 @@ int main(void) { { int fd = open("/dev/null", O_RDONLY); if (fd > 0 && fd != 0) { dup2(fd, 0); close(fd); } else if (fd < 0) { close(0); open("/dev/null", O_RDONLY); } } debug_config_init(); debug_set_level(DEBUG_LEVEL_ERROR); debug_set_categories(DEBUG_CATEGORY_ALL); + debug_set_category_level(DEBUG_CATEGORY_DEBUG, DEBUG_LEVEL_INFO); utun_instance_set_tun_init_enabled(0); srand((unsigned)time(NULL));