use crate::{ NetworkEvent, NodeHash, cryptographic_signature::{ CryptographicSignature, get_peer_key, sign_message, verify_signature, }, messages_channels::MultipleSenders, messages_structure::construct_message, peers_refresh::HandshakeHistory, registration, server_communication::generate_id, }; use std::{collections::HashMap, net::SocketAddr}; use std::{ net::IpAddr, sync::{Arc, Mutex}, }; pub enum EventType { SendRootRequest, } const ID: usize = 4; const TYPE: usize = 5; const LENGTH: usize = 7; const EXTENSIONS: usize = 4; const SIGNATURE: usize = 64; const PING: u8 = 0; const OK: u8 = 128; const ERROR: u8 = 129; const HELLO: u8 = 1; const HELLOREPLY: u8 = 130; const ROOTREQUEST: u8 = 2; const ROOTREPLY: u8 = 131; const DATUMREQUEST: u8 = 3; const NODATUM: u8 = 133; const DATUM: u8 = 132; const NATTRAVERSALREQUEST: u8 = 4; const NATTRAVERSALREQUEST2: u8 = 5; pub fn handle_recevied_message( messages_list: &Arc>>, recevied_message: &Vec, crypto_pair: &CryptographicSignature, //socket_addr: &SocketAddr, senders: &MultipleSenders, server_name: &String, cmd_tx: crossbeam_channel::Sender, ip: SocketAddr, handhsake_history: &Arc>, ) { if recevied_message.len() < 4 { return; } // Basic safety check let message_id: [u8; 4] = recevied_message[0..4].try_into().expect("size error"); let id = i32::from_be_bytes(message_id); let mut is_resp_to_server_handshake = false; if recevied_message[4] == HELLO { let length_bytes: [u8; 2] = recevied_message[TYPE..LENGTH] .try_into() .expect("Taille incorrecte"); let msg_length = u16::from_be_bytes(length_bytes) as usize; let ilength = u16::from_be_bytes(length_bytes); let received_name = &recevied_message[LENGTH + EXTENSIONS..LENGTH + ilength as usize]; let name = String::from_utf8(received_name.to_vec()).expect("wrong name"); if name.clone() == server_name.clone() { is_resp_to_server_handshake = true; } } let resp = parse_message( recevied_message.to_vec(), id, crypto_pair, cmd_tx, ip, messages_list, handhsake_history, senders, ); match resp { None => {} Some(resp_msg) => { println!("msg_sent:{:?}", resp_msg); senders.send_via( 0, resp_msg, ip.to_string(), is_resp_to_server_handshake, messages_list, ); } } // Lock the mutex to access the HashMap /*let list = messages_list.lock().unwrap(); let eventtype = list.get(&id); // Clone the enum so we can release the lock if needed match eventtype { Some(EventType::ServerHelloReply) => { /*registration::register_ip_addresses( crypto_pair, socket_addr.to_string(), senders, &messages_list, // Pass the mutable reference inside the lock 546, );*/ } Some(_) => print!("Not implemented"), None => { let message_type = recevied_message[4]; // Handle handshake if message_type == 1 { let mut resp_to_serv = false; println!("verify the signature"); let parsed_received_message = HandshakeMessage::parse(recevied_message.to_vec()); let received_name = String::from_utf8(parsed_received_message.name).expect("error"); let peer_pubkey = tokio::runtime::Runtime::new() .unwrap() .block_on(get_peer_key(&received_name)) .expect("failed to retrieve public key"); if received_name == server_name.to_string() { resp_to_serv = true; } if !verify_signature(peer_pubkey, recevied_message) { println!( "incorrect signature from given peer: {}, ignoring message {}", &received_name, id ); } else { // verify if this is a server handshake request let username_size = crypto_pair.username.len(); let hello_handshake = HandshakeMessage::helloReply( id as u32, username_size as u16 + 4, crypto_pair.username.clone(), ); //HandshakeMessage::display(&hello_handshake); let hello_handshake_serialized = hello_handshake.serialize(); let message_signed = sign_message(crypto_pair, &hello_handshake_serialized); senders.send_via(0, message_signed, socket_addr.to_string(), resp_to_serv); let mut list = messages_list.lock().expect("Failed to lock messages_list"); match list.get(&id) { Some(_) => { list.remove(&id); } None => { list.insert(id, EventType::ServerHelloReply); } } } } print!("Message not found for ID: {}", id) } }*/ } pub fn parse_message( received_message: Vec, id: i32, crypto_pair: &CryptographicSignature, cmd_tx: crossbeam_channel::Sender, ip: SocketAddr, messages_list: &Arc>>, handhsake_history_mutex: &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] .try_into() .expect("Taille incorrecte"); let msgtype = received_message[ID]; let length_bytes: [u8; 2] = received_message[TYPE..LENGTH] .try_into() .expect("Taille incorrecte"); let msg_length = u16::from_be_bytes(length_bytes) as usize; // verify signature match msgtype { HELLO | HELLOREPLY | NODATUM | NATTRAVERSALREQUEST | NATTRAVERSALREQUEST2 => { let ilength = u16::from_be_bytes(length_bytes); println!("name received length: {}", ilength); let received_name = &received_message[LENGTH + EXTENSIONS..LENGTH + ilength as usize]; let received_username = String::from_utf8(received_name.to_vec()); match received_username { Ok(username) => { let peer_pubkey = match handhsake_history.get_peer_info_username(username.clone()) { Some(peerinfo) => peerinfo.pubkey, _ => tokio::runtime::Runtime::new() .unwrap() .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); } _ => {} } let signature: [u8; SIGNATURE] = received_message [LENGTH + msg_length..LENGTH + msg_length + SIGNATURE] .try_into() .expect("Taille incorrecte"); if !verify_signature(peer_pubkey, &received_message) { println!( "incorrect signature from given peer: {}, ignoring message of type {} with id {}", &username, received_message[ID], id ); return None; } } Err(e) => { println!("incorrect name: {}", e); return None; } } } ROOTREPLY => { let ilength = u16::from_be_bytes(length_bytes); println!("name received length: {}", ilength); if let Some(peerinfo) = handhsake_history.get_peer_info_ip(ip.to_string()) { if !verify_signature(peerinfo.pubkey, &received_message) { println!( "incorrect signature from given peer: {}, ignoring message of type {} with id {}", &peerinfo.username, received_message[ID], id ); return None; } else { println!("signature verified"); } } } _ => {} } // 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 // // rien ? // si NATTRAVERSALREQUEST alors NATTRAVERSALREQUEST => { // send ok & send nattraversalrequest2 to peer constructed_message = construct_message(OK, Vec::new(), id, crypto_pair); let ilength = u16::from_be_bytes(length_bytes); let received_address = &received_message[LENGTH + EXTENSIONS..LENGTH + ilength as usize]; let address = String::from_utf8(received_address.to_vec()).expect("wrong name"); let natreq2 = construct_message( NATTRAVERSALREQUEST2, ip.to_string().into_bytes(), id, crypto_pair, ); senders.send_via( 0, natreq2.expect("couldnt construct message nattraversalrequest2"), address, false, &messages_list, ); } NATTRAVERSALREQUEST2 => { // send ok & send ping to peer constructed_message = construct_message(OK, Vec::new(), id, crypto_pair); let ilength = u16::from_be_bytes(length_bytes); let received_address = &received_message[LENGTH..LENGTH + ilength as usize]; let address = String::from_utf8(received_address.to_vec()).expect("wrong name"); let pingreq = construct_message(PING, Vec::new(), id, crypto_pair); senders.send_via( 0, pingreq.expect("couldnt construct message ping request"), address, false, &messages_list, ); } // // ERROR // // affiche un msg d'erreur ERROR => { if let Ok(err_received) = String::from_utf8(received_message[LENGTH..(msg_length + LENGTH)].to_vec()) { let err_msg = format!("Error received from peer {} : {}", ip, err_received); let _ = cmd_tx_clone.send(NetworkEvent::Error(err_msg)); } else { let err_msg = format!("Error received from peer {} : N/A", ip,); let _ = cmd_tx_clone.send(NetworkEvent::Error(err_msg)); } } // HELLO // // envoie une hello reply // HELLO => { let mut payload = Vec::new(); payload.extend_from_slice(&0u32.to_be_bytes()); payload.extend_from_slice(&crypto_pair.username.clone().as_bytes()); let helloreply = construct_message(HELLOREPLY, payload, id, crypto_pair); 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( received_message[TYPE..LENGTH] .try_into() .expect("incorrect size"), ); let received_username = &received_message[LENGTH + EXTENSIONS..LENGTH + received_length as usize]; handhsake_history.update_peer_info( ip.to_string(), String::from_utf8(received_username.to_vec()).expect("invalid conversion"), ); // verifie s'il faut renvoyer un root request let guard = messages_list.lock().expect("Échec du verrouillage"); let res = guard.get(&id); match res { Some(ev) => { match ev { EventType::SendRootRequest => { // envoyer la root request let rootrequest = construct_message( ROOTREQUEST, Vec::new(), generate_id(), crypto_pair, ); return rootrequest; } } } 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()); match peers_exist { Some(peerinfo) => { // envoyer le hash a la gui let received_hash: NodeHash = received_message[LENGTH..(32 + LENGTH)] .try_into() .expect("incorrect size"); let res = cmd_tx_clone.send(NetworkEvent::FileTreeRootReceived( peerinfo.username.clone(), received_hash, )); println!("file tree sent") } None => { eprintln!("no peers found"); } } } // // 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 // 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 }