mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 17:01:09 +03:00
Proper server and protocol event loop. Channels for shutdown and ping/pong trivial roundtrip. Working test.
This commit is contained in:
parent
2efa8ce706
commit
ee6fcab8db
8 changed files with 268 additions and 156 deletions
|
@ -79,7 +79,7 @@ impl Handshake {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let peer_info = PeerInfo{
|
let peer_info = PeerInfo {
|
||||||
capabilities: shake.capabilities,
|
capabilities: shake.capabilities,
|
||||||
user_agent: shake.user_agent,
|
user_agent: shake.user_agent,
|
||||||
addr: receiver_addr,
|
addr: receiver_addr,
|
||||||
|
@ -119,7 +119,7 @@ impl Handshake {
|
||||||
}
|
}
|
||||||
|
|
||||||
// all good, keep peer info
|
// all good, keep peer info
|
||||||
let peer_info = PeerInfo{
|
let peer_info = PeerInfo {
|
||||||
capabilities: hand.capabilities,
|
capabilities: hand.capabilities,
|
||||||
user_agent: hand.user_agent,
|
user_agent: hand.user_agent,
|
||||||
addr: conn.peer_addr().unwrap(),
|
addr: conn.peer_addr().unwrap(),
|
||||||
|
|
|
@ -39,5 +39,5 @@ mod protocol;
|
||||||
mod server;
|
mod server;
|
||||||
mod peer;
|
mod peer;
|
||||||
|
|
||||||
pub use server::Server;
|
pub use server::{Server, DummyAdapter};
|
||||||
pub use server::DEFAULT_LISTEN_ADDR;
|
pub use server::DEFAULT_LISTEN_ADDR;
|
||||||
|
|
|
@ -36,13 +36,13 @@ pub enum ErrCodes {
|
||||||
/// Types of messages
|
/// Types of messages
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
ERROR,
|
Error,
|
||||||
HAND,
|
Hand,
|
||||||
SHAKE,
|
Shake,
|
||||||
PING,
|
Ping,
|
||||||
PONG,
|
Pong,
|
||||||
GETPEERADDRS,
|
GetPeerAddrs,
|
||||||
PEERADDRS,
|
PeerAddrs,
|
||||||
/// Never used over the network but to detect unrecognized types.
|
/// Never used over the network but to detect unrecognized types.
|
||||||
MaxMsgType,
|
MaxMsgType,
|
||||||
}
|
}
|
||||||
|
@ -50,10 +50,17 @@ pub enum Type {
|
||||||
/// Header of any protocol message, used to identify incoming messages.
|
/// Header of any protocol message, used to identify incoming messages.
|
||||||
pub struct MsgHeader {
|
pub struct MsgHeader {
|
||||||
magic: [u8; 2],
|
magic: [u8; 2],
|
||||||
msg_type: Type,
|
pub msg_type: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MsgHeader {
|
impl MsgHeader {
|
||||||
|
pub fn new(msg_type: Type) -> MsgHeader {
|
||||||
|
MsgHeader {
|
||||||
|
magic: MAGIC,
|
||||||
|
msg_type: msg_type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn acceptable(&self) -> bool {
|
pub fn acceptable(&self) -> bool {
|
||||||
(self.msg_type as u8) < (Type::MaxMsgType as u8)
|
(self.msg_type as u8) < (Type::MaxMsgType as u8)
|
||||||
}
|
}
|
||||||
|
@ -74,20 +81,20 @@ impl Readable<MsgHeader> for MsgHeader {
|
||||||
try!(reader.expect_u8(MAGIC[0]));
|
try!(reader.expect_u8(MAGIC[0]));
|
||||||
try!(reader.expect_u8(MAGIC[1]));
|
try!(reader.expect_u8(MAGIC[1]));
|
||||||
let t = try!(reader.read_u8());
|
let t = try!(reader.read_u8());
|
||||||
if t < (Type::MaxMsgType as u8) {
|
if t >= (Type::MaxMsgType as u8) {
|
||||||
return Err(ser::Error::CorruptedData);
|
return Err(ser::Error::CorruptedData);
|
||||||
}
|
}
|
||||||
Ok(MsgHeader {
|
Ok(MsgHeader {
|
||||||
magic: MAGIC,
|
magic: MAGIC,
|
||||||
msg_type: match t {
|
msg_type: match t {
|
||||||
// TODO this is rather ugly, think of a better way
|
// TODO this is rather ugly, think of a better way
|
||||||
0 => Type::ERROR,
|
0 => Type::Error,
|
||||||
1 => Type::HAND,
|
1 => Type::Hand,
|
||||||
2 => Type::SHAKE,
|
2 => Type::Shake,
|
||||||
3 => Type::PING,
|
3 => Type::Ping,
|
||||||
4 => Type::PONG,
|
4 => Type::Pong,
|
||||||
5 => Type::GETPEERADDRS,
|
5 => Type::GetPeerAddrs,
|
||||||
6 => Type::PEERADDRS,
|
6 => Type::PeerAddrs,
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -16,7 +16,6 @@ use mioco::tcp::TcpStream;
|
||||||
|
|
||||||
use core::ser::Error;
|
use core::ser::Error;
|
||||||
use handshake::Handshake;
|
use handshake::Handshake;
|
||||||
use msg::*;
|
|
||||||
use types::*;
|
use types::*;
|
||||||
|
|
||||||
pub struct Peer {
|
pub struct Peer {
|
||||||
|
@ -28,10 +27,9 @@ unsafe impl Sync for Peer {}
|
||||||
unsafe impl Send for Peer {}
|
unsafe impl Send for Peer {}
|
||||||
|
|
||||||
impl Peer {
|
impl Peer {
|
||||||
|
|
||||||
pub fn connect(conn: TcpStream, hs: &Handshake) -> Result<Peer, Error> {
|
pub fn connect(conn: TcpStream, hs: &Handshake) -> Result<Peer, Error> {
|
||||||
let (proto, info) = try!(hs.connect(conn));
|
let (proto, info) = try!(hs.connect(conn));
|
||||||
Ok(Peer{
|
Ok(Peer {
|
||||||
info: info,
|
info: info,
|
||||||
proto: proto,
|
proto: proto,
|
||||||
})
|
})
|
||||||
|
@ -39,7 +37,7 @@ impl Peer {
|
||||||
|
|
||||||
pub fn accept(conn: TcpStream, hs: &Handshake) -> Result<Peer, Error> {
|
pub fn accept(conn: TcpStream, hs: &Handshake) -> Result<Peer, Error> {
|
||||||
let (proto, info) = try!(hs.handshake(conn));
|
let (proto, info) = try!(hs.handshake(conn));
|
||||||
Ok(Peer{
|
Ok(Peer {
|
||||||
info: info,
|
info: info,
|
||||||
proto: proto,
|
proto: proto,
|
||||||
})
|
})
|
||||||
|
@ -49,6 +47,14 @@ impl Peer {
|
||||||
self.proto.handle(na)
|
self.proto.handle(na)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn send_ping(&self) -> Option<Error> {
|
||||||
|
self.proto.send_ping()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sent_bytes(&self) -> u64 {
|
||||||
|
self.proto.sent_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn stop(&self) {
|
pub fn stop(&self) {
|
||||||
self.proto.as_ref().close()
|
self.proto.as_ref().close()
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,10 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ops::DerefMut;
|
use std::io::{Read, Write};
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use mioco;
|
use mioco;
|
||||||
use mioco::sync::mpsc::{sync_channel, SyncSender};
|
use mioco::sync::mpsc::{sync_channel, SyncSender};
|
||||||
|
@ -25,43 +27,90 @@ use handshake::Handshake;
|
||||||
use msg::*;
|
use msg::*;
|
||||||
use types::*;
|
use types::*;
|
||||||
|
|
||||||
|
/// First version of our communication protocol. Manages the underlying
|
||||||
|
/// connection, listening to incoming messages and transmitting outgoing ones.
|
||||||
pub struct ProtocolV1 {
|
pub struct ProtocolV1 {
|
||||||
|
// The underlying tcp connection.
|
||||||
conn: RefCell<TcpStream>,
|
conn: RefCell<TcpStream>,
|
||||||
//msg_send: Option<SyncSender<ser::Writeable>>,
|
// 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>>>,
|
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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Protocol for ProtocolV1 {
|
impl Protocol for ProtocolV1 {
|
||||||
|
/// 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.
|
||||||
fn handle(&self, server: &NetAdapter) -> Option<ser::Error> {
|
fn handle(&self, server: &NetAdapter) -> Option<ser::Error> {
|
||||||
// setup channels so we can switch between reads, writes and close
|
// setup channels so we can switch between reads, writes and close
|
||||||
let (msg_send, msg_recv) = sync_channel(10);
|
let (msg_send, msg_recv) = sync_channel(10);
|
||||||
let (stop_send, stop_recv) = sync_channel(1);
|
let (stop_send, stop_recv) = sync_channel(1);
|
||||||
|
{
|
||||||
//self.msg_send = Some(msg_send);
|
let mut msg_mut = self.msg_send.borrow_mut();
|
||||||
|
*msg_mut = Some(msg_send);
|
||||||
let mut stop_mut = self.stop_send.borrow_mut();
|
let mut stop_mut = self.stop_send.borrow_mut();
|
||||||
*stop_mut = Some(stop_send);
|
*stop_mut = Some(stop_send);
|
||||||
|
}
|
||||||
|
|
||||||
let mut conn = self.conn.borrow_mut();
|
let mut conn = self.conn.borrow_mut();
|
||||||
loop {
|
loop {
|
||||||
|
// main select loop, switches between listening, sending or stopping
|
||||||
select!(
|
select!(
|
||||||
r:conn => {
|
r:conn => {
|
||||||
|
// deser the header ot get the message type
|
||||||
let header = try_to_o!(ser::deserialize::<MsgHeader>(conn.deref_mut()));
|
let header = try_to_o!(ser::deserialize::<MsgHeader>(conn.deref_mut()));
|
||||||
if !header.acceptable() {
|
if !header.acceptable() {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
// 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"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
r:msg_recv => {
|
r:msg_recv => {
|
||||||
ser::serialize(conn.deref_mut(), msg_recv.recv().unwrap());
|
// 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));
|
||||||
},
|
},
|
||||||
r:stop_recv => {
|
r:stop_recv => {
|
||||||
|
// shuts the connection don and end the loop
|
||||||
stop_recv.recv();
|
stop_recv.recv();
|
||||||
conn.shutdown(Shutdown::Both);
|
conn.shutdown(Shutdown::Both);
|
||||||
return None;;
|
return None;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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) {
|
fn close(&self) {
|
||||||
let stop_send = self.stop_send.borrow();
|
let stop_send = self.stop_send.borrow();
|
||||||
stop_send.as_ref().unwrap().send(0);
|
stop_send.as_ref().unwrap().send(0);
|
||||||
|
@ -70,6 +119,11 @@ impl Protocol for ProtocolV1 {
|
||||||
|
|
||||||
impl ProtocolV1 {
|
impl ProtocolV1 {
|
||||||
pub fn new(conn: TcpStream) -> ProtocolV1 {
|
pub fn new(conn: TcpStream) -> ProtocolV1 {
|
||||||
ProtocolV1 { conn: RefCell::new(conn), /* msg_send: None, */ stop_send: RefCell::new(None) }
|
ProtocolV1 {
|
||||||
|
conn: RefCell::new(conn),
|
||||||
|
msg_send: RefCell::new(None),
|
||||||
|
stop_send: RefCell::new(None),
|
||||||
|
sent_bytes: Mutex::new(0),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ use std::str::FromStr;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use mioco;
|
use mioco;
|
||||||
|
use mioco::sync::mpsc::{sync_channel, SyncSender};
|
||||||
use mioco::tcp::{TcpListener, TcpStream};
|
use mioco::tcp::{TcpListener, TcpStream};
|
||||||
|
|
||||||
use core::ser::Error;
|
use core::ser::Error;
|
||||||
|
@ -37,57 +38,78 @@ fn listen_addr() -> SocketAddr {
|
||||||
FromStr::from_str(DEFAULT_LISTEN_ADDR).unwrap()
|
FromStr::from_str(DEFAULT_LISTEN_ADDR).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DummyAdapter {}
|
pub struct DummyAdapter {}
|
||||||
impl NetAdapter for DummyAdapter {}
|
impl NetAdapter for DummyAdapter {}
|
||||||
|
|
||||||
/// P2P server implementation, handling bootstrapping to find and connect to
|
/// P2P server implementation, handling bootstrapping to find and connect to
|
||||||
/// peers, receiving connections from other peers and keep track of all of them.
|
/// peers, receiving connections from other peers and keep track of all of them.
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
peers: RwLock<Vec<Arc<Peer>>>,
|
peers: RwLock<Vec<Arc<Peer>>>,
|
||||||
|
stop_send: RefCell<Option<SyncSender<u8>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for Server {}
|
||||||
|
unsafe impl Send for Server {}
|
||||||
|
|
||||||
// TODO TLS
|
// TODO TLS
|
||||||
impl Server {
|
impl Server {
|
||||||
|
/// Creates a new idle p2p server with no peers
|
||||||
pub fn new() -> Server {
|
pub fn new() -> Server {
|
||||||
Server{peers: RwLock::new(Vec::new())}
|
Server {
|
||||||
|
peers: RwLock::new(Vec::new()),
|
||||||
|
stop_send: RefCell::new(None),
|
||||||
}
|
}
|
||||||
/// Creates a new p2p server. Opens a TCP port to allow incoming
|
}
|
||||||
|
/// Starts the p2p server. Opens a TCP port to allow incoming
|
||||||
/// connections and starts the bootstrapping process to find peers.
|
/// connections and starts the bootstrapping process to find peers.
|
||||||
pub fn start(& self) -> Result<(), Error> {
|
pub fn start(&self) -> Result<(), Error> {
|
||||||
mioco::spawn(move || -> io::Result<()> {
|
|
||||||
let addr = DEFAULT_LISTEN_ADDR.parse().unwrap();
|
let addr = DEFAULT_LISTEN_ADDR.parse().unwrap();
|
||||||
let listener = try!(TcpListener::bind(&addr));
|
let listener = try!(TcpListener::bind(&addr).map_err(&Error::IOErr));
|
||||||
warn!("P2P server started on {}", addr);
|
warn!("P2P server started on {}", addr);
|
||||||
|
|
||||||
let hs = Arc::new(Handshake::new());
|
let hs = Arc::new(Handshake::new());
|
||||||
|
let (stop_send, stop_recv) = sync_channel(1);
|
||||||
|
{
|
||||||
|
let mut stop_mut = self.stop_send.borrow_mut();
|
||||||
|
*stop_mut = Some(stop_send);
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let conn = try!(listener.accept());
|
select!(
|
||||||
|
r:listener => {
|
||||||
|
let conn = try!(listener.accept().map_err(&Error::IOErr));
|
||||||
let hs = hs.clone();
|
let hs = hs.clone();
|
||||||
|
|
||||||
mioco::spawn(move || -> io::Result<()> {
|
let peer = try!(Peer::connect(conn, &hs));
|
||||||
let peer = try!(Peer::connect(conn, &hs).map_err(|_| io::Error::last_os_error()));
|
|
||||||
let wpeer = Arc::new(peer);
|
let wpeer = Arc::new(peer);
|
||||||
// {
|
{
|
||||||
// let mut peers = self.peers.write().unwrap();
|
let mut peers = self.peers.write().unwrap();
|
||||||
// peers.push(wpeer.clone());
|
peers.push(wpeer.clone());
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
mioco::spawn(move || -> io::Result<()> {
|
||||||
if let Some(err) = wpeer.run(&DummyAdapter{}) {
|
if let Some(err) = wpeer.run(&DummyAdapter{}) {
|
||||||
error!("{:?}", err);
|
error!("{:?}", err);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
r:stop_recv => {
|
||||||
|
stop_recv.recv();
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Stops the server. Disconnect from all peers at the same time.
|
||||||
pub fn stop(&self) {
|
pub fn stop(&self) {
|
||||||
let peers = self.peers.write().unwrap();
|
let peers = self.peers.write().unwrap();
|
||||||
for p in peers.deref() {
|
for p in peers.deref() {
|
||||||
p.stop();
|
p.stop();
|
||||||
}
|
}
|
||||||
|
let stop_send = self.stop_send.borrow();
|
||||||
|
stop_send.as_ref().unwrap().send(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Simulates an unrelated client connecting to our server. Mostly used for
|
/// Simulates an unrelated client connecting to our server. Mostly used for
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use core::ser::Error;
|
use core::ser::Error;
|
||||||
|
|
||||||
|
@ -36,12 +35,22 @@ pub struct PeerInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A given communication protocol agreed upon between 2 peers (usually
|
/// A given communication protocol agreed upon between 2 peers (usually
|
||||||
/// ourselves and a remove) after handshake.
|
/// ourselves and a remote) after handshake. This trait is necessary to allow
|
||||||
|
/// protocol negotiation as it gets upgraded to multiple versions.
|
||||||
pub trait Protocol {
|
pub trait Protocol {
|
||||||
/// Starts handling protocol communication, the peer(s) is expected to be
|
/// Starts handling protocol communication, the connection) is expected to
|
||||||
/// known already, usually passed during construction.
|
/// be known already, usually passed during construction. Will typically
|
||||||
|
/// block so needs to be called withing a coroutine. Should also be called
|
||||||
|
/// only once.
|
||||||
fn handle(&self, na: &NetAdapter) -> Option<Error>;
|
fn handle(&self, na: &NetAdapter) -> Option<Error>;
|
||||||
|
|
||||||
|
/// Sends a ping message to the remote peer.
|
||||||
|
fn send_ping(&self) -> Option<Error>;
|
||||||
|
|
||||||
|
/// How many bytes have been sent to the remote peer.
|
||||||
|
fn sent_bytes(&self) -> u64;
|
||||||
|
|
||||||
|
/// Close the connection to the remote peer.
|
||||||
fn close(&self);
|
fn close(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ extern crate mioco;
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::thread;
|
use std::sync::Arc;
|
||||||
use std::time;
|
use std::time;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -25,16 +25,30 @@ fn peer_handshake() {
|
||||||
env_logger::init().unwrap();
|
env_logger::init().unwrap();
|
||||||
|
|
||||||
mioco::start(|| -> io::Result<()> {
|
mioco::start(|| -> io::Result<()> {
|
||||||
let server = p2p::Server::new();
|
let server = Arc::new(p2p::Server::new());
|
||||||
server.start();
|
let in_server = server.clone();
|
||||||
|
mioco::spawn(move || -> io::Result<()> {
|
||||||
|
try!(in_server.start());
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
// given server a little time to start
|
// given server a little time to start
|
||||||
mioco::sleep(time::Duration::from_millis(200));
|
mioco::sleep(time::Duration::from_millis(200));
|
||||||
|
|
||||||
let addr = p2p::DEFAULT_LISTEN_ADDR.parse().unwrap();
|
let addr = p2p::DEFAULT_LISTEN_ADDR.parse().unwrap();
|
||||||
try!(p2p::Server::connect_as_client(addr).map_err(|_| io::Error::last_os_error()));
|
let peer = try!(p2p::Server::connect_as_client(addr).map_err(|_| io::Error::last_os_error()));
|
||||||
|
let peer = Arc::new(peer);
|
||||||
|
let in_peer = peer.clone();
|
||||||
|
mioco::spawn(move || -> io::Result<()> {
|
||||||
|
in_peer.run(&p2p::DummyAdapter{});
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
mioco::sleep(time::Duration::from_millis(100));
|
||||||
|
peer.send_ping();
|
||||||
|
mioco::sleep(time::Duration::from_millis(100));
|
||||||
|
assert!(peer.sent_bytes() > 0);
|
||||||
|
|
||||||
server.stop();
|
server.stop();
|
||||||
mioco::shutdown();
|
Ok(())
|
||||||
}).unwrap().unwrap();
|
}).unwrap().unwrap();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue