|
|
|
@ -1,4 +1,4 @@
|
|
|
|
|
use crate::crypto::PublicKey; |
|
|
|
|
use crate::crypto::{Keys, PublicKey}; |
|
|
|
|
use crate::message::{Message, MessageType, ServiceMessageType}; |
|
|
|
|
use crate::res::{IFError, IFResult}; |
|
|
|
|
use crate::transport::Transport; |
|
|
|
@ -8,6 +8,8 @@ use alloc::vec::Vec;
|
|
|
|
|
|
|
|
|
|
/// Main worker
|
|
|
|
|
pub struct IronForce { |
|
|
|
|
/// Keys for this instance
|
|
|
|
|
keys: Keys, |
|
|
|
|
/// the struct that manages communicating with neighbor nodes
|
|
|
|
|
transport: Transport, |
|
|
|
|
/// Tunnels that are known to this node
|
|
|
|
@ -20,40 +22,52 @@ pub struct IronForce {
|
|
|
|
|
messages: Vec<Message>, |
|
|
|
|
/// Tunnels that has not been confirmed yet (no backward spread)
|
|
|
|
|
///
|
|
|
|
|
/// `[(Tunnel, Optional target node)]`
|
|
|
|
|
tunnels_pending: Vec<(TunnelPublic, Option<PublicKey> /* target node */)>, |
|
|
|
|
/// `[(Tunnel, Optional target node, local peer ids)]`
|
|
|
|
|
tunnels_pending: Vec<(TunnelPublic, Option<PublicKey> /* target node */, (u64, u64) /* local peer ids */)>, |
|
|
|
|
/// True if this instance has background thread
|
|
|
|
|
has_background_worker: bool, |
|
|
|
|
/// Messages that were already processed (stored to avoid "echo chambers")
|
|
|
|
|
processed_messages: Vec<u64>, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl IronForce { |
|
|
|
|
/// Create new worker
|
|
|
|
|
pub fn new() -> Self { |
|
|
|
|
Self { |
|
|
|
|
keys: Keys::generate(), |
|
|
|
|
transport: Transport::new(crate::interfaces::get_interfaces()), |
|
|
|
|
tunnels: vec![], |
|
|
|
|
additional_modules: vec![], |
|
|
|
|
messages: vec![], |
|
|
|
|
tunnels_pending: vec![], |
|
|
|
|
has_background_worker: false, |
|
|
|
|
processed_messages: vec![], |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Create a new tunnel to another node
|
|
|
|
|
fn initialize_tunnel_creation(&mut self, destination: PublicKey) -> IFResult<()> { |
|
|
|
|
let tunnel = TunnelPublic::new_singlecast(); |
|
|
|
|
self.tunnels_pending.push((tunnel.clone(), Some(destination))); |
|
|
|
|
self.tunnels_pending |
|
|
|
|
.push((tunnel.clone(), Some(destination.clone()), (0, 0))); |
|
|
|
|
let message = Message::build() |
|
|
|
|
.message_type(MessageType::Service(ServiceMessageType::TunnelBuilding( |
|
|
|
|
tunnel |
|
|
|
|
))).build()?; |
|
|
|
|
.message_type(MessageType::Service( |
|
|
|
|
ServiceMessageType::TunnelBuildingForwardMovement( |
|
|
|
|
tunnel, |
|
|
|
|
destination.encrypt_data(&self.keys.get_public().to_vec())?, |
|
|
|
|
), |
|
|
|
|
)) |
|
|
|
|
.recipient(destination) |
|
|
|
|
.sign(&self.keys) |
|
|
|
|
.build()?; |
|
|
|
|
self.send_to_all(message)?; |
|
|
|
|
Ok(()) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Send a multicast or broadcast message
|
|
|
|
|
fn send_to_all(&mut self, message: Message) -> IFResult<()> { |
|
|
|
|
self.transport.send_message(serde_cbor::to_vec(&message)?, None) |
|
|
|
|
self.transport |
|
|
|
|
.send_message(serde_cbor::to_vec(&message)?, None) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Send a message through tunnel
|
|
|
|
@ -89,11 +103,81 @@ impl IronForce {
|
|
|
|
|
|
|
|
|
|
/// Process a message: if it's a service message, act accordingly.
|
|
|
|
|
/// Otherwise, add to `self.messages`
|
|
|
|
|
fn process_message(&mut self, message: Message, _inc_peer: u64) -> IFResult<()> { |
|
|
|
|
match message.message_type { |
|
|
|
|
fn process_message(&mut self, message: Message, inc_peer: u64) -> IFResult<()> { |
|
|
|
|
if self.processed_messages.contains(&message.message_id) { |
|
|
|
|
return Ok(()); |
|
|
|
|
} |
|
|
|
|
self.processed_messages.push(message.message_id); |
|
|
|
|
match &message.message_type { |
|
|
|
|
MessageType::Service(msg_type) => match msg_type { |
|
|
|
|
ServiceMessageType::TunnelBuilding(_tunnel) => { |
|
|
|
|
todo!() |
|
|
|
|
ServiceMessageType::TunnelBuildingForwardMovement(tunnel, sender_enc) => { |
|
|
|
|
if message.check_recipient(&self.keys) { |
|
|
|
|
let mut tunnel_pub = tunnel.clone(); |
|
|
|
|
tunnel_pub.id = Some(rand::random()); |
|
|
|
|
let sender = PublicKey::from_vec(self.keys.decrypt_data(sender_enc)?)?; |
|
|
|
|
let tunnel = Tunnel { |
|
|
|
|
id: tunnel_pub.id, |
|
|
|
|
local_ids: tunnel_pub.local_ids.clone(), |
|
|
|
|
peer_ids: (inc_peer, 0), |
|
|
|
|
ttd: 0, |
|
|
|
|
nodes_in_tunnel: None, |
|
|
|
|
is_multicast: false, |
|
|
|
|
target_node: Some(sender.clone()), |
|
|
|
|
}; |
|
|
|
|
self.tunnels.push(tunnel); |
|
|
|
|
self.send_to_all( |
|
|
|
|
Message::build() |
|
|
|
|
.message_type(MessageType::Service( |
|
|
|
|
ServiceMessageType::TunnelBuildingBackwardMovement(tunnel_pub.clone()), |
|
|
|
|
)) |
|
|
|
|
.tunnel(tunnel_pub.id.unwrap()) |
|
|
|
|
.sign(&self.keys) |
|
|
|
|
.build()? |
|
|
|
|
)?; |
|
|
|
|
} else { |
|
|
|
|
let mut tunnel = tunnel.clone(); |
|
|
|
|
tunnel.local_ids.push(rand::random()); |
|
|
|
|
self.tunnels_pending.push((tunnel.clone(), None, (inc_peer, 0))); |
|
|
|
|
self.send_to_all(message)?; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
ServiceMessageType::TunnelBuildingBackwardMovement(tunnel_p) => { |
|
|
|
|
match self |
|
|
|
|
.tunnels_pending |
|
|
|
|
.iter() |
|
|
|
|
.find(|tun| tunnel_p.local_ids.contains(tun.0.local_ids.last().unwrap())) |
|
|
|
|
{ |
|
|
|
|
// This doesn't concern us
|
|
|
|
|
None => {} |
|
|
|
|
// This is a tunnel initialization proposed by us (and we got it back, yay)
|
|
|
|
|
Some((_, Some(target), peers)) => { |
|
|
|
|
let tunnel = Tunnel { |
|
|
|
|
id: tunnel_p.id, |
|
|
|
|
local_ids: tunnel_p.local_ids.clone(), |
|
|
|
|
peer_ids: (peers.0, inc_peer), |
|
|
|
|
ttd: 0, |
|
|
|
|
nodes_in_tunnel: None, |
|
|
|
|
is_multicast: false, |
|
|
|
|
target_node: Some(target.clone()), |
|
|
|
|
}; |
|
|
|
|
self.tunnels.push(tunnel); |
|
|
|
|
// Send some initialization message or something
|
|
|
|
|
} |
|
|
|
|
// This is a tunnel initialization proposed by someone else that has passed through us on its forward movement
|
|
|
|
|
Some((_, None, peers)) => { |
|
|
|
|
let tunnel = Tunnel { |
|
|
|
|
id: tunnel_p.id, |
|
|
|
|
local_ids: tunnel_p.local_ids.clone(), |
|
|
|
|
peer_ids: (peers.0, inc_peer), |
|
|
|
|
ttd: 0, |
|
|
|
|
nodes_in_tunnel: None, |
|
|
|
|
is_multicast: false, |
|
|
|
|
target_node: None |
|
|
|
|
}; |
|
|
|
|
self.tunnels.push(tunnel); |
|
|
|
|
self.transport.send_message(serde_cbor::to_vec(&message)?, Some(peers.0))?; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
MessageType::SingleCast | MessageType::Broadcast => self.messages.push(message), |
|
|
|
@ -117,23 +201,44 @@ impl IronForce {
|
|
|
|
|
|
|
|
|
|
#[cfg(test)] |
|
|
|
|
mod if_testing { |
|
|
|
|
use crate::ironforce::IronForce; |
|
|
|
|
use alloc::vec::Vec; |
|
|
|
|
use alloc::vec; |
|
|
|
|
use alloc::boxed::Box; |
|
|
|
|
use crate::crypto::Keys; |
|
|
|
|
use crate::interface::test_interface::create_test_interfaces; |
|
|
|
|
use crate::ironforce::IronForce; |
|
|
|
|
use crate::res::IFResult; |
|
|
|
|
use crate::transport::Transport; |
|
|
|
|
use alloc::boxed::Box; |
|
|
|
|
use alloc::vec; |
|
|
|
|
use alloc::vec::Vec; |
|
|
|
|
|
|
|
|
|
fn create_test_network() -> Vec<IronForce> { |
|
|
|
|
let interfaces = create_test_interfaces(5); |
|
|
|
|
let transports = interfaces.into_iter().map(|interface| Transport::new(vec![Box::new(interface)])); |
|
|
|
|
transports.map(|tr| IronForce { |
|
|
|
|
transport: tr, |
|
|
|
|
tunnels: vec![], |
|
|
|
|
additional_modules: vec![], |
|
|
|
|
messages: vec![], |
|
|
|
|
tunnels_pending: vec![], |
|
|
|
|
has_background_worker: false |
|
|
|
|
}).collect() |
|
|
|
|
let transports = interfaces |
|
|
|
|
.into_iter() |
|
|
|
|
.map(|interface| Transport::new(vec![Box::new(interface)])); |
|
|
|
|
transports |
|
|
|
|
.map(|tr| IronForce { |
|
|
|
|
keys: Keys::generate(), |
|
|
|
|
transport: tr, |
|
|
|
|
tunnels: vec![], |
|
|
|
|
additional_modules: vec![], |
|
|
|
|
messages: vec![], |
|
|
|
|
tunnels_pending: vec![], |
|
|
|
|
has_background_worker: false, |
|
|
|
|
processed_messages: vec![], |
|
|
|
|
}) |
|
|
|
|
.collect() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
fn test_creating_a_tunnel() -> IFResult<()> { |
|
|
|
|
let mut network = create_test_network(); |
|
|
|
|
let key_1 = network[1].keys.get_public(); |
|
|
|
|
network[0].initialize_tunnel_creation(key_1)?; |
|
|
|
|
network[0].main_loop_iteration()?; |
|
|
|
|
network[1].main_loop_iteration()?; |
|
|
|
|
network[0].main_loop_iteration()?; |
|
|
|
|
assert!(!network[0].tunnels.is_empty()); |
|
|
|
|
// println!("T: {:?}", network[0].tunnels);
|
|
|
|
|
Ok(()) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|