From 8b2ab4861bc4e8c23cd73d34a86ae27ac31c2a97 Mon Sep 17 00:00:00 2001 From: TIBERGHIEN corentin Date: Wed, 21 Jan 2026 02:45:48 +0100 Subject: [PATCH] zzzz --- client-gui/src/gui_app.rs | 2 +- client-network/src/data.rs | 230 ++---------------------- client-network/src/datum_generation.rs | 200 +++++++++++++++++++++ client-network/src/datum_parsing.rs | 7 +- client-network/src/lib.rs | 48 +++-- client-network/src/message_handling.rs | 116 ++---------- client-network/src/messages_channels.rs | 7 +- client-network/src/peers_refresh.rs | 144 +++++++-------- client-network/src/registration.rs | 6 + todo.md | 51 ++---- 10 files changed, 351 insertions(+), 460 deletions(-) create mode 100644 client-network/src/datum_generation.rs diff --git a/client-gui/src/gui_app.rs b/client-gui/src/gui_app.rs index 05a17fe..2da5513 100644 --- a/client-gui/src/gui_app.rs +++ b/client-gui/src/gui_app.rs @@ -571,7 +571,7 @@ impl P2PClientApp { .enabled(true) .show(ui, |ui| { for child in &node.children_hashes { - self.draw_file_node(ui, child.content_hash, tree, depth + 1, None); + self.draw_file_node(ui, child.clone(), tree, depth + 1, None); } }); } diff --git a/client-network/src/data.rs b/client-network/src/data.rs index c3c9ce1..04171aa 100644 --- a/client-network/src/data.rs +++ b/client-network/src/data.rs @@ -3,51 +3,12 @@ use std::collections::HashMap; use std::hash::{DefaultHasher, Hash, Hasher}; // --- Constants --- -const MAX_CHUNK_DATA_SIZE: usize = 1024; -const MAX_DIRECTORY_ENTRIES: usize = 16; -const MAX_BIG_CHILDREN: usize = 32; -const MIN_BIG_CHILDREN: usize = 2; -const FILENAME_HASH_SIZE: usize = 32; -const DIRECTORY_ENTRY_SIZE: usize = FILENAME_HASH_SIZE * 2; // 64 bytes - -fn hash(data: &[u8]) -> NodeHash { - let mut hasher = DefaultHasher::new(); - data.hash(&mut hasher); - let hash_u64 = hasher.finish(); - - let mut hash_array = [0u8; FILENAME_HASH_SIZE]; - // Simple way to spread a 64-bit hash across 32 bytes for a unique-ish ID - for i in 0..8 { - hash_array[i] = (hash_u64 >> (i * 8)) as u8; - } - hash_array // The rest remains 0, satisfying the 32-byte requirement -} - -fn generate_random_filename() -> [u8; FILENAME_HASH_SIZE] { - let mut rng = rand::rng(); - let mut filename_bytes = [0; FILENAME_HASH_SIZE]; - - // Generate a random length for the base name - let name_len = rng.random_range(5..21); - - // Generate random alphanumeric characters - for i in 0..name_len { - let char_code = rng.random_range(97..123); // 'a' through 'z' - if i < FILENAME_HASH_SIZE { - filename_bytes[i] = char_code as u8; - } - } - - // Append a common extension - let ext = if rng.random_bool(0.5) { ".txt" } else { ".dat" }; - let ext_bytes = ext.as_bytes(); - let start_index = name_len.min(FILENAME_HASH_SIZE - ext_bytes.len()); - if start_index < FILENAME_HASH_SIZE { - filename_bytes[start_index..(start_index + ext_bytes.len())].copy_from_slice(ext_bytes); - } - - filename_bytes -} +pub const MAX_CHUNK_DATA_SIZE: usize = 1024; +pub const MAX_DIRECTORY_ENTRIES: usize = 16; +pub const MAX_BIG_CHILDREN: usize = 32; +pub const MIN_BIG_CHILDREN: usize = 2; +pub const FILENAME_HASH_SIZE: usize = 32; +pub const DIRECTORY_ENTRY_SIZE: usize = FILENAME_HASH_SIZE * 2; // 64 bytes pub type NodeHash = [u8; FILENAME_HASH_SIZE]; @@ -80,100 +41,6 @@ impl MerkleTree { } } -/*fn generate_random_file_node( - storage: &mut HashMap, -) -> Result { - let mut rng = rng(); - let is_big = rng.random_bool(0.2); // 20% chance of being a big file - - if !is_big { - // Generate a simple Chunk Node - let node = MerkleNode::Chunk(ChunkNode::new_random()); - let hash = hash(&node.serialize()); - storage.insert(hash, node); - Ok(hash) - } else { - // Generate a Big Node (a file composed of chunks) - let num_children = rng.random_range(MIN_BIG_CHILDREN..=MAX_BIG_CHILDREN.min(8)); // Limit complexity - let mut children_hashes = Vec::with_capacity(num_children); - - for _ in 0..num_children { - // Children must be Chunk or Big; for simplicity, we only generate Chunk children here. - let chunk_node = MerkleNode::Chunk(ChunkNode::new_random()); - let chunk_hash = hash(&chunk_node.serialize()); - storage.insert(chunk_hash, chunk_node); - children_hashes.push(chunk_hash); - } - - let node = MerkleNode::Big(BigNode::new(children_hashes)?); - let hash = hash(&node.serialize()); - storage.insert(hash, node); - Ok(hash) - } -}*/ - -/*fn generate_random_directory_node( - depth: u32, - max_depth: u32, - storage: &mut HashMap, -) -> Result { - let mut rng = rng(); - let current_depth = depth + 1; - let is_big_dir = rng.random_bool(0.3) && current_depth < max_depth; - - if !is_big_dir || current_depth >= max_depth { - // Generate a simple Directory Node (leaf level directory) - let num_entries = rng.random_range(1..=MAX_DIRECTORY_ENTRIES.min(5)); // Limit directory size for testing - let mut entries = Vec::with_capacity(num_entries); - - for _ in 0..num_entries { - if rng.random_bool(0.7) { - // 70% chance of creating a file (Chunk/Big) - let file_hash = generate_random_file_node(storage)?; - let entry = DirectoryEntry { - filename: generate_random_filename(), - content_hash: file_hash, - }; - entries.push(entry); - } else if current_depth < max_depth { - // 30% chance of creating a subdirectory - let dir_hash = generate_random_directory_node(current_depth, max_depth, storage)?; - - // Create a basic directory entry name - let mut filename_bytes = [0; 32]; - let subdir_name = format!("dir_{}", current_depth); - filename_bytes[..subdir_name.len()].copy_from_slice(subdir_name.as_bytes()); - - let entry = DirectoryEntry { - filename: filename_bytes, - content_hash: dir_hash, - }; - entries.push(entry); - } - } - - let node = MerkleNode::Directory(DirectoryNode::new(entries)?); - let hash = hash(&node.serialize()); - storage.insert(hash, node); - Ok(hash) - } else { - // Generate a BigDirectory Node (internal directory structure) - let num_children = rng.random_range(MIN_BIG_CHILDREN..=MAX_BIG_CHILDREN.min(4)); // Limit children count - let mut children = Vec::with_capacity(num_children); - - for _ in 0..num_children { - // Children must be Directory or BigDirectory - let child_hash = generate_random_directory_node(current_depth, max_depth, storage)?; - children.push(child_hash); - } - - let node = MerkleNode::BigDirectory(BigDirectoryNode::new(children)?); - let hash = hash(&node.serialize()); - storage.insert(hash, node); - Ok(hash) - } -}*/ - #[derive(Debug, Clone)] pub struct ChunkNode { pub data: Vec, @@ -208,7 +75,7 @@ impl ChunkNode { // Helper struct #[derive(Debug, Clone)] pub struct DirectoryEntry { - pub filename: Vec, + pub filename: [u8; FILENAME_HASH_SIZE], pub content_hash: NodeHash, } @@ -240,7 +107,7 @@ pub struct BigNode { } impl BigNode { - /*pub fn new(children_hashes: Vec) -> Result { + pub fn new(children_hashes: Vec) -> Result { let n = children_hashes.len(); if n < MIN_BIG_CHILDREN || n > MAX_BIG_CHILDREN { return Err(format!( @@ -249,17 +116,17 @@ impl BigNode { )); } Ok(BigNode { children_hashes }) - }*/ + } } #[derive(Debug, Clone)] pub struct BigDirectoryNode { - //pub children_hashes: Vec, - pub children_hashes: Vec, + pub children_hashes: Vec, + // pub children_hashes: Vec, } impl BigDirectoryNode { - /*pub fn new(children_hashes: Vec) -> Result { + pub fn new(children_hashes: Vec) -> Result { let n = children_hashes.len(); if n < MIN_BIG_CHILDREN || n > MAX_BIG_CHILDREN { return Err(format!( @@ -268,14 +135,6 @@ impl BigDirectoryNode { )); } Ok(BigDirectoryNode { children_hashes }) - }*/ - pub fn new(entries: Vec) -> Result { - if entries.len() > MAX_DIRECTORY_ENTRIES { - return Err(format!("Directory exceeds {} bytes", entries.len())); - } - Ok(BigDirectoryNode { - children_hashes: entries, - }) } } @@ -310,73 +169,10 @@ impl MerkleNode { } MerkleNode::BigDirectory(node) => { for hash in &node.children_hashes { - bytes.extend_from_slice(&hash.content_hash); + bytes.extend_from_slice(hash); } } } bytes } - - /*pub fn generate_random_tree( - max_depth: u32, - ) -> Result<(NodeHash, HashMap), String> { - let mut storage = HashMap::new(); - - // Start tree generation from the root directory at depth 0 - let root_hash = generate_random_directory_node(0, max_depth, &mut storage)?; - - Ok((root_hash, storage)) - }*/ - - /*pub fn generate_base_tree() -> (NodeHash, HashMap) { - let mut res = HashMap::new(); - - let node1 = MerkleNode::Chunk(ChunkNode::new_random()); - let hash1 = hash(&node1.serialize()); - - let node2 = MerkleNode::Chunk(ChunkNode::new_random()); - let hash2 = hash(&node2.serialize()); - - res.insert(hash1, node1); - res.insert(hash2, node2); - - let node3 = MerkleNode::Chunk(ChunkNode::new_random()); - let hash3 = hash(&node3.serialize()); - - res.insert(hash3, node3); - - let dir1 = MerkleNode::Directory(DirectoryNode { - entries: [DirectoryEntry { - filename: generate_random_filename(), - content_hash: hash3, - }] - .to_vec(), - }); - let hash_dir1 = hash(&dir1.serialize()); - - res.insert(hash_dir1, dir1); - - let root = MerkleNode::Directory(DirectoryNode { - entries: [ - DirectoryEntry { - filename: generate_random_filename(), - content_hash: hash1, - }, - DirectoryEntry { - filename: generate_random_filename(), - content_hash: hash2, - }, - DirectoryEntry { - filename: generate_random_filename(), - content_hash: hash_dir1, - }, - ] - .to_vec(), - }); - - let root_hash = hash(&root.serialize()); - res.insert(root_hash, root); - - (root_hash, res) - }*/ } diff --git a/client-network/src/datum_generation.rs b/client-network/src/datum_generation.rs new file mode 100644 index 0000000..9928998 --- /dev/null +++ b/client-network/src/datum_generation.rs @@ -0,0 +1,200 @@ +use crate::data::*; +use rand::{Rng, rng}; +use std::collections::HashMap; +use std::hash::{DefaultHasher, Hash, Hasher}; + +fn hash(data: &[u8]) -> NodeHash { + let mut hasher = DefaultHasher::new(); + data.hash(&mut hasher); + let hash_u64 = hasher.finish(); + + let mut hash_array = [0u8; FILENAME_HASH_SIZE]; + // Simple way to spread a 64-bit hash across 32 bytes for a unique-ish ID + for i in 0..8 { + hash_array[i] = (hash_u64 >> (i * 8)) as u8; + } + hash_array // The rest remains 0, satisfying the 32-byte requirement +} + +fn generate_random_filename() -> [u8; FILENAME_HASH_SIZE] { + let mut rng = rand::rng(); + let mut filename_bytes = [0; FILENAME_HASH_SIZE]; + + // Generate a random length for the base name + let name_len = rng.random_range(5..21); + + // Generate random alphanumeric characters + for i in 0..name_len { + let char_code = rng.random_range(97..123); // 'a' through 'z' + if i < FILENAME_HASH_SIZE { + filename_bytes[i] = char_code as u8; + } + } + + // Append a common extension + let ext = if rng.random_bool(0.5) { ".txt" } else { ".dat" }; + let ext_bytes = ext.as_bytes(); + let start_index = name_len.min(FILENAME_HASH_SIZE - ext_bytes.len()); + if start_index < FILENAME_HASH_SIZE { + filename_bytes[start_index..(start_index + ext_bytes.len())].copy_from_slice(ext_bytes); + } + + filename_bytes +} + +fn generate_random_file_node( + storage: &mut HashMap, +) -> Result { + let mut rng = rng(); + let is_big = rng.random_bool(0.2); // 20% chance of being a big file + + if !is_big { + // Generate a simple Chunk Node + let node = MerkleNode::Chunk(ChunkNode::new_random()); + let hash = hash(&node.serialize()); + storage.insert(hash, node); + Ok(hash) + } else { + // Generate a Big Node (a file composed of chunks) + let num_children = rng.random_range(MIN_BIG_CHILDREN..=MAX_BIG_CHILDREN.min(8)); // Limit complexity + let mut children_hashes = Vec::with_capacity(num_children); + + for _ in 0..num_children { + // Children must be Chunk or Big; for simplicity, we only generate Chunk children here. + let chunk_node = MerkleNode::Chunk(ChunkNode::new_random()); + let chunk_hash = hash(&chunk_node.serialize()); + storage.insert(chunk_hash, chunk_node); + children_hashes.push(chunk_hash); + } + + let node = MerkleNode::Big(BigNode::new(children_hashes)?); + let hash = hash(&node.serialize()); + storage.insert(hash, node); + Ok(hash) + } +} + +fn generate_random_directory_node( + depth: u32, + max_depth: u32, + storage: &mut HashMap, +) -> Result { + let mut rng = rng(); + let current_depth = depth + 1; + let is_big_dir = rng.random_bool(0.3) && current_depth < max_depth; + + if !is_big_dir || current_depth >= max_depth { + // Generate a simple Directory Node (leaf level directory) + let num_entries = rng.random_range(1..=MAX_DIRECTORY_ENTRIES.min(5)); // Limit directory size for testing + let mut entries = Vec::with_capacity(num_entries); + + for _ in 0..num_entries { + if rng.random_bool(0.7) { + // 70% chance of creating a file (Chunk/Big) + let file_hash = generate_random_file_node(storage)?; + let entry = DirectoryEntry { + filename: generate_random_filename(), + content_hash: file_hash, + }; + entries.push(entry); + } else if current_depth < max_depth { + // 30% chance of creating a subdirectory + let dir_hash = generate_random_directory_node(current_depth, max_depth, storage)?; + + // Create a basic directory entry name + let mut filename_bytes = [0; 32]; + let subdir_name = format!("dir_{}", current_depth); + filename_bytes[..subdir_name.len()].copy_from_slice(subdir_name.as_bytes()); + + let entry = DirectoryEntry { + filename: filename_bytes, + content_hash: dir_hash, + }; + entries.push(entry); + } + } + + let node = MerkleNode::Directory(DirectoryNode::new(entries)?); + let hash = hash(&node.serialize()); + storage.insert(hash, node); + Ok(hash) + } else { + // Generate a BigDirectory Node (internal directory structure) + let num_children = rng.random_range(MIN_BIG_CHILDREN..=MAX_BIG_CHILDREN.min(4)); // Limit children count + let mut children = Vec::with_capacity(num_children); + + for _ in 0..num_children { + // Children must be Directory or BigDirectory + let child_hash = generate_random_directory_node(current_depth, max_depth, storage)?; + children.push(child_hash); + } + + let node = MerkleNode::BigDirectory(BigDirectoryNode::new(children)?); + let hash = hash(&node.serialize()); + storage.insert(hash, node); + Ok(hash) + } +} + +pub fn generate_random_tree( + max_depth: u32, +) -> Result<(NodeHash, HashMap), String> { + let mut storage = HashMap::new(); + + // Start tree generation from the root directory at depth 0 + let root_hash = generate_random_directory_node(0, max_depth, &mut storage)?; + + Ok((root_hash, storage)) +} + +pub fn generate_base_tree() -> (NodeHash, HashMap) { + let mut res = HashMap::new(); + + let node1 = MerkleNode::Chunk(ChunkNode::new_random()); + let hash1 = hash(&node1.serialize()); + + let node2 = MerkleNode::Chunk(ChunkNode::new_random()); + let hash2 = hash(&node2.serialize()); + + res.insert(hash1, node1); + res.insert(hash2, node2); + + let node3 = MerkleNode::Chunk(ChunkNode::new_random()); + let hash3 = hash(&node3.serialize()); + + res.insert(hash3, node3); + + let dir1 = MerkleNode::Directory(DirectoryNode { + entries: [DirectoryEntry { + filename: generate_random_filename(), + content_hash: hash3, + }] + .to_vec(), + }); + let hash_dir1 = hash(&dir1.serialize()); + + res.insert(hash_dir1, dir1); + + let root = MerkleNode::Directory(DirectoryNode { + entries: [ + DirectoryEntry { + filename: generate_random_filename(), + content_hash: hash1, + }, + DirectoryEntry { + filename: generate_random_filename(), + content_hash: hash2, + }, + DirectoryEntry { + filename: generate_random_filename(), + content_hash: hash_dir1, + }, + ] + .to_vec(), + }); + + let root_hash = hash(&root.serialize()); + res.insert(root_hash, root); + + (root_hash, res) +} diff --git a/client-network/src/datum_parsing.rs b/client-network/src/datum_parsing.rs index 88bedd8..25503f4 100644 --- a/client-network/src/datum_parsing.rs +++ b/client-network/src/datum_parsing.rs @@ -31,7 +31,7 @@ pub fn parse_received_datum( hash.copy_from_slice(&recevied_datum[offset + 32..offset + 64]); // envoyer un datum request dir_entries.push(DirectoryEntry { - filename: name.to_vec(), + filename: name.try_into().expect("incorrect size"), content_hash: hash, }); } @@ -71,10 +71,7 @@ pub fn parse_received_datum( let mut hash = [0u8; 32]; hash.copy_from_slice(&recevied_datum[offset + 32..offset + 64]); // envoyer un datum request - dir_entries.push(DirectoryEntry { - filename: name.to_vec(), - content_hash: hash, - }); + dir_entries.push(hash); } let current = BigDirectoryNode::new(dir_entries); diff --git a/client-network/src/lib.rs b/client-network/src/lib.rs index a80b9c0..9224415 100644 --- a/client-network/src/lib.rs +++ b/client-network/src/lib.rs @@ -1,5 +1,6 @@ mod cryptographic_signature; mod data; +mod datum_generation; mod datum_parsing; mod message_handling; mod messages_channels; @@ -9,6 +10,7 @@ mod registration; mod server_communication; mod threads_handling; +use crate::peers_refresh::*; use crate::{ cryptographic_signature::CryptographicSignature, message_handling::EventType, @@ -22,8 +24,10 @@ use crate::{ threads_handling::Worker, }; use std::{ + clone, io::Error, net::{IpAddr, Ipv4Addr, UdpSocket}, + time::Duration, }; use std::{ net::SocketAddr, @@ -42,6 +46,7 @@ pub struct P2PSharedData { use bytes::Bytes; use p256::pkcs8::der::pem::Base64Encoder; +use reqwest::Client; impl P2PSharedData { pub fn new( @@ -63,9 +68,6 @@ impl P2PSharedData { let server_name = Arc::new(Mutex::new("".to_string())); let handhsake_peers = Arc::new(HandshakeHistory::new()); - let worker = handhsake_peers.update_handshake(); - - threads.push(worker); Ok(P2PSharedData { shared_socket: shared_socket, shared_cryptopair: shared_cryptopair, @@ -100,13 +102,12 @@ impl P2PSharedData { pub fn socket_ref(&self) -> &UdpSocket { &*self.shared_socket } - + pub fn handshakes(&self) -> Arc { + self.handshake_peers.clone() + } pub fn cryptopair_ref(&self) -> &CryptographicSignature { &*self.shared_cryptopair } - pub fn handshake_ref(&self) -> &HandshakeHistory { - &*self.handshake_peers - } pub fn messages_list_ref(&self) -> &Mutex> { &*self.shared_messageslist @@ -195,8 +196,6 @@ pub fn start_p2p_executor( // Use tokio to spawn the asynchronous networking logic tokio::task::spawn(async move { // P2P/Networking Setup goes here - let handshake_history = Arc::new(Mutex::new(HandshakeHistory::new())); - let handshake_clone = handshake_history.clone(); println!("Network executor started."); @@ -208,13 +207,20 @@ pub fn start_p2p_executor( NetworkCommand::ServerHandshake(username, ip) => { println!("server handshake called"); if let Some(sd) = shared_data.as_mut() { - start_receving_thread(sd, event_tx.clone(), &handshake_clone); + start_receving_thread(sd, event_tx.clone(), sd.handshakes()); start_retry_thread( sd.senders(), 4, sd.messages_list(), sd.threads().as_mut(), ); + update_handshake( + sd.senders(), + sd.cryptopair(), + sd.messages_list(), + sd.handshake_peers.username_k_peerinfo_v.clone(), + ); + let res = perform_handshake(&sd, username, ip, event_tx.clone(), true).await; } else { @@ -234,10 +240,7 @@ pub fn start_p2p_executor( NetworkCommand::Discover(username, hash, ip) => { // envoie un handshake au peer, puis un root request if let Some(sd) = shared_data.as_ref() { - let res = { - let m = handshake_clone.lock().unwrap(); - m.get_peer_info_username(username.clone()).cloned() - }; + let res = sd.handshake_peers.get_peer_info_username(username.clone()); match res { Some(peerinfo) => { let id = generate_id(); @@ -392,7 +395,11 @@ pub fn start_p2p_executor( ); } } - None => {} + None => { + let err_msg = + format!("failed to retreive socket address:").to_string(); + let res = event_tx.send(NetworkEvent::Error(err_msg)); + } } } println!("[Network] Ping() called"); @@ -428,13 +435,15 @@ pub fn start_p2p_executor( print!("{:?}", payload.clone()); + let id = generate_id(); let natreq = construct_message( NATTRAVERSALREQUEST, payload.clone(), - generate_id(), + id.clone(), &sd.cryptopair(), ); + sd.add_message(id, EventType::NatTraversal); sd.senders_ref().send_dispatch( natreq.expect( "couldnt construct message nattraversalrequest2", @@ -502,11 +511,14 @@ fn parse_pack(s: &str) -> Option<[u8; 6]> { /// pub async fn get_socket_address(username: String, ip: String) -> Option { - let client = reqwest::Client::new(); + let client = Client::builder() + .timeout(Duration::from_secs(5)) + .build() + .expect("cannot create client"); let uri = format!("{}/peers/{}/addresses", ip, username); let res = client.get(uri).send().await.expect("couldnt get response"); if res.status().is_success() { - println!("Successfully retreived the addresses."); + println!("Successfully retreived the addresses. {}", res.status()); } else { eprintln!( "Failed to get the peers addresses from the server. Status: {}", diff --git a/client-network/src/message_handling.rs b/client-network/src/message_handling.rs index d7e8727..69cf38c 100644 --- a/client-network/src/message_handling.rs +++ b/client-network/src/message_handling.rs @@ -36,7 +36,7 @@ const LENGTH: usize = 7; const EXTENSIONS: usize = 4; const SIGNATURE: usize = 64; -const PING: u8 = 0; +pub const PING: u8 = 0; const OK: u8 = 128; const ERROR: u8 = 129; const HELLO: u8 = 1; @@ -58,7 +58,7 @@ pub fn handle_recevied_message( server_name: &String, cmd_tx: crossbeam_channel::Sender, ip: SocketAddr, - handhsake_history: &Arc>, + handhsake_history: Arc, ) { if recevied_message.len() < 4 { return; @@ -114,10 +114,9 @@ pub fn parse_message( cmd_tx: crossbeam_channel::Sender, ip: SocketAddr, messages_list: &Arc>>, - handhsake_history_mutex: &Arc>, + handhsake_history: Arc, senders: &MultipleSenders, ) -> Option> { - let mut handhsake_history = handhsake_history_mutex.lock().unwrap(); let cmd_tx_clone = cmd_tx.clone(); let id_bytes: [u8; 4] = received_message[0..ID] @@ -148,12 +147,8 @@ pub fn parse_message( .block_on(get_peer_key(&username)) .expect("failed to retrieve public key"), }; - match msgtype { - HELLOREPLY => { - handhsake_history.add_new_handshake(peer_pubkey, "".to_string(), ip); - } - _ => {} - } + println!("handshake JULIUS added"); + handhsake_history.add_new_handshake(peer_pubkey, "".to_string(), ip); let signature: [u8; SIGNATURE] = received_message [LENGTH + msg_length..LENGTH + msg_length + SIGNATURE] .try_into() @@ -194,14 +189,10 @@ pub fn parse_message( // Message handling let mut constructed_message: Option> = None; match msgtype { - // PING - // - // envoie un OK PING => { constructed_message = construct_message(OK, Vec::new(), id, crypto_pair); } - // - // OK + OK => { let mut guard = messages_list.lock().unwrap(); let res = guard.get(&id); @@ -216,9 +207,7 @@ pub fn parse_message( } } } - // - // rien ? - // si NATTRAVERSALREQUEST alors + NATTRAVERSALREQUEST => { // send ok & send nattraversalrequest2 to peer constructed_message = construct_message(OK, Vec::new(), id, crypto_pair); @@ -277,10 +266,7 @@ pub fn parse_message( ); constructed_message = None; } - // - // ERROR - // - // affiche un msg d'erreur + ERROR => { if let Ok(err_received) = String::from_utf8(received_message[LENGTH..(msg_length + LENGTH)].to_vec()) @@ -292,10 +278,7 @@ pub fn parse_message( let _ = cmd_tx_clone.send(NetworkEvent::Error(err_msg)); } } - // HELLO - // - // envoie une hello reply - // + HELLO => { let mut payload = Vec::new(); @@ -318,10 +301,7 @@ pub fn parse_message( return helloreply; } - // HELLOREPLY - // - // - // ajoute a la liste des peers handshake + HELLOREPLY => { // ajoute l'username a la liste des peers handshake let received_length = u16::from_be_bytes( @@ -365,13 +345,6 @@ pub fn parse_message( None => {} } } - // - // ROOTREQUEST - // - // envoie un root reply - // - // ROOTREPLY - // ROOTREPLY => { // recuperer le pseudo du peers ayant repondu let peers_exist = handhsake_history.get_peer_info_ip(ip.to_string()); @@ -422,16 +395,6 @@ pub fn parse_message( } } } - // - // DATUMREQUEST - // - // envoie le datum - // - // NODATUM - // - // affiche un msg d'erreur - // - // DATUM DATUM => { let mut guard = messages_list.lock().expect("Échec du verrouillage"); let res = guard.get(&id); @@ -461,65 +424,6 @@ pub fn parse_message( None => {} } } - // parcourt le directory recu ou le big directory et renvoie une DATUMREQUEST pour chaque - // directory ou big directory lu - // - // NATTRAVERSALREQUEST - // - // repond OK et envoie un NATTRAVERSALREQUEST2 au pair B - // - // NATTRAVERSALREQUEST2 - // - // envoie OK à S puis envoie un ping à S - - // PING - // - // envoie un OK - // - // OK - // - // si NATTRAVERSALREQUEST alors - // - // ERROR - // - // affiche un msg d'erreur - // - // HELLO - // - // envoie une hello reply - // - // HELLOREPLY - // - // envoie un root request - // - // ROOTREQUEST - // - // envoie un root reply - // - // ROOTREPLY - // - // envoie un datum request - // - // DATUMREQUEST - // - // envoie le datum - // - // NODATUM - // - // affiche un msg d'erreur - // - // DATUM - // - // parcourt le directory recu ou le big directory et renvoie une DATUMREQUEST pour chaque - // directory ou big directory lu - // - // NATTRAVERSALREQUEST - // - // repond OK et envoie un NATTRAVERSALREQUEST2 au pair B - // - // NATTRAVERSALREQUEST2 - // - // envoie OK à S puis envoie un ping à S _ => return None, }; constructed_message diff --git a/client-network/src/messages_channels.rs b/client-network/src/messages_channels.rs index e0a603e..8a90dda 100644 --- a/client-network/src/messages_channels.rs +++ b/client-network/src/messages_channels.rs @@ -7,6 +7,7 @@ use crate::message_handling::EventType; use crate::message_handling::handle_recevied_message; use crate::peers_refresh::HandshakeHistory; use crate::threads_handling::Worker; +use std::clone; use std::collections::{HashMap, HashSet}; use std::hash::Hash; use std::net::SocketAddr; @@ -261,15 +262,13 @@ pub fn start_retry_thread( pub fn start_receving_thread( shared_data: &mut P2PSharedData, cmd_tx: crossbeam_channel::Sender, - handshake_history: &Arc>, + handshake_history: Arc, ) { let sock_clone = shared_data.socket(); let cryptopair_clone = shared_data.cryptopair(); let senders_clone = shared_data.senders(); let messages_clone = shared_data.messages_list(); let servername_clone = shared_data.servername(); - - let handshake_clone = handshake_history.clone(); let thread = thread::spawn(move || { let mut buf = [0u8; 1024]; loop { @@ -286,7 +285,7 @@ pub fn start_receving_thread( &servername_clone, cmd_tx.clone(), src, - &handshake_clone, + handshake_history.clone(), ); } Err(e) => eprintln!("Erreur de réception: {}", e), diff --git a/client-network/src/peers_refresh.rs b/client-network/src/peers_refresh.rs index 9153fba..a8ea8db 100644 --- a/client-network/src/peers_refresh.rs +++ b/client-network/src/peers_refresh.rs @@ -1,6 +1,8 @@ // this class consists of a thread that will re send pings every time the first element // of the stack is at the correct unix time +pub use crate::message_handling::*; + use std::{ collections::{HashMap, VecDeque}, net::{AddrParseError, Ipv4Addr, SocketAddr}, @@ -11,7 +13,10 @@ use std::{ time::{self, Duration, SystemTime}, }; -use crate::{NetworkEvent, threads_handling::Worker}; +use crate::{ + NetworkEvent, cryptographic_signature::CryptographicSignature, + messages_channels::MultipleSenders, threads_handling::Worker, +}; use crate::{ P2PSharedData, construct_message, generate_id, messages_structure, registration::perform_handshake, @@ -26,59 +31,35 @@ pub struct PeerInfo { pub ip: SocketAddr, } +#[derive(Debug, Clone)] pub struct HandshakeHistory { - //time_k_ip_v: HashMap, - username_k_peerinfo_v: HashMap, - ip_k_peerinfo_v: HashMap, + pub username_k_peerinfo_v: Arc>>, + ip_k_peerinfo_v: Arc>>, } impl HandshakeHistory { pub fn new() -> HandshakeHistory { HandshakeHistory { - //time_k_ip_v: HashMap::new(), - //ip_k_peerinfo_v: HashMap::new(), - username_k_peerinfo_v: HashMap::new(), - ip_k_peerinfo_v: HashMap::new(), + username_k_peerinfo_v: Arc::new(Mutex::new(HashMap::new())), + ip_k_peerinfo_v: Arc::new(Mutex::new(HashMap::new())), } } - /*pub fn update_handshake(&self) { - let hashmap_shared = Arc::new(self.username_k_peerinfo_v); - thread::spawn(move || { - let selfhashmap = hashmap_shared.clone(); - loop { - for peer in selfhashmap.keys() { - let peer_ip = selfhashmap.get(peer); - // send ping - } - let mut child = Command::new("sleep").arg("10").spawn().unwrap(); - let _result = child.wait().unwrap(); - } - }); - }*/ + pub fn get_peer_info_username(&self, username: String) -> Option { + //self.username_k_peerinfo_v.get(&username).clone() - pub fn get_peer_info_username(&self, username: String) -> Option<&PeerInfo> { - self.username_k_peerinfo_v.get(&username).clone() + let guard = self.username_k_peerinfo_v.lock().unwrap(); + + guard.get(&username).cloned() } - pub fn get_peer_info_ip(&self, ip: String) -> Option<&PeerInfo> { - self.ip_k_peerinfo_v.get(&ip).clone() + pub fn get_peer_info_ip(&self, ip: String) -> Option { + let guard = self.ip_k_peerinfo_v.lock().unwrap(); + + guard.get(&ip).cloned() } - pub fn update_handshake(&self) -> Worker { - let map_clone: Arc> = - Arc::new(self.username_k_peerinfo_v.clone()); - let map_for_thread = Arc::clone(&map_clone); - let handle = thread::spawn(move || { - loop { - for (peer, peerinfo) in map_for_thread.iter() {} - thread::sleep(Duration::from_secs(10)); - } - }); - Worker::spawn(handle, crate::threads_handling::WorkerType::PING) - } - - pub fn update_peer_info(&mut self, ip: String, username: String) { + pub fn update_peer_info(&self, ip: String, username: String) { let peerinfo = self.get_peer_info_ip(ip.clone()); match peerinfo { Some(peer_info) => match ip.parse::() { @@ -88,8 +69,18 @@ impl HandshakeHistory { pubkey: peer_info.pubkey, ip: addr, }; - self.ip_k_peerinfo_v.insert(ip, new_peer_info.clone()); - self.username_k_peerinfo_v.insert(username, new_peer_info); + let mut guardb = self.ip_k_peerinfo_v.lock().unwrap(); + guardb.insert(ip.to_string(), new_peer_info.clone()); + let mut guard = self.username_k_peerinfo_v.lock().unwrap(); + + guard.insert(username.to_string(), new_peer_info); + + println!( + "handshake added: {}, {}, {}", + username.to_string(), + ip.to_string(), + guard.len(), + ); } Err(e) => eprintln!("parse error: {}", e), }, @@ -99,43 +90,56 @@ impl HandshakeHistory { } } - pub fn add_new_handshake(&mut self, hash: VerifyingKey, username: String, ip: SocketAddr) { + pub fn add_new_handshake(&self, hash: VerifyingKey, username: String, ip: SocketAddr) { let peerinfo = PeerInfo { username: username.clone(), pubkey: hash, ip, }; - self.username_k_peerinfo_v - .insert(username, peerinfo.clone()); - self.ip_k_peerinfo_v - .insert(ip.to_string(), peerinfo.clone()); + let mut guard = self.username_k_peerinfo_v.lock().unwrap(); + guard.insert(username, peerinfo.clone()); + let mut guardb = self.ip_k_peerinfo_v.lock().unwrap(); + guardb.insert(ip.to_string(), peerinfo.clone()); } } -pub fn perform_discover( - username: String, - hash: String, - sd: &P2PSharedData, - server_ip: String, - event_tx: Sender, -) { - // first, sends handshake - if hash == "root" { - perform_handshake(sd, username, server_ip, event_tx, false); - /*if let Some(data) = construct_message( - messages_structure::ROOTREQUEST, - Vec::new(), - generate_id(), - sd.cryptopair_ref(), - ) { - if let Some(peerinfo) = sd.handshake_ref() { - sd.senders_ref() - .send_via(0, data, peerinfo.ip.to_string(), false); +pub fn update_handshake( + senders: Arc, + crypto_pair: Arc, + messages_list: Arc>>, + username_k_peerinfo_v: Arc>>, +) -> Worker { + let map_for_thread = username_k_peerinfo_v.clone(); + let handle = thread::spawn(move || { + loop { + println!("loop boucle"); + let guard = map_for_thread.lock().unwrap(); + println!("len:{}", guard.len()); + for (peer, peerinfo) in guard.iter() { + let id = generate_id(); + let mut map = messages_list.lock().unwrap(); + map.insert(id, EventType::Ping); + drop(map); + let pingrequest = construct_message(PING, Vec::new(), id, &crypto_pair); + if let Some(ping) = pingrequest { + senders.add_message_to_retry_queue( + ping.clone(), + peerinfo.ip.to_string(), + false, + ); + senders.send_dispatch( + ping, + peerinfo.ip.to_string(), + false, + messages_list.clone(), + ); + println!("ping envoye a {}", peer); + } } - }*/ - } else { - // envoyer un datum request - } + thread::sleep(Duration::from_secs(2)); + } + }); + Worker::spawn(handle, crate::threads_handling::WorkerType::PING) } #[cfg(test)] diff --git a/client-network/src/registration.rs b/client-network/src/registration.rs index 69035a2..0efd8e6 100644 --- a/client-network/src/registration.rs +++ b/client-network/src/registration.rs @@ -71,6 +71,12 @@ pub async fn perform_handshake( payload.extend_from_slice(&0u32.to_be_bytes()); payload.extend_from_slice(&crypto_pair.username.clone().as_bytes()); let hello_handshake = construct_message(1, payload, id, crypto_pair); + if is_server_handshake { + sd.add_message(id, EventType::Hello); + } else { + sd.add_message(id, EventType::HelloThenRootRequest); + } + match hello_handshake { Some(handshake_message) => { senders.send_dispatch( diff --git a/todo.md b/todo.md index d5d7193..6071fbc 100644 --- a/todo.md +++ b/todo.md @@ -1,58 +1,25 @@ # Todo -## peer discovery +## bugfix -## handshake +- ajouter hello et nat a l'exp backoff OK +- peers n'ayant pas d'adresse OK +- verifier le refresh des peers -# Todo - -## peer discovery - -- get rsquest to the uri /peers/ - -## registration with the server - -- generation of the cryptographic key OK -- put request to the uri (check if the peer is already connected) OK -- udp handshakes OK -- get request to the uri /peers/key to get the public key of a peer OK -- get request to the uri /peers/key/addresses OK - -## handshake - -- handshake structure OK - -- 5min timeout after handshake -- matain connection every 4 min - -## data transfer - -- request structure -- root/root reply structure -- datum/nodatum and datum structures -- nattraversal 1 and 2 structures - setting in gui to act as a relay -- chunk, directory, big, bigdirectory structures - -## fonctionnalités application - -## nat traversal - make hello and helloreply messages set the first extension bit to announce that peer is available for nat traversal - implement actual nat traversal requests - implement nat traversal : - - if hello/helloreply doesnt work with a peer, find a peer that supports nat traversal (server in priority) then begin protocol + - if hello/helloreply doesnt work with a peer, find a peer that supports nat traversal (server in priority) then begin protocol -fonctionnalités : +## fonctionnalités : rechercher les fichiers d'un pair telechargement des fichiers choisir un dossier à partager choisir le nombre de canaux -handshake server DOING -se deconnecter du réseau DOING - ## autre socket ipv6 @@ -71,3 +38,9 @@ socket ipv6 - generer une clé publique OK - verifier signature OK - 2 channels -> un pour envoyer et un pour recevoir OK +- get rsquest to the uri /peers/ OK +- request structure +- root/root reply structure +- datum/nodatum and datum structures +- nattraversal 1 and 2 structures +- chunk, directory, big, bigdirectory structures