2018-11-07 04:51:22 +03:00
|
|
|
// Copyright 2018 The Grin Developers
|
2017-01-30 02:52:01 +03:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2017-02-02 06:05:17 +03:00
|
|
|
//! Provides a connection wrapper that handles the lower level tasks in sending
|
2017-03-08 04:00:34 +03:00
|
|
|
//! or receiving data from the TCP socket, as well as dealing with timeouts.
|
2018-02-02 05:03:12 +03:00
|
|
|
//!
|
|
|
|
//! Because of a few idiosyncracies in the Rust `TcpStream`, this has to use
|
|
|
|
//! async I/O to be able to both read *and* write on the connection. Which
|
|
|
|
//! forces us to go through some additional gymnastic to loop over the async
|
|
|
|
//! stream and make sure we get the right number of bytes out.
|
|
|
|
|
2018-02-10 01:32:16 +03:00
|
|
|
use std::fs::File;
|
|
|
|
use std::io::{self, Read, Write};
|
2019-01-04 20:08:44 +03:00
|
|
|
use std::net::{Shutdown, TcpStream};
|
2018-10-20 03:13:07 +03:00
|
|
|
use std::sync::{mpsc, Arc};
|
2019-05-15 18:51:35 +03:00
|
|
|
use std::{
|
|
|
|
cmp,
|
|
|
|
thread::{self, JoinHandle},
|
|
|
|
time,
|
|
|
|
};
|
2017-01-30 02:52:01 +03:00
|
|
|
|
2019-06-27 19:19:41 +03:00
|
|
|
use crate::core::ser::{self, FixedLength, ProtocolVersion};
|
2019-05-14 19:07:51 +03:00
|
|
|
use crate::msg::{
|
|
|
|
read_body, read_discard, read_header, read_item, write_to_buf, MsgHeader, MsgHeaderWrapper,
|
|
|
|
Type,
|
|
|
|
};
|
2018-12-08 02:59:40 +03:00
|
|
|
use crate::types::Error;
|
|
|
|
use crate::util::read_write::{read_exact, write_all};
|
|
|
|
use crate::util::{RateCounter, RwLock};
|
2017-01-30 02:52:01 +03:00
|
|
|
|
2018-02-10 01:32:16 +03:00
|
|
|
/// A trait to be implemented in order to receive messages from the
|
|
|
|
/// connection. Allows providing an optional response.
|
2018-02-02 05:03:12 +03:00
|
|
|
pub trait MessageHandler: Send + 'static {
|
2018-11-11 02:30:57 +03:00
|
|
|
fn consume<'a>(
|
|
|
|
&self,
|
|
|
|
msg: Message<'a>,
|
2018-12-08 02:59:40 +03:00
|
|
|
writer: &'a mut dyn Write,
|
2019-05-15 18:51:35 +03:00
|
|
|
tracker: Arc<Tracker>,
|
2018-11-11 02:30:57 +03:00
|
|
|
) -> Result<Option<Response<'a>>, Error>;
|
2017-01-30 02:52:01 +03:00
|
|
|
}
|
|
|
|
|
2018-06-13 19:03:34 +03:00
|
|
|
// Macro to simplify the boilerplate around async I/O error handling,
|
2018-02-02 05:03:12 +03:00
|
|
|
// especially with WouldBlock kind of errors.
|
|
|
|
macro_rules! try_break {
|
2019-05-03 17:35:43 +03:00
|
|
|
($inner:expr) => {
|
2018-02-02 05:03:12 +03:00
|
|
|
match $inner {
|
|
|
|
Ok(v) => Some(v),
|
2018-06-13 19:03:34 +03:00
|
|
|
Err(Error::Connection(ref e)) if e.kind() == io::ErrorKind::WouldBlock => None,
|
2019-04-26 21:22:07 +03:00
|
|
|
Err(Error::Store(_))
|
|
|
|
| Err(Error::Chain(_))
|
|
|
|
| Err(Error::Internal)
|
|
|
|
| Err(Error::NoDandelionRelay) => None,
|
2019-05-03 17:35:43 +03:00
|
|
|
Err(ref e) => {
|
|
|
|
debug!("try_break: exit the loop: {:?}", e);
|
2018-02-02 05:03:12 +03:00
|
|
|
break;
|
2018-06-13 19:03:34 +03:00
|
|
|
}
|
2018-02-02 05:03:12 +03:00
|
|
|
}
|
2018-06-13 19:03:34 +03:00
|
|
|
};
|
2017-01-30 02:52:01 +03:00
|
|
|
}
|
|
|
|
|
2018-02-10 01:32:16 +03:00
|
|
|
/// A message as received by the connection. Provides access to the message
|
|
|
|
/// header lazily consumes the message body, handling its deserialization.
|
2018-02-02 05:03:12 +03:00
|
|
|
pub struct Message<'a> {
|
|
|
|
pub header: MsgHeader,
|
2018-12-08 02:59:40 +03:00
|
|
|
stream: &'a mut dyn Read,
|
2019-06-27 19:19:41 +03:00
|
|
|
version: ProtocolVersion,
|
2017-01-30 02:52:01 +03:00
|
|
|
}
|
|
|
|
|
2018-02-02 05:03:12 +03:00
|
|
|
impl<'a> Message<'a> {
|
2019-06-27 19:19:41 +03:00
|
|
|
fn from_header(
|
|
|
|
header: MsgHeader,
|
|
|
|
stream: &'a mut dyn Read,
|
|
|
|
version: ProtocolVersion,
|
|
|
|
) -> Message<'a> {
|
|
|
|
Message {
|
|
|
|
header,
|
|
|
|
stream,
|
|
|
|
version,
|
|
|
|
}
|
2017-01-30 02:52:01 +03:00
|
|
|
}
|
|
|
|
|
2018-02-10 01:32:16 +03:00
|
|
|
/// Read the message body from the underlying connection
|
2018-11-16 14:00:39 +03:00
|
|
|
pub fn body<T: ser::Readable>(&mut self) -> Result<T, Error> {
|
2019-06-27 19:19:41 +03:00
|
|
|
read_body(&self.header, self.stream, self.version)
|
2017-01-30 02:52:01 +03:00
|
|
|
}
|
2018-02-10 01:32:16 +03:00
|
|
|
|
2018-11-16 14:00:39 +03:00
|
|
|
/// Read a single "thing" from the underlying connection.
|
|
|
|
/// Return the thing and the total bytes read.
|
|
|
|
pub fn streaming_read<T: ser::Readable>(&mut self) -> Result<(T, u64), Error> {
|
2019-06-27 19:19:41 +03:00
|
|
|
read_item(self.stream, self.version)
|
2018-11-16 14:00:39 +03:00
|
|
|
}
|
|
|
|
|
2018-12-08 02:59:40 +03:00
|
|
|
pub fn copy_attachment(&mut self, len: usize, writer: &mut dyn Write) -> Result<usize, Error> {
|
2018-02-10 01:32:16 +03:00
|
|
|
let mut written = 0;
|
|
|
|
while written < len {
|
|
|
|
let read_len = cmp::min(8000, len - written);
|
|
|
|
let mut buf = vec![0u8; read_len];
|
2018-08-31 20:20:59 +03:00
|
|
|
read_exact(
|
2018-11-16 17:33:35 +03:00
|
|
|
&mut self.stream,
|
2018-08-31 20:20:59 +03:00
|
|
|
&mut buf[..],
|
|
|
|
time::Duration::from_secs(10),
|
|
|
|
true,
|
|
|
|
)?;
|
2018-02-10 01:32:16 +03:00
|
|
|
writer.write_all(&mut buf)?;
|
|
|
|
written += read_len;
|
|
|
|
}
|
2018-10-13 01:53:50 +03:00
|
|
|
Ok(written)
|
2018-02-10 01:32:16 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-16 17:33:35 +03:00
|
|
|
/// Response to a `Message`.
|
2018-02-10 01:32:16 +03:00
|
|
|
pub struct Response<'a> {
|
|
|
|
resp_type: Type,
|
|
|
|
body: Vec<u8>,
|
2018-12-08 02:59:40 +03:00
|
|
|
stream: &'a mut dyn Write,
|
2018-02-10 01:32:16 +03:00
|
|
|
attachment: Option<File>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Response<'a> {
|
2018-12-08 02:59:40 +03:00
|
|
|
pub fn new<T: ser::Writeable>(
|
|
|
|
resp_type: Type,
|
|
|
|
body: T,
|
|
|
|
stream: &'a mut dyn Write,
|
2019-02-25 21:48:54 +03:00
|
|
|
) -> Result<Response<'a>, Error> {
|
|
|
|
let body = ser::ser_vec(&body)?;
|
|
|
|
Ok(Response {
|
2018-11-16 17:33:35 +03:00
|
|
|
resp_type,
|
|
|
|
body,
|
|
|
|
stream,
|
|
|
|
attachment: None,
|
2019-02-25 21:48:54 +03:00
|
|
|
})
|
2018-11-16 17:33:35 +03:00
|
|
|
}
|
|
|
|
|
2019-05-15 18:51:35 +03:00
|
|
|
fn write(mut self, tracker: Arc<Tracker>) -> Result<(), Error> {
|
2019-02-25 21:48:54 +03:00
|
|
|
let mut msg = ser::ser_vec(&MsgHeader::new(self.resp_type, self.body.len() as u64))?;
|
2018-02-10 01:32:16 +03:00
|
|
|
msg.append(&mut self.body);
|
2018-11-16 17:33:35 +03:00
|
|
|
write_all(&mut self.stream, &msg[..], time::Duration::from_secs(10))?;
|
2019-05-15 18:51:35 +03:00
|
|
|
tracker.inc_sent(msg.len() as u64);
|
|
|
|
|
2018-02-10 01:32:16 +03:00
|
|
|
if let Some(mut file) = self.attachment {
|
|
|
|
let mut buf = [0u8; 8000];
|
|
|
|
loop {
|
|
|
|
match file.read(&mut buf[..]) {
|
|
|
|
Ok(0) => break,
|
2018-11-11 02:30:57 +03:00
|
|
|
Ok(n) => {
|
2018-11-16 17:33:35 +03:00
|
|
|
write_all(&mut self.stream, &buf[..n], time::Duration::from_secs(10))?;
|
2018-11-14 00:34:45 +03:00
|
|
|
// Increase sent bytes "quietly" without incrementing the counter.
|
|
|
|
// (In a loop here for the single attachment).
|
2019-05-15 18:51:35 +03:00
|
|
|
tracker.inc_quiet_sent(n as u64);
|
2018-11-11 02:30:57 +03:00
|
|
|
}
|
2018-02-10 01:32:16 +03:00
|
|
|
Err(e) => return Err(From::from(e)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_attachment(&mut self, file: File) {
|
|
|
|
self.attachment = Some(file);
|
|
|
|
}
|
2017-12-14 20:23:35 +03:00
|
|
|
}
|
2017-02-02 06:05:17 +03:00
|
|
|
|
2018-10-17 02:31:00 +03:00
|
|
|
pub const SEND_CHANNEL_CAP: usize = 10;
|
|
|
|
|
2019-05-15 18:51:35 +03:00
|
|
|
pub struct StopHandle {
|
2018-02-02 05:03:12 +03:00
|
|
|
/// Channel to close the connection
|
|
|
|
pub close_channel: mpsc::Sender<()>,
|
2019-05-15 18:51:35 +03:00
|
|
|
// we need Option to take ownhership of the handle in stop()
|
|
|
|
peer_thread: Option<JoinHandle<()>>,
|
2017-02-02 06:05:17 +03:00
|
|
|
}
|
|
|
|
|
2019-05-15 18:51:35 +03:00
|
|
|
impl StopHandle {
|
|
|
|
/// Schedule this connection to safely close via the async close_channel.
|
|
|
|
pub fn stop(&self) {
|
|
|
|
if self.close_channel.send(()).is_err() {
|
|
|
|
debug!("peer's close_channel is disconnected, must be stopped already");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-30 03:03:12 +03:00
|
|
|
pub fn wait(&mut self) {
|
2019-05-15 18:51:35 +03:00
|
|
|
if let Some(peer_thread) = self.peer_thread.take() {
|
|
|
|
// wait only if other thread is calling us, eg shutdown
|
|
|
|
if thread::current().id() != peer_thread.thread().id() {
|
|
|
|
debug!("waiting for thread {:?} exit", peer_thread.thread().id());
|
|
|
|
if let Err(e) = peer_thread.join() {
|
2019-05-30 03:03:12 +03:00
|
|
|
error!("failed to wait for peer thread to stop: {:?}", e);
|
2019-05-15 18:51:35 +03:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
debug!(
|
2019-05-30 03:03:12 +03:00
|
|
|
"attempt to wait for thread {:?} from itself",
|
2019-05-15 18:51:35 +03:00
|
|
|
peer_thread.thread().id()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ConnHandle {
|
|
|
|
/// Channel to allow sending data through the connection
|
|
|
|
pub send_channel: mpsc::SyncSender<Vec<u8>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ConnHandle {
|
|
|
|
pub fn send<T>(&self, body: T, msg_type: Type) -> Result<u64, Error>
|
2017-10-26 20:48:51 +03:00
|
|
|
where
|
2018-03-04 03:19:54 +03:00
|
|
|
T: ser::Writeable,
|
2017-02-02 06:05:17 +03:00
|
|
|
{
|
2019-02-25 21:48:54 +03:00
|
|
|
let buf = write_to_buf(body, msg_type)?;
|
2018-10-17 20:01:42 +03:00
|
|
|
let buf_len = buf.len();
|
2018-03-30 09:02:40 +03:00
|
|
|
self.send_channel.try_send(buf)?;
|
2019-05-15 18:51:35 +03:00
|
|
|
Ok(buf_len as u64)
|
|
|
|
}
|
|
|
|
}
|
2018-10-17 20:01:42 +03:00
|
|
|
|
2019-05-15 18:51:35 +03:00
|
|
|
pub struct Tracker {
|
|
|
|
/// Bytes we've sent.
|
|
|
|
pub sent_bytes: Arc<RwLock<RateCounter>>,
|
|
|
|
/// Bytes we've received.
|
|
|
|
pub received_bytes: Arc<RwLock<RateCounter>>,
|
|
|
|
}
|
2018-10-17 20:01:42 +03:00
|
|
|
|
2019-05-15 18:51:35 +03:00
|
|
|
impl Tracker {
|
|
|
|
pub fn new() -> Tracker {
|
|
|
|
let received_bytes = Arc::new(RwLock::new(RateCounter::new()));
|
|
|
|
let sent_bytes = Arc::new(RwLock::new(RateCounter::new()));
|
|
|
|
Tracker {
|
|
|
|
received_bytes,
|
|
|
|
sent_bytes,
|
|
|
|
}
|
2018-02-02 05:03:12 +03:00
|
|
|
}
|
2019-05-03 17:56:25 +03:00
|
|
|
|
2019-05-15 18:51:35 +03:00
|
|
|
pub fn inc_received(&self, size: u64) {
|
|
|
|
self.received_bytes.write().inc(size);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn inc_sent(&self, size: u64) {
|
|
|
|
self.sent_bytes.write().inc(size);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn inc_quiet_received(&self, size: u64) {
|
|
|
|
self.received_bytes.write().inc_quiet(size);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn inc_quiet_sent(&self, size: u64) {
|
|
|
|
self.sent_bytes.write().inc_quiet(size);
|
2019-05-03 17:56:25 +03:00
|
|
|
}
|
2018-02-02 05:03:12 +03:00
|
|
|
}
|
2017-02-02 06:05:17 +03:00
|
|
|
|
2018-02-02 05:03:12 +03:00
|
|
|
/// Start listening on the provided connection and wraps it. Does not hang
|
|
|
|
/// the current thread, instead just returns a future and the Connection
|
|
|
|
/// itself.
|
2019-05-15 18:51:35 +03:00
|
|
|
pub fn listen<H>(
|
|
|
|
stream: TcpStream,
|
2019-06-27 19:19:41 +03:00
|
|
|
version: ProtocolVersion,
|
2019-05-15 18:51:35 +03:00
|
|
|
tracker: Arc<Tracker>,
|
|
|
|
handler: H,
|
|
|
|
) -> io::Result<(ConnHandle, StopHandle)>
|
2018-02-02 05:03:12 +03:00
|
|
|
where
|
|
|
|
H: MessageHandler,
|
|
|
|
{
|
2018-10-17 02:31:00 +03:00
|
|
|
let (send_tx, send_rx) = mpsc::sync_channel(SEND_CHANNEL_CAP);
|
2018-02-02 05:03:12 +03:00
|
|
|
let (close_tx, close_rx) = mpsc::channel();
|
|
|
|
|
2018-03-04 03:19:54 +03:00
|
|
|
stream
|
|
|
|
.set_nonblocking(true)
|
|
|
|
.expect("Non-blocking IO not available.");
|
2019-06-27 19:19:41 +03:00
|
|
|
let peer_thread = poll(stream, version, handler, send_rx, close_rx, tracker)?;
|
2019-05-15 18:51:35 +03:00
|
|
|
|
|
|
|
Ok((
|
|
|
|
ConnHandle {
|
|
|
|
send_channel: send_tx,
|
|
|
|
},
|
|
|
|
StopHandle {
|
|
|
|
close_channel: close_tx,
|
|
|
|
peer_thread: Some(peer_thread),
|
|
|
|
},
|
|
|
|
))
|
2018-02-02 05:03:12 +03:00
|
|
|
}
|
2017-02-02 06:05:17 +03:00
|
|
|
|
2018-02-02 05:03:12 +03:00
|
|
|
fn poll<H>(
|
|
|
|
conn: TcpStream,
|
2019-06-27 19:19:41 +03:00
|
|
|
version: ProtocolVersion,
|
2018-02-02 05:03:12 +03:00
|
|
|
handler: H,
|
|
|
|
send_rx: mpsc::Receiver<Vec<u8>>,
|
2018-03-04 03:19:54 +03:00
|
|
|
close_rx: mpsc::Receiver<()>,
|
2019-05-15 18:51:35 +03:00
|
|
|
tracker: Arc<Tracker>,
|
|
|
|
) -> io::Result<JoinHandle<()>>
|
|
|
|
where
|
2018-02-02 05:03:12 +03:00
|
|
|
H: MessageHandler,
|
|
|
|
{
|
2018-11-16 17:33:35 +03:00
|
|
|
// Split out tcp stream out into separate reader/writer halves.
|
|
|
|
let mut reader = conn.try_clone().expect("clone conn for reader failed");
|
|
|
|
let mut writer = conn.try_clone().expect("clone conn for writer failed");
|
|
|
|
|
2019-05-15 18:51:35 +03:00
|
|
|
thread::Builder::new()
|
2018-03-04 03:19:54 +03:00
|
|
|
.name("peer".to_string())
|
|
|
|
.spawn(move || {
|
2019-04-23 09:29:24 +03:00
|
|
|
let sleep_time = time::Duration::from_millis(5);
|
2018-03-04 03:19:54 +03:00
|
|
|
let mut retry_send = Err(());
|
|
|
|
loop {
|
|
|
|
// check the read end
|
2019-06-27 19:19:41 +03:00
|
|
|
match try_break!(read_header(&mut reader, version, None)) {
|
2019-05-14 19:07:51 +03:00
|
|
|
Some(MsgHeaderWrapper::Known(header)) => {
|
2019-06-27 19:19:41 +03:00
|
|
|
let msg = Message::from_header(header, &mut reader, version);
|
2019-05-14 19:07:51 +03:00
|
|
|
|
|
|
|
trace!(
|
|
|
|
"Received message header, type {:?}, len {}.",
|
|
|
|
msg.header.msg_type,
|
|
|
|
msg.header.msg_len
|
|
|
|
);
|
|
|
|
|
|
|
|
// Increase received bytes counter
|
2019-05-15 18:51:35 +03:00
|
|
|
tracker.inc_received(MsgHeader::LEN as u64 + msg.header.msg_len);
|
2019-05-14 19:07:51 +03:00
|
|
|
|
|
|
|
if let Some(Some(resp)) =
|
2019-05-15 18:51:35 +03:00
|
|
|
try_break!(handler.consume(msg, &mut writer, tracker.clone()))
|
2019-05-14 19:07:51 +03:00
|
|
|
{
|
2019-05-15 18:51:35 +03:00
|
|
|
try_break!(resp.write(tracker.clone()));
|
2019-05-14 19:07:51 +03:00
|
|
|
}
|
2018-10-17 20:01:42 +03:00
|
|
|
}
|
2019-05-14 19:07:51 +03:00
|
|
|
Some(MsgHeaderWrapper::Unknown(msg_len)) => {
|
|
|
|
// Increase received bytes counter
|
2019-05-15 18:51:35 +03:00
|
|
|
tracker.inc_received(MsgHeader::LEN as u64 + msg_len);
|
2018-10-17 20:01:42 +03:00
|
|
|
|
2019-05-14 19:07:51 +03:00
|
|
|
try_break!(read_discard(msg_len, &mut reader));
|
2018-03-04 03:19:54 +03:00
|
|
|
}
|
2019-05-14 19:07:51 +03:00
|
|
|
None => {}
|
2017-02-02 06:05:17 +03:00
|
|
|
}
|
|
|
|
|
2018-11-07 04:51:22 +03:00
|
|
|
// check the write end, use or_else so try_recv is lazily eval'd
|
|
|
|
let maybe_data = retry_send.or_else(|_| send_rx.try_recv());
|
|
|
|
retry_send = Err(());
|
|
|
|
if let Ok(data) = maybe_data {
|
2019-05-15 18:51:35 +03:00
|
|
|
let written = try_break!(write_all(
|
|
|
|
&mut writer,
|
|
|
|
&data[..],
|
|
|
|
std::time::Duration::from_secs(10)
|
|
|
|
)
|
|
|
|
.map_err(&From::from));
|
2018-11-07 04:51:22 +03:00
|
|
|
if written.is_none() {
|
2018-03-04 03:19:54 +03:00
|
|
|
retry_send = Ok(data);
|
|
|
|
}
|
2018-02-02 05:03:12 +03:00
|
|
|
}
|
2018-03-04 03:19:54 +03:00
|
|
|
|
|
|
|
// check the close channel
|
|
|
|
if let Ok(_) = close_rx.try_recv() {
|
|
|
|
break;
|
2018-02-02 05:03:12 +03:00
|
|
|
}
|
2017-12-14 20:23:35 +03:00
|
|
|
|
2018-03-04 03:19:54 +03:00
|
|
|
thread::sleep(sleep_time);
|
2018-02-02 05:03:12 +03:00
|
|
|
}
|
2019-05-03 17:35:43 +03:00
|
|
|
|
|
|
|
debug!(
|
|
|
|
"Shutting down connection with {}",
|
|
|
|
conn.peer_addr()
|
|
|
|
.map(|a| a.to_string())
|
|
|
|
.unwrap_or("?".to_owned())
|
|
|
|
);
|
2019-01-07 09:44:07 +03:00
|
|
|
let _ = conn.shutdown(Shutdown::Both);
|
2019-05-15 18:51:35 +03:00
|
|
|
})
|
2018-02-02 05:03:12 +03:00
|
|
|
}
|