8 Commits

Author SHA1 Message Date
TIBERGHIEN corentin
c852c5bb4a root request 2026-01-13 17:13:35 +01:00
98fcc1a0b2 wip handling root request 2026-01-13 02:32:48 +01:00
8e279d9e24 wip datum 2026-01-11 22:12:08 +01:00
TIBERGHIEN corentin
92f38c9c12 fix name length issue 2026-01-10 20:34:51 +01:00
TIBERGHIEN corentin
489669b93d wip messages creation & handling 2026-01-09 20:09:39 +01:00
9fc33804d0 manage handshake wiip 2026-01-09 01:03:40 +01:00
TIBERGHIEN corentin
cd2f87cb81 wip 2026-01-08 19:12:07 +01:00
dc1767abe4 messages rewrite 2026-01-07 23:34:44 +01:00
12 changed files with 982 additions and 404 deletions

BIN
README.md

Binary file not shown.

View File

@@ -1,5 +1,5 @@
use client_network::{ use client_network::{
MerkleNode, MerkleTree, NetworkCommand, NetworkEvent, NodeHash, filename_to_string, ChunkNode, MerkleNode, MerkleTree, NetworkCommand, NetworkEvent, NodeHash, filename_to_string,
node_hash_to_hex_string, node_hash_to_hex_string,
}; };
use crossbeam_channel::{Receiver, Sender}; use crossbeam_channel::{Receiver, Sender};
@@ -27,7 +27,7 @@ pub struct P2PClientApp {
// GUI State // GUI State
status_message: String, status_message: String,
known_peers: Vec<(String, bool)>, known_peers: Vec<String>,
connect_address_input: String, connect_address_input: String,
connected_address: String, connected_address: String,
connect_name_input: String, connect_name_input: String,
@@ -49,11 +49,11 @@ pub struct P2PClientApp {
impl P2PClientApp { impl P2PClientApp {
pub fn new(cmd_tx: Sender<NetworkCommand>, event_rx: Receiver<NetworkEvent>) -> Self { pub fn new(cmd_tx: Sender<NetworkCommand>, event_rx: Receiver<NetworkEvent>) -> Self {
let (root_hash, tree_content) = MerkleNode::generate_base_tree(); //let (root_hash, tree_content) = MerkleNode::generate_base_tree();
let mut loaded_fs = HashMap::new(); let mut loaded_fs = HashMap::new();
let tree = MerkleTree::new(tree_content, root_hash); //let tree = MerkleTree::new(tree_content, root_hash);
loaded_fs.insert("bob".to_string(), tree); //loaded_fs.insert("bob".to_string(), tree);
Self { Self {
remaining: std::time::Duration::from_secs(0), remaining: std::time::Duration::from_secs(0),
@@ -62,7 +62,7 @@ impl P2PClientApp {
network_cmd_tx: cmd_tx, network_cmd_tx: cmd_tx,
network_event_rx: event_rx, network_event_rx: event_rx,
status_message: "Client Initialized. Awaiting network status...".to_string(), status_message: "Client Initialized. Awaiting network status...".to_string(),
known_peers: vec![("bob".to_string(), true)], known_peers: vec!["bob".to_string()],
connect_address_input: "https://jch.irif.fr:8443".to_string(), connect_address_input: "https://jch.irif.fr:8443".to_string(),
connected_address: "".to_string(), connected_address: "".to_string(),
loaded_fs, loaded_fs,
@@ -111,8 +111,8 @@ impl eframe::App for P2PClientApp {
todo!(); todo!();
self.status_message = format!("✅ Peer connected: {}", addr); self.status_message = format!("✅ Peer connected: {}", addr);
if !self.known_peers.contains(&(addr, true)) { if !self.known_peers.contains(&addr) {
self.known_peers.push((addr, true)); self.known_peers.push(addr);
} }
} }
NetworkEvent::PeerListUpdated(peers) => { NetworkEvent::PeerListUpdated(peers) => {
@@ -123,23 +123,41 @@ impl eframe::App for P2PClientApp {
NetworkEvent::FileTreeReceived(_peer_id, _) => { NetworkEvent::FileTreeReceived(_peer_id, _) => {
todo!(); todo!();
// self.loaded_tree_nodes.insert(_peer_id, tree); //self.loaded_tree_nodes.insert(_peer_id, tree);
self.status_message = "🔄 File tree updated successfully.".to_string(); //self.status_message = "🔄 File tree updated successfully.".to_string();
} }
NetworkEvent::FileTreeRootReceived(peer_id, root_hash) => { NetworkEvent::FileTreeRootReceived(peer_id, root_hash) => {
todo!(); // todo!();
// self.status_message = format!("🔄 Received Merkle Root from {}: {}", peer_id, &root_hash[..8]); /*self.status_message = format!(
// "🔄 Received Merkle Root from {}: {}",
// peer_id,
// self.active_peer_id = Some(peer_id.clone()); &root_hash[..8]
// );*/
//
// // Request the content of the root directory immediately if let Ok(chunknode) = ChunkNode::new(Vec::new()) {
// let _ = self.network_cmd_tx.send(NetworkCommand::RequestDirectoryContent( let mut data_map: HashMap<NodeHash, MerkleNode> = HashMap::new();
// peer_id, data_map.insert(root_hash, MerkleNode::Chunk(chunknode));
// root_hash, let tree = MerkleTree {
// )); data: data_map,
root: root_hash,
};
match &self.active_peer {
Some(activepeer) => {
self.loaded_fs.insert(activepeer.clone(), tree);
}
None => {}
}
println!("tree created");
}
//self.active_peer_id = Some(peer_id.clone());
// Request the content of the root directory immediately
/*let _ = self
.network_cmd_tx
.send(NetworkCommand::RequestDirectoryContent(peer_id, root_hash));*/
} }
NetworkEvent::Connected(ip) => { NetworkEvent::Connected(ip) => {
self.server_status = ServerStatus::Connected; self.server_status = ServerStatus::Connected;
@@ -301,7 +319,7 @@ impl eframe::App for P2PClientApp {
ui.label("No connection.."); ui.label("No connection..");
} }
ServerStatus::ConnectedHandshake => { ServerStatus::ConnectedHandshake => {
let str = format!("📡 {}", self.active_server); let str = format!("📡");
ui.label(str); ui.label(str);
} }
} }
@@ -344,7 +362,14 @@ impl eframe::App for P2PClientApp {
for peer in &self.known_peers { for peer in &self.known_peers {
let is_active = let is_active =
self.active_peer.as_ref().map_or(false, |id| id == peer); // if peer.id == self.active_peer_id self.active_peer.as_ref().map_or(false, |id| id == peer); // if peer.id == self.active_peer_id
let selectable = ui.selectable_label(is_active, format!("{}", peer));
let selectable;
if &self.active_server == peer {
selectable =
ui.selectable_label(is_active, format!("{} 📡 🌀", peer))
} else {
selectable = ui.selectable_label(is_active, format!("{}", peer));
}
if selectable.clicked() { if selectable.clicked() {
// switch to displaying this peer's tree // switch to displaying this peer's tree
self.active_peer = Some(peer.clone()); self.active_peer = Some(peer.clone());
@@ -353,11 +378,12 @@ impl eframe::App for P2PClientApp {
.loaded_fs .loaded_fs
.contains_key(self.active_peer.as_ref().unwrap()) .contains_key(self.active_peer.as_ref().unwrap())
{ {
todo!(); //todo!();
// let _ = self.network_cmd_tx.send(NetworkCommand::RequestDirectoryContent( let _ = self.network_cmd_tx.send(NetworkCommand::Discover(
// peer.clone(), peer.clone(),
// peer.clone(), "root".to_string(),
// )); self.connected_address.clone(),
));
} }
} }
selectable.context_menu(|ui| { selectable.context_menu(|ui| {
@@ -501,7 +527,13 @@ impl P2PClientApp {
entry.content_hash, entry.content_hash,
tree, tree,
depth + 1, depth + 1,
Some(entry.filename), Some(
entry
.filename
.as_slice()
.try_into()
.expect("incorrect size"),
),
); );
} }
}); });
@@ -522,7 +554,7 @@ impl P2PClientApp {
.enabled(true) .enabled(true)
.show(ui, |ui| { .show(ui, |ui| {
for child in &node.children_hashes { for child in &node.children_hashes {
self.draw_file_node(ui, child.clone(), tree, depth + 1, None); self.draw_file_node(ui, child.content_hash, tree, depth + 1, None);
} }
}); });
} }

View File

@@ -1,6 +1,5 @@
use std::io::Read; use std::io::Read;
use crate::messages_structure::HandshakeMessage;
use bytes::Bytes; use bytes::Bytes;
use p256::EncodedPoint; use p256::EncodedPoint;
use p256::ecdsa::{ use p256::ecdsa::{
@@ -109,11 +108,10 @@ pub fn sign_message(crypto_pair: &CryptographicSignature, message: &Vec<u8>) ->
let digest = Sha256::digest(&message[..7 + msg_length as usize]); let digest = Sha256::digest(&message[..7 + msg_length as usize]);
let signature = crypto_pair.priv_key.sign_prehash_recoverable(&digest); let signature = crypto_pair.priv_key.sign_prehash_recoverable(&digest);
let message_length = 12 + msg_length as usize + 32; let message_length = 7 + msg_length as usize + 64;
let mut signed_message = Vec::with_capacity(message_length); let mut signed_message = Vec::with_capacity(message_length);
println!("{}", message_length); println!("{}", message_length);
signed_message.extend_from_slice(&message[..8 + msg_length as usize]); signed_message.extend_from_slice(&message[..7 + msg_length as usize]);
signed_message.pop();
println!("signed_tmp:{:?}", signed_message); println!("signed_tmp:{:?}", signed_message);
match signature { match signature {
Ok(signature) => { Ok(signature) => {
@@ -124,7 +122,7 @@ pub fn sign_message(crypto_pair: &CryptographicSignature, message: &Vec<u8>) ->
let s_bytes = s.to_bytes(); let s_bytes = s.to_bytes();
signed_message.extend_from_slice(&r_bytes[..32]); signed_message.extend_from_slice(&r_bytes[..32]);
signed_message.extend_from_slice(&s_bytes[..32]); signed_message.extend_from_slice(&s_bytes[..32]);
println!("signed:{:?}", signed_message); println!("signed:{:?}, len: {}", signed_message, signed_message.len());
signed_message signed_message
} }
Err(e) => { Err(e) => {
@@ -148,10 +146,7 @@ mod tests {
println!("pubkey : {}", formatted_pubkey); println!("pubkey : {}", formatted_pubkey);
} }
/// /*#[test]
/// signs a message
///
#[test]
fn signing_message() { fn signing_message() {
let username = String::from("gamixtreize"); let username = String::from("gamixtreize");
let crypto_pair = CryptographicSignature::new(username.clone()); let crypto_pair = CryptographicSignature::new(username.clone());
@@ -160,5 +155,5 @@ mod tests {
let signed_message = sign_message(&crypto_pair, &ser); let signed_message = sign_message(&crypto_pair, &ser);
println!("unsigned_message: {:?}", ser); println!("unsigned_message: {:?}", ser);
println!("signed_message: {:?}", signed_message); println!("signed_message: {:?}", signed_message);
} }*/
} }

View File

@@ -80,7 +80,7 @@ impl MerkleTree {
} }
} }
fn generate_random_file_node( /*fn generate_random_file_node(
storage: &mut HashMap<NodeHash, MerkleNode>, storage: &mut HashMap<NodeHash, MerkleNode>,
) -> Result<NodeHash, String> { ) -> Result<NodeHash, String> {
let mut rng = rng(); let mut rng = rng();
@@ -110,9 +110,9 @@ fn generate_random_file_node(
storage.insert(hash, node); storage.insert(hash, node);
Ok(hash) Ok(hash)
} }
} }*/
fn generate_random_directory_node( /*fn generate_random_directory_node(
depth: u32, depth: u32,
max_depth: u32, max_depth: u32,
storage: &mut HashMap<NodeHash, MerkleNode>, storage: &mut HashMap<NodeHash, MerkleNode>,
@@ -172,7 +172,7 @@ fn generate_random_directory_node(
storage.insert(hash, node); storage.insert(hash, node);
Ok(hash) Ok(hash)
} }
} }*/
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ChunkNode { pub struct ChunkNode {
@@ -208,7 +208,7 @@ impl ChunkNode {
// Helper struct // Helper struct
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DirectoryEntry { pub struct DirectoryEntry {
pub filename: [u8; FILENAME_HASH_SIZE], pub filename: Vec<u8>,
pub content_hash: NodeHash, pub content_hash: NodeHash,
} }
@@ -240,7 +240,7 @@ pub struct BigNode {
} }
impl BigNode { impl BigNode {
pub fn new(children_hashes: Vec<NodeHash>) -> Result<Self, String> { /*pub fn new(children_hashes: Vec<NodeHash>) -> Result<Self, String> {
let n = children_hashes.len(); let n = children_hashes.len();
if n < MIN_BIG_CHILDREN || n > MAX_BIG_CHILDREN { if n < MIN_BIG_CHILDREN || n > MAX_BIG_CHILDREN {
return Err(format!( return Err(format!(
@@ -249,16 +249,17 @@ impl BigNode {
)); ));
} }
Ok(BigNode { children_hashes }) Ok(BigNode { children_hashes })
} }*/
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct BigDirectoryNode { pub struct BigDirectoryNode {
pub children_hashes: Vec<NodeHash>, //pub children_hashes: Vec<NodeHash>,
pub children_hashes: Vec<DirectoryEntry>,
} }
impl BigDirectoryNode { impl BigDirectoryNode {
pub fn new(children_hashes: Vec<NodeHash>) -> Result<Self, String> { /*pub fn new(children_hashes: Vec<NodeHash>) -> Result<Self, String> {
let n = children_hashes.len(); let n = children_hashes.len();
if n < MIN_BIG_CHILDREN || n > MAX_BIG_CHILDREN { if n < MIN_BIG_CHILDREN || n > MAX_BIG_CHILDREN {
return Err(format!( return Err(format!(
@@ -267,6 +268,14 @@ impl BigDirectoryNode {
)); ));
} }
Ok(BigDirectoryNode { children_hashes }) Ok(BigDirectoryNode { children_hashes })
}*/
pub fn new(entries: Vec<DirectoryEntry>) -> Result<Self, String> {
if entries.len() > MAX_DIRECTORY_ENTRIES {
return Err(format!("Directory exceeds {} bytes", entries.len()));
}
Ok(BigDirectoryNode {
children_hashes: entries,
})
} }
} }
@@ -301,14 +310,14 @@ impl MerkleNode {
} }
MerkleNode::BigDirectory(node) => { MerkleNode::BigDirectory(node) => {
for hash in &node.children_hashes { for hash in &node.children_hashes {
bytes.extend_from_slice(hash); bytes.extend_from_slice(&hash.content_hash);
} }
} }
} }
bytes bytes
} }
pub fn generate_random_tree( /*pub fn generate_random_tree(
max_depth: u32, max_depth: u32,
) -> Result<(NodeHash, HashMap<NodeHash, MerkleNode>), String> { ) -> Result<(NodeHash, HashMap<NodeHash, MerkleNode>), String> {
let mut storage = HashMap::new(); let mut storage = HashMap::new();
@@ -317,9 +326,9 @@ impl MerkleNode {
let root_hash = generate_random_directory_node(0, max_depth, &mut storage)?; let root_hash = generate_random_directory_node(0, max_depth, &mut storage)?;
Ok((root_hash, storage)) Ok((root_hash, storage))
} }*/
pub fn generate_base_tree() -> (NodeHash, HashMap<NodeHash, MerkleNode>) { /*pub fn generate_base_tree() -> (NodeHash, HashMap<NodeHash, MerkleNode>) {
let mut res = HashMap::new(); let mut res = HashMap::new();
let node1 = MerkleNode::Chunk(ChunkNode::new_random()); let node1 = MerkleNode::Chunk(ChunkNode::new_random());
@@ -369,5 +378,5 @@ impl MerkleNode {
res.insert(root_hash, root); res.insert(root_hash, root);
(root_hash, res) (root_hash, res)
} }*/
} }

View File

@@ -0,0 +1,96 @@
use crate::{BigDirectoryNode, DirectoryEntry, DirectoryNode, MerkleNode, MerkleTree, NodeHash};
use sha2::{Digest, Sha256};
const CHUNK: u8 = 0;
const DIRECTORY: u8 = 1;
const BIG: u8 = 2;
const BIGDIRECTORY: u8 = 3;
fn parse_received_datum(recevied_datum: Vec<u8>, datum_length: usize, mut tree: MerkleTree) {
if datum_length > recevied_datum.len() {
return;
}
if datum_length < 32 + 64 {
return;
}
let hash_name: [u8; 32] = recevied_datum[..32].try_into().expect("error");
let sigstart = datum_length - 64;
let value = &recevied_datum[32..sigstart];
let value_slice = value.to_vec();
let signature: [u8; 32] = recevied_datum[sigstart..datum_length]
.try_into()
.expect("Taille incorrecte");
let datum_type = value_slice[0];
match datum_type {
CHUNK => {
tree.data.insert(
hash_name,
MerkleNode::Chunk(crate::ChunkNode { data: value_slice }),
);
}
DIRECTORY => {
let nb_entries = value_slice[1];
let mut dir_entries = Vec::new();
let mut offset = 1 as usize;
for i in 0..nb_entries {
offset = (offset as u8 + 64 * i) as usize;
let name = &recevied_datum[offset..offset + 32];
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,
});
}
let current = DirectoryNode::new(dir_entries);
match current {
Ok(current_node) => {
tree.data
.insert(hash_name, MerkleNode::Directory(current_node));
}
Err(e) => {
println!("{}", e);
}
}
}
BIG => {
let chlidren: Vec<NodeHash> = Vec::new();
tree.data.insert(
hash_name,
MerkleNode::Big(crate::BigNode {
children_hashes: chlidren,
}),
);
}
BIGDIRECTORY => {
let nb_entries = value_slice[1];
let mut dir_entries = Vec::new();
let mut offset = 1 as usize;
for i in 0..nb_entries {
offset = (offset as u8 + 64 * i) as usize;
let name = &recevied_datum[offset..offset + 32];
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,
});
}
let current = BigDirectoryNode::new(dir_entries);
match current {
Ok(current_node) => {
tree.data
.insert(hash_name, MerkleNode::BigDirectory(current_node));
}
Err(e) => {
println!("{}", e);
}
}
}
_ => {}
}
}

View File

@@ -1,8 +1,10 @@
mod cryptographic_signature; mod cryptographic_signature;
mod data; mod data;
mod datum_parsing;
mod message_handling; mod message_handling;
mod messages_channels; mod messages_channels;
mod messages_structure; mod messages_structure;
mod peers_refresh;
mod registration; mod registration;
mod server_communication; mod server_communication;
@@ -10,8 +12,10 @@ use crate::{
cryptographic_signature::CryptographicSignature, cryptographic_signature::CryptographicSignature,
message_handling::EventType, message_handling::EventType,
messages_channels::{MultipleSenders, start_receving_thread}, messages_channels::{MultipleSenders, start_receving_thread},
messages_structure::{ROOTREQUEST, construct_message},
peers_refresh::HandshakeHistory,
registration::{ registration::{
get_socket_address, parse_addresses, register_ip_addresses, register_with_the_server, get_socket_address, parse_addresses, perform_handshake, register_with_the_server,
}, },
server_communication::{generate_id, get_peer_list}, server_communication::{generate_id, get_peer_list},
}; };
@@ -31,6 +35,7 @@ pub struct P2PSharedData {
shared_messageslist: Arc<Mutex<HashMap<i32, EventType>>>, shared_messageslist: Arc<Mutex<HashMap<i32, EventType>>>,
shared_senders: Arc<MultipleSenders>, shared_senders: Arc<MultipleSenders>,
server_name: Arc<Mutex<String>>, server_name: Arc<Mutex<String>>,
handshake_peers: Arc<HandshakeHistory>,
} }
impl P2PSharedData { impl P2PSharedData {
@@ -49,12 +54,14 @@ impl P2PSharedData {
let senders = MultipleSenders::new(1, &shared_socket, cmd_tx); let senders = MultipleSenders::new(1, &shared_socket, cmd_tx);
let shared_senders = Arc::new(senders); let shared_senders = Arc::new(senders);
let server_name = Arc::new(Mutex::new("".to_string())); let server_name = Arc::new(Mutex::new("".to_string()));
let handhsake_peers = Arc::new(HandshakeHistory::new());
Ok(P2PSharedData { Ok(P2PSharedData {
shared_socket: shared_socket, shared_socket: shared_socket,
shared_cryptopair: shared_cryptopair, shared_cryptopair: shared_cryptopair,
shared_messageslist: shared_messageslist, shared_messageslist: shared_messageslist,
shared_senders: shared_senders, shared_senders: shared_senders,
server_name: server_name, server_name: server_name,
handshake_peers: handhsake_peers,
}) })
} }
pub fn socket(&self) -> Arc<UdpSocket> { pub fn socket(&self) -> Arc<UdpSocket> {
@@ -85,6 +92,9 @@ impl P2PSharedData {
pub fn cryptopair_ref(&self) -> &CryptographicSignature { pub fn cryptopair_ref(&self) -> &CryptographicSignature {
&*self.shared_cryptopair &*self.shared_cryptopair
} }
pub fn handshake_ref(&self) -> &HandshakeHistory {
&*self.handshake_peers
}
pub fn messages_list_ref(&self) -> &Mutex<HashMap<i32, EventType>> { pub fn messages_list_ref(&self) -> &Mutex<HashMap<i32, EventType>> {
&*self.shared_messageslist &*self.shared_messageslist
@@ -113,6 +123,8 @@ pub enum NetworkCommand {
RequestChunk(String, String), RequestChunk(String, String),
Disconnect(), Disconnect(),
ResetServerPeer(), ResetServerPeer(),
Discover(String, String, String),
GetChildren(String, String),
// ... // ...
} }
@@ -123,10 +135,10 @@ pub enum NetworkEvent {
Disconnected(), Disconnected(),
Error(String), Error(String),
PeerConnected(String), PeerConnected(String),
PeerListUpdated(Vec<(String, bool)>), PeerListUpdated(Vec<String>),
FileTreeReceived(String, Vec<MerkleNode>), // peer_id, content FileTreeReceived(String, Vec<MerkleNode>), // peer_id, content
DataReceived(String, MerkleNode), DataReceived(String, MerkleNode),
FileTreeRootReceived(String, String), FileTreeRootReceived(String, NodeHash),
HandshakeFailed(), HandshakeFailed(),
ServerHandshakeFailed(String), ServerHandshakeFailed(String),
// ... // ...
@@ -161,6 +173,8 @@ pub fn start_p2p_executor(
// Use tokio to spawn the asynchronous networking logic // Use tokio to spawn the asynchronous networking logic
tokio::task::spawn(async move { tokio::task::spawn(async move {
// P2P/Networking Setup goes here // P2P/Networking Setup goes here
let handshake_history = Arc::new(Mutex::new(HandshakeHistory::new()));
let handshake_clone = handshake_history.clone();
println!("Network executor started."); println!("Network executor started.");
@@ -170,61 +184,13 @@ pub fn start_p2p_executor(
if let Ok(cmd) = cmd_rx.try_recv() { if let Ok(cmd) = cmd_rx.try_recv() {
match cmd { match cmd {
NetworkCommand::ServerHandshake(username, ip) => { NetworkCommand::ServerHandshake(username, ip) => {
println!("server handshake called");
if let Some(sd) = shared_data.as_ref() { if let Some(sd) = shared_data.as_ref() {
println!("username:{}, ip:{}", username, ip); start_receving_thread(sd, event_tx.clone(), &handshake_clone);
let server_addr_query = get_socket_address(username.clone(), ip); let res =
perform_handshake(&sd, username, ip, event_tx.clone(), true).await;
match server_addr_query.await { } else {
Ok(sockaddr_bytes) => { println!("no shared data");
match String::from_utf8(sockaddr_bytes.to_vec()) {
Ok(s) => {
let addresses = parse_addresses(&s);
if let Some(first) = addresses.first() {
sd.set_servername(username);
// first: &SocketAddr
start_receving_thread(
sd,
*first, // copie le SocketAddr (implémente Copy pour SocketAddr)
);
register_ip_addresses(
sd.cryptopair_ref(),
first.to_string(),
sd.senders_ref(),
sd.messages_list_ref(),
generate_id(),
);
//let res = event_tx
// .send(NetworkEvent::());
} else {
//let res = event_tx.send(NetworkEvent::Error());
let err_msg = format!(
"no valid socket addresses found in: {}",
s
)
.to_string();
let res =
event_tx.send(NetworkEvent::Error(err_msg));
}
}
Err(e) => {
//let res = event_tx.send(NetworkEvent::Error());
let err_msg = format!(
"invalid UTF-8 in socket address bytes: {}",
e
)
.to_string();
let res = event_tx.send(NetworkEvent::Error(err_msg));
}
}
}
Err(e) => {
let err_msg =
format!("failed to retreive socket address: {}", e)
.to_string();
let res = event_tx.send(NetworkEvent::Error(err_msg));
}
}
} }
} }
NetworkCommand::ConnectPeer(addr) => { NetworkCommand::ConnectPeer(addr) => {
@@ -237,6 +203,56 @@ pub fn start_p2p_executor(
NetworkCommand::RequestFileTree(_) => { NetworkCommand::RequestFileTree(_) => {
println!("[Network] RequestFileTree() called"); println!("[Network] RequestFileTree() called");
} }
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()
};
match res {
Some(peerinfo) => {
// envoyer un root request
let rootrequest = construct_message(
ROOTREQUEST,
Vec::new(),
generate_id(),
sd.cryptopair_ref(),
);
match rootrequest {
None => {}
Some(resp_msg) => {
println!("msg_sent:{:?}", resp_msg);
sd.senders_ref().send_via(
0,
resp_msg,
peerinfo.ip.to_string(),
false,
sd.messages_list_ref(),
);
}
}
}
None => {
// envoyer un handshake
let res = perform_handshake(
&sd,
username,
ip,
event_tx.clone(),
false,
)
.await;
}
}
} else {
println!("no shared data");
}
}
NetworkCommand::GetChildren(username, hash) => {
// envoie un datum request au peer
}
NetworkCommand::RequestDirectoryContent(_, _) => { NetworkCommand::RequestDirectoryContent(_, _) => {
println!("[Network] RequestDirectoryContent() called"); println!("[Network] RequestDirectoryContent() called");
} }
@@ -292,7 +308,7 @@ pub fn start_p2p_executor(
match get_peer_list(ip).await { match get_peer_list(ip).await {
Ok(body) => match String::from_utf8(body.to_vec()) { Ok(body) => match String::from_utf8(body.to_vec()) {
Ok(peers_list) => { Ok(peers_list) => {
let mut peers: Vec<(String, bool)> = Vec::new(); let mut peers: Vec<String> = Vec::new();
let mut current = String::new(); let mut current = String::new();
for i in peers_list.chars() { for i in peers_list.chars() {
if i == '\n' { if i == '\n' {

View File

@@ -1,52 +1,53 @@
use crate::{ use crate::{
NetworkEvent, NetworkEvent, NodeHash,
cryptographic_signature::{ cryptographic_signature::{
CryptographicSignature, get_peer_key, sign_message, verify_signature, CryptographicSignature, get_peer_key, sign_message, verify_signature,
}, },
messages_channels::MultipleSenders, messages_channels::MultipleSenders,
messages_structure::HandshakeMessage, messages_structure::construct_message,
peers_refresh::HandshakeHistory,
registration, registration,
server_communication::generate_id,
}; };
use std::sync::{Arc, Mutex};
use std::{collections::HashMap, net::SocketAddr}; use std::{collections::HashMap, net::SocketAddr};
use std::{
net::IpAddr,
sync::{Arc, Mutex},
};
pub enum EventType { pub enum EventType {
ServerHelloReply, SendRootRequest,
PeerHelloReply,
PeerHello,
} }
/*pub fn handle_recevied_message( const ID: usize = 4;
messages_list: &mut HashMap<i32, EventType>, const TYPE: usize = 5;
recevied_message: &Vec<u8>, const LENGTH: usize = 7;
crypto_pair: &CryptographicSignature, const EXTENSIONS: usize = 4;
socket_addr: &SocketAddr, const SIGNATURE: usize = 64;
senders: &MultipleSenders,
) { const PING: u8 = 0;
let message_id: [u8; 4] = recevied_message[0..4].try_into().expect("size error"); const OK: u8 = 128;
let id = i32::from_be_bytes(message_id); const ERROR: u8 = 129;
let eventtype = messages_list.get(&id); const HELLO: u8 = 1;
match eventtype { const HELLOREPLY: u8 = 130;
Some(EventType::ServerHelloReply) => { const ROOTREQUEST: u8 = 2;
registration::register_ip_addresses( const ROOTREPLY: u8 = 131;
&crypto_pair, const DATUMREQUEST: u8 = 3;
socket_addr.ip().to_string(), const NODATUM: u8 = 133;
&senders, const DATUM: u8 = 132;
messages_list, const NATTRAVERSALREQUEST: u8 = 4;
); const NATTRAVERSALREQUEST2: u8 = 5;
}
Some(_) => print!("Not implemented"),
None => print!("Message not found"),
}
}*/
pub fn handle_recevied_message( pub fn handle_recevied_message(
messages_list: &Arc<Mutex<HashMap<i32, EventType>>>, messages_list: &Arc<Mutex<HashMap<i32, EventType>>>,
recevied_message: &Vec<u8>, recevied_message: &Vec<u8>,
crypto_pair: &CryptographicSignature, crypto_pair: &CryptographicSignature,
socket_addr: &SocketAddr, //socket_addr: &SocketAddr,
senders: &MultipleSenders, senders: &MultipleSenders,
server_name: &String, server_name: &String,
cmd_tx: crossbeam_channel::Sender<NetworkEvent>,
ip: SocketAddr,
handhsake_history: &Arc<Mutex<HandshakeHistory>>,
) { ) {
if recevied_message.len() < 4 { if recevied_message.len() < 4 {
return; return;
@@ -55,8 +56,47 @@ pub fn handle_recevied_message(
let message_id: [u8; 4] = recevied_message[0..4].try_into().expect("size error"); let message_id: [u8; 4] = recevied_message[0..4].try_into().expect("size error");
let id = i32::from_be_bytes(message_id); 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,
);
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 // Lock the mutex to access the HashMap
let list = messages_list.lock().unwrap(); /*let list = messages_list.lock().unwrap();
let eventtype = list.get(&id); // Clone the enum so we can release the lock if needed let eventtype = list.get(&id); // Clone the enum so we can release the lock if needed
match eventtype { match eventtype {
@@ -118,5 +158,271 @@ pub fn handle_recevied_message(
} }
print!("Message not found for ID: {}", id) print!("Message not found for ID: {}", id)
} }
} }*/
}
pub fn parse_message(
received_message: Vec<u8>,
id: i32,
crypto_pair: &CryptographicSignature,
cmd_tx: crossbeam_channel::Sender<NetworkEvent>,
ip: SocketAddr,
messages_list: &Arc<Mutex<HashMap<i32, EventType>>>,
handhsake_history_mutex: &Arc<Mutex<HandshakeHistory>>,
) -> Option<Vec<u8>> {
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<Vec<u8>> = None;
match msgtype {
// PING
//
// envoie un OK
PING => {
constructed_message = construct_message(OK, Vec::new(), id, crypto_pair);
}
//
// OK
//
// rien ?
// si NATTRAVERSALREQUEST alors
//
// 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
} }

View File

@@ -2,6 +2,7 @@ use crate::P2PSharedData;
use crate::cryptographic_signature::CryptographicSignature; use crate::cryptographic_signature::CryptographicSignature;
use crate::message_handling::EventType; use crate::message_handling::EventType;
use crate::message_handling::handle_recevied_message; use crate::message_handling::handle_recevied_message;
use crate::peers_refresh::HandshakeHistory;
use std::collections::HashMap; use std::collections::HashMap;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::net::UdpSocket; use std::net::UdpSocket;
@@ -21,9 +22,9 @@ pub struct MultipleSenders {
} }
pub struct Message { pub struct Message {
payload: Vec<u8>, pub payload: Vec<u8>,
address: String, pub address: String,
is_resp_to_server_handshake: bool, pub is_resp_to_server_handshake: bool,
} }
struct RetryMessage { struct RetryMessage {
@@ -205,60 +206,74 @@ impl MultipleSenders {
data: Vec<u8>, data: Vec<u8>,
remote_addr: String, remote_addr: String,
is_resp_to_server_handshake: bool, is_resp_to_server_handshake: bool,
messages_list: &Mutex<HashMap<i32, EventType>>,
) { ) {
println!( println!(
"is_resp_to_server_handshake {}", "is_resp_to_server_handshake {}",
is_resp_to_server_handshake is_resp_to_server_handshake
); );
let msg_to_send = Message {
payload: data.clone(),
address: remote_addr,
is_resp_to_server_handshake,
};
if let Some(sender) = self.senders.get(channel_idx) { if let Some(sender) = self.senders.get(channel_idx) {
let _ = sender.send(Message { let _ = sender.send(msg_to_send);
payload: data, }
address: remote_addr, if !is_resp_to_server_handshake {
is_resp_to_server_handshake, let mut guard = messages_list.lock().unwrap();
}); let message_id: [u8; 4] = data[0..4].try_into().expect("size error");
let id = i32::from_be_bytes(message_id);
guard.insert(id, EventType::SendRootRequest);
} }
} }
/*pub fn start_receving_thread(
socket: &Arc<UdpSocket>,
messages_list: &Arc<HashMap<i32, EventType>>,
crypto_pair: &Arc<CryptographicSignature>,
socket_addr: SocketAddr,
senders: &Arc<MultipleSenders>,
) {
let sock_clone = Arc::clone(socket);
let cryptopair_clone = Arc::clone(crypto_pair);
let senders_clone = Arc::clone(senders);
let messages_clone = Arc::clone(messages_list);
thread::spawn(move || {
let mut buf = [0u8; 1024];
loop {
match sock_clone.recv_from(&mut buf) {
Ok((amt, src)) => {
handle_recevied_message(
&messages_clone,
&buf.to_vec(),
&cryptopair_clone,
&socket_addr,
&senders_clone,
);
println!("Reçu {} octets de {}: {:?}", amt, src, &buf[..amt]);
}
Err(e) => eprintln!("Erreur de réception: {}", e),
}
}
});
}*/
} }
/*pub fn start_receving_thread( pub fn start_receving_thread(
socket: &Arc<UdpSocket>, shared_data: &P2PSharedData,
messages_list: &Arc<HashMap<i32, EventType>>, cmd_tx: crossbeam_channel::Sender<NetworkEvent>,
crypto_pair: &Arc<CryptographicSignature>, handshake_history: &Arc<Mutex<HandshakeHistory>>,
socket_addr: SocketAddr,
senders: &Arc<MultipleSenders>,
) { ) {
let sock_clone = Arc::clone(socket);
let cryptopair_clone = Arc::clone(crypto_pair);
let senders_clone = Arc::clone(senders);
let messages_clone = Arc::clone(messages_list);
thread::spawn(move || {
let mut buf = [0u8; 1024];
loop {
match sock_clone.recv_from(&mut buf) {
Ok((amt, src)) => {
handle_recevied_message(
&messages_clone,
&buf.to_vec(),
&cryptopair_clone,
&socket_addr,
&senders_clone,
);
println!("Reçu {} octets de {}: {:?}", amt, src, &buf[..amt]);
}
Err(e) => eprintln!("Erreur de réception: {}", e),
}
}
});
}*/
pub fn start_receving_thread(shared_data: &P2PSharedData, socket_addr: SocketAddr) {
let sock_clone = shared_data.socket(); let sock_clone = shared_data.socket();
let cryptopair_clone = shared_data.cryptopair(); let cryptopair_clone = shared_data.cryptopair();
let senders_clone = shared_data.senders(); let senders_clone = shared_data.senders();
let messages_clone = shared_data.messages_list(); let messages_clone = shared_data.messages_list();
let servername_clone = shared_data.servername(); let servername_clone = shared_data.servername();
let handshake_clone = handshake_history.clone();
thread::spawn(move || { thread::spawn(move || {
let mut buf = [0u8; 1024]; let mut buf = [0u8; 1024];
loop { loop {
@@ -271,9 +286,11 @@ pub fn start_receving_thread(shared_data: &P2PSharedData, socket_addr: SocketAdd
&messages_clone, &messages_clone,
&received_data, &received_data,
&cryptopair_clone, &cryptopair_clone,
&socket_addr,
&senders_clone, &senders_clone,
&servername_clone, &servername_clone,
cmd_tx.clone(),
src,
&handshake_clone,
); );
} }
Err(e) => eprintln!("Erreur de réception: {}", e), Err(e) => eprintln!("Erreur de réception: {}", e),

View File

@@ -1,172 +1,69 @@
pub struct UDPMessage { use crate::{
id: u32, cryptographic_signature::{CryptographicSignature, sign_message},
msg_type: u8, server_communication::generate_id,
length: u16, };
body: Vec<u8>,
signature: Vec<u8>, const ID: usize = 4;
} const TYPE: usize = 5;
const LENGTH: usize = 7;
pub struct HandshakeMessage { const EXTENSIONS: usize = 4;
pub id: u32, const SIGNATURE: usize = 64;
msg_type: u8,
length: u16, const PING: u8 = 0;
extensions: u32, const OK: u8 = 128;
pub name: Vec<u8>, const ERROR: u8 = 129;
pub signature: Vec<u8>, const HELLO: u8 = 1;
} const HELLOREPLY: u8 = 130;
pub const ROOTREQUEST: u8 = 2;
pub struct NatTraversal {} const ROOTREPLY: u8 = 131;
const DATUMREQUEST: u8 = 3;
impl UDPMessage { const NODATUM: u8 = 133;
pub fn ping(id: u32) -> UDPMessage { const DATUM: u8 = 132;
UDPMessage { const NATTRAVERSALREQUEST: u8 = 4;
id: id, const NATTRAVERSALREQUEST2: u8 = 5;
msg_type: 0,
length: 0, pub fn construct_message(
body: vec![0; 985], msgtype: u8,
signature: vec![0; 32], payload: Vec<u8>,
} id: i32,
} crypto_pair: &CryptographicSignature,
) -> Option<Vec<u8>> {
pub fn error(id: u32) -> UDPMessage { let mut message = Vec::new();
UDPMessage {
id: id, // ID
msg_type: 129, // type
length: 0, message.extend_from_slice(&id.to_be_bytes());
body: vec![0; 985],
signature: vec![0; 32], message.push(msgtype);
}
} match msgtype {
HELLO | HELLOREPLY => {
pub fn parse(received_message: Vec<u8>) -> UDPMessage { // length
let id_bytes: [u8; 4] = received_message[0..4] let a = payload.len() as u16;
.try_into() println!("payload size:{}", a);
.expect("Taille incorrecte"); message.extend_from_slice(&a.to_be_bytes());
let length_bytes: [u8; 2] = received_message[5..7] message.extend_from_slice(&payload);
.try_into() let signature = sign_message(crypto_pair, &message);
.expect("Taille incorrecte"); return Some(signature);
let msg_length = u16::from_be_bytes(length_bytes); }
let name_bytes = &received_message[7..msg_length as usize + 8]; PING | OK | ROOTREQUEST => {
let signature_bytes = message.extend_from_slice(&0u16.to_be_bytes());
&received_message[msg_length as usize + 8..msg_length as usize + 9 + 32]; return Some(message);
UDPMessage { }
id: u32::from_be_bytes(id_bytes), ERROR | DATUMREQUEST => {
msg_type: received_message[4], message.extend_from_slice(&payload.len().to_be_bytes());
length: u16::from_be_bytes(length_bytes), message.extend_from_slice(&payload);
body: name_bytes.to_vec(), return Some(message);
signature: signature_bytes.to_vec(), }
} ROOTREPLY | NODATUM | DATUM | NATTRAVERSALREQUEST => {
} message.extend_from_slice(&payload.len().to_be_bytes());
message.extend_from_slice(&payload);
pub fn display(&self) { let signature = sign_message(crypto_pair, &message);
println!("ID: {:?}", self.id); message.extend_from_slice(&signature);
println!("Message Type: {}", self.msg_type); return Some(message);
println!("Length: {:?}", self.length); }
let good_length = usize::min(self.length as usize, 985);
println!("name: {:?}", &self.body[..good_length]); _ => {}
println!("Signature: {:?}", self.signature); }
} None
}
impl HandshakeMessage {
pub fn display(&self) {
println!("ID: {:?}", self.id);
println!("Message Type: {}", self.msg_type);
println!("Length: {:?}", self.length);
println!("extensions: {:?}", self.extensions);
println!("name: {:?}", &self.name[..(self.length - 4) as usize]);
println!("Signature: {:?}", self.signature);
}
pub fn hello(id: u32, length: u16, username: String) -> HandshakeMessage {
let name_vec = username.trim_end_matches(char::from(0)).as_bytes().to_vec();
HandshakeMessage {
id: id,
msg_type: 1,
length: length,
extensions: 0,
name: name_vec,
signature: vec![0; 64],
}
}
pub fn helloReply(id: u32, length: u16, username: String) -> HandshakeMessage {
let name_vec = username.trim_end_matches(char::from(0)).as_bytes().to_vec();
HandshakeMessage {
id: id,
msg_type: 130,
length: length,
extensions: 0,
name: name_vec,
signature: vec![0; 64],
}
}
pub fn serialize(&self) -> Vec<u8> {
let mut out = Vec::with_capacity(4 + 1 + 2 + 4 + self.name.len() + self.signature.len());
// id: u32 little-endian
out.extend_from_slice(&self.id.to_be_bytes());
// msg_type: u8
out.push(self.msg_type);
out.extend_from_slice(&self.length.to_be_bytes());
out.extend_from_slice(&self.extensions.to_be_bytes());
out.extend_from_slice(&self.name);
out.extend_from_slice(&self.signature);
out
}
pub fn parse(received_message: Vec<u8>) -> HandshakeMessage {
let id_bytes: [u8; 4] = received_message[0..4]
.try_into()
.expect("Taille incorrecte");
let length_bytes: [u8; 2] = received_message[5..7]
.try_into()
.expect("Taille incorrecte");
let msg_length = u16::from_be_bytes(length_bytes);
let extensions_bytes: [u8; 4] = received_message[7..11]
.try_into()
.expect("Taille incorrecte");
let name_bytes = &received_message[11..(11 + msg_length - 4) as usize];
let signature_bytes =
&received_message[(11 + msg_length - 4) as usize..(11 + msg_length - 4 + 64) as usize];
HandshakeMessage {
id: u32::from_be_bytes(id_bytes),
msg_type: received_message[4],
length: u16::from_be_bytes(length_bytes),
extensions: u32::from_be_bytes(extensions_bytes),
name: name_bytes.to_vec(),
signature: signature_bytes.to_vec(),
}
}
}
#[cfg(test)]
mod tests {
// Note this useful idiom: importing names from outer (for mod tests) scope.
use super::*;
/// creates an handshake message
#[tokio::test]
async fn creating_handshake_msg() {
let username = String::from("charlie_kirk");
let handshake = HandshakeMessage::hello(0, 12, username);
handshake.display();
}
/// parses an handshake message
#[tokio::test]
async fn parse_handshakemessage() {
let username = String::from("charlie_kirk");
let handshake = HandshakeMessage::hello(0, 12, username);
let ser = handshake.serialize();
let parsed = HandshakeMessage::parse(ser);
handshake.display();
parsed.display();
}
} }

View File

@@ -0,0 +1,160 @@
// 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
use std::{
collections::{HashMap, VecDeque},
net::{AddrParseError, Ipv4Addr, SocketAddr},
ops::Add,
process::Command,
sync::{Arc, Mutex},
thread,
time::{self, Duration, SystemTime},
};
use crate::NetworkEvent;
use crate::{
P2PSharedData, construct_message, generate_id, messages_structure,
registration::perform_handshake,
};
use crossbeam_channel::{Receiver, Sender};
use p256::ecdsa::VerifyingKey;
#[derive(Debug, Clone)]
pub struct PeerInfo {
pub username: String,
pub pubkey: VerifyingKey,
pub ip: SocketAddr,
}
pub struct HandshakeHistory {
//time_k_ip_v: HashMap<u64, u64>,
username_k_peerinfo_v: HashMap<String, PeerInfo>,
ip_k_peerinfo_v: HashMap<String, PeerInfo>,
}
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(),
}
}
/*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<&PeerInfo> {
self.username_k_peerinfo_v.get(&username).clone()
}
pub fn get_peer_info_ip(&self, ip: String) -> Option<&PeerInfo> {
self.ip_k_peerinfo_v.get(&ip).clone()
}
pub fn update_handshake(&self) {
// clone the map so we own it (cheap if PeerInfo is Clone)
let map_clone: Arc<HashMap<String, PeerInfo>> =
Arc::new(self.username_k_peerinfo_v.clone());
//let map_ip_clone: Arc<HashMap<String, PeerInfo>> = Arc::new(self.ip_k_peerinfo_v.clone());
let map_for_thread = Arc::clone(&map_clone);
thread::spawn(move || {
loop {
// Arc<HashMap<..>> derefs to &HashMap so these reads work
for (peer, peerinfo) in map_for_thread.iter() {
// send ping to peerinfo
}
thread::sleep(Duration::from_secs(10));
}
});
}
pub fn update_peer_info(&mut self, ip: String, username: String) {
let peerinfo = self.get_peer_info_ip(ip.clone());
match peerinfo {
Some(peer_info) => match ip.parse::<SocketAddr>() {
Ok(addr) => {
let new_peer_info = PeerInfo {
username: username.clone(),
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);
}
Err(e) => eprintln!("parse error: {}", e),
},
None => {
eprintln!("no peer info found in hashmap")
}
}
}
pub fn add_new_handshake(&mut 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());
}
}
pub fn perform_discover(
username: String,
hash: String,
sd: &P2PSharedData,
server_ip: String,
event_tx: Sender<NetworkEvent>,
) {
// 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);
}
}*/
} else {
// envoyer un datum request
}
}
#[cfg(test)]
mod tests {
use std::net::{IpAddr, Ipv4Addr};
use super::*;
/*#[test]
fn creating_cryptographic_signature() {
let mut hh = HandshakeHistory::new();
hh.add_new_handshake(
20,
"putain".to_string(),
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 1),
);
}*/
}

View File

@@ -1,10 +1,14 @@
use bytes::Bytes; use bytes::Bytes;
use getrandom::Error; use getrandom::Error;
use crate::NetworkEvent;
use crate::P2PSharedData;
use crate::cryptographic_signature::{CryptographicSignature, formatPubKey, sign_message}; use crate::cryptographic_signature::{CryptographicSignature, formatPubKey, sign_message};
use crate::message_handling::EventType; use crate::message_handling::EventType;
use crate::messages_channels::{Message, MultipleSenders}; use crate::messages_channels::{Message, MultipleSenders};
use crate::messages_structure::{HandshakeMessage, UDPMessage}; use crate::messages_structure::construct_message;
use crate::server_communication::generate_id;
use crossbeam_channel::{Receiver, Sender};
use std::collections::HashMap; use std::collections::HashMap;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::net::UdpSocket; use std::net::UdpSocket;
@@ -66,24 +70,68 @@ pub fn parse_addresses(input: &String) -> Vec<SocketAddr> {
/// ///
/// registers the IP addresses by sending a Hello request to the server. /// registers the IP addresses by sending a Hello request to the server.
/// ///
pub fn register_ip_addresses( pub async fn perform_handshake(
crypto_pair: &CryptographicSignature, sd: &P2PSharedData,
server_uri: String, username: String,
senders: &MultipleSenders, ip: String,
messages_list: &Mutex<HashMap<i32, EventType>>, event_tx: Sender<NetworkEvent>,
id: i32, is_server_handshake: bool,
) { ) {
let username_size = crypto_pair.username.len(); println!("username: {}, ip: {}", username.clone(), ip.clone());
let hello_handshake = HandshakeMessage::hello( let crypto_pair = sd.cryptopair_ref();
id as u32, let senders = sd.senders_ref();
username_size as u16 + 4, let messages_list = sd.messages_list_ref();
crypto_pair.username.clone(), let id = generate_id();
); let server_addr_query = get_socket_address(username.clone(), ip.clone());
//HandshakeMessage::display(&hello_handshake); match server_addr_query.await {
let hello_handshake_serialized = hello_handshake.serialize(); Ok(sockaddr_bytes) => {
let message_signed = sign_message(crypto_pair, &hello_handshake_serialized); match String::from_utf8(sockaddr_bytes.to_vec()) {
senders.send_via(0, message_signed, server_uri, false); Ok(s) => {
let mut list = messages_list.lock().expect("Failed to lock messages_list"); let addresses = parse_addresses(&s);
if let Some(first) = addresses.first() {
sd.set_servername(username);
// first: &SocketAddr
let mut payload = Vec::new();
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);
match hello_handshake {
Some(handshake_message) => {
senders.send_via(
0,
handshake_message,
first.to_string(),
is_server_handshake,
messages_list,
);
}
None => {}
}
//let res = event_tx
// .send(NetworkEvent::());
} else {
//let res = event_tx.send(NetworkEvent::Error());
let err_msg =
format!("no valid socket addresses found in: {}", s).to_string();
let res = event_tx.send(NetworkEvent::Error(err_msg));
}
}
Err(e) => {
//let res = event_tx.send(NetworkEvent::Error());
let err_msg =
format!("invalid UTF-8 in socket address bytes: {}", e).to_string();
let res = event_tx.send(NetworkEvent::Error(err_msg));
}
}
}
Err(e) => {
let err_msg = format!("failed to retreive socket address: {}", e).to_string();
let res = event_tx.send(NetworkEvent::Error(err_msg));
}
}
/*let mut list = messages_list.lock().expect("Failed to lock messages_list");
match list.get(&id) { match list.get(&id) {
Some(_) => { Some(_) => {
list.remove(&id); list.remove(&id);
@@ -92,12 +140,13 @@ pub fn register_ip_addresses(
list.insert(id, EventType::ServerHelloReply); list.insert(id, EventType::ServerHelloReply);
} }
} }
println!("message sent: {}", &id); println!("message sent: {}", &id);*/
// 3. Perform the insertion // 3. Perform the insertion
/*let mut buf = [0u8; 1024]; /*let mut buf = [0u8; 1024];
socket.recv_from(&mut buf).expect("receive failed"); socket.recv_from(&mut buf).expect("receive failed");
let hello_handshake_received = UDPMessage::parse(buf.to_vec()); let hello_handshake_received = UDPMessage::parse(buf.to_vec());
hello_handshake_received.display();*/ hello_handshake_received.display();*/
//TODO
} }
#[cfg(test)] #[cfg(test)]

55
todo.md
View File

@@ -1,25 +1,13 @@
# Todo # Todo :
## peer discovery ## 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
- handshake structure OK
- 5min timeout after handshake - 5min timeout after handshake
- matain connection every 4 min - matain connection every 4 min
## data transfer ## data transfer
- request structure - request structure
- root/root reply structure - root/root reply structure
- datum/nodatum and datum structures - datum/nodatum and datum structures
@@ -27,21 +15,34 @@
- setting in gui to act as a relay - setting in gui to act as a relay
- chunk, directory, big, bigdirectory structures - chunk, directory, big, bigdirectory structures
## nat traversal ## fonctionnalités application :
- 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
fonctionnalités :
s'enregistrer avec le serveur OK
rechercher un pair
generer une clé publique OK
rechercher les fichiers d'un pair rechercher les fichiers d'un pair
telechargement des fichiers telechargement des fichiers
choisir un dossier à partager choisir un dossier à partager
se deconnecter du réseau choisir le nombre de canaux
handshake server DOING
se deconnecter du réseau DOING
## autre :
socket ipv6
# FAIT :
- choisir un pseudo OK
- get rsquest to the uri /peers/ OK
- generation of the cryptographic key OK
- put request to the uri (check if the peer is already connected) 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
- udp handshakes OK
- handshake structure OK
- s'enregistrer avec le serveur OK
- generer une clé publique OK
- verifier signature OK
- 2 channels -> un pour envoyer et un pour recevoir OK
2 channels -> un pour envoyer et un pour recevoir OK