2018-03-19 10:12:20 -07:00
|
|
|
//! Comms task structure. A comms task communicates with a remote node through a
|
|
|
|
//! socket. Local communication with coordinating threads is made via
|
2018-04-04 04:49:11 -07:00
|
|
|
//! `crossbeam_channel::unbounded()`.
|
2018-07-31 02:57:12 -07:00
|
|
|
use bincode;
|
2018-04-30 08:55:51 -07:00
|
|
|
use crossbeam;
|
|
|
|
use crossbeam_channel::{Receiver, Sender};
|
2018-10-24 02:38:14 -07:00
|
|
|
use serde::{de::DeserializeOwned, Serialize};
|
2018-04-30 08:55:51 -07:00
|
|
|
use std::io;
|
2018-04-06 08:04:28 -07:00
|
|
|
use std::net::TcpStream;
|
2018-03-20 09:32:19 -07:00
|
|
|
|
2018-10-10 07:11:27 -07:00
|
|
|
use hbbft::SourcedMessage;
|
2018-03-19 10:12:20 -07:00
|
|
|
|
2018-04-06 09:01:14 -07:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Error {
|
|
|
|
IoError(io::Error),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<io::Error> for Error {
|
2018-04-30 08:55:51 -07:00
|
|
|
fn from(err: io::Error) -> Error {
|
|
|
|
Error::IoError(err)
|
|
|
|
}
|
2018-04-06 09:01:14 -07:00
|
|
|
}
|
|
|
|
|
2018-03-19 10:12:20 -07:00
|
|
|
/// A communication task connects a remote node to the thread that manages the
|
|
|
|
/// consensus algorithm.
|
2018-07-31 02:57:12 -07:00
|
|
|
pub struct CommsTask<'a, M: 'a> {
|
2018-03-19 10:12:20 -07:00
|
|
|
/// The transmit side of the multiple producer channel from comms threads.
|
2018-05-10 08:50:07 -07:00
|
|
|
tx: &'a Sender<SourcedMessage<M, usize>>,
|
2018-04-05 05:09:46 -07:00
|
|
|
/// The receive side of the channel to the comms thread.
|
2018-05-10 08:50:07 -07:00
|
|
|
rx: &'a Receiver<M>,
|
2018-03-19 10:12:20 -07:00
|
|
|
/// The socket IO task.
|
2018-07-31 02:57:12 -07:00
|
|
|
stream: TcpStream,
|
2018-04-03 15:08:26 -07:00
|
|
|
/// The index of this comms task for identification against its remote node.
|
2018-04-30 08:55:51 -07:00
|
|
|
pub node_index: usize,
|
2018-03-19 10:12:20 -07:00
|
|
|
}
|
|
|
|
|
2018-10-24 02:38:14 -07:00
|
|
|
impl<'a, M: Serialize + DeserializeOwned + Send + 'a> CommsTask<'a, M> {
|
2018-04-30 08:55:51 -07:00
|
|
|
pub fn new(
|
2018-05-10 08:50:07 -07:00
|
|
|
tx: &'a Sender<SourcedMessage<M, usize>>,
|
|
|
|
rx: &'a Receiver<M>,
|
2018-04-30 08:55:51 -07:00
|
|
|
stream: TcpStream,
|
|
|
|
node_index: usize,
|
|
|
|
) -> Self {
|
|
|
|
debug!(
|
|
|
|
"Creating comms task #{} for {:?}",
|
|
|
|
node_index,
|
|
|
|
stream.peer_addr().unwrap()
|
|
|
|
);
|
2018-04-04 04:18:57 -07:00
|
|
|
|
2018-03-19 10:12:20 -07:00
|
|
|
CommsTask {
|
2018-04-29 06:27:40 -07:00
|
|
|
tx,
|
|
|
|
rx,
|
2018-07-31 02:57:12 -07:00
|
|
|
stream,
|
2018-04-30 08:55:51 -07:00
|
|
|
node_index,
|
2018-03-19 10:12:20 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The main socket IO loop and an asynchronous thread responding to manager
|
|
|
|
/// thread requests.
|
2018-05-10 08:50:07 -07:00
|
|
|
pub fn run(mut self) -> Result<(), Error> {
|
2018-03-20 09:32:19 -07:00
|
|
|
// Borrow parts of `self` before entering the thread binding scope.
|
2018-05-10 08:50:07 -07:00
|
|
|
let tx = self.tx;
|
|
|
|
let rx = self.rx;
|
2018-07-31 02:57:12 -07:00
|
|
|
let mut stream1 = self.stream.try_clone()?;
|
2018-04-03 15:08:26 -07:00
|
|
|
let node_index = self.node_index;
|
2018-03-20 09:32:19 -07:00
|
|
|
|
2018-05-10 08:50:07 -07:00
|
|
|
crossbeam::scope(move |scope| {
|
2018-03-20 09:32:19 -07:00
|
|
|
// Local comms receive loop thread.
|
|
|
|
scope.spawn(move || {
|
2018-04-04 05:49:37 -07:00
|
|
|
loop {
|
2018-04-05 05:09:46 -07:00
|
|
|
// Receive a multicast message from the manager thread.
|
|
|
|
let message = rx.recv().unwrap();
|
|
|
|
// Forward the message to the remote node.
|
2018-07-31 02:57:12 -07:00
|
|
|
bincode::serialize_into(&mut stream1, &message)
|
|
|
|
.expect("message serialization failed");
|
2018-04-04 04:49:11 -07:00
|
|
|
}
|
2018-03-20 09:32:19 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
// Remote comms receive loop.
|
2018-04-05 09:10:08 -07:00
|
|
|
debug!("Starting remote RX loop for node {}", node_index);
|
2018-03-20 09:32:19 -07:00
|
|
|
loop {
|
2018-07-31 02:57:12 -07:00
|
|
|
match bincode::deserialize_from(&mut self.stream) {
|
2018-04-04 04:18:57 -07:00
|
|
|
Ok(message) => {
|
2018-04-30 08:55:51 -07:00
|
|
|
tx.send(SourcedMessage {
|
|
|
|
source: node_index,
|
2018-07-31 02:57:12 -07:00
|
|
|
message,
|
2018-04-30 08:55:51 -07:00
|
|
|
}).unwrap();
|
|
|
|
}
|
2018-07-31 02:57:12 -07:00
|
|
|
Err(err) => {
|
|
|
|
if let bincode::ErrorKind::Io(ref io_err) = *err {
|
|
|
|
if io_err.kind() == io::ErrorKind::UnexpectedEof {
|
|
|
|
info!("Node {} disconnected.", node_index);
|
|
|
|
break;
|
|
|
|
}
|
2018-07-25 14:38:33 -07:00
|
|
|
}
|
2018-07-31 02:57:12 -07:00
|
|
|
panic!("Node {} - Deserialization error {:?}", node_index, err);
|
|
|
|
}
|
2018-03-19 10:12:20 -07:00
|
|
|
}
|
|
|
|
}
|
2018-03-20 09:32:19 -07:00
|
|
|
});
|
2018-04-06 09:01:14 -07:00
|
|
|
Ok(())
|
2018-03-19 10:12:20 -07:00
|
|
|
}
|
|
|
|
}
|