|
|
|
|
@ -1,5 +1,7 @@
|
|
|
|
|
// test_socks_http_proxy.c — SOCKS5 + HTTP CONNECT proxy integration test
|
|
|
|
|
// 2 workers (1 SOCKS + 1 HTTP), 25 reqs each, files up to 100KB
|
|
|
|
|
// test_socks_http_proxy.c — Comprehensive SOCKS5 + HTTP proxy integration test
|
|
|
|
|
// 4 workers: socks_ipv4, socks_domain, http_proxy, https_connect
|
|
|
|
|
// Files: 1KB, 100KB, 1MB, 10MB — deterministic content, byte-by-byte verification
|
|
|
|
|
// HTTP + HTTPS (self-signed cert) + POST/echo + HEAD + OPTIONS
|
|
|
|
|
#include <stdio.h> |
|
|
|
|
#include <stdlib.h> |
|
|
|
|
#include <string.h> |
|
|
|
|
@ -28,25 +30,27 @@
|
|
|
|
|
#include "../src/routing.h" |
|
|
|
|
#include "../src/tun_if.h" |
|
|
|
|
|
|
|
|
|
#define TIMEOUT_MS 120000 |
|
|
|
|
#define WORKERS 3 |
|
|
|
|
#define REQS_PER_WORKER 25 |
|
|
|
|
#define TIMEOUT_MS 300000 |
|
|
|
|
#define WORKERS 4 |
|
|
|
|
|
|
|
|
|
static const int file_sizes[] = { 1024, 10*1024, 50*1024, 100*1024 }; |
|
|
|
|
static const int file_counts[] = { 8, 7, 5, 5 }; // sum = 25
|
|
|
|
|
static const char* file_names[] = { "f_1k.bin", "f_10k.bin", "f_50k.bin", "f_100k.bin" }; |
|
|
|
|
enum { W_SOCKS_IPV4, W_SOCKS_DOMAIN, W_HTTP_PROXY, W_HTTPS_CONNECT }; |
|
|
|
|
|
|
|
|
|
static const int file_sizes[] = { 1024, 100*1024, 1024*1024, 10*1024*1024 }; |
|
|
|
|
static const char* file_names[] = { "f_1k.bin", "f_100k.bin", "f_1m.bin", "f_10m.bin" }; |
|
|
|
|
static const int num_files = 4; |
|
|
|
|
|
|
|
|
|
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 pid_t g_http_pid = 0; |
|
|
|
|
static pid_t g_http_pid = 0, g_https_pid = 0; |
|
|
|
|
static pid_t g_workers[WORKERS]; |
|
|
|
|
static int g_http_port = 0, g_cli_port = 0, g_srv_port = 0; |
|
|
|
|
static int g_http_port = 0, g_https_port = 0, g_cli_port = 0, g_srv_port = 0; |
|
|
|
|
static int g_socks_port = 0, g_http_proxy_port = 0; |
|
|
|
|
static char g_tmpdir[256]; |
|
|
|
|
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); |
|
|
|
|
@ -62,8 +66,13 @@ static int alloc_port(void) {
|
|
|
|
|
|
|
|
|
|
static void gen_file(const char* path, int size, int seed) { |
|
|
|
|
FILE* f = fopen(path, "wb"); |
|
|
|
|
if (!f) return; |
|
|
|
|
for (int i = 0; i < size; i++) { uint8_t b = (uint8_t)((i ^ seed) & 0xFF); fwrite(&b, 1, 1, f); } |
|
|
|
|
if (!f) { fprintf(stderr, "gen_file: fopen(%s) failed\n", path); return; } |
|
|
|
|
uint8_t buf[4096]; |
|
|
|
|
for (int off = 0; off < size; off += (int)sizeof(buf)) { |
|
|
|
|
int chunk = size - off; if (chunk > (int)sizeof(buf)) chunk = (int)sizeof(buf); |
|
|
|
|
for (int i = 0; i < chunk; i++) buf[i] = (uint8_t)(((off + i) ^ seed) & 0xFF); |
|
|
|
|
fwrite(buf, 1, (size_t)chunk, f); |
|
|
|
|
} |
|
|
|
|
fclose(f); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -72,7 +81,7 @@ static int start_http_server(int port, const char* dir) {
|
|
|
|
|
FILE* sf = fopen(script, "w"); |
|
|
|
|
if (!sf) return -1; |
|
|
|
|
fprintf(sf, |
|
|
|
|
"import sys,os\n" |
|
|
|
|
"import sys,os,ssl,threading\n" |
|
|
|
|
"from http.server import HTTPServer,SimpleHTTPRequestHandler\n" |
|
|
|
|
"class H(SimpleHTTPRequestHandler):\n" |
|
|
|
|
" def do_POST(self):\n" |
|
|
|
|
@ -91,7 +100,7 @@ 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(('',port),H).serve_forever()\n" |
|
|
|
|
"HTTPServer(('127.0.0.1',port),H).serve_forever()\n" |
|
|
|
|
); |
|
|
|
|
fclose(sf); |
|
|
|
|
|
|
|
|
|
@ -107,6 +116,66 @@ static int start_http_server(int port, const char* dir) {
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
fprintf(sf, |
|
|
|
|
"import sys,os,ssl,threading,traceback\n" |
|
|
|
|
"from http.server import HTTPServer,SimpleHTTPRequestHandler\n" |
|
|
|
|
"class H(SimpleHTTPRequestHandler):\n" |
|
|
|
|
" def do_GET(self):\n" |
|
|
|
|
" try:\n super().do_GET()\n" |
|
|
|
|
" except Exception as e:\n" |
|
|
|
|
" sys.stderr.write(f'HTTPS_ERR GET {self.path}: {e}\\n{traceback.format_exc()}\\n')\n" |
|
|
|
|
" def do_POST(self):\n" |
|
|
|
|
" if self.path=='/echo':\n" |
|
|
|
|
" n=int(self.headers.get('Content-Length',0))\n" |
|
|
|
|
" b=self.rfile.read(n)\n" |
|
|
|
|
" self.send_response(200)\n" |
|
|
|
|
" self.send_header('Content-Type','application/octet-stream')\n" |
|
|
|
|
" self.send_header('Content-Length',str(len(b)))\n" |
|
|
|
|
" self.end_headers();self.wfile.write(b)\n" |
|
|
|
|
" else:self.send_response(405);self.end_headers()\n" |
|
|
|
|
" def do_OPTIONS(self):\n" |
|
|
|
|
" self.send_response(200)\n" |
|
|
|
|
" self.send_header('Allow','GET,HEAD,POST,OPTIONS')\n" |
|
|
|
|
" self.send_header('Content-Length','0')\n" |
|
|
|
|
" self.end_headers()\n" |
|
|
|
|
"os.chdir(sys.argv[3])\n" |
|
|
|
|
"ctx=ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)\n" |
|
|
|
|
"ctx.load_cert_chain(sys.argv[1],sys.argv[2])\n" |
|
|
|
|
"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" |
|
|
|
|
"httpd.serve_forever()\n" |
|
|
|
|
); |
|
|
|
|
fclose(sf); |
|
|
|
|
|
|
|
|
|
pid_t pid = fork(); |
|
|
|
|
if (pid < 0) 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); |
|
|
|
|
_exit(1); |
|
|
|
|
} |
|
|
|
|
g_https_pid = pid; |
|
|
|
|
usleep(300000); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int gen_self_signed_cert(const char* tmpdir, char* cert_out, size_t cert_sz, char* key_out, size_t key_sz) { |
|
|
|
|
snprintf(cert_out, cert_sz, "%s/cert.pem", tmpdir); |
|
|
|
|
snprintf(key_out, key_sz, "%s/key.pem", tmpdir); |
|
|
|
|
char cmd[512]; |
|
|
|
|
snprintf(cmd, sizeof(cmd), |
|
|
|
|
"openssl req -x509 -newkey rsa:2048 -keyout %s -out %s -days 1 -nodes -subj '/CN=127.0.0.1' 2>/dev/null", |
|
|
|
|
key_out, cert_out); |
|
|
|
|
int rc = system(cmd); |
|
|
|
|
if (rc != 0) { fprintf(stderr, "[FAIL] openssl cert generation\n"); return -1; } |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static char* make_cfg_server(void) { |
|
|
|
|
static char buf[1024]; |
|
|
|
|
snprintf(buf, sizeof(buf), |
|
|
|
|
@ -149,64 +218,84 @@ static int conn_ready(struct UTUN_INSTANCE* inst) {
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int worker_main(const char* type, const char* proxy, const char* url_base, const char* tmpdir) { |
|
|
|
|
static int worker_main(int wtype, const char* socks_proxy, const char* http_proxy, |
|
|
|
|
const char* url_http, const char* url_https, const char* tmpdir) { |
|
|
|
|
const char* type_names[] = { "socks_ipv4", "socks_domain", "http_proxy", "https_connect" }; |
|
|
|
|
const char* tname = type_names[wtype]; |
|
|
|
|
|
|
|
|
|
for (int fi = 0; fi < num_files; fi++) { |
|
|
|
|
int count = file_counts[fi]; |
|
|
|
|
char expected[512]; |
|
|
|
|
char expected[512], out[512], url[512], cmd[2048]; |
|
|
|
|
snprintf(expected, sizeof(expected), "%s/%s", tmpdir, file_names[fi]); |
|
|
|
|
snprintf(out, sizeof(out), "%s/out_%d_%d_%s", tmpdir, getpid(), fi, file_names[fi]); |
|
|
|
|
|
|
|
|
|
const char* base = (wtype == W_HTTPS_CONNECT) ? url_https : url_http; |
|
|
|
|
snprintf(url, sizeof(url), "%s/%s", base, file_names[fi]); |
|
|
|
|
|
|
|
|
|
switch (wtype) { |
|
|
|
|
case W_SOCKS_IPV4: |
|
|
|
|
snprintf(cmd, sizeof(cmd), "curl -s --connect-timeout 15 --max-time 60 --socks5 %s -o %s %s 2>/dev/null", |
|
|
|
|
socks_proxy, out, url); |
|
|
|
|
break; |
|
|
|
|
case W_SOCKS_DOMAIN: |
|
|
|
|
snprintf(cmd, sizeof(cmd), "curl -s --connect-timeout 15 --max-time 60 --socks5-hostname %s -o %s %s 2>/dev/null", |
|
|
|
|
socks_proxy, out, url); |
|
|
|
|
break; |
|
|
|
|
case W_HTTP_PROXY: |
|
|
|
|
snprintf(cmd, sizeof(cmd), "curl -s --connect-timeout 15 --max-time 60 -x http://%s -o %s %s 2>/dev/null", |
|
|
|
|
http_proxy, out, url); |
|
|
|
|
break; |
|
|
|
|
case W_HTTPS_CONNECT: |
|
|
|
|
snprintf(cmd, sizeof(cmd), "curl -s --connect-timeout 15 --max-time 60 --proxytunnel -x %s -k -o %s %s 2>/dev/null", |
|
|
|
|
http_proxy, out, url); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (int i = 0; i < count; i++) { |
|
|
|
|
char cmd[1024], out[512], url[512]; |
|
|
|
|
snprintf(out, sizeof(out), "%s/out_%d_%s_%d.bin", tmpdir, (int)getpid(), file_names[fi], i); |
|
|
|
|
snprintf(url, sizeof(url), "%s/%s", url_base, file_names[fi]); |
|
|
|
|
if (strcmp(type, "socks") == 0) |
|
|
|
|
snprintf(cmd, sizeof(cmd), "curl -s --connect-timeout 10 --max-time 30 --socks5-hostname %s -o %s %s 2>/dev/null", proxy, out, url); |
|
|
|
|
else if (strcmp(type, "http_connect") == 0) |
|
|
|
|
snprintf(cmd, sizeof(cmd), "curl -s --connect-timeout 10 --max-time 30 --proxytunnel -x %s -o %s %s 2>/dev/null", proxy, out, url); |
|
|
|
|
else |
|
|
|
|
snprintf(cmd, sizeof(cmd), "curl -s --connect-timeout 10 --max-time 30 -x %s -o %s %s 2>/dev/null", proxy, out, url); |
|
|
|
|
|
|
|
|
|
int rc = system(cmd); |
|
|
|
|
if (rc != 0) { fprintf(stderr, "[FAIL] worker %s %s iter %d curl exit %d\n", type, file_names[fi], i, WEXITSTATUS(rc)); return 1; } |
|
|
|
|
|
|
|
|
|
char cmp_cmd[1024]; |
|
|
|
|
snprintf(cmp_cmd, sizeof(cmp_cmd), "cmp -s %s %s", out, expected); |
|
|
|
|
if (system(cmp_cmd) != 0) { fprintf(stderr, "[FAIL] worker %s %s iter %d mismatch\n", type, file_names[fi], i); return 1; } |
|
|
|
|
unlink(out); |
|
|
|
|
int rc = system(cmd); |
|
|
|
|
if (rc != 0) { fprintf(stderr, "[FAIL] %s %s curl exit=%d\n", tname, file_names[fi], WEXITSTATUS(rc)); return 1; } |
|
|
|
|
|
|
|
|
|
char cmp_cmd[1024]; |
|
|
|
|
snprintf(cmp_cmd, sizeof(cmp_cmd), "cmp -s %s %s", out, expected); |
|
|
|
|
if (system(cmp_cmd) != 0) { |
|
|
|
|
fprintf(stderr, "[FAIL] %s %s byte mismatch\n", tname, file_names[fi]); |
|
|
|
|
|
|
|
|
|
char sizecmd[1024]; snprintf(sizecmd, sizeof(sizecmd), "wc -c <%s", out); |
|
|
|
|
FILE* pf = popen(sizecmd, "r"); if (pf) { int sz = 0; fscanf(pf, "%d", &sz); pclose(pf); |
|
|
|
|
fprintf(stderr, " downloaded: %d bytes, expected: %d bytes\n", sz, file_sizes[fi]); } |
|
|
|
|
unlink(out); return 1; |
|
|
|
|
} |
|
|
|
|
unlink(out); |
|
|
|
|
} |
|
|
|
|
if (strcmp(type, "http_proxy") == 0) { |
|
|
|
|
char cmd[1024], out[512], f1[512]; |
|
|
|
|
|
|
|
|
|
if (wtype == W_HTTP_PROXY) { |
|
|
|
|
char cmd[2048], out[512], f1[512]; |
|
|
|
|
int seed = (int)getpid() ^ 0x55; |
|
|
|
|
|
|
|
|
|
// POST /echo — echo body back, compare
|
|
|
|
|
snprintf(f1, sizeof(f1), "%s/post_%d.bin", tmpdir, (int)getpid()); |
|
|
|
|
gen_file(f1, 512, seed); |
|
|
|
|
snprintf(out, sizeof(out), "%s/post_out_%d.bin", tmpdir, (int)getpid()); |
|
|
|
|
snprintf(f1, sizeof(f1), "%s/post_%d.bin", tmpdir, getpid()); |
|
|
|
|
gen_file(f1, 256, seed); |
|
|
|
|
snprintf(out, sizeof(out), "%s/post_out_%d.bin", tmpdir, getpid()); |
|
|
|
|
snprintf(cmd, sizeof(cmd), |
|
|
|
|
"curl -s --connect-timeout 10 --max-time 10 -x %s --data-binary @%s -o %s %s/echo 2>/dev/null", |
|
|
|
|
proxy, f1, out, url_base); |
|
|
|
|
if (system(cmd) != 0) { fprintf(stderr, "[FAIL] http_proxy POST curl\n"); unlink(f1); return 1; } |
|
|
|
|
"curl -s --connect-timeout 10 --max-time 30 -x http://%s --data-binary @%s -o %s %s/echo 2>/dev/null", |
|
|
|
|
http_proxy, f1, out, url_http); |
|
|
|
|
if (system(cmd) != 0) { fprintf(stderr, "[FAIL] %s POST/echo curl\n", tname); unlink(f1); return 1; } |
|
|
|
|
snprintf(cmd, sizeof(cmd), "cmp -s %s %s", out, f1); |
|
|
|
|
if (system(cmd) != 0) { fprintf(stderr, "[FAIL] http_proxy POST cmp\n"); unlink(f1); unlink(out); return 1; } |
|
|
|
|
if (system(cmd) != 0) { fprintf(stderr, "[FAIL] %s POST/echo cmp\n", tname); unlink(f1); unlink(out); return 1; } |
|
|
|
|
unlink(f1); unlink(out); |
|
|
|
|
|
|
|
|
|
// HEAD /f_1k.bin — check status 200
|
|
|
|
|
snprintf(cmd, sizeof(cmd), |
|
|
|
|
"curl -s -I --connect-timeout 10 --max-time 10 -x %s %s/f_1k.bin 2>/dev/null | head -1 | grep -q '200 OK'", |
|
|
|
|
proxy, url_base); |
|
|
|
|
if (system(cmd) != 0) { fprintf(stderr, "[FAIL] http_proxy HEAD 200\n"); return 1; } |
|
|
|
|
"curl -s -I --connect-timeout 10 --max-time 30 -x http://%s %s/f_1k.bin 2>/dev/null | head -1 | grep -q '200 OK'", |
|
|
|
|
http_proxy, url_http); |
|
|
|
|
if (system(cmd) != 0) { fprintf(stderr, "[FAIL] %s HEAD 200\n", tname); return 1; } |
|
|
|
|
|
|
|
|
|
// OPTIONS /f_1k.bin — check Allow header
|
|
|
|
|
snprintf(out, sizeof(out), "%s/opt_%d.txt", tmpdir, (int)getpid()); |
|
|
|
|
snprintf(out, sizeof(out), "%s/opt_%d.txt", tmpdir, getpid()); |
|
|
|
|
snprintf(cmd, sizeof(cmd), |
|
|
|
|
"curl -s -i --connect-timeout 10 --max-time 10 -x %s -X OPTIONS -o %s %s/f_1k.bin 2>/dev/null", |
|
|
|
|
proxy, out, url_base); |
|
|
|
|
if (system(cmd) != 0) { fprintf(stderr, "[FAIL] http_proxy OPTIONS curl\n"); return 1; } |
|
|
|
|
"curl -s -i --connect-timeout 10 --max-time 30 -x http://%s -X OPTIONS -o %s %s/f_1k.bin 2>/dev/null", |
|
|
|
|
http_proxy, out, url_http); |
|
|
|
|
if (system(cmd) != 0) { fprintf(stderr, "[FAIL] %s OPTIONS curl\n", tname); return 1; } |
|
|
|
|
snprintf(cmd, sizeof(cmd), "grep -q 'Allow:' %s", out); |
|
|
|
|
if (system(cmd) != 0) { fprintf(stderr, "[FAIL] http_proxy OPTIONS Allow\n"); unlink(out); return 1; } |
|
|
|
|
if (system(cmd) != 0) { fprintf(stderr, "[FAIL] %s OPTIONS Allow\n", tname); unlink(out); return 1; } |
|
|
|
|
unlink(out); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -218,17 +307,35 @@ static void monitor(void* arg) {
|
|
|
|
|
if (conn_ready(g_cli) && conn_ready(g_srv)) { |
|
|
|
|
printf(" ETCP connected, launching %d workers...\n", WORKERS); fflush(stdout); |
|
|
|
|
g_phase = 1; |
|
|
|
|
char url[128]; snprintf(url, sizeof(url), "http://127.0.0.1:%d", g_http_port); |
|
|
|
|
char socks_proxy[64]; snprintf(socks_proxy, sizeof(socks_proxy), "127.0.0.1:%d", g_socks_port); |
|
|
|
|
char http_proxy[64]; snprintf(http_proxy, sizeof(http_proxy), "http://127.0.0.1:%d", g_http_proxy_port); |
|
|
|
|
|
|
|
|
|
const char* worker_types[] = { "socks", "http_connect", "http_proxy" }; |
|
|
|
|
const char* worker_proxies[] = { socks_proxy, http_proxy, http_proxy }; |
|
|
|
|
char url_http[128]; snprintf(url_http, sizeof(url_http), "http://127.0.0.1:%d", g_http_port); |
|
|
|
|
char url_https[128]; snprintf(url_https, sizeof(url_https), "https://127.0.0.1:%d", g_https_port); |
|
|
|
|
char socks[64]; snprintf(socks, sizeof(socks), "127.0.0.1:%d", g_socks_port); |
|
|
|
|
char hproxy[64]; snprintf(hproxy, sizeof(hproxy), "127.0.0.1:%d", g_http_proxy_port); |
|
|
|
|
|
|
|
|
|
// Для socks_domain worker'а: используем localhost вместо 127.0.0.1 чтобы тестировать atyp=3 (DNS через SOCKS)
|
|
|
|
|
char url_http_local[128]; |
|
|
|
|
snprintf(url_http_local, sizeof(url_http_local), "http://localhost:%d", g_http_port); |
|
|
|
|
|
|
|
|
|
struct { |
|
|
|
|
int type; |
|
|
|
|
const char* socks; |
|
|
|
|
const char* hproxy; |
|
|
|
|
const char* url_h; |
|
|
|
|
const char* url_s; |
|
|
|
|
} wcfg[WORKERS] = { |
|
|
|
|
{ W_SOCKS_IPV4, socks, NULL, url_http, NULL }, |
|
|
|
|
{ W_SOCKS_DOMAIN,socks, NULL, url_http_local, NULL }, |
|
|
|
|
{ W_HTTP_PROXY, NULL, hproxy, url_http, NULL }, |
|
|
|
|
{ W_HTTPS_CONNECT,NULL, hproxy, NULL, url_https }, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
for (int i = 0; i < WORKERS; i++) { |
|
|
|
|
pid_t pid = fork(); |
|
|
|
|
if (pid < 0) { printf("[FAIL] fork worker %d: %s\n", i, strerror(errno)); g_done = -1; return; } |
|
|
|
|
if (pid == 0) { |
|
|
|
|
int rc = worker_main(worker_types[i], worker_proxies[i], url, g_tmpdir); |
|
|
|
|
int rc = worker_main(wcfg[i].type, wcfg[i].socks, wcfg[i].hproxy, |
|
|
|
|
wcfg[i].url_h, wcfg[i].url_s, g_tmpdir); |
|
|
|
|
_exit(rc); |
|
|
|
|
} |
|
|
|
|
g_workers[i] = pid; |
|
|
|
|
@ -251,42 +358,48 @@ static void monitor(void* arg) {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!g_done) g_mon_id = uasync_set_timeout(g_ua, 500, NULL, monitor, "mon"); |
|
|
|
|
if (!g_done) g_mon_id = uasync_set_timeout(g_ua, 1000, NULL, monitor, "mon"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void test_timeout(void* arg) { |
|
|
|
|
(void)arg; |
|
|
|
|
if (!g_done) { printf("[FAIL] timeout\n"); g_done = -1; } |
|
|
|
|
if (!g_done) { printf("[FAIL] timeout (%ds)\n", TIMEOUT_MS/1000); g_done = -1; } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int main(void) { |
|
|
|
|
printf("=== test_socks_http_proxy ===\n"); fflush(stdout); |
|
|
|
|
|
|
|
|
|
// Резервируем fd 0
|
|
|
|
|
{ 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); |
|
|
|
|
utun_instance_set_tun_init_enabled(0); |
|
|
|
|
srand((unsigned)time(NULL)); |
|
|
|
|
|
|
|
|
|
g_http_port = alloc_port(); g_cli_port = alloc_port(); g_srv_port = alloc_port(); |
|
|
|
|
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_cli_port < 0 || g_srv_port < 0 || g_socks_port < 0 || g_http_proxy_port < 0) { |
|
|
|
|
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 socks=%d http_proxy=%d\n", g_http_port, g_socks_port, g_http_proxy_port); |
|
|
|
|
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; } |
|
|
|
|
|
|
|
|
|
int seed = (int)time(NULL) ^ (int)getpid(); |
|
|
|
|
if (gen_self_signed_cert(g_tmpdir, g_cert, sizeof(g_cert), g_key, sizeof(g_key)) < 0) goto cleanup; |
|
|
|
|
|
|
|
|
|
g_file_seed = (int)time(NULL) ^ (int)getpid(); |
|
|
|
|
int total_mb = 0; |
|
|
|
|
for (int fi = 0; fi < num_files; fi++) { |
|
|
|
|
char path[512]; snprintf(path, sizeof(path), "%s/%s", g_tmpdir, file_names[fi]); |
|
|
|
|
gen_file(path, file_sizes[fi], seed + fi); |
|
|
|
|
gen_file(path, file_sizes[fi], g_file_seed + fi); |
|
|
|
|
total_mb += file_sizes[fi]; |
|
|
|
|
} |
|
|
|
|
printf(" test files: 1k, 10k, 50k, 100k\n"); fflush(stdout); |
|
|
|
|
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; } |
|
|
|
|
printf(" HTTP/HTTPS servers started\n"); |
|
|
|
|
|
|
|
|
|
g_ua = uasync_create(); |
|
|
|
|
if (!g_ua) { printf("[FAIL] uasync_create\n"); goto cleanup; } |
|
|
|
|
@ -305,13 +418,19 @@ int main(void) {
|
|
|
|
|
|
|
|
|
|
if (to_id) uasync_cancel_timeout(g_ua, to_id); |
|
|
|
|
|
|
|
|
|
if (g_ok) printf("[PASS] test_socks_http_proxy — %d reqs, %d workers (socks/http_connect/http_proxy), up to 100KB\n", WORKERS * REQS_PER_WORKER, WORKERS); |
|
|
|
|
else printf("[FAIL] test_socks_http_proxy\n"); |
|
|
|
|
if (g_ok) { |
|
|
|
|
int total_files = WORKERS * num_files; |
|
|
|
|
printf("[PASS] test_socks_http_proxy — %d workers × %d files (%.1fMB each) = %d downloads verified byte-by-byte\n", |
|
|
|
|
WORKERS, num_files, total_mb / (1024.0*1024.0), total_files); |
|
|
|
|
} else { |
|
|
|
|
printf("[FAIL] test_socks_http_proxy\n"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cleanup: |
|
|
|
|
for (int i = 0; i < WORKERS; i++) if (g_workers[i] > 0) { kill(g_workers[i], SIGKILL); waitpid(g_workers[i], NULL, 0); } |
|
|
|
|
if (g_mon_id) uasync_cancel_timeout(g_ua, g_mon_id); |
|
|
|
|
if (g_http_pid > 0) { kill(g_http_pid, SIGKILL); waitpid(g_http_pid, NULL, 0); } |
|
|
|
|
if (g_https_pid > 0) { kill(g_https_pid, SIGKILL); waitpid(g_https_pid, NULL, 0); } |
|
|
|
|
if (g_cli) { g_cli->running = 0; utun_instance_destroy(g_cli); } |
|
|
|
|
if (g_srv) { g_srv->running = 0; utun_instance_destroy(g_srv); } |
|
|
|
|
if (g_ua) uasync_destroy(g_ua, 0); |
|
|
|
|
|