Rewrite server to be asynchronous

Rewrite of the vented server that uses async-std and async tcp
streams. The Protocol itself is unchanged but the api for implementations
needs to be adapted.

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/1/head
trivernis 4 years ago
parent 984c1308f9
commit d017e8e250
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -1,7 +1,7 @@
[package] [package]
name = "vented" name = "vented"
description = "Event driven encrypted tcp communicaton" description = "Event driven encrypted tcp communicaton"
version = "0.10.5" version = "0.11.0"
authors = ["trivernis <trivernis@protonmail.com>"] authors = ["trivernis <trivernis@protonmail.com>"]
edition = "2018" edition = "2018"
readme = "README.md" readme = "README.md"
@ -17,7 +17,6 @@ rmp-serde = "0.14.4"
serde = { version = "1.0.117", features = ["serde_derive"] } serde = { version = "1.0.117", features = ["serde_derive"] }
byteorder = "1.3.4" byteorder = "1.3.4"
parking_lot = "0.11.0" parking_lot = "0.11.0"
scheduled-thread-pool = "0.2.5"
log = "0.4.11" log = "0.4.11"
crypto_box = "0.5.0" crypto_box = "0.5.0"
rand = "0.7.3" rand = "0.7.3"
@ -26,7 +25,7 @@ generic-array = "0.14.4"
typenum = "1.12.0" typenum = "1.12.0"
x25519-dalek = "1.1.0" x25519-dalek = "1.1.0"
crossbeam-utils = "0.8.0" crossbeam-utils = "0.8.0"
crossbeam-channel = "0.5.0" async-std = "1.7.0"
[dev-dependencies] [dev-dependencies]
simple_logger = "1.11.0" simple_logger = "1.11.0"

@ -1,6 +1,6 @@
# Vented # Vented
Vented is an event based TCP server with encryption that uses message pack for payload data. Vented is an event based asynchronous TCP server with encryption that uses message pack for payload data.
## Encryption ## Encryption
@ -15,31 +15,35 @@ The crate used for the key exchanges is [x25519-dalek](https://crates.io/crates/
```rust ```rust
use vented::server::VentedServer; use vented::server::VentedServer;
use vented::server::data::Node; use vented::server::data::{Node, ServerTimeouts};
use vented::crypto::SecretKey; use vented::stream::SecretKey;
use rand::thread_rng; use rand::thread_rng;
use vented::event::Event; use vented::event::Event;
fn main() { fn main() {
let global_secret_b = SecretKey::generate(&mut thread_rng());
let nodes = vec![ let nodes = vec![
Node { Node {
id: "B".to_string(), id: "B".to_string(),
address: None, addresses: vec![],
public_key: global_secret_b.public_key() // load it from somewhere trusted: true,
}, public_key: global_secret_b.public_key() // load it from somewhere
},
]; ];
// in a real world example the secret key needs to be loaded from somewhere because connections // in a real world example the secret key needs to be loaded from somewhere because connections
// with unknown keys are not accepted. // with unknown keys are not accepted.
let global_secret = SecretKey::new(&mut thread_rng()); let global_secret = SecretKey::generate(&mut thread_rng());
let mut server = VentedServer::new("A".to_string(), global_secret, nodes.clone(), 4); let mut server = VentedServer::new("A".to_string(), global_secret, nodes.clone(), ServerTimeouts::default());
server.listen("localhost:20000".to_string()); server.listen("localhost:20000".to_string());
server.on("pong", |_event| { server.on("pong", |_event| {
println!("Pong!"); Box::pin(async {println!("Pong!");
None // the return value is the response event Option<Event> None
})
}); });
server.emit("B".to_string(), Event::new("ping".to_string())).unwrap(); assert!(async_std::task::block_on(server.emit("B", Event::new("ping".to_string()))).is_err()) // this won't work without a known node B
}
} }
``` ```

