1- use std:: io:: Read ;
21use std:: io:: { self , Write } ;
32use std:: sync:: atomic:: { AtomicBool , AtomicUsize , Ordering } ;
43use std:: sync:: { Arc , Mutex } ;
@@ -16,6 +15,8 @@ use args::UserArgs;
1615mod agent;
1716use crate :: agent:: create_configured_agent;
1817
18+ mod raw_socket;
19+
1920mod locations;
2021mod table;
2122#[ cfg( test) ]
@@ -259,61 +260,73 @@ fn upload_test(
259260 }
260261}
261262
262- // download some bytes from cloudflare
263+ // download some bytes from cloudflare using raw encrypted byte reading
263264fn download_test (
264265 bytes_to_request : usize ,
265266 total_bytes_counter : & Arc < AtomicUsize > ,
266267 current_down_speed : & Arc < AtomicUsize > ,
267268 exit_signal : & Arc < AtomicBool > ,
268269) -> Result < ( ) > {
269- let agent: Agent = create_configured_agent ( ) ;
270-
271- let resp = match agent
272- . get ( format ! ( "{CLOUDFLARE_SPEEDTEST_DOWNLOAD_URL}&bytes={bytes_to_request}" ) . as_str ( ) )
273- . call ( )
274- {
275- Ok ( resp) => resp,
276- Err ( err) => {
277- if !CTRL_C_PRESSED . load ( Ordering :: Relaxed ) {
278- eprintln ! ( "Error in download thread: {err}" ) ;
279- }
280- return Ok ( ( ) ) ;
281- }
282- } ;
283-
284- let body = resp. into_body ( ) ;
285- let mut resp_reader = body. into_reader ( ) ;
286- let mut total_bytes_sank: usize = 0 ;
287-
270+ // Keep making new requests until exit_signal is set
288271 loop {
289272 // exit if we have passed deadline
290273 if exit_signal. load ( Ordering :: Relaxed ) {
291274 return Ok ( ( ) ) ;
292275 }
293276
294- // if we are fast, take big chunks
295- // if we are slow, take small chunks
296- let current_recv_buff =
297- get_appropriate_buff_size ( current_down_speed. load ( Ordering :: Relaxed ) ) ;
277+ // Establish connection, perform TLS handshake, send HTTP request
278+ let mut conn = match raw_socket:: RawDownloadConnection :: connect (
279+ CLOUDFLARE_SPEEDTEST_DOWNLOAD_URL ,
280+ bytes_to_request,
281+ ) {
282+ Ok ( conn) => conn,
283+ Err ( err) => {
284+ if !CTRL_C_PRESSED . load ( Ordering :: Relaxed ) {
285+ eprintln ! ( "Error in download thread: {err}" ) ;
286+ }
287+ return Ok ( ( ) ) ;
288+ }
289+ } ;
290+
291+ let mut total_bytes_sank: usize = 0 ;
298292
299- // copy bytes into the void
300- let bytes_sank = std:: io:: copy (
301- & mut resp_reader. by_ref ( ) . take ( current_recv_buff) ,
302- & mut std:: io:: sink ( ) ,
303- ) ? as usize ;
293+ // Read from this connection until it's exhausted
294+ loop {
295+ // exit if we have passed deadline
296+ if exit_signal. load ( Ordering :: Relaxed ) {
297+ return Ok ( ( ) ) ;
298+ }
304299
305- //println!("Thread {:?} sank {} bytes", std::thread::current().id(), bytes_sank);
300+ // if we are fast, take big chunks
301+ // if we are slow, take small chunks
302+ let current_recv_buff =
303+ get_appropriate_buff_size ( current_down_speed. load ( Ordering :: Relaxed ) ) as usize ;
304+
305+ // Read raw encrypted bytes directly from socket (no TLS decryption!)
306+ let mut buf = vec ! [ 0u8 ; current_recv_buff] ;
307+ let bytes_read = match conn. read_encrypted_bytes ( & mut buf) {
308+ Ok ( n) => n,
309+ Err ( err) => {
310+ if !CTRL_C_PRESSED . load ( Ordering :: Relaxed ) {
311+ eprintln ! ( "Error reading from socket: {err}" ) ;
312+ }
313+ // Connection error, break to create a new connection
314+ break ;
315+ }
316+ } ;
306317
307- if bytes_sank == 0 {
308- if total_bytes_sank == 0 {
309- eprintln ! ( "Cloudflare sent an empty response?" ) ;
318+ if bytes_read == 0 {
319+ if total_bytes_sank == 0 {
320+ eprintln ! ( "Cloudflare sent an empty response?" ) ;
321+ }
322+ // Connection exhausted, break inner loop to make a new request
323+ break ;
310324 }
311325
312- return Ok ( ( ) ) ;
326+ // Count the encrypted bytes we received (wire bytes including TLS overhead)
327+ total_bytes_sank += bytes_read;
328+ total_bytes_counter. fetch_add ( bytes_read, Ordering :: SeqCst ) ;
313329 }
314-
315- total_bytes_sank += bytes_sank;
316- total_bytes_counter. fetch_add ( bytes_sank, Ordering :: SeqCst ) ;
317330 }
318331}
319332
0 commit comments