2022-07-15 15:18:03 +02:00
|
|
|
use std::{path::PathBuf, time::Duration};
|
2022-07-10 21:16:50 +02:00
|
|
|
use tokio::{
|
|
|
|
fs::File,
|
|
|
|
io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader, BufWriter},
|
|
|
|
net::TcpStream,
|
|
|
|
time::sleep,
|
|
|
|
};
|
|
|
|
|
2022-07-15 15:18:03 +02:00
|
|
|
pub async fn connect(addr: String, fileroot: PathBuf) -> Result<(), Box<dyn std::error::Error>> {
|
2022-07-10 21:16:50 +02:00
|
|
|
println!("[+] Connecting to {}", addr);
|
2022-07-15 15:18:03 +02:00
|
|
|
let mut stream = TcpStream::connect(addr.clone()).await?;
|
2022-07-10 21:16:50 +02:00
|
|
|
|
|
|
|
let (reader, writer) = stream.split();
|
|
|
|
let mut reader = BufReader::new(reader);
|
|
|
|
let mut writer = BufWriter::new(writer);
|
|
|
|
|
|
|
|
let mut buf = Vec::new();
|
|
|
|
|
|
|
|
loop {
|
2022-07-15 15:18:03 +02:00
|
|
|
let bytes_read = reader.read_buf(&mut buf).await?;
|
2022-07-10 21:16:50 +02:00
|
|
|
if bytes_read == 0 {
|
2022-07-11 20:10:05 +02:00
|
|
|
println!("[-] No more bytes received, closing connection");
|
2022-07-10 21:16:50 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-07-11 20:10:05 +02:00
|
|
|
// Receive buffersize
|
2022-07-15 15:18:03 +02:00
|
|
|
let buffersize = String::from_utf8(buf.clone())?.parse::<usize>()?;
|
2022-07-11 20:10:05 +02:00
|
|
|
println!("[+] Selected buffersize: {}", buffersize);
|
|
|
|
buf.clear();
|
|
|
|
|
|
|
|
// ACK buffersize
|
2022-07-16 03:49:55 +02:00
|
|
|
writer.write_all(b"ACK\n").await.unwrap();
|
2022-07-15 15:18:03 +02:00
|
|
|
writer.flush().await?;
|
2022-07-11 20:10:05 +02:00
|
|
|
|
2022-07-16 03:49:55 +02:00
|
|
|
// Receive file amount (or termination request if the server does not have any files available)
|
|
|
|
let file_amount: usize;
|
|
|
|
let _bytes_read = reader.read_until(b'\n', &mut buf).await?;
|
|
|
|
let msg = String::from_utf8(buf.clone())?;
|
|
|
|
if msg.trim() == "FIN" {
|
|
|
|
println!("[-] Server does not have any files available, closing connection");
|
|
|
|
writer.write_all(b"FIN\n").await?;
|
|
|
|
writer.flush().await?;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
file_amount = msg.trim().parse::<usize>()?;
|
|
|
|
println!("[+] Total of {} files available", file_amount);
|
|
|
|
buf.clear();
|
2022-07-10 21:16:50 +02:00
|
|
|
|
2022-07-16 03:49:55 +02:00
|
|
|
// ACK file amount
|
|
|
|
writer.write_all(b"ACK\n").await?;
|
|
|
|
writer.flush().await?;
|
|
|
|
}
|
2022-07-10 21:16:50 +02:00
|
|
|
|
|
|
|
// Receive file metadata
|
|
|
|
println!("[+] Receiving file metadata");
|
|
|
|
let mut metadata = Vec::<(String, u64)>::new();
|
|
|
|
while metadata.len() < file_amount {
|
2022-07-15 15:18:03 +02:00
|
|
|
reader.read_until(b'\n', &mut buf).await?;
|
|
|
|
let msg = String::from_utf8(buf.clone())?;
|
2022-07-10 21:16:50 +02:00
|
|
|
buf.clear();
|
|
|
|
|
|
|
|
// Parse 'filesize:filename'
|
|
|
|
let split = msg.split(":").collect::<Vec<&str>>();
|
2022-07-15 15:18:03 +02:00
|
|
|
let filesize = split[0].trim().parse::<u64>()?;
|
2022-07-10 21:16:50 +02:00
|
|
|
let filename = split[1].trim().to_string();
|
|
|
|
|
|
|
|
metadata.push((filename, filesize));
|
|
|
|
}
|
|
|
|
println!("[INFO] Metadata: {:?}", metadata);
|
|
|
|
|
|
|
|
// Send request for each file by filename
|
2022-07-15 15:18:03 +02:00
|
|
|
// TODO: Choose files based on input
|
|
|
|
println!("[+] Requesting files individually");
|
2022-07-10 21:16:50 +02:00
|
|
|
for file in &metadata {
|
|
|
|
println!("[INFO] Current request: [{:?}]", file);
|
2022-07-16 03:49:55 +02:00
|
|
|
let msg = file.0.to_string() + "\n";
|
|
|
|
writer.write_all(msg.as_bytes()).await?;
|
2022-07-15 15:18:03 +02:00
|
|
|
writer.flush().await?;
|
2022-07-10 21:16:50 +02:00
|
|
|
|
2022-07-11 20:10:05 +02:00
|
|
|
// Create file locally
|
2022-07-15 15:18:03 +02:00
|
|
|
let mut output_path = fileroot.clone();
|
|
|
|
output_path.push(file.0.clone());
|
2022-07-10 21:16:50 +02:00
|
|
|
|
2022-07-15 15:18:03 +02:00
|
|
|
let output_file = File::create(output_path.clone()).await?;
|
|
|
|
println!("[+] New file: {:#?}", output_path);
|
2022-07-10 21:16:50 +02:00
|
|
|
let mut file_buf = BufWriter::new(output_file);
|
|
|
|
|
|
|
|
// Receive the file itself
|
|
|
|
let mut remaining_data = file.1;
|
2022-07-11 20:10:05 +02:00
|
|
|
let mut buf = vec![0u8; buffersize];
|
2022-07-10 21:16:50 +02:00
|
|
|
|
|
|
|
while remaining_data != 0 {
|
2022-07-11 20:10:05 +02:00
|
|
|
if remaining_data >= buffersize as u64 {
|
2022-07-10 21:16:50 +02:00
|
|
|
let read_result = reader.read(&mut buf);
|
|
|
|
|
|
|
|
match read_result.await {
|
|
|
|
Ok(0) => {
|
|
|
|
println!("[-] Waiting for data to become available...");
|
|
|
|
sleep(Duration::from_secs(5)).await;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
Ok(n) => {
|
2022-07-15 15:18:03 +02:00
|
|
|
file_buf.write_all(&mut buf).await?;
|
|
|
|
file_buf.flush().await?;
|
2022-07-10 21:16:50 +02:00
|
|
|
remaining_data = remaining_data - n as u64;
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let read_result = reader.read(&mut buf);
|
|
|
|
|
|
|
|
match read_result.await {
|
|
|
|
Ok(_) => {
|
|
|
|
let mut buf_slice = &buf[0..(remaining_data as usize)];
|
2022-07-15 15:18:03 +02:00
|
|
|
file_buf.write_all(&mut buf_slice).await?;
|
|
|
|
file_buf.flush().await?;
|
2022-07-10 21:16:50 +02:00
|
|
|
remaining_data = 0;
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ACK file
|
2022-07-16 03:49:55 +02:00
|
|
|
writer.write_all(b"ACK\n").await?;
|
2022-07-15 15:18:03 +02:00
|
|
|
writer.flush().await?;
|
2022-07-10 21:16:50 +02:00
|
|
|
println!(
|
2022-07-15 15:18:03 +02:00
|
|
|
"[+] Successfully wrote {} bytes to {:#?}\n",
|
2022-07-10 21:16:50 +02:00
|
|
|
file.1, output_path
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-07-11 20:10:05 +02:00
|
|
|
println!("[+] All files finished, requesting connection termination");
|
2022-07-16 03:49:55 +02:00
|
|
|
writer.write_all(b"FIN\n").await?;
|
2022-07-15 15:18:03 +02:00
|
|
|
writer.flush().await?;
|
2022-07-10 21:16:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|