2016-10-25 07:35:10 +03:00
|
|
|
// Copyright 2016 The Grin Developers
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
2016-10-29 22:36:45 +03:00
|
|
|
use std::cell::RefCell;
|
2016-10-31 04:23:52 +03:00
|
|
|
use std::io::{Read, Write};
|
|
|
|
use std::ops::{Deref, DerefMut};
|
2016-10-29 22:36:45 +03:00
|
|
|
use std::rc::Rc;
|
2016-10-31 04:23:52 +03:00
|
|
|
use std::sync::Mutex;
|
2016-10-29 22:36:45 +03:00
|
|
|
|
|
|
|
use mioco;
|
2016-10-30 18:24:19 +03:00
|
|
|
use mioco::sync::mpsc::{sync_channel, SyncSender};
|
2016-10-29 22:36:45 +03:00
|
|
|
use mioco::tcp::{TcpStream, Shutdown};
|
|
|
|
|
2016-10-25 07:35:10 +03:00
|
|
|
use core::ser;
|
2016-10-29 22:36:45 +03:00
|
|
|
use handshake::Handshake;
|
2016-10-26 08:06:13 +03:00
|
|
|
use msg::*;
|
|
|
|
use types::*;
|
2016-10-25 07:35:10 +03:00
|
|
|
|
2016-10-31 04:23:52 +03:00
|
|
|
/// First version of our communication protocol. Manages the underlying
|
|
|
|
/// connection, listening to incoming messages and transmitting outgoing ones.
|
2016-10-29 22:36:45 +03:00
|
|
|
pub struct ProtocolV1 {
|
2016-10-31 04:23:52 +03:00
|
|
|
// The underlying tcp connection.
|
2016-10-29 22:36:45 +03:00
|
|
|
conn: RefCell<TcpStream>,
|
2016-10-31 04:23:52 +03:00
|
|
|
// Send channel for the rest of the local system to send messages to the peer we're connected to.
|
|
|
|
msg_send: RefCell<Option<SyncSender<Vec<u8>>>>,
|
|
|
|
// Stop channel to exit the send/listen loop.
|
|
|
|
stop_send: RefCell<Option<SyncSender<u8>>>,
|
|
|
|
// Used both to count the amount of data sent and lock writing to the conn. We can't wrap conn with
|
|
|
|
// the lock as we're always listening to receive.
|
|
|
|
sent_bytes: Mutex<u64>,
|
2016-10-25 07:35:10 +03:00
|
|
|
}
|
|
|
|
|
2016-10-29 22:36:45 +03:00
|
|
|
impl Protocol for ProtocolV1 {
|
2016-10-31 04:23:52 +03:00
|
|
|
/// Main protocol connection handling loop, starts listening to incoming
|
|
|
|
/// messages and transmitting messages the rest of the local system wants
|
|
|
|
/// to send. Must be called before any interaction with a protocol instance
|
|
|
|
/// and should only be called once. Will block so also needs to be called
|
|
|
|
/// within a coroutine.
|
2016-10-29 22:36:45 +03:00
|
|
|
fn handle(&self, server: &NetAdapter) -> Option<ser::Error> {
|
2016-10-31 04:23:52 +03:00
|
|
|
// setup channels so we can switch between reads, writes and close
|
|
|
|
let (msg_send, msg_recv) = sync_channel(10);
|
|
|
|
let (stop_send, stop_recv) = sync_channel(1);
|
|
|
|
{
|
|
|
|
let mut msg_mut = self.msg_send.borrow_mut();
|
|
|
|
*msg_mut = Some(msg_send);
|
|
|
|
let mut stop_mut = self.stop_send.borrow_mut();
|
|
|
|
*stop_mut = Some(stop_send);
|
|
|
|
}
|
2016-10-29 22:36:45 +03:00
|
|
|
|
2016-10-31 04:23:52 +03:00
|
|
|
let mut conn = self.conn.borrow_mut();
|
2016-10-25 07:35:10 +03:00
|
|
|
loop {
|
2016-10-31 04:23:52 +03:00
|
|
|
// main select loop, switches between listening, sending or stopping
|
|
|
|
select!(
|
2016-10-29 22:36:45 +03:00
|
|
|
r:conn => {
|
2016-10-31 04:23:52 +03:00
|
|
|
// deser the header ot get the message type
|
2016-10-29 22:36:45 +03:00
|
|
|
let header = try_to_o!(ser::deserialize::<MsgHeader>(conn.deref_mut()));
|
|
|
|
if !header.acceptable() {
|
|
|
|
continue;
|
2016-10-31 04:23:52 +03:00
|
|
|
}
|
|
|
|
// check the message and hopefully do what's expected
|
|
|
|
match header.msg_type {
|
|
|
|
Type::Ping => {
|
|
|
|
// respond with pong
|
|
|
|
let data = try_to_o!(ser::ser_vec(&MsgHeader::new(Type::Pong)));
|
|
|
|
let mut sent_bytes = self.sent_bytes.lock().unwrap();
|
|
|
|
*sent_bytes += data.len() as u64;
|
|
|
|
try_to_o!(conn.deref_mut().write_all(&data[..]).map_err(&ser::Error::IOErr));
|
|
|
|
},
|
|
|
|
Type::Pong => {},
|
|
|
|
_ => error!("uncaught unknown"),
|
2016-10-29 22:36:45 +03:00
|
|
|
}
|
|
|
|
},
|
2016-10-30 18:24:19 +03:00
|
|
|
r:msg_recv => {
|
2016-10-31 04:23:52 +03:00
|
|
|
// relay a message originated from the rest of the local system
|
|
|
|
let data = &msg_recv.recv().unwrap()[..];
|
|
|
|
let mut sent_bytes = self.sent_bytes.lock().unwrap();
|
|
|
|
*sent_bytes += data.len() as u64;
|
|
|
|
try_to_o!(conn.deref_mut().write_all(data).map_err(&ser::Error::IOErr));
|
2016-10-30 18:24:19 +03:00
|
|
|
},
|
|
|
|
r:stop_recv => {
|
2016-10-31 04:23:52 +03:00
|
|
|
// shuts the connection don and end the loop
|
2016-10-30 18:24:19 +03:00
|
|
|
stop_recv.recv();
|
|
|
|
conn.shutdown(Shutdown::Both);
|
2016-10-31 04:23:52 +03:00
|
|
|
return None;
|
2016-10-29 22:36:45 +03:00
|
|
|
}
|
|
|
|
);
|
2016-10-25 07:35:10 +03:00
|
|
|
}
|
|
|
|
}
|
2016-10-30 18:24:19 +03:00
|
|
|
|
2016-10-31 04:23:52 +03:00
|
|
|
/// Sends a ping message to the remote peer. Will panic if handle has never
|
|
|
|
/// been called on this protocol.
|
|
|
|
fn send_ping(&self) -> Option<ser::Error> {
|
|
|
|
let data = try_to_o!(ser::ser_vec(&MsgHeader::new(Type::Ping)));
|
|
|
|
let msg_send = self.msg_send.borrow();
|
|
|
|
msg_send.as_ref().unwrap().send(data);
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
fn sent_bytes(&self) -> u64 {
|
|
|
|
*self.sent_bytes.lock().unwrap().deref()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn close(&self) {
|
|
|
|
let stop_send = self.stop_send.borrow();
|
|
|
|
stop_send.as_ref().unwrap().send(0);
|
|
|
|
}
|
2016-10-25 07:35:10 +03:00
|
|
|
}
|
|
|
|
|
2016-10-29 22:36:45 +03:00
|
|
|
impl ProtocolV1 {
|
|
|
|
pub fn new(conn: TcpStream) -> ProtocolV1 {
|
2016-10-31 04:23:52 +03:00
|
|
|
ProtocolV1 {
|
|
|
|
conn: RefCell::new(conn),
|
|
|
|
msg_send: RefCell::new(None),
|
|
|
|
stop_send: RefCell::new(None),
|
|
|
|
sent_bytes: Mutex::new(0),
|
|
|
|
}
|
2016-10-28 00:28:02 +03:00
|
|
|
}
|
2016-10-25 07:35:10 +03:00
|
|
|
}
|