@ -29,7 +29,7 @@
# include "../src/tun_if.h"
# include "../src/tun_if.h"
# define TIMEOUT_MS 120000
# define TIMEOUT_MS 120000
# define WORKERS 2
# define WORKERS 3
# define REQS_PER_WORKER 25
# define REQS_PER_WORKER 25
static const int file_sizes [ ] = { 1024 , 10 * 1024 , 50 * 1024 , 100 * 1024 } ;
static const int file_sizes [ ] = { 1024 , 10 * 1024 , 50 * 1024 , 100 * 1024 } ;
@ -68,11 +68,38 @@ static void gen_file(const char* path, int size, int seed) {
}
}
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 ;
fprintf ( sf ,
" import sys,os \n "
" from http.server import HTTPServer,SimpleHTTPRequestHandler \n "
" class H(SimpleHTTPRequestHandler): \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 "
" port=int(sys.argv[1]) \n "
" os.chdir(sys.argv[2]) \n "
" HTTPServer(('',port),H).serve_forever() \n "
) ;
fclose ( sf ) ;
pid_t pid = fork ( ) ;
pid_t pid = fork ( ) ;
if ( pid < 0 ) return - 1 ;
if ( pid < 0 ) return - 1 ;
if ( pid = = 0 ) {
if ( pid = = 0 ) {
char port_str [ 16 ] ; snprintf ( port_str , sizeof ( port_str ) , " %d " , port ) ;
char port_str [ 16 ] ; snprintf ( port_str , sizeof ( port_str ) , " %d " , port ) ;
execlp ( " python3 " , " python3 " , " -m " , " http.server " , port_str , " --directory " , dir , ( char * ) NULL ) ;
execlp ( " python3 " , " python3 " , script , port_str , dir , ( char * ) NULL ) ;
_exit ( 1 ) ;
_exit ( 1 ) ;
}
}
g_http_pid = pid ;
g_http_pid = pid ;
@ -134,8 +161,10 @@ static int worker_main(const char* type, const char* proxy, const char* url_base
snprintf ( url , sizeof ( url ) , " %s/%s " , url_base , file_names [ fi ] ) ;
snprintf ( url , sizeof ( url ) , " %s/%s " , url_base , file_names [ fi ] ) ;
if ( strcmp ( type , " socks " ) = = 0 )
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 ) ;
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
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 ) ;
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 ) ;
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 ; }
if ( rc ! = 0 ) { fprintf ( stderr , " [FAIL] worker %s %s iter %d curl exit %d \n " , type , file_names [ fi ] , i , WEXITSTATUS ( rc ) ) ; return 1 ; }
@ -146,6 +175,38 @@ static int worker_main(const char* type, const char* proxy, const char* url_base
unlink ( out ) ;
unlink ( out ) ;
}
}
}
}
if ( strcmp ( type , " http_proxy " ) = = 0 ) {
char cmd [ 1024 ] , 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 ( 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 ; }
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 ; }
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 ; }
// OPTIONS /f_1k.bin — check Allow header
snprintf ( out , sizeof ( out ) , " %s/opt_%d.txt " , tmpdir , ( int ) 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 ; }
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 ; }
unlink ( out ) ;
}
return 0 ;
return 0 ;
}
}
@ -161,11 +222,13 @@ static void monitor(void* arg) {
char socks_proxy [ 64 ] ; snprintf ( socks_proxy , sizeof ( socks_proxy ) , " 127.0.0.1:%d " , g_socks_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 ) ;
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 } ;
for ( int i = 0 ; i < WORKERS ; i + + ) {
for ( int i = 0 ; i < WORKERS ; i + + ) {
pid_t pid = fork ( ) ;
pid_t pid = fork ( ) ;
if ( pid < 0 ) { printf ( " [FAIL] fork worker %d: %s \n " , i , strerror ( errno ) ) ; g_done = - 1 ; return ; }
if ( pid < 0 ) { printf ( " [FAIL] fork worker %d: %s \n " , i , strerror ( errno ) ) ; g_done = - 1 ; return ; }
if ( pid = = 0 ) {
if ( pid = = 0 ) {
int rc = worker_main ( i < WORKERS / 2 ? " socks " : " http " , i < WORKERS / 2 ? socks_proxy : http_proxy , url , g_tmpdir ) ;
int rc = worker_main ( worker_types [ i ] , worker_proxies [ i ] , url , g_tmpdir ) ;
_exit ( rc ) ;
_exit ( rc ) ;
}
}
g_workers [ i ] = pid ;
g_workers [ i ] = pid ;
@ -242,7 +305,7 @@ int main(void) {
if ( to_id ) uasync_cancel_timeout ( g_ua , to_id ) ;
if ( to_id ) uasync_cancel_timeout ( g_ua , to_id ) ;
if ( g_ok ) printf ( " [PASS] test_socks_http_proxy — %d reqs, %d workers, up to 100KB \n " , WORKERS * REQS_PER_WORKER , WORKERS ) ;
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 " ) ;
else printf ( " [FAIL] test_socks_http_proxy \n " ) ;
cleanup :
cleanup :