@ -1,10 +1,11 @@
use std::io::Read; use async_std::io::{Read, ReadExt};
use byteorder::{BigEndian, ByteOrder, ReadBytesExt}; use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::utils::result::{VentedError, VentedResult}; use crate::utils::result::{VentedError, VentedResult};
use async_std::net::TcpStream;
pub trait GenericEvent {} pub trait GenericEvent {}
@ -72,17 +73,38 @@ impl Event {
data data
} }
pub fn from<R: Read + ReadBytesExt>(buf: &mut R) -> VentedResult<Self> {
let name_length = buf.read_u16::<BigEndian>()?;
let mut name_buf = vec![0u8; name_length as usize];
buf.read_exact(&mut name_buf)?;
let event_name = String::from_utf8(name_buf).map_err(|_| VentedError::NameDecodingError)?;
let payload_length = buf.read_u64::<BigEndian>()?;
let mut payload = vec![0u8; payload_length as usize];
buf.read_exact(&mut payload)?;
Ok(Self {
name: event_name,
payload,
origin: None,
})
}
/// Deserializes the message from bytes that can be read from the given reader /// Deserializes the message from bytes that can be read from the given reader
/// The result will be the Message with the specific message payload type /// The result will be the Message with the specific message payload type
pub fn from_bytes<R: Read>(bytes: &mut R) -> VentedResult<Self> { pub async fn from_async_tcp(stream: &mut TcpStream) -> VentedResult<Self> {
let name_length = bytes.read_u16::<BigEndian>()?; let mut name_length_raw = [0u8; 2];
stream.read_exact(&mut name_length_raw).await?;
let name_length = BigEndian::read_u16(&mut name_length_raw);
let mut name_buf = vec![0u8; name_length as usize]; let mut name_buf = vec![0u8; name_length as usize];
bytes.read_exact(&mut name_buf)?; stream.read_exact(&mut name_buf).await?;
let event_name = String::from_utf8(name_buf).map_err(|_| VentedError::NameDecodingError)?; let event_name = String::from_utf8(name_buf).map_err(|_| VentedError::NameDecodingError)?;
let payload_length = bytes.read_u64::<BigEndian>()?; let mut payload_length_raw = [0u8; 8];
stream.read_exact(&mut payload_length_raw).await?;
let payload_length = BigEndian::read_u64(&payload_length_raw);
let mut payload = vec![0u8; payload_length as usize]; let mut payload = vec![0u8; payload_length as usize];
bytes.read_exact(&mut payload)?; stream.read_exact(&mut payload).await?;
Ok(Self { Ok(Self {
name: event_name, name: event_name,

@ -34,7 +34,7 @@ fn it_deserializes_events() {
let mut event = Event::with_payload("test".to_string(), &payload); let mut event = Event::with_payload("test".to_string(), &payload);
let event_bytes = event.as_bytes(); let event_bytes = event.as_bytes();
let deserialized_event = Event::from_bytes(&mut event_bytes.as_slice()).unwrap(); let deserialized_event = Event::from(&mut event_bytes.as_slice()).unwrap();
assert_eq!(deserialized_event.name, "test".to_string()); assert_eq!(deserialized_event.name, "test".to_string());
assert_eq!( assert_eq!(
deserialized_event.get_payload::<SimplePayload>().unwrap(), deserialized_event.get_payload::<SimplePayload>().unwrap(),

@ -1,49 +1,77 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::event::Event; use crate::event::Event;
use async_std::prelude::*;
use async_std::sync::Arc;
use async_std::task;
use parking_lot::Mutex;
use std::pin::Pin;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
pub trait EventCallback:
Fn(Event) -> Pin<Box<dyn Future<Output = Option<Event>>>> + Send + Sync
{
}
/// A handler for events /// A handler for events
#[derive(Clone)]
pub struct EventHandler { pub struct EventHandler {
event_handlers: HashMap<String, Vec<Box<dyn Fn(Event) -> Option<Event> + Send + Sync>>>, event_handlers: Arc<
Mutex<
HashMap<
String,
Vec<
Box<
dyn Fn(Event) -> Pin<Box<dyn Future<Output = Option<Event>>>> + Send + Sync,
>,
>,
>,
>,
>,
} }
impl EventHandler { impl EventHandler {
/// Creates a new vented event_handler /// Creates a new vented event_handler
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
event_handlers: HashMap::new(), event_handlers: Arc::new(Mutex::new(HashMap::new())),
} }
} }
/// Adds a handler for the given event /// Adds a handler for the given event
pub fn on<F: 'static>(&mut self, event_name: &str, handler: F) pub fn on<F: 'static>(&mut self, event_name: &str, handler: F)
where where
F: Fn(Event) -> Option<Event> + Send + Sync, F: Fn(Event) -> Pin<Box<dyn Future<Output = Option<Event>>>> + Send + Sync,
{ {
match self.event_handlers.get_mut(event_name) { let mut handlers = self.event_handlers.lock();
match handlers.get_mut(event_name) {
Some(handlers) => handlers.push(Box::new(handler)), Some(handlers) => handlers.push(Box::new(handler)),
None => { None => {
self.event_handlers handlers.insert(event_name.to_string(), vec![Box::new(handler)]);
.insert(event_name.to_string(), vec![Box::new(handler)]);
} }
} }
} }
/// Handles a single event /// Handles a single event
pub fn handle_event(&mut self, event: Event) -> Vec<Event> { pub async fn handle_event(&mut self, event: Event) -> Vec<Event> {
let mut response_events = Vec::new(); let mut response_events: Vec<Event> = Vec::new();
if let Some(handlers) = self.event_handlers.get(&event.name) { if let Some(handlers) = self.event_handlers.lock().get(&event.name) {
for handler in handlers { for handler in handlers {
if let Some(e) = handler(event.clone()) { let result = handler(event.clone());
response_events.push(e); task::block_on(async {
} if let Some(e) = result.await {
response_events.push(e.clone());
}
})
} }
} }
response_events response_events
} }
} }
unsafe impl Send for EventHandler {}
unsafe impl Sync for EventHandler {}

@ -1,8 +1,9 @@
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use crate::event::Event; use crate::event::Event;
use crate::event_handler::EventHandler; use crate::event_handler::EventHandler;
use async_std::task;
#[test] #[test]
fn it_handles_events() { fn it_handles_events() {
@ -11,39 +12,53 @@ fn it_handles_events() {
{ {
let call_count = Arc::clone(&call_count); let call_count = Arc::clone(&call_count);
handler.on("test", move |event| { handler.on("test", move |event| {
call_count.fetch_add(1, Ordering::Relaxed); let call_count = Arc::clone(&call_count);
Box::pin(async move {
call_count.fetch_add(1, Ordering::Relaxed);
Some(event) Some(event)
})
}); });
} }
{ {
let call_count = Arc::clone(&call_count); let call_count = Arc::clone(&call_count);
handler.on("test", move |_event| { handler.on("test", move |_event| {
call_count.fetch_add(1, Ordering::Relaxed); let call_count = Arc::clone(&call_count);
Box::pin(async move {
call_count.fetch_add(1, Ordering::Relaxed);
None None
})
}); });
} }
{ {
let call_count = Arc::clone(&call_count); let call_count = Arc::clone(&call_count);
handler.on("test2", move |_event| { handler.on("test2", move |_event| {
call_count.fetch_add(1, Ordering::Relaxed); let call_count = Arc::clone(&call_count);
Box::pin(async move {
call_count.fetch_add(1, Ordering::Relaxed);
None None
})
}); });
} }
{ {
let call_count = Arc::clone(&call_count); let call_count = Arc::clone(&call_count);
handler.on("test2", move |_event| { handler.on("test2", move |_event| {
call_count.fetch_add(1, Ordering::Relaxed); let call_count = Arc::clone(&call_count);
Box::pin(async move {
call_count.fetch_add(1, Ordering::Relaxed);
None None
})
}) })
} }
handler.handle_event(Event::new("test".to_string())); task::block_on(async move {
handler.handle_event(Event::new("test".to_string())); handler.handle_event(Event::new("test".to_string())).await;
handler.handle_event(Event::new("test2".to_string())); handler.handle_event(Event::new("test".to_string())).await;
handler.handle_event(Event::new("test2".to_string())).await;
});
assert_eq!(call_count.load(Ordering::Relaxed), 6) assert_eq!(call_count.load(Ordering::Relaxed), 6)
} }

@ -1,8 +1,9 @@
#[macro_use]
pub mod utils;
pub use crossbeam_utils::sync::WaitGroup; pub use crossbeam_utils::sync::WaitGroup;
pub mod event; pub mod event;
pub mod event_handler; pub mod event_handler;
pub mod server; pub mod server;
pub mod stream; pub mod stream;
pub mod utils;

@ -1,18 +1,9 @@
use std::collections::HashMap;
use std::sync::Arc;
use crypto_box::SecretKey;
use parking_lot::Mutex;
use scheduled_thread_pool::ScheduledThreadPool;
use x25519_dalek::PublicKey; use x25519_dalek::PublicKey;
use crate::event_handler::EventHandler;
use crate::stream::cryptostream::CryptoStream;
use crate::stream::manager::{ConcurrentStreamManager, CONNECTION_TIMEOUT_SECONDS};
use crate::utils::result::VentedError;
use crate::utils::sync::AsyncValue;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
pub const CONNECTION_TIMEOUT_SECS: u64 = 10;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Node { pub struct Node {
pub id: String, pub id: String,
@ -34,21 +25,6 @@ pub enum NodeState {
Unknown, Unknown,
} }
#[derive(Clone)]
pub(crate) struct ServerConnectionContext {
pub is_server: bool,
pub node_id: String,
pub global_secret: SecretKey,
pub known_nodes: Arc<Mutex<HashMap<String, NodeData>>>,
pub event_handler: Arc<Mutex<EventHandler>>,
pub forwarded_connections: Arc<Mutex<HashMap<(String, String), AsyncValue<CryptoStream, ()>>>>,
pub sender_pool: Arc<Mutex<ScheduledThreadPool>>,
pub recv_pool: Arc<Mutex<ScheduledThreadPool>>,
pub redirect_handles: Arc<Mutex<HashMap<[u8; 16], AsyncValue<(), VentedError>>>>,
pub manager: ConcurrentStreamManager,
pub timeouts: ServerTimeouts,
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ServerTimeouts { pub struct ServerTimeouts {
pub send_timeout: Duration, pub send_timeout: Duration,
@ -58,8 +34,8 @@ pub struct ServerTimeouts {
impl Default for ServerTimeouts { impl Default for ServerTimeouts {
fn default() -> Self { fn default() -> Self {
Self { Self {
send_timeout: Duration::from_secs(CONNECTION_TIMEOUT_SECONDS), send_timeout: Duration::from_secs(CONNECTION_TIMEOUT_SECS),
redirect_timeout: Duration::from_secs(CONNECTION_TIMEOUT_SECONDS * 2), redirect_timeout: Duration::from_secs(CONNECTION_TIMEOUT_SECS * 2),
} }
} }
} }

@ -1,32 +1,28 @@
use async_std::net::{TcpListener, TcpStream};
use std::collections::HashMap; use std::collections::HashMap;
use std::io::Write;
use std::iter::FromIterator; use std::iter::FromIterator;
use std::mem;
use std::net::{TcpListener, TcpStream};
use std::sync::Arc; use std::sync::Arc;
use std::thread;
use std::time::Instant; use std::time::Instant;
use crossbeam_utils::sync::WaitGroup;
use crypto_box::{PublicKey, SecretKey}; use crypto_box::{PublicKey, SecretKey};
use parking_lot::Mutex; use parking_lot::Mutex;
use scheduled_thread_pool::ScheduledThreadPool;
use sha2::Digest; use sha2::Digest;
use x25519_dalek::StaticSecret; use x25519_dalek::StaticSecret;
use crate::event::Event; use crate::event::Event;
use crate::event_handler::EventHandler; use crate::event_handler::EventHandler;
use crate::server::data::{Node, NodeData, NodeState, ServerConnectionContext, ServerTimeouts}; use crate::server::data::{Node, NodeData, NodeState, ServerTimeouts};
use crate::server::server_events::{ use crate::server::server_events::{
AuthPayload, ChallengePayload, NodeInformationPayload, RedirectPayload, VersionMismatchPayload, AuthPayload, ChallengePayload, NodeInformationPayload, RedirectPayload, VersionMismatchPayload,
ACCEPT_EVENT, AUTH_EVENT, CHALLENGE_EVENT, CONNECT_EVENT, MISMATCH_EVENT, READY_EVENT, ACCEPT_EVENT, AUTH_EVENT, CHALLENGE_EVENT, CONNECT_EVENT, MISMATCH_EVENT, READY_EVENT,
REDIRECT_EVENT, REJECT_EVENT, REDIRECT_EVENT, REJECT_EVENT,
}; };
use crate::stream::cryptostream::CryptoStream; use crate::stream::cryptostream::CryptoStream;
use crate::stream::manager::ConcurrentStreamManager;
use crate::utils::result::{VentedError, VentedResult}; use crate::utils::result::{VentedError, VentedResult};
use crate::utils::sync::AsyncValue; use crate::utils::sync::AsyncValue;
use std::cmp::max; use async_std::prelude::*;
use async_std::task;
use std::pin::Pin;
pub mod data; pub mod data;
pub mod server_events; pub mod server_events;
@ -57,28 +53,28 @@ type ForwardFutureVector = Arc<Mutex<HashMap<(String, String), AsyncValue<Crypto
/// // in a real world example the secret key needs to be loaded from somewhere because connections /// // in a real world example the secret key needs to be loaded from somewhere because connections
/// // with unknown keys are not accepted. /// // with unknown keys are not accepted.
/// let global_secret = SecretKey::generate(&mut thread_rng()); /// let global_secret = SecretKey::generate(&mut thread_rng());
/// let mut server = VentedServer::new("A".to_string(), global_secret, nodes.clone(), ServerTimeouts::default(), 4, 100); /// let mut server = VentedServer::new("A".to_string(), global_secret, nodes.clone(), ServerTimeouts::default());
/// ///
/// ///
/// server.listen("localhost:20000".to_string()); /// server.listen("localhost:20000".to_string());
/// server.on("pong", |_event| { /// server.on("pong", |_event| {
/// println!("Pong!"); /// Box::pin(async {println!("Pong!");
/// ///
/// None // the return value is the response event Option<Event> /// None
/// })
/// }); /// });
/// assert!(server.emit("B", Event::new("ping".to_string())).get_value().is_err()) // this won't work without a known node B /// assert!(async_std::task::block_on(server.emit("B", Event::new("ping".to_string()))).is_err()) // this won't work without a known node B
/// ``` /// ```
#[derive(Clone)]
pub struct VentedServer { pub struct VentedServer {
forwarded_connections: ForwardFutureVector, forwarded_connections: ForwardFutureVector,
known_nodes: Arc<Mutex<HashMap<String, NodeData>>>, known_nodes: Arc<Mutex<HashMap<String, NodeData>>>,
event_handler: Arc<Mutex<EventHandler>>, event_handler: EventHandler,
global_secret_key: SecretKey, global_secret_key: SecretKey,
node_id: String, node_id: String,
redirect_handles: Arc<Mutex<HashMap<[u8; 16], AsyncValue<(), VentedError>>>>, redirect_handles: Arc<Mutex<HashMap<[u8; 16], AsyncValue<(), VentedError>>>>,
manager: ConcurrentStreamManager,
sender_pool: Arc<Mutex<ScheduledThreadPool>>,
receiver_pool: Arc<Mutex<ScheduledThreadPool>>,
timeouts: ServerTimeouts, timeouts: ServerTimeouts,
connections: Arc<Mutex<HashMap<String, CryptoStream>>>,
} }
impl VentedServer { impl VentedServer {
@ -90,13 +86,11 @@ impl VentedServer {
secret_key: SecretKey, secret_key: SecretKey,
nodes: Vec<Node>, nodes: Vec<Node>,
timeouts: ServerTimeouts, timeouts: ServerTimeouts,
num_threads: usize,
max_threads: usize,
) -> Self { ) -> Self {
let mut server = Self { let mut server = Self {
node_id, node_id,
manager: ConcurrentStreamManager::new(max_threads), connections: Arc::new(Mutex::new(HashMap::new())),
event_handler: Arc::new(Mutex::new(EventHandler::new())), event_handler: EventHandler::new(),
forwarded_connections: Arc::new(Mutex::new(HashMap::new())), forwarded_connections: Arc::new(Mutex::new(HashMap::new())),
global_secret_key: secret_key, global_secret_key: secret_key,
known_nodes: Arc::new(Mutex::new(HashMap::from_iter( known_nodes: Arc::new(Mutex::new(HashMap::from_iter(
@ -106,18 +100,9 @@ impl VentedServer {
.map(|node| (node.id.clone(), node.into())), .map(|node| (node.id.clone(), node.into())),
))), ))),
redirect_handles: Arc::new(Mutex::new(HashMap::new())), redirect_handles: Arc::new(Mutex::new(HashMap::new())),
sender_pool: Arc::new(Mutex::new(ScheduledThreadPool::new(max(
num_threads / 2,
1,
)))),
receiver_pool: Arc::new(Mutex::new(ScheduledThreadPool::new(max(
num_threads / 2,
1,
)))),
timeouts, timeouts,
}; };
server.register_events(); server.register_events();
server.start_event_listener();
server server
} }
@ -143,10 +128,9 @@ impl VentedServer {
} }
/// Emits an event to the specified Node /// Emits an event to the specified Node
/// The actual writing is done in a separate thread from the thread pool. #[inline]
/// For that reason an Async value is returned to use it to wait for the result pub async fn emit<S: ToString>(&self, node_id: S, event: Event) -> VentedResult<()> {
pub fn emit<S: ToString>(&self, node_id: S, event: Event) -> AsyncValue<(), VentedError> { self.send_event(&node_id.to_string(), event, true).await
Self::send_event(self.get_server_context(), &node_id.to_string(), event, true)
} }
/// Adds a handler for the given event. /// Adds a handler for the given event.
@ -154,204 +138,129 @@ impl VentedServer {
/// Multiple handlers can be registered for an event. /// Multiple handlers can be registered for an event.
pub fn on<F: 'static>(&mut self, event_name: &str, handler: F) pub fn on<F: 'static>(&mut self, event_name: &str, handler: F)
where where
F: Fn(Event) -> Option<Event> + Send + Sync, F: Fn(Event) -> Pin<Box<dyn Future<Output = Option<Event>>>> + Send + Sync,
{ {
self.event_handler.lock().on(event_name, handler); self.event_handler.on(event_name, handler);
} }
/// Starts listening on the specified address (with port!) /// Starts listening on the specified address (with port!)
/// This will cause a new thread to start up so that the method returns immediately /// This will cause a new thread to start up so that the method returns immediately
/// With the returned wait group one can wait for the server to be ready. /// With the returned wait group one can wait for the server to be ready.
/// The method can be called multiple times to start listeners on multiple ports. /// The method can be called multiple times to start listeners on multiple ports.
pub fn listen(&mut self, address: String) -> WaitGroup { pub fn listen(&self, address: String) {
let context = self.get_server_context(); let this = self.clone();
let wg = WaitGroup::new(); task::spawn(async move {
let wg2 = WaitGroup::clone(&wg); let listener = match TcpListener::bind(&address).await {
Ok(l) => l,
thread::spawn(move || match TcpListener::bind(&address) { Err(e) => {
Ok(listener) => { log::error!("Failed to bind listener to address {}: {}", address, e);
log::info!("Listener running on {}", address); return;
std::mem::drop(wg); }
};
for connection in listener.incoming() { log::info!("Listener running on {}", address);
match connection { while let Some(connection) = listener.incoming().next().await {
Ok(stream) => { match connection {
if let Err(e) = Self::handle_connection(context.clone(), stream) { Ok(stream) => {
let mut this = this.clone();
task::spawn(async move {
if let Err(e) = this.handle_connection(stream).await {
log::error!("Failed to handle connection: {}", e); log::error!("Failed to handle connection: {}", e);
} }
} });
Err(e) => log::trace!("Failed to establish connection: {}", e),
}
}
}
Err(e) => {
log::error!("Failed to bind listener: {}", e);
std::mem::drop(wg);
}
});
wg2
}
/// Returns a copy of the servers metadata
fn get_server_context(&self) -> ServerConnectionContext {
ServerConnectionContext {
is_server: true,
node_id: self.node_id.clone(),
global_secret: self.global_secret_key.clone(),
known_nodes: Arc::clone(&self.known_nodes),
event_handler: Arc::clone(&self.event_handler),
sender_pool: Arc::clone(&self.sender_pool),
forwarded_connections: Arc::clone(&self.forwarded_connections),
redirect_handles: Arc::clone(&self.redirect_handles),
manager: self.manager.clone(),
recv_pool: Arc::clone(&self.receiver_pool),
timeouts: self.timeouts.clone(),
}
}
/// Starts the event listener thread
fn start_event_listener(&self) {
let receiver = self.manager.receiver();
let event_handler = Arc::clone(&self.event_handler);
let context = self.get_server_context();
let wg = WaitGroup::new();
thread::spawn({
let wg = WaitGroup::clone(&wg);
move || {
mem::drop(wg);
while let Ok((origin, event)) = receiver.recv() {
if let Some(node) = context.known_nodes.lock().get_mut(&origin) {
node.set_node_state(NodeState::Alive(Instant::now()));
} }
let responses = event_handler.lock().handle_event(event); Err(e) => {
log::trace!("Failed to establish connection: {}", e);
for response in responses { continue;
Self::send_event(context.clone(), &origin, response, true);
} }
} }
log::warn!("Event listener stopped!");
} }
}); });
wg.wait();
} }
/// Sends an event asynchronously to a node /// Sends an event asynchronously to a node
/// The redirect flag is used to determine if it should be tried to redirect an event after /// The redirect flag is used to determine if it should be tried to redirect an event after
/// a direct sending attempt failed /// a direct sending attempt failed
fn send_event( async fn send_event(&self, target: &String, event: Event, redirect: bool) -> VentedResult<()> {
context: ServerConnectionContext,
target: &String,
event: Event,
redirect: bool,
) -> AsyncValue<(), VentedError> {
log::trace!( log::trace!(
"Emitting: '{}' from {} to {}", "Emitting: '{}' from {} to {}",
event.name, event.name,
context.node_id, self.node_id,
target target
); );
if context.manager.has_connection(target) { let mut result = Ok(());
let node_state = if let Ok(mut stream) = self.get_connection(target).await {
log::trace!("Reusing existing connection."); log::trace!("Reusing existing connection.");
context.manager.send(target, event) match stream.send(event).await {
} else { Ok(_) => NodeState::Alive(Instant::now()),
let future = AsyncValue::new(); Err(e) => {
result = Err(e);
context.sender_pool.lock().execute({ NodeState::Dead(Instant::now())
let mut future = AsyncValue::clone(&future); }
let node_id = target.clone(); }
let context = context.clone(); } else if redirect {
log::trace!("Trying to use a proxy node...");
move || { match self.send_event_redirected(&target, event).await {
log::trace!("Trying to establish connection..."); Ok(_) => {
let node_state = if let Ok(connection) = result = Ok(());
Self::get_connection(context.clone(), &node_id) NodeState::Alive(Instant::now())
{ }
if let Err(e) = context.manager.add_connection(connection) { Err(e) => {
future.reject(e); log::trace!("Failed to redirect: {}", e);
return; result = Err(e);
} NodeState::Dead(Instant::now())
log::trace!("Established new connection.");
let result = context.manager.send(&node_id, event).get_value();
match result {
Ok(_) => {
future.resolve(());
NodeState::Alive(Instant::now())
}
Err(e) => {
future.reject(e);
NodeState::Dead(Instant::now())
}
}
} else if redirect {
log::trace!("Trying to use a proxy node...");
let result = Self::send_event_redirected(context.clone(), &node_id, event);
match result {
Ok(_) => {
future.resolve(());
NodeState::Alive(Instant::now())
}
Err(e) => {
future.reject(e);
NodeState::Dead(Instant::now())
}
}
} else {
log::trace!("Failed to emit event to node {}", node_id);
future.reject(VentedError::UnreachableNode(node_id.clone()));
NodeState::Dead(Instant::now())
};
if let Some(node) = context.known_nodes.lock().get_mut(&node_id) {
node.set_node_state(node_state);
}
} }
}); }
} else {
log::trace!("Failed to emit event to node {}", target);
result = Err(VentedError::UnreachableNode(target.clone()));
future NodeState::Dead(Instant::now())
};
if let Some(node) = self.known_nodes.lock().get_mut(target) {
node.set_node_state(node_state);
} }
result
} }
/// Tries to send an event redirected by emitting a redirect event to all public nodes /// Tries to send an event redirected by emitting a redirect event to all public nodes
fn send_event_redirected( async fn send_event_redirected(&self, target: &String, event: Event) -> VentedResult<()> {
context: ServerConnectionContext, let connected_nodes = self
target: &String,
event: Event,
) -> VentedResult<()> {
let public_nodes = context
.known_nodes .known_nodes
.lock() .lock()
.values() .values()
.filter(|node| !node.node().addresses.is_empty() && node.is_alive()) .filter(|node| node.is_alive())
.cloned() .cloned()
.collect::<Vec<NodeData>>(); .collect::<Vec<NodeData>>();
for node in public_nodes { for node in connected_nodes {
let payload = RedirectPayload::new( let payload = RedirectPayload::new(
context.node_id.clone(), self.node_id.clone(),
node.node().id.clone(), node.node().id.clone(),
target.clone(), target.clone(),
event.clone().as_bytes(), event.clone().as_bytes(),
); );
let mut future = AsyncValue::new(); let mut value = AsyncValue::new();
context self.redirect_handles
.redirect_handles
.lock() .lock()
.insert(payload.id, AsyncValue::clone(&future)); .insert(payload.id, AsyncValue::clone(&value));
if let Err(e) = Self::send_event( if let Ok(mut stream) = self.get_connection(&node.node().id).await {
context.clone(), if let Err(e) = stream
&node.node().id, .send(Event::with_payload(REDIRECT_EVENT, &payload))
Event::with_payload(REDIRECT_EVENT, &payload), .await
false, {
) log::trace!("Failed to redirect via {}: {}", stream.receiver_node(), e);
.get_value() continue;
{ }
log::error!("Failed to redirect via {}: {}", node.node().id, e); } else {
continue;
} }
if let Some(Ok(_)) = if let Some(Ok(_)) = value
future.get_value_with_timeout(context.timeouts.redirect_timeout.clone()) .get_value_with_timeout_async(self.timeouts.redirect_timeout.clone())
.await
{ {
return Ok(()); return Ok(());
} else { } else {
@ -364,46 +273,76 @@ impl VentedServer {
/// Handles a single connection by first performing a key exchange and /// Handles a single connection by first performing a key exchange and
/// then establishing an encrypted connection /// then establishing an encrypted connection
fn handle_connection(context: ServerConnectionContext, stream: TcpStream) -> VentedResult<()> { async fn handle_connection(&mut self, stream: TcpStream) -> VentedResult<()> {
let event_handler = Arc::clone(&context.event_handler);
stream.set_write_timeout(Some(context.timeouts.send_timeout))?;
log::trace!( log::trace!(
"Received connection from {}", "Received connection from {}",
stream.peer_addr().expect("Failed to get peer address") stream.peer_addr().expect("Failed to get peer address")
); );
context.recv_pool.lock().execute({ let stream = self.perform_server_key_exchange(stream).await?;
let context = context.clone();
move || {
let manager = context.manager.clone();
let stream = match VentedServer::get_crypto_stream(context, stream) { log::trace!("Secure connection established.");
Ok(stream) => stream, self.connections
Err(e) => { .lock()
log::error!("Failed to establish encrypted connection: {}", e); .insert(stream.receiver_node().clone(), stream.clone());
return; self.event_handler
.handle_event(Event::new(READY_EVENT))
.await;
Self::read_stream(
stream.clone(),
self.connections.clone(),
self.event_handler.clone(),
)
.await;
Ok(())
}
/// Reads events from the stream and removes it from the known connections when it's closed
async fn read_stream(
mut stream: CryptoStream,
connections: Arc<Mutex<HashMap<String, CryptoStream>>>,
mut handler: EventHandler,
) {
loop {
match stream.read().await {
Ok(mut event) => {
event.origin = Some(stream.receiver_node().clone());
let results = handler.handle_event(event).await;
for result in results {
if let Err(e) = stream.send(result).await {
log::error!(
"Failed to send event to {}: {}",
stream.receiver_node(),
e
);
break;
}
} }
};
log::trace!("Secure connection established.");
if let Err(e) = manager.add_connection(stream) {
log::trace!("Failed to add connection to manager: {}", e);
return;
} }
event_handler.lock().handle_event(Event::new(READY_EVENT)); Err(e) => {
log::error!(
"Failed to read events from {}: {}",
stream.receiver_node(),
e
);
break;
}
} }
}); }
connections.lock().remove(stream.receiver_node());
Ok(())
} }
/// Takes three attempts to retrieve a connection for the given node. /// Takes three attempts to retrieve a connection for the given node.
/// First it tries to use the already established connection stored in the shared connections vector. /// First it tries to use the already established connection stored in the shared connections vector.
/// If that fails it tries to establish a new connection to the node by using the known address /// If that fails it tries to establish a new connection to the node by using the known address
fn get_connection( async fn get_connection(&self, target: &String) -> VentedResult<CryptoStream> {
context: ServerConnectionContext, if let Some(stream) = self.connections.lock().get(target) {
target: &String, log::trace!("Reusing existing connection.");
) -> VentedResult<CryptoStream> { return Ok(stream.clone());
let target_node = context }
let target_node = self
.known_nodes .known_nodes
.lock() .lock()
.get(target) .get(target)
@ -413,12 +352,11 @@ impl VentedServer {
log::trace!("Connecting to known addresses"); log::trace!("Connecting to known addresses");
for address in &target_node.node().addresses { for address in &target_node.node().addresses {
match Self::connect(context.clone(), address.clone()) { match self.connect(address.clone()).await {
Ok(stream) => return Ok(stream), Ok(stream) => return Ok(stream),
Err(e) => { Err(e) => {
log::error!("Failed to connect to node {}'s address: {}", target, e); log::error!("Failed to connect to node {}'s address: {}", target, e);
context self.known_nodes
.known_nodes
.lock() .lock()
.get_mut(target) .get_mut(target)
.unwrap() .unwrap()
@ -433,84 +371,43 @@ impl VentedServer {
Err(VentedError::UnreachableNode(target.clone())) Err(VentedError::UnreachableNode(target.clone()))
} }
/// Establishes a crypto stream for the given stream
fn get_crypto_stream(
context: ServerConnectionContext,
stream: TcpStream,
) -> VentedResult<CryptoStream> {
let (_, stream) = VentedServer::perform_key_exchange(
context.is_server,
stream,
context.node_id.clone(),
context.global_secret,
context.known_nodes,
)?;
Ok(stream)
}
/// Connects to the given address as a tcp client /// Connects to the given address as a tcp client
fn connect( async fn connect(&self, address: String) -> VentedResult<CryptoStream> {
mut context: ServerConnectionContext, let stream = TcpStream::connect(address).await?;
address: String, let stream = self.perform_client_key_exchange(stream).await?;
) -> VentedResult<CryptoStream> { self.connections
let stream = TcpStream::connect(address)?; .lock()
stream.set_write_timeout(Some(context.timeouts.send_timeout))?; .insert(stream.receiver_node().clone(), stream.clone());
context.is_server = false; task::spawn(Self::read_stream(
let stream = Self::get_crypto_stream(context, stream)?; stream.clone(),
self.connections.clone(),
self.event_handler.clone(),
));
Ok(stream) Ok(stream)
} }
/// Performs a key exchange
fn perform_key_exchange(
is_server: bool,
stream: TcpStream,
own_node_id: String,
global_secret: SecretKey,
known_nodes: Arc<Mutex<HashMap<String, NodeData>>>,
) -> VentedResult<(String, CryptoStream)> {
let secret_key = SecretKey::generate(&mut rand::thread_rng());
if is_server {
Self::perform_server_key_exchange(
stream,
&secret_key,
own_node_id,
global_secret,
known_nodes,
)
} else {
Self::perform_client_key_exchange(
stream,
&secret_key,
own_node_id,
global_secret,
known_nodes,
)
}
}
/// Performs the client side DH key exchange /// Performs the client side DH key exchange
fn perform_client_key_exchange( async fn perform_client_key_exchange(
&self,
mut stream: TcpStream, mut stream: TcpStream,
secret_key: &SecretKey, ) -> VentedResult<CryptoStream> {
own_node_id: String, let secret_key = SecretKey::generate(&mut rand::thread_rng());
global_secret: SecretKey, stream
known_nodes: Arc<Mutex<HashMap<String, NodeData>>>, .write(
) -> VentedResult<(String, CryptoStream)> { &Event::with_payload(
stream.write( CONNECT_EVENT,
&Event::with_payload( &NodeInformationPayload {
CONNECT_EVENT, public_key: secret_key.public_key().to_bytes(),
&NodeInformationPayload { node_id: self.node_id.clone(),
public_key: secret_key.public_key().to_bytes(), vented_version: PROTOCOL_VERSION.to_string(),
node_id: own_node_id, },
vented_version: PROTOCOL_VERSION.to_string(), )
}, .as_bytes(),
) )
.as_bytes(), .await?;
)?; stream.flush().await?;
stream.flush()?; let event = Event::from_async_tcp(&mut stream).await?;
let event = Event::from_bytes(&mut stream)?;
if event.name != CONNECT_EVENT { if event.name != CONNECT_EVENT {
return Err(VentedError::UnexpectedEvent(event.name)); return Err(VentedError::UnexpectedEvent(event.name));
@ -522,34 +419,39 @@ impl VentedServer {
} = event.get_payload::<NodeInformationPayload>().unwrap(); } = event.get_payload::<NodeInformationPayload>().unwrap();
if !Self::compare_version(&vented_version, PROTOCOL_VERSION) { if !Self::compare_version(&vented_version, PROTOCOL_VERSION) {
stream.write( stream
&Event::with_payload( .write(
MISMATCH_EVENT, &Event::with_payload(
&VersionMismatchPayload::new(PROTOCOL_VERSION, &vented_version), MISMATCH_EVENT,
&VersionMismatchPayload::new(PROTOCOL_VERSION, &vented_version),
)
.as_bytes(),
) )
.as_bytes(), .await?;
)?; stream.flush().await?;
stream.flush()?;
return Err(VentedError::VersionMismatch(vented_version)); return Err(VentedError::VersionMismatch(vented_version));
} }
let public_key = PublicKey::from(public_key); let public_key = PublicKey::from(public_key);
let node_data = if let Some(data) = known_nodes.lock().get(&node_id) { let node_data = if let Some(data) = self.known_nodes.lock().get(&node_id) {
data.clone() data.clone()
} else { } else {
stream.write(&Event::new(REJECT_EVENT).as_bytes())?; stream.write(&Event::new(REJECT_EVENT).as_bytes()).await?;
stream.flush()?; stream.flush().await?;
return Err(VentedError::UnknownNode(node_id)); return Err(VentedError::UnknownNode(node_id));
}; };
let mut stream = CryptoStream::new(node_id.clone(), stream, &public_key, &secret_key)?; let mut stream = CryptoStream::new(node_id.clone(), stream, &public_key, &secret_key)?;
log::trace!("Authenticating recipient..."); log::trace!("Authenticating recipient...");
let key_a = Self::authenticate_other(&mut stream, node_data.node().public_key)?; let key_a = Self::authenticate_other(&mut stream, node_data.node().public_key).await?;
log::trace!("Authenticating self..."); log::trace!("Authenticating self...");
let key_b = let key_b = Self::authenticate_self(
Self::authenticate_self(&mut stream, StaticSecret::from(global_secret.to_bytes()))?; &mut stream,
StaticSecret::from(self.global_secret_key.to_bytes()),
)
.await?;
log::trace!("Connection fully authenticated."); log::trace!("Connection fully authenticated.");
let pre_secret = StaticSecret::from(secret_key.to_bytes()).diffie_hellman(&public_key); let pre_secret = StaticSecret::from(secret_key.to_bytes()).diffie_hellman(&public_key);
@ -558,19 +460,18 @@ impl VentedServer {
let final_public = final_secret.public_key(); let final_public = final_secret.public_key();
stream.update_key(&final_secret, &final_public); stream.update_key(&final_secret, &final_public);
Ok((node_id, stream)) Ok(stream)
} }
/// Performs a DH key exchange by using the crypto_box module and events /// Performs a DH key exchange by using the crypto_box module and events
/// On success it returns a secret box with the established secret and the node id of the client /// On success it returns a secret box with the established secret and the node id of the client
fn perform_server_key_exchange( async fn perform_server_key_exchange(
&self,
mut stream: TcpStream, mut stream: TcpStream,
secret_key: &SecretKey, ) -> VentedResult<CryptoStream> {
own_node_id: String, let secret_key = SecretKey::generate(&mut rand::thread_rng());
global_secret: SecretKey, let event = Event::from_async_tcp(&mut stream).await?;
known_nodes: Arc<Mutex<HashMap<String, NodeData>>>,
) -> VentedResult<(String, CryptoStream)> {
let event = Event::from_bytes(&mut stream)?;
if event.name != CONNECT_EVENT { if event.name != CONNECT_EVENT {
return Err(VentedError::UnexpectedEvent(event.name)); return Err(VentedError::UnexpectedEvent(event.name));
} }
@ -581,46 +482,54 @@ impl VentedServer {
} = event.get_payload::<NodeInformationPayload>().unwrap(); } = event.get_payload::<NodeInformationPayload>().unwrap();
if !Self::compare_version(&vented_version, PROTOCOL_VERSION) { if !Self::compare_version(&vented_version, PROTOCOL_VERSION) {
stream.write( stream
&Event::with_payload( .write(
MISMATCH_EVENT, &Event::with_payload(
&VersionMismatchPayload::new(PROTOCOL_VERSION, &vented_version), MISMATCH_EVENT,
&VersionMismatchPayload::new(PROTOCOL_VERSION, &vented_version),
)
.as_bytes(),
) )
.as_bytes(), .await?;
)?; stream.flush().await?;
stream.flush()?;
return Err(VentedError::VersionMismatch(vented_version)); return Err(VentedError::VersionMismatch(vented_version));
} }
let public_key = PublicKey::from(public_key); let public_key = PublicKey::from(public_key);
let node_data = if let Some(data) = known_nodes.lock().get(&node_id) { let data_options = self.known_nodes.lock().get(&node_id).cloned();
data.clone() let node_data = if let Some(data) = data_options {
data
} else { } else {
stream.write(&Event::new(REJECT_EVENT).as_bytes())?; stream.write(&Event::new(REJECT_EVENT).as_bytes()).await?;
stream.flush()?; stream.flush().await?;
return Err(VentedError::UnknownNode(node_id)); return Err(VentedError::UnknownNode(node_id));
}; };
stream.write( stream
&Event::with_payload( .write(
CONNECT_EVENT, &Event::with_payload(
&NodeInformationPayload { CONNECT_EVENT,
public_key: secret_key.public_key().to_bytes(), &NodeInformationPayload {
node_id: own_node_id, public_key: secret_key.public_key().to_bytes(),
vented_version: PROTOCOL_VERSION.to_string(), node_id: self.node_id.clone(),
}, vented_version: PROTOCOL_VERSION.to_string(),
},
)
.as_bytes(),
) )
.as_bytes(), .await?;
)?; stream.flush().await?;
stream.flush()?;
let mut stream = CryptoStream::new(node_id.clone(), stream, &public_key, &secret_key)?; let mut stream = CryptoStream::new(node_id.clone(), stream, &public_key, &secret_key)?;
log::trace!("Authenticating self..."); log::trace!("Authenticating self...");
let key_a = let key_a = Self::authenticate_self(
Self::authenticate_self(&mut stream, StaticSecret::from(global_secret.to_bytes()))?; &mut stream,
StaticSecret::from(self.global_secret_key.to_bytes()),
)
.await?;
log::trace!("Authenticating recipient..."); log::trace!("Authenticating recipient...");
let key_b = Self::authenticate_other(&mut stream, node_data.node().public_key)?; let key_b = Self::authenticate_other(&mut stream, node_data.node().public_key).await?;
log::trace!("Connection fully authenticated."); log::trace!("Connection fully authenticated.");
let pre_secret = StaticSecret::from(secret_key.to_bytes()).diffie_hellman(&public_key); let pre_secret = StaticSecret::from(secret_key.to_bytes()).diffie_hellman(&public_key);
@ -629,59 +538,63 @@ impl VentedServer {
let final_public = final_secret.public_key(); let final_public = final_secret.public_key();
stream.update_key(&final_secret, &final_public); stream.update_key(&final_secret, &final_public);
Ok((node_id, stream)) Ok(stream)
} }
/// Performs the challenged side of the authentication challenge /// Performs the challenged side of the authentication challenge
fn authenticate_self( async fn authenticate_self(
stream: &CryptoStream, stream: &mut CryptoStream,
static_secret: StaticSecret, static_secret: StaticSecret,
) -> VentedResult<Vec<u8>> { ) -> VentedResult<Vec<u8>> {
let challenge_event = stream.read()?; let challenge_event = stream.read().await?;
if challenge_event.name != CHALLENGE_EVENT { if challenge_event.name != CHALLENGE_EVENT {
stream.send(Event::new(REJECT_EVENT))?; stream.send(Event::new(REJECT_EVENT)).await?;
return Err(VentedError::UnexpectedEvent(challenge_event.name)); return Err(VentedError::UnexpectedEvent(challenge_event.name));
} }
let ChallengePayload { public_key } = challenge_event.get_payload()?; let ChallengePayload { public_key } = challenge_event.get_payload()?;
let auth_key = static_secret.diffie_hellman(&PublicKey::from(public_key)); let auth_key = static_secret.diffie_hellman(&PublicKey::from(public_key));
stream.send(Event::with_payload( stream
AUTH_EVENT, .send(Event::with_payload(
&AuthPayload { AUTH_EVENT,
calculated_secret: auth_key.to_bytes(), &AuthPayload {
}, calculated_secret: auth_key.to_bytes(),
))?; },
))
.await?;
let response = stream.read()?; let response = stream.read().await?;
match response.name.as_str() { match response.name.as_str() {
ACCEPT_EVENT => Ok(auth_key.to_bytes().to_vec()), ACCEPT_EVENT => Ok(auth_key.to_bytes().to_vec()),
REJECT_EVENT => Err(VentedError::Rejected), REJECT_EVENT => Err(VentedError::Rejected),
_ => { _ => {
stream.send(Event::new(REJECT_EVENT))?; stream.send(Event::new(REJECT_EVENT)).await?;
Err(VentedError::UnexpectedEvent(response.name)) Err(VentedError::UnexpectedEvent(response.name))
} }
} }
} }
/// Authenticates the other party by using their stored public key and a generated secret /// Authenticates the other party by using their stored public key and a generated secret
fn authenticate_other( async fn authenticate_other(
stream: &CryptoStream, stream: &mut CryptoStream,
other_static_public: PublicKey, other_static_public: PublicKey,
) -> VentedResult<Vec<u8>> { ) -> VentedResult<Vec<u8>> {
let auth_secret = SecretKey::generate(&mut rand::thread_rng()); let auth_secret = SecretKey::generate(&mut rand::thread_rng());
stream.send(Event::with_payload( stream
CHALLENGE_EVENT, .send(Event::with_payload(
&ChallengePayload { CHALLENGE_EVENT,
public_key: auth_secret.public_key().to_bytes(), &ChallengePayload {
}, public_key: auth_secret.public_key().to_bytes(),
))?; },
))
.await?;
let auth_event = stream.read()?; let auth_event = stream.read().await?;
if auth_event.name != AUTH_EVENT { if auth_event.name != AUTH_EVENT {
stream.send(Event::new(REJECT_EVENT))?; stream.send(Event::new(REJECT_EVENT)).await?;
return Err(VentedError::UnexpectedEvent(auth_event.name)); return Err(VentedError::UnexpectedEvent(auth_event.name));
} }
let AuthPayload { calculated_secret } = auth_event.get_payload()?; let AuthPayload { calculated_secret } = auth_event.get_payload()?;
@ -689,10 +602,10 @@ impl VentedServer {
StaticSecret::from(auth_secret.to_bytes()).diffie_hellman(&other_static_public); StaticSecret::from(auth_secret.to_bytes()).diffie_hellman(&other_static_public);
if expected_secret.to_bytes() != calculated_secret { if expected_secret.to_bytes() != calculated_secret {
stream.send(Event::new(REJECT_EVENT))?; stream.send(Event::new(REJECT_EVENT)).await?;
Err(VentedError::AuthFailed) Err(VentedError::AuthFailed)
} else { } else {
stream.send(Event::new(ACCEPT_EVENT))?; stream.send(Event::new(ACCEPT_EVENT)).await?;
Ok(calculated_secret.to_vec()) Ok(calculated_secret.to_vec())
} }
} }

@ -103,153 +103,158 @@ impl VentedServer {
self.on(REDIRECT_CONFIRM_EVENT, { self.on(REDIRECT_CONFIRM_EVENT, {
let redirect_handles = Arc::clone(&self.redirect_handles); let redirect_handles = Arc::clone(&self.redirect_handles);
move |event| { move |event| {
let payload = event.get_payload::<RedirectResponsePayload>().ok()?; let redirect_handles = Arc::clone(&redirect_handles);
let mut future = redirect_handles.lock().remove(&payload.id)?; Box::pin(async move {
future.resolve(()); let payload = event.get_payload::<RedirectResponsePayload>().ok()?;
let mut value = redirect_handles.lock().remove(&payload.id)?;
None value.resolve(());
None
})
} }
}); });
self.on(REDIRECT_FAIL_EVENT, { self.on(REDIRECT_FAIL_EVENT, {
let redirect_handles = Arc::clone(&self.redirect_handles); let redirect_handles = Arc::clone(&self.redirect_handles);
move |event| { move |event| {
let payload = event.get_payload::<RedirectResponsePayload>().ok()?; let redirect_handles = Arc::clone(&redirect_handles);
let mut future = redirect_handles.lock().remove(&payload.id)?; Box::pin(async move {
future.reject(VentedError::Rejected); let payload = event.get_payload::<RedirectResponsePayload>().ok()?;
let mut value = redirect_handles.lock().remove(&payload.id)?;
value.reject(VentedError::Rejected);
None None
})
} }
}); });
self.on(REDIRECT_EVENT, { self.on(REDIRECT_EVENT, {
let manager = self.manager.clone(); let connections = Arc::clone(&self.connections);
let pool = Arc::clone(&self.sender_pool);
move |event| { move |event| {
let payload = event.get_payload::<RedirectPayload>().ok()?; let connections = Arc::clone(&connections);
let origin = event.origin?; Box::pin(async move {
let manager = manager.clone(); let payload = event.get_payload::<RedirectPayload>().ok()?;
if payload.source == event.origin? {
pool.lock().execute(move || { let opt_stream = connections.lock().get(&payload.target).cloned();
let response = if manager if let Some(mut stream) = opt_stream {
.send( if let Ok(_) = stream
&payload.target, .send(Event::with_payload(REDIRECT_REDIRECTED_EVENT, &payload))
Event::with_payload(REDIRECT_REDIRECTED_EVENT, &payload), .await
) {
.get_value() return Some(Event::with_payload(
.is_ok() REDIRECT_CONFIRM_EVENT,
{ &RedirectResponsePayload { id: payload.id },
Event::with_payload( ));
REDIRECT_CONFIRM_EVENT, }
&RedirectResponsePayload { id: payload.id }, }
) }
} else {
Event::with_payload(
REDIRECT_FAIL_EVENT,
&RedirectResponsePayload { id: payload.id },
)
};
manager.send(&origin, response);
});
None Some(Event::with_payload(
REDIRECT_FAIL_EVENT,
&RedirectResponsePayload { id: payload.id },
))
})
} }
}); });
self.on(REDIRECT_REDIRECTED_EVENT, { self.on(REDIRECT_REDIRECTED_EVENT, {
let event_handler = Arc::clone(&self.event_handler); let event_handler = self.event_handler.clone();
let manager = self.manager.clone(); let connections = Arc::clone(&self.connections);
let pool = self.sender_pool.clone();
let known_nodes = Arc::clone(&self.known_nodes);
move |event| { move |event| {
let payload = event.get_payload::<RedirectPayload>().ok()?; let connections = Arc::clone(&connections);
let event = Event::from_bytes(&mut &payload.content[..]).ok()?; let mut event_handler = event_handler.clone();
Box::pin(async move {
let payload = event.get_payload::<RedirectPayload>().ok()?;
let event = Event::from(&mut &payload.content[..]).ok()?;
let origin = event.origin.clone()?;
if known_nodes.lock().contains_key(&payload.source) { let responses = event_handler.handle_event(event).await;
pool.lock().execute({ let responses = responses
let event_handler = Arc::clone(&event_handler); .iter()
let manager = manager.clone(); .cloned()
move || { .map(|mut value| {
let responses = event_handler.lock().handle_event(event); let payload = payload.clone();
responses Event::with_payload(
.iter() REDIRECT_EVENT,
.cloned() &RedirectPayload::new(
.map(|mut value| { payload.target,
let payload = payload.clone(); payload.proxy,
Event::with_payload( payload.source,
REDIRECT_EVENT, value.as_bytes(),
&RedirectPayload::new( ),
payload.target, )
payload.proxy, })
payload.source, .collect::<Vec<Event>>();
value.as_bytes(), let opt_stream = connections.lock().get(&origin).cloned();
), if let Some(mut stream) = opt_stream {
) for response in responses {
}) stream.send(response).await.ok()?;
.for_each(|event| {
manager.send(&payload.proxy, event);
});
} }
}); }
}
None None
})
} }
}); });
self.on(NODE_LIST_EVENT, { self.on(NODE_LIST_EVENT, {
let node_list = Arc::clone(&self.known_nodes); let node_list = Arc::clone(&self.known_nodes);
let own_id = self.node_id.clone(); let own_node_id = self.node_id.clone();
move |event| { move |event| {
let list = event.get_payload::<NodeListPayload>().ok()?; let node_list = Arc::clone(&node_list);
let mut own_nodes = node_list.lock(); let own_node_id = own_node_id.clone();
let origin = event.origin?; Box::pin(async move {
let list = event.get_payload::<NodeListPayload>().ok()?;
let mut own_nodes = node_list.lock();
let origin = event.origin?;
if !own_nodes.get(&origin)?.node().trusted { if !own_nodes.get(&origin)?.node().trusted {
log::warn!("Untrusted node '{}' tried to send network update!", origin); log::warn!("Untrusted node '{}' tried to send network update!", origin);
return None; return None;
} }
let mut new_nodes = 0; let mut new_nodes = 0;
for node in list.nodes { for node in list.nodes {
if !own_nodes.contains_key(&node.id) && node.id != own_id { if !own_nodes.contains_key(&node.id) && node.id != own_node_id {
own_nodes.insert( own_nodes.insert(
node.id.clone(), node.id.clone(),
Node { Node {
id: node.id, id: node.id,
trusted: false, trusted: false,
public_key: PublicKey::from(node.public_key), public_key: PublicKey::from(node.public_key),
addresses: node.addresses, addresses: node.addresses,
} }
.into(), .into(),
); );
new_nodes += 1; new_nodes += 1;
}
} }
} log::debug!("Updated node list: Added {} new nodes", new_nodes);
log::debug!("Updated node list: Added {} new nodes", new_nodes);
None None
})
} }
}); });
self.on(NODE_LIST_REQUEST_EVENT, { self.on(NODE_LIST_REQUEST_EVENT, {
let node_list = Arc::clone(&self.known_nodes); let node_list = Arc::clone(&self.known_nodes);
move |event| { move |event| {
let sender_id = event.origin?; let node_list = Arc::clone(&node_list);
let nodes = node_list Box::pin(async move {
.lock() let sender_id = event.origin?;
.values() let nodes = node_list
.filter(|node| node.node().id != sender_id) .lock()
.map(|node| NodeListElement { .values()
id: node.node().id.clone(), .filter(|node| node.node().id != sender_id)
addresses: node.node().addresses.clone(), .map(|node| NodeListElement {
public_key: node.node().public_key.to_bytes(), id: node.node().id.clone(),
}) addresses: node.node().addresses.clone(),
.collect(); public_key: node.node().public_key.to_bytes(),
})
.collect();
Some(Event::with_payload( Some(Event::with_payload(
NODE_LIST_EVENT, NODE_LIST_EVENT,
&NodeListPayload { nodes }, &NodeListPayload { nodes },
)) ))
})
} }
}); });
} }

@ -1,6 +1,4 @@
use std::io::{Read, Write}; use async_std::prelude::*;
use std::net::{Shutdown, TcpStream};
use std::sync::Arc;
use byteorder::{BigEndian, ByteOrder}; use byteorder::{BigEndian, ByteOrder};
use crypto_box::aead::{Aead, Payload}; use crypto_box::aead::{Aead, Payload};
@ -8,18 +6,19 @@ use crypto_box::{ChaChaBox, SecretKey};
use generic_array::GenericArray; use generic_array::GenericArray;
use parking_lot::Mutex; use parking_lot::Mutex;
use sha2::Digest; use sha2::Digest;
use std::sync::Arc;
use typenum::*; use typenum::*;
use x25519_dalek::PublicKey; use x25519_dalek::PublicKey;
use crate::event::Event; use crate::event::Event;
use crate::utils::result::VentedResult; use crate::utils::result::VentedResult;
use async_std::net::{Shutdown, TcpStream};
/// A cryptographical stream object that handles encryption and decryption of streams /// A cryptographical stream object that handles encryption and decryption of streams
#[derive(Clone)] #[derive(Clone)]
pub struct CryptoStream { pub struct CryptoStream {
recv_node_id: String, recv_node_id: String,
send_stream: Arc<Mutex<TcpStream>>, stream: TcpStream,
recv_stream: Arc<Mutex<TcpStream>>,
send_secret: Arc<Mutex<EncryptionBox<ChaChaBox>>>, send_secret: Arc<Mutex<EncryptionBox<ChaChaBox>>>,
recv_secret: Arc<Mutex<EncryptionBox<ChaChaBox>>>, recv_secret: Arc<Mutex<EncryptionBox<ChaChaBox>>>,
} }
@ -32,15 +31,12 @@ impl CryptoStream {
public_key: &PublicKey, public_key: &PublicKey,
secret_key: &SecretKey, secret_key: &SecretKey,
) -> VentedResult<Self> { ) -> VentedResult<Self> {
let send_stream = Arc::new(Mutex::new(inner.try_clone()?));
let recv_stream = Arc::new(Mutex::new(inner));
let send_box = EncryptionBox::new(ChaChaBox::new(public_key, secret_key)); let send_box = EncryptionBox::new(ChaChaBox::new(public_key, secret_key));
let recv_box = EncryptionBox::new(ChaChaBox::new(public_key, secret_key)); let recv_box = EncryptionBox::new(ChaChaBox::new(public_key, secret_key));
Ok(Self { Ok(Self {
recv_node_id: node_id, recv_node_id: node_id,
send_stream, stream: inner,
recv_stream,
send_secret: Arc::new(Mutex::new(send_box)), send_secret: Arc::new(Mutex::new(send_box)),
recv_secret: Arc::new(Mutex::new(recv_box)), recv_secret: Arc::new(Mutex::new(recv_box)),
}) })
@ -50,17 +46,16 @@ impl CryptoStream {
/// format: /// format:
/// length: u64 /// length: u64
/// data: length /// data: length
pub fn send(&self, mut event: Event) -> VentedResult<()> { pub async fn send(&mut self, mut event: Event) -> VentedResult<()> {
let ciphertext = self.send_secret.lock().encrypt(&event.as_bytes())?; let ciphertext = self.send_secret.lock().encrypt(&event.as_bytes())?;
let mut stream = self.send_stream.lock();
let mut length_raw = [0u8; 8]; let mut length_raw = [0u8; 8];
BigEndian::write_u64(&mut length_raw, ciphertext.len() as u64); BigEndian::write_u64(&mut length_raw, ciphertext.len() as u64);
log::trace!("Encoded event '{}' to raw message", event.name); log::trace!("Encoded event '{}' to raw message", event.name);
stream.write(&length_raw)?; self.stream.write(&length_raw).await?;
stream.write(&ciphertext)?; self.stream.write(&ciphertext).await?;
stream.flush()?; self.stream.flush().await?;
log::trace!("Event sent"); log::trace!("Event sent");
@ -68,19 +63,18 @@ impl CryptoStream {
} }
/// Reads an event from the stream. Blocks until data is received /// Reads an event from the stream. Blocks until data is received
pub fn read(&self) -> VentedResult<Event> { pub async fn read(&mut self) -> VentedResult<Event> {
let mut stream = self.recv_stream.lock();
let mut length_raw = [0u8; 8]; let mut length_raw = [0u8; 8];
stream.read_exact(&mut length_raw)?; self.stream.read_exact(&mut length_raw).await?;
let length = BigEndian::read_u64(&length_raw); let length = BigEndian::read_u64(&length_raw);
let mut ciphertext = vec![0u8; length as usize]; let mut ciphertext = vec![0u8; length as usize];
stream.read(&mut ciphertext)?; self.stream.read(&mut ciphertext).await?;
log::trace!("Received raw message"); log::trace!("Received raw message");
let plaintext = self.recv_secret.lock().decrypt(&ciphertext)?; let plaintext = self.recv_secret.lock().decrypt(&ciphertext)?;
let event = Event::from_bytes(&mut &plaintext[..])?; let event = Event::from(&mut &plaintext[..])?;
log::trace!("Decoded message to event '{}'", event.name); log::trace!("Decoded message to event '{}'", event.name);
Ok(event) Ok(event)
@ -100,8 +94,8 @@ impl CryptoStream {
} }
/// Closes both streams /// Closes both streams
pub fn shutdown(&self) -> VentedResult<()> { pub fn shutdown(&mut self) -> VentedResult<()> {
self.send_stream.lock().shutdown(Shutdown::Both)?; self.stream.shutdown(Shutdown::Both)?;
Ok(()) Ok(())
} }

@ -1,148 +0,0 @@
use std::collections::HashMap;
use std::mem;
use std::sync::Arc;
use std::thread;
use std::thread::{JoinHandle, ThreadId};
use std::time::Duration;
use crossbeam_channel::{Receiver, Sender};
use parking_lot::Mutex;
use crate::event::Event;
use crate::stream::cryptostream::CryptoStream;
use crate::utils::result::{VentedError, VentedResult};
use crate::utils::sync::AsyncValue;
use crate::WaitGroup;
const MAX_ENQUEUED_EVENTS: usize = 50;
pub const CONNECTION_TIMEOUT_SECONDS: u64 = 5;
#[derive(Clone, Debug)]
pub struct ConcurrentStreamManager {
max_threads: usize,
threads: Arc<Mutex<HashMap<ThreadId, JoinHandle<()>>>>,
emitters: Arc<Mutex<HashMap<String, Sender<(Event, AsyncValue<(), VentedError>)>>>>,
event_receiver: Receiver<(String, Event)>,
listener_sender: Sender<(String, Event)>,
}
impl ConcurrentStreamManager {
pub fn new(max_threads: usize) -> Self {
let (sender, receiver) = crossbeam_channel::unbounded();
Self {
max_threads,
threads: Arc::new(Mutex::new(HashMap::new())),
emitters: Arc::new(Mutex::new(HashMap::new())),
event_receiver: receiver,
listener_sender: sender,
}
}
/// Returns if the manager has a connection to the given node
pub fn has_connection(&self, node: &String) -> bool {
self.emitters.lock().contains_key(node)
}
/// Returns the receiver for events
pub fn receiver(&self) -> Receiver<(String, Event)> {
self.event_receiver.clone()
}
/// Sends an event and returns an async value with the result
pub fn send(&self, target: &String, event: Event) -> AsyncValue<(), VentedError> {
let mut value = AsyncValue::new();
if let Some(emitter) = self.emitters.lock().get(target) {
if let Err(_) = emitter.send_timeout(
(event, value.clone()),
Duration::from_secs(CONNECTION_TIMEOUT_SECONDS),
) {
value.reject(VentedError::UnreachableNode(target.clone()));
}
} else {
value.reject(VentedError::UnknownNode(target.clone()))
}
value
}
/// Adds a connection to the manager causing it to start two new threads
/// This call blocks until the two threads are started up
pub fn add_connection(&self, stream: CryptoStream) -> VentedResult<()> {
if self.threads.lock().len() > self.max_threads {
return Err(VentedError::TooManyThreads);
}
let sender = self.listener_sender.clone();
let recv_id = stream.receiver_node().clone();
let (emitter, receiver) = crossbeam_channel::bounded(MAX_ENQUEUED_EVENTS);
self.emitters.lock().insert(recv_id.clone(), emitter);
let wg = WaitGroup::new();
let sender_thread = thread::Builder::new()
.name(format!("sender-{}", stream.receiver_node()))
.spawn({
let stream = stream.clone();
let recv_id = recv_id.clone();
let emitters = Arc::clone(&self.emitters);
let threads = Arc::clone(&self.threads);
let wg = WaitGroup::clone(&wg);
move || {
mem::drop(wg);
while let Ok((event, mut future)) = receiver.recv() {
if let Err(e) = stream.send(event) {
log::debug!("Failed to send event to {}: {}", recv_id, e);
future.reject(e);
break;
}
future.resolve(());
}
if let Err(e) = stream.shutdown() {
log::error!("Failed to shutdown stream: {}", e);
}
emitters.lock().remove(&recv_id);
threads.lock().remove(&thread::current().id());
}
})?;
self.threads
.lock()
.insert(sender_thread.thread().id(), sender_thread);
let receiver_thread = thread::Builder::new()
.name(format!("receiver-{}", stream.receiver_node()))
.spawn({
let threads = Arc::clone(&self.threads);
let wg = WaitGroup::clone(&wg);
move || {
mem::drop(wg);
loop {
match stream.read() {
Ok(mut event) => {
event.origin = Some(stream.receiver_node().clone());
if let Err(e) = sender.send((stream.receiver_node().clone(), event))
{
log::trace!("Failed to get event from {}: {}", recv_id, e);
break;
}
}
Err(e) => {
log::error!("Failed to send event: {}", e);
break;
}
}
}
if let Err(e) = stream.shutdown() {
log::error!("Failed to shutdown stream: {}", e);
}
threads.lock().remove(&thread::current().id());
}
})?;
self.threads
.lock()
.insert(receiver_thread.thread().id(), receiver_thread);
wg.wait();
Ok(())
}
}

@ -2,4 +2,3 @@ pub use crypto_box::PublicKey;
pub use crypto_box::SecretKey; pub use crypto_box::SecretKey;
pub mod cryptostream; pub mod cryptostream;
pub mod manager;

@ -1,6 +1,6 @@
use std::{mem, thread};
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use std::{mem};
use parking_lot::Mutex; use parking_lot::Mutex;
@ -15,8 +15,8 @@ pub struct AsyncValue<V, E> {
} }
impl<V, E> AsyncValue<V, E> impl<V, E> AsyncValue<V, E>
where where
E: std::fmt::Display, E: std::fmt::Display,
{ {
/// Creates the future with no value /// Creates the future with no value
pub fn new() -> Self { pub fn new() -> Self {
@ -51,8 +51,8 @@ impl<V, E> AsyncValue<V, E>
} }
pub fn on_error<F>(&mut self, cb: F) -> &mut Self pub fn on_error<F>(&mut self, cb: F) -> &mut Self
where where
F: FnOnce(&E) -> () + Send + Sync + 'static, F: FnOnce(&E) -> () + Send + Sync + 'static,
{ {
self.err_cb.lock().replace(Box::new(cb)); self.err_cb.lock().replace(Box::new(cb));
@ -60,8 +60,8 @@ impl<V, E> AsyncValue<V, E>
} }
pub fn on_success<F>(&mut self, cb: F) -> &mut Self pub fn on_success<F>(&mut self, cb: F) -> &mut Self
where where
F: FnOnce(&V) -> () + Send + Sync + 'static, F: FnOnce(&V) -> () + Send + Sync + 'static,
{ {
self.ok_cb.lock().replace(Box::new(cb)); self.ok_cb.lock().replace(Box::new(cb));
@ -113,12 +113,32 @@ impl<V, E> AsyncValue<V, E>
} }
} }
/// Returns the value asynchronously
pub async fn get_value_async(&mut self) -> Result<V, E> {
while self.value.lock().is_none() {
async_std::task::sleep(Duration::from_millis(1)).await;
}
if let Some(err) = self.error.lock().take() {
Err(err)
} else {
Ok(self.value.lock().take().unwrap())
}
}
/// Returns the value of the future only blocking for the given timeout /// Returns the value of the future only blocking for the given timeout
pub fn get_value_with_timeout(&mut self, timeout: Duration) -> Option<Result<V, E>> { pub fn get_value_with_timeout(&mut self, timeout: Duration) -> Option<Result<V, E>> {
async_std::task::block_on(self.get_value_with_timeout_async(timeout))
}
/// Returns the value of the future asynchronous with a timeout after the given duration
pub async fn get_value_with_timeout_async(
&mut self,
timeout: Duration,
) -> Option<Result<V, E>> {
let start = Instant::now(); let start = Instant::now();
while self.value.lock().is_none() { while self.value.lock().is_none() {
thread::sleep(Duration::from_millis(1)); async_std::task::sleep(Duration::from_millis(1)).await;
if start.elapsed() > timeout { if start.elapsed() > timeout {
break; break;
} }
@ -144,3 +164,6 @@ impl<T, E> Clone for AsyncValue<T, E> {
} }
} }
} }
unsafe impl<T, E> Sync for AsyncValue<T, E> {}
unsafe impl<T, E> Send for AsyncValue<T, E> {}

@ -1,7 +1,8 @@
use async_std::task;
use crypto_box::SecretKey; use crypto_box::SecretKey;
use log::LevelFilter;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::thread;
use std::time::Duration; use std::time::Duration;
use vented::event::Event; use vented::event::Event;
use vented::server::data::{Node, ServerTimeouts}; use vented::server::data::{Node, ServerTimeouts};
@ -9,7 +10,12 @@ use vented::server::server_events::NODE_LIST_REQUEST_EVENT;
use vented::server::VentedServer; use vented::server::VentedServer;
fn setup() { fn setup() {
simple_logger::SimpleLogger::new().init().unwrap(); simple_logger::SimpleLogger::new()
.with_module_level("async_std", LevelFilter::Warn)
.with_module_level("async_io", LevelFilter::Warn)
.with_module_level("polling", LevelFilter::Warn)
.init()
.unwrap();
} }
#[test] #[test]
@ -51,74 +57,80 @@ fn test_server_communication() {
trusted: false, trusted: false,
}) })
} }
let mut server_a = VentedServer::new(
"A".to_string(),
global_secret_a,
nodes_a,
ServerTimeouts::default(),
20,
100,
);
let mut server_b = VentedServer::new(
"B".to_string(),
global_secret_b,
nodes.clone(),
ServerTimeouts::default(),
3,
100,
);
let server_c = VentedServer::new(
"C".to_string(),
global_secret_c,
nodes,
ServerTimeouts::default(),
3,
100,
);
let wg = server_a.listen("localhost:22222".to_string());
wg.wait();
server_a.on("ping", { task::block_on(async {
let ping_count = Arc::clone(&ping_count); let mut server_a = VentedServer::new(
move |_| { "A".to_string(),
ping_count.fetch_add(1, Ordering::Relaxed); global_secret_a,
nodes_a,
ServerTimeouts::default(),
);
let mut server_b = VentedServer::new(
"B".to_string(),
global_secret_b,
nodes.clone(),
ServerTimeouts::default(),
);
let server_c = VentedServer::new(
"C".to_string(),
global_secret_c,
nodes,
ServerTimeouts::default(),
);
server_a.listen("localhost:22222".to_string());
Some(Event::new("pong".to_string())) server_a.on("ping", {
} let ping_count = Arc::clone(&ping_count);
}); move |_| {
server_b.on("pong", { let ping_count = Arc::clone(&ping_count);
let pong_count = Arc::clone(&pong_count); Box::pin(async move {
move |_| { ping_count.fetch_add(1, Ordering::Relaxed);
pong_count.fetch_add(1, Ordering::Relaxed);
None Some(Event::new("pong".to_string()))
})
}
});
server_b.on("pong", {
let pong_count = Arc::clone(&pong_count);
move |_| {
let pong_count = Arc::clone(&pong_count);
Box::pin(async move {
pong_count.fetch_add(1, Ordering::Relaxed);
None
})
}
});
for i in 0..10 {
assert!(server_a
.emit(format!("Nodes-{}", i), Event::new("ping"))
.await
.is_err());
} }
});
for i in 0..10 {
server_a.emit(format!("Nodes-{}", i), Event::new("ping"));
}
server_b
.emit("A", Event::new(NODE_LIST_REQUEST_EVENT))
.on_success(|_| println!("Success"))
.block_unwrap();
server_c
.emit("A", Event::new("ping".to_string()))
.block_unwrap();
for _ in 0..9 {
server_b server_b
.emit("A", Event::new(NODE_LIST_REQUEST_EVENT))
.await
.unwrap();
server_c
.emit("A", Event::new("ping".to_string())) .emit("A", Event::new("ping".to_string()))
.block_unwrap(); .await
} .unwrap();
server_a for _ in 0..9 {
.emit("B", Event::new("pong".to_string())) server_b
.block_unwrap(); .emit("A", Event::new("ping".to_string()))
server_b .await
.emit("C", Event::new("ping".to_string())) .unwrap();
.block_unwrap(); }
server_a
.emit("B", Event::new("pong".to_string()))
.await
.unwrap();
server_b
.emit("C", Event::new("ping".to_string()))
.await
.unwrap();
task::sleep(Duration::from_secs(1)).await;
});
// wait one second to make sure the servers were able to process the events // wait one second to make sure the servers were able to process the events
for _ in 0..100 {
thread::sleep(Duration::from_millis(10));
}
assert_eq!(ping_count.load(Ordering::SeqCst), 10); assert_eq!(ping_count.load(Ordering::SeqCst), 10);
assert_eq!(pong_count.load(Ordering::SeqCst), 10); assert_eq!(pong_count.load(Ordering::SeqCst), 10);

Loading…
Cancel
Save