From 3ea37f0c379a56c4b0421dec1ac1449221984e1e Mon Sep 17 00:00:00 2001 From: none Date: Tue, 30 May 2023 13:45:48 +0200 Subject: [PATCH] add WIP rust server --- .gitignore | 2 +- Cargo.lock => rust/client/Cargo.lock | 2 +- Cargo.toml => rust/client/Cargo.toml | 2 +- {src => rust/client/src}/big_array.rs | 0 {src => rust/client/src}/main.rs | 0 rust/server/Cargo.lock | 219 ++++++++++++++++++++++++++ rust/server/Cargo.toml | 20 +++ rust/server/notes | 13 ++ rust/server/src/big_array.rs | 68 ++++++++ rust/server/src/main.rs | 126 +++++++++++++++ 10 files changed, 449 insertions(+), 3 deletions(-) rename Cargo.lock => rust/client/Cargo.lock (99%) rename Cargo.toml => rust/client/Cargo.toml (96%) rename {src => rust/client/src}/big_array.rs (100%) rename {src => rust/client/src}/main.rs (100%) create mode 100644 rust/server/Cargo.lock create mode 100644 rust/server/Cargo.toml create mode 100644 rust/server/notes create mode 100644 rust/server/src/big_array.rs create mode 100644 rust/server/src/main.rs diff --git a/.gitignore b/.gitignore index 51cd57e..32fd317 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ received/ # Added by cargo -/target +target # from optimize_dependencies diff --git a/Cargo.lock b/rust/client/Cargo.lock similarity index 99% rename from Cargo.lock rename to rust/client/Cargo.lock index 65a5184..c58d745 100644 --- a/Cargo.lock +++ b/rust/client/Cargo.lock @@ -72,7 +72,7 @@ dependencies = [ ] [[package]] -name = "itransfer" +name = "itransfer_client" version = "0.1.0" dependencies = [ "bincode", diff --git a/Cargo.toml b/rust/client/Cargo.toml similarity index 96% rename from Cargo.toml rename to rust/client/Cargo.toml index de882d8..dc66f48 100644 --- a/Cargo.toml +++ b/rust/client/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "itransfer" +name = "itransfer_client" version = "0.1.0" edition = "2021" diff --git a/src/big_array.rs b/rust/client/src/big_array.rs similarity index 100% rename from src/big_array.rs rename to rust/client/src/big_array.rs diff --git a/src/main.rs b/rust/client/src/main.rs similarity index 100% rename from src/main.rs rename to rust/client/src/main.rs diff --git a/rust/server/Cargo.lock b/rust/server/Cargo.lock new file mode 100644 index 0000000..0d299a8 --- /dev/null +++ b/rust/server/Cargo.lock @@ -0,0 +1,219 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +dependencies = [ + "memchr", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "itransfer_client" +version = "0.1.0" +dependencies = [ + "bincode", + "byteorder", + "regex", + "serde", + "sha2", + "sha3", +] + +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "libc" +version = "0.2.144" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "proc-macro2" +version = "1.0.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" + +[[package]] +name = "serde" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "syn" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "unicode-ident" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" diff --git a/rust/server/Cargo.toml b/rust/server/Cargo.toml new file mode 100644 index 0000000..a7dca21 --- /dev/null +++ b/rust/server/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "itransfer_client" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bincode = "1.3.3" +serde = { version = "1.0.163", features = ["serde_derive"], default-features = false } +byteorder = { default-features = false, version = "1.4.3" } +sha3 = { default-features = false, version = "0.10.8" } +sha2 = { default-features = false, version = "0.10.6" } +regex = { default-features = true, version = "1.8.3" } + +[profile.release] +lto = true # Enable link-time optimization +codegen-units = 1 # Reduce number of codegen units to increase optimizations +panic = 'abort' # Abort on panic +strip = true # Strip symbols from binary; remove pdb diff --git a/rust/server/notes b/rust/server/notes new file mode 100644 index 0000000..8d350cc --- /dev/null +++ b/rust/server/notes @@ -0,0 +1,13 @@ +packet size 1 - max: + file request + format: `[filename]` + +packet size 2 - max: + hash request + format: `[filename]:` + regex name: `hash_request_regex` + +packet size 3 - max: + missing packet request + format: `[filename]/[packet number]/[packet number]/...` + regex name: `missing_packet_request_regex` \ No newline at end of file diff --git a/rust/server/src/big_array.rs b/rust/server/src/big_array.rs new file mode 100644 index 0000000..f586968 --- /dev/null +++ b/rust/server/src/big_array.rs @@ -0,0 +1,68 @@ +use std::fmt; +use std::marker::PhantomData; +use serde::ser::{Serialize, Serializer, SerializeTuple}; +use serde::de::{Deserialize, Deserializer, Visitor, SeqAccess, Error}; + +pub trait BigArray<'de>: Sized { + fn serialize(&self, serializer: S) -> Result + where S: Serializer; + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de>; +} + +macro_rules! big_array { + ($($len:expr,)+) => { + $( + impl<'de, T> BigArray<'de> for [T; $len] + where T: Default + Copy + Serialize + Deserialize<'de> + { + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + let mut seq = serializer.serialize_tuple(self.len())?; + for elem in &self[..] { + seq.serialize_element(elem)?; + } + seq.end() + } + + fn deserialize(deserializer: D) -> Result<[T; $len], D::Error> + where D: Deserializer<'de> + { + struct ArrayVisitor { + element: PhantomData, + } + + impl<'de, T> Visitor<'de> for ArrayVisitor + where T: Default + Copy + Deserialize<'de> + { + type Value = [T; $len]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("an array of length ", $len)) + } + + fn visit_seq(self, mut seq: A) -> Result<[T; $len], A::Error> + where A: SeqAccess<'de> + { + let mut arr = [T::default(); $len]; + for i in 0..$len { + arr[i] = seq.next_element()? + .ok_or_else(|| Error::invalid_length(i, &self))?; + } + Ok(arr) + } + } + + let visitor = ArrayVisitor { element: PhantomData }; + deserializer.deserialize_tuple($len, visitor) + } + } + )+ + } +} + +big_array! { + 40, 48, 50, 56, 64, 72, 96, 100, 128, 160, 192, 200, 224, 256, 384, 488, 512, + 768, 1024, 2048, 4096, 8192, 16384, 32768, 65536, +} \ No newline at end of file diff --git a/rust/server/src/main.rs b/rust/server/src/main.rs new file mode 100644 index 0000000..2ff654f --- /dev/null +++ b/rust/server/src/main.rs @@ -0,0 +1,126 @@ +use bincode::{self, options, Options}; +use std::{net::{UdpSocket, SocketAddr}, io::Read}; +use serde::{Serialize, Deserialize}; +use sha3::{Digest, Sha3_512}; +use sha2::Sha512; +use regex::Regex; + +mod big_array; +use big_array::BigArray; + +const MAX_FRAME_PAYLOAD:u16=508; +const MAX_FRAME_PAYLOAD_U:usize=MAX_FRAME_PAYLOAD as usize; +const HEADER_SIZE:u16 = 20; +const MAX_PAYLOAD:u16 = MAX_FRAME_PAYLOAD - HEADER_SIZE; +const MAX_PAYLOAD_U:usize = MAX_PAYLOAD as usize; + +#[derive(Serialize, Deserialize)] +struct PacketInformation { + packet_numbers: u32, //4 bytes + last_packet_size: u16, //2 bytes + response_filename_checksum: u64, //8 bytes +} //14 bytes + +#[derive(Serialize, Deserialize)] +struct Packet { + packet_number: u32, //4 bytes + payload_hash: [u8; 16], //16 bytes + #[serde(with = "BigArray")] + payload: [u8; MAX_PAYLOAD_U], //488 bytes +} //512 bytes + +#[derive(Serialize, Deserialize)] +struct StrPacket { + #[serde(with = "BigArray")] + payload: [u8; MAX_PAYLOAD_U] +} + +fn main() { + let port = "1337"; + let timeout = 100; + let local_addr: SocketAddr = ("0.0.0.0:".to_string()+port).parse().expect("Failed to parse address"); + let socket = UdpSocket::bind(local_addr).expect("Failed to bind socket"); + + socket.set_read_timeout(Some(std::time::Duration::from_millis(timeout))).expect("set_read_timeout call failed"); + + println!("UDP Server up and running on port {}", local_addr.port()); + + let _options = options().with_big_endian().allow_trailing_bytes().with_fixint_encoding(); + + let hash_request_regex = Regex::new(r"[a-zA-Z0-9.-_ ]+:").unwrap(); + + let missing_packet_request_regex = Regex::new(r"([a-zA-Z0-9.-_ ]+)(/[0-9]+)+").unwrap(); + + loop { + let mut buffer = [0u8; MAX_FRAME_PAYLOAD_U]; + let res = socket.recv_from(&mut buffer); + if let Ok((_received_bytes, remote_addr)) = res { + let filled_buffer = &buffer;//[..received_bytes]; + + let request_packet = bincode::deserialize::(filled_buffer).unwrap(); + let request: String = request_packet.payload.iter().map(|&c| c as char).collect(); + println!("Received request: {}", request); + let req = request.as_str(); + + if hash_request_regex.is_match(req) { + println!("Received hash request"); + continue; + } + + if missing_packet_request_regex.is_match(req) { + println!("Received missing packet request"); + continue; + } + + println!("Received file request"); + + let request = "files/".to_string() + req; + + let file_result = std::fs::File::open(request); + + if file_result.is_err() { + println!("File not found"); + continue; + } + + let mut file = file_result.unwrap(); + + let mut file_buffer = [0u8; MAX_PAYLOAD_U]; + + let mut packet_number = 0u32; + + let file_length = file.metadata().unwrap().len(); + println!("file length: {}", file_length); + + let packet_information = PacketInformation { + packet_numbers: (file_length/MAX_PAYLOAD as u64) as u32, + last_packet_size: (file_length%MAX_PAYLOAD as u64) as u16, + response_filename_checksum: request_packet.payload.iter().fold(0u64, |acc, &x| acc.wrapping_add(x as u64)), + }; + + socket.send_to(bincode::serialize(&packet_information).unwrap().as_slice(), remote_addr).expect("Failed to send packet information"); + + //read file chunk by chunk + + while let Ok(bytes_read) = file.read(&mut file_buffer) { + if bytes_read == 0 { + break; + } + + let mut hasher = Sha3_512::new(); + hasher.update(&file_buffer[..bytes_read]); + let result = hasher.finalize(); + let mut packet = Packet { + packet_number, + payload_hash: [0u8; 16], + payload: file_buffer[..bytes_read].try_into().unwrap(), + }; + packet.payload_hash.copy_from_slice(&result[..16]); + packet.payload[..bytes_read].copy_from_slice(&file_buffer[..bytes_read]); + let packet_bytes = bincode::serialize(&packet).unwrap(); + socket.send_to(&packet_bytes, remote_addr).expect("Failed to send packet"); + packet_number += 1; + } + } + } +}