Initial commit
This commit is contained in:
commit
02f7d74267
21
.github/workflows/ci.yml
vendored
Normal file
21
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
name: Cargo Build & Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build_and_test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Build
|
||||||
|
run: cargo build --verbose
|
||||||
|
- name: Run tests
|
||||||
|
run: cargo test --verbose
|
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
/target
|
||||||
|
|
||||||
|
data/**
|
||||||
|
output/**
|
||||||
|
|
||||||
|
!output/.placeholder
|
||||||
|
!data/.placeholder
|
308
Cargo.lock
generated
Normal file
308
Cargo.lock
generated
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.126"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mio"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"wasi",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_cpus"
|
||||||
|
version = "1.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac8b1a9b2518dc799a2271eff1688707eb315f0d4697aa6b0871369ca4c4da55"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
"parking_lot_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot_core"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"smallvec",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.2.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook-registry"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smallvec"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.98"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio"
|
||||||
|
version = "1.19.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"libc",
|
||||||
|
"memchr",
|
||||||
|
"mio",
|
||||||
|
"num_cpus",
|
||||||
|
"once_cell",
|
||||||
|
"parking_lot",
|
||||||
|
"pin-project-lite",
|
||||||
|
"signal-hook-registry",
|
||||||
|
"socket2",
|
||||||
|
"tokio-macros",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-macros"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-socket-test"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
15
Cargo.toml
Normal file
15
Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "tokio-socket-test"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "server"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "client"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tokio = { version = "1.19.2", features = ["full"] }
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 einisto
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
0
data/.placeholder
Normal file
0
data/.placeholder
Normal file
0
output/.placeholder
Normal file
0
output/.placeholder
Normal file
127
src/bin/client.rs
Normal file
127
src/bin/client.rs
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
use tokio::{
|
||||||
|
fs::File,
|
||||||
|
io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader, BufWriter},
|
||||||
|
net::TcpStream,
|
||||||
|
time::sleep,
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Remove panics/unwraps & add proper error handling
|
||||||
|
|
||||||
|
const BUFFERSIZE: usize = 8192;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// TODO: Clap
|
||||||
|
let addr = "127.0.0.1:8080";
|
||||||
|
let mut stream = TcpStream::connect(addr).await?;
|
||||||
|
println!("[+] Connecting to {}", addr);
|
||||||
|
|
||||||
|
let (reader, writer) = stream.split();
|
||||||
|
let mut reader = BufReader::new(reader);
|
||||||
|
let mut writer = BufWriter::new(writer);
|
||||||
|
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let bytes_read = reader.read_buf(&mut buf).await.unwrap();
|
||||||
|
if bytes_read == 0 {
|
||||||
|
println!("[-] No more bytes received, disconnecting from the server...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive file amount
|
||||||
|
let file_amount = String::from_utf8(buf.clone())
|
||||||
|
.unwrap()
|
||||||
|
.parse::<usize>()
|
||||||
|
.unwrap();
|
||||||
|
println!("[+] Total of {} files available", file_amount);
|
||||||
|
buf.clear();
|
||||||
|
|
||||||
|
// ACK file amount
|
||||||
|
writer.write_all(b"ACK").await.unwrap();
|
||||||
|
writer.flush().await.unwrap();
|
||||||
|
|
||||||
|
// Receive file metadata
|
||||||
|
println!("[+] Receiving file metadata");
|
||||||
|
let mut metadata = Vec::<(String, u64)>::new();
|
||||||
|
while metadata.len() < file_amount {
|
||||||
|
reader.read_until(b'\n', &mut buf).await.unwrap();
|
||||||
|
let msg = String::from_utf8(buf.clone()).unwrap();
|
||||||
|
buf.clear();
|
||||||
|
|
||||||
|
// Parse 'filesize:filename'
|
||||||
|
let split = msg.split(":").collect::<Vec<&str>>();
|
||||||
|
let filesize = split[0].trim().parse::<u64>().unwrap();
|
||||||
|
let filename = split[1].trim().to_string();
|
||||||
|
|
||||||
|
metadata.push((filename, filesize));
|
||||||
|
}
|
||||||
|
println!("[INFO] Metadata: {:?}", metadata);
|
||||||
|
|
||||||
|
// Send request for each file by filename
|
||||||
|
println!("[+] Requesting files individually"); // TODO: Choose files based on input
|
||||||
|
for file in &metadata {
|
||||||
|
println!("[INFO] Current request: [{:?}]", file);
|
||||||
|
writer.write_all(file.0.as_bytes()).await.unwrap();
|
||||||
|
writer.flush().await.unwrap();
|
||||||
|
|
||||||
|
// Create file locally (./output/)
|
||||||
|
let output_path = String::from("./output/") + file.0.as_str();
|
||||||
|
|
||||||
|
let output_file = File::create(output_path.clone()).await.unwrap();
|
||||||
|
println!("[+] New file: {}", output_path);
|
||||||
|
let mut file_buf = BufWriter::new(output_file);
|
||||||
|
|
||||||
|
// Receive the file itself
|
||||||
|
let mut remaining_data = file.1;
|
||||||
|
let mut buf = [0u8; BUFFERSIZE];
|
||||||
|
|
||||||
|
while remaining_data != 0 {
|
||||||
|
if remaining_data >= BUFFERSIZE as u64 {
|
||||||
|
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) => {
|
||||||
|
file_buf.write_all(&mut buf).await.unwrap();
|
||||||
|
file_buf.flush().await.unwrap();
|
||||||
|
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)];
|
||||||
|
file_buf.write_all(&mut buf_slice).await.unwrap();
|
||||||
|
file_buf.flush().await.unwrap();
|
||||||
|
remaining_data = 0;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ACK file
|
||||||
|
writer.write_all(b"ACK").await.unwrap();
|
||||||
|
writer.flush().await.unwrap();
|
||||||
|
println!(
|
||||||
|
"[+] Successfully wrote {} bytes to {}\n",
|
||||||
|
file.1, output_path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("[+] All finished, disconnecting...");
|
||||||
|
writer.write_all(b"FIN").await.unwrap();
|
||||||
|
writer.flush().await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
123
src/bin/server.rs
Normal file
123
src/bin/server.rs
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
use std::fs::read_dir;
|
||||||
|
use tokio::{
|
||||||
|
self,
|
||||||
|
fs::File,
|
||||||
|
io::{AsyncReadExt, AsyncWriteExt, BufReader, BufWriter},
|
||||||
|
net::TcpListener,
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Remove panics/unwraps & add proper error handling
|
||||||
|
|
||||||
|
const BUFFERSIZE: usize = 8192;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// TODO: Clap
|
||||||
|
let addr = "127.0.0.1:8080";
|
||||||
|
let listener = TcpListener::bind(addr).await?;
|
||||||
|
println!("[+] Listening on {}", addr);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let (mut socket, addr) = listener.accept().await?;
|
||||||
|
println!("[+] New client: {}", addr);
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let (reader, writer) = socket.split();
|
||||||
|
let mut reader = BufReader::new(reader);
|
||||||
|
let mut writer = BufWriter::new(writer);
|
||||||
|
|
||||||
|
let mut vec_buf = Vec::new();
|
||||||
|
|
||||||
|
let (metadata_list, file_amount) = get_metadata().await;
|
||||||
|
|
||||||
|
// Send file amount
|
||||||
|
writer
|
||||||
|
.write_all(file_amount.to_string().as_bytes())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
writer.flush().await.unwrap();
|
||||||
|
|
||||||
|
// Read ACK
|
||||||
|
let _bytes_read = reader.read_buf(&mut vec_buf).await.unwrap();
|
||||||
|
if String::from_utf8(vec_buf.clone()).unwrap() != "ACK" {
|
||||||
|
panic!("ACK not received (amount)");
|
||||||
|
} else {
|
||||||
|
vec_buf.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send file metadata
|
||||||
|
for file in &metadata_list {
|
||||||
|
// Newline as delimiter between instances
|
||||||
|
let msg = format!("{}:{}\n", file.1, file.0);
|
||||||
|
writer.write_all(msg.as_bytes()).await.unwrap();
|
||||||
|
writer.flush().await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle file request(s)
|
||||||
|
println!("[+] Ready to serve files");
|
||||||
|
loop {
|
||||||
|
let bytes_read = reader.read_buf(&mut vec_buf).await.unwrap();
|
||||||
|
|
||||||
|
if bytes_read == 0 {
|
||||||
|
println!("File request never received");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
let msg = String::from_utf8(vec_buf.clone()).unwrap();
|
||||||
|
vec_buf.clear();
|
||||||
|
|
||||||
|
if msg == "FIN" {
|
||||||
|
println!("[+] FIN received, terminating connection...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let input_path = String::from("./data/") + msg.as_str();
|
||||||
|
|
||||||
|
println!("[+] File requested: {}", input_path);
|
||||||
|
let mut file = File::open(input_path.clone()).await.unwrap();
|
||||||
|
let mut remaining_data = file.metadata().await.unwrap().len();
|
||||||
|
let mut filebuf = [0u8; BUFFERSIZE];
|
||||||
|
|
||||||
|
while remaining_data != 0 {
|
||||||
|
let read_result = file.read(&mut filebuf);
|
||||||
|
match read_result.await {
|
||||||
|
Ok(n) => {
|
||||||
|
writer.write_all(&filebuf).await.unwrap();
|
||||||
|
writer.flush().await.unwrap();
|
||||||
|
remaining_data = remaining_data - n as u64;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read ACK
|
||||||
|
let _bytes_read = reader.read_buf(&mut vec_buf).await.unwrap();
|
||||||
|
if String::from_utf8(vec_buf.clone()).unwrap() != "ACK" {
|
||||||
|
panic!("ACK not received (amount)");
|
||||||
|
} else {
|
||||||
|
println!("[+] File transfer successfully done\n");
|
||||||
|
vec_buf.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_metadata() -> (Vec<(String, u64)>, usize) {
|
||||||
|
let mut metadata = Vec::<(String, u64)>::new();
|
||||||
|
let paths = read_dir("./data").unwrap();
|
||||||
|
|
||||||
|
for filename in paths {
|
||||||
|
let filepath = filename.unwrap().path().display().to_string(); // ????
|
||||||
|
let split = filepath.split("/").collect::<Vec<&str>>();
|
||||||
|
let filename = split[split.len() - 1].to_string();
|
||||||
|
let file = File::open(filepath).await.unwrap();
|
||||||
|
let filesize = file.metadata().await.unwrap().len();
|
||||||
|
|
||||||
|
metadata.push((filename, filesize));
|
||||||
|
}
|
||||||
|
|
||||||
|
let amount = metadata.len();
|
||||||
|
|
||||||
|
(metadata, amount)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user