From 7d1a0238dea8788a80371cb8bc2300a8c23088e5 Mon Sep 17 00:00:00 2001 From: Toralf Wittner Date: Mon, 15 Oct 2018 10:42:11 +0200 Subject: [PATCH 01/19] Add shutdown functionality to `NodeStream`. (#560) Add shutdown functionality to `NodeStream`. Add `NodeStream::shutdown` to allow triggering the shutdown process, and `NodeStream::poll_shutdown` as the internal way to drive any potential shutdown to completion. --- core/src/muxing.rs | 1 + core/src/nodes/handled_node.rs | 116 +++++++++++----------- core/src/nodes/node.rs | 175 ++++++++++++++++++++++++--------- 3 files changed, 186 insertions(+), 106 deletions(-) diff --git a/core/src/muxing.rs b/core/src/muxing.rs index 46dc28b8418..f07088bc744 100644 --- a/core/src/muxing.rs +++ b/core/src/muxing.rs @@ -28,6 +28,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use tokio_io::{AsyncRead, AsyncWrite}; /// Ways to shutdown a substream or stream muxer. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Shutdown { /// Shutdown inbound direction. Inbound, diff --git a/core/src/nodes/handled_node.rs b/core/src/nodes/handled_node.rs index 65c5bac7bda..456d782718d 100644 --- a/core/src/nodes/handled_node.rs +++ b/core/src/nodes/handled_node.rs @@ -20,7 +20,7 @@ use muxing::StreamMuxer; use nodes::node::{NodeEvent, NodeStream, Substream}; -use futures::prelude::*; +use futures::{prelude::*, stream::Fuse}; use std::io::Error as IoError; use Multiaddr; @@ -124,10 +124,12 @@ where TMuxer: StreamMuxer, THandler: NodeHandler>, { - /// Node that handles the muxing. Can be `None` if the handled node is shutting down. - node: Option>, + /// Node that handles the muxing. + node: Fuse>, /// Handler that processes substreams. handler: THandler, + // True, if the node is shutting down. + is_shutting_down: bool } impl HandledNode @@ -140,8 +142,9 @@ where #[inline] pub fn new(muxer: TMuxer, multiaddr_future: TAddrFut, handler: THandler) -> Self { HandledNode { - node: Some(NodeStream::new(muxer, multiaddr_future)), + node: NodeStream::new(muxer, multiaddr_future).fuse(), handler, + is_shutting_down: false } } @@ -151,26 +154,26 @@ where self.handler.inject_event(event); } - /// Returns true if the inbound channel of the muxer is closed. + /// Returns true if the inbound channel of the muxer is open. /// - /// If `true` is returned, then no more inbound substream will be received. + /// If `true` is returned, more inbound substream will be received. #[inline] - pub fn is_inbound_closed(&self) -> bool { - self.node.as_ref().map(|n| n.is_inbound_closed()).unwrap_or(true) + pub fn is_inbound_open(&self) -> bool { + self.node.get_ref().is_inbound_open() } - /// Returns true if the outbound channel of the muxer is closed. + /// Returns true if the outbound channel of the muxer is open. /// - /// If `true` is returned, then no more outbound substream will be opened. + /// If `true` is returned, more outbound substream will be opened. #[inline] - pub fn is_outbound_closed(&self) -> bool { - self.node.as_ref().map(|n| n.is_outbound_closed()).unwrap_or(true) + pub fn is_outbound_open(&self) -> bool { + self.node.get_ref().is_outbound_open() } /// Returns true if the handled node is in the process of shutting down. #[inline] pub fn is_shutting_down(&self) -> bool { - self.node.is_none() + self.is_shutting_down } /// Indicates to the handled node that it should shut down. After calling this method, the @@ -178,13 +181,14 @@ where /// /// After this method returns, `is_shutting_down()` should return true. pub fn shutdown(&mut self) { - if let Some(node) = self.node.take() { - for user_data in node.close() { - self.handler.inject_outbound_closed(user_data); - } + self.node.get_mut().shutdown_all(); + self.is_shutting_down = true; + + for user_data in self.node.get_mut().cancel_outgoing() { + self.handler.inject_outbound_closed(user_data); } - self.handler.shutdown(); + self.handler.shutdown() } } @@ -201,60 +205,54 @@ where loop { let mut node_not_ready = false; - match self.node.as_mut().map(|n| n.poll()) { - Some(Ok(Async::NotReady)) | None => {}, - Some(Ok(Async::Ready(Some(NodeEvent::InboundSubstream { substream })))) => { - self.handler.inject_substream(substream, NodeHandlerEndpoint::Listener); - }, - Some(Ok(Async::Ready(Some(NodeEvent::OutboundSubstream { user_data, substream })))) => { + match self.node.poll()? { + Async::NotReady => (), + Async::Ready(Some(NodeEvent::InboundSubstream { substream })) => { + self.handler.inject_substream(substream, NodeHandlerEndpoint::Listener) + } + Async::Ready(Some(NodeEvent::OutboundSubstream { user_data, substream })) => { let endpoint = NodeHandlerEndpoint::Dialer(user_data); - self.handler.inject_substream(substream, endpoint); - }, - Some(Ok(Async::Ready(None))) => { + self.handler.inject_substream(substream, endpoint) + } + Async::Ready(None) => { node_not_ready = true; - self.node = None; - self.handler.shutdown(); - }, - Some(Ok(Async::Ready(Some(NodeEvent::Multiaddr(result))))) => { - self.handler.inject_multiaddr(result); - }, - Some(Ok(Async::Ready(Some(NodeEvent::OutboundClosed { user_data })))) => { - self.handler.inject_outbound_closed(user_data); - }, - Some(Ok(Async::Ready(Some(NodeEvent::InboundClosed)))) => { - self.handler.inject_inbound_closed(); - }, - Some(Err(err)) => { - self.node = None; - return Err(err); - }, + if !self.is_shutting_down { + self.handler.shutdown() + } + } + Async::Ready(Some(NodeEvent::Multiaddr(result))) => { + self.handler.inject_multiaddr(result) + } + Async::Ready(Some(NodeEvent::OutboundClosed { user_data })) => { + self.handler.inject_outbound_closed(user_data) + } + Async::Ready(Some(NodeEvent::InboundClosed)) => { + self.handler.inject_inbound_closed() + } } - match self.handler.poll() { - Ok(Async::NotReady) => { + match self.handler.poll()? { + Async::NotReady => { if node_not_ready { - break; + break } - }, - Ok(Async::Ready(Some(NodeHandlerEvent::OutboundSubstreamRequest(user_data)))) => { - if let Some(node) = self.node.as_mut() { - match node.open_substream(user_data) { + } + Async::Ready(Some(NodeHandlerEvent::OutboundSubstreamRequest(user_data))) => { + if self.node.get_ref().is_outbound_open() { + match self.node.get_mut().open_substream(user_data) { Ok(()) => (), Err(user_data) => self.handler.inject_outbound_closed(user_data), } } else { self.handler.inject_outbound_closed(user_data); } - }, - Ok(Async::Ready(Some(NodeHandlerEvent::Custom(event)))) => { + } + Async::Ready(Some(NodeHandlerEvent::Custom(event))) => { return Ok(Async::Ready(Some(event))); - }, - Ok(Async::Ready(None)) => { - return Ok(Async::Ready(None)); - }, - Err(err) => { - return Err(err); - }, + } + Async::Ready(None) => { + return Ok(Async::Ready(None)) + } } } diff --git a/core/src/nodes/node.rs b/core/src/nodes/node.rs index b22384ab573..10c2098b3d1 100644 --- a/core/src/nodes/node.rs +++ b/core/src/nodes/node.rs @@ -59,10 +59,10 @@ where { /// The muxer used to manage substreams. muxer: Arc, - /// If true, the inbound side of the muxer has closed earlier and should no longer be polled. - inbound_finished: bool, - /// If true, the outbound side of the muxer has closed earlier. - outbound_finished: bool, + /// Tracks the state of the muxers inbound direction. + inbound_state: StreamState, + /// Tracks the state of the muxers outbound direction. + outbound_state: StreamState, /// Address of the node ; can be empty if the address hasn't been resolved yet. address: Addr, /// List of substreams we are currently opening. @@ -83,6 +83,19 @@ enum Addr { /// A successfully opened substream. pub type Substream = muxing::SubstreamRef>; +// Track state of stream muxer per direction. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum StreamState { + // direction is open + Open, + // direction is shutting down + Shutdown, + // direction has shutdown and is flushing + Flush, + // direction is closed + Closed +} + /// Event that can happen on the `NodeStream`. #[derive(Debug)] pub enum NodeEvent @@ -134,8 +147,8 @@ where pub fn new(muxer: TMuxer, multiaddr_future: TAddrFut) -> Self { NodeStream { muxer: Arc::new(muxer), - inbound_finished: false, - outbound_finished: false, + inbound_state: StreamState::Open, + outbound_state: StreamState::Open, address: Addr::Future(multiaddr_future), outbound_substreams: SmallVec::new(), } @@ -161,7 +174,7 @@ where /// `OutboundSubstream` event or an `OutboundClosed` event containing the user data that has /// been passed to this method. pub fn open_substream(&mut self, user_data: TUserData) -> Result<(), TUserData> { - if self.outbound_finished { + if self.outbound_state != StreamState::Open { return Err(user_data); } @@ -171,25 +184,30 @@ where Ok(()) } - /// Returns true if the inbound channel of the muxer is closed. + /// Returns true if the inbound channel of the muxer is open. /// - /// If `true` is returned, then no more inbound substream will be produced. + /// If `true` is returned, more inbound substream will be produced. #[inline] - pub fn is_inbound_closed(&self) -> bool { - self.inbound_finished + pub fn is_inbound_open(&self) -> bool { + self.inbound_state == StreamState::Open } - /// Returns true if the outbound channel of the muxer is closed. + /// Returns true if the outbound channel of the muxer is open. /// - /// If `true` is returned, then no more outbound substream can be opened. Calling + /// If `true` is returned, more outbound substream can be opened. Otherwise, calling /// `open_substream` will return an `Err`. #[inline] - pub fn is_outbound_closed(&self) -> bool { - self.outbound_finished + pub fn is_outbound_open(&self) -> bool { + self.outbound_state == StreamState::Open } /// Destroys the node stream and returns all the pending outbound substreams. pub fn close(mut self) -> Vec { + self.cancel_outgoing() + } + + /// Destroys all outbound streams and returns the corresponding user data. + pub fn cancel_outgoing(&mut self) -> Vec { let mut out = Vec::with_capacity(self.outbound_substreams.len()); for (user_data, outbound) in self.outbound_substreams.drain() { out.push(user_data); @@ -197,6 +215,75 @@ where } out } + + /// Trigger node shutdown. + /// + /// After this, `NodeStream::poll` will eventually produce `None`, when both endpoints are + /// closed. + pub fn shutdown_all(&mut self) { + if self.inbound_state == StreamState::Open { + self.inbound_state = StreamState::Shutdown + } + if self.outbound_state == StreamState::Open { + self.outbound_state = StreamState::Shutdown + } + } + + // If in progress, drive this node's stream muxer shutdown to completion. + fn poll_shutdown(&mut self) -> Poll<(), IoError> { + use self::StreamState::*; + loop { + match (self.inbound_state, self.outbound_state) { + (Open, Open) | (Open, Closed) | (Closed, Open) | (Closed, Closed) => { + return Ok(Async::Ready(())) + } + (Shutdown, Shutdown) => { + if let Async::Ready(()) = self.muxer.shutdown(muxing::Shutdown::All)? { + self.inbound_state = StreamState::Flush; + self.outbound_state = StreamState::Flush; + continue + } + return Ok(Async::NotReady) + } + (Shutdown, _) => { + if let Async::Ready(()) = self.muxer.shutdown(muxing::Shutdown::Inbound)? { + self.inbound_state = StreamState::Flush; + continue + } + return Ok(Async::NotReady) + } + (_, Shutdown) => { + if let Async::Ready(()) = self.muxer.shutdown(muxing::Shutdown::Outbound)? { + self.outbound_state = StreamState::Flush; + continue + } + return Ok(Async::NotReady) + } + (Flush, Open) => { + if let Async::Ready(()) = self.muxer.flush_all()? { + self.inbound_state = StreamState::Closed; + continue + } + return Ok(Async::NotReady) + } + (Open, Flush) => { + if let Async::Ready(()) = self.muxer.flush_all()? { + self.outbound_state = StreamState::Closed; + continue + } + return Ok(Async::NotReady) + } + (Flush, Flush) | (Flush, Closed) | (Closed, Flush) => { + if let Async::Ready(()) = self.muxer.flush_all()? { + self.inbound_state = StreamState::Closed; + self.outbound_state = StreamState::Closed; + continue + } + return Ok(Async::NotReady) + } + } + } + } } impl Stream for NodeStream @@ -208,21 +295,25 @@ where type Error = IoError; fn poll(&mut self) -> Poll, Self::Error> { + // Drive the shutdown process, if any. + if self.poll_shutdown()?.is_not_ready() { + return Ok(Async::NotReady) + } + // Polling inbound substream. - if !self.inbound_finished { - match self.muxer.poll_inbound() { - Ok(Async::Ready(Some(substream))) => { + if self.inbound_state == StreamState::Open { + match self.muxer.poll_inbound()? { + Async::Ready(Some(substream)) => { let substream = muxing::substream_from_ref(self.muxer.clone(), substream); return Ok(Async::Ready(Some(NodeEvent::InboundSubstream { substream, }))); } - Ok(Async::Ready(None)) => { - self.inbound_finished = true; + Async::Ready(None) => { + self.inbound_state = StreamState::Closed; return Ok(Async::Ready(Some(NodeEvent::InboundClosed))); } - Ok(Async::NotReady) => {} - Err(err) => return Err(err), + Async::NotReady => {} } } @@ -240,7 +331,7 @@ where }))); } Ok(Async::Ready(None)) => { - self.outbound_finished = true; + self.outbound_state = StreamState::Closed; self.muxer.destroy_outbound(outbound); return Ok(Async::Ready(Some(NodeEvent::OutboundClosed { user_data }))); } @@ -275,8 +366,11 @@ where } // Closing the node if there's no way we can do anything more. - if self.inbound_finished && self.outbound_finished && self.outbound_substreams.is_empty() { - return Ok(Async::Ready(None)); + if self.inbound_state == StreamState::Closed + && self.outbound_state == StreamState::Closed + && self.outbound_substreams.is_empty() + { + return Ok(Async::Ready(None)) } // Nothing happened. Register our task to be notified and return. @@ -292,8 +386,8 @@ where fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.debug_struct("NodeStream") .field("address", &self.multiaddr()) - .field("inbound_finished", &self.inbound_finished) - .field("outbound_finished", &self.outbound_finished) + .field("inbound_state", &self.inbound_state) + .field("outbound_state", &self.outbound_state) .field("outbound_substreams", &self.outbound_substreams.len()) .finish() } @@ -310,19 +404,6 @@ where for (_, outbound) in self.outbound_substreams.drain() { self.muxer.destroy_outbound(outbound); } - // TODO: Maybe the shutdown logic should not be part of the destructor? - match (self.inbound_finished, self.outbound_finished) { - (true, true) => {} - (true, false) => { - let _ = self.muxer.shutdown(muxing::Shutdown::Outbound); - } - (false, true) => { - let _ = self.muxer.shutdown(muxing::Shutdown::Inbound); - } - (false, false) => { - let _ = self.muxer.shutdown(muxing::Shutdown::All); - } - } } } @@ -402,7 +483,7 @@ mod node_stream { }) }); - // Opening a second substream fails because `outbound_finished` is now true + // Opening a second substream fails because `outbound_state` is no longer open. assert_matches!(ns.open_substream(vec![22]), Err(user_data) => { assert_eq!(user_data, vec![22]); }); @@ -411,8 +492,8 @@ mod node_stream { #[test] fn query_inbound_outbound_state() { let ns = build_node_stream(); - assert_eq!(ns.is_inbound_closed(), false); - assert_eq!(ns.is_outbound_closed(), false); + assert!(ns.is_inbound_open()); + assert!(ns.is_outbound_open()); } #[test] @@ -426,7 +507,7 @@ mod node_stream { assert_matches!(node_event, NodeEvent::InboundClosed) }); - assert_eq!(ns.is_inbound_closed(), true); + assert!(!ns.is_inbound_open()); } #[test] @@ -436,7 +517,7 @@ mod node_stream { muxer.set_outbound_connection_state(DummyConnectionState::Closed); let mut ns = NodeStream::<_, _, Vec>::new(muxer, addr); - assert_eq!(ns.is_outbound_closed(), false); + assert!(ns.is_outbound_open()); ns.open_substream(vec![1]).unwrap(); let poll_result = ns.poll(); @@ -447,7 +528,7 @@ mod node_stream { }) }); - assert_eq!(ns.is_outbound_closed(), true, "outbound connection should be closed after polling"); + assert!(!ns.is_outbound_open(), "outbound connection should be closed after polling"); } #[test] @@ -552,7 +633,7 @@ mod node_stream { ns.open_substream(vec![1]).unwrap(); ns.poll().unwrap(); // poll past inbound ns.poll().unwrap(); // poll outbound - assert_eq!(ns.is_outbound_closed(), false); + assert!(ns.is_outbound_open()); assert!(format!("{:?}", ns).contains("outbound_substreams: 1")); } From e179951c74cb0c8916d27329f2dfd78917dddfb2 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Mon, 15 Oct 2018 10:12:40 +0100 Subject: [PATCH 02/19] Add some documentation to listeners stream (#547) * Add some documentation to listeners stream * Fix concern --- core/src/nodes/listeners.rs | 52 +++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/core/src/nodes/listeners.rs b/core/src/nodes/listeners.rs index 51aebd5e96b..80ded1f1d86 100644 --- a/core/src/nodes/listeners.rs +++ b/core/src/nodes/listeners.rs @@ -23,9 +23,57 @@ use std::fmt; use void::Void; use {Multiaddr, Transport}; -/// Implementation of `Stream` that handles listeners. +/// Implementation of `futures::Stream` that allows listening on multiaddresses. /// -/// The stream cannot produce errors. +/// To start using a `ListenersStream`, create one with `new` by passing an implementation of +/// `Transport`. This `Transport` will be used to start listening, therefore you want to pass +/// a `Transport` that supports the protocols you wish you listen on. +/// +/// Then, call `ListenerStream::listen_on` for all addresses you want to start listening on. +/// +/// The `ListenersStream` never ends and never produces errors. If a listener errors or closes, +/// an event is generated on the stream and the listener is then dropped, but the `ListenersStream` +/// itself continues. +/// +/// # Example +/// +/// ```no_run +/// # extern crate futures; +/// # extern crate libp2p_core; +/// # extern crate libp2p_tcp_transport; +/// # extern crate tokio; +/// # fn main() { +/// use futures::prelude::*; +/// use libp2p_core::nodes::listeners::{ListenersEvent, ListenersStream}; +/// +/// let mut listeners = ListenersStream::new(libp2p_tcp_transport::TcpConfig::new()); +/// +/// // Ask the `listeners` to start listening on the given multiaddress. +/// listeners.listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap()).unwrap(); +/// +/// // You can retreive the list of active listeners with `listeners()`. +/// println!("Listening on: {:?}", listeners.listeners().collect::>()); +/// +/// // The `listeners` will now generate events when polled. +/// let future = listeners.for_each(move |event| { +/// match event { +/// ListenersEvent::Closed { listen_addr, listener, result } => { +/// println!("Listener {} has been closed: {:?}", listen_addr, result); +/// }, +/// ListenersEvent::Incoming { upgrade, listen_addr } => { +/// println!("A connection has arrived on {}", listen_addr); +/// // We don't do anything with the newly-opened connection, but in a real-life +/// // program you probably want to use it! +/// drop(upgrade); +/// }, +/// }; +/// +/// Ok(()) +/// }); +/// +/// tokio::run(future.map_err(|_| ())); +/// # } +/// ``` pub struct ListenersStream where TTrans: Transport, From 2c98d0694235aba3ee89e8b43d639af2e6d1651d Mon Sep 17 00:00:00 2001 From: Toralf Wittner Date: Mon, 15 Oct 2018 16:29:32 +0200 Subject: [PATCH 03/19] Change some `nat_traversal`s to consider a prefix. (#550) Change some `nat_traversal`s to consider a prefix. Transports should consider only the relevant address prefix. --- core/src/transport/mod.rs | 8 +++- misc/multiaddr/src/lib.rs | 5 +++ transports/tcp/src/lib.rs | 40 +++++-------------- transports/websocket/src/browser.rs | 61 ++++++++++++----------------- transports/websocket/src/desktop.rs | 20 +--------- 5 files changed, 48 insertions(+), 86 deletions(-) diff --git a/core/src/transport/mod.rs b/core/src/transport/mod.rs index da50b339601..77354f20ecd 100644 --- a/core/src/transport/mod.rs +++ b/core/src/transport/mod.rs @@ -116,8 +116,12 @@ pub trait Transport { /// a remote node observes for one of our dialers. /// /// For example, if `server` is `/ip4/0.0.0.0/tcp/3000` and `observed` is - /// `/ip4/80.81.82.83/tcp/29601`, then we should return `/ip4/80.81.82.83/tcp/3000`. Each - /// implementation of `Transport` is only responsible for handling the protocols it supports. + /// `/ip4/80.81.82.83/tcp/29601`, then we should return `/ip4/80.81.82.83/tcp/3000`. + /// + /// Each implementation of `Transport` is only responsible for handling the protocols it + /// supports and should only consider the prefix of `observed` necessary to perform the + /// address translation (e.g. `/ip4/80.81.82.83`) but should otherwise preserve `server` + /// as is. /// /// Returns `None` if nothing can be determined. This happens if this trait implementation /// doesn't recognize the protocols, or if `server` and `observed` are related. diff --git a/misc/multiaddr/src/lib.rs b/misc/multiaddr/src/lib.rs index eb7051c42f3..04c4c5607a2 100644 --- a/misc/multiaddr/src/lib.rs +++ b/misc/multiaddr/src/lib.rs @@ -120,6 +120,11 @@ impl fmt::Display for Multiaddr { } impl Multiaddr { + /// Create a new, empty multiaddress. + pub fn empty() -> Multiaddr { + Multiaddr { bytes: Vec::new() } + } + /// Returns the raw bytes representation of the multiaddr. #[inline] pub fn into_bytes(self) -> Vec { diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index aa92aa2ea1b..01f8498fa35 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -54,7 +54,6 @@ use futures::{future, future::FutureResult, prelude::*, Async, Poll}; use multiaddr::{Protocol, Multiaddr, ToMultiaddr}; use std::fmt; use std::io::{Error as IoError, Read, Write}; -use std::iter; use std::net::SocketAddr; use std::time::Duration; use swarm::Transport; @@ -194,40 +193,21 @@ impl Transport for TcpConfig { } fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { - // Check that `server` only has two components and retreive them. - let mut server_protocols_iter = server.iter(); - let server_proto1 = server_protocols_iter.next()?; - let server_proto2 = server_protocols_iter.next()?; - if server_protocols_iter.next().is_some() { - return None; - } - - // Check that `observed` only has two components and retreive them. - let mut observed_protocols_iter = observed.iter(); - let observed_proto1 = observed_protocols_iter.next()?; - let observed_proto2 = observed_protocols_iter.next()?; - if observed_protocols_iter.next().is_some() { - return None; - } + let mut address = Multiaddr::empty(); - // Check that `server` is a valid TCP/IP address. - match (&server_proto1, &server_proto2) { - (&Protocol::Ip4(_), &Protocol::Tcp(_)) - | (&Protocol::Ip6(_), &Protocol::Tcp(_)) => {} - _ => return None, + // Use the observed IP address. + match server.iter().zip(observed.iter()).next() { + Some((Protocol::Ip4(_), x@Protocol::Ip4(_))) => address.append(x), + Some((Protocol::Ip6(_), x@Protocol::Ip6(_))) => address.append(x), + _ => return None } - // Check that `observed` is a valid TCP/IP address. - match (&observed_proto1, &observed_proto2) { - (&Protocol::Ip4(_), &Protocol::Tcp(_)) - | (&Protocol::Ip6(_), &Protocol::Tcp(_)) => {} - _ => return None, + // Carry over everything else from the server address. + for proto in server.iter().skip(1) { + address.append(proto) } - let result = iter::once(observed_proto1.clone()) - .chain(iter::once(server_proto2.clone())) - .collect(); - Some(result) + Some(address) } } diff --git a/transports/websocket/src/browser.rs b/transports/websocket/src/browser.rs index d8a0bb5f54c..e62a69c18f6 100644 --- a/transports/websocket/src/browser.rs +++ b/transports/websocket/src/browser.rs @@ -209,49 +209,40 @@ impl Transport for BrowserWsConfig { } fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { - let mut server_protocols = server.iter(); - let server_proto0 = server_protocols.next()?; - let server_proto1 = server_protocols.next()?; - let server_proto2 = server_protocols.next()?; - if server_protocols.next().is_some() { - return None; - } + let mut address = Multiaddr::empty(); - let mut observed_protocols = observed.iter(); - let obs_proto0 = observed_protocols.next()?; - let obs_proto1 = observed_protocols.next()?; - let obs_proto2 = observed_protocols.next()?; - if observed_protocols.next().is_some() { - return None; - } + let mut iter = server.iter().zip(observed.iter()); - // Check that `server` is a valid TCP/IP address. - match (&server_proto0, &server_proto1, &server_proto2) { - (&Protocol::Ip4(_), &Protocol::Tcp(_), &Protocol::Ws) - | (&Protocol::Ip6(_), &Protocol::Tcp(_), &Protocol::Ws) - | (&Protocol::Ip4(_), &Protocol::Tcp(_), &Protocol::Wss) - | (&Protocol::Ip6(_), &Protocol::Tcp(_), &Protocol::Wss) => {} - _ => return None, + // Use the observed IP address. + match iter.next() { + Some((Protocol::Ip4(_), x@Protocol::Ip4(_))) => address.append(x), + Some((Protocol::Ip6(_), x@Protocol::Ip6(_))) => address.append(x), + _ => return None } - // Check that `observed` is a valid TCP/IP address. - match (&obs_proto0, &obs_proto1, &obs_proto2) { - (&Protocol::Ip4(_), &Protocol::Tcp(_), &Protocol::Ws) - | (&Protocol::Ip6(_), &Protocol::Tcp(_), &Protocol::Ws) - | (&Protocol::Ip4(_), &Protocol::Tcp(_), &Protocol::Wss) - | (&Protocol::Ip6(_), &Protocol::Tcp(_), &Protocol::Wss) => {} - _ => return None, + // Skip over next protocol (assumed to contain port information). + if iter.next().is_none() { + return None } - // Note that it will still work if the server uses WSS while the client uses WS, - // or vice-versa. + // Check for WS/WSS. + // + // Note that it will still work if the server uses WSS while the client uses + // WS, or vice-versa. + match iter.next() { + Some((x@Protocol::Ws, Protocol::Ws)) => address.append(x), + Some((x@Protocol::Ws, Protocol::Wss)) => address.append(x), + Some((x@Protocol::Wss, Protocol::Ws)) => address.append(x), + Some((x@Protocol::Wss, Protocol::Wss)) => address.append(x), + _ => return None + } - let result = iter::once(obs_proto0) - .chain(iter::once(server_proto1)) - .chain(iter::once(server_proto2)) - .collect(); + // Carry over everything else from the server address. + for proto in server.iter().skip(3) { + address.append(proto) + } - Some(result) + Some(address) } } diff --git a/transports/websocket/src/desktop.rs b/transports/websocket/src/desktop.rs index 4e6321f3e10..a86d46361ba 100644 --- a/transports/websocket/src/desktop.rs +++ b/transports/websocket/src/desktop.rs @@ -236,25 +236,7 @@ where } fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { - let mut server = server.clone(); - let last_proto = match server.pop() { - Some(v @ Protocol::Ws) | Some(v @ Protocol::Wss) => v, - _ => return None, - }; - - let mut observed = observed.clone(); - match observed.pop() { - Some(Protocol::Ws) => false, - Some(Protocol::Wss) => true, - _ => return None, - }; - - self.transport - .nat_traversal(&server, &observed) - .map(move |mut result| { - result.append(last_proto); - result - }) + self.transport.nat_traversal(server, observed) } } From 724d0f5d82bd79a3299c0ee4105ea86f2675b27c Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Mon, 15 Oct 2018 16:17:55 +0100 Subject: [PATCH 04/19] Remove the old API (#565) * Remove the old API * Fix integration test --- .circleci/config.yml | 4 - Cargo.toml | 22 - core/src/connection_reuse.rs | 816 ------------------------------ core/src/lib.rs | 47 -- core/src/transport/memory.rs | 88 ---- core/src/transport/mod.rs | 13 - core/tests/lots_of_connec.rs | 77 --- core/tests/multiplex.rs | 261 ---------- examples/echo-dialer.rs | 141 ------ examples/echo-server.rs | 144 ------ examples/floodsub.rs | 160 ------ examples/kademlia.rs | 292 ----------- examples/ping-client.rs | 123 ----- examples/random_peerid.rs | 32 -- examples/relay.rs | 224 -------- examples/test-rsa-private-key.pk8 | Bin 1219 -> 0 bytes examples/test-rsa-public-key.der | Bin 294 -> 0 bytes src/lib.rs | 2 +- 18 files changed, 1 insertion(+), 2445 deletions(-) delete mode 100644 core/src/connection_reuse.rs delete mode 100644 core/tests/lots_of_connec.rs delete mode 100644 core/tests/multiplex.rs delete mode 100644 examples/echo-dialer.rs delete mode 100644 examples/echo-server.rs delete mode 100644 examples/floodsub.rs delete mode 100644 examples/kademlia.rs delete mode 100644 examples/ping-client.rs delete mode 100644 examples/random_peerid.rs delete mode 100644 examples/relay.rs delete mode 100644 examples/test-rsa-private-key.pk8 delete mode 100644 examples/test-rsa-public-key.der diff --git a/.circleci/config.yml b/.circleci/config.yml index 9e15501c66b..3eaea96b0a0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -105,10 +105,6 @@ jobs: - checkout - restore_cache: key: integration-test-cache - - run: - command: cargo run --example ping-client -- /ip4/127.0.0.1/tcp/4001 - - run: - command: cargo run --example echo-dialer -- /ip4/127.0.0.1/tcp/10333 - save_cache: key: integration-test-cache paths: diff --git a/Cargo.toml b/Cargo.toml index 14bd9423237..0d95e2314ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,28 +47,6 @@ tokio-current-thread = "0.1" tokio-io = "0.1" tokio-stdin = "0.1" -[[example]] -name = "echo-dialer" - -[[example]] -name = "echo-server" - -[[example]] -name = "floodsub" - -[[example]] -name = "kademlia" - -[[example]] -name = "ping-client" - -[[example]] -name = "random_peerid" - -[[example]] -name = "relay" - - [workspace] members = [ "core", diff --git a/core/src/connection_reuse.rs b/core/src/connection_reuse.rs deleted file mode 100644 index 68287dc03d5..00000000000 --- a/core/src/connection_reuse.rs +++ /dev/null @@ -1,816 +0,0 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -//! Contains the `ConnectionReuse` struct. Stores open muxed connections to nodes so that dialing -//! a node reuses the same connection instead of opening a new one. -//! -//! A `ConnectionReuse` can only be created from an `UpgradedNode` whose `ConnectionUpgrade` -//! yields as `StreamMuxer`. -//! -//! # Behaviour -//! -//! The API exposed by the `ConnectionReuse` struct consists in the `Transport` trait -//! implementation, with the `dial` and `listen_on` methods. -//! -//! When called on a `ConnectionReuse`, the `listen_on` method will listen on the given -//! multiaddress (by using the underlying `Transport`), then will apply a `flat_map` on the -//! incoming connections so that we actually listen to the incoming substreams of each connection. -//! -//! When called on a `ConnectionReuse`, the `dial` method will try to use a connection that has -//! already been opened earlier, and open an outgoing substream on it. If none is available, it -//! will dial the given multiaddress. Dialed node can also spontaneously open new substreams with -//! us. In order to handle these new substreams you should use the `next_incoming` method of the -//! `MuxedTransport` trait. - -use fnv::FnvHashMap; -use futures::future::{self, FutureResult}; -use futures::{Async, Future, Poll, Stream, stream, task}; -use futures::stream::FuturesUnordered; -use multiaddr::Multiaddr; -use muxing::{self, StreamMuxer}; -use parking_lot::Mutex; -use std::collections::hash_map::Entry; -use std::io::{Error as IoError, ErrorKind as IoErrorKind, Read, Write}; -use std::mem; -use std::ops::{Deref, DerefMut}; -use std::sync::{Arc, atomic::AtomicUsize, atomic::Ordering}; -use tokio_io::{AsyncRead, AsyncWrite}; -use transport::{MuxedTransport, Transport}; - -/// Allows reusing the same muxed connection multiple times. -/// -/// Can be created from an `UpgradedNode` through the `From` trait. -/// -/// Implements the `Transport` trait. -pub struct ConnectionReuse -where - T: Transport, - T: Transport, - M: StreamMuxer, -{ - /// Struct shared between most of the `ConnectionReuse` infrastructure. - shared: Arc>>, -} - -impl Clone for ConnectionReuse -where - T: Transport, - T: Transport, - M: StreamMuxer, -{ - #[inline] - fn clone(&self) -> Self { - ConnectionReuse { - shared: self.shared.clone(), - } - } -} - -/// Struct shared between most of the `ConnectionReuse` infrastructure. -struct Shared -where - T: Transport, - T: Transport, - M: StreamMuxer, -{ - /// Underlying transport and connection upgrade, used when we need to dial or listen. - transport: T, - - /// All the connections that were opened, whether successful and/or active or not. - // TODO: this will grow forever - connections: FnvHashMap>, - - /// Tasks to notify when one or more new elements were added to `connections`. - notify_on_new_connec: FnvHashMap, - - /// Next `connection_id` to use when opening a connection. - next_connection_id: u64, - - /// Next `listener_id` for the next listener we create. - next_listener_id: u64, -} - -enum PeerState where M: StreamMuxer { - /// Connection is active and can be used to open substreams. - Active { - /// The muxer to open new substreams. - muxer: Arc, - /// Custom data passed to the output. - custom_data: D, - /// Future of the address of the client. - client_addr: Multiaddr, - /// Unique identifier for this connection in the `ConnectionReuse`. - connection_id: u64, - /// Number of open substreams. - num_substreams: u64, - /// Id of the listener that created this connection, or `None` if it was opened by a - /// dialer. - listener_id: Option, - }, - - /// Connection is pending. - // TODO: stronger Future type - Pending { - /// Future that produces the muxer. - future: Box + Send>, - /// All the tasks to notify when `future` resolves. - notify: FnvHashMap, - }, - - /// An earlier connection attempt errored. - Errored(IoError), - - /// The `PeerState` is poisonned. Happens if a panic happened while executing some of the - /// functions. - Poisonned, -} - -impl ConnectionReuse -where - T: Transport, - T: Transport, - M: StreamMuxer, -{ - #[inline] - pub(crate) fn new(node: T) -> ConnectionReuse { - ConnectionReuse { - shared: Arc::new(Mutex::new(Shared { - transport: node, - connections: Default::default(), - notify_on_new_connec: Default::default(), - next_connection_id: 0, - next_listener_id: 0, - })), - } - } -} - -impl Transport for ConnectionReuse -where - T: Transport + Send + 'static, // TODO: 'static :( - T::Dial: Send, - T::MultiaddrFuture: Send, - T::Listener: Send, - T::ListenerUpgrade: Send, - T: Transport + Clone + 'static, // TODO: 'static :( - M: Send + Sync + StreamMuxer + 'static, - D: Send + Clone + 'static, - T: Clone, -{ - type Output = (D, ConnectionReuseSubstream); - type MultiaddrFuture = future::FutureResult; - type Listener = Box + Send>; - type ListenerUpgrade = FutureResult<(Self::Output, Self::MultiaddrFuture), IoError>; - type Dial = ConnectionReuseDial; - - fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { - let mut shared = self.shared.lock(); - - let (listener, new_addr) = match shared.transport.clone().listen_on(addr.clone()) { - Ok((l, a)) => (l, a), - Err((_, addr)) => { - return Err(( - ConnectionReuse { - shared: self.shared.clone(), - }, - addr, - )); - } - }; - - let listener = listener - .map(|upgr| { - upgr.and_then(|(out, addr)| { - trace!("Waiting for remote's address as listener"); - addr.map(move |addr| (out, addr)) - }) - }) - .fuse(); - - let listener_id = shared.next_listener_id; - shared.next_listener_id += 1; - - let listener = ConnectionReuseListener { - shared: self.shared.clone(), - listener, - listener_id, - current_upgrades: FuturesUnordered::new(), - }; - - Ok((Box::new(listener) as Box<_>, new_addr)) - } - - #[inline] - fn dial(self, addr: Multiaddr) -> Result { - let mut shared = self.shared.lock(); - - // If an earlier attempt to dial this multiaddress failed, we clear the error. Otherwise - // the returned `Future` will immediately produce the error. - let must_clear = match shared.connections.get(&addr) { - Some(&PeerState::Errored(ref err)) => { - trace!("Clearing existing connection to {} which errored earlier: {:?}", addr, err); - true - }, - _ => false, - }; - if must_clear { - shared.connections.remove(&addr); - } - - Ok(ConnectionReuseDial { - outbound: None, - shared: self.shared.clone(), - addr, - }) - } - - #[inline] - fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { - self.shared.lock().transport.nat_traversal(server, observed) - } -} - -impl MuxedTransport for ConnectionReuse -where - T: Transport + Send + 'static, // TODO: 'static :( - T::Dial: Send, - T::MultiaddrFuture: Send, - T::Listener: Send, - T::ListenerUpgrade: Send, - T: Transport + Clone + 'static, // TODO: 'static :( - M: Send + Sync + StreamMuxer + 'static, - D: Send + Clone + 'static, - T: Clone, -{ - type Incoming = ConnectionReuseIncoming; - type IncomingUpgrade = - future::FutureResult<((D, ConnectionReuseSubstream), Self::MultiaddrFuture), IoError>; - - #[inline] - fn next_incoming(self) -> Self::Incoming { - ConnectionReuseIncoming { - shared: self.shared.clone(), - } - } -} - -static NEXT_TASK_ID: AtomicUsize = AtomicUsize::new(0); -// `TASK_ID` is used internally to uniquely identify each task. -task_local!{ - static TASK_ID: usize = NEXT_TASK_ID.fetch_add(1, Ordering::Relaxed) -} - -/// Implementation of `Future` for dialing a node. -pub struct ConnectionReuseDial -where - T: Transport, - T: Transport, - M: StreamMuxer, -{ - /// The future that will construct the substream, the connection id the muxer comes from, and - /// the `Future` of the client's multiaddr. - /// If `None`, we need to grab a new outbound substream from the muxer. - outbound: Option>, - - // Shared between the whole connection reuse mechanism. - shared: Arc>>, - - // The address we're trying to dial. - addr: Multiaddr, -} - -struct ConnectionReuseDialOut -where - M: StreamMuxer, -{ - /// Custom data for the connection. - custom_data: D, - /// The pending outbound substream. - stream: muxing::OutboundSubstreamRefWrapFuture>, - /// Id of the connection that was used to create the substream. - connection_id: u64, - /// Address of the remote. - client_addr: Multiaddr, -} - -impl Future for ConnectionReuseDial -where - T: Transport + Clone, - M: Send + StreamMuxer + 'static, - D: Send + Clone + 'static, - ::Dial: Send + 'static, - ::MultiaddrFuture: Send + 'static, -{ - type Item = ((D, ConnectionReuseSubstream), FutureResult); - type Error = IoError; - - fn poll(&mut self) -> Poll { - loop { - let should_kill_existing_muxer; - if let Some(mut outbound) = self.outbound.take() { - match outbound.stream.poll() { - Ok(Async::Ready(Some(inner))) => { - trace!("Opened new outgoing substream to {}", self.addr); - let substream = ConnectionReuseSubstream { - connection_id: outbound.connection_id, - shared: self.shared.clone(), - inner, - addr: outbound.client_addr.clone(), - }; - return Ok(Async::Ready(((outbound.custom_data, substream), future::ok(outbound.client_addr)))); - }, - Ok(Async::NotReady) => { - self.outbound = Some(outbound); - return Ok(Async::NotReady); - }, - Ok(Async::Ready(None)) => { - // The muxer can no longer produce outgoing substreams. - // Let's reopen a connection. - trace!("Closing existing connection to {} ; can't produce outgoing substreams", self.addr); - should_kill_existing_muxer = true; - }, - Err(err) => { - // If we get an error while opening a substream, we decide to ignore it - // and open a new muxer. - // If opening the muxer produces an error, *then* we will return it. - debug!("Error while opening outgoing substream to {}: {:?}", self.addr, err); - should_kill_existing_muxer = true; - }, - } - } else { - should_kill_existing_muxer = false; - } - - // If we reach this point, that means we have to fill `self.outbound`. - // If `should_kill_existing_muxer`, do not use any existing connection but create a - // new one instead. - let mut shared = self.shared.lock(); - let shared = &mut *shared; // Avoids borrow errors - - // TODO: could be optimized - if should_kill_existing_muxer { - shared.connections.remove(&self.addr); - } - let connec = match shared.connections.entry(self.addr.clone()) { - Entry::Occupied(e) => e.into_mut(), - Entry::Vacant(e) => { - // Build the connection. - let state = match shared.transport.clone().dial(self.addr.clone()) { - Ok(future) => { - trace!("Opened new connection to {:?}", self.addr); - let future = future.and_then(|(out, addr)| addr.map(move |a| (out, a))); - let future = Box::new(future); - PeerState::Pending { future, notify: Default::default() } - }, - Err(_) => { - trace!("Failed to open connection to {:?}, multiaddr not supported", self.addr); - let err = IoError::new(IoErrorKind::ConnectionRefused, "multiaddr not supported"); - PeerState::Errored(err) - }, - }; - - for task in shared.notify_on_new_connec.drain() { - task.1.notify(); - } - - e.insert(state) - }, - }; - - match mem::replace(&mut *connec, PeerState::Poisonned) { - PeerState::Active { muxer, custom_data, connection_id, listener_id, mut num_substreams, client_addr } => { - let outbound = muxing::outbound_from_ref_and_wrap(muxer.clone()); - num_substreams += 1; - *connec = PeerState::Active { muxer, custom_data: custom_data.clone(), connection_id, listener_id, num_substreams, client_addr: client_addr.clone() }; - trace!("Using existing connection to {} to open outbound substream", self.addr); - self.outbound = Some(ConnectionReuseDialOut { - custom_data, - stream: outbound, - connection_id, - client_addr, - }); - }, - PeerState::Pending { mut future, mut notify } => { - match future.poll() { - Ok(Async::Ready(((custom_data, muxer), client_addr))) => { - trace!("Successful new connection to {} ({})", self.addr, client_addr); - for task in notify { - task.1.notify(); - } - let muxer = Arc::new(muxer); - let first_outbound = muxing::outbound_from_ref_and_wrap(muxer.clone()); - let connection_id = shared.next_connection_id; - shared.next_connection_id += 1; - *connec = PeerState::Active { muxer, custom_data: custom_data.clone(), connection_id, num_substreams: 1, listener_id: None, client_addr: client_addr.clone() }; - self.outbound = Some(ConnectionReuseDialOut { - custom_data, - stream: first_outbound, - connection_id, - client_addr, - }); - }, - Ok(Async::NotReady) => { - notify.insert(TASK_ID.with(|&t| t), task::current()); - *connec = PeerState::Pending { future, notify }; - return Ok(Async::NotReady); - }, - Err(err) => { - trace!("Failed new connection to {}: {:?}", self.addr, err); - let io_err = IoError::new(err.kind(), err.to_string()); - *connec = PeerState::Errored(err); - return Err(io_err); - }, - } - }, - PeerState::Errored(err) => { - trace!("Existing new connection to {} errored earlier: {:?}", self.addr, err); - let io_err = IoError::new(err.kind(), err.to_string()); - *connec = PeerState::Errored(err); - return Err(io_err); - }, - PeerState::Poisonned => { - panic!("Poisonned peer state"); - }, - } - } - } -} - -impl Drop for ConnectionReuseDial -where - T: Transport, - T: Transport, - M: StreamMuxer, -{ - fn drop(&mut self) { - if let Some(outbound) = self.outbound.take() { - let mut shared = self.shared.lock(); - remove_one_substream(&mut *shared, outbound.connection_id, &outbound.client_addr); - } - } -} - -/// Implementation of `Stream` for the connections incoming from listening on a specific address. -pub struct ConnectionReuseListener -where - T: Transport, - T: Transport, - M: StreamMuxer, -{ - /// The main listener. - listener: stream::Fuse, - /// Identifier for this listener. Used to determine which connections were opened by it. - listener_id: u64, - /// Opened connections that need to be upgraded. - current_upgrades: FuturesUnordered + Send>>, - - /// Shared between the whole connection reuse mechanism. - shared: Arc>>, -} - -impl Stream for ConnectionReuseListener -where - T: Transport, - T: Transport, - M: StreamMuxer, - D: Clone, - L: Stream, - Lu: Future + Send + 'static, -{ - type Item = FutureResult<((D, ConnectionReuseSubstream), FutureResult), IoError>; - type Error = IoError; - - fn poll(&mut self) -> Poll, Self::Error> { - // Check for any incoming connection on the listening socket. - // Note that since `self.listener` is a `Fuse`, it's not a problem to continue polling even - // after it is finished or after it error'ed. - loop { - match self.listener.poll() { - Ok(Async::Ready(Some(upgrade))) => { - trace!("New incoming connection"); - self.current_upgrades.push(Box::new(upgrade)); - } - Ok(Async::NotReady) => break, - Ok(Async::Ready(None)) => { - debug!("Listener has been closed"); - break; - } - Err(err) => { - debug!("Error while polling listener: {:?}", err); - return Err(err); - } - }; - } - - // Process the connections being upgraded. - loop { - match self.current_upgrades.poll() { - Ok(Async::Ready(Some(((custom_data, muxer), client_addr)))) => { - // Successfully upgraded a new incoming connection. - trace!("New multiplexed connection from {}", client_addr); - let mut shared = self.shared.lock(); - let muxer = Arc::new(muxer); - let connection_id = shared.next_connection_id; - shared.next_connection_id += 1; - let state = PeerState::Active { muxer, custom_data, connection_id, listener_id: Some(self.listener_id), num_substreams: 1, client_addr: client_addr.clone() }; - shared.connections.insert(client_addr, state); - for to_notify in shared.notify_on_new_connec.drain() { - to_notify.1.notify(); - } - } - Ok(Async::Ready(None)) | Ok(Async::NotReady) => { - break; - }, - Err(err) => { - // Insert the rest of the pending upgrades, but not the current one. - debug!("Error while upgrading listener connection: {:?}", err); - return Ok(Async::Ready(Some(future::err(err)))); - } - } - } - - // Poll all the incoming connections on all the connections we opened. - let mut shared = self.shared.lock(); - match poll_incoming(&self.shared, &mut shared, Some(self.listener_id)) { - Ok(Async::Ready(None)) => { - if self.listener.is_done() && self.current_upgrades.is_empty() { - Ok(Async::Ready(None)) - } else { - Ok(Async::NotReady) - } - }, - Ok(Async::Ready(Some(substream))) => { - Ok(Async::Ready(Some(substream))) - }, - Ok(Async::NotReady) => { - Ok(Async::NotReady) - } - Err(err) => { - Ok(Async::Ready(Some(future::err(err)))) - } - } - } -} - -/// Implementation of `Future` that yields the next incoming substream from a dialed connection. -#[must_use = "futures do nothing unless polled"] -pub struct ConnectionReuseIncoming -where - T: Transport, - T: Transport, - M: StreamMuxer, -{ - // Shared between the whole connection reuse system. - shared: Arc>>, -} - -impl Future for ConnectionReuseIncoming -where - T: Transport, - T: Transport, - M: StreamMuxer, - D: Clone, -{ - type Item = future::FutureResult<((D, ConnectionReuseSubstream), future::FutureResult), IoError>; - type Error = IoError; - - #[inline] - fn poll(&mut self) -> Poll { - let mut shared = self.shared.lock(); - match poll_incoming(&self.shared, &mut shared, None) { - Ok(Async::Ready(Some(substream))) => { - Ok(Async::Ready(substream)) - }, - Ok(Async::Ready(None)) | Ok(Async::NotReady) => { - // TODO: will add an element to the list every time - shared.notify_on_new_connec.insert(TASK_ID.with(|&v| v), task::current()); - Ok(Async::NotReady) - }, - Err(err) => Err(err) - } - } -} - -/// Polls the incoming substreams on all the incoming connections that match the `listener`. -/// -/// Returns `Ready(None)` if no connection is matching the `listener`. Returns `NotReady` if -/// one or more connections are matching the `listener` but they are not ready. -fn poll_incoming(shared_arc: &Arc>>, shared: &mut Shared, listener: Option) - -> Poll), FutureResult), IoError>>, IoError> -where - T: Transport, - T: Transport, - M: StreamMuxer, - D: Clone, -{ - // Keys of the elements in `shared.connections` to remove afterwards. - let mut to_remove = Vec::new(); - // Substream to return, if any found. - let mut ret_value = None; - let mut found_one = false; - - for (addr, state) in shared.connections.iter_mut() { - match *state { - PeerState::Active { ref custom_data, ref muxer, ref mut num_substreams, connection_id, ref client_addr, listener_id } => { - if listener_id != listener { - continue; - } - found_one = true; - - match muxer.poll_inbound() { - Ok(Async::Ready(Some(inner))) => { - trace!("New incoming substream from {}", client_addr); - *num_substreams += 1; - let substream = ConnectionReuseSubstream { - inner: muxing::substream_from_ref(muxer.clone(), inner), - shared: shared_arc.clone(), - connection_id, - addr: client_addr.clone(), - }; - ret_value = Some(Ok(((custom_data.clone(), substream), future::ok(client_addr.clone())))); - break; - }, - Ok(Async::Ready(None)) => { - // The muxer isn't capable of opening any inbound stream anymore, so - // we close the connection entirely. - trace!("Removing existing connection to {} as it cannot open inbound anymore", addr); - to_remove.push(addr.clone()); - }, - Ok(Async::NotReady) => (), - Err(err) => { - // If an error happens while opening an inbound stream, we close the - // connection entirely. - trace!("Error while opening inbound substream to {}: {:?}", addr, err); - to_remove.push(addr.clone()); - ret_value = Some(Err(err)); - break; - }, - } - }, - PeerState::Pending { ref mut notify, .. } => { - notify.insert(TASK_ID.with(|&t| t), task::current()); - }, - PeerState::Errored(_) => {}, - PeerState::Poisonned => { - panic!("Poisonned peer state"); - }, - } - } - - for to_remove in to_remove { - shared.connections.remove(&to_remove); - } - - match ret_value { - Some(Ok(val)) => Ok(Async::Ready(Some(future::ok(val)))), - Some(Err(err)) => Err(err), - None => { - if found_one { - Ok(Async::NotReady) - } else { - Ok(Async::Ready(None)) - } - }, - } -} - -/// Removes one substream from an active connection. Closes the connection if necessary. -fn remove_one_substream(shared: &mut Shared, connec_id: u64, addr: &Multiaddr) -where - T: Transport, - T: Transport, - M: StreamMuxer, -{ - shared.connections.retain(|_, connec| { - if let PeerState::Active { connection_id, ref mut num_substreams, .. } = connec { - if *connection_id == connec_id { - *num_substreams -= 1; - if *num_substreams == 0 { - trace!("All substreams to {} closed ; closing main connection", addr); - return false; - } - } - } - - true - }); -} - -/// Wraps around the `Substream`. -pub struct ConnectionReuseSubstream -where - T: Transport, - T: Transport, - M: StreamMuxer, -{ - inner: muxing::SubstreamRef>, - shared: Arc>>, - /// Id this connection was created from. - connection_id: u64, - /// Address of the remote. - addr: Multiaddr, -} - -impl Deref for ConnectionReuseSubstream -where - T: Transport, - T: Transport, - M: StreamMuxer, -{ - type Target = muxing::SubstreamRef>; - - #[inline] - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl DerefMut for ConnectionReuseSubstream -where - T: Transport, - T: Transport, - M: StreamMuxer, -{ - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} - -impl Read for ConnectionReuseSubstream -where - T: Transport, - T: Transport, - M: StreamMuxer, -{ - #[inline] - fn read(&mut self, buf: &mut [u8]) -> Result { - self.inner.read(buf) - } -} - -impl AsyncRead for ConnectionReuseSubstream -where - T: Transport, - T: Transport, - M: StreamMuxer, -{ -} - -impl Write for ConnectionReuseSubstream -where - T: Transport, - T: Transport, - M: StreamMuxer, -{ - #[inline] - fn write(&mut self, buf: &[u8]) -> Result { - self.inner.write(buf) - } - - #[inline] - fn flush(&mut self) -> Result<(), IoError> { - self.inner.flush() - } -} - -impl AsyncWrite for ConnectionReuseSubstream -where - T: Transport, - T: Transport, - M: StreamMuxer, -{ - #[inline] - fn shutdown(&mut self) -> Poll<(), IoError> { - self.inner.shutdown() - } -} - -impl Drop for ConnectionReuseSubstream -where - T: Transport, - T: Transport, - M: StreamMuxer, -{ - fn drop(&mut self) { - let mut shared = self.shared.lock(); - remove_one_substream(&mut *shared, self.connection_id, &self.addr); - } -} diff --git a/core/src/lib.rs b/core/src/lib.rs index 469b09b4021..00292c3ab4a 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -164,47 +164,6 @@ //! also implements the `ConnectionUpgrade` trait and will choose one of the protocols amongst the //! ones supported. //! -//! # Swarm -//! -//! Once you have created an object that implements the `Transport` trait, you can put it in a -//! *swarm*. This is done by calling the `swarm()` freestanding function with the transport -//! alongside with a function or a closure that will turn the output of the upgrade (usually an -//! actual protocol, as explained above) into a `Future` producing `()`. -//! -//! ```no_run -//! extern crate futures; -//! extern crate libp2p_ping; -//! extern crate libp2p_core; -//! extern crate libp2p_tcp_transport; -//! extern crate tokio_current_thread; -//! -//! use futures::{Future, Stream}; -//! use libp2p_ping::{Ping, PingOutput}; -//! use libp2p_core::Transport; -//! -//! # fn main() { -//! let transport = libp2p_tcp_transport::TcpConfig::new() -//! .with_dummy_muxing(); -//! -//! let (swarm_controller, swarm_future) = libp2p_core::swarm(transport.with_upgrade(Ping::default()), -//! |out, client_addr| { -//! match out { -//! PingOutput::Ponger(processing) => Box::new(processing) as Box>, -//! PingOutput::Pinger(mut pinger) => { -//! pinger.ping(()); -//! let f = pinger.into_future().map(|_| ()).map_err(|(err, _)| err); -//! Box::new(f) as Box> -//! }, -//! } -//! }); -//! -//! // The `swarm_controller` can then be used to do some operations. -//! swarm_controller.listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap()); -//! -//! // Runs until everything is finished. -//! tokio_current_thread::block_on_all(swarm_future.for_each(|_| Ok(()))).unwrap(); -//! # } -//! ``` extern crate bs58; extern crate bytes; @@ -244,11 +203,9 @@ extern crate tokio_mock_task; /// Multi-address re-export. pub extern crate multiaddr; -mod connection_reuse; mod keys_proto; mod peer_id; mod public_key; -mod unique; #[cfg(test)] mod tests; @@ -256,16 +213,12 @@ mod tests; pub mod either; pub mod muxing; pub mod nodes; -pub mod swarm; pub mod transport; pub mod upgrade; -pub use self::connection_reuse::ConnectionReuse; pub use self::multiaddr::Multiaddr; pub use self::muxing::StreamMuxer; pub use self::peer_id::PeerId; pub use self::public_key::PublicKey; -pub use self::swarm::{swarm, SwarmController, SwarmEvents}; pub use self::transport::{MuxedTransport, Transport}; -pub use self::unique::{UniqueConnec, UniqueConnecFuture, UniqueConnecState}; pub use self::upgrade::{ConnectionUpgrade, Endpoint}; diff --git a/core/src/transport/memory.rs b/core/src/transport/memory.rs index 309dee4a522..14d53111396 100644 --- a/core/src/transport/memory.rs +++ b/core/src/transport/memory.rs @@ -190,91 +190,3 @@ impl Into>> for Chan { RwStreamSink::new(self) } } - -#[cfg(test)] -mod tests { - use bytes::Bytes; - use futures::{future::{self, Either, Loop}, prelude::*, sync::mpsc}; - use std::{io, iter}; - use {transport::memory, swarm, ConnectionUpgrade, Endpoint, Transport}; - use tokio_codec::{BytesCodec, Framed}; - use tokio_current_thread; - - #[test] - fn echo() { - #[derive(Clone)] - struct Echo(mpsc::UnboundedSender<()>); - - impl ConnectionUpgrade, Maf> for Echo { - type NamesIter = iter::Once<(Bytes, ())>; - type UpgradeIdentifier = (); - type Output = (); - type MultiaddrFuture = Maf; - type Future = Box + Send>; - - fn protocol_names(&self) -> Self::NamesIter { - iter::once(("/echo/1.0.0".into(), ())) - } - - fn upgrade(self, chan: memory::Channel, _: (), e: Endpoint, maf: Maf) -> Self::Future { - let chan = Framed::new(chan, BytesCodec::new()); - match e { - Endpoint::Listener => { - let future = future::loop_fn(chan, move |chan| { - chan.into_future() - .map_err(|(e, _)| e) - .and_then(move |(msg, chan)| { - if let Some(msg) = msg { - println!("listener received: {:?}", msg); - Either::A(chan.send(msg.freeze()).map(Loop::Continue)) - } else { - println!("listener received EOF at destination"); - Either::B(future::ok(Loop::Break(()))) - } - }) - }); - Box::new(future.map(move |()| ((), maf))) as Box<_> - } - Endpoint::Dialer => { - let future = chan.send("hello world".into()) - .and_then(|chan| { - chan.into_future().map_err(|(e, _)| e).map(|(n,_ )| n) - }) - .and_then(|msg| { - println!("dialer received: {:?}", msg.unwrap()); - self.0.send(()) - .map(|_| ()) - .map_err(|e| io::Error::new(io::ErrorKind::Other, e)) - }); - Box::new(future.map(move |()| ((), maf))) as Box<_> - } - } - } - } - - let (finish_tx, finish_rx) = mpsc::unbounded(); - let echo = Echo(finish_tx); - - let (dialer, listener) = memory::connector(); - - let dialer = dialer.with_dummy_muxing().with_upgrade(echo.clone()); - let listener = listener.with_dummy_muxing().with_upgrade(echo); - - let (control, future) = swarm(listener, |sock, _addr| Ok(sock)); - - control.listen_on("/memory".parse().expect("/memory is a valid multiaddr")).unwrap(); - control.dial("/memory".parse().expect("/memory is a valid multiaddr"), dialer).unwrap(); - - let finish_rx = finish_rx.into_future() - .map(|_| ()) - .map_err(|((), _)| io::Error::new(io::ErrorKind::Other, "receive error")); - - let future = future - .for_each(|_| Ok(())) - .select(finish_rx) - .map(|_| ()) - .map_err(|(e, _)| e); - - tokio_current_thread::block_on_all(future).unwrap(); - } -} diff --git a/core/src/transport/mod.rs b/core/src/transport/mod.rs index 77354f20ecd..7679e3f09c3 100644 --- a/core/src/transport/mod.rs +++ b/core/src/transport/mod.rs @@ -29,10 +29,8 @@ //! `UpgradedNode::or_upgrade` methods, you can combine multiple transports and/or upgrades //! together in a complex chain of protocols negotiation. -use connection_reuse::ConnectionReuse; use futures::prelude::*; use multiaddr::Multiaddr; -use muxing::StreamMuxer; use std::io::Error as IoError; use tokio_io::{AsyncRead, AsyncWrite}; use upgrade::{ConnectionUpgrade, Endpoint}; @@ -243,17 +241,6 @@ pub trait Transport { DummyMuxing::new(self) } - /// Turns this `Transport` into a `ConnectionReuse`. If the `Output` implements the - /// `StreamMuxer` trait, the returned object will implement `Transport` and `MuxedTransport`. - #[inline] - fn into_connection_reuse(self) -> ConnectionReuse - where - Self: Sized + Transport, - M: StreamMuxer, - { - ConnectionReuse::new(self) - } - /// Wraps around the `Transport` and makes it interruptible. #[inline] fn interruptible(self) -> (interruptible::Interruptible, interruptible::Interrupt) diff --git a/core/tests/lots_of_connec.rs b/core/tests/lots_of_connec.rs deleted file mode 100644 index 99a69a9e9dd..00000000000 --- a/core/tests/lots_of_connec.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -extern crate bytes; -extern crate futures; -extern crate libp2p_mplex as multiplex; -extern crate libp2p_core; -extern crate libp2p_tcp_transport; -extern crate rand; -extern crate tokio_current_thread; -extern crate tokio_io; - -use futures::{future, future::Future, Stream}; -use libp2p_core::Transport; -use libp2p_tcp_transport::TcpConfig; -use std::sync::{atomic, Arc}; - -#[test] -fn lots_of_swarms() { - let transport = TcpConfig::new().with_dummy_muxing(); - - let mut swarm_controllers = Vec::new(); - let mut swarm_futures = Vec::new(); - - let num_established = Arc::new(atomic::AtomicUsize::new(0)); - - for _ in 0 .. 200 + rand::random::() % 100 { - let esta = num_established.clone(); - let (ctrl, fut) = libp2p_core::swarm( - transport.clone(), - move |socket, _| { - esta.fetch_add(1, atomic::Ordering::SeqCst); - future::ok(socket).join(future::empty::<(), _>()).map(|_| ()) - } - ); - - swarm_controllers.push(ctrl); - swarm_futures.push(fut.for_each(|_| Ok(()))); - } - - let mut addresses = Vec::new(); - for ctrl in &swarm_controllers { - addresses.push(ctrl.listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()).unwrap()); - } - - let mut dial_fut = Vec::new(); - let num_to_establish = 150 + rand::random::() % 150; - for _ in 0 .. num_to_establish { - let ctrl = swarm_controllers.get(rand::random::() % swarm_controllers.len()).unwrap(); - let to_dial = addresses.get(rand::random::() % addresses.len()).unwrap(); - dial_fut.push(ctrl.dial(to_dial.clone(), transport.clone()).unwrap()); - } - - let select_swarm = future::select_all(swarm_futures).map(|_| ()).map_err(|(err, _, _)| err); - let select_dial = future::join_all(dial_fut).map(|_| ()); - let combined = select_swarm.select(select_dial).map(|_| ()).map_err(|(err, _)| err); - tokio_current_thread::block_on_all(combined).unwrap(); - - assert_eq!(num_established.load(atomic::Ordering::SeqCst), num_to_establish * 2); -} diff --git a/core/tests/multiplex.rs b/core/tests/multiplex.rs deleted file mode 100644 index 989216cc304..00000000000 --- a/core/tests/multiplex.rs +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -extern crate bytes; -extern crate futures; -extern crate libp2p_mplex as multiplex; -extern crate libp2p_core; -extern crate libp2p_tcp_transport; -extern crate tokio_current_thread; -extern crate tokio_io; - -use bytes::BytesMut; -use futures::future::Future; -use futures::{Sink, Stream}; -use libp2p_core::{muxing, Multiaddr, MuxedTransport, Transport, transport}; -use std::sync::{atomic, Arc}; -use std::thread; -use tokio_io::codec::length_delimited::Framed; - -// Ensures that a transport is only ever used once for dialing. -#[derive(Debug)] -struct OnlyOnce(T, atomic::AtomicBool); -impl From for OnlyOnce { - fn from(tp: T) -> OnlyOnce { - OnlyOnce(tp, atomic::AtomicBool::new(false)) - } -} -impl Clone for OnlyOnce { - fn clone(&self) -> Self { - OnlyOnce( - self.0.clone(), - atomic::AtomicBool::new(self.1.load(atomic::Ordering::SeqCst)), - ) - } -} -impl Transport for OnlyOnce { - type Output = T::Output; - type MultiaddrFuture = T::MultiaddrFuture; - type Listener = T::Listener; - type ListenerUpgrade = T::ListenerUpgrade; - type Dial = T::Dial; - fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { - Ok(self.0.listen_on(addr).unwrap_or_else(|_| panic!())) - } - fn dial(self, addr: Multiaddr) -> Result { - assert!(!self.1.swap(true, atomic::Ordering::SeqCst)); - Ok(self.0.dial(addr).unwrap_or_else(|_| panic!())) - } - fn nat_traversal(&self, a: &Multiaddr, b: &Multiaddr) -> Option { - self.0.nat_traversal(a, b) - } -} - -#[test] -fn client_to_server_outbound() { - // A client opens a connection to a server, then an outgoing substream, then sends a message - // on that substream. - - let (tx, rx) = transport::connector(); - - let bg_thread = thread::spawn(move || { - let future = rx - .with_upgrade(multiplex::MplexConfig::new()) - .map(|val, _| ((), val)) - .into_connection_reuse() - .map(|((), val), _| val) - .listen_on("/memory".parse().unwrap()) - .unwrap_or_else(|_| panic!()).0 - .into_future() - .map_err(|(err, _)| err) - .and_then(|(client, _)| client.unwrap()) - .map(|client| client.0) - .map(|client| Framed::<_, BytesMut>::new(client)) - .and_then(|client| { - client - .into_future() - .map_err(|(err, _)| err) - .map(|(msg, _)| msg) - }) - .and_then(|msg| { - let msg = msg.unwrap(); - assert_eq!(msg, "hello world"); - Ok(()) - }); - - tokio_current_thread::block_on_all(future).unwrap(); - }); - - let future = tx - .with_upgrade(multiplex::MplexConfig::new()) - .dial("/memory".parse().unwrap()) - .unwrap_or_else(|_| panic!()) - .and_then(|client| muxing::outbound_from_ref_and_wrap(Arc::new(client.0))) - .map(|server| Framed::<_, BytesMut>::new(server.unwrap())) - .and_then(|server| server.send("hello world".into())) - .map(|_| ()); - - tokio_current_thread::block_on_all(future).unwrap(); - bg_thread.join().unwrap(); -} - -#[test] -fn connection_reused_for_dialing() { - // A client dials the same multiaddress twice in a row. We check that it uses two substreams - // instead of opening two different connections. - - let (tx, rx) = transport::connector(); - - let bg_thread = thread::spawn(move || { - let future = OnlyOnce::from(rx) - .with_upgrade(multiplex::MplexConfig::new()) - .map(|val, _| ((), val)) - .into_connection_reuse() - .map(|((), val), _| val) - .listen_on("/memory".parse().unwrap()) - .unwrap_or_else(|_| panic!()).0 - .into_future() - .map_err(|(err, _)| err) - .and_then(|(client, rest)| client.unwrap().map(move |c| (c.0, rest))) - .map(|(client, rest)| (Framed::<_, BytesMut>::new(client), rest)) - .and_then(|(client, rest)| { - client - .into_future() - .map(|v| (v, rest)) - .map_err(|(err, _)| err) - }) - .and_then(|((msg, _), rest)| { - let msg = msg.unwrap(); - assert_eq!(msg, "hello world"); - Ok(rest) - }) - .flatten_stream() - .into_future() - .map_err(|(err, _)| err) - .and_then(|(client, _)| client.unwrap()) - .map(|client| client.0) - .map(|client| Framed::<_, BytesMut>::new(client)) - .and_then(|client| client.into_future().map_err(|(err, _)| err)) - .and_then(|(msg, _)| { - let msg = msg.unwrap(); - assert_eq!(msg, "second message"); - Ok(()) - }); - - tokio_current_thread::block_on_all(future).unwrap(); - }); - - let transport = OnlyOnce::from(tx) - .with_upgrade(multiplex::MplexConfig::new()) - .map(|val, _| ((), val)) - .into_connection_reuse() - .map(|((), val), _| val); - - let future = transport - .clone() - .dial("/memory".parse().unwrap()) - .unwrap_or_else(|_| panic!()) - .map(|server| Framed::<_, BytesMut>::new(server.0)) - .and_then(|server| server.send("hello world".into())) - .and_then(|first_connec| { - transport - .clone() - .dial("/memory".parse().unwrap()) - .unwrap_or_else(|_| panic!()) - .map(|server| Framed::<_, BytesMut>::new(server.0)) - .map(|server| (first_connec, server)) - }) - .and_then(|(_first, second)| second.send("second message".into())) - .map(|_| ()); - - tokio_current_thread::block_on_all(future).unwrap(); - bg_thread.join().unwrap(); -} - -#[test] -fn use_opened_listen_to_dial() { - // A server waits for an incoming substream and a message on it, then opens an outgoing - // substream on that same connection, that the client has to accept. The client then sends a - // message on that new substream. - - let (tx, rx) = transport::connector(); - - let bg_thread = thread::spawn(move || { - let future = OnlyOnce::from(rx) - .with_upgrade(multiplex::MplexConfig::new()) - .listen_on("/memory".parse().unwrap()) - .unwrap_or_else(|_| panic!()).0 - .into_future() - .map_err(|(err, _)| err) - .and_then(|(client, _)| client.unwrap()) - .map(|client| Arc::new(client.0)) - .and_then(|c| { - let c2 = c.clone(); - muxing::inbound_from_ref_and_wrap(c.clone()).map(move |i| (c2, i)) - }) - .map(|(muxer, client)| (muxer, Framed::<_, BytesMut>::new(client.unwrap()))) - .and_then(|(muxer, client)| { - client - .into_future() - .map(move |msg| (muxer, msg)) - .map_err(|(err, _)| err) - }) - .and_then(|(muxer, (msg, _))| { - let msg = msg.unwrap(); - assert_eq!(msg, "hello world"); - muxing::outbound_from_ref_and_wrap(muxer) - }) - .map(|client| Framed::<_, BytesMut>::new(client.unwrap())) - .and_then(|client| client.into_future().map_err(|(err, _)| err)) - .and_then(|(msg, _)| { - let msg = msg.unwrap(); - assert_eq!(msg, "second message"); - Ok(()) - }); - - tokio_current_thread::block_on_all(future).unwrap(); - }); - - let transport = OnlyOnce::from(tx) - .with_upgrade(multiplex::MplexConfig::new()) - .map(|val, _| ((), val)) - .into_connection_reuse() - .map(|((), val), _| val); - - let future = transport - .clone() - .dial("/memory".parse().unwrap()) - .unwrap_or_else(|_| panic!()) - .map(|server| Framed::<_, BytesMut>::new(server.0)) - .and_then(|server| server.send("hello world".into())) - .and_then(|first_connec| { - transport - .clone() - .next_incoming() - .and_then(|server| server) - .map(|server| Framed::<_, BytesMut>::new(server.0)) - .map(|server| (first_connec, server)) - }) - .and_then(|(_first, second)| second.send("second message".into())) - .map(|_| ()); - - tokio_current_thread::block_on_all(future).unwrap(); - bg_thread.join().unwrap(); -} diff --git a/examples/echo-dialer.rs b/examples/echo-dialer.rs deleted file mode 100644 index 337abfe80f1..00000000000 --- a/examples/echo-dialer.rs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2017 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -extern crate bytes; -extern crate env_logger; -extern crate futures; -extern crate libp2p; -extern crate tokio_codec; -extern crate tokio_current_thread; - -use futures::sync::oneshot; -use futures::{Future, Sink, Stream}; -use std::env; -use libp2p::SimpleProtocol; -use libp2p::core::Transport; -use libp2p::core::{upgrade, either::EitherOutput}; -use libp2p::tcp::TcpConfig; -use tokio_codec::{BytesCodec, Framed}; -use libp2p::websocket::WsConfig; - -fn main() { - env_logger::init(); - - // Determine which address to dial. - let target_addr = env::args() - .nth(1) - .unwrap_or("/ip4/127.0.0.1/tcp/10333".to_owned()); - - // We start by creating a `TcpConfig` that indicates that we want TCP/IP. - let transport = TcpConfig::new() - // In addition to TCP/IP, we also want to support the Websockets protocol on top of TCP/IP. - // The parameter passed to `WsConfig::new()` must be an implementation of `Transport` to be - // used for the underlying multiaddress. - .or_transport(WsConfig::new(TcpConfig::new())) - - // On top of TCP/IP, we will use either the plaintext protocol or the secio protocol, - // depending on which one the remote supports. - .with_upgrade({ - let plain_text = upgrade::PlainTextConfig; - - let secio = { - let private_key = include_bytes!("test-rsa-private-key.pk8"); - let public_key = include_bytes!("test-rsa-public-key.der").to_vec(); - let keypair = libp2p::secio::SecioKeyPair::rsa_from_pkcs8(private_key, public_key).unwrap(); - libp2p::secio::SecioConfig::new(keypair) - - }; - - upgrade::or( - upgrade::map(plain_text, |pt| EitherOutput::First(pt)), - upgrade::map(secio, |out: libp2p::secio::SecioOutput<_>| EitherOutput::Second(out.stream)) - ) - }) - - // On top of plaintext or secio, we will use the multiplex protocol. - .with_upgrade(libp2p::mplex::MplexConfig::new()) - // The object returned by the call to `with_upgrade(MplexConfig::new())` can't be used as a - // `Transport` because the output of the upgrade is not a stream but a controller for - // muxing. We have to explicitly call `into_connection_reuse()` in order to turn this into - // a `Transport`. - .map(|val, _| ((), val)) - .into_connection_reuse() - .map(|((), val), _| val); - - // Building a struct that represents the protocol that we are going to use for dialing. - let proto = SimpleProtocol::new("/echo/1.0.0", |socket| { - // This closure is called whenever a stream using the "echo" protocol has been - // successfully negotiated. The parameter is the raw socket (implements the AsyncRead - // and AsyncWrite traits), and the closure must return an implementation of - // `IntoFuture` that can yield any type of object. - Ok(Framed::new(socket, BytesCodec::new())) - }); - - let (finished_tx, finished_rx) = oneshot::channel(); - let mut finished_tx = Some(finished_tx); - - // Let's put this `transport` into a *swarm*. The swarm will handle all the incoming - // connections for us. The second parameter we pass is the connection upgrade that is accepted - // by the listening part. We don't want to accept anything, so we pass a dummy object that - // represents a connection that is always denied. - let (swarm_controller, swarm_future) = libp2p::core::swarm( - transport.clone().with_upgrade(proto.clone()), - |echo, _client_addr| { - // `echo` is what the closure used when initializing `proto` returns. - // Consequently, please note that the `send` method is available only because the type - // `length_delimited::Framed` has a `send` method. - println!("Sending \"hello world\" to listener"); - let finished_tx = finished_tx.take(); - echo.send("hello world".into()) - // Then listening for one message from the remote. - .and_then(|echo| { - echo.into_future().map_err(|(e, _)| e).map(|(n,_ )| n) - }) - .and_then(move |message| { - println!("Received message from listener: {:?}", message.unwrap()); - if let Some(finished_tx) = finished_tx { - finished_tx.send(()).unwrap(); - } - Ok(()) - }) - }, - ); - - // We now use the controller to dial to the address. - swarm_controller - .dial(target_addr.parse().expect("invalid multiaddr"), transport.with_upgrade(proto)) - // If the multiaddr protocol exists but is not supported, then we get an error containing - // the original multiaddress. - .expect("unsupported multiaddr"); - - // The address we actually listen on can be different from the address that was passed to - // the `listen_on` function. For example if you pass `/ip4/0.0.0.0/tcp/0`, then the port `0` - // will be replaced with the actual port. - - // `swarm_future` is a future that contains all the behaviour that we want, but nothing has - // actually started yet. Because we created the `TcpConfig` with tokio, we need to run the - // future through the tokio core. - let final_future = swarm_future - .for_each(|_| Ok(())) - .select(finished_rx.map_err(|_| unreachable!())) - .map(|_| ()) - .map_err(|(err, _)| err); - tokio_current_thread::block_on_all(final_future).unwrap(); -} diff --git a/examples/echo-server.rs b/examples/echo-server.rs deleted file mode 100644 index a1f22ce842d..00000000000 --- a/examples/echo-server.rs +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2017 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -extern crate bytes; -extern crate env_logger; -extern crate futures; -extern crate libp2p; -extern crate tokio_codec; -extern crate tokio_current_thread; - -use futures::future::{loop_fn, Future, IntoFuture, Loop}; -use futures::{Sink, Stream}; -use std::env; -use libp2p::SimpleProtocol; -use libp2p::core::Transport; -use libp2p::core::{upgrade, either::EitherOutput}; -use libp2p::tcp::TcpConfig; -use tokio_codec::{BytesCodec, Framed}; -use libp2p::websocket::WsConfig; - -fn main() { - env_logger::init(); - - // Determine which address to listen to. - let listen_addr = env::args() - .nth(1) - .unwrap_or("/ip4/0.0.0.0/tcp/10333".to_owned()); - - // We start by creating a `TcpConfig` that indicates that we want TCP/IP. - let transport = TcpConfig::new() - // In addition to TCP/IP, we also want to support the Websockets protocol on top of TCP/IP. - // The parameter passed to `WsConfig::new()` must be an implementation of `Transport` to be - // used for the underlying multiaddress. - .or_transport(WsConfig::new(TcpConfig::new())) - - // On top of TCP/IP, we will use either the plaintext protocol or the secio protocol, - // depending on which one the remote supports. - .with_upgrade({ - let plain_text = upgrade::PlainTextConfig; - - let secio = { - let private_key = include_bytes!("test-rsa-private-key.pk8"); - let public_key = include_bytes!("test-rsa-public-key.der").to_vec(); - let keypair = libp2p::secio::SecioKeyPair::rsa_from_pkcs8(private_key, public_key).unwrap(); - libp2p::secio::SecioConfig::new(keypair) - }; - - upgrade::or( - upgrade::map(plain_text, |pt| EitherOutput::First(pt)), - upgrade::map(secio, |out: libp2p::secio::SecioOutput<_>| EitherOutput::Second(out.stream)) - ) - }) - - // On top of plaintext or secio, we will use the multiplex protocol. - .with_upgrade(libp2p::mplex::MplexConfig::new()) - // The object returned by the call to `with_upgrade(MplexConfig::new())` can't be used as a - // `Transport` because the output of the upgrade is not a stream but a controller for - // muxing. We have to explicitly call `into_connection_reuse()` in order to turn this into - // a `Transport`. - .map(|val, _| ((), val)) - .into_connection_reuse() - .map(|((), val), _| val); - - // We now have a `transport` variable that can be used either to dial nodes or listen to - // incoming connections, and that will automatically apply secio and multiplex on top - // of any opened stream. - - // We now prepare the protocol that we are going to negotiate with nodes that open a connection - // or substream to our server. - let proto = SimpleProtocol::new("/echo/1.0.0", |socket| { - // This closure is called whenever a stream using the "echo" protocol has been - // successfully negotiated. The parameter is the raw socket (implements the AsyncRead - // and AsyncWrite traits), and the closure must return an implementation of - // `IntoFuture` that can yield any type of object. - Ok(Framed::new(socket, BytesCodec::new())) - }); - - // Let's put this `transport` into a *swarm*. The swarm will handle all the incoming and - // outgoing connections for us. - let (swarm_controller, swarm_future) = libp2p::core::swarm( - transport.clone().with_upgrade(proto), - |socket, _client_addr| { - println!("Successfully negotiated protocol"); - - // The type of `socket` is exactly what the closure of `SimpleProtocol` returns. - - // We loop forever in order to handle all the messages sent by the client. - loop_fn(socket, move |socket| { - socket - .into_future() - .map_err(|(e, _)| e) - .and_then(move |(msg, rest)| { - if let Some(msg) = msg { - // One message has been received. We send it back to the client. - println!( - "Received a message: {:?}\n => Sending back \ - identical message to remote", msg - ); - Box::new(rest.send(msg.freeze()).map(|m| Loop::Continue(m))) - as Box> - } else { - // End of stream. Connection closed. Breaking the loop. - println!("Received EOF\n => Dropping connection"); - Box::new(Ok(Loop::Break(())).into_future()) - as Box> - } - }) - }) - }, - ); - - // We now use the controller to listen on the address. - let address = swarm_controller - .listen_on(listen_addr.parse().expect("invalid multiaddr")) - // If the multiaddr protocol exists but is not supported, then we get an error containing - // the original multiaddress. - .expect("unsupported multiaddr"); - // The address we actually listen on can be different from the address that was passed to - // the `listen_on` function. For example if you pass `/ip4/0.0.0.0/tcp/0`, then the port `0` - // will be replaced with the actual port. - println!("Now listening on {:?}", address); - - // `swarm_future` is a future that contains all the behaviour that we want, but nothing has - // actually started yet. Because we created the `TcpConfig` with tokio, we need to run the - // future through the tokio core. - tokio_current_thread::block_on_all(swarm_future.for_each(|_| Ok(()))).unwrap(); -} diff --git a/examples/floodsub.rs b/examples/floodsub.rs deleted file mode 100644 index 5f006a66cf7..00000000000 --- a/examples/floodsub.rs +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -extern crate bytes; -extern crate env_logger; -extern crate futures; -extern crate libp2p; -extern crate rand; -extern crate tokio_current_thread; -extern crate tokio_io; -extern crate tokio_stdin; - -use futures::Stream; -use futures::future::Future; -use std::{env, mem}; -use libp2p::core::{either::EitherOutput, upgrade}; -use libp2p::core::{Multiaddr, Transport, PublicKey}; -use libp2p::peerstore::PeerId; -use libp2p::tcp::TcpConfig; -use libp2p::websocket::WsConfig; - -fn main() { - env_logger::init(); - - // Determine which address to listen to. - let listen_addr = env::args() - .nth(1) - .unwrap_or("/ip4/0.0.0.0/tcp/10050".to_owned()); - - // We start by creating a `TcpConfig` that indicates that we want TCP/IP. - let transport = TcpConfig::new() - // In addition to TCP/IP, we also want to support the Websockets protocol on top of TCP/IP. - // The parameter passed to `WsConfig::new()` must be an implementation of `Transport` to be - // used for the underlying multiaddress. - .or_transport(WsConfig::new(TcpConfig::new())) - - // On top of TCP/IP, we will use either the plaintext protocol or the secio protocol, - // depending on which one the remote supports. - .with_upgrade({ - let plain_text = upgrade::PlainTextConfig; - - let secio = { - let private_key = include_bytes!("test-rsa-private-key.pk8"); - let public_key = include_bytes!("test-rsa-public-key.der").to_vec(); - libp2p::secio::SecioConfig::new( - libp2p::secio::SecioKeyPair::rsa_from_pkcs8(private_key, public_key).unwrap() - ) - }; - - upgrade::or( - upgrade::map(plain_text, |pt| EitherOutput::First(pt)), - upgrade::map(secio, |out: libp2p::secio::SecioOutput<_>| EitherOutput::Second(out.stream)) - ) - }) - - // On top of plaintext or secio, we will use the multiplex protocol. - .with_upgrade(libp2p::mplex::MplexConfig::new()) - // The object returned by the call to `with_upgrade(MplexConfig::new())` can't be used as a - // `Transport` because the output of the upgrade is not a stream but a controller for - // muxing. We have to explicitly call `into_connection_reuse()` in order to turn this into - // a `Transport`. - .map(|val, _| ((), val)) - .into_connection_reuse() - .map(|((), val), _| val); - - // We now have a `transport` variable that can be used either to dial nodes or listen to - // incoming connections, and that will automatically apply secio and multiplex on top - // of any opened stream. - - // We now prepare the protocol that we are going to negotiate with nodes that open a connection - // or substream to our server. - let my_id = { - let key = (0..2048).map(|_| rand::random::()).collect::>(); - PeerId::from_public_key(PublicKey::Rsa(key)) - }; - - let (floodsub_upgrade, floodsub_rx) = libp2p::floodsub::FloodSubUpgrade::new(my_id); - - // Let's put this `transport` into a *swarm*. The swarm will handle all the incoming and - // outgoing connections for us. - let (swarm_controller, swarm_future) = libp2p::core::swarm( - transport.clone().with_upgrade(floodsub_upgrade.clone()), - |socket, _| { - println!("Successfully negotiated protocol"); - socket - }, - ); - - let address = swarm_controller - .listen_on(listen_addr.parse().expect("invalid multiaddr")) - .expect("unsupported multiaddr"); - println!("Now listening on {:?}", address); - - let topic = libp2p::floodsub::TopicBuilder::new("chat").build(); - - let floodsub_ctl = libp2p::floodsub::FloodSubController::new(&floodsub_upgrade); - floodsub_ctl.subscribe(&topic); - - let floodsub_rx = floodsub_rx.for_each(|msg| { - if let Ok(msg) = String::from_utf8(msg.data) { - println!("< {}", msg); - } - Ok(()) - }); - - let stdin = { - let mut buffer = Vec::new(); - tokio_stdin::spawn_stdin_stream_unbounded().for_each(move |msg| { - if msg != b'\r' && msg != b'\n' { - buffer.push(msg); - return Ok(()); - } else if buffer.is_empty() { - return Ok(()); - } - - let msg = String::from_utf8(mem::replace(&mut buffer, Vec::new())).unwrap(); - if msg.starts_with("/dial ") { - let target: Multiaddr = msg[6..].parse().unwrap(); - println!("*Dialing {}*", target); - swarm_controller - .dial( - target, - transport.clone().with_upgrade(floodsub_upgrade.clone()), - ) - .unwrap(); - } else { - floodsub_ctl.publish(&topic, msg.into_bytes()); - } - - Ok(()) - }) - }; - - let final_fut = swarm_future - .for_each(|_| Ok(())) - .select(floodsub_rx) - .map(|_| ()) - .map_err(|e| e.0) - .select(stdin.map_err(|_| unreachable!())) - .map(|_| ()) - .map_err(|e| e.0); - tokio_current_thread::block_on_all(final_fut).unwrap(); -} diff --git a/examples/kademlia.rs b/examples/kademlia.rs deleted file mode 100644 index f2c08d06464..00000000000 --- a/examples/kademlia.rs +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright 2017 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -// Libp2p's code unfortunately produces very large types. Rust's default length limit for type -// names is not large enough, therefore we need this attribute. -#![type_length_limit = "4194304"] - -extern crate bigint; -extern crate bytes; -extern crate env_logger; -extern crate futures; -extern crate libp2p; -extern crate tokio_current_thread; -extern crate tokio_io; -extern crate multiaddr; - -use bigint::U512; -use futures::{Future, Stream}; -use libp2p::peerstore::{PeerAccess, PeerId, Peerstore}; -use multiaddr::Multiaddr; -use std::collections::HashMap; -use std::env; -use std::sync::{Arc, Mutex}; -use std::time::Duration; -use libp2p::core::{Transport, PublicKey, UniqueConnec}; -use libp2p::core::{upgrade, either::EitherOutput}; -use libp2p::kad::{KadConnecConfig, KadConnectionType, KadPeer, KadQueryEvent, KadSystem}; -use libp2p::kad::{KadSystemConfig, KadIncomingRequest}; -use libp2p::tcp::TcpConfig; - -fn main() { - env_logger::init(); - - // Determine which addresses to listen to. - let listen_addrs = { - let mut args = env::args().skip(1).collect::>(); - if args.is_empty() { - args.push("/ip4/0.0.0.0/tcp/0".to_owned()); - } - args - }; - - let peer_store = Arc::new(libp2p::peerstore::memory_peerstore::MemoryPeerstore::empty()); - ipfs_bootstrap(&*peer_store); - - // We create a `TcpConfig` that indicates that we want TCP/IP. - let transport = TcpConfig::new() - - // On top of TCP/IP, we will use either the plaintext protocol or the secio protocol, - // depending on which one the remote supports. - .with_upgrade({ - let plain_text = upgrade::PlainTextConfig; - - let secio = { - let private_key = include_bytes!("test-rsa-private-key.pk8"); - let public_key = include_bytes!("test-rsa-public-key.der").to_vec(); - libp2p::secio::SecioConfig::new( - libp2p::secio::SecioKeyPair::rsa_from_pkcs8(private_key, public_key).unwrap() - ) - }; - - upgrade::or( - upgrade::map(plain_text, |pt| EitherOutput::First(pt)), - upgrade::map(secio, |out: libp2p::secio::SecioOutput<_>| EitherOutput::Second(out.stream)) - ) - }) - - // On top of plaintext or secio, we will use the multiplex protocol. - .with_upgrade(libp2p::mplex::MplexConfig::new()) - // The object returned by the call to `with_upgrade(MplexConfig::new())` can't be used as a - // `Transport` because the output of the upgrade is not a stream but a controller for - // muxing. We have to explicitly call `into_connection_reuse()` in order to turn this into - // a `Transport`. - .map(|val, _| ((), val)) - .into_connection_reuse() - .map(|((), val), _| val); - - let addr_resolver = { - let peer_store = peer_store.clone(); - move |peer_id| { - peer_store - .peer(&peer_id) - .into_iter() - .flat_map(|peer| peer.addrs()) - .collect::>() - .into_iter() - } - }; - - let transport = libp2p::identify::PeerIdTransport::new(transport, addr_resolver) - .and_then({ - let peer_store = peer_store.clone(); - move |id_out, _, remote_addr| { - let socket = id_out.socket; - let original_addr = id_out.original_addr; - id_out.info.map(move |info| { - let peer_id = info.info.public_key.into_peer_id(); - peer_store.peer_or_create(&peer_id).add_addr(original_addr, Duration::from_secs(3600)); - (socket, remote_addr) - }) - } - }); - - // We now have a `transport` variable that can be used either to dial nodes or listen to - // incoming connections, and that will automatically apply secio and multiplex on top - // of any opened stream. - - let my_peer_id = PeerId::from_public_key(PublicKey::Rsa(include_bytes!("test-rsa-public-key.der").to_vec())); - println!("Local peer id is: {:?}", my_peer_id); - - let kad_system = Arc::new(KadSystem::without_init(KadSystemConfig { - parallelism: 3, - local_peer_id: my_peer_id.clone(), - kbuckets_timeout: Duration::from_secs(10), - request_timeout: Duration::from_secs(10), - known_initial_peers: peer_store.peers(), - })); - - let active_kad_connections = Arc::new(Mutex::new(HashMap::<_, UniqueConnec<_>>::new())); - - // Let's put this `transport` into a *swarm*. The swarm will handle all the incoming and - // outgoing connections for us. - let (swarm_controller, swarm_future) = libp2p::core::swarm( - transport.clone().with_upgrade(KadConnecConfig::new()), - { - let peer_store = peer_store.clone(); - let kad_system = kad_system.clone(); - let active_kad_connections = active_kad_connections.clone(); - move |(kad_ctrl, kad_stream), node_addr| { - let peer_store = peer_store.clone(); - let kad_system = kad_system.clone(); - let active_kad_connections = active_kad_connections.clone(); - node_addr.and_then(move |node_addr| { - let node_id = p2p_multiaddr_to_node_id(node_addr); - let node_id2 = node_id.clone(); - let fut = kad_stream.for_each(move |req| { - let peer_store = peer_store.clone(); - kad_system.update_kbuckets(node_id2.clone()); - match req { - KadIncomingRequest::FindNode { searched, responder } => { - let result = kad_system - .known_closest_peers(&searched) - .map(move |peer_id| { - let addrs = peer_store - .peer(&peer_id) - .into_iter() - .flat_map(|p| p.addrs()) - .collect::>(); - KadPeer { - node_id: peer_id.clone(), - multiaddrs: addrs, - connection_ty: KadConnectionType::Connected, // meh :-/ - } - }) - .collect::>(); - responder.respond(result); - }, - KadIncomingRequest::GetProviders { .. } => { - }, - KadIncomingRequest::AddProvider { .. } => { - }, - KadIncomingRequest::PingPong => { - } - }; - Ok(()) - }); - - let mut active_kad_connections = active_kad_connections.lock().unwrap(); - active_kad_connections - .entry(node_id) - .or_insert_with(Default::default) - .tie_or_passthrough(kad_ctrl, fut) - }) - } - } - ); - - for listen_addr in listen_addrs { - let addr = swarm_controller - .listen_on(listen_addr.parse().expect("invalid multiaddr")) - .expect("unsupported multiaddr"); - println!("Now listening on {:?}", addr); - } - - let finish_enum = kad_system - .find_node(my_peer_id.clone(), |peer| { - let addr = Multiaddr::from(libp2p::multiaddr::Protocol::P2p(peer.clone().into())); - active_kad_connections.lock().unwrap().entry(peer.clone()) - .or_insert_with(Default::default) - .dial(&swarm_controller, &addr, transport.clone().with_upgrade(KadConnecConfig::new())) - }) - .filter_map(move |event| { - match event { - KadQueryEvent::PeersReported(peers) => { - for peer in peers { - peer_store.peer_or_create(&peer.node_id) - .add_addrs(peer.multiaddrs, Duration::from_secs(3600)); - } - None - }, - KadQueryEvent::Finished(out) => Some(out), - } - }) - .into_future() - .map_err(|(err, _)| err) - .map(|(out, _)| out.unwrap()) - .and_then(|out| { - let local_hash = U512::from(my_peer_id.digest()); - println!("Results of peer discovery for {:?}:", my_peer_id); - for n in out { - let other_hash = U512::from(n.digest()); - let dist = 512 - (local_hash ^ other_hash).leading_zeros(); - println!("* {:?} (distance bits = {:?} (lower is better))", n, dist); - } - Ok(()) - }); - - // `swarm_future` is a future that contains all the behaviour that we want, but nothing has - // actually started yet. Because we created the `TcpConfig` with tokio, we need to run the - // future through the tokio core. - tokio_current_thread::block_on_all( - finish_enum - .select(swarm_future.for_each(|_| Ok(()))) - .map(|(n, _)| n) - .map_err(|(err, _)| err), - ).unwrap(); -} - -/// Expects a multiaddr of the format `/p2p/` and returns the node ID. -/// Panics if the format is not correct. -fn p2p_multiaddr_to_node_id(client_addr: Multiaddr) -> PeerId { - let (first, second); - { - let mut iter = client_addr.iter(); - first = iter.next(); - second = iter.next(); - } - match (first, second) { - (Some(libp2p::multiaddr::Protocol::P2p(node_id)), None) => - PeerId::from_multihash(node_id).expect("libp2p always reports a valid node id"), - _ => panic!("Reported multiaddress is in the wrong format ; programmer error") - } -} - -/// Stores initial addresses on the given peer store. Uses a very large timeout. -pub fn ipfs_bootstrap

(peer_store: P) -where - P: Peerstore + Clone, -{ - const ADDRESSES: &[&str] = &[ - "/ip4/127.0.0.1/tcp/4001/p2p/QmQRx32wQkw3hB45j4UDw8V9Ju4mGbxMyhs2m8mpFrFkur", - // TODO: add some bootstrap nodes here - ]; - - let ttl = Duration::from_secs(100 * 365 * 24 * 3600); - - for address in ADDRESSES.iter() { - let mut multiaddr = address - .parse::() - .expect("failed to parse hard-coded multiaddr"); - - let p2p_component = multiaddr.pop().expect("hard-coded multiaddr is empty"); - let peer = match p2p_component { - libp2p::multiaddr::Protocol::P2p(key) => { - PeerId::from_multihash(key).expect("invalid peer id") - } - _ => panic!("hard-coded multiaddr didn't end with /p2p/"), - }; - - peer_store - .clone() - .peer_or_create(&peer) - .add_addr(multiaddr, ttl.clone()); - } -} diff --git a/examples/ping-client.rs b/examples/ping-client.rs deleted file mode 100644 index 5ebe5c33f08..00000000000 --- a/examples/ping-client.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2017 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -extern crate bytes; -extern crate env_logger; -extern crate futures; -extern crate libp2p; -extern crate tokio_current_thread; -extern crate tokio_io; - -use futures::{Future, Stream}; -use futures::sync::oneshot; -use std::env; -use libp2p::core::Transport; -use libp2p::core::{upgrade, either::EitherOutput}; -use libp2p::tcp::TcpConfig; - -fn main() { - env_logger::init(); - - // Determine which address to dial. - let target_addr = env::args() - .nth(1) - .unwrap_or("/ip4/127.0.0.1/tcp/4001".to_owned()); - - // We start by creating a `TcpConfig` that indicates that we want TCP/IP. - let transport = TcpConfig::new() - - // On top of TCP/IP, we will use either the plaintext protocol or the secio protocol, - // depending on which one the remote supports. - .with_upgrade({ - let plain_text = upgrade::PlainTextConfig; - - let secio = { - let private_key = include_bytes!("test-rsa-private-key.pk8"); - let public_key = include_bytes!("test-rsa-public-key.der").to_vec(); - libp2p::secio::SecioConfig::new( - libp2p::secio::SecioKeyPair::rsa_from_pkcs8(private_key, public_key).unwrap() - ) - }; - - upgrade::or( - upgrade::map(plain_text, |pt| EitherOutput::First(pt)), - upgrade::map(secio, |out: libp2p::secio::SecioOutput<_>| EitherOutput::Second(out.stream)) - ) - }) - - // On top of plaintext or secio, we will use the multiplex protocol. - .with_upgrade(libp2p::mplex::MplexConfig::new()) - // The object returned by the call to `with_upgrade(MplexConfig::new())` can't be used as a - // `Transport` because the output of the upgrade is not a stream but a controller for - // muxing. We have to explicitly call `into_connection_reuse()` in order to turn this into - // a `Transport`. - .map(|val, _| ((), val)) - .into_connection_reuse() - .map(|((), val), _| val); - - // Let's put this `transport` into a *swarm*. The swarm will handle all the incoming - // connections for us. The second parameter we pass is the connection upgrade that is accepted - // by the listening part. We don't want to accept anything, so we pass a dummy object that - // represents a connection that is always denied. - let (tx, rx) = oneshot::channel(); - let mut tx = Some(tx); - let (swarm_controller, swarm_future) = libp2p::core::swarm( - transport.clone().with_upgrade(libp2p::ping::Ping::default()), - |out, _client_addr| { - if let libp2p::ping::PingOutput::Pinger(mut pinger) = out { - let tx = tx.take(); - pinger.ping(()); - pinger - .into_future() - .map(move |_| { - println!("Received pong from the remote"); - if let Some(tx) = tx { - let _ = tx.send(()); - } - () - }) - .map_err(|(e, _)| e) - } else { - unreachable!() - } - }, - ); - - // We now use the controller to dial to the address. - swarm_controller - .dial(target_addr.parse().expect("invalid multiaddr"), - transport.with_upgrade(libp2p::ping::Ping::default())) - // If the multiaddr protocol exists but is not supported, then we get an error containing - // the original multiaddress. - .expect("unsupported multiaddr"); - - // The address we actually listen on can be different from the address that was passed to - // the `listen_on` function. For example if you pass `/ip4/0.0.0.0/tcp/0`, then the port `0` - // will be replaced with the actual port. - - // `swarm_future` is a future that contains all the behaviour that we want, but nothing has - // actually started yet. Because we created the `TcpConfig` with tokio, we need to run the - // future through the tokio core. - tokio_current_thread::block_on_all( - rx.select(swarm_future.for_each(|_| Ok(())).map_err(|_| unreachable!())) - .map_err(|(e, _)| e) - .map(|_| ()), - ).unwrap(); -} diff --git a/examples/random_peerid.rs b/examples/random_peerid.rs deleted file mode 100644 index 6fce007bde7..00000000000 --- a/examples/random_peerid.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -extern crate libp2p; -extern crate rand; - -use libp2p::{PeerId, core::PublicKey}; - -fn main() { - let pid = { - let key = (0..2048).map(|_| rand::random::()).collect::>(); - PeerId::from_public_key(PublicKey::Rsa(key)) - }; - println!("{}", pid.to_base58()); -} diff --git a/examples/relay.rs b/examples/relay.rs deleted file mode 100644 index 0eab6c4bef2..00000000000 --- a/examples/relay.rs +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -//! Example runs -//! ============ -//! -//! As destination -//! -------------- -//! -//! relay listen \ -//! --self "QmcwnUP8cM2U4EeMW6g6nbFUQRyE6xXh65TPaZD9bqkhdK" \ -//! --listen "/ip4/127.0.0.1/tcp/10003" \ -//! --peer "QmXnxVaQoP8cPm2J5uN73GPEu3pCkJdYDNDCMZS8dMxTXL=/ip4/127.0.0.1/tcp/10002" -//! -//! As relay -//! -------- -//! -//! relay listen \ -//! --self "QmXnxVaQoP8cPm2J5uN73GPEu3pCkJdYDNDCMZS8dMxTXL" \ -//! --listen "/ip4/127.0.0.1/tcp/10002" \ -//! --peer "QmcwnUP8cM2U4EeMW6g6nbFUQRyE6xXh65TPaZD9bqkhdK=/ip4/127.0.0.1/tcp/10003" -//! -//! As source -//! --------- -//! -//! relay dial \ -//! --self "QmYJ46WjbwxLkrTGU1JZNEN3HnYbcuES8QahG1PAMCxFY8" \ -//! --destination "QmcwnUP8cM2U4EeMW6g6nbFUQRyE6xXh65TPaZD9bqkhdK" \ -//! --relay "QmXnxVaQoP8cPm2J5uN73GPEu3pCkJdYDNDCMZS8dMxTXL" \ -//! --peer "QmXnxVaQoP8cPm2J5uN73GPEu3pCkJdYDNDCMZS8dMxTXL=/ip4/127.0.0.1/tcp/10002" - -extern crate bytes; -extern crate env_logger; -extern crate futures; -extern crate libp2p; -extern crate libp2p_yamux; -extern crate rand; -#[macro_use] -extern crate structopt; -extern crate tokio_codec; -extern crate tokio_current_thread; - -use libp2p::SimpleProtocol; -use libp2p::core::Multiaddr; -use libp2p::core::transport::Transport; -use libp2p::core::upgrade; -use futures::{future::{self, Either, Loop, loop_fn}, prelude::*}; -use libp2p::peerstore::{PeerAccess, PeerId, Peerstore, memory_peerstore::MemoryPeerstore}; -use libp2p::relay::{RelayConfig, RelayTransport}; -use std::{error::Error, iter, str::FromStr, sync::Arc, time::Duration}; -use structopt::StructOpt; -use libp2p::tcp::TcpConfig; -use tokio_codec::{BytesCodec, Framed}; - -fn main() -> Result<(), Box> { - env_logger::init(); - match Options::from_args() { - Options::Dialer(opts) => run_dialer(opts), - Options::Listener(opts) => run_listener(opts) - } -} - -#[derive(Debug, StructOpt)] -#[structopt(name = "relay", about = "Usage example for /libp2p/relay/circuit/0.1.0")] -enum Options { - #[structopt(name = "dial")] - /// Run in dial mode. - Dialer(DialerOpts), - #[structopt(name = "listen")] - /// Run in listener mode. - Listener(ListenerOpts) -} - -#[derive(Debug, StructOpt)] -struct DialerOpts { - #[structopt(short = "s", long = "self", parse(try_from_str))] - /// The PeerId of this node. - me: PeerId, - #[structopt(short = "d", long = "destination", parse(try_from_str))] - /// The PeerId to dial. - dest: PeerId, - #[structopt(short = "r", long = "relay", parse(try_from_str))] - /// The PeerId of the relay node to use when dialing the destination. - relay: PeerId, - #[structopt(short = "p", long = "peer", parse(try_from_str = "parse_peer_addr"))] - /// A network peer known to this node (format: PeerId=Multiaddr). - /// For example: QmXnxVaQoP8cPm2J5uN73GPEu3pCkJdYDNDCMZS8dMxTXL=/ip4/127.0.0.1/tcp/12345 - peers: Vec<(PeerId, Multiaddr)> -} - -#[derive(Debug, StructOpt)] -struct ListenerOpts { - #[structopt(short = "s", long = "self", parse(try_from_str))] - /// The PeerId of this node. - me: PeerId, - #[structopt(short = "p", long = "peer", parse(try_from_str = "parse_peer_addr"))] - /// A network peer know to this node (format: PeerId=Multiaddr). - /// For example: QmXnxVaQoP8cPm2J5uN73GPEu3pCkJdYDNDCMZS8dMxTXL=/ip4/127.0.0.1/tcp/12345 - peers: Vec<(PeerId, Multiaddr)>, - #[structopt(short = "l", long = "listen", parse(try_from_str))] - /// The multiaddress to listen for incoming connections. - listen: Multiaddr -} - -fn run_dialer(opts: DialerOpts) -> Result<(), Box> { - let store = Arc::new(MemoryPeerstore::empty()); - for (p, a) in opts.peers { - store.peer_or_create(&p).add_addr(a, Duration::from_secs(600)) - } - - let transport = { - let tcp = TcpConfig::new() - .with_upgrade(libp2p_yamux::Config::default()) - .map(|val, _| ((), val)) - .into_connection_reuse() - .map(|((), val), _| val); - RelayTransport::new(opts.me, tcp, store, iter::once(opts.relay)).with_dummy_muxing() - }; - - let echo = SimpleProtocol::new("/echo/1.0.0", |socket| { - Ok(Framed::new(socket, BytesCodec::new())) - }); - - let (control, future) = libp2p::core::swarm(transport.clone().with_upgrade(echo.clone()), |socket, _| { - println!("sending \"hello world\""); - socket.send("hello world".into()) - .and_then(|socket| socket.into_future().map_err(|(e, _)| e).map(|(m, _)| m)) - .and_then(|message| { - println!("received message: {:?}", message); - Ok(()) - }) - }); - - let address = format!("/p2p-circuit/p2p/{}", opts.dest.to_base58()).parse()?; - - control.dial(address, transport.with_upgrade(echo)).map_err(|_| "failed to dial")?; - - tokio_current_thread::block_on_all(future.for_each(|_| Ok(()))).map_err(From::from) -} - -fn run_listener(opts: ListenerOpts) -> Result<(), Box> { - let store = Arc::new(MemoryPeerstore::empty()); - for (p, a) in opts.peers { - store.peer_or_create(&p).add_addr(a, Duration::from_secs(600)) - } - - let transport = TcpConfig::new() - .with_upgrade(libp2p_yamux::Config::default()) - .map(|val, _| ((), val)) - .into_connection_reuse() - .map(|((), val), _| val); - - let relay = RelayConfig::new(opts.me, transport.clone(), store); - - let echo = SimpleProtocol::new("/echo/1.0.0", |socket| { - Ok(Framed::new(socket, BytesCodec::new())) - }); - - let upgraded = transport.with_upgrade(relay) - .and_then(|out, endpoint, addr| { - match out { - libp2p::relay::Output::Sealed(future) => { - Either::A(future.map(|out| (Either::A(out), Either::A(addr)))) - } - libp2p::relay::Output::Stream(socket) => { - Either::B(upgrade::apply(socket, echo, endpoint, addr) - .map(|(out, addr)| (Either::B(out), Either::B(addr)))) - } - } - }); - - let (control, future) = libp2p::core::swarm(upgraded, |out, _| { - match out { - Either::A(()) => Either::A(future::ok(())), - Either::B(socket) => Either::B(loop_fn(socket, move |socket| { - socket.into_future() - .map_err(|(e, _)| e) - .and_then(move |(msg, socket)| { - if let Some(msg) = msg { - println!("received at destination: {:?}", msg); - Either::A(socket.send(msg.freeze()).map(Loop::Continue)) - } else { - println!("received EOF at destination"); - Either::B(future::ok(Loop::Break(()))) - } - }) - })) - } - }); - - control.listen_on(opts.listen).map_err(|_| "failed to listen")?; - tokio_current_thread::block_on_all(future.for_each(|_| Ok(()))).map_err(From::from) -} - -// Custom parsers /////////////////////////////////////////////////////////// - -fn parse_peer_addr(s: &str) -> Result<(PeerId, Multiaddr), Box> { - let mut iter = s.splitn(2, '='); - let p = iter.next() - .and_then(|s| PeerId::from_str(s).ok()) - .ok_or("missing or invalid PeerId")?; - let m = iter.next() - .and_then(|s| Multiaddr::from_str(s).ok()) - .ok_or("missing or invalid Multiaddr")?; - Ok((p, m)) -} - diff --git a/examples/test-rsa-private-key.pk8 b/examples/test-rsa-private-key.pk8 deleted file mode 100644 index 452b7af11377ca1ab27401dc29b616ef383bae72..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1219 zcmV;!1U&mNf&{+;0RS)!1_>&LNQUrsW5^Br2+u}0)hbn0K;(V^2bVN z^6JnD0u>N`%LEsu=I@2}mws$CbWZw13NOPfhRl(fuf3{^%zE zD<5MhzfrHEn>LrHpH`#5@t7bD8o-i^V=Z;bf&k)}fueF0QupYyHZRMH-uoYB#V%=N zP5Q+;IGb9t&-r`kVG&K-9bm~s`9D}dMdRgdzdCitb$gkA$N51Fe#0l^@v)BOi=pF! z`Ee_Vz+JC$&DjIIlc`C|K9#QE8LTjRz{;TxU0W)pfj@U~wc)_w(^C2{o?Rir)+30o zR2gNwrrG`fccEYmqUfxDN}|cJc!?HM;Mby!x^aOVzSRI+m}i|$69NMP009Dm0RTb? zWm%&A0V0z$x7K_|mXHEb`;!bfnuv44sQ)ihEVaJ_*9^e z`_Uz!2bc2bA_)plRLd)vZh*u zqaF!7WvpOc@2Q4m;}isE24<*f((VOG(2WS-8{^b@!Q|$h?w!1sMshmNeumGeJt?R( z^JelR{z+T^kR;KJ8xi#F@JhN8zK5m^^X?D z(FeGrDk+4fdJTs*j;f0FkaJ!?cj$D@iO#Ee5>61+=hO1 zeFCSr6T)Xnl#9T4hUB%qvK5|615cI3Ms;J8XTP-}L{F>I*{ENia^=mQaYm^ZmSY=~}B_sjk(cKnl}2vkQJzY(GH!h_WJV#ExlBBF?MyN#H|yG5Z36 zfdHS|G=S4qRA+@;Ro?vd5N;!;{e)P)lZ}gA}fdHS(jQkNk$Uy_0jtgnPEOu>zSC&I2 z0q>-J_7Jj_5XdEvQ8)gXH2kmtO5oRwN&7!ebDW7At+Mw^knOjkiVjd*4dD5zS$p1; z{ui_P!?rM=V@our1ArXI^38s-z&Q@%ik>o?U%xoQbbJm=5!+q5rYUeBL1F{f>v_I% zKxYDhfdI?^vg%7f{7?uV0L(D$=Uk}TOx#P}#7fUFJw)onjI-GyOsQ6JP>Uv* hv60PPFuRS$Ty2a9Lxa2c4}sY^u8x&NYgA)~zP3@lPz3-0 diff --git a/examples/test-rsa-public-key.der b/examples/test-rsa-public-key.der deleted file mode 100644 index 9e62c93ec1938e6e003e97d46d595414be26460c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 294 zcmV+>0ondAf&n5h4F(A+hDe6@4FLfG1potr0S^E$f&mHwf&l>l!*J^I$4Y1N>d*-S z6%c;Q1Q({}?;Z;rN9D3rUM+P2KG5e0NG@T=mA+iGf6Hx8P4D;7{U~7m=qCRwA7d!L zQLmz#HkYTLR-?f2m>>-rz> Date: Wed, 17 Oct 2018 10:17:40 +0100 Subject: [PATCH 05/19] New core (#568) * New core * Fix lifetime requirements * Remove identify transport * Address &mut & ref ref mut * Fix whitespaces --- core/src/either.rs | 97 ++-- core/src/lib.rs | 4 +- core/src/nodes/collection.rs | 95 ++-- core/src/nodes/handled_node.rs | 70 +-- core/src/nodes/handled_node_tasks.rs | 87 ++-- core/src/nodes/listeners.rs | 50 +- core/src/nodes/mod.rs | 9 +- core/src/nodes/node.rs | 136 +---- core/src/nodes/{swarm.rs => raw_swarm.rs} | 572 ++++++++++++---------- core/src/tests/dummy_transport.rs | 9 +- core/src/transport/and_then.rs | 74 +-- core/src/transport/boxed.rs | 122 +---- core/src/transport/choice.rs | 46 +- core/src/transport/denied.rs | 19 +- core/src/transport/interruptible.rs | 16 +- core/src/transport/map.rs | 42 +- core/src/transport/map_err.rs | 95 +--- core/src/transport/map_err_dial.rs | 20 +- core/src/transport/memory.rs | 18 +- core/src/transport/mod.rs | 55 +-- core/src/transport/upgrade.rs | 92 +--- core/src/upgrade/apply.rs | 37 +- core/src/upgrade/choice.rs | 54 +- core/src/upgrade/denied.rs | 8 +- core/src/upgrade/loop_upg.rs | 20 +- core/src/upgrade/map.rs | 12 +- core/src/upgrade/mod.rs | 2 - core/src/upgrade/plaintext.rs | 9 +- core/src/upgrade/toggleable.rs | 10 +- core/src/upgrade/traits.rs | 7 +- muxers/mplex/src/lib.rs | 9 +- muxers/mplex/tests/two_peers.rs | 10 +- muxers/yamux/src/lib.rs | 11 +- protocols/floodsub/src/lib.rs | 19 +- protocols/identify/Cargo.toml | 2 + protocols/identify/src/lib.rs | 6 +- protocols/identify/src/protocol.rs | 31 +- protocols/kad/src/kad_server.rs | 15 +- protocols/kad/src/protocol.rs | 13 +- protocols/ping/src/lib.rs | 27 +- protocols/secio/src/lib.rs | 11 +- src/lib.rs | 1 - src/simple.rs | 10 +- transports/dns/src/lib.rs | 8 +- transports/ratelimit/src/lib.rs | 18 +- transports/relay/src/protocol.rs | 37 +- transports/relay/src/transport.rs | 17 +- transports/tcp/src/lib.rs | 83 ++-- transports/timeout/src/lib.rs | 55 +-- transports/uds/src/lib.rs | 17 +- transports/websocket/src/browser.rs | 12 +- transports/websocket/src/desktop.rs | 44 +- 52 files changed, 850 insertions(+), 1493 deletions(-) rename core/src/nodes/{swarm.rs => raw_swarm.rs} (66%) diff --git a/core/src/either.rs b/core/src/either.rs index 30a8b18df49..0566dbd36d9 100644 --- a/core/src/either.rs +++ b/core/src/either.rs @@ -18,10 +18,11 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use futures::{prelude::*, future}; +use futures::prelude::*; use muxing::{Shutdown, StreamMuxer}; use std::io::{Error as IoError, Read, Write}; use tokio_io::{AsyncRead, AsyncWrite}; +use Multiaddr; /// Implements `AsyncRead` and `AsyncWrite` and dispatches all method calls to /// either `First` or `Second`. @@ -39,8 +40,8 @@ where #[inline] unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { match self { - &EitherOutput::First(ref a) => a.prepare_uninitialized_buffer(buf), - &EitherOutput::Second(ref b) => b.prepare_uninitialized_buffer(buf), + EitherOutput::First(a) => a.prepare_uninitialized_buffer(buf), + EitherOutput::Second(b) => b.prepare_uninitialized_buffer(buf), } } } @@ -53,8 +54,8 @@ where #[inline] fn read(&mut self, buf: &mut [u8]) -> Result { match self { - &mut EitherOutput::First(ref mut a) => a.read(buf), - &mut EitherOutput::Second(ref mut b) => b.read(buf), + EitherOutput::First(a) => a.read(buf), + EitherOutput::Second(b) => b.read(buf), } } } @@ -67,8 +68,8 @@ where #[inline] fn shutdown(&mut self) -> Poll<(), IoError> { match self { - &mut EitherOutput::First(ref mut a) => a.shutdown(), - &mut EitherOutput::Second(ref mut b) => b.shutdown(), + EitherOutput::First(a) => a.shutdown(), + EitherOutput::Second(b) => b.shutdown(), } } } @@ -81,16 +82,16 @@ where #[inline] fn write(&mut self, buf: &[u8]) -> Result { match self { - &mut EitherOutput::First(ref mut a) => a.write(buf), - &mut EitherOutput::Second(ref mut b) => b.write(buf), + EitherOutput::First(a) => a.write(buf), + EitherOutput::Second(b) => b.write(buf), } } #[inline] fn flush(&mut self) -> Result<(), IoError> { match self { - &mut EitherOutput::First(ref mut a) => a.flush(), - &mut EitherOutput::Second(ref mut b) => b.flush(), + EitherOutput::First(a) => a.flush(), + EitherOutput::Second(b) => b.flush(), } } } @@ -104,16 +105,16 @@ where type OutboundSubstream = EitherOutbound; fn poll_inbound(&self) -> Poll, IoError> { - match *self { - EitherOutput::First(ref inner) => inner.poll_inbound().map(|p| p.map(|o| o.map(EitherOutput::First))), - EitherOutput::Second(ref inner) => inner.poll_inbound().map(|p| p.map(|o| o.map(EitherOutput::Second))), + match self { + EitherOutput::First(inner) => inner.poll_inbound().map(|p| p.map(|o| o.map(EitherOutput::First))), + EitherOutput::Second(inner) => inner.poll_inbound().map(|p| p.map(|o| o.map(EitherOutput::Second))), } } fn open_outbound(&self) -> Self::OutboundSubstream { - match *self { - EitherOutput::First(ref inner) => EitherOutbound::A(inner.open_outbound()), - EitherOutput::Second(ref inner) => EitherOutbound::B(inner.open_outbound()), + match self { + EitherOutput::First(inner) => EitherOutbound::A(inner.open_outbound()), + EitherOutput::Second(inner) => EitherOutbound::B(inner.open_outbound()), } } @@ -130,14 +131,14 @@ where } fn destroy_outbound(&self, substream: Self::OutboundSubstream) { - match *self { - EitherOutput::First(ref inner) => { + match self { + EitherOutput::First(inner) => { match substream { EitherOutbound::A(substream) => inner.destroy_outbound(substream), _ => panic!("Wrong API usage") } }, - EitherOutput::Second(ref inner) => { + EitherOutput::Second(inner) => { match substream { EitherOutbound::B(substream) => inner.destroy_outbound(substream), _ => panic!("Wrong API usage") @@ -195,14 +196,14 @@ where } fn destroy_substream(&self, substream: Self::Substream) { - match *self { - EitherOutput::First(ref inner) => { + match self { + EitherOutput::First(inner) => { match substream { EitherOutput::First(substream) => inner.destroy_substream(substream), _ => panic!("Wrong API usage") } }, - EitherOutput::Second(ref inner) => { + EitherOutput::Second(inner) => { match substream { EitherOutput::Second(substream) => inner.destroy_substream(substream), _ => panic!("Wrong API usage") @@ -212,16 +213,16 @@ where } fn shutdown(&self, kind: Shutdown) -> Poll<(), IoError> { - match *self { - EitherOutput::First(ref inner) => inner.shutdown(kind), - EitherOutput::Second(ref inner) => inner.shutdown(kind) + match self { + EitherOutput::First(inner) => inner.shutdown(kind), + EitherOutput::Second(inner) => inner.shutdown(kind) } } fn flush_all(&self) -> Poll<(), IoError> { - match *self { - EitherOutput::First(ref inner) => inner.flush_all(), - EitherOutput::Second(ref inner) => inner.flush_all() + match self { + EitherOutput::First(inner) => inner.flush_all(), + EitherOutput::Second(inner) => inner.flush_all() } } } @@ -243,52 +244,44 @@ pub enum EitherListenStream { impl Stream for EitherListenStream where - AStream: Stream, - BStream: Stream, + AStream: Stream, + BStream: Stream, { - type Item = EitherListenUpgrade; + type Item = (EitherFuture, Multiaddr); type Error = IoError; #[inline] fn poll(&mut self) -> Poll, Self::Error> { match self { - &mut EitherListenStream::First(ref mut a) => a.poll() - .map(|i| i.map(|v| v.map(EitherListenUpgrade::First))), - &mut EitherListenStream::Second(ref mut a) => a.poll() - .map(|i| i.map(|v| v.map(EitherListenUpgrade::Second))), + EitherListenStream::First(a) => a.poll() + .map(|i| (i.map(|v| (v.map(|(o, addr)| (EitherFuture::First(o), addr)))))), + EitherListenStream::Second(a) => a.poll() + .map(|i| (i.map(|v| (v.map(|(o, addr)| (EitherFuture::Second(o), addr)))))), } } } -// TODO: This type is needed because of the lack of `impl Trait` in stable Rust. -// If Rust had impl Trait we could use the Either enum from the futures crate and add some -// modifiers to it. This custom enum is a combination of Either and these modifiers. +/// Implements `Future` and dispatches all method calls to either `First` or `Second`. #[derive(Debug, Copy, Clone)] #[must_use = "futures do nothing unless polled"] -pub enum EitherListenUpgrade { +pub enum EitherFuture { First(A), Second(B), } -impl Future for EitherListenUpgrade +impl Future for EitherFuture where - A: Future, - B: Future, + AFuture: Future, + BFuture: Future, { - type Item = (EitherOutput, future::Either); + type Item = EitherOutput; type Error = IoError; #[inline] fn poll(&mut self) -> Poll { match self { - &mut EitherListenUpgrade::First(ref mut a) => { - let (item, addr) = try_ready!(a.poll()); - Ok(Async::Ready((EitherOutput::First(item), future::Either::A(addr)))) - } - &mut EitherListenUpgrade::Second(ref mut b) => { - let (item, addr) = try_ready!(b.poll()); - Ok(Async::Ready((EitherOutput::Second(item), future::Either::B(addr)))) - } + EitherFuture::First(a) => a.poll().map(|v| v.map(EitherOutput::First)), + EitherFuture::Second(a) => a.poll().map(|v| v.map(EitherOutput::Second)), } } } diff --git a/core/src/lib.rs b/core/src/lib.rs index 00292c3ab4a..798405bba50 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -142,7 +142,7 @@ //! // TODO: right now the only available protocol is ping, but we want to replace it with //! // something that is more simple to use //! .dial("127.0.0.1:12345".parse::().unwrap()).unwrap_or_else(|_| panic!()) -//! .and_then(|(out, _)| { +//! .and_then(|out| { //! match out { //! PingOutput::Ponger(processing) => Box::new(processing) as Box>, //! PingOutput::Pinger(mut pinger) => { @@ -220,5 +220,5 @@ pub use self::multiaddr::Multiaddr; pub use self::muxing::StreamMuxer; pub use self::peer_id::PeerId; pub use self::public_key::PublicKey; -pub use self::transport::{MuxedTransport, Transport}; +pub use self::transport::Transport; pub use self::upgrade::{ConnectionUpgrade, Endpoint}; diff --git a/core/src/nodes/collection.rs b/core/src/nodes/collection.rs index 90384314fa3..fc17f43aaf8 100644 --- a/core/src/nodes/collection.rs +++ b/core/src/nodes/collection.rs @@ -25,16 +25,15 @@ use nodes::node::Substream; use nodes::handled_node_tasks::{HandledNodesEvent, HandledNodesTasks}; use nodes::handled_node_tasks::{Task as HandledNodesTask, TaskId}; use nodes::handled_node::NodeHandler; -use std::{collections::hash_map::Entry, fmt, mem}; -use std::io::{Error as IoError, ErrorKind as IoErrorKind}; -use {Multiaddr, PeerId}; +use std::{collections::hash_map::Entry, fmt, io, mem}; +use PeerId; // TODO: make generic over PeerId /// Implementation of `Stream` that handles a collection of nodes. -pub struct CollectionStream { +pub struct CollectionStream { /// Object that handles the tasks. - inner: HandledNodesTasks, + inner: HandledNodesTasks, /// List of nodes, with the task id that handles this node. The corresponding entry in `tasks` /// must always be in the `Connected` state. nodes: FnvHashMap, @@ -43,7 +42,7 @@ pub struct CollectionStream { tasks: FnvHashMap, } -impl fmt::Debug for CollectionStream { +impl fmt::Debug for CollectionStream { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { let mut list = f.debug_list(); for (id, task) in &self.tasks { @@ -70,10 +69,10 @@ enum TaskState { } /// Event that can happen on the `CollectionStream`. -pub enum CollectionEvent<'a, TInEvent:'a , TOutEvent: 'a> { +pub enum CollectionEvent<'a, TInEvent:'a , TOutEvent: 'a, THandler: 'a> { /// A connection to a node has succeeded. You must use the provided event in order to accept /// the connection. - NodeReached(CollectionReachEvent<'a, TInEvent, TOutEvent>), + NodeReached(CollectionReachEvent<'a, TInEvent, TOutEvent, THandler>), /// A connection to a node has been closed. /// @@ -85,11 +84,13 @@ pub enum CollectionEvent<'a, TInEvent:'a , TOutEvent: 'a> { }, /// A connection to a node has errored. + /// + /// Can only happen after a node has been successfully reached. NodeError { /// Identifier of the node. peer_id: PeerId, /// The error that happened. - error: IoError, + error: io::Error, }, /// An error happened on the future that was trying to reach a node. @@ -97,7 +98,9 @@ pub enum CollectionEvent<'a, TInEvent:'a , TOutEvent: 'a> { /// Identifier of the reach attempt that failed. id: ReachAttemptId, /// Error that happened on the future. - error: IoError, + error: io::Error, + /// The handler that was passed to `add_reach_attempt`. + handler: THandler, }, /// A node has produced an event. @@ -109,7 +112,7 @@ pub enum CollectionEvent<'a, TInEvent:'a , TOutEvent: 'a> { }, } -impl<'a, TInEvent, TOutEvent> fmt::Debug for CollectionEvent<'a, TInEvent, TOutEvent> +impl<'a, TInEvent, TOutEvent, THandler> fmt::Debug for CollectionEvent<'a, TInEvent, TOutEvent, THandler> where TOutEvent: fmt::Debug { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { @@ -130,7 +133,7 @@ where TOutEvent: fmt::Debug .field("error", error) .finish() }, - CollectionEvent::ReachError { ref id, ref error } => { + CollectionEvent::ReachError { ref id, ref error, .. } => { f.debug_struct("CollectionEvent::ReachError") .field("id", id) .field("error", error) @@ -148,16 +151,16 @@ where TOutEvent: fmt::Debug /// Event that happens when we reach a node. #[must_use = "The node reached event is used to accept the newly-opened connection"] -pub struct CollectionReachEvent<'a, TInEvent: 'a, TOutEvent: 'a> { +pub struct CollectionReachEvent<'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a> { /// Peer id we connected to. peer_id: PeerId, /// The task id that reached the node. id: TaskId, /// The `CollectionStream` we are referencing. - parent: &'a mut CollectionStream, + parent: &'a mut CollectionStream, } -impl<'a, TInEvent, TOutEvent> CollectionReachEvent<'a, TInEvent, TOutEvent> { +impl<'a, TInEvent, TOutEvent, THandler> CollectionReachEvent<'a, TInEvent, TOutEvent, THandler> { /// Returns the peer id the node that has been reached. #[inline] pub fn peer_id(&self) -> &PeerId { @@ -220,7 +223,7 @@ impl<'a, TInEvent, TOutEvent> CollectionReachEvent<'a, TInEvent, TOutEvent> { } } -impl<'a, TInEvent, TOutEvent> fmt::Debug for CollectionReachEvent<'a, TInEvent, TOutEvent> { +impl<'a, TInEvent, TOutEvent, THandler> fmt::Debug for CollectionReachEvent<'a, TInEvent, TOutEvent, THandler> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.debug_struct("CollectionReachEvent") .field("peer_id", &self.peer_id) @@ -229,7 +232,7 @@ impl<'a, TInEvent, TOutEvent> fmt::Debug for CollectionReachEvent<'a, TInEvent, } } -impl<'a, TInEvent, TOutEvent> Drop for CollectionReachEvent<'a, TInEvent, TOutEvent> { +impl<'a, TInEvent, TOutEvent, THandler> Drop for CollectionReachEvent<'a, TInEvent, TOutEvent, THandler> { fn drop(&mut self) { let task_state = self.parent.tasks.remove(&self.id); debug_assert!(if let Some(TaskState::Pending) = task_state { true } else { false }); @@ -255,7 +258,7 @@ pub enum CollectionNodeAccept { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct ReachAttemptId(TaskId); -impl CollectionStream { +impl CollectionStream { /// Creates a new empty collection. #[inline] pub fn new() -> Self { @@ -270,12 +273,11 @@ impl CollectionStream { /// /// This method spawns a task dedicated to resolving this future and processing the node's /// events. - pub fn add_reach_attempt(&mut self, future: TFut, handler: THandler) + pub fn add_reach_attempt(&mut self, future: TFut, handler: THandler) -> ReachAttemptId where - TFut: Future + Send + 'static, - TAddrFut: Future + Send + 'static, - THandler: NodeHandler, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, + TFut: Future + Send + 'static, + THandler: NodeHandler, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, TInEvent: Send + 'static, TOutEvent: Send + 'static, THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be required? @@ -362,44 +364,44 @@ impl CollectionStream { /// > **Note**: we use a regular `poll` method instead of implementing `Stream` in order to /// > remove the `Err` variant, but also because we want the `CollectionStream` to stay /// > borrowed if necessary. - pub fn poll(&mut self) -> Async>> { + pub fn poll(&mut self) -> Async> { let item = match self.inner.poll() { Async::Ready(item) => item, Async::NotReady => return Async::NotReady, }; match item { - Some(HandledNodesEvent::TaskClosed { id, result }) => { - match (self.tasks.remove(&id), result) { - (Some(TaskState::Pending), Err(err)) => { - Async::Ready(Some(CollectionEvent::ReachError { + HandledNodesEvent::TaskClosed { id, result, handler } => { + match (self.tasks.remove(&id), result, handler) { + (Some(TaskState::Pending), Err(err), Some(handler)) => { + Async::Ready(CollectionEvent::ReachError { id: ReachAttemptId(id), error: err, - })) + handler, + }) }, - (Some(TaskState::Pending), Ok(())) => { + (Some(TaskState::Pending), _, _) => { // TODO: this variant shouldn't happen ; prove this - Async::Ready(Some(CollectionEvent::ReachError { - id: ReachAttemptId(id), - error: IoError::new(IoErrorKind::Other, "couldn't reach the node"), - })) + panic!() }, - (Some(TaskState::Connected(peer_id)), Ok(())) => { + (Some(TaskState::Connected(peer_id)), Ok(()), _handler) => { + debug_assert!(_handler.is_none()); let _node_task_id = self.nodes.remove(&peer_id); debug_assert_eq!(_node_task_id, Some(id)); - Async::Ready(Some(CollectionEvent::NodeClosed { + Async::Ready(CollectionEvent::NodeClosed { peer_id, - })) + }) }, - (Some(TaskState::Connected(peer_id)), Err(err)) => { + (Some(TaskState::Connected(peer_id)), Err(err), _handler) => { + debug_assert!(_handler.is_none()); let _node_task_id = self.nodes.remove(&peer_id); debug_assert_eq!(_node_task_id, Some(id)); - Async::Ready(Some(CollectionEvent::NodeError { + Async::Ready(CollectionEvent::NodeError { peer_id, error: err, - })) + }) }, - (None, _) => { + (None, _, _) => { panic!("self.tasks is always kept in sync with the tasks in self.inner ; \ when we add a task in self.inner we add a corresponding entry in \ self.tasks, and remove the entry only when the task is closed ; \ @@ -407,14 +409,14 @@ impl CollectionStream { }, } }, - Some(HandledNodesEvent::NodeReached { id, peer_id }) => { - Async::Ready(Some(CollectionEvent::NodeReached(CollectionReachEvent { + HandledNodesEvent::NodeReached { id, peer_id } => { + Async::Ready(CollectionEvent::NodeReached(CollectionReachEvent { parent: self, id, peer_id, - }))) + })) }, - Some(HandledNodesEvent::NodeEvent { id, event }) => { + HandledNodesEvent::NodeEvent { id, event } => { let peer_id = match self.tasks.get(&id) { Some(TaskState::Connected(peer_id)) => peer_id.clone(), _ => panic!("we can only receive NodeEvent events from a task after we \ @@ -423,12 +425,11 @@ impl CollectionStream { self.tasks is switched to the Connected state ; qed"), }; - Async::Ready(Some(CollectionEvent::NodeEvent { + Async::Ready(CollectionEvent::NodeEvent { peer_id, event, - })) + }) } - None => Async::Ready(None), } } } diff --git a/core/src/nodes/handled_node.rs b/core/src/nodes/handled_node.rs index 456d782718d..cc638ab6f26 100644 --- a/core/src/nodes/handled_node.rs +++ b/core/src/nodes/handled_node.rs @@ -22,20 +22,18 @@ use muxing::StreamMuxer; use nodes::node::{NodeEvent, NodeStream, Substream}; use futures::{prelude::*, stream::Fuse}; use std::io::Error as IoError; -use Multiaddr; /// Handler for the substreams of a node. -/// -/// > Note: When implementing the various methods, don't forget that you have to register the -/// > task that was the latest to poll and notify it. // TODO: right now it is possible for a node handler to be built, then shut down right after if we // realize we dialed the wrong peer for example ; this could be surprising and should either // be documented or changed (favouring the "documented" right now) -pub trait NodeHandler { +pub trait NodeHandler { /// Custom event that can be received from the outside. type InEvent; /// Custom event that can be produced by the handler and that will be returned by the swarm. type OutEvent; + /// The type of the substream containing the data. + type Substream; /// Information about a substream. Can be sent to the handler through a `NodeHandlerEndpoint`, /// and will be passed back in `inject_substream` or `inject_outbound_closed`. type OutboundOpenInfo; @@ -43,7 +41,7 @@ pub trait NodeHandler { /// Sends a new substream to the handler. /// /// The handler is responsible for upgrading the substream to whatever protocol it wants. - fn inject_substream(&mut self, substream: TSubstream, endpoint: NodeHandlerEndpoint); + fn inject_substream(&mut self, substream: Self::Substream, endpoint: NodeHandlerEndpoint); /// Indicates to the handler that the inbound part of the muxer has been closed, and that /// therefore no more inbound substream will be produced. @@ -53,9 +51,6 @@ pub trait NodeHandler { /// part of the muxer has been closed. fn inject_outbound_closed(&mut self, user_data: Self::OutboundOpenInfo); - /// Indicates to the handler that the multiaddr future has resolved. - fn inject_multiaddr(&mut self, multiaddr: Result); - /// Injects an event coming from the outside into the handler. fn inject_event(&mut self, event: Self::InEvent); @@ -78,6 +73,26 @@ pub enum NodeHandlerEndpoint { Listener, } +impl NodeHandlerEndpoint { + /// Returns true for `Dialer`. + #[inline] + pub fn is_dialer(&self) -> bool { + match self { + NodeHandlerEndpoint::Dialer(_) => true, + NodeHandlerEndpoint::Listener => false, + } + } + + /// Returns true for `Listener`. + #[inline] + pub fn is_listener(&self) -> bool { + match self { + NodeHandlerEndpoint::Dialer(_) => false, + NodeHandlerEndpoint::Listener => true, + } + } +} + /// Event produced by a handler. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum NodeHandlerEvent { @@ -119,30 +134,29 @@ impl NodeHandlerEvent { /// A node combined with an implementation of `NodeHandler`. // TODO: impl Debug -pub struct HandledNode +pub struct HandledNode where TMuxer: StreamMuxer, - THandler: NodeHandler>, + THandler: NodeHandler>, { /// Node that handles the muxing. - node: Fuse>, + node: Fuse>, /// Handler that processes substreams. handler: THandler, // True, if the node is shutting down. is_shutting_down: bool } -impl HandledNode +impl HandledNode where TMuxer: StreamMuxer, - THandler: NodeHandler>, - TAddrFut: Future, + THandler: NodeHandler>, { /// Builds a new `HandledNode`. #[inline] - pub fn new(muxer: TMuxer, multiaddr_future: TAddrFut, handler: THandler) -> Self { + pub fn new(muxer: TMuxer, handler: THandler) -> Self { HandledNode { - node: NodeStream::new(muxer, multiaddr_future).fuse(), + node: NodeStream::new(muxer).fuse(), handler, is_shutting_down: false } @@ -192,11 +206,10 @@ where } } -impl Stream for HandledNode +impl Stream for HandledNode where TMuxer: StreamMuxer, - THandler: NodeHandler>, - TAddrFut: Future, + THandler: NodeHandler>, { type Item = THandler::OutEvent; type Error = IoError; @@ -220,9 +233,6 @@ where self.handler.shutdown() } } - Async::Ready(Some(NodeEvent::Multiaddr(result))) => { - self.handler.inject_multiaddr(result) - } Async::Ready(Some(NodeEvent::OutboundClosed { user_data })) => { self.handler.inject_outbound_closed(user_data) } @@ -263,8 +273,8 @@ where #[cfg(test)] mod tests { use super::*; - use futures::future; use muxing::{StreamMuxer, Shutdown}; + use std::marker::PhantomData; use tokio::runtime::current_thread; // TODO: move somewhere? this could be useful as a dummy @@ -288,15 +298,17 @@ mod tests { #[test] fn proper_shutdown() { // Test that `shutdown()` is properly called on the handler once a node stops. - struct Handler { + struct Handler { did_substream_attempt: bool, inbound_closed: bool, substream_attempt_cancelled: bool, shutdown_called: bool, + marker: PhantomData, }; - impl NodeHandler for Handler { + impl NodeHandler for Handler { type InEvent = (); type OutEvent = (); + type Substream = T; type OutboundOpenInfo = (); fn inject_substream(&mut self, _: T, _: NodeHandlerEndpoint<()>) { panic!() } fn inject_inbound_closed(&mut self) { @@ -307,7 +319,6 @@ mod tests { assert!(!self.substream_attempt_cancelled); self.substream_attempt_cancelled = true; } - fn inject_multiaddr(&mut self, _: Result) {} fn inject_event(&mut self, _: Self::InEvent) { panic!() } fn shutdown(&mut self) { assert!(self.inbound_closed); @@ -325,17 +336,18 @@ mod tests { } } } - impl Drop for Handler { + impl Drop for Handler { fn drop(&mut self) { assert!(self.shutdown_called); } } - let handled = HandledNode::new(InstaCloseMuxer, future::empty(), Handler { + let handled = HandledNode::new(InstaCloseMuxer, Handler { did_substream_attempt: false, inbound_closed: false, substream_attempt_cancelled: false, shutdown_called: false, + marker: PhantomData, }); current_thread::Runtime::new().unwrap().block_on(handled.for_each(|_| Ok(()))).unwrap(); diff --git a/core/src/nodes/handled_node_tasks.rs b/core/src/nodes/handled_node_tasks.rs index 55457205b84..611330d2857 100644 --- a/core/src/nodes/handled_node_tasks.rs +++ b/core/src/nodes/handled_node_tasks.rs @@ -29,7 +29,7 @@ use std::io::Error as IoError; use std::{fmt, mem}; use tokio_executor; use void::Void; -use {Multiaddr, PeerId}; +use PeerId; // TODO: make generic over PeerId @@ -51,7 +51,7 @@ use {Multiaddr, PeerId}; /// Implementation of `Stream` that handles a collection of nodes. // TODO: implement Debug -pub struct HandledNodesTasks { +pub struct HandledNodesTasks { /// For each active task, a sender allowing to transmit messages. Closing the sender interrupts /// the task. It is possible that we receive messages from tasks that used to be in this list /// but no longer are, in which case we should ignore them. @@ -64,12 +64,12 @@ pub struct HandledNodesTasks { to_spawn: SmallVec<[Box + Send>; 8]>, /// Sender to emit events to the outside. Meant to be cloned and sent to tasks. - events_tx: mpsc::UnboundedSender<(InToExtMessage, TaskId)>, + events_tx: mpsc::UnboundedSender<(InToExtMessage, TaskId)>, /// Receiver side for the events. - events_rx: mpsc::UnboundedReceiver<(InToExtMessage, TaskId)>, + events_rx: mpsc::UnboundedReceiver<(InToExtMessage, TaskId)>, } -impl fmt::Debug for HandledNodesTasks { +impl fmt::Debug for HandledNodesTasks { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.debug_list() .entries(self.tasks.keys().cloned()) @@ -79,15 +79,19 @@ impl fmt::Debug for HandledNodesTasks /// Event that can happen on the `HandledNodesTasks`. #[derive(Debug)] -pub enum HandledNodesEvent { +pub enum HandledNodesEvent { /// A task has been closed. /// /// This happens once the node handler closes or an error happens. + // TODO: send back undelivered events? TaskClosed { /// Identifier of the task that closed. id: TaskId, /// What happened. result: Result<(), IoError>, + /// If the task closed before reaching the node, this contains the handler that was passed + /// to `add_reach_attempt`. + handler: Option, }, /// A task has succeesfully connected to a node. @@ -111,7 +115,7 @@ pub enum HandledNodesEvent { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct TaskId(usize); -impl HandledNodesTasks { +impl HandledNodesTasks { /// Creates a new empty collection. #[inline] pub fn new() -> Self { @@ -130,12 +134,11 @@ impl HandledNodesTasks { /// /// This method spawns a task dedicated to resolving this future and processing the node's /// events. - pub fn add_reach_attempt(&mut self, future: TFut, handler: THandler) + pub fn add_reach_attempt(&mut self, future: TFut, handler: THandler) -> TaskId where - TFut: Future + Send + 'static, - TAddrFut: Future + Send + 'static, - THandler: NodeHandler, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, + TFut: Future + Send + 'static, + THandler: NodeHandler, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, TInEvent: Send + 'static, TOutEvent: Send + 'static, THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be required? @@ -193,7 +196,7 @@ impl HandledNodesTasks { } /// Provides an API similar to `Stream`, except that it cannot error. - pub fn poll(&mut self) -> Async>> { + pub fn poll(&mut self) -> Async> { for to_spawn in self.to_spawn.drain() { tokio_executor::spawn(to_spawn); } @@ -210,22 +213,22 @@ impl HandledNodesTasks { match message { InToExtMessage::NodeEvent(event) => { - break Async::Ready(Some(HandledNodesEvent::NodeEvent { + break Async::Ready(HandledNodesEvent::NodeEvent { id: task_id, event, - })); + }); }, InToExtMessage::NodeReached(peer_id) => { - break Async::Ready(Some(HandledNodesEvent::NodeReached { + break Async::Ready(HandledNodesEvent::NodeReached { id: task_id, peer_id, - })); + }); }, - InToExtMessage::TaskClosed(result) => { + InToExtMessage::TaskClosed(result, handler) => { let _ = self.tasks.remove(&task_id); - break Async::Ready(Some(HandledNodesEvent::TaskClosed { - id: task_id, result - })); + break Async::Ready(HandledNodesEvent::TaskClosed { + id: task_id, result, handler + }); }, } } @@ -249,6 +252,7 @@ pub struct Task<'a, TInEvent: 'a> { impl<'a, TInEvent> Task<'a, TInEvent> { /// Sends an event to the given node. + // TODO: report back on delivery #[inline] pub fn send_event(&mut self, event: TInEvent) { // It is possible that the sender is closed if the background task has already finished @@ -279,48 +283,48 @@ impl<'a, TInEvent> fmt::Debug for Task<'a, TInEvent> { } } -impl Stream for HandledNodesTasks { - type Item = HandledNodesEvent; +impl Stream for HandledNodesTasks { + type Item = HandledNodesEvent; type Error = Void; // TODO: use ! once stable #[inline] fn poll(&mut self) -> Poll, Self::Error> { - Ok(self.poll()) + Ok(self.poll().map(Option::Some)) } } /// Message to transmit from a task to the public API. #[derive(Debug)] -enum InToExtMessage { +enum InToExtMessage { /// A connection to a node has succeeded. NodeReached(PeerId), /// The task closed. - TaskClosed(Result<(), IoError>), + TaskClosed(Result<(), IoError>, Option), /// An event from the node. NodeEvent(TOutEvent), } /// Implementation of `Future` that handles a single node, and all the communications between /// the various components of the `HandledNodesTasks`. -struct NodeTask +struct NodeTask where TMuxer: StreamMuxer, - THandler: NodeHandler>, + THandler: NodeHandler>, { /// Sender to transmit events to the outside. - events_tx: mpsc::UnboundedSender<(InToExtMessage, TaskId)>, + events_tx: mpsc::UnboundedSender<(InToExtMessage, TaskId)>, /// Receiving end for events sent from the main `HandledNodesTasks`. in_events_rx: stream::Fuse>, /// Inner state of the `NodeTask`. - inner: NodeTaskInner, + inner: NodeTaskInner, /// Identifier of the attempt. id: TaskId, } -enum NodeTaskInner +enum NodeTaskInner where TMuxer: StreamMuxer, - THandler: NodeHandler>, + THandler: NodeHandler>, { /// Future to resolve to connect to the node. Future { @@ -335,19 +339,18 @@ where }, /// Fully functional node. - Node(HandledNode), + Node(HandledNode), /// A panic happened while polling. Poisoned, } -impl Future for - NodeTask +impl Future for + NodeTask where TMuxer: StreamMuxer, - TFut: Future, - TAddrFut: Future, - THandler: NodeHandler, InEvent = TInEvent, OutEvent = TOutEvent>, + TFut: Future, + THandler: NodeHandler, InEvent = TInEvent, OutEvent = TOutEvent>, { type Item = (); type Error = (); @@ -369,9 +372,9 @@ where // Check whether dialing succeeded. match future.poll() { - Ok(Async::Ready(((peer_id, muxer), addr_fut))) => { + Ok(Async::Ready((peer_id, muxer))) => { let event = InToExtMessage::NodeReached(peer_id); - let mut node = HandledNode::new(muxer, addr_fut, handler); + let mut node = HandledNode::new(muxer, handler); for event in events_buffer { node.inject_event(event); } @@ -386,7 +389,7 @@ where }, Err(err) => { // End the task - let event = InToExtMessage::TaskClosed(Err(err)); + let event = InToExtMessage::TaskClosed(Err(err), Some(handler)); let _ = self.events_tx.unbounded_send((event, self.id)); return Ok(Async::Ready(())); } @@ -427,12 +430,12 @@ where } } Ok(Async::Ready(None)) => { - let event = InToExtMessage::TaskClosed(Ok(())); + let event = InToExtMessage::TaskClosed(Ok(()), None); let _ = self.events_tx.unbounded_send((event, self.id)); return Ok(Async::Ready(())); // End the task. } Err(err) => { - let event = InToExtMessage::TaskClosed(Err(err)); + let event = InToExtMessage::TaskClosed(Err(err), None); let _ = self.events_tx.unbounded_send((event, self.id)); return Ok(Async::Ready(())); // End the task. } diff --git a/core/src/nodes/listeners.rs b/core/src/nodes/listeners.rs index 80ded1f1d86..c47a05ec6f8 100644 --- a/core/src/nodes/listeners.rs +++ b/core/src/nodes/listeners.rs @@ -60,7 +60,7 @@ use {Multiaddr, Transport}; /// ListenersEvent::Closed { listen_addr, listener, result } => { /// println!("Listener {} has been closed: {:?}", listen_addr, result); /// }, -/// ListenersEvent::Incoming { upgrade, listen_addr } => { +/// ListenersEvent::Incoming { upgrade, listen_addr, .. } => { /// println!("A connection has arrived on {}", listen_addr); /// // We don't do anything with the newly-opened connection, but in a real-life /// // program you probably want to use it! @@ -107,6 +107,8 @@ where upgrade: TTrans::ListenerUpgrade, /// Address of the listener which received the connection. listen_addr: Multiaddr, + /// Address used to send back data to the incoming client. + send_back_addr: Multiaddr, }, /// A listener has closed, either gracefully or with an error. @@ -177,7 +179,7 @@ where } /// Provides an API similar to `Stream`, except that it cannot error. - pub fn poll(&mut self) -> Async>> { + pub fn poll(&mut self) -> Async> { // We remove each element from `listeners` one by one and add them back. for n in (0..self.listeners.len()).rev() { let mut listener = self.listeners.swap_remove(n); @@ -185,27 +187,28 @@ where Ok(Async::NotReady) => { self.listeners.push(listener); } - Ok(Async::Ready(Some(upgrade))) => { + Ok(Async::Ready(Some((upgrade, send_back_addr)))) => { let listen_addr = listener.address.clone(); self.listeners.push(listener); - return Async::Ready(Some(ListenersEvent::Incoming { + return Async::Ready(ListenersEvent::Incoming { upgrade, listen_addr, - })); + send_back_addr, + }); } Ok(Async::Ready(None)) => { - return Async::Ready(Some(ListenersEvent::Closed { + return Async::Ready(ListenersEvent::Closed { listen_addr: listener.address, listener: listener.listener, result: Ok(()), - })); + }); } Err(err) => { - return Async::Ready(Some(ListenersEvent::Closed { + return Async::Ready(ListenersEvent::Closed { listen_addr: listener.address, listener: listener.listener, result: Err(err), - })); + }); } } } @@ -224,7 +227,7 @@ where #[inline] fn poll(&mut self) -> Poll, Self::Error> { - Ok(self.poll()) + Ok(self.poll().map(Option::Some)) } } @@ -294,7 +297,7 @@ mod tests { Async::Ready(Some(n)) => { let addr = l.address.clone(); let stream = stream::iter_ok(n..) - .map(move |stream| future::ok( (stream, future::ok(addr.clone())) )); + .map(move |stream| (future::ok(stream), addr.clone())); Box::new(stream) } Async::Ready(None) => { @@ -320,8 +323,9 @@ mod tests { .map_err(|(err, _)| err) .and_then(|(event, _)| { match event { - Some(ListenersEvent::Incoming { listen_addr, upgrade }) => { + Some(ListenersEvent::Incoming { listen_addr, upgrade, send_back_addr }) => { assert_eq!(listen_addr, "/memory".parse().unwrap()); + assert_eq!(send_back_addr, "/memory".parse().unwrap()); upgrade.map(|_| ()).map_err(|_| panic!()) }, _ => panic!() @@ -384,11 +388,11 @@ mod tests { ls.listen_on(addr1).expect("listen_on failed"); ls.listen_on(addr2).expect("listen_on failed"); - assert_matches!(ls.poll(), Async::Ready(Some(listeners_event)) => { - assert_matches!(listeners_event, ListenersEvent::Incoming{mut upgrade, listen_addr} => { + assert_matches!(ls.poll(), Async::Ready(listeners_event) => { + assert_matches!(listeners_event, ListenersEvent::Incoming{mut upgrade, listen_addr, ..} => { assert_eq!(listen_addr.to_string(), "/ip4/127.0.0.2/tcp/4321"); assert_matches!(upgrade.poll().unwrap(), Async::Ready(tup) => { - assert_matches!(tup, (1, _)) + assert_eq!(tup, 1) }); }) }); @@ -407,11 +411,11 @@ mod tests { // Make the second listener return NotReady so we get the first listener next poll() set_listener_state(&mut ls, 1, ListenerState::Ok(Async::NotReady)); - assert_matches!(ls.poll(), Async::Ready(Some(listeners_event)) => { - assert_matches!(listeners_event, ListenersEvent::Incoming{mut upgrade, listen_addr} => { + assert_matches!(ls.poll(), Async::Ready(listeners_event) => { + assert_matches!(listeners_event, ListenersEvent::Incoming{mut upgrade, listen_addr, ..} => { assert_eq!(listen_addr.to_string(), "/ip4/127.0.0.1/tcp/1234"); assert_matches!(upgrade.poll().unwrap(), Async::Ready(tup) => { - assert_matches!(tup, (1, _)) + assert_eq!(tup, 1) }); }) }); @@ -425,7 +429,7 @@ mod tests { let mut ls = ListenersStream::new(t); ls.listen_on(addr).expect("listen_on failed"); set_listener_state(&mut ls, 0, ListenerState::Ok(Async::Ready(None))); - assert_matches!(ls.poll(), Async::Ready(Some(listeners_event)) => { + assert_matches!(ls.poll(), Async::Ready(listeners_event) => { assert_matches!(listeners_event, ListenersEvent::Closed{..}) }); assert_eq!(ls.listeners.len(), 0); // it's gone @@ -439,7 +443,7 @@ mod tests { let mut ls = ListenersStream::new(t); ls.listen_on(addr).expect("listen_on failed"); set_listener_state(&mut ls, 0, ListenerState::Error); // simulate an error on the socket - assert_matches!(ls.poll(), Async::Ready(Some(listeners_event)) => { + assert_matches!(ls.poll(), Async::Ready(listeners_event) => { assert_matches!(listeners_event, ListenersEvent::Closed{..}) }); assert_eq!(ls.listeners.len(), 0); // it's gone @@ -458,14 +462,14 @@ mod tests { // polling processes listeners in reverse order // Only the last listener ever gets processed for _n in 0..10 { - assert_matches!(ls.poll(), Async::Ready(Some(ListenersEvent::Incoming{listen_addr, ..})) => { + assert_matches!(ls.poll(), Async::Ready(ListenersEvent::Incoming{listen_addr, ..}) => { assert_eq!(listen_addr.to_string(), "/ip4/127.0.0.3/tcp/1233") }) } // Make last listener NotReady so now only the third listener is processed set_listener_state(&mut ls, 3, ListenerState::Ok(Async::NotReady)); for _n in 0..10 { - assert_matches!(ls.poll(), Async::Ready(Some(ListenersEvent::Incoming{listen_addr, ..})) => { + assert_matches!(ls.poll(), Async::Ready(ListenersEvent::Incoming{listen_addr, ..}) => { assert_eq!(listen_addr.to_string(), "/ip4/127.0.0.2/tcp/1232") }) } @@ -483,7 +487,7 @@ mod tests { // If the listeners do not yield items continuously (the normal case) we // process them in the expected, reverse, order. for n in (0..4).rev() { - assert_matches!(ls.poll(), Async::Ready(Some(ListenersEvent::Incoming{listen_addr, ..})) => { + assert_matches!(ls.poll(), Async::Ready(ListenersEvent::Incoming{listen_addr, ..}) => { assert_eq!(listen_addr.to_string(), format!("/ip4/127.0.0.{}/tcp/123{}", n, n)); }); // kick the last listener (current) to NotReady state diff --git a/core/src/nodes/mod.rs b/core/src/nodes/mod.rs index bf206e94b75..1d78ea7b3a3 100644 --- a/core/src/nodes/mod.rs +++ b/core/src/nodes/mod.rs @@ -18,10 +18,13 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -mod handled_node_tasks; - pub mod collection; pub mod handled_node; +pub mod handled_node_tasks; pub mod listeners; pub mod node; -pub mod swarm; +pub mod raw_swarm; + +pub use self::node::Substream; +pub use self::handled_node::{NodeHandlerEvent, NodeHandlerEndpoint}; +pub use self::raw_swarm::{ConnectedPoint, Peer, RawSwarm, RawSwarmEvent}; diff --git a/core/src/nodes/node.rs b/core/src/nodes/node.rs index 10c2098b3d1..e072e57d068 100644 --- a/core/src/nodes/node.rs +++ b/core/src/nodes/node.rs @@ -24,16 +24,12 @@ use smallvec::SmallVec; use std::fmt; use std::io::Error as IoError; use std::sync::Arc; -use Multiaddr; // Implementor notes // ================= // // In order to minimize the risk of bugs in higher-level code, we want to avoid as much as // possible having a racy API. The behaviour of methods should be well-defined and predictable. -// As an example, calling the `multiaddr()` method should return `Some` only after a -// `MultiaddrResolved` event has been emitted and never before, even if we technically already -// know the address. // // In order to respect this coding practice, we should theoretically provide events such as "data // incoming on a substream", or "a substream is ready to be written". This would however make the @@ -53,7 +49,7 @@ use Multiaddr; /// /// The stream will close once both the inbound and outbound channels are closed, and no more /// outbound substream attempt is pending. -pub struct NodeStream +pub struct NodeStream where TMuxer: muxing::StreamMuxer, { @@ -63,23 +59,10 @@ where inbound_state: StreamState, /// Tracks the state of the muxers outbound direction. outbound_state: StreamState, - /// Address of the node ; can be empty if the address hasn't been resolved yet. - address: Addr, /// List of substreams we are currently opening. outbound_substreams: SmallVec<[(TUserData, TMuxer::OutboundSubstream); 8]>, } -/// Address of the node. -#[derive(Debug, Clone)] -enum Addr { - /// Future that will resolve the address. - Future(TAddrFut), - /// The address is now known. - Resolved(Multiaddr), - /// An error happened while resolving the future. - Errored, -} - /// A successfully opened substream. pub type Substream = muxing::SubstreamRef>; @@ -102,12 +85,6 @@ pub enum NodeEvent where TMuxer: muxing::StreamMuxer, { - /// The multiaddress future of the node has been resolved. - /// - /// If this succeeded, after this event has been emitted calling `multiaddr()` will return - /// `Some`. - Multiaddr(Result), - /// A new inbound substream arrived. InboundSubstream { /// The newly-opened substream. @@ -137,35 +114,21 @@ where #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct OutboundSubstreamId(usize); -impl NodeStream +impl NodeStream where TMuxer: muxing::StreamMuxer, - TAddrFut: Future, { /// Creates a new node events stream. #[inline] - pub fn new(muxer: TMuxer, multiaddr_future: TAddrFut) -> Self { + pub fn new(muxer: TMuxer) -> Self { NodeStream { muxer: Arc::new(muxer), inbound_state: StreamState::Open, outbound_state: StreamState::Open, - address: Addr::Future(multiaddr_future), outbound_substreams: SmallVec::new(), } } - /// Returns the multiaddress of the node, if already known. - /// - /// This method will always return `None` before a successful `Multiaddr` event has been - /// returned by `poll()`, and will always return `Some` afterwards. - #[inline] - pub fn multiaddr(&self) -> Option<&Multiaddr> { - match self.address { - Addr::Resolved(ref addr) => Some(addr), - Addr::Future(_) | Addr::Errored => None, - } - } - /// Starts the process of opening a new outbound substream. /// /// Returns an error if the outbound side of the muxer is closed. @@ -286,10 +249,9 @@ where } } -impl Stream for NodeStream +impl Stream for NodeStream where TMuxer: muxing::StreamMuxer, - TAddrFut: Future, { type Item = NodeEvent; type Error = IoError; @@ -345,26 +307,6 @@ where } } - // Check whether the multiaddress is resolved. - { - let poll = match self.address { - Addr::Future(ref mut fut) => Some(fut.poll()), - Addr::Resolved(_) | Addr::Errored => None, - }; - - match poll { - Some(Ok(Async::NotReady)) | None => {} - Some(Ok(Async::Ready(addr))) => { - self.address = Addr::Resolved(addr.clone()); - return Ok(Async::Ready(Some(NodeEvent::Multiaddr(Ok(addr))))); - } - Some(Err(err)) => { - self.address = Addr::Errored; - return Ok(Async::Ready(Some(NodeEvent::Multiaddr(Err(err))))); - } - } - } - // Closing the node if there's no way we can do anything more. if self.inbound_state == StreamState::Closed && self.outbound_state == StreamState::Closed @@ -378,14 +320,12 @@ where } } -impl fmt::Debug for NodeStream +impl fmt::Debug for NodeStream where TMuxer: muxing::StreamMuxer, - TAddrFut: Future, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.debug_struct("NodeStream") - .field("address", &self.multiaddr()) .field("inbound_state", &self.inbound_state) .field("outbound_state", &self.outbound_state) .field("outbound_substreams", &self.outbound_substreams.len()) @@ -393,7 +333,7 @@ where } } -impl Drop for NodeStream +impl Drop for NodeStream where TMuxer: muxing::StreamMuxer, { @@ -436,40 +376,22 @@ where TTrans: Transport, #[cfg(test)] mod node_stream { - use multiaddr::Multiaddr; use super::NodeStream; - use futures::{future::self, prelude::*, Future}; + use futures::prelude::*; use tokio_mock_task::MockTask; use super::NodeEvent; use tests::dummy_muxer::{DummyMuxer, DummyConnectionState}; - use std::io::Error as IoError; - - fn build_node_stream() -> NodeStream, Vec> { - let addr = future::ok("/ip4/127.0.0.1/tcp/1234".parse::().expect("bad maddr")); + fn build_node_stream() -> NodeStream> { let muxer = DummyMuxer::new(); - NodeStream::<_, _, Vec>::new(muxer, addr) - } - - #[test] - fn multiaddr_is_available_once_polled() { - let mut node_stream = build_node_stream(); - assert!(node_stream.multiaddr().is_none()); - match node_stream.poll() { - Ok(Async::Ready(Some(NodeEvent::Multiaddr(Ok(addr))))) => { - assert_eq!(addr.to_string(), "/ip4/127.0.0.1/tcp/1234") - } - _ => panic!("unexpected poll return value" ) - } - assert!(node_stream.multiaddr().is_some()); + NodeStream::<_, Vec>::new(muxer) } #[test] fn can_open_outbound_substreams_until_an_outbound_channel_is_closed() { - let addr = future::ok("/ip4/127.0.0.1/tcp/1234".parse::().expect("bad maddr")); let mut muxer = DummyMuxer::new(); muxer.set_outbound_connection_state(DummyConnectionState::Closed); - let mut ns = NodeStream::<_, _, Vec>::new(muxer, addr); + let mut ns = NodeStream::<_, Vec>::new(muxer); // open first substream works assert!(ns.open_substream(vec![1,2,3]).is_ok()); @@ -498,10 +420,9 @@ mod node_stream { #[test] fn query_inbound_state() { - let addr = future::ok("/ip4/127.0.0.1/tcp/1234".parse::().expect("bad maddr")); let mut muxer = DummyMuxer::new(); muxer.set_inbound_connection_state(DummyConnectionState::Closed); - let mut ns = NodeStream::<_, _, Vec>::new(muxer, addr); + let mut ns = NodeStream::<_, Vec>::new(muxer); assert_matches!(ns.poll(), Ok(Async::Ready(Some(node_event))) => { assert_matches!(node_event, NodeEvent::InboundClosed) @@ -512,10 +433,9 @@ mod node_stream { #[test] fn query_outbound_state() { - let addr = future::ok("/ip4/127.0.0.1/tcp/1234".parse::().expect("bad multiaddr")); let mut muxer = DummyMuxer::new(); muxer.set_outbound_connection_state(DummyConnectionState::Closed); - let mut ns = NodeStream::<_, _, Vec>::new(muxer, addr); + let mut ns = NodeStream::<_, Vec>::new(muxer); assert!(ns.is_outbound_open()); @@ -548,13 +468,12 @@ mod node_stream { let mut task = MockTask::new(); task.enter(|| { // ensure the address never resolves - let addr = future::empty(); let mut muxer = DummyMuxer::new(); // ensure muxer.poll_inbound() returns Async::NotReady muxer.set_inbound_connection_state(DummyConnectionState::Pending); // ensure muxer.poll_outbound() returns Async::NotReady muxer.set_outbound_connection_state(DummyConnectionState::Pending); - let mut ns = NodeStream::<_, _, Vec>::new(muxer, addr); + let mut ns = NodeStream::<_, Vec>::new(muxer); assert_matches!(ns.poll(), Ok(Async::NotReady)); }); @@ -562,13 +481,12 @@ mod node_stream { #[test] fn poll_closes_the_node_stream_when_no_more_work_can_be_done() { - let addr = future::ok("/ip4/127.0.0.1/tcp/1234".parse::().expect("bad multiaddr")); let mut muxer = DummyMuxer::new(); // ensure muxer.poll_inbound() returns Async::Ready(None) muxer.set_inbound_connection_state(DummyConnectionState::Closed); // ensure muxer.poll_outbound() returns Async::Ready(None) muxer.set_outbound_connection_state(DummyConnectionState::Closed); - let mut ns = NodeStream::<_, _, Vec>::new(muxer, addr); + let mut ns = NodeStream::<_, Vec>::new(muxer); ns.open_substream(vec![]).unwrap(); ns.poll().unwrap(); // poll_inbound() ns.poll().unwrap(); // poll_outbound() @@ -577,32 +495,14 @@ mod node_stream { assert_matches!(ns.poll(), Ok(Async::Ready(None))); } - #[test] - fn poll_resolves_the_address() { - let addr = future::ok("/ip4/127.0.0.1/tcp/1234".parse::().expect("bad multiaddr")); - let mut muxer = DummyMuxer::new(); - // ensure muxer.poll_inbound() returns Async::Ready(None) - muxer.set_inbound_connection_state(DummyConnectionState::Closed); - // ensure muxer.poll_outbound() returns Async::Ready(None) - muxer.set_outbound_connection_state(DummyConnectionState::Closed); - let mut ns = NodeStream::<_, _, Vec>::new(muxer, addr); - ns.open_substream(vec![]).unwrap(); - ns.poll().unwrap(); // poll_inbound() - ns.poll().unwrap(); // poll_outbound() - assert_matches!(ns.poll(), Ok(Async::Ready(Some(node_event))) => { - assert_matches!(node_event, NodeEvent::Multiaddr(Ok(_))) - }); - } - #[test] fn poll_sets_up_substreams_yielding_them_in_reverse_order() { - let addr = future::ok("/ip4/127.0.0.1/tcp/1234".parse::().expect("bad multiaddr")); let mut muxer = DummyMuxer::new(); // ensure muxer.poll_inbound() returns Async::Ready(None) muxer.set_inbound_connection_state(DummyConnectionState::Closed); // ensure muxer.poll_outbound() returns Async::Ready(Some(substream)) muxer.set_outbound_connection_state(DummyConnectionState::Opened); - let mut ns = NodeStream::<_, _, Vec>::new(muxer, addr); + let mut ns = NodeStream::<_, Vec>::new(muxer); ns.open_substream(vec![1]).unwrap(); ns.open_substream(vec![2]).unwrap(); ns.poll().unwrap(); // poll_inbound() @@ -623,13 +523,12 @@ mod node_stream { #[test] fn poll_keeps_outbound_substreams_when_the_outgoing_connection_is_not_ready() { - let addr = future::ok("/ip4/127.0.0.1/tcp/1234".parse::().expect("bad multiaddr")); let mut muxer = DummyMuxer::new(); // ensure muxer.poll_inbound() returns Async::Ready(None) muxer.set_inbound_connection_state(DummyConnectionState::Closed); // ensure muxer.poll_outbound() returns Async::NotReady muxer.set_outbound_connection_state(DummyConnectionState::Pending); - let mut ns = NodeStream::<_, _, Vec>::new(muxer, addr); + let mut ns = NodeStream::<_, Vec>::new(muxer); ns.open_substream(vec![1]).unwrap(); ns.poll().unwrap(); // poll past inbound ns.poll().unwrap(); // poll outbound @@ -639,11 +538,10 @@ mod node_stream { #[test] fn poll_returns_incoming_substream() { - let addr = future::ok("/ip4/127.0.0.1/tcp/1234".parse::().expect("bad multiaddr")); let mut muxer = DummyMuxer::new(); // ensure muxer.poll_inbound() returns Async::Ready(Some(subs)) muxer.set_inbound_connection_state(DummyConnectionState::Opened); - let mut ns = NodeStream::<_, _, Vec>::new(muxer, addr); + let mut ns = NodeStream::<_, Vec>::new(muxer); assert_matches!(ns.poll(), Ok(Async::Ready(Some(node_event))) => { assert_matches!(node_event, NodeEvent::InboundSubstream{ substream: _ }); }); diff --git a/core/src/nodes/swarm.rs b/core/src/nodes/raw_swarm.rs similarity index 66% rename from core/src/nodes/swarm.rs rename to core/src/nodes/raw_swarm.rs index 97e96250bad..e1b8ed2b301 100644 --- a/core/src/nodes/swarm.rs +++ b/core/src/nodes/raw_swarm.rs @@ -29,11 +29,10 @@ use nodes::listeners::{ListenersEvent, ListenersStream}; use nodes::node::Substream; use std::collections::hash_map::{Entry, OccupiedEntry}; use std::io::{Error as IoError, ErrorKind as IoErrorKind}; -use void::Void; use {Endpoint, Multiaddr, PeerId, Transport}; /// Implementation of `Stream` that handles the nodes. -pub struct Swarm +pub struct RawSwarm where TTrans: Transport, { @@ -41,14 +40,11 @@ where listeners: ListenersStream, /// The nodes currently active. - active_nodes: CollectionStream, + active_nodes: CollectionStream, /// The reach attempts of the swarm. /// This needs to be a separate struct in order to handle multiple mutable borrows issues. reach_attempts: ReachAttempts, - - /// Object that builds new handlers. - handler_build: THandlerBuild, } struct ReachAttempts { @@ -59,8 +55,8 @@ struct ReachAttempts { /// the peer ID. other_reach_attempts: Vec<(ReachAttemptId, ConnectedPoint)>, - /// For each peer ID we're connected to, contains the multiaddress we're connected to. - connected_multiaddresses: FnvHashMap, + /// For each peer ID we're connected to, contains the endpoint we're connected to. + connected_points: FnvHashMap, } /// Attempt to reach a peer. @@ -74,8 +70,8 @@ struct OutReachAttempt { next_attempts: Vec, } -/// Event that can happen on the `Swarm`. -pub enum SwarmEvent +/// Event that can happen on the `RawSwarm`. +pub enum RawSwarmEvent<'a, TTrans: 'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a> where TTrans: Transport, { @@ -90,15 +86,17 @@ where }, /// A new connection arrived on a listener. - IncomingConnection { - /// Address of the listener which received the connection. - listen_addr: Multiaddr, - }, + IncomingConnection(IncomingConnectionEvent<'a, TTrans, TInEvent, TOutEvent, THandler>), - /// An error happened when negotiating a new connection. + /// A new connection was arriving on a listener, but an error happened when negotiating it. + /// + /// This can include, for example, an error during the handshake of the encryption layer, or + /// the connection unexpectedly closed. IncomingConnectionError { /// Address of the listener which received the connection. listen_addr: Multiaddr, + /// Address used to send back data to the remote. + send_back_addr: Multiaddr, /// The error that happened. error: IoError, }, @@ -116,8 +114,8 @@ where Replaced { /// Id of the peer. peer_id: PeerId, - /// Multiaddr we were connected to, or `None` if it was unknown. - closed_multiaddr: Option, + /// Endpoint we were connected to. + closed_endpoint: ConnectedPoint, /// If `Listener`, then we received the connection. If `Dial`, then it's a connection that /// we opened. endpoint: ConnectedPoint, @@ -130,16 +128,16 @@ where NodeClosed { /// Identifier of the node. peer_id: PeerId, - /// Address we were connected to. `None` if not known. - address: Option, + /// Endpoint we were connected to. + endpoint: ConnectedPoint, }, /// The muxer of a node has produced an error. NodeError { /// Identifier of the node. peer_id: PeerId, - /// Address we were connected to. `None` if not known. - address: Option, + /// Endpoint we were connected to. + endpoint: ConnectedPoint, /// The error that happened. error: IoError, }, @@ -165,26 +163,12 @@ where UnknownPeerDialError { /// The multiaddr we failed to reach. multiaddr: Multiaddr, + /// The error that happened. error: IoError, - }, - /// When dialing a peer, we successfully connected to a remote whose peer id doesn't match - /// what we expected. - PublicKeyMismatch { - /// Id of the peer we were expecting. - expected_peer_id: PeerId, - - /// Id of the peer we actually obtained. - actual_peer_id: PeerId, - - /// The multiaddr we failed to reach. - multiaddr: Multiaddr, - - /// Returns the number of multiaddresses that still need to be attempted in order to reach - /// `expected_peer_id`. If this is non-zero, then there's still a chance we can connect to - /// this node. If this is zero, then we have definitely failed. - remain_addrs_attempt: usize, + /// The handler that was passed to `dial()`. + handler: THandler, }, /// A node produced a custom event. @@ -196,7 +180,82 @@ where }, } +/// A new connection arrived on a listener. +pub struct IncomingConnectionEvent<'a, TTrans: 'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a> +where TTrans: Transport +{ + /// The produced upgrade. + upgrade: TTrans::ListenerUpgrade, + /// Address of the listener which received the connection. + listen_addr: Multiaddr, + /// Address used to send back data to the remote. + send_back_addr: Multiaddr, + /// Reference to the `active_nodes` field of the swarm. + active_nodes: &'a mut CollectionStream, + /// Reference to the `other_reach_attempts` field of the swarm. + other_reach_attempts: &'a mut Vec<(ReachAttemptId, ConnectedPoint)>, +} + +impl<'a, TTrans, TInEvent, TOutEvent, TMuxer, THandler> IncomingConnectionEvent<'a, TTrans, TInEvent, TOutEvent, THandler> +where + TTrans: Transport + Clone, + TTrans::Dial: Send + 'static, + TTrans::ListenerUpgrade: Send + 'static, + THandler: NodeHandler, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, + THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be necessary + TMuxer: StreamMuxer + Send + Sync + 'static, + TMuxer::OutboundSubstream: Send, + TMuxer::Substream: Send, + TInEvent: Send + 'static, + TOutEvent: Send + 'static, +{ + /// Starts processing the incoming connection and sets the handler to use for it. + #[inline] + pub fn accept(self, handler: THandler) { + self.accept_with_builder(|_| handler) + } + + /// Same as `accept`, but accepts a closure that turns a `ConnectedPoint` into a handler. + pub fn accept_with_builder(self, builder: TBuilder) + where TBuilder: FnOnce(&ConnectedPoint) -> THandler + { + let connected_point = self.to_connected_point(); + let handler = builder(&connected_point); + let id = self.active_nodes.add_reach_attempt(self.upgrade, handler); + self.other_reach_attempts.push(( + id, + connected_point, + )); + } +} + +impl<'a, TTrans, TInEvent, TOutEvent, THandler> IncomingConnectionEvent<'a, TTrans, TInEvent, TOutEvent, THandler> +where TTrans: Transport +{ + /// Address of the listener that received the connection. + #[inline] + pub fn listen_addr(&self) -> &Multiaddr { + &self.listen_addr + } + + /// Address used to send back data to the dialer. + #[inline] + pub fn send_back_addr(&self) -> &Multiaddr { + &self.send_back_addr + } + + /// Builds the `ConnectedPoint` corresponding to the incoming connection. + #[inline] + pub fn to_connected_point(&self) -> ConnectedPoint { + ConnectedPoint::Listener { + listen_addr: self.listen_addr.clone(), + send_back_addr: self.send_back_addr.clone(), + } + } +} + /// How we connected to a node. +// TODO: move definition #[derive(Debug, Clone)] pub enum ConnectedPoint { /// We dialed the node. @@ -208,20 +267,35 @@ pub enum ConnectedPoint { Listener { /// Address of the listener that received the connection. listen_addr: Multiaddr, + /// Stack of protocols used to send back data to the remote. + send_back_addr: Multiaddr, }, } +impl<'a> From<&'a ConnectedPoint> for Endpoint { + #[inline] + fn from(endpoint: &'a ConnectedPoint) -> Endpoint { + endpoint.to_endpoint() + } +} + impl From for Endpoint { #[inline] fn from(endpoint: ConnectedPoint) -> Endpoint { - match endpoint { + endpoint.to_endpoint() + } +} + +impl ConnectedPoint { + /// Turns the `ConnectedPoint` into the corresponding `Endpoint`. + #[inline] + pub fn to_endpoint(&self) -> Endpoint { + match *self { ConnectedPoint::Dialer { .. } => Endpoint::Dialer, ConnectedPoint::Listener { .. } => Endpoint::Listener, } } -} -impl ConnectedPoint { /// Returns true if we are `Dialer`. #[inline] pub fn is_dialer(&self) -> bool { @@ -241,64 +315,26 @@ impl ConnectedPoint { } } -/// Trait for structures that can create new factories. -pub trait HandlerFactory { - /// The generated handler. - type Handler; - - /// Creates a new handler. - fn new_handler(&self) -> Self::Handler; -} - -impl HandlerFactory for T where T: Fn() -> THandler { - type Handler = THandler; - - #[inline] - fn new_handler(&self) -> THandler { - (*self)() - } -} - -impl - Swarm +impl + RawSwarm where TTrans: Transport + Clone, TMuxer: StreamMuxer, - THandlerBuild: HandlerFactory, - THandler: NodeHandler, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, + THandler: NodeHandler, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be necessary { /// Creates a new node events stream. #[inline] - pub fn new(transport: TTrans) -> Swarm THandler> - where THandler: Default, - { - // TODO: with_capacity? - Swarm { - listeners: ListenersStream::new(transport), - active_nodes: CollectionStream::new(), - reach_attempts: ReachAttempts { - out_reach_attempts: Default::default(), - other_reach_attempts: Vec::new(), - connected_multiaddresses: Default::default(), - }, - handler_build: Default::default, - } - } - - /// Same as `new`, but lets you specify a way to build a node handler. - #[inline] - pub fn with_handler_builder(transport: TTrans, handler_build: THandlerBuild) -> Self { + pub fn new(transport: TTrans) -> Self { // TODO: with_capacity? - Swarm { + RawSwarm { listeners: ListenersStream::new(transport), active_nodes: CollectionStream::new(), reach_attempts: ReachAttempts { out_reach_attempts: Default::default(), other_reach_attempts: Vec::new(), - connected_multiaddresses: Default::default(), + connected_points: Default::default(), }, - handler_build, } } @@ -340,11 +376,12 @@ where } /// Dials a multiaddress without knowing the peer ID we're going to obtain. - pub fn dial(&mut self, addr: Multiaddr) -> Result<(), Multiaddr> + /// + /// The second parameter is the handler to use if we manage to reach a node. + pub fn dial(&mut self, addr: Multiaddr, handler: THandler) -> Result<(), Multiaddr> where TTrans: Transport + Clone, TTrans::Dial: Send + 'static, - TTrans::MultiaddrFuture: Send + 'static, TMuxer: StreamMuxer + Send + Sync + 'static, TMuxer::OutboundSubstream: Send, TMuxer::Substream: Send, @@ -356,9 +393,9 @@ where Err((_, addr)) => return Err(addr), }; - let reach_id = self.active_nodes.add_reach_attempt(future, self.handler_build.new_handler()); - self.reach_attempts.other_reach_attempts - .push((reach_id, ConnectedPoint::Dialer { address: addr })); + let connected_point = ConnectedPoint::Dialer { address: addr }; + let reach_id = self.active_nodes.add_reach_attempt(future, handler); + self.reach_attempts.other_reach_attempts.push((reach_id, connected_point)); Ok(()) } @@ -387,7 +424,7 @@ where /// Grants access to a struct that represents a peer. #[inline] - pub fn peer(&mut self, peer_id: PeerId) -> Peer { + pub fn peer(&mut self, peer_id: PeerId) -> Peer { // TODO: we do `peer_mut(...).is_some()` followed with `peer_mut(...).unwrap()`, otherwise // the borrow checker yells at us. @@ -399,12 +436,12 @@ where .peer_mut(&peer_id) .expect("we checked for Some just above"), peer_id, - connected_multiaddresses: &mut self.reach_attempts.connected_multiaddresses, + connected_points: &mut self.reach_attempts.connected_points, }); } if self.reach_attempts.out_reach_attempts.get_mut(&peer_id).is_some() { - debug_assert!(!self.reach_attempts.connected_multiaddresses.contains_key(&peer_id)); + debug_assert!(!self.reach_attempts.connected_points.contains_key(&peer_id)); return Peer::PendingConnect(PeerPendingConnect { attempt: match self.reach_attempts.out_reach_attempts.entry(peer_id.clone()) { Entry::Occupied(e) => e, @@ -414,7 +451,7 @@ where }); } - debug_assert!(!self.reach_attempts.connected_multiaddresses.contains_key(&peer_id)); + debug_assert!(!self.reach_attempts.connected_points.contains_key(&peer_id)); Peer::NotConnected(PeerNotConnected { nodes: self, peer_id, @@ -426,11 +463,11 @@ where /// /// It is a logic error to call this method if we already have an outgoing attempt to the /// given peer. - fn start_dial_out(&mut self, peer_id: PeerId, first: Multiaddr, rest: Vec) + fn start_dial_out(&mut self, peer_id: PeerId, handler: THandler, first: Multiaddr, + rest: Vec) where TTrans: Transport + Clone, TTrans::Dial: Send + 'static, - TTrans::MultiaddrFuture: Send + 'static, TMuxer: StreamMuxer + Send + Sync + 'static, TMuxer::OutboundSubstream: Send, TMuxer::Substream: Send, @@ -438,11 +475,23 @@ where TOutEvent: Send + 'static, { let reach_id = match self.transport().clone().dial(first.clone()) { - Ok(fut) => self.active_nodes.add_reach_attempt(fut, self.handler_build.new_handler()), + Ok(fut) => { + let expected_peer_id = peer_id.clone(); + let fut = fut.and_then(move |(actual_peer_id, muxer)| { + if actual_peer_id == expected_peer_id { + Ok((actual_peer_id, muxer)) + } else { + let msg = format!("public key mismatch ; expected = {:?} ; obtained = {:?}", + expected_peer_id, actual_peer_id); + Err(IoError::new(IoErrorKind::Other, msg)) + } + }); + self.active_nodes.add_reach_attempt(fut, handler) + }, Err((_, addr)) => { let msg = format!("unsupported multiaddr {}", addr); let fut = future::err(IoError::new(IoErrorKind::Other, msg)); - self.active_nodes.add_reach_attempt::<_, _, future::FutureResult, _>(fut, self.handler_build.new_handler()) + self.active_nodes.add_reach_attempt(fut, handler) }, }; @@ -459,51 +508,48 @@ where } /// Provides an API similar to `Stream`, except that it cannot error. - pub fn poll(&mut self) -> Async>> + pub fn poll(&mut self) -> Async> where TTrans: Transport + Clone, TTrans::Dial: Send + 'static, - TTrans::MultiaddrFuture: Future + Send + 'static, TTrans::ListenerUpgrade: Send + 'static, TMuxer: StreamMuxer + Send + Sync + 'static, TMuxer::OutboundSubstream: Send, TMuxer::Substream: Send, TInEvent: Send + 'static, TOutEvent: Send + 'static, - THandlerBuild: HandlerFactory, - THandler: NodeHandler, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, + THandler: NodeHandler, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be necessary { // Start by polling the listeners for events. match self.listeners.poll() { Async::NotReady => (), - Async::Ready(Some(ListenersEvent::Incoming { + Async::Ready(ListenersEvent::Incoming { upgrade, listen_addr, - })) => { - let id = self.active_nodes.add_reach_attempt(upgrade, self.handler_build.new_handler()); - self.reach_attempts.other_reach_attempts.push(( - id, - ConnectedPoint::Listener { - listen_addr: listen_addr.clone(), - }, - )); - return Async::Ready(Some(SwarmEvent::IncomingConnection { + send_back_addr, + }) => { + let event = IncomingConnectionEvent { + upgrade, listen_addr, - })); + send_back_addr, + active_nodes: &mut self.active_nodes, + other_reach_attempts: &mut self.reach_attempts.other_reach_attempts, + }; + + return Async::Ready(RawSwarmEvent::IncomingConnection(event)); } - Async::Ready(Some(ListenersEvent::Closed { + Async::Ready(ListenersEvent::Closed { listen_addr, listener, result, - })) => { - return Async::Ready(Some(SwarmEvent::ListenerClosed { + }) => { + return Async::Ready(RawSwarmEvent::ListenerClosed { listen_addr, listener, result, - })); + }); } - Async::Ready(None) => unreachable!("The listeners stream never finishes"), } // Poll the existing nodes. @@ -511,44 +557,53 @@ where let (action, out_event); match self.active_nodes.poll() { Async::NotReady => break, - Async::Ready(Some(CollectionEvent::NodeReached(reach_event))) => { + Async::Ready(CollectionEvent::NodeReached(reach_event)) => { let (a, e) = handle_node_reached(&mut self.reach_attempts, reach_event); action = a; out_event = e; } - Async::Ready(Some(CollectionEvent::ReachError { id, error })) => { - let (a, e) = handle_reach_error(&mut self.reach_attempts, id, error); + Async::Ready(CollectionEvent::ReachError { id, error, handler }) => { + let (a, e) = handle_reach_error(&mut self.reach_attempts, id, error, handler); action = a; out_event = e; } - Async::Ready(Some(CollectionEvent::NodeError { + Async::Ready(CollectionEvent::NodeError { peer_id, error, - })) => { - let address = self.reach_attempts.connected_multiaddresses.remove(&peer_id); + }) => { + let endpoint = self.reach_attempts.connected_points.remove(&peer_id) + .expect("We insert into connected_points whenever a connection is \ + opened and remove only when a connection is closed ; the \ + underlying API is guaranteed to always deliver a connection \ + closed message after it has been opened, and no two closed \ + messages ; qed"); debug_assert!(!self.reach_attempts.out_reach_attempts.contains_key(&peer_id)); action = Default::default(); - out_event = SwarmEvent::NodeError { + out_event = RawSwarmEvent::NodeError { peer_id, - address, + endpoint, error, }; } - Async::Ready(Some(CollectionEvent::NodeClosed { peer_id })) => { - let address = self.reach_attempts.connected_multiaddresses.remove(&peer_id); + Async::Ready(CollectionEvent::NodeClosed { peer_id }) => { + let endpoint = self.reach_attempts.connected_points.remove(&peer_id) + .expect("We insert into connected_points whenever a connection is \ + opened and remove only when a connection is closed ; the \ + underlying API is guaranteed to always deliver a connection \ + closed message after it has been opened, and no two closed \ + messages ; qed"); debug_assert!(!self.reach_attempts.out_reach_attempts.contains_key(&peer_id)); action = Default::default(); - out_event = SwarmEvent::NodeClosed { peer_id, address }; + out_event = RawSwarmEvent::NodeClosed { peer_id, endpoint }; } - Async::Ready(Some(CollectionEvent::NodeEvent { peer_id, event })) => { + Async::Ready(CollectionEvent::NodeEvent { peer_id, event }) => { action = Default::default(); - out_event = SwarmEvent::NodeEvent { peer_id, event }; + out_event = RawSwarmEvent::NodeEvent { peer_id, event }; } - Async::Ready(None) => unreachable!("CollectionStream never ends"), }; - if let Some((peer_id, first, rest)) = action.start_dial_out { - self.start_dial_out(peer_id, first, rest); + if let Some((peer_id, handler, first, rest)) = action.start_dial_out { + self.start_dial_out(peer_id, handler, first, rest); } if let Some(interrupt) = action.interrupt { @@ -563,7 +618,7 @@ where attempts ; qed"); } - return Async::Ready(Some(out_event)); + return Async::Ready(out_event); } Async::NotReady @@ -571,27 +626,35 @@ where } /// Internal struct indicating an action to perform of the swarm. -#[derive(Debug, Default)] +#[derive(Debug)] #[must_use] -struct ActionItem { - start_dial_out: Option<(PeerId, Multiaddr, Vec)>, +struct ActionItem { + start_dial_out: Option<(PeerId, THandler, Multiaddr, Vec)>, interrupt: Option, } +impl Default for ActionItem { + fn default() -> Self { + ActionItem { + start_dial_out: None, + interrupt: None, + } + } +} + /// Handles a node reached event from the collection. /// /// Returns an event to return from the stream. /// /// > **Note**: The event **must** have been produced by the collection of nodes, otherwise /// > panics will likely happen. -fn handle_node_reached( +fn handle_node_reached<'a, TTrans, TMuxer, TInEvent, TOutEvent, THandler>( reach_attempts: &mut ReachAttempts, - event: CollectionReachEvent -) -> (ActionItem, SwarmEvent) + event: CollectionReachEvent +) -> (ActionItem, RawSwarmEvent<'a, TTrans, TInEvent, TOutEvent, THandler>) where TTrans: Transport + Clone, TTrans::Dial: Send + 'static, - TTrans::MultiaddrFuture: Send + 'static, TMuxer: StreamMuxer + Send + Sync + 'static, TMuxer::OutboundSubstream: Send, TMuxer::Substream: Send, @@ -605,10 +668,11 @@ where .iter() .position(|i| i.0 == event.reach_attempt_id()) { - let (_, endpoint) = reach_attempts.other_reach_attempts.swap_remove(in_pos); + let (_, opened_endpoint) = reach_attempts.other_reach_attempts.swap_remove(in_pos); + + // Set the endpoint for this peer. + let closed_endpoint = reach_attempts.connected_points.insert(event.peer_id().clone(), opened_endpoint.clone()); - // Clear the known multiaddress for this peer. - let closed_multiaddr = reach_attempts.connected_multiaddresses.remove(&event.peer_id()); // Cancel any outgoing attempt to this peer. let action = if let Some(attempt) = reach_attempts.out_reach_attempts.remove(&event.peer_id()) { debug_assert_ne!(attempt.id, event.reach_attempt_id()); @@ -622,13 +686,18 @@ where let (outcome, peer_id) = event.accept(); if outcome == CollectionNodeAccept::ReplacedExisting { - return (action, SwarmEvent::Replaced { + let closed_endpoint = closed_endpoint + .expect("We insert into connected_points whenever a connection is opened and \ + remove only when a connection is closed ; the underlying API is \ + guaranteed to always deliver a connection closed message after it has \ + been opened, and no two closed messages ; qed"); + return (action, RawSwarmEvent::Replaced { peer_id, - endpoint, - closed_multiaddr, + endpoint: opened_endpoint, + closed_endpoint, }); } else { - return (action, SwarmEvent::Connected { peer_id, endpoint }); + return (action, RawSwarmEvent::Connected { peer_id, endpoint: opened_endpoint }); } } @@ -646,60 +715,29 @@ where .expect("is_outgoing_and_ok is true only if reach_attempts.out_reach_attempts.get(event.peer_id()) \ returned Some"); - let closed_multiaddr = reach_attempts.connected_multiaddresses - .insert(event.peer_id().clone(), attempt.cur_attempted.clone()); - let endpoint = ConnectedPoint::Dialer { + let opened_endpoint = ConnectedPoint::Dialer { address: attempt.cur_attempted, }; + let closed_endpoint = reach_attempts.connected_points + .insert(event.peer_id().clone(), opened_endpoint.clone()) + .expect("We insert into connected_points whenever a connection is opened and remove \ + only when a connection is closed ; the underlying API is guaranteed to always \ + deliver a connection closed message after it has been opened, and no two \ + closed messages ; qed"); + let (outcome, peer_id) = event.accept(); if outcome == CollectionNodeAccept::ReplacedExisting { - return (Default::default(), SwarmEvent::Replaced { + return (Default::default(), RawSwarmEvent::Replaced { peer_id, - endpoint, - closed_multiaddr, + endpoint: opened_endpoint, + closed_endpoint, }); } else { - return (Default::default(), SwarmEvent::Connected { peer_id, endpoint }); + return (Default::default(), RawSwarmEvent::Connected { peer_id, endpoint: opened_endpoint }); } } - // If in neither, check outgoing reach attempts again as we may have a public - // key mismatch. - let expected_peer_id = reach_attempts - .out_reach_attempts - .iter() - .find(|(_, a)| a.id == event.reach_attempt_id()) - .map(|(p, _)| p.clone()); - if let Some(expected_peer_id) = expected_peer_id { - debug_assert_ne!(&expected_peer_id, event.peer_id()); - let attempt = reach_attempts.out_reach_attempts.remove(&expected_peer_id) - .expect("expected_peer_id is a key that is grabbed from out_reach_attempts"); - - let num_remain = attempt.next_attempts.len(); - let failed_addr = attempt.cur_attempted.clone(); - - let peer_id = event.deny(); - - let action = if !attempt.next_attempts.is_empty() { - let mut attempt = attempt; - let next = attempt.next_attempts.remove(0); - ActionItem { - start_dial_out: Some((expected_peer_id.clone(), next, attempt.next_attempts)), - .. Default::default() - } - } else { - Default::default() - }; - - return (action, SwarmEvent::PublicKeyMismatch { - remain_addrs_attempt: num_remain, - expected_peer_id, - actual_peer_id: peer_id, - multiaddr: failed_addr, - }); - } - // We didn't find any entry in neither the outgoing connections not ingoing connections. // TODO: improve proof or remove ; this is too complicated right now panic!("The API of collection guarantees that the id sent back in NodeReached (which is where \ @@ -715,11 +753,12 @@ where /// /// > **Note**: The event **must** have been produced by the collection of nodes, otherwise /// > panics will likely happen. -fn handle_reach_error( +fn handle_reach_error<'a, TTrans, TInEvent, TOutEvent, THandler>( reach_attempts: &mut ReachAttempts, reach_id: ReachAttemptId, error: IoError, -) -> (ActionItem, SwarmEvent) + handler: THandler, +) -> (ActionItem, RawSwarmEvent<'a, TTrans, TInEvent, TOutEvent, THandler>) where TTrans: Transport { // Search for the attempt in `out_reach_attempts`. @@ -740,14 +779,14 @@ where TTrans: Transport let mut attempt = attempt; let next_attempt = attempt.next_attempts.remove(0); ActionItem { - start_dial_out: Some((peer_id.clone(), next_attempt, attempt.next_attempts)), + start_dial_out: Some((peer_id.clone(), handler, next_attempt, attempt.next_attempts)), .. Default::default() } } else { Default::default() }; - return (action, SwarmEvent::DialError { + return (action, RawSwarmEvent::DialError { remain_addrs_attempt: num_remain, peer_id, multiaddr: failed_addr, @@ -764,13 +803,14 @@ where TTrans: Transport let (_, endpoint) = reach_attempts.other_reach_attempts.swap_remove(in_pos); match endpoint { ConnectedPoint::Dialer { address } => { - return (Default::default(), SwarmEvent::UnknownPeerDialError { + return (Default::default(), RawSwarmEvent::UnknownPeerDialError { multiaddr: address, error, + handler, }); } - ConnectedPoint::Listener { listen_addr } => { - return (Default::default(), SwarmEvent::IncomingConnectionError { listen_addr, error }); + ConnectedPoint::Listener { listen_addr, send_back_addr } => { + return (Default::default(), RawSwarmEvent::IncomingConnectionError { listen_addr, send_back_addr, error }); } } } @@ -786,7 +826,7 @@ where TTrans: Transport } /// State of a peer in the system. -pub enum Peer<'a, TTrans: 'a, TInEvent: 'a, TOutEvent: 'a, THandlerBuild: 'a> +pub enum Peer<'a, TTrans: 'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a> where TTrans: Transport, { @@ -794,23 +834,22 @@ where Connected(PeerConnected<'a, TInEvent>), /// We are currently attempting to connect to this peer. - PendingConnect(PeerPendingConnect<'a, TInEvent, TOutEvent>), + PendingConnect(PeerPendingConnect<'a, TInEvent, TOutEvent, THandler>), /// We are not connected to this peer at all. /// /// > **Note**: It is however possible that a pending incoming connection is being negotiated /// > and will connect to this peer, but we don't know it yet. - NotConnected(PeerNotConnected<'a, TTrans, TInEvent, TOutEvent, THandlerBuild>), + NotConnected(PeerNotConnected<'a, TTrans, TInEvent, TOutEvent, THandler>), } // TODO: add other similar methods that wrap to the ones of `PeerNotConnected` -impl<'a, TTrans, TMuxer, TInEvent, TOutEvent, THandler, THandlerBuild> - Peer<'a, TTrans, TInEvent, TOutEvent, THandlerBuild> +impl<'a, TTrans, TMuxer, TInEvent, TOutEvent, THandler> + Peer<'a, TTrans, TInEvent, TOutEvent, THandler> where TTrans: Transport, TMuxer: StreamMuxer, - THandlerBuild: HandlerFactory, - THandler: NodeHandler, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, + THandler: NodeHandler, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be necessary { /// If we are connected, returns the `PeerConnected`. @@ -824,7 +863,7 @@ where /// If a connection is pending, returns the `PeerPendingConnect`. #[inline] - pub fn as_pending_connect(self) -> Option> { + pub fn as_pending_connect(self) -> Option> { match self { Peer::PendingConnect(peer) => Some(peer), _ => None, @@ -833,7 +872,7 @@ where /// If we are not connected, returns the `PeerNotConnected`. #[inline] - pub fn as_not_connected(self) -> Option> { + pub fn as_not_connected(self) -> Option> { match self { Peer::NotConnected(peer) => Some(peer), _ => None, @@ -841,36 +880,50 @@ where } /// If we're not connected, opens a new connection to this peer using the given multiaddr. + /// + /// If we reach a peer but the `PeerId` doesn't correspond to the one we're expecting, then + /// the whole connection is immediately closed. + /// + /// > **Note**: It is possible that the attempt reaches a node that doesn't have the peer id + /// > that we are expecting, in which case the handler will be used for this "wrong" + /// > node. #[inline] pub fn or_connect( self, addr: Multiaddr, - ) -> Result, Self> + handler: THandler, + ) -> Result, Self> where TTrans: Transport + Clone, TTrans::Dial: Send + 'static, - TTrans::MultiaddrFuture: Send + 'static, TMuxer: StreamMuxer + Send + Sync + 'static, TMuxer::OutboundSubstream: Send, TMuxer::Substream: Send, TInEvent: Send + 'static, TOutEvent: Send + 'static, { - self.or_connect_with(move |_| addr) + self.or_connect_with(move |_| addr, handler) } /// If we're not connected, calls the function passed as parameter and opens a new connection /// using the returned address. + /// + /// If we reach a peer but the `PeerId` doesn't correspond to the one we're expecting, then + /// the whole connection is immediately closed. + /// + /// > **Note**: It is possible that the attempt reaches a node that doesn't have the peer id + /// > that we are expecting, in which case the handler will be used for this "wrong" + /// > node. #[inline] pub fn or_connect_with( self, addr: TFn, - ) -> Result, Self> + handler: THandler, + ) -> Result, Self> where TFn: FnOnce(&PeerId) -> Multiaddr, TTrans: Transport + Clone, TTrans::Dial: Send + 'static, - TTrans::MultiaddrFuture: Send + 'static, TMuxer: StreamMuxer + Send + Sync + 'static, TMuxer::OutboundSubstream: Send, TMuxer::Substream: Send, @@ -882,7 +935,7 @@ where Peer::PendingConnect(peer) => Ok(PeerPotentialConnect::PendingConnect(peer)), Peer::NotConnected(peer) => { let addr = addr(&peer.peer_id); - match peer.connect(addr) { + match peer.connect(addr, handler) { Ok(peer) => Ok(PeerPotentialConnect::PendingConnect(peer)), Err(peer) => Err(Peer::NotConnected(peer)), } @@ -892,15 +945,15 @@ where } /// Peer we are potentially going to connect to. -pub enum PeerPotentialConnect<'a, TInEvent: 'a, TOutEvent: 'a> { +pub enum PeerPotentialConnect<'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a> { /// We are connected to this peer. Connected(PeerConnected<'a, TInEvent>), /// We are currently attempting to connect to this peer. - PendingConnect(PeerPendingConnect<'a, TInEvent, TOutEvent>), + PendingConnect(PeerPendingConnect<'a, TInEvent, TOutEvent, THandler>), } -impl<'a, TInEvent, TOutEvent> PeerPotentialConnect<'a, TInEvent, TOutEvent> { +impl<'a, TInEvent, TOutEvent, THandler> PeerPotentialConnect<'a, TInEvent, TOutEvent, THandler> { /// Closes the connection or the connection attempt. /// /// If the connection was active, returns the list of outbound substream openings that were @@ -925,7 +978,7 @@ impl<'a, TInEvent, TOutEvent> PeerPotentialConnect<'a, TInEvent, TOutEvent> { /// If a connection is pending, returns the `PeerPendingConnect`. #[inline] - pub fn as_pending_connect(self) -> Option> { + pub fn as_pending_connect(self) -> Option> { match self { PeerPotentialConnect::PendingConnect(peer) => Some(peer), _ => None, @@ -936,8 +989,8 @@ impl<'a, TInEvent, TOutEvent> PeerPotentialConnect<'a, TInEvent, TOutEvent> { /// Access to a peer we are connected to. pub struct PeerConnected<'a, TInEvent: 'a> { peer: CollecPeerMut<'a, TInEvent>, - /// Reference to the `connected_multiaddresses` field of the parent. - connected_multiaddresses: &'a mut FnvHashMap, + /// Reference to the `connected_points` field of the parent. + connected_points: &'a mut FnvHashMap, peer_id: PeerId, } @@ -948,14 +1001,18 @@ impl<'a, TInEvent> PeerConnected<'a, TInEvent> { // TODO: consider returning a `PeerNotConnected` ; however this makes all the borrows things // much more annoying to deal with pub fn close(self) { - self.connected_multiaddresses.remove(&self.peer_id); + self.connected_points.remove(&self.peer_id); self.peer.close() } - /// Returns the outcome of the future that resolves the multiaddress of the peer. + /// Returns the endpoint we're connected to. #[inline] - pub fn multiaddr(&self) -> Option<&Multiaddr> { - self.connected_multiaddresses.get(&self.peer_id) + pub fn endpoint(&self) -> &ConnectedPoint { + self.connected_points.get(&self.peer_id) + .expect("We insert into connected_points whenever a connection is opened and remove \ + only when a connection is closed ; the underlying API is guaranteed to always \ + deliver a connection closed message after it has been opened, and no two \ + closed messages ; qed") } /// Sends an event to the node. @@ -966,12 +1023,12 @@ impl<'a, TInEvent> PeerConnected<'a, TInEvent> { } /// Access to a peer we are attempting to connect to. -pub struct PeerPendingConnect<'a, TInEvent: 'a, TOutEvent: 'a> { +pub struct PeerPendingConnect<'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a> { attempt: OccupiedEntry<'a, PeerId, OutReachAttempt>, - active_nodes: &'a mut CollectionStream, + active_nodes: &'a mut CollectionStream, } -impl<'a, TInEvent, TOutEvent> PeerPendingConnect<'a, TInEvent, TOutEvent> { +impl<'a, TInEvent, TOutEvent, THandler> PeerPendingConnect<'a, TInEvent, TOutEvent, THandler> { /// Interrupt this connection attempt. // TODO: consider returning a PeerNotConnected ; however that is really pain in terms of // borrows @@ -1013,54 +1070,58 @@ impl<'a, TInEvent, TOutEvent> PeerPendingConnect<'a, TInEvent, TOutEvent> { } /// Access to a peer we're not connected to. -pub struct PeerNotConnected<'a, TTrans: 'a, TInEvent: 'a, TOutEvent: 'a, THandlerBuild: 'a> +pub struct PeerNotConnected<'a, TTrans: 'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a> where TTrans: Transport, { peer_id: PeerId, - nodes: &'a mut Swarm, + nodes: &'a mut RawSwarm, } -impl<'a, TTrans, TInEvent, TOutEvent, TMuxer, THandler, THandlerBuild> - PeerNotConnected<'a, TTrans, TInEvent, TOutEvent, THandlerBuild> +impl<'a, TTrans, TInEvent, TOutEvent, TMuxer, THandler> + PeerNotConnected<'a, TTrans, TInEvent, TOutEvent, THandler> where TTrans: Transport, TMuxer: StreamMuxer, - THandlerBuild: HandlerFactory, - THandler: NodeHandler, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, + THandler: NodeHandler, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be necessary { /// Attempts a new connection to this node using the given multiaddress. + /// + /// If we reach a peer but the `PeerId` doesn't correspond to the one we're expecting, then + /// the whole connection is immediately closed. #[inline] - pub fn connect(self, addr: Multiaddr) -> Result, Self> + pub fn connect(self, addr: Multiaddr, handler: THandler) -> Result, Self> where TTrans: Transport + Clone, TTrans::Dial: Send + 'static, - TTrans::MultiaddrFuture: Send + 'static, TMuxer: StreamMuxer + Send + Sync + 'static, TMuxer::OutboundSubstream: Send, TMuxer::Substream: Send, TInEvent: Send + 'static, TOutEvent: Send + 'static, { - self.connect_inner(addr, Vec::new()) + self.connect_inner(handler, addr, Vec::new()) } /// Attempts a new connection to this node using the given multiaddresses. /// - /// The multiaddresses passes as parameter will be tried one by one. + /// The multiaddresses passed as parameter will be tried one by one. /// /// If the iterator is empty, TODO: what to do? at the moment we unwrap + /// + /// If we reach a peer but the `PeerId` doesn't correspond to the one we're expecting, then + /// the whole connection is immediately closed. #[inline] pub fn connect_iter( self, addrs: TIter, - ) -> Result, Self> + handler: THandler, + ) -> Result, Self> where TIter: IntoIterator, TTrans: Transport + Clone, TTrans::Dial: Send + 'static, - TTrans::MultiaddrFuture: Send + 'static, TMuxer: StreamMuxer + Send + Sync + 'static, TMuxer::OutboundSubstream: Send, TMuxer::Substream: Send, @@ -1070,26 +1131,26 @@ where let mut addrs = addrs.into_iter(); let first = addrs.next().unwrap(); // TODO: bad let rest = addrs.collect(); - self.connect_inner(first, rest) + self.connect_inner(handler, first, rest) } /// Inner implementation of `connect`. fn connect_inner( self, + handler: THandler, first: Multiaddr, rest: Vec, - ) -> Result, Self> + ) -> Result, Self> where TTrans: Transport + Clone, TTrans::Dial: Send + 'static, - TTrans::MultiaddrFuture: Send + 'static, TMuxer: StreamMuxer + Send + Sync + 'static, TMuxer::OutboundSubstream: Send, TMuxer::Substream: Send, TInEvent: Send + 'static, TOutEvent: Send + 'static, { - self.nodes.start_dial_out(self.peer_id.clone(), first, rest); + self.nodes.start_dial_out(self.peer_id.clone(), handler, first, rest); Ok(PeerPendingConnect { attempt: match self.nodes.reach_attempts.out_reach_attempts.entry(self.peer_id) { @@ -1102,28 +1163,3 @@ where }) } } - -impl Stream for - Swarm -where - TTrans: Transport + Clone, - TTrans::Dial: Send + 'static, - TTrans::MultiaddrFuture: Future + Send + 'static, - TTrans::ListenerUpgrade: Send + 'static, - TMuxer: StreamMuxer + Send + Sync + 'static, - TMuxer::OutboundSubstream: Send, - TMuxer::Substream: Send, - TInEvent: Send + 'static, - TOutEvent: Send + 'static, - THandlerBuild: HandlerFactory, - THandler: NodeHandler, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, - THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be necessary -{ - type Item = SwarmEvent; - type Error = Void; // TODO: use `!` once stable - - #[inline] - fn poll(&mut self) -> Poll, Self::Error> { - Ok(self.poll()) - } -} diff --git a/core/src/tests/dummy_transport.rs b/core/src/tests/dummy_transport.rs index 6241a4c1260..37d1ad6ce58 100644 --- a/core/src/tests/dummy_transport.rs +++ b/core/src/tests/dummy_transport.rs @@ -47,10 +47,9 @@ impl DummyTransport { } impl Transport for DummyTransport { type Output = usize; - type Listener = Box + Send>; - type ListenerUpgrade = FutureResult<(Self::Output, Self::MultiaddrFuture), io::Error>; - type MultiaddrFuture = FutureResult; - type Dial = Box + Send>; + type Listener = Box + Send>; + type ListenerUpgrade = FutureResult; + type Dial = Box + Send>; fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> where @@ -59,7 +58,7 @@ impl Transport for DummyTransport { let addr2 = addr.clone(); match self.listener_state { ListenerState::Ok(async) => { - let tupelize = move |stream| future::ok( (stream, future::ok(addr.clone())) ); + let tupelize = move |stream| (future::ok(stream), addr.clone()); Ok(match async { Async::NotReady => { let stream = stream::poll_fn(|| Ok(Async::NotReady)).map(tupelize); diff --git a/core/src/transport/and_then.rs b/core/src/transport/and_then.rs index dcfb6664e16..461448a5d09 100644 --- a/core/src/transport/and_then.rs +++ b/core/src/transport/and_then.rs @@ -20,9 +20,9 @@ use futures::prelude::*; use multiaddr::Multiaddr; +use nodes::raw_swarm::ConnectedPoint; use std::io::Error as IoError; -use transport::{MuxedTransport, Transport}; -use upgrade::Endpoint; +use transport::Transport; /// See the `Transport::and_then` method. #[inline] @@ -37,21 +37,19 @@ pub struct AndThen { upgrade: C, } -impl Transport for AndThen +impl Transport for AndThen where T: Transport + 'static, T::Dial: Send, T::Listener: Send, T::ListenerUpgrade: Send, - C: FnOnce(T::Output, Endpoint, T::MultiaddrFuture) -> F + Clone + Send + 'static, - F: Future + Send + 'static, - Maf: Future + 'static, + C: FnOnce(T::Output, ConnectedPoint) -> F + Clone + Send + 'static, + F: Future + Send + 'static, { type Output = O; - type MultiaddrFuture = Maf; - type Listener = Box + Send>; - type ListenerUpgrade = Box + Send>; - type Dial = Box + Send>; + type Listener = Box + Send>; + type ListenerUpgrade = Box + Send>; + type Dial = Box + Send>; #[inline] fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { @@ -69,17 +67,24 @@ where } }; + let listen_addr = new_addr.clone(); + // Try to negotiate the protocol. // Note that failing to negotiate a protocol will never produce a future with an error. // Instead the `stream` will produce `Ok(Err(...))`. // `stream` can only produce an `Err` if `listening_stream` produces an `Err`. - let stream = listening_stream.map(move |connection| { + let stream = listening_stream.map(move |(connection, client_addr)| { let upgrade = upgrade.clone(); - let future = connection.and_then(move |(stream, client_addr)| { - upgrade(stream, Endpoint::Listener, client_addr) + let connected_point = ConnectedPoint::Listener { + listen_addr: listen_addr.clone(), + send_back_addr: client_addr.clone(), + }; + + let future = connection.and_then(move |stream| { + upgrade(stream, connected_point) }); - Box::new(future) as Box<_> + (Box::new(future) as Box<_>, client_addr) }); Ok((Box::new(stream), new_addr)) @@ -101,10 +106,14 @@ where } }; + let connected_point = ConnectedPoint::Dialer { + address: addr, + }; + let future = dialed_fut // Try to negotiate the protocol. - .and_then(move |(connection, client_addr)| { - upgrade(connection, Endpoint::Dialer, client_addr) + .and_then(move |connection| { + upgrade(connection, connected_point) }); Ok(Box::new(future)) @@ -115,36 +124,3 @@ where self.transport.nat_traversal(server, observed) } } - -impl MuxedTransport for AndThen -where - T: MuxedTransport + 'static, - T::Dial: Send, - T::Listener: Send, - T::ListenerUpgrade: Send, - T::Incoming: Send, - T::IncomingUpgrade: Send, - C: FnOnce(T::Output, Endpoint, T::MultiaddrFuture) -> F + Clone + Send + 'static, - F: Future + Send + 'static, - Maf: Future + 'static, -{ - type Incoming = Box + Send>; - type IncomingUpgrade = Box + Send>; - - #[inline] - fn next_incoming(self) -> Self::Incoming { - let upgrade = self.upgrade; - - let future = self.transport.next_incoming().map(|future| { - // Try to negotiate the protocol. - let future = future.and_then(move |(connection, client_addr)| { - let upgrade = upgrade.clone(); - upgrade(connection, Endpoint::Listener, client_addr) - }); - - Box::new(future) as Box + Send> - }); - - Box::new(future) as Box<_> - } -} diff --git a/core/src/transport/boxed.rs b/core/src/transport/boxed.rs index dff8298f91a..7b47d150844 100644 --- a/core/src/transport/boxed.rs +++ b/core/src/transport/boxed.rs @@ -23,7 +23,7 @@ use multiaddr::Multiaddr; use std::fmt; use std::io::Error as IoError; use std::sync::Arc; -use transport::{MuxedTransport, Transport}; +use transport::Transport; /// See the `Transport::boxed` method. #[inline] @@ -33,35 +33,17 @@ where T::Dial: Send + 'static, T::Listener: Send + 'static, T::ListenerUpgrade: Send + 'static, - T::MultiaddrFuture: Send + 'static, { Boxed { inner: Arc::new(transport) as Arc<_>, } } -/// See the `Transport::boxed_muxed` method. -#[inline] -pub fn boxed_muxed(transport: T) -> BoxedMuxed -where - T: MuxedTransport + Clone + Send + Sync + 'static, - T::Dial: Send + 'static, - T::Listener: Send + 'static, - T::ListenerUpgrade: Send + 'static, - T::MultiaddrFuture: Send + 'static, - T::Incoming: Send + 'static, - T::IncomingUpgrade: Send + 'static, -{ - BoxedMuxed { - inner: Arc::new(transport) as Arc<_>, - } -} -pub type MultiaddrFuture = Box + Send>; -pub type Dial = Box + Send>; -pub type Listener = Box, Error = IoError> + Send>; -pub type ListenerUpgrade = Box + Send>; -pub type Incoming = Box, Error = IoError> + Send>; -pub type IncomingUpgrade = Box + Send>; +pub type Dial = Box + Send>; +pub type Listener = Box, Multiaddr), Error = IoError> + Send>; +pub type ListenerUpgrade = Box + Send>; +pub type Incoming = Box, Multiaddr), Error = IoError> + Send>; +pub type IncomingUpgrade = Box + Send>; trait Abstract { fn listen_on(&self, addr: Multiaddr) -> Result<(Listener, Multiaddr), Multiaddr>; @@ -75,22 +57,19 @@ where T::Dial: Send + 'static, T::Listener: Send + 'static, T::ListenerUpgrade: Send + 'static, - T::MultiaddrFuture: Send + 'static, { fn listen_on(&self, addr: Multiaddr) -> Result<(Listener, Multiaddr), Multiaddr> { let (listener, new_addr) = Transport::listen_on(self.clone(), addr).map_err(|(_, addr)| addr)?; - let fut = listener.map(|upgrade| { - let fut = upgrade.map(|(out, addr)| (out, Box::new(addr) as MultiaddrFuture)); - Box::new(fut) as ListenerUpgrade + let fut = listener.map(|(upgrade, addr)| { + (Box::new(upgrade) as ListenerUpgrade, addr) }); Ok((Box::new(fut) as Box<_>, new_addr)) } fn dial(&self, addr: Multiaddr) -> Result, Multiaddr> { let fut = Transport::dial(self.clone(), addr) - .map_err(|(_, addr)| addr)? - .map(|(out, addr)| (out, Box::new(addr) as MultiaddrFuture)); + .map_err(|(_, addr)| addr)?; Ok(Box::new(fut) as Box<_>) } @@ -100,29 +79,6 @@ where } } -trait AbstractMuxed: Abstract { - fn next_incoming(&self) -> Incoming; -} - -impl AbstractMuxed for T -where - T: MuxedTransport + Clone + 'static, - T::Dial: Send + 'static, - T::Listener: Send + 'static, - T::ListenerUpgrade: Send + 'static, - T::MultiaddrFuture: Send + 'static, - T::Incoming: Send + 'static, - T::IncomingUpgrade: Send + 'static, -{ - fn next_incoming(&self) -> Incoming { - let fut = MuxedTransport::next_incoming(self.clone()).map(|upgrade| { - let fut = upgrade.map(|(out, addr)| (out, Box::new(addr) as MultiaddrFuture)); - Box::new(fut) as IncomingUpgrade - }); - Box::new(fut) as Box<_> - } -} - /// See the `Transport::boxed` method. pub struct Boxed { inner: Arc + Send + Sync>, @@ -145,7 +101,6 @@ impl Clone for Boxed { impl Transport for Boxed { type Output = O; - type MultiaddrFuture = MultiaddrFuture; type Listener = Listener; type ListenerUpgrade = ListenerUpgrade; type Dial = Dial; @@ -171,62 +126,3 @@ impl Transport for Boxed { self.inner.nat_traversal(server, observed) } } - -/// See the `Transport::boxed_muxed` method. -pub struct BoxedMuxed { - inner: Arc + Send + Sync>, -} - -impl fmt::Debug for BoxedMuxed { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "BoxedMuxedTransport") - } -} - -impl Clone for BoxedMuxed { - #[inline] - fn clone(&self) -> Self { - BoxedMuxed { - inner: self.inner.clone(), - } - } -} - -impl Transport for BoxedMuxed { - type Output = O; - type MultiaddrFuture = MultiaddrFuture; - type Listener = Listener; - type ListenerUpgrade = ListenerUpgrade; - type Dial = Dial; - - #[inline] - fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { - match self.inner.listen_on(addr) { - Ok(listen) => Ok(listen), - Err(addr) => Err((self, addr)), - } - } - - #[inline] - fn dial(self, addr: Multiaddr) -> Result { - match self.inner.dial(addr) { - Ok(dial) => Ok(dial), - Err(addr) => Err((self, addr)), - } - } - - #[inline] - fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { - self.inner.nat_traversal(server, observed) - } -} - -impl MuxedTransport for BoxedMuxed { - type Incoming = Incoming; - type IncomingUpgrade = IncomingUpgrade; - - #[inline] - fn next_incoming(self) -> Self::Incoming { - self.inner.next_incoming() - } -} diff --git a/core/src/transport/choice.rs b/core/src/transport/choice.rs index 78288cf98b5..3f5b684d89d 100644 --- a/core/src/transport/choice.rs +++ b/core/src/transport/choice.rs @@ -18,11 +18,9 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use either::{EitherListenStream, EitherListenUpgrade, EitherOutput}; -use futures::{prelude::*, future}; +use either::{EitherListenStream, EitherOutput, EitherFuture}; use multiaddr::Multiaddr; -use std::io::Error as IoError; -use transport::{MuxedTransport, Transport}; +use transport::Transport; /// Struct returned by `or_transport()`. #[derive(Debug, Copy, Clone)] @@ -41,10 +39,8 @@ where { type Output = EitherOutput; type Listener = EitherListenStream; - type ListenerUpgrade = EitherListenUpgrade; - type MultiaddrFuture = future::Either; - type Dial = - EitherListenUpgrade<::Future, ::Future>; + type ListenerUpgrade = EitherFuture; + type Dial = EitherFuture; fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { let (first, addr) = match self.0.listen_on(addr) { @@ -60,12 +56,12 @@ where fn dial(self, addr: Multiaddr) -> Result { let (first, addr) = match self.0.dial(addr) { - Ok(connec) => return Ok(EitherListenUpgrade::First(connec)), + Ok(connec) => return Ok(EitherFuture::First(connec)), Err(err) => err, }; match self.1.dial(addr) { - Ok(connec) => Ok(EitherListenUpgrade::Second(connec)), + Ok(connec) => Ok(EitherFuture::Second(connec)), Err((second, addr)) => Err((OrTransport(first, second), addr)), } } @@ -80,33 +76,3 @@ where self.1.nat_traversal(server, observed) } } - -impl MuxedTransport for OrTransport -where - A: MuxedTransport, - B: MuxedTransport, - A::Incoming: Send + 'static, // TODO: meh :-/ - B::Incoming: Send + 'static, // TODO: meh :-/ - A::IncomingUpgrade: Send + 'static, // TODO: meh :-/ - B::IncomingUpgrade: Send + 'static, // TODO: meh :-/ - A::Output: 'static, // TODO: meh :-/ - B::Output: 'static, // TODO: meh :-/ -{ - type Incoming = Box + Send>; - type IncomingUpgrade = - Box, Self::MultiaddrFuture), Error = IoError> + Send>; - - #[inline] - fn next_incoming(self) -> Self::Incoming { - let first = self.0.next_incoming().map(|out| { - let fut = out.map(move |(v, addr)| (EitherOutput::First(v), future::Either::A(addr))); - Box::new(fut) as Box + Send> - }); - let second = self.1.next_incoming().map(|out| { - let fut = out.map(move |(v, addr)| (EitherOutput::Second(v), future::Either::B(addr))); - Box::new(fut) as Box + Send> - }); - let future = first.select(second).map(|(i, _)| i).map_err(|(e, _)| e); - Box::new(future) as Box<_> - } -} diff --git a/core/src/transport/denied.rs b/core/src/transport/denied.rs index 2f77c79ae22..87a0beb41e5 100644 --- a/core/src/transport/denied.rs +++ b/core/src/transport/denied.rs @@ -18,11 +18,9 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use futures::future; use futures::prelude::*; use multiaddr::Multiaddr; use std::io::{self, Cursor}; -use transport::MuxedTransport; use transport::Transport; /// Dummy implementation of `Transport` that just denies every single attempt. @@ -32,10 +30,9 @@ pub struct DeniedTransport; impl Transport for DeniedTransport { // TODO: could use `!` for associated types once stable type Output = Cursor>; - type MultiaddrFuture = Box + Send + Sync>; - type Listener = Box + Send + Sync>; - type ListenerUpgrade = Box + Send + Sync>; - type Dial = Box + Send + Sync>; + type Listener = Box + Send + Sync>; + type ListenerUpgrade = Box + Send + Sync>; + type Dial = Box + Send + Sync>; #[inline] fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { @@ -52,13 +49,3 @@ impl Transport for DeniedTransport { None } } - -impl MuxedTransport for DeniedTransport { - type Incoming = future::Empty; - type IncomingUpgrade = future::Empty<(Self::Output, Self::MultiaddrFuture), io::Error>; - - #[inline] - fn next_incoming(self) -> Self::Incoming { - future::empty() - } -} diff --git a/core/src/transport/interruptible.rs b/core/src/transport/interruptible.rs index 3638b8fef51..db24e99518f 100644 --- a/core/src/transport/interruptible.rs +++ b/core/src/transport/interruptible.rs @@ -20,7 +20,7 @@ use futures::{future, prelude::*, sync::oneshot}; use std::io::{Error as IoError, ErrorKind as IoErrorKind}; -use transport::{MuxedTransport, Transport}; +use transport::Transport; use Multiaddr; /// See `Transport::interruptible`. @@ -46,7 +46,6 @@ where T: Transport, { type Output = T::Output; - type MultiaddrFuture = T::MultiaddrFuture; type Listener = T::Listener; type ListenerUpgrade = T::ListenerUpgrade; type Dial = InterruptibleDial; @@ -78,19 +77,6 @@ where } } -impl MuxedTransport for Interruptible -where - T: MuxedTransport, -{ - type Incoming = T::Incoming; - type IncomingUpgrade = T::IncomingUpgrade; - - #[inline] - fn next_incoming(self) -> Self::Incoming { - self.transport.next_incoming() - } -} - /// Dropping this object interrupts the dialing of the corresponding `Interruptible`. pub struct Interrupt { _tx: oneshot::Sender<()>, diff --git a/core/src/transport/map.rs b/core/src/transport/map.rs index d4e09068fa0..f7dad92294a 100644 --- a/core/src/transport/map.rs +++ b/core/src/transport/map.rs @@ -21,7 +21,7 @@ use futures::prelude::*; use multiaddr::Multiaddr; use std::io::Error as IoError; -use transport::{MuxedTransport, Transport}; +use transport::Transport; use Endpoint; /// See `Transport::map`. @@ -48,22 +48,21 @@ where F: FnOnce(T::Output, Endpoint) -> D + Clone + Send + 'static, // TODO: 'static :-/ { type Output = D; - type MultiaddrFuture = T::MultiaddrFuture; - type Listener = Box + Send>; - type ListenerUpgrade = Box + Send>; - type Dial = Box + Send>; + type Listener = Box + Send>; + type ListenerUpgrade = Box + Send>; + type Dial = Box + Send>; fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { let map = self.map; match self.transport.listen_on(addr) { Ok((stream, listen_addr)) => { - let stream = stream.map(move |future| { + let stream = stream.map(move |(future, addr)| { let map = map.clone(); let future = future .into_future() - .map(move |(output, addr)| (map(output, Endpoint::Listener), addr)); - Box::new(future) as Box<_> + .map(move |output| map(output, Endpoint::Listener)); + (Box::new(future) as Box<_>, addr) }); Ok((Box::new(stream), listen_addr)) } @@ -78,7 +77,7 @@ where Ok(future) => { let future = future .into_future() - .map(move |(output, addr)| (map(output, Endpoint::Dialer), addr)); + .map(move |output| map(output, Endpoint::Dialer)); Ok(Box::new(future)) } Err((transport, addr)) => Err((Map { transport, map }, addr)), @@ -90,28 +89,3 @@ where self.transport.nat_traversal(server, observed) } } - -impl MuxedTransport for Map -where - T: MuxedTransport + 'static, // TODO: 'static :-/ - T::Dial: Send, - T::Listener: Send, - T::ListenerUpgrade: Send, - T::Incoming: Send, - T::IncomingUpgrade: Send, - F: FnOnce(T::Output, Endpoint) -> D + Clone + Send + 'static, // TODO: 'static :-/ -{ - type Incoming = Box + Send>; - type IncomingUpgrade = Box + Send>; - - fn next_incoming(self) -> Self::Incoming { - let map = self.map; - let future = self.transport.next_incoming().map(move |upgrade| { - let future = upgrade.map(move |(output, addr)| { - (map(output, Endpoint::Listener), addr) - }); - Box::new(future) as Box<_> - }); - Box::new(future) - } -} diff --git a/core/src/transport/map_err.rs b/core/src/transport/map_err.rs index 3008f0fd7cf..f8b92839572 100644 --- a/core/src/transport/map_err.rs +++ b/core/src/transport/map_err.rs @@ -21,7 +21,7 @@ use futures::prelude::*; use multiaddr::Multiaddr; use std::io::Error as IoError; -use transport::{MuxedTransport, Transport}; +use transport::Transport; /// See `Transport::map_err`. #[derive(Debug, Copy, Clone)] @@ -44,7 +44,6 @@ where F: FnOnce(IoError) -> IoError + Clone, { type Output = T::Output; - type MultiaddrFuture = T::MultiaddrFuture; type Listener = MapErrListener; type ListenerUpgrade = MapErrListenerUpgrade; type Dial = MapErrDial; @@ -76,23 +75,6 @@ where } } -impl MuxedTransport for MapErr -where - T: MuxedTransport, - F: FnOnce(IoError) -> IoError + Clone, -{ - type Incoming = MapErrIncoming; - type IncomingUpgrade = MapErrIncomingUpgrade; - - #[inline] - fn next_incoming(self) -> Self::Incoming { - MapErrIncoming { - inner: self.transport.next_incoming(), - map: Some(self.map), - } - } -} - /// Listening stream for `MapErr`. pub struct MapErrListener where T: Transport { @@ -104,14 +86,14 @@ impl Stream for MapErrListener where T: Transport, F: FnOnce(IoError) -> IoError + Clone, { - type Item = MapErrListenerUpgrade; + type Item = (MapErrListenerUpgrade, Multiaddr); type Error = IoError; #[inline] fn poll(&mut self) -> Poll, Self::Error> { match try_ready!(self.inner.poll()) { - Some(value) => Ok(Async::Ready( - Some(MapErrListenerUpgrade { inner: value, map: Some(self.map.clone()) }))), + Some((value, addr)) => Ok(Async::Ready( + Some((MapErrListenerUpgrade { inner: value, map: Some(self.map.clone()) }, addr)))), None => Ok(Async::Ready(None)) } } @@ -128,7 +110,7 @@ impl Future for MapErrListenerUpgrade where T: Transport, F: FnOnce(IoError) -> IoError, { - type Item = (T::Output, T::MultiaddrFuture); + type Item = T::Output; type Error = IoError; #[inline] @@ -159,72 +141,7 @@ impl Future for MapErrDial where T: Transport, F: FnOnce(IoError) -> IoError, { - type Item = (T::Output, T::MultiaddrFuture); - type Error = IoError; - - #[inline] - fn poll(&mut self) -> Poll { - match self.inner.poll() { - Ok(Async::Ready(value)) => { - Ok(Async::Ready(value)) - }, - Ok(Async::NotReady) => Ok(Async::NotReady), - Err(err) => { - let map = self.map.take().expect("poll() called again after error"); - Err(map(err)) - } - } - } -} - -/// Incoming future for `MapErr`. -pub struct MapErrIncoming -where T: MuxedTransport -{ - inner: T::Incoming, - map: Option, -} - -impl Future for MapErrIncoming -where T: MuxedTransport, - F: FnOnce(IoError) -> IoError, -{ - type Item = MapErrIncomingUpgrade; - type Error = IoError; - - #[inline] - fn poll(&mut self) -> Poll { - match self.inner.poll() { - Ok(Async::Ready(value)) => { - let map = self.map.take().expect("poll() called again after error"); - let value = MapErrIncomingUpgrade { - inner: value, - map: Some(map), - }; - Ok(Async::Ready(value)) - }, - Ok(Async::NotReady) => Ok(Async::NotReady), - Err(err) => { - let map = self.map.take().expect("poll() called again after error"); - Err(map(err)) - } - } - } -} - -/// Incoming upgrade future for `MapErr`. -pub struct MapErrIncomingUpgrade -where T: MuxedTransport -{ - inner: T::IncomingUpgrade, - map: Option, -} - -impl Future for MapErrIncomingUpgrade -where T: MuxedTransport, - F: FnOnce(IoError) -> IoError, -{ - type Item = (T::Output, T::MultiaddrFuture); + type Item = T::Output; type Error = IoError; #[inline] diff --git a/core/src/transport/map_err_dial.rs b/core/src/transport/map_err_dial.rs index f99ff8e9966..8019df65242 100644 --- a/core/src/transport/map_err_dial.rs +++ b/core/src/transport/map_err_dial.rs @@ -21,7 +21,7 @@ use futures::prelude::*; use multiaddr::Multiaddr; use std::io::Error as IoError; -use transport::{MuxedTransport, Transport}; +use transport::Transport; /// See `Transport::map_err_dial`. #[derive(Debug, Copy, Clone)] @@ -45,10 +45,9 @@ where F: FnOnce(IoError, Multiaddr) -> IoError + Clone + Send + 'static, // TODO: 'static :-/ { type Output = T::Output; - type MultiaddrFuture = T::MultiaddrFuture; type Listener = T::Listener; type ListenerUpgrade = T::ListenerUpgrade; - type Dial = Box + Send>; + type Dial = Box + Send>; fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { match self.transport.listen_on(addr) { @@ -74,18 +73,3 @@ where self.transport.nat_traversal(server, observed) } } - -impl MuxedTransport for MapErrDial -where - T: MuxedTransport + 'static, // TODO: 'static :-/ - T::Dial: Send, - F: FnOnce(IoError, Multiaddr) -> IoError + Clone + Send + 'static, // TODO: 'static :-/ -{ - type Incoming = T::Incoming; - type IncomingUpgrade = T::IncomingUpgrade; - - #[inline] - fn next_incoming(self) -> Self::Incoming { - self.transport.next_incoming() - } -} diff --git a/core/src/transport/memory.rs b/core/src/transport/memory.rs index 14d53111396..f77e9b95251 100644 --- a/core/src/transport/memory.rs +++ b/core/src/transport/memory.rs @@ -52,10 +52,9 @@ impl Clone for Dialer { impl Transport for Dialer { type Output = Channel; - type Listener = Box + Send>; - type ListenerUpgrade = FutureResult<(Self::Output, Self::MultiaddrFuture), io::Error>; - type MultiaddrFuture = FutureResult; - type Dial = Box + Send>; + type Listener = Box + Send>; + type ListenerUpgrade = FutureResult; + type Dial = Box + Send>; fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { Err((self, addr)) @@ -70,7 +69,7 @@ impl Transport for Dialer { let a = Chan { incoming: a_rx, outgoing: b_tx }; let b = Chan { incoming: b_rx, outgoing: a_tx }; let future = self.0.send(b) - .map(move |_| (a.into(), future::ok(addr))) + .map(move |_| a.into()) .map_err(|_| io::ErrorKind::ConnectionRefused.into()); Ok(Box::new(future)) } @@ -95,10 +94,9 @@ impl Clone for Listener { impl Transport for Listener { type Output = Channel; - type Listener = Box + Send>; - type ListenerUpgrade = FutureResult<(Self::Output, Self::MultiaddrFuture), io::Error>; - type MultiaddrFuture = FutureResult; - type Dial = Box + Send>; + type Listener = Box + Send>; + type ListenerUpgrade = FutureResult; + type Dial = Box + Send>; fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { if !is_memory_addr(&addr) { @@ -108,7 +106,7 @@ impl Transport for Listener { let receiver = self.0.clone(); let stream = stream::poll_fn(move || receiver.lock().poll()) .map(move |channel| { - future::ok((channel.into(), future::ok(addr.clone()))) + (future::ok(channel.into()), addr.clone()) }) .map_err(|()| unreachable!()); Ok((Box::new(stream), addr2)) diff --git a/core/src/transport/mod.rs b/core/src/transport/mod.rs index 7679e3f09c3..7a353f1e524 100644 --- a/core/src/transport/mod.rs +++ b/core/src/transport/mod.rs @@ -31,6 +31,7 @@ use futures::prelude::*; use multiaddr::Multiaddr; +use nodes::raw_swarm::ConnectedPoint; use std::io::Error as IoError; use tokio_io::{AsyncRead, AsyncWrite}; use upgrade::{ConnectionUpgrade, Endpoint}; @@ -39,21 +40,16 @@ pub mod and_then; pub mod boxed; pub mod choice; pub mod denied; -pub mod dummy; pub mod interruptible; pub mod map; pub mod map_err; pub mod map_err_dial; pub mod memory; -pub mod muxed; pub mod upgrade; -pub use self::boxed::BoxedMuxed; pub use self::choice::OrTransport; pub use self::denied::DeniedTransport; -pub use self::dummy::DummyMuxing; pub use self::memory::connector; -pub use self::muxed::MuxedTransport; pub use self::upgrade::UpgradedNode; /// A transport is an object that can be used to produce connections by listening or dialing a @@ -75,19 +71,15 @@ pub trait Transport { /// An item should be produced whenever a connection is received at the lowest level of the /// transport stack. The item is a `Future` that is signalled once some pre-processing has /// taken place, and that connection has been upgraded to the wanted protocols. - type Listener: Stream; - - /// Future that produces the multiaddress of the remote. - type MultiaddrFuture: Future; + type Listener: Stream; /// After a connection has been received, we may need to do some asynchronous pre-processing /// on it (eg. an intermediary protocol negotiation). While this pre-processing takes place, we /// want to be able to continue polling on the listener. - // TODO: we could move the `MultiaddrFuture` to the `Listener` trait - type ListenerUpgrade: Future; + type ListenerUpgrade: Future; /// A future which indicates that we are currently dialing to a peer. - type Dial: Future; + type Dial: Future; /// Listen on the given multiaddr. Returns a stream of incoming connections, plus a modified /// version of the `Multiaddr`. This new `Multiaddr` is the one that that should be advertised @@ -132,27 +124,10 @@ pub trait Transport { Self::Dial: Send + 'static, Self::Listener: Send + 'static, Self::ListenerUpgrade: Send + 'static, - Self::MultiaddrFuture: Send + 'static, { boxed::boxed(self) } - /// Turns this `Transport` into an abstract boxed transport. - /// - /// This is the version if the transport supports muxing. - #[inline] - fn boxed_muxed(self) -> boxed::BoxedMuxed - where Self: Sized + MuxedTransport + Clone + Send + Sync + 'static, - Self::Dial: Send + 'static, - Self::Listener: Send + 'static, - Self::ListenerUpgrade: Send + 'static, - Self::MultiaddrFuture: Send + 'static, - Self::Incoming: Send + 'static, - Self::IncomingUpgrade: Send + 'static, - { - boxed::boxed_muxed(self) - } - /// Applies a function on the output of the `Transport`. #[inline] fn map(self, map: F) -> map::Map @@ -207,7 +182,7 @@ pub trait Transport { where Self: Sized, Self::Output: AsyncRead + AsyncWrite, - U: ConnectionUpgrade, + U: ConnectionUpgrade, { UpgradedNode::new(self, upgrade) } @@ -218,29 +193,15 @@ pub trait Transport { /// > **Note**: The concept of an *upgrade* for example includes middlewares such *secio* /// > (communication encryption), *multiplex*, but also a protocol handler. #[inline] - fn and_then(self, upgrade: C) -> and_then::AndThen + fn and_then(self, upgrade: C) -> and_then::AndThen where Self: Sized, - C: FnOnce(Self::Output, Endpoint, Self::MultiaddrFuture) -> F + Clone + 'static, - F: Future + 'static, - Maf: Future + 'static, + C: FnOnce(Self::Output, ConnectedPoint) -> F + Clone + 'static, + F: Future + 'static, { and_then::and_then(self, upgrade) } - /// Builds a dummy implementation of `MuxedTransport` that uses this transport. - /// - /// The resulting object will not actually use muxing. This means that dialing the same node - /// twice will result in two different connections instead of two substreams on the same - /// connection. - #[inline] - fn with_dummy_muxing(self) -> DummyMuxing - where - Self: Sized, - { - DummyMuxing::new(self) - } - /// Wraps around the `Transport` and makes it interruptible. #[inline] fn interruptible(self) -> (interruptible::Interruptible, interruptible::Interrupt) diff --git a/core/src/transport/upgrade.rs b/core/src/transport/upgrade.rs index 8d9fc6218a5..e661b535de7 100644 --- a/core/src/transport/upgrade.rs +++ b/core/src/transport/upgrade.rs @@ -22,7 +22,7 @@ use futures::prelude::*; use multiaddr::Multiaddr; use std::io::Error as IoError; use tokio_io::{AsyncRead, AsyncWrite}; -use transport::{MuxedTransport, Transport}; +use transport::Transport; use upgrade::{apply, ConnectionUpgrade, Endpoint}; /// Implements the `Transport` trait. Dials or listens, then upgrades any dialed or received @@ -50,9 +50,8 @@ where T::Dial: Send, T::Listener: Send, T::ListenerUpgrade: Send, - T::MultiaddrFuture: Send, T::Output: Send + AsyncRead + AsyncWrite, - C: ConnectionUpgrade + Send + 'a, + C: ConnectionUpgrade + Send + 'a, C::NamesIter: Send, C::Future: Send, C::UpgradeIdentifier: Send, @@ -72,7 +71,7 @@ where pub fn dial( self, addr: Multiaddr, - ) -> Result + Send + 'a>, (Self, Multiaddr)> + ) -> Result + Send + 'a>, (Self, Multiaddr)> where C::NamesIter: Clone, // TODO: not elegant { @@ -92,48 +91,13 @@ where let future = dialed_fut // Try to negotiate the protocol. - .and_then(move |(connection, client_addr)| { - apply(connection, upgrade, Endpoint::Dialer, client_addr) + .and_then(move |connection| { + apply(connection, upgrade, Endpoint::Dialer) }); Ok(Box::new(future)) } - /// If the underlying transport is a `MuxedTransport`, then after calling `dial` we may receive - /// substreams opened by the dialed nodes. - /// - /// This function returns the next incoming substream. You are strongly encouraged to call it - /// if you have a muxed transport. - pub fn next_incoming( - self, - ) -> Box< - Future< - Item = Box + Send + 'a>, - Error = IoError, - > - + Send + 'a, - > - where - T: MuxedTransport, - T::Incoming: Send, - T::IncomingUpgrade: Send, - C::NamesIter: Clone, // TODO: not elegant - C: Clone, - { - let upgrade = self.upgrade; - - let future = self.transports.next_incoming().map(|future| { - // Try to negotiate the protocol. - let future = future.and_then(move |(connection, client_addr)| { - apply(connection, upgrade, Endpoint::Listener, client_addr) - }); - - Box::new(future) as Box + Send> - }); - - Box::new(future) as Box<_> - } - /// Start listening on the multiaddr using the transport that was passed to `new`. /// Then whenever a connection is opened, it is upgraded. /// @@ -147,7 +111,7 @@ where ( Box< Stream< - Item = Box + Send + 'a>, + Item = (Box + Send + 'a>, Multiaddr), Error = IoError, > + Send @@ -179,15 +143,15 @@ where // Note that failing to negotiate a protocol will never produce a future with an error. // Instead the `stream` will produce `Ok(Err(...))`. // `stream` can only produce an `Err` if `listening_stream` produces an `Err`. - let stream = listening_stream.map(move |connection| { + let stream = listening_stream.map(move |(connection, client_addr)| { let upgrade = upgrade.clone(); let connection = connection // Try to negotiate the protocol. - .and_then(move |(connection, client_addr)| { - apply(connection, upgrade, Endpoint::Listener, client_addr) + .and_then(move |connection| { + apply(connection, upgrade, Endpoint::Listener) }); - Box::new(connection) as Box<_> + (Box::new(connection) as Box<_>, client_addr) }); Ok((Box::new(stream), new_addr)) @@ -200,19 +164,16 @@ where T::Dial: Send, T::Listener: Send, T::ListenerUpgrade: Send, - T::MultiaddrFuture: Send, T::Output: Send + AsyncRead + AsyncWrite, - C: ConnectionUpgrade + Clone + Send + 'static, - C::MultiaddrFuture: Future, + C: ConnectionUpgrade + Clone + Send + 'static, C::NamesIter: Clone + Send, C::Future: Send, C::UpgradeIdentifier: Send, { type Output = C::Output; - type MultiaddrFuture = C::MultiaddrFuture; - type Listener = Box + Send>; - type ListenerUpgrade = Box + Send>; - type Dial = Box + Send>; + type Listener = Box + Send>; + type ListenerUpgrade = Box + Send>; + type Dial = Box + Send>; #[inline] fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { @@ -229,28 +190,3 @@ where self.transports.nat_traversal(server, observed) } } - -impl MuxedTransport for UpgradedNode -where - T: MuxedTransport + 'static, - T::Dial: Send, - T::Listener: Send, - T::ListenerUpgrade: Send, - T::MultiaddrFuture: Send, - T::Output: Send + AsyncRead + AsyncWrite, - T::Incoming: Send, - T::IncomingUpgrade: Send, - C: ConnectionUpgrade + Clone + Send + 'static, - C::MultiaddrFuture: Future, - C::NamesIter: Clone + Send, - C::Future: Send, - C::UpgradeIdentifier: Send, -{ - type Incoming = Box + Send>; - type IncomingUpgrade = Box + Send>; - - #[inline] - fn next_incoming(self) -> Self::Incoming { - self.next_incoming() - } -} diff --git a/core/src/upgrade/apply.rs b/core/src/upgrade/apply.rs index 7389f70e8fb..2e82d981cd4 100644 --- a/core/src/upgrade/apply.rs +++ b/core/src/upgrade/apply.rs @@ -29,9 +29,9 @@ use upgrade::{ConnectionUpgrade, Endpoint}; /// /// Returns a `Future` that returns the outcome of the connection upgrade. #[inline] -pub fn apply(conn: C, upgrade: U, e: Endpoint, remote: Maf) -> UpgradeApplyFuture +pub fn apply(conn: C, upgrade: U, e: Endpoint) -> UpgradeApplyFuture where - U: ConnectionUpgrade, + U: ConnectionUpgrade, U::NamesIter: Clone, // TODO: not elegant C: AsyncRead + AsyncWrite, { @@ -40,31 +40,28 @@ where future: negotiate(conn, &upgrade, e), upgrade, endpoint: e, - remote } } } /// Future, returned from `apply` which performs a connection upgrade. -pub struct UpgradeApplyFuture +pub struct UpgradeApplyFuture where - U: ConnectionUpgrade, + U: ConnectionUpgrade, C: AsyncRead + AsyncWrite { - inner: UpgradeApplyState + inner: UpgradeApplyState } - -enum UpgradeApplyState +enum UpgradeApplyState where - U: ConnectionUpgrade, + U: ConnectionUpgrade, C: AsyncRead + AsyncWrite { Init { future: NegotiationFuture, U::UpgradeIdentifier>, upgrade: U, - endpoint: Endpoint, - remote: Maf + endpoint: Endpoint }, Upgrade { future: U::Future @@ -72,28 +69,28 @@ where Undefined } -impl Future for UpgradeApplyFuture +impl Future for UpgradeApplyFuture where - U: ConnectionUpgrade, + U: ConnectionUpgrade, U::NamesIter: Clone, C: AsyncRead + AsyncWrite { - type Item = (U::Output, U::MultiaddrFuture); + type Item = U::Output; type Error = IoError; fn poll(&mut self) -> Poll { loop { match mem::replace(&mut self.inner, UpgradeApplyState::Undefined) { - UpgradeApplyState::Init { mut future, upgrade, endpoint, remote } => { + UpgradeApplyState::Init { mut future, upgrade, endpoint } => { let (upgrade_id, connection) = match future.poll()? { Async::Ready(x) => x, Async::NotReady => { - self.inner = UpgradeApplyState::Init { future, upgrade, endpoint, remote }; + self.inner = UpgradeApplyState::Init { future, upgrade, endpoint }; return Ok(Async::NotReady) } }; self.inner = UpgradeApplyState::Upgrade { - future: upgrade.upgrade(connection, upgrade_id, endpoint, remote) + future: upgrade.upgrade(connection, upgrade_id, endpoint) }; } UpgradeApplyState::Upgrade { mut future } => { @@ -124,13 +121,13 @@ where /// /// Returns a `Future` that returns the negotiated protocol and the stream. #[inline] -pub fn negotiate( +pub fn negotiate( connection: C, upgrade: &U, endpoint: Endpoint, ) -> NegotiationFuture, U::UpgradeIdentifier> where - U: ConnectionUpgrade, + U: ConnectionUpgrade, U::NamesIter: Clone, // TODO: not elegant C: AsyncRead + AsyncWrite, { @@ -144,7 +141,6 @@ where } } - /// Future, returned by `negotiate`, which negotiates a protocol and stream. pub struct NegotiationFuture { inner: Either, DialerSelectFuture> @@ -175,7 +171,6 @@ where } } - /// Iterator adapter which adds equality matching predicates to items. /// Used in `NegotiationFuture`. #[derive(Clone)] diff --git a/core/src/upgrade/choice.rs b/core/src/upgrade/choice.rs index f7484af1583..7dfa815132e 100644 --- a/core/src/upgrade/choice.rs +++ b/core/src/upgrade/choice.rs @@ -19,8 +19,7 @@ // DEALINGS IN THE SOFTWARE. use bytes::Bytes; -use futures::{future, prelude::*}; -use std::io::Error as IoError; +use futures::future; use tokio_io::{AsyncRead, AsyncWrite}; use upgrade::{ConnectionUpgrade, Endpoint}; @@ -37,11 +36,11 @@ pub fn or(me: A, other: B) -> OrUpgrade { #[derive(Debug, Copy, Clone)] pub struct OrUpgrade(A, B); -impl ConnectionUpgrade for OrUpgrade +impl ConnectionUpgrade for OrUpgrade where C: AsyncRead + AsyncWrite, - A: ConnectionUpgrade, - B: ConnectionUpgrade, + A: ConnectionUpgrade, + B: ConnectionUpgrade, { type NamesIter = NamesIterChain; type UpgradeIdentifier = EitherUpgradeIdentifier; @@ -55,8 +54,7 @@ where } type Output = O; - type MultiaddrFuture = future::Either; - type Future = EitherConnUpgrFuture; + type Future = future::Either; #[inline] fn upgrade( @@ -64,14 +62,13 @@ where socket: C, id: Self::UpgradeIdentifier, ty: Endpoint, - remote_addr: Maf, ) -> Self::Future { match id { EitherUpgradeIdentifier::First(id) => { - EitherConnUpgrFuture::First(self.0.upgrade(socket, id, ty, remote_addr)) + future::Either::A(self.0.upgrade(socket, id, ty)) } EitherUpgradeIdentifier::Second(id) => { - EitherConnUpgrFuture::Second(self.1.upgrade(socket, id, ty, remote_addr)) + future::Either::B(self.1.upgrade(socket, id, ty)) } } } @@ -84,43 +81,6 @@ pub enum EitherUpgradeIdentifier { Second(B), } -/// Implements `Future` and redirects calls to either `First` or `Second`. -/// -/// Additionally, the output will be wrapped inside a `EitherOutput`. -/// -// TODO: This type is needed because of the lack of `impl Trait` in stable Rust. -// If Rust had impl Trait we could use the Either enum from the futures crate and add some -// modifiers to it. This custom enum is a combination of Either and these modifiers. -#[derive(Debug, Copy, Clone)] -#[must_use = "futures do nothing unless polled"] -pub enum EitherConnUpgrFuture { - First(A), - Second(B), -} - -impl Future for EitherConnUpgrFuture -where - A: Future, - B: Future, -{ - type Item = (O, future::Either); - type Error = IoError; - - #[inline] - fn poll(&mut self) -> Poll { - match self { - &mut EitherConnUpgrFuture::First(ref mut a) => { - let (item, fut) = try_ready!(a.poll()); - Ok(Async::Ready((item, future::Either::A(fut)))) - } - &mut EitherConnUpgrFuture::Second(ref mut b) => { - let (item, fut) = try_ready!(b.poll()); - Ok(Async::Ready((item, future::Either::B(fut)))) - } - } - } -} - /// Internal type used by the `OrUpgrade` struct. /// /// > **Note**: This type is needed because of the lack of `-> impl Trait` in Rust. It can be diff --git a/core/src/upgrade/denied.rs b/core/src/upgrade/denied.rs index 3cb9b836ccf..1ead49f93c0 100644 --- a/core/src/upgrade/denied.rs +++ b/core/src/upgrade/denied.rs @@ -20,7 +20,6 @@ use bytes::Bytes; use futures::prelude::*; -use multiaddr::Multiaddr; use std::{io, iter}; use tokio_io::{AsyncRead, AsyncWrite}; use upgrade::{ConnectionUpgrade, Endpoint}; @@ -29,15 +28,14 @@ use upgrade::{ConnectionUpgrade, Endpoint}; #[derive(Debug, Copy, Clone)] pub struct DeniedConnectionUpgrade; -impl ConnectionUpgrade for DeniedConnectionUpgrade +impl ConnectionUpgrade for DeniedConnectionUpgrade where C: AsyncRead + AsyncWrite, { type NamesIter = iter::Empty<(Bytes, ())>; type UpgradeIdentifier = (); // TODO: could use `!` type Output = (); // TODO: could use `!` - type MultiaddrFuture = Box + Send + Sync>; // TODO: could use `!` - type Future = Box + Send + Sync>; // TODO: could use `!` + type Future = Box + Send + Sync>; // TODO: could use `!` #[inline] fn protocol_names(&self) -> Self::NamesIter { @@ -45,7 +43,7 @@ where } #[inline] - fn upgrade(self, _: C, _: Self::UpgradeIdentifier, _: Endpoint, _: Maf) -> Self::Future { + fn upgrade(self, _: C, _: Self::UpgradeIdentifier, _: Endpoint) -> Self::Future { unreachable!("the denied connection upgrade always fails to negotiate") } } diff --git a/core/src/upgrade/loop_upg.rs b/core/src/upgrade/loop_upg.rs index faf761c0010..f597c9eccd2 100644 --- a/core/src/upgrade/loop_upg.rs +++ b/core/src/upgrade/loop_upg.rs @@ -61,23 +61,20 @@ pub struct LoopUpg { } // TODO: 'static :-/ -impl ConnectionUpgrade<(State, Socket), AddrFut> +impl ConnectionUpgrade<(State, Socket)> for LoopUpg where State: Send + 'static, Socket: AsyncRead + AsyncWrite + Send + 'static, Inner: ConnectionUpgrade< (State, Socket), - AddrFut, Output = Loop, - MultiaddrFuture = AddrFut, > + Clone + Send + 'static, Inner::NamesIter: Clone + Send + 'static, Inner::UpgradeIdentifier: Send, Inner::Future: Send, - AddrFut: Send + 'static, Out: Send + 'static, { type NamesIter = Inner::NamesIter; @@ -88,29 +85,27 @@ where } type Output = Out; - type MultiaddrFuture = AddrFut; - type Future = Box + Send>; + type Future = Box + Send>; fn upgrade( self, (state, socket): (State, Socket), id: Self::UpgradeIdentifier, endpoint: Endpoint, - remote_addr: AddrFut, ) -> Self::Future { let inner = self.inner; let fut = future::loop_fn( - (state, socket, id, remote_addr, MAX_LOOPS), - move |(state, socket, id, remote_addr, loops_remaining)| { + (state, socket, id, MAX_LOOPS), + move |(state, socket, id, loops_remaining)| { // When we enter a recursion of the `loop_fn`, a protocol has already been // negotiated. So what we have to do is upgrade then negotiate the next protocol // (if necessary), and then only continue iteration in the `future::loop_fn`. let inner = inner.clone(); inner .clone() - .upgrade((state, socket), id, endpoint, remote_addr) - .and_then(move |(loop_out, remote_addr)| match loop_out { + .upgrade((state, socket), id, endpoint) + .and_then(move |loop_out| match loop_out { Loop::Continue(state, socket) => { // Produce an error if we reached the recursion limit. if loops_remaining == 0 { @@ -126,14 +121,13 @@ where state, socket, id, - remote_addr, loops_remaining - 1, )) }); future::Either::A(fut) } Loop::Break(fin) => { - future::Either::B(future::ok(FutLoop::Break((fin, remote_addr)))) + future::Either::B(future::ok(FutLoop::Break(fin))) } }) }, diff --git a/core/src/upgrade/map.rs b/core/src/upgrade/map.rs index 92f365ec6f1..4ead163d5de 100644 --- a/core/src/upgrade/map.rs +++ b/core/src/upgrade/map.rs @@ -36,9 +36,9 @@ pub struct Map { map: F, } -impl ConnectionUpgrade for Map +impl ConnectionUpgrade for Map where - U: ConnectionUpgrade, + U: ConnectionUpgrade, U::Future: Send + 'static, // TODO: 'static :( C: AsyncRead + AsyncWrite, F: FnOnce(U::Output) -> O + Send + 'static, // TODO: 'static :( @@ -51,20 +51,18 @@ where } type Output = O; - type MultiaddrFuture = U::MultiaddrFuture; - type Future = Box + Send>; + type Future = Box + Send>; fn upgrade( self, socket: C, id: Self::UpgradeIdentifier, ty: Endpoint, - remote_addr: Maf, ) -> Self::Future { let map = self.map; let fut = self.upgrade - .upgrade(socket, id, ty, remote_addr) - .map(move |(out, maf)| (map(out), maf)); + .upgrade(socket, id, ty) + .map(map); Box::new(fut) as Box<_> } } diff --git a/core/src/upgrade/mod.rs b/core/src/upgrade/mod.rs index d01a60fec52..279d5a9b44e 100644 --- a/core/src/upgrade/mod.rs +++ b/core/src/upgrade/mod.rs @@ -23,7 +23,6 @@ pub mod choice; pub mod denied; pub mod loop_upg; pub mod map; -pub mod map_addr; pub mod plaintext; pub mod toggleable; pub mod traits; @@ -33,7 +32,6 @@ pub use self::choice::{or, OrUpgrade}; pub use self::denied::DeniedConnectionUpgrade; pub use self::loop_upg::{loop_upg, Loop}; pub use self::map::map; -pub use self::map_addr::map_with_addr; pub use self::plaintext::PlainTextConfig; pub use self::toggleable::toggleable; pub use self::traits::{ConnectionUpgrade, Endpoint}; diff --git a/core/src/upgrade/plaintext.rs b/core/src/upgrade/plaintext.rs index ceaf179b1a2..ac969853960 100644 --- a/core/src/upgrade/plaintext.rs +++ b/core/src/upgrade/plaintext.rs @@ -32,19 +32,18 @@ use upgrade::{ConnectionUpgrade, Endpoint}; #[derive(Debug, Copy, Clone)] pub struct PlainTextConfig; -impl ConnectionUpgrade for PlainTextConfig +impl ConnectionUpgrade for PlainTextConfig where C: AsyncRead + AsyncWrite, { type Output = C; - type Future = FutureResult<(C, F), IoError>; + type Future = FutureResult; type UpgradeIdentifier = (); - type MultiaddrFuture = F; type NamesIter = iter::Once<(Bytes, ())>; #[inline] - fn upgrade(self, i: C, _: (), _: Endpoint, remote_addr: F) -> Self::Future { - future::ok((i, remote_addr)) + fn upgrade(self, i: C, _: (), _: Endpoint) -> Self::Future { + future::ok(i) } #[inline] diff --git a/core/src/upgrade/toggleable.rs b/core/src/upgrade/toggleable.rs index 33ea8f329e0..5383ca463f9 100644 --- a/core/src/upgrade/toggleable.rs +++ b/core/src/upgrade/toggleable.rs @@ -65,10 +65,10 @@ impl Toggleable { } } -impl ConnectionUpgrade for Toggleable +impl ConnectionUpgrade for Toggleable where C: AsyncRead + AsyncWrite, - U: ConnectionUpgrade, + U: ConnectionUpgrade, { type NamesIter = ToggleableIter; type UpgradeIdentifier = U::UpgradeIdentifier; @@ -82,8 +82,7 @@ where } type Output = U::Output; - type MultiaddrFuture = U::MultiaddrFuture; - type Future = future::Either, U::Future>; + type Future = future::Either, U::Future>; #[inline] fn upgrade( @@ -91,10 +90,9 @@ where socket: C, id: Self::UpgradeIdentifier, ty: Endpoint, - remote_addr: Maf, ) -> Self::Future { if self.enabled { - future::Either::B(self.inner.upgrade(socket, id, ty, remote_addr)) + future::Either::B(self.inner.upgrade(socket, id, ty)) } else { future::Either::A(future::empty()) } diff --git a/core/src/upgrade/traits.rs b/core/src/upgrade/traits.rs index 519992460f2..82efde57b7f 100644 --- a/core/src/upgrade/traits.rs +++ b/core/src/upgrade/traits.rs @@ -50,7 +50,7 @@ impl Not for Endpoint { /// > **Note**: The `upgrade` method of this trait uses `self` and not `&self` or `&mut self`. /// > This has been designed so that you would implement this trait on `&Foo` or /// > `&mut Foo` instead of directly on `Foo`. -pub trait ConnectionUpgrade { +pub trait ConnectionUpgrade { /// Iterator returned by `protocol_names`. type NamesIter: Iterator; /// Type that serves as an identifier for the protocol. This type only exists to be returned @@ -68,10 +68,8 @@ pub trait ConnectionUpgrade { /// > **Note**: For upgrades that add an intermediary layer (such as `secio` or `multiplex`), /// > this associated type must implement `AsyncRead + AsyncWrite`. type Output; - /// Type of the future that will resolve to the remote's multiaddr. - type MultiaddrFuture; /// Type of the future that will resolve to `Self::Output`. - type Future: Future; + type Future: Future; /// This method is called after protocol negotiation has been performed. /// @@ -82,6 +80,5 @@ pub trait ConnectionUpgrade { socket: C, id: Self::UpgradeIdentifier, ty: Endpoint, - remote_addr: TAddrFut, ) -> Self::Future; } diff --git a/muxers/mplex/src/lib.rs b/muxers/mplex/src/lib.rs index 670e11c5bca..2de8c8b9a62 100644 --- a/muxers/mplex/src/lib.rs +++ b/muxers/mplex/src/lib.rs @@ -117,18 +117,17 @@ pub enum MaxBufferBehaviour { Block, } -impl ConnectionUpgrade for MplexConfig +impl ConnectionUpgrade for MplexConfig where C: AsyncRead + AsyncWrite, { type Output = Multiplex; - type MultiaddrFuture = Maf; - type Future = future::FutureResult<(Self::Output, Self::MultiaddrFuture), IoError>; + type Future = future::FutureResult; type UpgradeIdentifier = (); type NamesIter = iter::Once<(Bytes, ())>; #[inline] - fn upgrade(self, i: C, _: (), endpoint: Endpoint, remote_addr: Maf) -> Self::Future { + fn upgrade(self, i: C, _: (), endpoint: Endpoint) -> Self::Future { let max_buffer_len = self.max_buffer_len; let out = Multiplex { @@ -149,7 +148,7 @@ where }) }; - future::ok((out, remote_addr)) + future::ok(out) } #[inline] diff --git a/muxers/mplex/tests/two_peers.rs b/muxers/mplex/tests/two_peers.rs index 7c030fa95a6..26fd1507db4 100644 --- a/muxers/mplex/tests/two_peers.rs +++ b/muxers/mplex/tests/two_peers.rs @@ -52,8 +52,8 @@ fn client_to_server_outbound() { let future = listener .into_future() .map_err(|(err, _)| err) - .and_then(|(client, _)| client.unwrap().map(|v| Arc::new(v.0))) - .and_then(|client| muxing::outbound_from_ref_and_wrap(client)) + .and_then(|(client, _)| client.unwrap().0) + .and_then(|client| muxing::outbound_from_ref_and_wrap(Arc::new(client))) .map(|client| Framed::<_, bytes::BytesMut>::new(client.unwrap())) .and_then(|client| { client @@ -75,7 +75,7 @@ fn client_to_server_outbound() { let future = transport .dial(rx.recv().unwrap()) .unwrap() - .and_then(|client| muxing::inbound_from_ref_and_wrap(Arc::new(client.0))) + .and_then(|client| muxing::inbound_from_ref_and_wrap(Arc::new(client))) .map(|server| Framed::<_, bytes::BytesMut>::new(server.unwrap())) .and_then(|server| server.send("hello world".into())) .map(|_| ()); @@ -102,7 +102,7 @@ fn client_to_server_inbound() { let future = listener .into_future() .map_err(|(err, _)| err) - .and_then(|(client, _)| client.unwrap().map(|v| v.0)) + .and_then(|(client, _)| client.unwrap().0) .and_then(|client| muxing::inbound_from_ref_and_wrap(Arc::new(client))) .map(|client| Framed::<_, bytes::BytesMut>::new(client.unwrap())) .and_then(|client| { @@ -125,7 +125,7 @@ fn client_to_server_inbound() { let future = transport .dial(rx.recv().unwrap()) .unwrap() - .and_then(|(client, _)| muxing::outbound_from_ref_and_wrap(Arc::new(client))) + .and_then(|client| muxing::outbound_from_ref_and_wrap(Arc::new(client))) .map(|server| Framed::<_, bytes::BytesMut>::new(server.unwrap())) .and_then(|server| server.send("hello world".into())) .map(|_| ()); diff --git a/muxers/yamux/src/lib.rs b/muxers/yamux/src/lib.rs index 2b8610c9f75..0ec13430f29 100644 --- a/muxers/yamux/src/lib.rs +++ b/muxers/yamux/src/lib.rs @@ -134,10 +134,9 @@ impl Default for Config { } } -impl core::ConnectionUpgrade for Config +impl core::ConnectionUpgrade for Config where C: AsyncRead + AsyncWrite + 'static, - M: 'static { type UpgradeIdentifier = (); type NamesIter = iter::Once<(Bytes, ())>; @@ -147,15 +146,15 @@ where } type Output = Yamux; - type MultiaddrFuture = M; - type Future = FutureResult<(Yamux, M), io::Error>; + type Future = FutureResult, io::Error>; - fn upgrade(self, i: C, _: (), end: Endpoint, remote: M) -> Self::Future { + fn upgrade(self, i: C, _: (), end: Endpoint) -> Self::Future { let mode = match end { Endpoint::Dialer => yamux::Mode::Client, Endpoint::Listener => yamux::Mode::Server }; - future::ok((Yamux::new(i, self.0, mode), remote)) + + future::ok(Yamux::new(i, self.0, mode)) } } diff --git a/protocols/floodsub/src/lib.rs b/protocols/floodsub/src/lib.rs index 65cb2392d71..c84150bbce1 100644 --- a/protocols/floodsub/src/lib.rs +++ b/protocols/floodsub/src/lib.rs @@ -89,10 +89,9 @@ impl FloodSubUpgrade { } } -impl ConnectionUpgrade for FloodSubUpgrade +impl ConnectionUpgrade for FloodSubUpgrade where C: AsyncRead + AsyncWrite + Send + 'static, - Maf: Future + Send + 'static, { type NamesIter = iter::Once<(Bytes, Self::UpgradeIdentifier)>; type UpgradeIdentifier = (); @@ -103,8 +102,7 @@ where } type Output = FloodSubFuture; - type MultiaddrFuture = future::FutureResult; - type Future = Box + Send>; + type Future = Box + Send>; #[inline] fn upgrade( @@ -112,11 +110,13 @@ where socket: C, _: Self::UpgradeIdentifier, _: Endpoint, - remote_addr: Maf, ) -> Self::Future { debug!("Upgrading connection as floodsub"); - let future = remote_addr.and_then(move |remote_addr| { + let future = { + // FIXME: WRONG + let remote_addr: Multiaddr = "/ip4/127.0.0.1/tcp/5000".parse().unwrap(); + // Whenever a new node connects, we send to it a message containing the topics we are // already subscribed to. let init_msg: Vec = { @@ -168,7 +168,6 @@ where } let inner = self.inner.clone(); - let remote_addr_ret = future::ok(remote_addr.clone()); let future = future::loop_fn( (floodsub_sink, messages), move |(floodsub_sink, messages)| { @@ -215,10 +214,10 @@ where }, ); - future::ok((FloodSubFuture { + future::ok(FloodSubFuture { inner: Box::new(future) as Box<_>, - }, remote_addr_ret)) - }); + }) + }; Box::new(future) as Box<_> } diff --git a/protocols/identify/Cargo.toml b/protocols/identify/Cargo.toml index 365bf0995b6..e055733ea33 100644 --- a/protocols/identify/Cargo.toml +++ b/protocols/identify/Cargo.toml @@ -16,7 +16,9 @@ parking_lot = "0.6" protobuf = "2.0.2" tokio-codec = "0.1" tokio-io = "0.1.0" +tokio-timer = "0.2.6" unsigned-varint = { version = "0.2.1", features = ["codec"] } +void = "1.0" [dev-dependencies] libp2p-tcp-transport = { path = "../../transports/tcp" } diff --git a/protocols/identify/src/lib.rs b/protocols/identify/src/lib.rs index b8fd5ff772b..503bb55cade 100644 --- a/protocols/identify/src/lib.rs +++ b/protocols/identify/src/lib.rs @@ -77,14 +77,12 @@ extern crate parking_lot; extern crate protobuf; extern crate tokio_codec; extern crate tokio_io; +extern crate tokio_timer; extern crate unsigned_varint; +extern crate void; -pub use self::identify_transport::IdentifyTransportOutcome; -pub use self::peer_id_transport::{PeerIdTransport, PeerIdTransportOutput}; pub use self::protocol::{IdentifyInfo, IdentifyOutput}; pub use self::protocol::{IdentifyProtocolConfig, IdentifySender}; -mod identify_transport; -mod peer_id_transport; mod protocol; mod structs_proto; diff --git a/protocols/identify/src/protocol.rs b/protocols/identify/src/protocol.rs index 31506a02ed6..671dbc6bdd1 100644 --- a/protocols/identify/src/protocol.rs +++ b/protocols/identify/src/protocol.rs @@ -20,8 +20,7 @@ use bytes::{Bytes, BytesMut}; use futures::{future, Future, Sink, Stream}; -use libp2p_core::{ConnectionUpgrade, Endpoint, PublicKey}; -use multiaddr::Multiaddr; +use libp2p_core::{ConnectionUpgrade, Endpoint, Multiaddr, PublicKey}; use protobuf::Message as ProtobufMessage; use protobuf::parse_from_bytes as protobuf_parse_from_bytes; use protobuf::RepeatedField; @@ -111,23 +110,21 @@ pub struct IdentifyInfo { pub protocols: Vec, } -impl ConnectionUpgrade for IdentifyProtocolConfig +impl ConnectionUpgrade for IdentifyProtocolConfig where C: AsyncRead + AsyncWrite + Send + 'static, - Maf: Future + Send + 'static, { type NamesIter = iter::Once<(Bytes, Self::UpgradeIdentifier)>; type UpgradeIdentifier = (); type Output = IdentifyOutput; - type MultiaddrFuture = future::Either, Maf>; - type Future = Box + Send>; + type Future = Box + Send>; #[inline] fn protocol_names(&self) -> Self::NamesIter { iter::once((Bytes::from("/ipfs/id/1.0.0"), ())) } - fn upgrade(self, socket: C, _: (), ty: Endpoint, remote_addr: Maf) -> Self::Future { + fn upgrade(self, socket: C, _: (), ty: Endpoint) -> Self::Future { trace!("Upgrading connection as {:?}", ty); let socket = Framed::new(socket, codec::UviBytes::default()); @@ -153,12 +150,10 @@ where trace!("Remote observes us as {:?}", observed_addr); trace!("Information received: {:?}", info); - let out = IdentifyOutput::RemoteInfo { + Ok(IdentifyOutput::RemoteInfo { info, observed_addr: observed_addr.clone(), - }; - - Ok((out, future::Either::A(future::ok(observed_addr)))) + }) } else { debug!("Identify protocol stream closed before receiving info"); Err(IoErrorKind::InvalidData.into()) @@ -170,15 +165,7 @@ where Endpoint::Listener => { let sender = IdentifySender { inner: socket }; - - let future = future::ok({ - let io = IdentifyOutput::Sender { - sender, - }; - - (io, future::Either::B(remote_addr)) - }); - + let future = future::ok(IdentifyOutput::Sender { sender }); Box::new(future) as Box<_> } } @@ -251,7 +238,7 @@ mod tests { let future = listener .into_future() .map_err(|(err, _)| err) - .and_then(|(client, _)| client.unwrap().map(|v| v.0)) + .and_then(|(client, _)| client.unwrap().0) .and_then(|identify| match identify { IdentifyOutput::Sender { sender, .. } => sender.send( IdentifyInfo { @@ -277,7 +264,7 @@ mod tests { let future = transport .dial(rx.recv().unwrap()) .unwrap_or_else(|_| panic!()) - .and_then(|(identify, _)| match identify { + .and_then(|identify| match identify { IdentifyOutput::RemoteInfo { info, observed_addr, diff --git a/protocols/kad/src/kad_server.rs b/protocols/kad/src/kad_server.rs index 2a9c3e4340f..45a7e7c6396 100644 --- a/protocols/kad/src/kad_server.rs +++ b/protocols/kad/src/kad_server.rs @@ -64,7 +64,7 @@ impl KadConnecConfig { } } -impl ConnectionUpgrade for KadConnecConfig +impl ConnectionUpgrade for KadConnecConfig where C: AsyncRead + AsyncWrite + Send + 'static, // TODO: 'static :-/ { @@ -72,22 +72,21 @@ where KadConnecController, Box + Send>, ); - type MultiaddrFuture = Maf; - type Future = future::Map<>::Future, fn((>::Output, Maf)) -> (Self::Output, Maf)>; + type Future = future::Map<>::Future, fn(>::Output) -> Self::Output>; type NamesIter = iter::Once<(Bytes, ())>; type UpgradeIdentifier = (); #[inline] fn protocol_names(&self) -> Self::NamesIter { - ConnectionUpgrade::::protocol_names(&self.raw_proto) + ConnectionUpgrade::::protocol_names(&self.raw_proto) } #[inline] - fn upgrade(self, incoming: C, id: (), endpoint: Endpoint, addr: Maf) -> Self::Future { + fn upgrade(self, incoming: C, id: (), endpoint: Endpoint) -> Self::Future { self.raw_proto - .upgrade(incoming, id, endpoint, addr) - .map:: _, _>(move |(connec, addr)| { - (build_from_sink_stream(connec), addr) + .upgrade(incoming, id, endpoint) + .map:: _, _>(move |connec| { + build_from_sink_stream(connec) }) } } diff --git a/protocols/kad/src/protocol.rs b/protocols/kad/src/protocol.rs index 64120182b34..3ef816486e2 100644 --- a/protocols/kad/src/protocol.rs +++ b/protocols/kad/src/protocol.rs @@ -128,13 +128,12 @@ impl Into for KadPeer { #[derive(Debug, Default, Copy, Clone)] pub struct KademliaProtocolConfig; -impl ConnectionUpgrade for KademliaProtocolConfig +impl ConnectionUpgrade for KademliaProtocolConfig where C: AsyncRead + AsyncWrite + 'static, // TODO: 'static :-/ { type Output = KadStreamSink; - type MultiaddrFuture = Maf; - type Future = future::FutureResult<(Self::Output, Self::MultiaddrFuture), IoError>; + type Future = future::FutureResult; type NamesIter = iter::Once<(Bytes, ())>; type UpgradeIdentifier = (); @@ -144,8 +143,8 @@ where } #[inline] - fn upgrade(self, incoming: C, _: (), _: Endpoint, addr: Maf) -> Self::Future { - future::ok((kademlia_protocol(incoming), addr)) + fn upgrade(self, incoming: C, _: (), _: Endpoint) -> Self::Future { + future::ok(kademlia_protocol(incoming)) } } @@ -489,7 +488,7 @@ mod tests { let future = listener .into_future() .map_err(|(err, _)| err) - .and_then(|(client, _)| client.unwrap().map(|v| v.0)) + .and_then(|(client, _)| client.unwrap().0) .and_then(|proto| proto.into_future().map_err(|(err, _)| err).map(|(v, _)| v)) .map(|recv_msg| { assert_eq!(recv_msg.unwrap(), msg_server); @@ -504,7 +503,7 @@ mod tests { let future = transport .dial(rx.recv().unwrap()) .unwrap_or_else(|_| panic!()) - .and_then(|proto| proto.0.send(msg_client)) + .and_then(|proto| proto.send(msg_client)) .map(|_| ()); let _ = tokio_current_thread::block_on_all(future).unwrap(); diff --git a/protocols/ping/src/lib.rs b/protocols/ping/src/lib.rs index fcb8663daa4..af4092c16e0 100644 --- a/protocols/ping/src/lib.rs +++ b/protocols/ping/src/lib.rs @@ -63,7 +63,7 @@ //! let ping_finished_future = libp2p_tcp_transport::TcpConfig::new() //! .with_upgrade(Ping::default()) //! .dial("127.0.0.1:12345".parse::().unwrap()).unwrap_or_else(|_| panic!()) -//! .and_then(|(out, _)| { +//! .and_then(|out| { //! match out { //! PingOutput::Ponger(processing) => Box::new(processing) as Box + Send>, //! PingOutput::Pinger(mut pinger) => { @@ -123,7 +123,7 @@ pub enum PingOutput { Ponger(PingListener), } -impl ConnectionUpgrade for Ping +impl ConnectionUpgrade for Ping where TSocket: AsyncRead + AsyncWrite, { @@ -136,8 +136,7 @@ where } type Output = PingOutput; - type MultiaddrFuture = Maf; - type Future = FutureResult<(Self::Output, Self::MultiaddrFuture), IoError>; + type Future = FutureResult; #[inline] fn upgrade( @@ -145,14 +144,13 @@ where socket: TSocket, _: Self::UpgradeIdentifier, endpoint: Endpoint, - remote_addr: Maf, ) -> Self::Future { let out = match endpoint { Endpoint::Dialer => upgrade_as_dialer(socket), Endpoint::Listener => upgrade_as_listener(socket), }; - Ok((out, remote_addr)).into_future() + Ok(out).into_future() } } @@ -399,9 +397,8 @@ mod tests { use self::tokio_tcp::TcpListener; use self::tokio_tcp::TcpStream; use super::{Ping, PingOutput}; - use futures::{future, Future, Stream}; - use libp2p_core::{ConnectionUpgrade, Endpoint, Multiaddr}; - use std::io::Error as IoError; + use futures::{Future, Stream}; + use libp2p_core::{ConnectionUpgrade, Endpoint}; // TODO: rewrite tests with the MemoryTransport @@ -419,10 +416,9 @@ mod tests { c.unwrap(), (), Endpoint::Listener, - future::ok::("/ip4/127.0.0.1/tcp/10000".parse().unwrap()), ) }) - .and_then(|(out, _)| match out { + .and_then(|out| match out { PingOutput::Ponger(service) => service, _ => unreachable!(), }); @@ -434,10 +430,9 @@ mod tests { c, (), Endpoint::Dialer, - future::ok::("/ip4/127.0.0.1/tcp/10000".parse().unwrap()), ) }) - .and_then(|(out, _)| match out { + .and_then(|out| match out { PingOutput::Pinger(mut pinger) => { pinger.ping(()); pinger.into_future().map(|_| ()).map_err(|_| panic!()) @@ -464,10 +459,9 @@ mod tests { c.unwrap(), (), Endpoint::Listener, - future::ok::("/ip4/127.0.0.1/tcp/10000".parse().unwrap()), ) }) - .and_then(|(out, _)| match out { + .and_then(|out| match out { PingOutput::Ponger(service) => service, _ => unreachable!(), }); @@ -479,10 +473,9 @@ mod tests { c, (), Endpoint::Dialer, - future::ok::("/ip4/127.0.0.1/tcp/10000".parse().unwrap()), ) }) - .and_then(|(out, _)| match out { + .and_then(|out| match out { PingOutput::Pinger(mut pinger) => { for n in 0..20 { pinger.ping(n); diff --git a/protocols/secio/src/lib.rs b/protocols/secio/src/lib.rs index a7a61756872..8ec9991ac78 100644 --- a/protocols/secio/src/lib.rs +++ b/protocols/secio/src/lib.rs @@ -58,7 +58,7 @@ //! //! let future = transport.dial("/ip4/127.0.0.1/tcp/12345".parse::().unwrap()) //! .unwrap_or_else(|_| panic!("Unable to dial node")) -//! .and_then(|(connection, _)| { +//! .and_then(|connection| { //! // Sends "hello world" on the connection, will be encrypted. //! write_all(connection, "hello world") //! }); @@ -349,14 +349,12 @@ where pub ephemeral_public_key: Vec, } -impl libp2p_core::ConnectionUpgrade for SecioConfig +impl libp2p_core::ConnectionUpgrade for SecioConfig where S: AsyncRead + AsyncWrite + Send + 'static, // TODO: 'static :( - Maf: Send + 'static, // TODO: 'static :( { type Output = SecioOutput; - type MultiaddrFuture = Maf; - type Future = Box + Send>; + type Future = Box + Send>; type NamesIter = iter::Once<(Bytes, ())>; type UpgradeIdentifier = (); @@ -371,7 +369,6 @@ where incoming: S, _: (), _: libp2p_core::Endpoint, - remote_addr: Maf, ) -> Self::Future { debug!("Starting secio upgrade"); @@ -384,7 +381,7 @@ where ephemeral_public_key: ephemeral, } }).map_err(map_err); - Box::new(wrapped.map(move |out| (out, remote_addr))) + Box::new(wrapped) } } diff --git a/src/lib.rs b/src/lib.rs index 2d81fb74bda..b43f807192f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -212,7 +212,6 @@ impl CommonTransport { impl Transport for CommonTransport { type Output = ::Output; - type MultiaddrFuture = ::MultiaddrFuture; type Listener = ::Listener; type ListenerUpgrade = ::ListenerUpgrade; type Dial = ::Dial; diff --git a/src/simple.rs b/src/simple.rs index f640af86f1a..42dbd789eaa 100644 --- a/src/simple.rs +++ b/src/simple.rs @@ -57,13 +57,12 @@ impl Clone for SimpleProtocol { } } -impl ConnectionUpgrade for SimpleProtocol +impl ConnectionUpgrade for SimpleProtocol where C: AsyncRead + AsyncWrite, F: Fn(C) -> O, O: IntoFuture, O::Future: Send + 'static, - Maf: Send + 'static, { type NamesIter = iter::Once<(Bytes, ())>; type UpgradeIdentifier = (); @@ -74,13 +73,12 @@ where } type Output = O::Item; - type MultiaddrFuture = Maf; - type Future = Box + Send>; + type Future = Box + Send>; #[inline] - fn upgrade(self, socket: C, _: (), _: Endpoint, client_addr: Maf) -> Self::Future { + fn upgrade(self, socket: C, _: (), _: Endpoint) -> Self::Future { let upgrade = &self.upgrade; - let fut = upgrade(socket).into_future().from_err().map(move |out| (out, client_addr)); + let fut = upgrade(socket).into_future().from_err(); Box::new(fut) as Box<_> } } diff --git a/transports/dns/src/lib.rs b/transports/dns/src/lib.rs index d0e63796f98..9b7948ac2ee 100644 --- a/transports/dns/src/lib.rs +++ b/transports/dns/src/lib.rs @@ -98,10 +98,9 @@ where T::Dial: Send, { type Output = T::Output; - type MultiaddrFuture = T::MultiaddrFuture; type Listener = T::Listener; type ListenerUpgrade = T::ListenerUpgrade; - type Dial = Box + Send>; + type Dial = Box + Send>; #[inline] fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { @@ -227,9 +226,9 @@ mod tests { extern crate libp2p_tcp_transport; use self::libp2p_tcp_transport::TcpConfig; use futures::future; + use swarm::Transport; use multiaddr::{Protocol, Multiaddr}; use std::io::Error as IoError; - use swarm::Transport; use DnsConfig; #[test] @@ -238,10 +237,9 @@ mod tests { struct CustomTransport; impl Transport for CustomTransport { type Output = ::Output; - type MultiaddrFuture = ::MultiaddrFuture; type Listener = ::Listener; type ListenerUpgrade = ::ListenerUpgrade; - type Dial = future::Empty<(Self::Output, Self::MultiaddrFuture), IoError>; + type Dial = future::Empty; #[inline] fn listen_on( diff --git a/transports/ratelimit/src/lib.rs b/transports/ratelimit/src/lib.rs index 9fc86a240f4..215806a5503 100644 --- a/transports/ratelimit/src/lib.rs +++ b/transports/ratelimit/src/lib.rs @@ -119,16 +119,16 @@ impl AsyncWrite for Connection { pub struct Listener(RateLimited); impl Stream for Listener { - type Item = ListenerUpgrade; + type Item = (ListenerUpgrade, Multiaddr); type Error = io::Error; fn poll(&mut self) -> Poll, Self::Error> { match try_ready!(self.0.value.poll()) { - Some(upgrade) => { + Some((upgrade, addr)) => { let r = self.0.rlimiter.clone(); let w = self.0.wlimiter.clone(); let u = ListenerUpgrade(RateLimited::from_parts(upgrade, r, w)); - Ok(Async::Ready(Some(u))) + Ok(Async::Ready(Some((u, addr)))) } None => Ok(Async::Ready(None)), } @@ -143,14 +143,14 @@ where T: Transport + 'static, T::Output: AsyncRead + AsyncWrite, { - type Item = (Connection, T::MultiaddrFuture); + type Item = Connection; type Error = io::Error; fn poll(&mut self) -> Poll { - let (conn, addr) = try_ready!(self.0.value.poll()); + let conn = try_ready!(self.0.value.poll()); let r = self.0.rlimiter.clone(); let w = self.0.wlimiter.clone(); - Ok(Async::Ready((Connection::new(conn, r, w)?, addr))) + Ok(Async::Ready(Connection::new(conn, r, w)?)) } } @@ -158,14 +158,12 @@ impl Transport for RateLimited where T: Transport + 'static, T::Dial: Send, - T::MultiaddrFuture: Send, T::Output: AsyncRead + AsyncWrite + Send, { type Output = Connection; - type MultiaddrFuture = T::MultiaddrFuture; type Listener = Listener; type ListenerUpgrade = ListenerUpgrade; - type Dial = Box, Self::MultiaddrFuture), Error = io::Error> + Send>; + type Dial = Box, Error = io::Error> + Send>; fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> where @@ -197,7 +195,7 @@ where .dial(addr) .map(move |dial| { let future = dial - .and_then(move |(conn, addr)| Ok((Connection::new(conn, r, w)?, addr))); + .and_then(move |conn| Ok(Connection::new(conn, r, w)?)); Box::new(future) as Box<_> }) .map_err(|(transport, a)| (RateLimited::from_parts(transport, r2, w2), a)) diff --git a/transports/relay/src/protocol.rs b/transports/relay/src/protocol.rs index b08ba98115e..984ce4d764d 100644 --- a/transports/relay/src/protocol.rs +++ b/transports/relay/src/protocol.rs @@ -49,18 +49,16 @@ pub enum Output { Sealed(Box + Send>) } -impl ConnectionUpgrade for RelayConfig +impl ConnectionUpgrade for RelayConfig where C: AsyncRead + AsyncWrite + Send + 'static, T: Transport + Clone + Send + 'static, T::Dial: Send, T::Listener: Send, T::ListenerUpgrade: Send, - T::MultiaddrFuture: Send, T::Output: AsyncRead + AsyncWrite + Send, P: Deref + Clone + Send + 'static, S: 'static, - Maf: Send + 'static, for<'a> &'a S: Peerstore { type NamesIter = iter::Once<(Bytes, Self::UpgradeIdentifier)>; @@ -71,10 +69,9 @@ where } type Output = Output; - type MultiaddrFuture = Maf; - type Future = Box + Send>; + type Future = Box + Send>; - fn upgrade(self, conn: C, _: (), _: Endpoint, remote_addr: Maf) -> Self::Future { + fn upgrade(self, conn: C, _: (), _: Endpoint) -> Self::Future { let future = Io::new(conn).recv().and_then(move |(message, io)| { let msg = if let Some(m) = message { m @@ -95,7 +92,7 @@ where } } }); - Box::new(future.map(move |out| (out, remote_addr))) + Box::new(future) } } @@ -105,7 +102,6 @@ where T::Dial: Send, // TODO: remove T::Listener: Send, // TODO: remove T::ListenerUpgrade: Send, // TODO: remove - T::MultiaddrFuture: Send, // TODO: remove T::Output: Send + AsyncRead + AsyncWrite, P: Deref + Clone + 'static, for<'a> &'a S: Peerstore, @@ -158,7 +154,7 @@ where .into_future() .map_err(|(err, _stream)| err) .and_then(move |(ok, _stream)| { - if let Some((c, a)) = ok { + if let Some(c) = ok { // send STOP message to destination and expect back a SUCCESS message let future = Io::new(c).send(stop) .and_then(Io::recv) @@ -168,7 +164,7 @@ where None => return Err(io_err("no message from destination")) }; if is_success(&rsp) { - Ok((io.into(), a)) + Ok(io.into()) } else { Err(io_err("no success response from relay")) } @@ -181,7 +177,7 @@ where // signal success or failure to source .then(move |result| { match result { - Ok((c, _)) => { + Ok(c) => { let msg = status(CircuitRelay_Status::SUCCESS); A(io.send(msg).map(|io| (io.into(), c))) } @@ -251,7 +247,7 @@ fn stop_message(from: &Peer, dest: &Peer) -> CircuitRelay { #[derive(Debug, Clone)] struct TrivialUpgrade; -impl ConnectionUpgrade for TrivialUpgrade +impl ConnectionUpgrade for TrivialUpgrade where C: AsyncRead + AsyncWrite + 'static { @@ -263,21 +259,19 @@ where } type Output = C; - type MultiaddrFuture = Maf; - type Future = FutureResult<(Self::Output, Maf), io::Error>; + type Future = FutureResult; - fn upgrade(self, conn: C, _: (), _: Endpoint, remote_addr: Maf) -> Self::Future { - future::ok((conn, remote_addr)) + fn upgrade(self, conn: C, _: (), _: Endpoint) -> Self::Future { + future::ok(conn) } } #[derive(Debug, Clone)] pub(crate) struct Source(pub(crate) CircuitRelay); -impl ConnectionUpgrade for Source +impl ConnectionUpgrade for Source where C: AsyncRead + AsyncWrite + Send + 'static, - Maf: Send + 'static, { type NamesIter = iter::Once<(Bytes, Self::UpgradeIdentifier)>; type UpgradeIdentifier = (); @@ -287,10 +281,9 @@ where } type Output = C; - type MultiaddrFuture = Maf; - type Future = Box + Send>; + type Future = Box + Send>; - fn upgrade(self, conn: C, _: (), _: Endpoint, remote_addr: Maf) -> Self::Future { + fn upgrade(self, conn: C, _: (), _: Endpoint) -> Self::Future { let future = Io::new(conn) .send(self.0) .and_then(Io::recv) @@ -305,7 +298,7 @@ where Err(io_err("no success response from relay")) } }); - Box::new(future.map(move |out| (out, remote_addr))) + Box::new(future) } } diff --git a/transports/relay/src/transport.rs b/transports/relay/src/transport.rs index fe2c8b95b84..0e216b8506d 100644 --- a/transports/relay/src/transport.rs +++ b/transports/relay/src/transport.rs @@ -43,17 +43,15 @@ where T::Dial: Send, T::Listener: Send, T::ListenerUpgrade: Send, - T::MultiaddrFuture: Send, T::Output: AsyncRead + AsyncWrite + Send, P: Deref + Clone + 'static, S: 'static, for<'a> &'a S: Peerstore { type Output = T::Output; - type MultiaddrFuture = T::MultiaddrFuture; - type Listener = Box + Send>; - type ListenerUpgrade = Box + Send>; - type Dial = Box + Send>; + type Listener = Box + Send>; + type ListenerUpgrade = Box + Send>; + type Dial = Box + Send>; fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { Err((self, addr)) @@ -92,7 +90,6 @@ where T::Dial: Send, T::Listener: Send, T::ListenerUpgrade: Send, - T::MultiaddrFuture: Send, T::Output: AsyncRead + AsyncWrite + Send, P: Deref + Clone + 'static, for<'a> &'a S: Peerstore @@ -114,7 +111,7 @@ where } // Relay to destination over any available relay node. - fn relay_to(self, destination: &Peer) -> Result, Self> { + fn relay_to(self, destination: &Peer) -> Result, Self> { trace!("relay_to {:?}", destination.id); let mut dials = Vec::new(); for relay in &*self.relays { @@ -152,7 +149,7 @@ where } // Relay to destination via the given peer. - fn relay_via(self, relay: &Peer, destination: &Peer) -> Result, Self> { + fn relay_via(self, relay: &Peer, destination: &Peer) -> Result, Self> { trace!("relay_via {:?} to {:?}", relay.id, destination.id); let mut addresses = Vec::new(); @@ -183,9 +180,9 @@ where .into_future() .map_err(|(err, _stream)| err) .and_then(move |(ok, _stream)| match ok { - Some((out, addr)) => { + Some(out) => { debug!("connected"); - Ok((out, addr)) + Ok(out) } None => { info!("failed to dial to {:?}", relay.id); diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index 01f8498fa35..2064003eb39 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -134,8 +134,7 @@ impl TcpConfig { impl Transport for TcpConfig { type Output = TcpTransStream; type Listener = TcpListenStream; - type ListenerUpgrade = FutureResult<(Self::Output, Self::MultiaddrFuture), IoError>; - type MultiaddrFuture = FutureResult; + type ListenerUpgrade = FutureResult; type Dial = TcpDialFut; fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { @@ -181,7 +180,6 @@ impl Transport for TcpConfig { Ok(TcpDialFut { inner: TcpStream::connect(&socket_addr), config: self, - addr: Some(addr), }) } else { debug!("Instantly refusing dialing {}, as it is invalid", addr); @@ -260,32 +258,21 @@ pub struct TcpDialFut { inner: ConnectFuture, /// Original configuration. config: TcpConfig, - /// Address we're dialing. Extracted when the `Future` finishes. - addr: Option, } impl Future for TcpDialFut { - type Item = (TcpTransStream, FutureResult); + type Item = TcpTransStream; type Error = IoError; - fn poll(&mut self) -> Poll<(TcpTransStream, FutureResult), IoError> { + fn poll(&mut self) -> Poll { match self.inner.poll() { Ok(Async::Ready(stream)) => { apply_config(&self.config, &stream)?; - let addr = self - .addr - .take() - .expect("TcpDialFut polled again after finished"); - let out = TcpTransStream { inner: stream }; - Ok(Async::Ready((out, future::ok(addr)))) + Ok(Async::Ready(TcpTransStream { inner: stream })) } Ok(Async::NotReady) => Ok(Async::NotReady), Err(err) => { - let addr = self - .addr - .as_ref() - .expect("TcpDialFut polled again after finished"); - debug!("Error while dialing {:?} => {:?}", addr, err); + debug!("Error while dialing => {:?}", err); Err(err) } } @@ -300,13 +287,13 @@ pub struct TcpListenStream { } impl Stream for TcpListenStream { - type Item = FutureResult<(TcpTransStream, FutureResult), IoError>; + type Item = (FutureResult, Multiaddr); type Error = IoError; fn poll( &mut self, ) -> Poll< - Option), IoError>>, + Option<(FutureResult, Multiaddr)>, IoError, > { let inner = match self.inner { @@ -316,28 +303,36 @@ impl Stream for TcpListenStream { } }; - match inner.poll() { - Ok(Async::Ready(Some(sock))) => { - match apply_config(&self.config, &sock) { - Ok(()) => (), - Err(err) => return Ok(Async::Ready(Some(future::err(err)))), - }; - - let addr = match sock.peer_addr() { - // TODO: remove this expect() - Ok(addr) => addr - .to_multiaddr() - .expect("generating a multiaddr from a socket addr never fails"), - Err(err) => return Ok(Async::Ready(Some(future::err(err)))), - }; - - debug!("Incoming connection from {}", addr); - let ret = future::ok((TcpTransStream { inner: sock }, future::ok(addr))); - Ok(Async::Ready(Some(ret))) + loop { + match inner.poll() { + Ok(Async::Ready(Some(sock))) => { + let addr = match sock.peer_addr() { + // TODO: remove this expect() + Ok(addr) => addr + .to_multiaddr() + .expect("generating a multiaddr from a socket addr never fails"), + Err(err) => { + // If we can't get the address of the newly-opened socket, there's + // nothing we can except ignore this connection attempt. + error!("Ignored incoming because could't determine its \ + address: {:?}", err); + continue + }, + }; + + match apply_config(&self.config, &sock) { + Ok(()) => (), + Err(err) => return Ok(Async::Ready(Some((future::err(err), addr)))), + }; + + debug!("Incoming connection from {}", addr); + let ret = future::ok(TcpTransStream { inner: sock }); + break Ok(Async::Ready(Some((ret, addr)))) + } + Ok(Async::Ready(None)) => break Ok(Async::Ready(None)), + Ok(Async::NotReady) => break Ok(Async::NotReady), + Err(()) => unreachable!("sleep_on_error never produces an error"), } - Ok(Async::Ready(None)) => Ok(Async::Ready(None)), - Ok(Async::NotReady) => Ok(Async::NotReady), - Err(()) => unreachable!("sleep_on_error never produces an error"), } } } @@ -465,8 +460,8 @@ mod tests { std::thread::spawn(move || { let addr = "/ip4/127.0.0.1/tcp/12345".parse::().unwrap(); let tcp = TcpConfig::new(); - let listener = tcp.listen_on(addr).unwrap().0.for_each(|sock| { - sock.and_then(|(sock, _)| { + let listener = tcp.listen_on(addr).unwrap().0.for_each(|(sock, _)| { + sock.and_then(|sock| { // Define what to do with the socket that just connected to us // Which in this case is read 3 bytes let handle_conn = tokio_io::io::read_exact(sock, [0; 3]) @@ -489,7 +484,7 @@ mod tests { let socket = tcp.dial(addr.clone()).unwrap(); // Define what to do with the socket once it's obtained let action = socket.then(|sock| -> Result<(), ()> { - sock.unwrap().0.write(&[0x1, 0x2, 0x3]).unwrap(); + sock.unwrap().write(&[0x1, 0x2, 0x3]).unwrap(); Ok(()) }); // Execute the future in our event loop diff --git a/transports/timeout/src/lib.rs b/transports/timeout/src/lib.rs index 1d2f7a8160f..fa0b39c5141 100644 --- a/transports/timeout/src/lib.rs +++ b/transports/timeout/src/lib.rs @@ -31,7 +31,7 @@ extern crate log; extern crate tokio_timer; use futures::{Async, Future, Poll, Stream}; -use libp2p_core::{Multiaddr, MuxedTransport, Transport}; +use libp2p_core::{Multiaddr, Transport}; use std::io::{Error as IoError, ErrorKind as IoErrorKind}; use std::time::Duration; use tokio_timer::Timeout; @@ -85,7 +85,6 @@ where InnerTrans: Transport, { type Output = InnerTrans::Output; - type MultiaddrFuture = InnerTrans::MultiaddrFuture; type Listener = TimeoutListener; type ListenerUpgrade = TokioTimerMapErr>; type Dial = TokioTimerMapErr>; @@ -135,22 +134,6 @@ where } } -impl MuxedTransport for TransportTimeout -where - InnerTrans: MuxedTransport, -{ - type Incoming = TimeoutIncoming; - type IncomingUpgrade = TokioTimerMapErr>; - - #[inline] - fn next_incoming(self) -> Self::Incoming { - TimeoutIncoming { - inner: self.inner.next_incoming(), - timeout: self.incoming_timeout, - } - } -} - // TODO: can be removed and replaced with an `impl Stream` once impl Trait is fully stable // in Rust (https://github.com/rust-lang/rust/issues/34511) pub struct TimeoutListener { @@ -158,50 +141,26 @@ pub struct TimeoutListener { timeout: Duration, } -impl Stream for TimeoutListener +impl Stream for TimeoutListener where - InnerStream: Stream, + InnerStream: Stream, { - type Item = TokioTimerMapErr>; + type Item = (TokioTimerMapErr>, Multiaddr); type Error = InnerStream::Error; fn poll(&mut self) -> Poll, Self::Error> { - let inner_fut = try_ready!(self.inner.poll()); - if let Some(inner_fut) = inner_fut { + let poll_out = try_ready!(self.inner.poll()); + if let Some((inner_fut, addr)) = poll_out { let fut = TokioTimerMapErr { inner: Timeout::new(inner_fut, self.timeout), }; - Ok(Async::Ready(Some(fut))) + Ok(Async::Ready(Some((fut, addr)))) } else { Ok(Async::Ready(None)) } } } -// TODO: can be removed and replaced with an `impl Future` once impl Trait is fully stable -// in Rust (https://github.com/rust-lang/rust/issues/34511) -#[must_use = "futures do nothing unless polled"] -pub struct TimeoutIncoming { - inner: InnerFut, - timeout: Duration, -} - -impl Future for TimeoutIncoming -where - InnerFut: Future, -{ - type Item = TokioTimerMapErr>; - type Error = InnerFut::Error; - - fn poll(&mut self) -> Poll { - let inner_fut = try_ready!(self.inner.poll()); - let fut = TokioTimerMapErr { - inner: Timeout::new(inner_fut, self.timeout), - }; - Ok(Async::Ready(fut)) - } -} - /// Wraps around a `Future`. Turns the error type from `TimeoutError` to `IoError`. // TODO: can be replaced with `impl Future` once `impl Trait` are fully stable in Rust // (https://github.com/rust-lang/rust/issues/34511) diff --git a/transports/uds/src/lib.rs b/transports/uds/src/lib.rs index c2b76e11b62..c326fa9f7d3 100644 --- a/transports/uds/src/lib.rs +++ b/transports/uds/src/lib.rs @@ -86,10 +86,9 @@ impl UdsConfig { impl Transport for UdsConfig { type Output = UnixStream; - type Listener = Box + Send + Sync>; - type ListenerUpgrade = FutureResult<(Self::Output, Self::MultiaddrFuture), IoError>; - type MultiaddrFuture = FutureResult; - type Dial = Box + Send + Sync>; + type Listener = Box + Send + Sync>; + type ListenerUpgrade = FutureResult; + type Dial = Box + Send + Sync>; // TODO: name this type fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { if let Ok(path) = multiaddr_to_path(&addr) { @@ -109,7 +108,7 @@ impl Transport for UdsConfig { // Pull out a stream of sockets for incoming connections listener.incoming().map(move |sock| { debug!("Incoming connection on {}", addr); - future::ok((sock, future::ok(addr.clone()))) + (future::ok(sock), addr.clone()) }) }) .flatten_stream(); @@ -122,7 +121,7 @@ impl Transport for UdsConfig { fn dial(self, addr: Multiaddr) -> Result { if let Ok(path) = multiaddr_to_path(&addr) { debug!("Dialing {}", addr); - let fut = UnixStream::connect(&path).map(|t| (t, future::ok(addr))); + let fut = UnixStream::connect(&path); Ok(Box::new(fut) as Box<_>) } else { Err((self, addr)) @@ -203,8 +202,8 @@ mod tests { std::thread::spawn(move || { let tcp = UdsConfig::new(); - let listener = tcp.listen_on(addr2).unwrap().0.for_each(|sock| { - sock.and_then(|(sock, _)| { + let listener = tcp.listen_on(addr2).unwrap().0.for_each(|(sock, _)| { + sock.and_then(|sock| { // Define what to do with the socket that just connected to us // Which in this case is read 3 bytes let handle_conn = tokio_io::io::read_exact(sock, [0; 3]) @@ -226,7 +225,7 @@ mod tests { let socket = tcp.dial(addr.clone()).unwrap(); // Define what to do with the socket once it's obtained let action = socket.then(|sock| -> Result<(), ()> { - sock.unwrap().0.write(&[0x1, 0x2, 0x3]).unwrap(); + sock.unwrap().write(&[0x1, 0x2, 0x3]).unwrap(); Ok(()) }); // Execute the future in our event loop diff --git a/transports/websocket/src/browser.rs b/transports/websocket/src/browser.rs index e62a69c18f6..d646c8a2e6a 100644 --- a/transports/websocket/src/browser.rs +++ b/transports/websocket/src/browser.rs @@ -20,7 +20,7 @@ use futures::stream::Then as StreamThen; use futures::sync::{mpsc, oneshot}; -use futures::{future, future::FutureResult, Async, Future, Poll, Stream}; +use futures::{Async, Future, Poll, Stream}; use multiaddr::{Protocol, Multiaddr}; use rw_stream_sink::RwStreamSink; use std::io::{Error as IoError, ErrorKind as IoErrorKind}; @@ -53,11 +53,9 @@ impl BrowserWsConfig { impl Transport for BrowserWsConfig { type Output = BrowserWsConn; - type MultiaddrFuture = FutureResult; - type Listener = Box + Send>; // TODO: use `!` - type ListenerUpgrade = - Box + Send>; // TODO: use `!` - type Dial = Box + Send>; + type Listener = Box + Send>; // TODO: use `!` + type ListenerUpgrade = Box + Send>; // TODO: use `!` + type Dial = Box + Send>; #[inline] fn listen_on(self, a: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { @@ -196,7 +194,7 @@ impl Transport for BrowserWsConfig { Ok(Box::new(open_rx.then(|result| { match result { - Ok(Ok(r)) => Ok((r, future::ok(original_addr))), + Ok(Ok(r)) => Ok(r), Ok(Err(e)) => Err(e), // `Err` would happen here if `open_tx` is destroyed. `open_tx` is captured by // the `WebSocket`, and the `WebSocket` is captured by `open_cb`, which is itself diff --git a/transports/websocket/src/desktop.rs b/transports/websocket/src/desktop.rs index a86d46361ba..14275074d60 100644 --- a/transports/websocket/src/desktop.rs +++ b/transports/websocket/src/desktop.rs @@ -60,19 +60,16 @@ where // TODO: this 'static is pretty arbitrary and is necessary because of the websocket library T: Transport + 'static, T::Dial: Send, - T::MultiaddrFuture: Send, T::Listener: Send, T::ListenerUpgrade: Send, // TODO: this Send is pretty arbitrary and is necessary because of the websocket library T::Output: AsyncRead + AsyncWrite + Send, { type Output = Box; - type MultiaddrFuture = Box + Send>; type Listener = - stream::Map::ListenerUpgrade) -> Self::ListenerUpgrade>; - type ListenerUpgrade = - Box + Send>; - type Dial = Box + Send>; + stream::Map::ListenerUpgrade, Multiaddr)) -> (Self::ListenerUpgrade, Multiaddr)>; + type ListenerUpgrade = Box + Send>; + type Dial = Box + Send>; fn listen_on( self, @@ -102,14 +99,12 @@ where debug!("Listening on {}", new_addr); - let listen = inner_listen.map::<_, fn(_) -> _>(|stream| { + let listen = inner_listen.map::<_, fn(_) -> _>(|(stream, mut client_addr)| { + // Need to suffix `/ws` to each client address. + client_addr.append(Protocol::Ws); + // Upgrade the listener to websockets like the websockets library requires us to do. - let upgraded = stream.and_then(|(stream, client_addr)| { - // Need to suffix `/ws` to each client address. - let client_addr = client_addr.map(|mut addr| { - addr.append(Protocol::Ws); - addr - }); + let upgraded = stream.and_then(move |stream| { debug!("Incoming connection"); stream @@ -149,10 +144,9 @@ where .map(|s| Box::new(Ok(s).into_future()) as Box + Send>) .into_future() .flatten() - .map(move |v| (v, Box::new(client_addr) as Box + Send>)) }); - Box::new(upgraded) as Box + Send> + (Box::new(upgraded) as Box + Send>, client_addr) }); Ok((listen, new_addr)) @@ -194,16 +188,7 @@ where let dial = inner_dial .into_future() - .and_then(move |(connec, client_addr)| { - let client_addr = Box::new(client_addr.map(move |mut addr| { - if is_wss { - addr.append(Protocol::Wss); - } else { - addr.append(Protocol::Ws); - }; - addr - })) as Box + Send>; - + .and_then(move |connec| { ClientBuilder::new(&ws_addr) .expect("generated ws address is always valid") .async_connect_on(connec) @@ -229,7 +214,6 @@ where let read_write = RwStreamSink::new(framed_data); Box::new(read_write) as Box }) - .map(move |c| (c, client_addr)) }); Ok(Box::new(dial) as Box<_>) @@ -294,8 +278,8 @@ mod tests { let listener = listener .into_future() .map_err(|(e, _)| e) - .and_then(|(c, _)| c.unwrap().map(|v| v.0)); - let dialer = ws_config.clone().dial(addr).unwrap().map(|v| v.0); + .and_then(|(c, _)| c.unwrap().0); + let dialer = ws_config.clone().dial(addr).unwrap(); let future = listener .select(dialer) @@ -317,8 +301,8 @@ mod tests { let listener = listener .into_future() .map_err(|(e, _)| e) - .and_then(|(c, _)| c.unwrap().map(|v| v.0)); - let dialer = ws_config.clone().dial(addr).unwrap().map(|v| v.0); + .and_then(|(c, _)| c.unwrap().0); + let dialer = ws_config.clone().dial(addr).unwrap(); let future = listener .select(dialer) From 840663e181fa75e65f22f6722e5dc5444e969401 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 17 Oct 2018 12:26:42 +0100 Subject: [PATCH 06/19] Remove two unused files (#567) --- core/src/swarm.rs | 569 --------------------------------- core/src/unique.rs | 759 --------------------------------------------- 2 files changed, 1328 deletions(-) delete mode 100644 core/src/swarm.rs delete mode 100644 core/src/unique.rs diff --git a/core/src/swarm.rs b/core/src/swarm.rs deleted file mode 100644 index f7d95ee56ef..00000000000 --- a/core/src/swarm.rs +++ /dev/null @@ -1,569 +0,0 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -use futures::stream::StreamFuture; -use futures::sync::oneshot; -use futures::{Async, Future, IntoFuture, Poll, Stream}; -use futures::task; -use parking_lot::Mutex; -use std::fmt; -use std::io::{Error as IoError, ErrorKind as IoErrorKind}; -use std::sync::Arc; -use {Multiaddr, MuxedTransport, Transport}; - -/// Creates a swarm. -/// -/// Requires an upgraded transport, and a function or closure that will turn the upgrade into a -/// `Future` that produces a `()`. -/// -/// Produces a `SwarmController` and an implementation of `Future`. The controller can be used to -/// control, and the `Future` must be driven to completion in order for things to work. -pub fn swarm( - transport: T, - handler: H, -) -> (SwarmController, SwarmEvents) -where - T: MuxedTransport + Clone + 'static, // TODO: 'static :-/ - H: FnMut(T::Output, Box + Send>) -> F, - F: IntoFuture, -{ - let shared = Arc::new(Mutex::new(Shared { - next_incoming: transport.clone().next_incoming(), - listeners: Vec::new(), - listeners_upgrade: Vec::new(), - dialers: Vec::new(), - to_process: Vec::new(), - task_to_notify: None, - })); - - let future = SwarmEvents { - transport: transport.clone(), - shared: shared.clone(), - handler: handler, - }; - - let controller = SwarmController { - transport, - shared, - }; - - (controller, future) -} - -/// Allows control of what the swarm is doing. -pub struct SwarmController -where - T: MuxedTransport + 'static, // TODO: 'static :-/ -{ - /// Shared between the swarm infrastructure. - shared: Arc>>, - - /// Transport used to dial or listen. - transport: T, -} - -impl fmt::Debug for SwarmController -where - T: fmt::Debug + MuxedTransport + 'static, // TODO: 'static :-/ -{ - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_tuple("SwarmController") - .field(&self.transport) - .finish() - } -} - -impl Clone for SwarmController -where - T: MuxedTransport + Clone + 'static, // TODO: 'static :-/ -{ - fn clone(&self) -> Self { - SwarmController { - transport: self.transport.clone(), - shared: self.shared.clone(), - } - } -} - -impl SwarmController -where - T: MuxedTransport + Clone + 'static, // TODO: 'static :-/ - T::Dial: Send, - T::MultiaddrFuture: Send, - T::Listener: Send, - T::ListenerUpgrade: Send, - T::Output: Send, - F: 'static, -{ - /// Asks the swarm to dial the node with the given multiaddress. The connection is then - /// upgraded using the `upgrade`, and the output is sent to the handler that was passed when - /// calling `swarm`. - /// - /// Returns a future that is signalled once the closure in the `swarm` has returned its future. - /// Therefore if the closure in the swarm has some side effect (eg. write something in a - /// variable), this side effect will be observable when this future succeeds. - #[inline] - pub fn dial(&self, multiaddr: Multiaddr, transport: Du) - -> Result, Multiaddr> - where - Du: Transport + 'static, // TODO: 'static :-/ - Du::Dial: Send, - Du::MultiaddrFuture: Send, - Du::Output: Into, - { - self.dial_then(multiaddr, transport, |v| v) - } - - /// Internal version of `dial` that allows adding a closure that is called after either the - /// dialing fails or the handler has been called with the resulting future. - /// - /// The returned future is filled with the output of `then`. - pub(crate) fn dial_then(&self, multiaddr: Multiaddr, transport: Du, then: TThen) - -> Result, Multiaddr> - where - Du: Transport + 'static, // TODO: 'static :-/ - Du::Dial: Send, - Du::MultiaddrFuture: Send, - Du::Output: Into, - TThen: FnOnce(Result<(), IoError>) -> Result<(), IoError> + Send + 'static, - { - trace!("Swarm dialing {}", multiaddr); - - match transport.dial(multiaddr.clone()) { - Ok(dial) => { - let (tx, rx) = oneshot::channel(); - let mut then = Some(move |val| { - let _ = tx.send(then(val)); - }); - // Unfortunately the `Box` type is still unusable in Rust right now, - // so we use a `Box` instead and panic if it is called multiple times. - let mut then = Box::new(move |val: Result<(), IoError>| { - let then = then.take().expect("The Boxed FnMut should only be called once"); - then(val); - }) as Box; - - let dial = dial.then(|result| { - match result { - Ok((output, client_addr)) => { - let client_addr = Box::new(client_addr) as Box + Send>; - Ok((output.into(), then, client_addr)) - } - Err(err) => { - debug!("Error in dialer upgrade: {:?}", err); - let err_clone = IoError::new(err.kind(), err.to_string()); - then(Err(err)); - Err(err_clone) - } - } - }); - - let mut shared = self.shared.lock(); - shared.dialers.push((multiaddr, Box::new(dial) as Box<_>)); - if let Some(task) = shared.task_to_notify.take() { - task.notify(); - } - - Ok(rx.then(|result| { - match result { - Ok(Ok(())) => Ok(()), - Ok(Err(err)) => Err(err), - Err(_) => Err(IoError::new(IoErrorKind::ConnectionAborted, - "dial cancelled the swarm future has been destroyed")), - } - })) - } - Err((_, multiaddr)) => Err(multiaddr), - } - } - - /// Interrupts all dialing attempts to a specific multiaddress. - /// - /// Has no effect if the dialing attempt has already succeeded, in which case it will be - /// dispatched to the handler. - pub fn interrupt_dial(&self, multiaddr: &Multiaddr) { - let mut shared = self.shared.lock(); - shared.dialers.retain(|dialer| { - &dialer.0 != multiaddr - }); - } - - /// Adds a multiaddr to listen on. All the incoming connections will use the `upgrade` that - /// was passed to `swarm`. - // TODO: add a way to cancel a listener - pub fn listen_on(&self, multiaddr: Multiaddr) -> Result { - match self.transport.clone().listen_on(multiaddr) { - Ok((listener, new_addr)) => { - trace!("Swarm listening on {}", new_addr); - let mut shared = self.shared.lock(); - let listener = Box::new( - listener.map(|f| { - let f = f.map(|(out, maf)| { - (out, Box::new(maf) as Box + Send>) - }); - - Box::new(f) as Box + Send> - }), - ) as Box + Send>; - shared.listeners.push((new_addr.clone(), listener.into_future())); - if let Some(task) = shared.task_to_notify.take() { - task.notify(); - } - Ok(new_addr) - } - Err((_, multiaddr)) => Err(multiaddr), - } - } -} - -/// Future that must be driven to completion in order for the swarm to work. -#[must_use = "futures do nothing unless polled"] -pub struct SwarmEvents -where - T: MuxedTransport + 'static, // TODO: 'static :-/ -{ - /// Shared between the swarm infrastructure. - shared: Arc>>, - - /// The transport used to dial. - transport: T, - - /// Swarm handler. - handler: H, -} - -impl Stream for SwarmEvents -where - T: MuxedTransport + Clone + 'static, // TODO: 'static :-/, - T::MultiaddrFuture: Send, - T::IncomingUpgrade: Send, - H: FnMut(T::Output, Box + Send>) -> If, - If: IntoFuture, - F: Future + 'static, // TODO: 'static :-/ -{ - type Item = SwarmEvent; - type Error = IoError; - - fn poll(&mut self) -> Poll, Self::Error> { - let mut shared = self.shared.lock(); - let handler = &mut self.handler; - - loop { - match shared.next_incoming.poll() { - Ok(Async::Ready(connec)) => { - debug!("Swarm received new multiplexed incoming connection"); - shared.next_incoming = self.transport.clone().next_incoming(); - let connec = connec.map(|(out, maf)| { - (out, Box::new(maf) as Box + Send>) - }); - shared.listeners_upgrade.push(Box::new(connec) as Box<_>); - } - Ok(Async::NotReady) => break, - Err(err) => { - // TODO: should that stop everything? - debug!("Error in multiplexed incoming connection: {:?}", err); - shared.next_incoming = self.transport.clone().next_incoming(); - return Ok(Async::Ready(Some(SwarmEvent::IncomingError(err)))); - } - } - } - - // We remove each element from `shared.listeners` one by one and add them back only - // if relevant. - for n in (0 .. shared.listeners.len()).rev() { - let (listen_addr, mut listener) = shared.listeners.swap_remove(n); - loop { - match listener.poll() { - Ok(Async::Ready((Some(upgrade), remaining))) => { - trace!("Swarm received new connection on listener socket"); - shared.listeners_upgrade.push(upgrade); - listener = remaining.into_future(); - } - Ok(Async::Ready((None, _))) => { - debug!("Listener closed gracefully"); - return Ok(Async::Ready(Some(SwarmEvent::ListenerClosed { - listen_addr - }))); - }, - Err((error, _)) => { - debug!("Error in listener: {:?}", error); - return Ok(Async::Ready(Some(SwarmEvent::ListenerError { - listen_addr, - error, - }))); - } - Ok(Async::NotReady) => { - shared.listeners.push((listen_addr, listener)); - break; - } - } - } - } - - // We remove each element from `shared.listeners_upgrade` one by one and add them back - // only if relevant. - for n in (0 .. shared.listeners_upgrade.len()).rev() { - let mut listener_upgrade = shared.listeners_upgrade.swap_remove(n); - match listener_upgrade.poll() { - Ok(Async::Ready((output, client_addr))) => { - debug!("Successfully upgraded incoming connection"); - // TODO: unlock mutex before calling handler, in order to avoid deadlocks if - // the user does something stupid - shared.to_process.push(handler(output, client_addr).into_future()); - } - Err(err) => { - debug!("Error in listener upgrade: {:?}", err); - return Ok(Async::Ready(Some(SwarmEvent::ListenerUpgradeError(err)))); - } - Ok(Async::NotReady) => { - shared.listeners_upgrade.push(listener_upgrade); - }, - } - } - - // We remove each element from `shared.dialers` one by one and add them back only - // if relevant. - for n in (0 .. shared.dialers.len()).rev() { - let (client_addr, mut dialer) = shared.dialers.swap_remove(n); - match dialer.poll() { - Ok(Async::Ready((output, mut notifier, addr))) => { - trace!("Successfully upgraded dialed connection"); - // TODO: unlock mutex before calling handler, in order to avoid deadlocks if - // the user does something stupid - shared.to_process.push(handler(output, addr).into_future()); - notifier(Ok(())); - } - Err(error) => { - return Ok(Async::Ready(Some(SwarmEvent::DialFailed { - client_addr, - error, - }))); - }, - Ok(Async::NotReady) => { - shared.dialers.push((client_addr, dialer)); - }, - } - } - - // We remove each element from `shared.to_process` one by one and add them back only - // if relevant. - for n in (0 .. shared.to_process.len()).rev() { - let mut to_process = shared.to_process.swap_remove(n); - match to_process.poll() { - Ok(Async::Ready(())) => { - trace!("Future returned by swarm handler driven to completion"); - return Ok(Async::Ready(Some(SwarmEvent::HandlerFinished { - handler_future: to_process, - }))); - } - Err(error) => { - debug!("Error in processing: {:?}", error); - return Ok(Async::Ready(Some(SwarmEvent::HandlerError { - handler_future: to_process, - error, - }))); - } - Ok(Async::NotReady) => { - shared.to_process.push(to_process); - } - } - } - - // TODO: we never return `Ok(Ready)` because there's no way to know whether - // `next_incoming()` can produce anything more in the future ; also we would need to - // know when the controller has been dropped - shared.task_to_notify = Some(task::current()); - Ok(Async::NotReady) - } -} - -// TODO: stronger typing -struct Shared where T: MuxedTransport + 'static { - /// Next incoming substream on the transport. - next_incoming: T::Incoming, - - /// All the active listeners. - listeners: Vec<( - Multiaddr, - StreamFuture< - Box< - Stream< - Item = Box + Send>), Error = IoError> + Send>, - Error = IoError, - > + Send, - >, - >, - )>, - - /// Futures that upgrade an incoming listening connection to a full connection. - listeners_upgrade: - Vec + Send>), Error = IoError> + Send>>, - - /// Futures that dial a remote address. - /// - /// Contains the address we dial, so that we can cancel it if necessary. - dialers: Vec<(Multiaddr, Box) + Send>, Box + Send>), Error = IoError> + Send>)>, - - /// List of futures produced by the swarm closure. Must be processed to the end. - to_process: Vec, - - /// The task to notify whenever we add a new element in one of the lists. - /// Necessary so that the task wakes up and the element gets polled. - task_to_notify: Option, -} - -/// Event that happens in the swarm. -#[derive(Debug)] -pub enum SwarmEvent { - /// An error has happened while polling the muxed transport for incoming connections. - IncomingError(IoError), - - /// A listener has gracefully closed. - ListenerClosed { - /// Address the listener was listening on. - listen_addr: Multiaddr, - }, - - /// A listener has stopped because it produced an error. - ListenerError { - /// Address the listener was listening on. - listen_addr: Multiaddr, - /// The error that happened. - error: IoError, - }, - - /// An error happened while upgrading an incoming connection. - ListenerUpgradeError(IoError), - - /// Failed to dial a remote address. - DialFailed { - /// Address we were trying to dial. - client_addr: Multiaddr, - /// Error that happened. - error: IoError, - }, - - /// A future returned by the handler has finished. - HandlerFinished { - /// The future originally returned by the handler. - handler_future: F, - }, - - /// A future returned by the handler has produced an error. - HandlerError { - /// The future originally returned by the handler. - handler_future: F, - /// The error that happened. - error: IoError, - }, -} - -#[cfg(test)] -mod tests { - use futures::{Future, Stream, future}; - use rand; - use transport::{self, DeniedTransport, Transport}; - use std::io::Error as IoError; - use std::sync::{atomic, Arc}; - use swarm; - use tokio::runtime::current_thread; - - #[test] - fn transport_error_propagation_listen() { - let (swarm_ctrl, _swarm_future) = swarm(DeniedTransport, |_, _| future::empty()); - assert!(swarm_ctrl.listen_on("/ip4/127.0.0.1/tcp/10000".parse().unwrap()).is_err()); - } - - #[test] - fn transport_error_propagation_dial() { - let (swarm_ctrl, _swarm_future) = swarm(DeniedTransport, |_, _| future::empty()); - let addr = "/ip4/127.0.0.1/tcp/10000".parse().unwrap(); - assert!(swarm_ctrl.dial(addr, DeniedTransport).is_err()); - } - - #[test] - fn basic_dial() { - let (tx, rx) = transport::connector(); - - let reached_tx = Arc::new(atomic::AtomicBool::new(false)); - let reached_tx2 = reached_tx.clone(); - - let reached_rx = Arc::new(atomic::AtomicBool::new(false)); - let reached_rx2 = reached_rx.clone(); - - let (swarm_ctrl1, swarm_future1) = swarm(rx.with_dummy_muxing(), |_, _| { - reached_rx2.store(true, atomic::Ordering::SeqCst); - future::empty() - }); - swarm_ctrl1.listen_on("/memory".parse().unwrap()).unwrap(); - - let (swarm_ctrl2, swarm_future2) = swarm(tx.clone().with_dummy_muxing(), |_, _| { - reached_tx2.store(true, atomic::Ordering::SeqCst); - future::empty() - }); - - let dial_success = swarm_ctrl2.dial("/memory".parse().unwrap(), tx).unwrap(); - let future = swarm_future2.for_each(|_| Ok(())) - .select(swarm_future1.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err) - .select(dial_success).map(|_| ()).map_err(|(err, _)| err); - - current_thread::Runtime::new().unwrap().block_on(future).unwrap(); - assert!(reached_tx.load(atomic::Ordering::SeqCst)); - assert!(reached_rx.load(atomic::Ordering::SeqCst)); - } - - #[test] - fn dial_multiple_times() { - let (tx, rx) = transport::connector(); - let reached = Arc::new(atomic::AtomicUsize::new(0)); - let reached2 = reached.clone(); - let (swarm_ctrl, swarm_future) = swarm(rx.with_dummy_muxing(), |_, _| { - reached2.fetch_add(1, atomic::Ordering::SeqCst); - future::empty() - }); - swarm_ctrl.listen_on("/memory".parse().unwrap()).unwrap(); - let num_dials = 20000 + rand::random::() % 20000; - let mut dials = Vec::new(); - for _ in 0 .. num_dials { - let f = swarm_ctrl.dial("/memory".parse().unwrap(), tx.clone()).unwrap(); - dials.push(f); - } - let future = future::join_all(dials) - .map(|_| ()) - .select(swarm_future.for_each(|_| Ok(()))) - .map_err(|(err, _)| err); - current_thread::Runtime::new().unwrap().block_on(future).unwrap(); - assert_eq!(reached.load(atomic::Ordering::SeqCst), num_dials); - } - - #[test] - fn future_isnt_dropped() { - // Tests that the future in the closure isn't being dropped. - let (tx, rx) = transport::connector(); - let (swarm_ctrl, swarm_future) = swarm(rx.with_dummy_muxing(), |_, _| { - future::empty() - .then(|_: Result<(), ()>| -> Result<(), IoError> { panic!() }) // <-- the test - }); - swarm_ctrl.listen_on("/memory".parse().unwrap()).unwrap(); - let dial_success = swarm_ctrl.dial("/memory".parse().unwrap(), tx).unwrap(); - let future = dial_success.select(swarm_future.for_each(|_| Ok(()))) - .map_err(|(err, _)| err); - current_thread::Runtime::new().unwrap().block_on(future).unwrap(); - } -} diff --git a/core/src/unique.rs b/core/src/unique.rs deleted file mode 100644 index 0e6215874b8..00000000000 --- a/core/src/unique.rs +++ /dev/null @@ -1,759 +0,0 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -use fnv::FnvHashMap; -use futures::{future, sync::oneshot, task, Async, Future, Poll, IntoFuture}; -use parking_lot::Mutex; -use {Multiaddr, MuxedTransport, SwarmController, Transport}; -use std::io::{Error as IoError, ErrorKind as IoErrorKind}; -use std::mem; -use std::sync::{Arc, Weak, atomic::AtomicUsize, atomic::Ordering}; -use transport::interruptible::Interrupt; - -/// Storage for a unique connection with a remote. -pub struct UniqueConnec { - inner: Arc>>, -} - -enum UniqueConnecInner { - /// The `UniqueConnec` was created, but nothing is in it. - Empty, - /// We started dialing, but no response has been obtained so far. - Pending { - /// Tasks that need to be awakened when the content of this object is set. - tasks_waiting: FnvHashMap, - /// Future that represents when `tie_*` should have been called. - // TODO: Send + Sync bound is meh - dial_fut: Box + Send + Sync>, - /// Dropping this object will automatically interrupt the dial, which is very useful if - /// we clear or drop the `UniqueConnec`. - interrupt: Interrupt, - }, - /// The value of this unique connec has been set. - /// Can only transition to `Empty` when the future has expired. - Full { - /// Content of the object. - value: T, - /// Sender to trigger if the content gets cleared. - on_clear: oneshot::Sender<()>, - }, - /// The `dial_fut` has errored. - Errored(IoError), -} - -impl UniqueConnec { - /// Builds a new empty `UniqueConnec`. - #[inline] - pub fn empty() -> Self { - UniqueConnec { - inner: Arc::new(Mutex::new(UniqueConnecInner::Empty)), - } - } - - /// Builds a new `UniqueConnec` that contains a value. - #[inline] - pub fn with_value(value: T) -> Self { - let (on_clear, _) = oneshot::channel(); - UniqueConnec { - inner: Arc::new(Mutex::new(UniqueConnecInner::Full { value, on_clear })), - } - } - - /// Instantly returns the value from the object if there is any. - pub fn poll(&self) -> Option - where T: Clone, - { - let inner = self.inner.lock(); - if let UniqueConnecInner::Full { ref value, .. } = &*inner { - Some(value.clone()) - } else { - None - } - } - - /// Loads the value from the object. - /// - /// If the object is empty or has errored earlier, dials the given multiaddress with the - /// given transport. - /// - /// The closure of the `swarm` is expected to call `tie_*()` on the `UniqueConnec`. Failure - /// to do so will make the `UniqueConnecFuture` produce an error. - /// - /// One critical property of this method, is that if a connection incomes and `tie_*` is - /// called, then it will be returned by the returned future. - #[inline] - pub fn dial(&self, swarm: &SwarmController, multiaddr: &Multiaddr, - transport: Du) -> UniqueConnecFuture - where T: Clone + Send + 'static, // TODO: 'static :-/ - Du: Transport + 'static, // TODO: 'static :-/ - Du::Output: Into, - Du::Dial: Send, - Du::MultiaddrFuture: Send, - S: Clone + MuxedTransport, - S::Dial: Send, - S::Listener: Send, - S::ListenerUpgrade: Send, - S::Output: Send, - S::MultiaddrFuture: Send, - F: 'static, - { - self.dial_inner(swarm, multiaddr, transport, true) - } - - /// Same as `dial`, except that the future will produce an error if an earlier attempt to dial - /// has errored. - #[inline] - pub fn dial_if_empty(&self, swarm: &SwarmController, multiaddr: &Multiaddr, - transport: Du) -> UniqueConnecFuture - where T: Clone + Send + 'static, // TODO: 'static :-/ - Du: Transport + 'static, // TODO: 'static :-/ - Du::Output: Into, - Du::Dial: Send, - Du::MultiaddrFuture: Send, - S: Clone + MuxedTransport, - S::Dial: Send, - S::Listener: Send, - S::ListenerUpgrade: Send, - S::Output: Send, - S::MultiaddrFuture: Send, - F: 'static, - { - self.dial_inner(swarm, multiaddr, transport, false) - } - - /// Inner implementation of `dial_*`. - fn dial_inner(&self, swarm: &SwarmController, multiaddr: &Multiaddr, - transport: Du, dial_if_err: bool) -> UniqueConnecFuture - where T: Clone + Send + 'static, // TODO: 'static :-/ - Du: Transport + 'static, // TODO: 'static :-/ - Du::Output: Into, - Du::Dial: Send, - Du::MultiaddrFuture: Send, - S: Clone + MuxedTransport, - S::Dial: Send, - S::Listener: Send, - S::ListenerUpgrade: Send, - S::Output: Send, - S::MultiaddrFuture: Send, - F: 'static, - { - let mut inner = self.inner.lock(); - match &*inner { - UniqueConnecInner::Empty => (), - UniqueConnecInner::Errored(_) if dial_if_err => (), - _ => return UniqueConnecFuture { inner: Arc::downgrade(&self.inner) }, - }; - - let weak_inner = Arc::downgrade(&self.inner); - - let (transport, interrupt) = transport.interruptible(); - let dial_fut = swarm.dial_then(multiaddr.clone(), transport, - move |val: Result<(), IoError>| { - let inner = match weak_inner.upgrade() { - Some(i) => i, - None => return val - }; - - let mut inner = inner.lock(); - if let UniqueConnecInner::Full { .. } = *inner { - return val; - } - - let new_val = UniqueConnecInner::Errored(match val { - Ok(()) => IoError::new(IoErrorKind::ConnectionRefused, - "dialing has succeeded but tie_* hasn't been called"), - Err(ref err) => IoError::new(err.kind(), err.to_string()), - }); - - match mem::replace(&mut *inner, new_val) { - UniqueConnecInner::Pending { tasks_waiting, .. } => { - for task in tasks_waiting { - task.1.notify(); - } - }, - _ => () - }; - - val - }); - - let dial_fut = dial_fut - .map_err(|_| IoError::new(IoErrorKind::Other, "multiaddress not supported")) - .into_future() - .flatten(); - - *inner = UniqueConnecInner::Pending { - tasks_waiting: Default::default(), - dial_fut: Box::new(dial_fut), - interrupt, - }; - - UniqueConnecFuture { inner: Arc::downgrade(&self.inner) } - } - - /// Puts `value` inside the object. - /// Additionally, the `UniqueConnec` will be tied to the `until` future. When the future drops - /// or finishes, the `UniqueConnec` is automatically cleared. If the `UniqueConnec` is cleared - /// by the user, the future automatically stops. - /// The returned future is an adjusted version of that same future. - /// - /// If the object already contains something, then `until` is dropped and a dummy future that - /// immediately ends is returned. - pub fn tie_or_stop(&self, value: T, until: F) -> impl Future - where F: Future - { - self.tie_inner(value, until, false) - } - - /// Same as `tie_or_stop`, except that is if the object already contains something, then - /// `until` is returned immediately and can live in parallel. - pub fn tie_or_passthrough(&self, value: T, until: F) -> impl Future - where F: Future - { - self.tie_inner(value, until, true) - } - - /// Inner implementation of `tie_*`. - fn tie_inner(&self, value: T, until: F, pass_through: bool) -> impl Future - where F: Future - { - let mut tasks_to_notify = Default::default(); - - let mut inner = self.inner.lock(); - let (on_clear, on_clear_rx) = oneshot::channel(); - match mem::replace(&mut *inner, UniqueConnecInner::Full { value, on_clear }) { - UniqueConnecInner::Empty => {}, - UniqueConnecInner::Errored(_) => {}, - UniqueConnecInner::Pending { tasks_waiting, .. } => { - tasks_to_notify = tasks_waiting; - }, - old @ UniqueConnecInner::Full { .. } => { - // Keep the old value. - *inner = old; - if pass_through { - return future::Either::B(future::Either::A(until)); - } else { - return future::Either::B(future::Either::B(future::ok(()))); - } - }, - }; - drop(inner); - - struct Cleaner(Weak>>); - impl Drop for Cleaner { - #[inline] - fn drop(&mut self) { - if let Some(inner) = self.0.upgrade() { - *inner.lock() = UniqueConnecInner::Empty; - } - } - } - let cleaner = Cleaner(Arc::downgrade(&self.inner)); - - // The mutex is unlocked when we notify the pending tasks. - for task in tasks_to_notify { - task.1.notify(); - } - - let fut = until - .select(on_clear_rx.then(|_| Ok(()))) - .map(|((), _)| ()) - .map_err(|(err, _)| err) - .then(move |val| { - drop(cleaner); // Make sure that `cleaner` gets called there. - val - }); - future::Either::A(fut) - } - - /// Clears the content of the object. - /// - /// Has no effect if the content is empty or pending. - /// If the node was full, calling `clear` will stop the future returned by `tie_*`. - pub fn clear(&self) { - let mut inner = self.inner.lock(); - match mem::replace(&mut *inner, UniqueConnecInner::Empty) { - UniqueConnecInner::Empty => {}, - UniqueConnecInner::Errored(_) => {}, - pending @ UniqueConnecInner::Pending { .. } => { - *inner = pending; - }, - UniqueConnecInner::Full { on_clear, .. } => { - // TODO: Should we really replace the `Full` with an `Empty` here? What about - // letting dropping the future clear the connection automatically? Otherwise - // it is possible that the user dials before the future gets dropped, in which - // case the future dropping will set the value to `Empty`. But on the other hand, - // it is expected that `clear()` is instantaneous and if it is followed with - // `dial()` then it should dial. - let _ = on_clear.send(()); - }, - }; - } - - /// Returns the state of the object. - /// - /// Note that this can be racy, as the object can be used at the same time. In other words, - /// the returned value may no longer reflect the actual state. - pub fn state(&self) -> UniqueConnecState { - match *self.inner.lock() { - UniqueConnecInner::Empty => UniqueConnecState::Empty, - UniqueConnecInner::Errored(_) => UniqueConnecState::Errored, - UniqueConnecInner::Pending { .. } => UniqueConnecState::Pending, - UniqueConnecInner::Full { .. } => UniqueConnecState::Full, - } - } - - /// Returns true if the object has a pending or active connection. Returns false if the object - /// is empty or the connection has errored earlier. - #[inline] - pub fn is_alive(&self) -> bool { - match self.state() { - UniqueConnecState::Empty => false, - UniqueConnecState::Errored => false, - UniqueConnecState::Pending => true, - UniqueConnecState::Full => true, - } - } -} - -impl Clone for UniqueConnec { - #[inline] - fn clone(&self) -> UniqueConnec { - UniqueConnec { - inner: self.inner.clone(), - } - } -} - -impl Default for UniqueConnec { - #[inline] - fn default() -> Self { - UniqueConnec::empty() - } -} - -impl Drop for UniqueConnec { - fn drop(&mut self) { - // Notify the waiting futures if we are the last `UniqueConnec`. - if let Some(inner) = Arc::get_mut(&mut self.inner) { - match *inner.get_mut() { - UniqueConnecInner::Pending { ref mut tasks_waiting, .. } => { - for task in tasks_waiting.drain() { - task.1.notify(); - } - }, - _ => () - } - } - } -} - -/// Future returned by `UniqueConnec::dial()`. -#[must_use = "futures do nothing unless polled"] -pub struct UniqueConnecFuture { - inner: Weak>>, -} - -impl Future for UniqueConnecFuture - where T: Clone -{ - type Item = T; - type Error = IoError; - - fn poll(&mut self) -> Poll { - let inner = match self.inner.upgrade() { - Some(inner) => inner, - // All the `UniqueConnec` have been destroyed. - None => return Err(IoErrorKind::ConnectionAborted.into()), - }; - - let mut inner = inner.lock(); - match mem::replace(&mut *inner, UniqueConnecInner::Empty) { - UniqueConnecInner::Empty => { - // This can happen if `tie_*()` is called, and the future expires before the - // future returned by `dial()` gets polled. This means that the connection has been - // closed. - Err(IoErrorKind::ConnectionAborted.into()) - }, - UniqueConnecInner::Pending { mut tasks_waiting, mut dial_fut, interrupt } => { - match dial_fut.poll() { - Ok(Async::Ready(())) => { - // This happens if we successfully dialed a remote, but the callback - // doesn't call `tie_*`. This can be a logic error by the user, - // but could also indicate that the user decided to filter out this - // connection for whatever reason. - *inner = UniqueConnecInner::Errored(IoErrorKind::ConnectionAborted.into()); - Err(IoErrorKind::ConnectionAborted.into()) - }, - Ok(Async::NotReady) => { - static NEXT_TASK_ID: AtomicUsize = AtomicUsize::new(0); - task_local! { - static TASK_ID: usize = NEXT_TASK_ID.fetch_add(1, Ordering::Relaxed) - } - tasks_waiting.insert(TASK_ID.with(|&k| k), task::current()); - *inner = UniqueConnecInner::Pending { tasks_waiting, dial_fut, interrupt }; - Ok(Async::NotReady) - } - Err(err) => { - let tr = IoError::new(err.kind(), err.to_string()); - *inner = UniqueConnecInner::Errored(err); - Err(tr) - }, - } - }, - UniqueConnecInner::Full { value, on_clear } => { - *inner = UniqueConnecInner::Full { - value: value.clone(), - on_clear - }; - Ok(Async::Ready(value)) - }, - UniqueConnecInner::Errored(err) => { - let tr = IoError::new(err.kind(), err.to_string()); - *inner = UniqueConnecInner::Errored(err); - Err(tr) - }, - } - } -} - -/// State of a `UniqueConnec`. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum UniqueConnecState { - /// The object is empty. - Empty, - /// `dial` has been called and we are waiting for `tie_*` to be called. - Pending, - /// `tie_*` has been called. - Full, - /// The future returned by the closure of `dial` has errored or has finished before - /// `tie_*` has been called. - Errored, -} - -#[cfg(test)] -mod tests { - use futures::{future, sync::oneshot, Future, Stream}; - use transport::DeniedTransport; - use std::io::Error as IoError; - use std::sync::{Arc, atomic}; - use std::time::Duration; - use {UniqueConnec, UniqueConnecState}; - use {swarm, transport, Transport}; - use tokio::runtime::current_thread; - use tokio_timer; - - #[test] - fn basic_working() { - // Checks the basic working of the `UniqueConnec`. - let (tx, rx) = transport::connector(); - let unique_connec = UniqueConnec::empty(); - let unique_connec2 = unique_connec.clone(); - assert_eq!(unique_connec.state(), UniqueConnecState::Empty); - - let (swarm_ctrl, swarm_future) = swarm(rx.with_dummy_muxing(), |_, _| { - // Note that this handles both the dial and the listen. - assert!(unique_connec2.is_alive()); - unique_connec2.tie_or_stop(12, future::empty()) - }); - swarm_ctrl.listen_on("/memory".parse().unwrap()).unwrap(); - - let dial_success = unique_connec - .dial(&swarm_ctrl, &"/memory".parse().unwrap(), tx) - .map(|val| { assert_eq!(val, 12); }); - assert_eq!(unique_connec.state(), UniqueConnecState::Pending); - - let future = dial_success.select(swarm_future.for_each(|_| Ok(()))).map_err(|(err, _)| err); - current_thread::Runtime::new().unwrap().block_on(future).unwrap(); - assert_eq!(unique_connec.state(), UniqueConnecState::Full); - } - - #[test] - fn invalid_multiaddr_produces_error() { - // Tests that passing an invalid multiaddress generates an error. - let unique = UniqueConnec::empty(); - assert_eq!(unique.state(), UniqueConnecState::Empty); - let unique2 = unique.clone(); - let (swarm_ctrl, _swarm_fut) = swarm(DeniedTransport, |_, _| { - unique2.tie_or_stop((), future::empty()) - }); - let fut = unique.dial(&swarm_ctrl, &"/ip4/1.2.3.4".parse().unwrap(), DeniedTransport); - assert!(fut.wait().is_err()); - assert_eq!(unique.state(), UniqueConnecState::Errored); - } - - #[test] - fn tie_or_stop_stops() { - // Tests that `tie_or_stop` destroys additional futures passed to it. - let (tx, rx) = transport::connector(); - let unique_connec = UniqueConnec::empty(); - let unique_connec2 = unique_connec.clone(); - - // This channel is used to detect whether the future has been dropped. - let (msg_tx, msg_rx) = oneshot::channel(); - - let mut num_connec = 0; - let mut msg_rx = Some(msg_rx); - let (swarm_ctrl1, swarm_future1) = swarm(rx.with_dummy_muxing(), move |_, _| { - num_connec += 1; - if num_connec == 1 { - unique_connec2.tie_or_stop(12, future::Either::A(future::empty())) - } else { - let fut = msg_rx.take().unwrap().map_err(|_| panic!()); - unique_connec2.tie_or_stop(13, future::Either::B(fut)) - } - }); - swarm_ctrl1.listen_on("/memory".parse().unwrap()).unwrap(); - - let (swarm_ctrl2, swarm_future2) = swarm(tx.clone().with_dummy_muxing(), move |_, _| { - future::empty() - }); - - let dial_success = unique_connec - .dial(&swarm_ctrl2, &"/memory".parse().unwrap(), tx.clone()) - .map(|val| { assert_eq!(val, 12); }) - .inspect({ - let c = unique_connec.clone(); - move |_| { assert!(c.is_alive()); } - }) - .and_then(|_| { - tokio_timer::sleep(Duration::from_secs(1)) - .map_err(|_| unreachable!()) - }) - .and_then(move |_| { - swarm_ctrl2.dial("/memory".parse().unwrap(), tx) - .unwrap_or_else(|_| panic!()) - }) - .inspect({ - let c = unique_connec.clone(); - move |_| { - assert_eq!(c.poll(), Some(12)); // Not 13 - assert!(msg_tx.send(()).is_err()); - } - }); - - let future = dial_success - .select(swarm_future2.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err) - .select(swarm_future1.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err); - - current_thread::Runtime::new().unwrap().block_on(future).unwrap(); - assert!(unique_connec.is_alive()); - } - - #[test] - fn tie_or_passthrough_passes_through() { - // Tests that `tie_or_passthrough` doesn't delete additional futures passed to it when - // it is already full, and doesn't gets its value modified when that happens. - let (tx, rx) = transport::connector(); - let unique_connec = UniqueConnec::empty(); - let unique_connec2 = unique_connec.clone(); - - let mut num = 12; - let (swarm_ctrl, swarm_future) = swarm(rx.with_dummy_muxing(), move |_, _| { - // Note that this handles both the dial and the listen. - let fut = future::empty().then(|_: Result<(), ()>| -> Result<(), IoError> { panic!() }); - num += 1; - unique_connec2.tie_or_passthrough(num, fut) - }); - swarm_ctrl.listen_on("/memory".parse().unwrap()).unwrap(); - - let dial_success = unique_connec - .dial(&swarm_ctrl, &"/memory".parse().unwrap(), tx.clone()) - .map(|val| { assert_eq!(val, 13); }); - - swarm_ctrl.dial("/memory".parse().unwrap(), tx) - .unwrap(); - - let future = dial_success.select(swarm_future.for_each(|_| Ok(()))).map_err(|(err, _)| err); - current_thread::Runtime::new().unwrap().block_on(future).unwrap(); - assert_eq!(unique_connec.poll(), Some(13)); - } - - #[test] - fn cleared_when_future_drops() { - // Tests that the `UniqueConnec` gets cleared when the future we associate with it gets - // destroyed. - let (tx, rx) = transport::connector(); - let unique_connec = UniqueConnec::empty(); - let unique_connec2 = unique_connec.clone(); - - let (msg_tx, msg_rx) = oneshot::channel(); - let mut msg_rx = Some(msg_rx); - - let (swarm_ctrl1, swarm_future1) = swarm(rx.with_dummy_muxing(), move |_, _| { - future::empty() - }); - swarm_ctrl1.listen_on("/memory".parse().unwrap()).unwrap(); - - let (swarm_ctrl2, swarm_future2) = swarm(tx.clone().with_dummy_muxing(), move |_, _| { - let fut = msg_rx.take().unwrap().map_err(|_| -> IoError { unreachable!() }); - unique_connec2.tie_or_stop(12, fut) - }); - - let dial_success = unique_connec - .dial(&swarm_ctrl2, &"/memory".parse().unwrap(), tx) - .map(|val| { assert_eq!(val, 12); }) - .inspect({ - let c = unique_connec.clone(); - move |_| { assert!(c.is_alive()); } - }) - .and_then(|_| { - msg_tx.send(()).unwrap(); - tokio_timer::sleep(Duration::from_secs(1)) - .map_err(|_| unreachable!()) - }) - .inspect({ - let c = unique_connec.clone(); - move |_| { assert!(!c.is_alive()); } - }); - - let future = dial_success - .select(swarm_future1.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err) - .select(swarm_future2.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err); - - current_thread::Runtime::new().unwrap().block_on(future).unwrap(); - assert!(!unique_connec.is_alive()); - } - - #[test] - fn future_drops_when_cleared() { - // Tests that the future returned by `tie_or_*` ends when the `UniqueConnec` get cleared. - let (tx, rx) = transport::connector(); - let unique_connec = UniqueConnec::empty(); - let unique_connec2 = unique_connec.clone(); - - let (swarm_ctrl1, swarm_future1) = swarm(rx.with_dummy_muxing(), move |_, _| { - future::empty() - }); - swarm_ctrl1.listen_on("/memory".parse().unwrap()).unwrap(); - - let finished = Arc::new(atomic::AtomicBool::new(false)); - let finished2 = finished.clone(); - let (swarm_ctrl2, swarm_future2) = swarm(tx.clone().with_dummy_muxing(), move |_, _| { - let finished2 = finished2.clone(); - unique_connec2.tie_or_stop(12, future::empty()).then(move |v| { - finished2.store(true, atomic::Ordering::Relaxed); - v - }) - }); - - let dial_success = unique_connec - .dial(&swarm_ctrl2, &"/memory".parse().unwrap(), tx) - .map(|val| { assert_eq!(val, 12); }) - .inspect({ - let c = unique_connec.clone(); - move |_| { - assert!(c.is_alive()); - c.clear(); - assert!(!c.is_alive()); - } - }) - .and_then(|_| { - tokio_timer::sleep(Duration::from_secs(1)) - .map_err(|_| unreachable!()) - }) - .inspect({ - let c = unique_connec.clone(); - move |_| { - assert!(finished.load(atomic::Ordering::Relaxed)); - assert!(!c.is_alive()); - } - }); - - let future = dial_success - .select(swarm_future1.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err) - .select(swarm_future2.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err); - - current_thread::Runtime::new().unwrap().block_on(future).unwrap(); - assert!(!unique_connec.is_alive()); - } - - #[test] - fn future_drops_when_destroyed() { - // Tests that the future returned by `tie_or_*` ends when the `UniqueConnec` get dropped. - let (tx, rx) = transport::connector(); - let unique_connec = UniqueConnec::empty(); - let mut unique_connec2 = Some(unique_connec.clone()); - - let (swarm_ctrl1, swarm_future1) = swarm(rx.with_dummy_muxing(), move |_, _| { - future::empty() - }); - swarm_ctrl1.listen_on("/memory".parse().unwrap()).unwrap(); - - let finished = Arc::new(atomic::AtomicBool::new(false)); - let finished2 = finished.clone(); - let (swarm_ctrl2, swarm_future2) = swarm(tx.clone().with_dummy_muxing(), move |_, _| { - let finished2 = finished2.clone(); - unique_connec2.take().unwrap().tie_or_stop(12, future::empty()).then(move |v| { - finished2.store(true, atomic::Ordering::Relaxed); - v - }) - }); - - let dial_success = unique_connec - .dial(&swarm_ctrl2, &"/memory".parse().unwrap(), tx) - .map(|val| { assert_eq!(val, 12); }) - .inspect(move |_| { - assert!(unique_connec.is_alive()); - drop(unique_connec); - }) - .and_then(|_| { - tokio_timer::sleep(Duration::from_secs(1)) - .map_err(|_| unreachable!()) - }) - .inspect(move |_| { - assert!(finished.load(atomic::Ordering::Relaxed)); - }); - - let future = dial_success - .select(swarm_future1.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err) - .select(swarm_future2.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err); - - current_thread::Runtime::new().unwrap().block_on(future).unwrap(); - } - - #[test] - fn error_if_unique_connec_destroyed_before_future() { - // Tests that the future returned by `dial` returns an error if the `UniqueConnec` no - // longer exists. - let (tx, rx) = transport::connector(); - - let (swarm_ctrl, swarm_future) = swarm(rx.with_dummy_muxing(), move |_, _| { - future::empty() - }); - swarm_ctrl.listen_on("/memory".parse().unwrap()).unwrap(); - - let unique_connec = UniqueConnec::empty(); - let dial_success = unique_connec - .dial(&swarm_ctrl, &"/memory".parse().unwrap(), tx) - .then(|val: Result<(), IoError>| { - assert!(val.is_err()); - Ok(()) - }); - drop(unique_connec); - - let future = dial_success - .select(swarm_future.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err); - current_thread::Runtime::new().unwrap().block_on(future).unwrap(); - } - - // TODO: test that dialing is interrupted when UniqueConnec is cleared - // TODO: test that dialing is interrupted when UniqueConnec is dropped -} From a77c1a6bf7a2e4aed66a77358671efe5bf548412 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 18 Oct 2018 09:42:20 +0100 Subject: [PATCH 07/19] Fix panic in raw swarm (#571) --- core/src/nodes/raw_swarm.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/core/src/nodes/raw_swarm.rs b/core/src/nodes/raw_swarm.rs index e1b8ed2b301..1f25fe43bc2 100644 --- a/core/src/nodes/raw_swarm.rs +++ b/core/src/nodes/raw_swarm.rs @@ -720,14 +720,15 @@ where }; let closed_endpoint = reach_attempts.connected_points - .insert(event.peer_id().clone(), opened_endpoint.clone()) - .expect("We insert into connected_points whenever a connection is opened and remove \ - only when a connection is closed ; the underlying API is guaranteed to always \ - deliver a connection closed message after it has been opened, and no two \ - closed messages ; qed"); + .insert(event.peer_id().clone(), opened_endpoint.clone()); let (outcome, peer_id) = event.accept(); if outcome == CollectionNodeAccept::ReplacedExisting { + let closed_endpoint = closed_endpoint + .expect("We insert into connected_points whenever a connection is opened and \ + remove only when a connection is closed ; the underlying API is guaranteed \ + to always deliver a connection closed message after it has been opened, \ + and no two closed messages ; qed"); return (Default::default(), RawSwarmEvent::Replaced { peer_id, endpoint: opened_endpoint, From 1e223f627dba3e29b4313ba44f2afa608cc7b385 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 18 Oct 2018 15:21:14 +0100 Subject: [PATCH 08/19] Remove other unused files (#570) --- protocols/identify/src/identify_transport.rs | 333 ----------------- protocols/identify/src/peer_id_transport.rs | 370 ------------------- 2 files changed, 703 deletions(-) delete mode 100644 protocols/identify/src/identify_transport.rs delete mode 100644 protocols/identify/src/peer_id_transport.rs diff --git a/protocols/identify/src/identify_transport.rs b/protocols/identify/src/identify_transport.rs deleted file mode 100644 index dc039c0d41a..00000000000 --- a/protocols/identify/src/identify_transport.rs +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -use fnv::FnvHashMap; -use futures::{future, Future, Stream}; -use libp2p_core::{Multiaddr, MuxedTransport, Transport}; -use parking_lot::Mutex; -use protocol::{IdentifyInfo, IdentifyOutput, IdentifyProtocolConfig}; -use std::collections::hash_map::Entry; -use std::error::Error; -use std::io::Error as IoError; -use std::sync::Arc; -use tokio_io::{AsyncRead, AsyncWrite}; - -/// Implementation of `Transport`. See [the crate root description](index.html). -pub struct IdentifyTransport { - transport: Trans, - // Each entry is protected by an asynchronous mutex, so that if we dial the same node twice - // simultaneously, the second time will block until the first time has identified it. - cache: Arc>>, -} - -impl Clone for IdentifyTransport - where Trans: Clone, -{ - fn clone(&self) -> Self { - IdentifyTransport { - transport: self.transport.clone(), - cache: self.cache.clone(), - } - } -} - -type CacheEntry = future::Shared + Send>>; - -impl IdentifyTransport { - /// Creates an `IdentifyTransport` that wraps around the given transport and peerstore. - #[inline] - pub fn new(transport: Trans) -> Self { - IdentifyTransport { - transport, - cache: Arc::new(Mutex::new(Default::default())), - } - } -} - -impl Transport for IdentifyTransport -where - Trans: Transport + Clone + Send + 'static, // TODO: 'static :( - Trans::Dial: Send, - Trans::Listener: Send, - Trans::ListenerUpgrade: Send, - Trans::MultiaddrFuture: Send, - Trans::Output: AsyncRead + AsyncWrite + Send, -{ - type Output = IdentifyTransportOutput; - type MultiaddrFuture = future::FutureResult; - type Listener = Box + Send>; - type ListenerUpgrade = Box + Send>; - type Dial = Box + Send>; - - #[inline] - fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { - let (listener, new_addr) = match self.transport.clone().listen_on(addr.clone()) { - Ok((l, a)) => (l, a), - Err((inner, addr)) => { - let id = IdentifyTransport { - transport: inner, - cache: self.cache, - }; - return Err((id, addr)); - } - }; - - let identify_upgrade = self.transport.with_upgrade(IdentifyProtocolConfig); - let cache = self.cache.clone(); - - let listener = listener.map(move |connec| { - let identify_upgrade = identify_upgrade.clone(); - let cache = cache.clone(); - let fut = connec - .and_then(move |(connec, client_addr)| { - trace!("Incoming connection, waiting for client address"); - client_addr.map(move |addr| (connec, addr)) - }) - .and_then(move |(connec, client_addr)| { - debug!("Incoming connection from {}", client_addr); - - // Dial the address that connected to us and try upgrade with the - // identify protocol. - let info_future = cache_entry(&cache, client_addr.clone(), { let client_addr = client_addr.clone(); move || { - debug!("No cache entry for {}, dialing back in order to identify", client_addr); - future::lazy(|| { trace!("Starting identify back"); identify_upgrade - .dial(client_addr) - .unwrap_or_else(|(_, addr)| { - panic!("the multiaddr {} was determined to be valid earlier", addr) - }) }) - .map(move |(identify, _)| { - let (info, observed_addr) = match identify { - IdentifyOutput::RemoteInfo { info, observed_addr } => { - (info, observed_addr) - }, - _ => unreachable!( - "the identify protocol guarantees that we receive \ - remote information when we dial a node" - ), - }; - - debug!("Identified dialed back connection as pubkey {:?}", info.public_key); - IdentifyTransportOutcome { - info, - observed_addr, - } - }) - .map_err(move |err| { - debug!("Failed to identify dialed back connection"); - err - }) - }}); - - let out = IdentifyTransportOutput { - socket: connec, - info: Box::new(info_future), - }; - - Ok((out, future::ok(client_addr))) - }); - - Box::new(fut) as Box + Send> - }); - - Ok((Box::new(listener) as Box<_>, new_addr)) - } - - #[inline] - fn dial(self, addr: Multiaddr) -> Result { - // We dial a first time the node. - let dial = match self.transport.clone().dial(addr) { - Ok(d) => d, - Err((transport, addr)) => { - let id = IdentifyTransport { - transport, - cache: self.cache, - }; - return Err((id, addr)); - } - }; - - // Once successfully dialed, we dial again to identify. - let identify_upgrade = self.transport.with_upgrade(IdentifyProtocolConfig); - let cache = self.cache.clone(); - let future = dial - .and_then(move |(connec, client_addr)| { - trace!("Dialing successful, waiting for client address"); - client_addr.map(move |addr| (connec, addr)) - }) - .and_then(move |(socket, addr)| { - trace!("Dialing successful ; client address is {}", addr); - let info_future = cache_entry(&cache, addr.clone(), { let addr = addr.clone(); move || { - trace!("No cache entry for {} ; dialing again for identification", addr); - future::lazy(|| { trace!("Starting identify back"); identify_upgrade - .dial(addr) - .unwrap_or_else(|(_, addr)| { - panic!("the multiaddr {} was determined to be valid earlier", addr) - }) }) - .map(move |(identify, _)| { - let (info, observed_addr) = match identify { - IdentifyOutput::RemoteInfo { info, observed_addr } => { - (info, observed_addr) - } - _ => unreachable!( - "the identify protocol guarantees that we receive \ - remote information when we dial a node" - ), - }; - - IdentifyTransportOutcome { - info, - observed_addr, - } - }) - }}); - - let out = IdentifyTransportOutput { - socket: socket, - info: Box::new(info_future), - }; - - Ok((out, future::ok(addr))) - }); - - Ok(Box::new(future) as Box<_>) - } - - #[inline] - fn nat_traversal(&self, a: &Multiaddr, b: &Multiaddr) -> Option { - self.transport.nat_traversal(a, b) - } -} - -impl MuxedTransport for IdentifyTransport -where - Trans: MuxedTransport + Clone + Send + 'static, - Trans::Dial: Send, - Trans::Listener: Send, - Trans::ListenerUpgrade: Send, - Trans::MultiaddrFuture: Send, - Trans::Output: AsyncRead + AsyncWrite + Send, - Trans::Incoming: Send, - Trans::IncomingUpgrade: Send, -{ - type Incoming = Box + Send>; - type IncomingUpgrade = Box + Send>; - - #[inline] - fn next_incoming(self) -> Self::Incoming { - let identify_upgrade = self.transport.clone().with_upgrade(IdentifyProtocolConfig); - let cache = self.cache.clone(); - - let future = self.transport.next_incoming().map(move |incoming| { - let cache = cache.clone(); - let future = incoming - .and_then(move |(connec, client_addr)| { - debug!("Incoming substream ; waiting for client address"); - client_addr.map(move |addr| (connec, addr)) - }) - .and_then(move |(connec, client_addr)| { - debug!("Incoming substream from {}", client_addr); - - // Dial the address that connected to us and try upgrade with the - // identify protocol. - let info_future = cache_entry(&cache, client_addr.clone(), { let client_addr = client_addr.clone(); move || { - debug!("No cache entry from {} ; dialing back to identify", client_addr); - future::lazy(|| { trace!("Starting identify back"); identify_upgrade - .dial(client_addr) - .unwrap_or_else(|(_, client_addr)| { - panic!("the multiaddr {} was determined to be valid earlier", client_addr) - }) }) - .map(move |(identify, _)| { - let (info, observed_addr) = match identify { - IdentifyOutput::RemoteInfo { info, observed_addr } => { - (info, observed_addr) - }, - _ => unreachable!( - "the identify protocol guarantees that we receive \ - remote information when we dial a node" - ), - }; - - debug!("Identified incoming substream as pubkey {:?}", info.public_key); - IdentifyTransportOutcome { - info, - observed_addr, - } - }) - .map_err(move |err| { - debug!("Failed to identify incoming substream"); - err - }) - }}); - - let out = IdentifyTransportOutput { - socket: connec, - info: Box::new(info_future), - }; - - Ok((out, future::ok(client_addr))) - }); - - Box::new(future) as Box + Send> - }); - - Box::new(future) as Box<_> - } -} - -/// Output of the identify transport. -pub struct IdentifyTransportOutput { - /// The socket to communicate with the remote. - pub socket: S, - /// Outcome of the identification of the remote. - pub info: Box + Send>, -} - -/// Outcome of the identification of the remote. -#[derive(Debug, Clone)] -pub struct IdentifyTransportOutcome { - /// Identification of the remote. - pub info: IdentifyInfo, - /// Address the remote sees for us. - pub observed_addr: Multiaddr, -} - -fn cache_entry(cache: &Mutex>, addr: Multiaddr, if_no_entry: F) - -> impl Future -where F: FnOnce() -> Fut, - Fut: Future + Send + 'static, -{ - trace!("Looking up cache entry for {}", addr); - let mut cache = cache.lock(); - match cache.entry(addr) { - Entry::Occupied(entry) => { - trace!("Cache entry found, cloning"); - future::Either::A(entry.get().clone()) - }, - - Entry::Vacant(entry) => { - trace!("No cache entry available"); - let future = (Box::new(if_no_entry()) as Box + Send>).shared(); - entry.insert(future.clone()); - future::Either::B(future) - }, - }.map(|out| (*out).clone()).map_err(|err| IoError::new(err.kind(), err.description())) -} - -// TODO: test that we receive back what the remote sent us diff --git a/protocols/identify/src/peer_id_transport.rs b/protocols/identify/src/peer_id_transport.rs deleted file mode 100644 index b810ac7d9cb..00000000000 --- a/protocols/identify/src/peer_id_transport.rs +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -use futures::{future, stream, Future, Stream}; -use identify_transport::{IdentifyTransport, IdentifyTransportOutcome}; -use libp2p_core::{PeerId, MuxedTransport, Transport}; -use multiaddr::{Protocol, Multiaddr}; -use std::io::{Error as IoError, ErrorKind as IoErrorKind}; -use tokio_io::{AsyncRead, AsyncWrite}; - -/// Implementation of `Transport`. See [the crate root description](index.html). -#[derive(Clone)] -pub struct PeerIdTransport { - transport: IdentifyTransport, - addr_resolver: AddrRes, -} - -impl PeerIdTransport { - /// Creates an `PeerIdTransport` that wraps around the given transport and address resolver. - #[inline] - pub fn new(transport: Trans, addr_resolver: AddrRes) -> Self { - PeerIdTransport { - transport: IdentifyTransport::new(transport), - addr_resolver, - } - } -} - -impl Transport for PeerIdTransport -where - Trans: Transport + Clone + Send + 'static, // TODO: 'static :( - Trans::Dial: Send, - Trans::Listener: Send, - Trans::ListenerUpgrade: Send, - Trans::MultiaddrFuture: Send, - Trans::Output: AsyncRead + AsyncWrite + Send, - AddrRes: Fn(PeerId) -> AddrResOut + 'static, // TODO: 'static :( - AddrResOut: IntoIterator + 'static, // TODO: 'static :( - AddrResOut::IntoIter: Send, -{ - type Output = PeerIdTransportOutput; - type MultiaddrFuture = Box + Send>; - type Listener = Box + Send>; - type ListenerUpgrade = Box + Send>; - type Dial = Box + Send>; - - #[inline] - fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { - // Note that `listen_on` expects a "regular" multiaddr (eg. `/ip/.../tcp/...`), - // and not `/p2p/`. - - let (listener, listened_addr) = match self.transport.listen_on(addr) { - Ok((listener, addr)) => (listener, addr), - Err((inner, addr)) => { - let id = PeerIdTransport { - transport: inner, - addr_resolver: self.addr_resolver, - }; - - return Err((id, addr)); - } - }; - - let listener = listener.map(move |connec| { - let fut = connec - .and_then(move |(connec, client_addr)| { - client_addr.map(move |addr| (connec, addr)) - }) - .map(move |(connec, original_addr)| { - debug!("Successfully incoming connection from {}", original_addr); - let info = connec.info.shared(); - let out = PeerIdTransportOutput { - socket: connec.socket, - info: Box::new(info.clone() - .map(move |info| (*info).clone()) - .map_err(move |err| { let k = err.kind(); IoError::new(k, err) })), - original_addr: original_addr.clone(), - }; - let real_addr = Box::new(info - .map_err(move |err| { let k = err.kind(); IoError::new(k, err) }) - .map(move |info| { - let peer_id = info.info.public_key.clone().into_peer_id(); - debug!("Identified {} as {:?}", original_addr, peer_id); - Protocol::P2p(peer_id.into()).into() - })) as Box + Send>; - (out, real_addr) - }); - - Box::new(fut) as Box + Send> - }); - - Ok((Box::new(listener) as Box<_>, listened_addr)) - } - - #[inline] - fn dial(self, addr: Multiaddr) -> Result { - match multiaddr_to_peerid(addr.clone()) { - Ok(peer_id) => { - // If the multiaddress is a peer ID, try each known multiaddress (taken from the - // address resolved) one by one. - let addrs = { - let resolver = &self.addr_resolver; - resolver(peer_id.clone()).into_iter() - }; - - trace!("Try dialing peer ID {:?} ; loading multiaddrs from addr resolver", peer_id); - - let transport = self.transport; - let future = stream::iter_ok(addrs) - // Try to dial each address through the transport. - .filter_map(move |addr| { - match transport.clone().dial(addr) { - Ok(dial) => Some(dial), - Err((_, addr)) => { - debug!("Address {} not supported by underlying transport", addr); - None - }, - } - }) - .and_then(move |dial| dial) - // Pick the first non-failing dial result by filtering out the ones which fail. - .then(|res| Ok(res)) - .filter_map(|res| res.ok()) - .into_future() - .map_err(|(err, _)| err) - .and_then(move |(connec, _)| { - match connec { - Some(connec) => Ok((connec, peer_id)), - None => { - debug!("All multiaddresses failed when dialing peer {:?}", peer_id); - Err(IoError::new(IoErrorKind::Other, "couldn't find any multiaddress for peer")) - }, - } - }) - .and_then(move |((connec, original_addr), peer_id)| { - original_addr.map(move |addr| (connec, addr, peer_id)) - }) - .and_then(move |(connec, original_addr, peer_id)| { - debug!("Successfully dialed peer {:?} through {}", peer_id, original_addr); - let out = PeerIdTransportOutput { - socket: connec.socket, - info: connec.info, - original_addr: original_addr, - }; - // Replace the multiaddress with the one of the form `/p2p/...` or `/ipfs/...`. - Ok((out, Box::new(future::ok(addr)) as Box + Send>)) - }); - - Ok(Box::new(future) as Box<_>) - } - - Err(addr) => { - // If the multiaddress is something else, propagate it to the underlying transport. - trace!("Propagating {} to the underlying transport", addr); - let dial = match self.transport.dial(addr) { - Ok(d) => d, - Err((inner, addr)) => { - let id = PeerIdTransport { - transport: inner, - addr_resolver: self.addr_resolver, - }; - return Err((id, addr)); - } - }; - - let future = dial - .and_then(move |(connec, original_addr)| { - original_addr.map(move |addr| (connec, addr)) - }) - .map(move |(connec, original_addr)| { - debug!("Successfully dialed {}", original_addr); - let info = connec.info.shared(); - let out = PeerIdTransportOutput { - socket: connec.socket, - info: Box::new(info.clone() - .map(move |info| (*info).clone()) - .map_err(move |err| { let k = err.kind(); IoError::new(k, err) })), - original_addr: original_addr.clone(), - }; - let real_addr = Box::new(info - .map_err(move |err| { let k = err.kind(); IoError::new(k, err) }) - .map(move |info| { - let peer_id = info.info.public_key.clone().into_peer_id(); - debug!("Identified {} as {:?}", original_addr, peer_id); - Protocol::P2p(peer_id.into()).into() - })) as Box + Send>; - (out, real_addr) - }); - - Ok(Box::new(future) as Box<_>) - } - } - } - - #[inline] - fn nat_traversal(&self, a: &Multiaddr, b: &Multiaddr) -> Option { - self.transport.nat_traversal(a, b) - } -} - -impl MuxedTransport for PeerIdTransport -where - Trans: MuxedTransport + Clone + Send + 'static, - Trans::Dial: Send, - Trans::Listener: Send, - Trans::ListenerUpgrade: Send, - Trans::MultiaddrFuture: Send, - Trans::Output: AsyncRead + AsyncWrite + Send, - Trans::Incoming: Send, - Trans::IncomingUpgrade: Send, - AddrRes: Fn(PeerId) -> AddrResOut + 'static, // TODO: 'static :( - AddrResOut: IntoIterator + 'static, // TODO: 'static :( - AddrResOut::IntoIter: Send, -{ - type Incoming = Box + Send>; - type IncomingUpgrade = Box + Send>; - - #[inline] - fn next_incoming(self) -> Self::Incoming { - let future = self.transport.next_incoming().map(move |incoming| { - let future = incoming - .and_then(move |(connec, original_addr)| { - original_addr.map(move |addr| (connec, addr)) - }) - .map(move |(connec, original_addr)| { - debug!("Successful incoming substream from {}", original_addr); - let info = connec.info.shared(); - let out = PeerIdTransportOutput { - socket: connec.socket, - info: Box::new(info.clone() - .map(move |info| (*info).clone()) - .map_err(move |err| { let k = err.kind(); IoError::new(k, err) })), - original_addr: original_addr.clone(), - }; - let real_addr = Box::new(info - .map_err(move |err| { let k = err.kind(); IoError::new(k, err) }) - .map(move |info| { - let peer_id = info.info.public_key.clone().into_peer_id(); - debug!("Identified {} as {:?}", original_addr, peer_id); - Protocol::P2p(peer_id.into()).into() - })) as Box + Send>; - (out, real_addr) - }); - - Box::new(future) as Box + Send> - }); - - Box::new(future) as Box<_> - } -} - -/// Output of the identify transport. -pub struct PeerIdTransportOutput { - /// The socket to communicate with the remote. - pub socket: S, - - /// Identification of the remote. - /// This may not be known immediately, hence why we use a future. - pub info: Box + Send>, - - /// Original address of the remote. - /// This layer turns the address of the remote into the `/p2p/...` form, but stores the - /// original address in this field. - pub original_addr: Multiaddr, -} - -// If the multiaddress is in the form `/p2p/...`, turn it into a `PeerId`. -// Otherwise, return it as-is. -fn multiaddr_to_peerid(addr: Multiaddr) -> Result { - if addr.iter().next().is_none() { - return Err(addr) - } - match addr.iter().last() { - Some(Protocol::P2p(ref peer_id)) => { - match PeerId::from_multihash(peer_id.clone()) { - Ok(peer_id) => Ok(peer_id), - Err(_) => Err(addr), - } - } - _ => Err(addr), - } -} - -#[cfg(test)] -mod tests { - extern crate libp2p_tcp_transport; - extern crate tokio_current_thread; - - use self::libp2p_tcp_transport::TcpConfig; - use PeerIdTransport; - use futures::{Future, Stream}; - use libp2p_core::{Transport, PeerId, PublicKey}; - use multiaddr::{Protocol, Multiaddr}; - use std::io::Error as IoError; - use std::iter; - - #[test] - fn dial_peer_id() { - // When we dial an `/p2p/...` address, the `PeerIdTransport` should look into the - // peerstore and dial one of the known multiaddresses of the node instead. - - #[derive(Debug, Clone)] - struct UnderlyingTrans { - inner: TcpConfig, - } - impl Transport for UnderlyingTrans { - type Output = ::Output; - type MultiaddrFuture = ::MultiaddrFuture; - type Listener = Box + Send>; - type ListenerUpgrade = Box + Send>; - type Dial = ::Dial; - #[inline] - fn listen_on( - self, - _: Multiaddr, - ) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { - unreachable!() - } - #[inline] - fn dial(self, addr: Multiaddr) -> Result { - assert_eq!( - addr, - "/ip4/127.0.0.1/tcp/12345".parse::().unwrap() - ); - Ok(self.inner.dial(addr).unwrap_or_else(|_| panic!())) - } - #[inline] - fn nat_traversal(&self, a: &Multiaddr, b: &Multiaddr) -> Option { - self.inner.nat_traversal(a, b) - } - } - - let peer_id = PeerId::from_public_key(PublicKey::Ed25519(vec![1, 2, 3, 4])); - - let underlying = UnderlyingTrans { - inner: TcpConfig::new(), - }; - let transport = PeerIdTransport::new(underlying, { - let peer_id = peer_id.clone(); - move |addr| { - assert_eq!(addr, peer_id); - vec!["/ip4/127.0.0.1/tcp/12345".parse().unwrap()] - } - }); - - let future = transport - .dial(iter::once(Protocol::P2p(peer_id.into())).collect()) - .unwrap_or_else(|_| panic!()) - .then::<_, Result<(), ()>>(|_| Ok(())); - - let _ = tokio_current_thread::block_on_all(future).unwrap(); - } -} From 46dd6b61b289699b58df155fb2180c2eafd1523d Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 18 Oct 2018 17:03:47 +0100 Subject: [PATCH 09/19] Fix panicking when Kad responder is destroyed (#575) --- protocols/kad/src/kad_server.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/protocols/kad/src/kad_server.rs b/protocols/kad/src/kad_server.rs index 45a7e7c6396..521bc1a0ee0 100644 --- a/protocols/kad/src/kad_server.rs +++ b/protocols/kad/src/kad_server.rs @@ -360,10 +360,11 @@ where }, Some(EventSource::LocalResponse(message)) => { let future = message - .map_err(|_| { + .map_err(|err| { // The user destroyed the responder without responding. warn!("Kad responder object destroyed without responding"); - panic!() // TODO: what to do here? we have to close the connection + // TODO: what to do here? we have to close the connection + IoError::new(IoErrorKind::Other, err) }) .and_then(move |message| { kad_sink From de26ba1d2dea97d94df68138d090888705d8f11d Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Sat, 20 Oct 2018 13:12:05 +0200 Subject: [PATCH 10/19] Fix the polling process in handled node (#582) --- core/src/nodes/handled_node.rs | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/core/src/nodes/handled_node.rs b/core/src/nodes/handled_node.rs index cc638ab6f26..dd2f2c13b40 100644 --- a/core/src/nodes/handled_node.rs +++ b/core/src/nodes/handled_node.rs @@ -143,6 +143,8 @@ where node: Fuse>, /// Handler that processes substreams. handler: THandler, + /// If true, `handler` has returned `Ready(None)` and therefore shouldn't be polled again. + handler_is_done: bool, // True, if the node is shutting down. is_shutting_down: bool } @@ -158,6 +160,7 @@ where HandledNode { node: NodeStream::new(muxer).fuse(), handler, + handler_is_done: false, is_shutting_down: false } } @@ -196,13 +199,11 @@ where /// After this method returns, `is_shutting_down()` should return true. pub fn shutdown(&mut self) { self.node.get_mut().shutdown_all(); - self.is_shutting_down = true; - for user_data in self.node.get_mut().cancel_outgoing() { self.handler.inject_outbound_closed(user_data); } - - self.handler.shutdown() + self.handler.shutdown(); + self.is_shutting_down = true; } } @@ -216,10 +217,14 @@ where fn poll(&mut self) -> Poll, Self::Error> { loop { + if self.node.is_done() && self.handler_is_done { + return Ok(Async::Ready(None)); + } + let mut node_not_ready = false; match self.node.poll()? { - Async::NotReady => (), + Async::NotReady => node_not_ready = true, Async::Ready(Some(NodeEvent::InboundSubstream { substream })) => { self.handler.inject_substream(substream, NodeHandlerEndpoint::Listener) } @@ -228,8 +233,8 @@ where self.handler.inject_substream(substream, endpoint) } Async::Ready(None) => { - node_not_ready = true; if !self.is_shutting_down { + self.is_shutting_down = true; self.handler.shutdown() } } @@ -241,7 +246,7 @@ where } } - match self.handler.poll()? { + match if self.handler_is_done { Async::Ready(None) } else { self.handler.poll()? } { Async::NotReady => { if node_not_ready { break @@ -261,7 +266,12 @@ where return Ok(Async::Ready(Some(event))); } Async::Ready(None) => { - return Ok(Async::Ready(None)) + self.handler_is_done = true; + if !self.is_shutting_down { + self.is_shutting_down = true; + self.node.get_mut().cancel_outgoing(); + self.node.get_mut().shutdown_all(); + } } } } From 4a894851ab4d555bb267eaa50f5b8842f7117291 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 23 Oct 2018 12:07:06 +0200 Subject: [PATCH 11/19] Remove even more unused files (#581) * Remove even more unused files * Remove dummy.rs as well --- core/src/transport/dummy.rs | 87 ------------------------------------ core/src/transport/muxed.rs | 52 --------------------- core/src/upgrade/map_addr.rs | 80 --------------------------------- 3 files changed, 219 deletions(-) delete mode 100644 core/src/transport/dummy.rs delete mode 100644 core/src/transport/muxed.rs delete mode 100644 core/src/upgrade/map_addr.rs diff --git a/core/src/transport/dummy.rs b/core/src/transport/dummy.rs deleted file mode 100644 index c8c36229b81..00000000000 --- a/core/src/transport/dummy.rs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2017 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -use futures::future; -use multiaddr::Multiaddr; -use std::io::Error as IoError; -use transport::{MuxedTransport, Transport}; - -/// Dummy implementation of `MuxedTransport` that uses an inner `Transport`. -#[derive(Debug, Copy, Clone)] -pub struct DummyMuxing { - inner: T, -} - -impl DummyMuxing { - pub fn new(transport: T) -> DummyMuxing { - DummyMuxing { inner: transport } - } -} - -impl MuxedTransport for DummyMuxing -where - T: Transport, -{ - type Incoming = future::Empty; - type IncomingUpgrade = future::Empty<(T::Output, Self::MultiaddrFuture), IoError>; - - fn next_incoming(self) -> Self::Incoming - where - Self: Sized, - { - future::empty() - } -} - -impl Transport for DummyMuxing -where - T: Transport, -{ - type Output = T::Output; - type MultiaddrFuture = T::MultiaddrFuture; - type Listener = T::Listener; - type ListenerUpgrade = T::ListenerUpgrade; - type Dial = T::Dial; - - #[inline] - fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> - where - Self: Sized, - { - self.inner - .listen_on(addr) - .map_err(|(inner, addr)| (DummyMuxing { inner }, addr)) - } - - #[inline] - fn dial(self, addr: Multiaddr) -> Result - where - Self: Sized, - { - self.inner - .dial(addr) - .map_err(|(inner, addr)| (DummyMuxing { inner }, addr)) - } - - #[inline] - fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { - self.inner.nat_traversal(server, observed) - } -} diff --git a/core/src/transport/muxed.rs b/core/src/transport/muxed.rs deleted file mode 100644 index eb877e27a34..00000000000 --- a/core/src/transport/muxed.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2017 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -use futures::prelude::*; -use futures::stream; -use std::io::Error as IoError; -use transport::Transport; - -/// Extension trait for `Transport`. Implemented on structs that provide a `Transport` on which -/// the dialed node can dial you back. -pub trait MuxedTransport: Transport { - /// Future resolving to a future that will resolve to an incoming connection. - type Incoming: Future; - /// Future resolving to an incoming connection. - type IncomingUpgrade: Future; - - /// Returns the next incoming substream opened by a node that we dialed ourselves. - /// - /// > **Note**: Doesn't produce incoming substreams coming from addresses we are listening on. - /// > This only concerns nodes that we dialed with `dial()`. - fn next_incoming(self) -> Self::Incoming - where - Self: Sized; - - /// Returns a stream of incoming connections. - #[inline] - fn incoming( - self, - ) -> stream::AndThen, fn(Self) -> Self::Incoming, Self::Incoming> - where - Self: Sized + Clone, - { - stream::repeat(self).and_then(|me| me.next_incoming()) - } -} diff --git a/core/src/upgrade/map_addr.rs b/core/src/upgrade/map_addr.rs deleted file mode 100644 index 4b6de993d02..00000000000 --- a/core/src/upgrade/map_addr.rs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -use std::io::Error as IoError; -use futures::{future, prelude::*}; -use tokio_io::{AsyncRead, AsyncWrite}; -use upgrade::{ConnectionUpgrade, Endpoint}; -use Multiaddr; - -/// Applies a closure on the output of a connection upgrade. -#[inline] -pub fn map_with_addr(upgrade: U, map: F) -> MapAddr - where F: FnOnce(I, &Multiaddr) -> O -{ - MapAddr { upgrade, map } -} - -/// Application of a closure on the output of a connection upgrade. -#[derive(Debug, Copy, Clone)] -pub struct MapAddr { - upgrade: U, - map: F, -} - -impl ConnectionUpgrade for MapAddr -where - U: ConnectionUpgrade, - U::Future: Send + 'static, // TODO: 'static :( - U::MultiaddrFuture: Future + Send + 'static, // TODO: 'static :( - U::Output: Send + 'static, // TODO: 'static :( - C: AsyncRead + AsyncWrite, - F: FnOnce(U::Output, &Multiaddr) -> O + Send + 'static, // TODO: 'static :( -{ - type NamesIter = U::NamesIter; - type UpgradeIdentifier = U::UpgradeIdentifier; - - fn protocol_names(&self) -> Self::NamesIter { - self.upgrade.protocol_names() - } - - type Output = O; - type MultiaddrFuture = future::FutureResult; - type Future = Box + Send>; - - fn upgrade( - self, - socket: C, - id: Self::UpgradeIdentifier, - ty: Endpoint, - remote_addr: Maf, - ) -> Self::Future { - let map = self.map; - let fut = self.upgrade - .upgrade(socket, id, ty, remote_addr) - .and_then(|(out, addr)| { - addr.map(move |addr| { - let out = map(out, &addr); - (out, future::ok(addr)) - }) - }); - Box::new(fut) as Box<_> - } -} From 490ae980c7011246ab361b4d3f2791c179670d3d Mon Sep 17 00:00:00 2001 From: jamartin9 Date: Thu, 25 Oct 2018 05:26:37 -0400 Subject: [PATCH 12/19] #399 remove tokio_current_thread tests (#577) * remove tokio_current_thread tests * Review changes: Removed newline Moved uds tokio test crate to top to avoid self and keep with convention of other test crates Removed sleep from uds test and block until all futures are completed. --- Cargo.toml | 2 +- core/Cargo.toml | 1 - core/src/lib.rs | 8 +++---- misc/multistream-select/Cargo.toml | 2 +- misc/multistream-select/src/lib.rs | 12 +++++++---- .../multistream-select/src/protocol/dialer.rs | 6 ++++-- .../src/protocol/listener.rs | 6 ++++-- misc/multistream-select/src/tests.rs | 21 +++++++++++-------- muxers/mplex/Cargo.toml | 2 +- muxers/mplex/tests/two_peers.rs | 15 ++++++++----- protocols/identify/Cargo.toml | 2 +- protocols/identify/src/protocol.rs | 11 +++++----- protocols/kad/Cargo.toml | 2 +- protocols/kad/src/protocol.rs | 12 ++++++----- protocols/ping/Cargo.toml | 2 +- protocols/ping/src/lib.rs | 17 ++++++++------- protocols/secio/Cargo.toml | 2 +- protocols/secio/src/codec/mod.rs | 9 +++++--- protocols/secio/src/handshake.rs | 7 ++++--- protocols/secio/src/lib.rs | 6 ++++-- transports/dns/Cargo.toml | 1 + transports/tcp/Cargo.toml | 2 +- transports/tcp/src/lib.rs | 17 ++++++++------- transports/uds/Cargo.toml | 2 +- transports/uds/src/lib.rs | 20 ++++++++++-------- transports/websocket/Cargo.toml | 2 +- transports/websocket/src/desktop.rs | 10 ++++++--- 27 files changed, 117 insertions(+), 82 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0d95e2314ed..50ac9e40d71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ bigint = "4.2" env_logger = "0.5.4" rand = "0.4" structopt = "0.2" -tokio-current-thread = "0.1" +tokio = "0.1" tokio-io = "0.1" tokio-stdin = "0.1" diff --git a/core/Cargo.toml b/core/Cargo.toml index 048c464e3c7..ba64ec2d4ca 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -29,7 +29,6 @@ libp2p-mplex = { path = "../muxers/mplex" } rand = "0.5" tokio = "0.1" tokio-codec = "0.1" -tokio-current-thread = "0.1" tokio-timer = "0.2" assert_matches = "1.3" tokio-mock-task = "0.1" diff --git a/core/src/lib.rs b/core/src/lib.rs index 798405bba50..82ee1a8283c 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -129,11 +129,12 @@ //! extern crate libp2p_ping; //! extern crate libp2p_core; //! extern crate libp2p_tcp_transport; -//! extern crate tokio_current_thread; +//! extern crate tokio; //! //! use futures::{Future, Stream}; //! use libp2p_ping::{Ping, PingOutput}; //! use libp2p_core::Transport; +//! use tokio::runtime::current_thread::Runtime; //! //! # fn main() { //! let ping_finished_future = libp2p_tcp_transport::TcpConfig::new() @@ -154,7 +155,8 @@ //! }); //! //! // Runs until the ping arrives. -//! tokio_current_thread::block_on_all(ping_finished_future).unwrap(); +//! let mut rt = Runtime::new().unwrap(); +//! let _ = rt.block_on(ping_finished_future).unwrap(); //! # } //! ``` //! @@ -191,8 +193,6 @@ extern crate tokio; #[cfg(test)] extern crate tokio_codec; #[cfg(test)] -extern crate tokio_current_thread; -#[cfg(test)] extern crate tokio_timer; #[cfg(test)] #[macro_use] diff --git a/misc/multistream-select/Cargo.toml b/misc/multistream-select/Cargo.toml index 0be9b8c7b58..fadd6812276 100644 --- a/misc/multistream-select/Cargo.toml +++ b/misc/multistream-select/Cargo.toml @@ -14,5 +14,5 @@ tokio-io = "0.1" unsigned-varint = { version = "0.2.1", features = ["codec"] } [dev-dependencies] -tokio-current-thread = "0.1" +tokio = "0.1" tokio-tcp = "0.1" diff --git a/misc/multistream-select/src/lib.rs b/misc/multistream-select/src/lib.rs index 1e1c0dffa8f..102dc37ad91 100644 --- a/misc/multistream-select/src/lib.rs +++ b/misc/multistream-select/src/lib.rs @@ -45,7 +45,7 @@ //! extern crate bytes; //! extern crate futures; //! extern crate multistream_select; -//! extern crate tokio_current_thread; +//! extern crate tokio; //! extern crate tokio_tcp; //! //! # fn main() { @@ -53,6 +53,7 @@ //! use multistream_select::dialer_select_proto; //! use futures::{Future, Sink, Stream}; //! use tokio_tcp::TcpStream; +//! use tokio::runtime::current_thread::Runtime; //! //! #[derive(Debug, Copy, Clone)] //! enum MyProto { Echo, Hello } @@ -68,7 +69,8 @@ //! dialer_select_proto(connec, protos).map(|r| r.0) //! }); //! -//! let negotiated_protocol: MyProto = tokio_current_thread::block_on_all(client) +//! let mut rt = Runtime::new().unwrap(); +//! let negotiated_protocol: MyProto = rt.block_on(client) //! .expect("failed to find a protocol"); //! println!("negotiated: {:?}", negotiated_protocol); //! # } @@ -80,7 +82,7 @@ //! extern crate bytes; //! extern crate futures; //! extern crate multistream_select; -//! extern crate tokio_current_thread; +//! extern crate tokio; //! extern crate tokio_tcp; //! //! # fn main() { @@ -88,6 +90,7 @@ //! use multistream_select::listener_select_proto; //! use futures::{Future, Sink, Stream}; //! use tokio_tcp::TcpListener; +//! use tokio::runtime::current_thread::Runtime; //! //! #[derive(Debug, Copy, Clone)] //! enum MyProto { Echo, Hello } @@ -108,7 +111,8 @@ //! Ok(()) //! }); //! -//! tokio_current_thread::block_on_all(server).expect("failed to run server"); +//! let mut rt = Runtime::new().unwrap(); +//! let _ = rt.block_on(server).expect("failed to run server"); //! # } //! ``` diff --git a/misc/multistream-select/src/protocol/dialer.rs b/misc/multistream-select/src/protocol/dialer.rs index 21c884fbd61..996b6447d6d 100644 --- a/misc/multistream-select/src/protocol/dialer.rs +++ b/misc/multistream-select/src/protocol/dialer.rs @@ -183,8 +183,9 @@ impl Future for DialerFuture { #[cfg(test)] mod tests { - extern crate tokio_current_thread; + extern crate tokio; extern crate tokio_tcp; + use self::tokio::runtime::current_thread::Runtime; use self::tokio_tcp::{TcpListener, TcpStream}; use bytes::Bytes; use futures::Future; @@ -210,7 +211,8 @@ mod tests { dialer.send(DialerToListenerMessage::ProtocolRequest { name: p }) }); - match tokio_current_thread::block_on_all(server.join(client)) { + let mut rt = Runtime::new().unwrap(); + match rt.block_on(server.join(client)) { Err(MultistreamSelectError::WrongProtocolName) => (), _ => panic!(), } diff --git a/misc/multistream-select/src/protocol/listener.rs b/misc/multistream-select/src/protocol/listener.rs index d39fe86ec14..e20f3a503ea 100644 --- a/misc/multistream-select/src/protocol/listener.rs +++ b/misc/multistream-select/src/protocol/listener.rs @@ -225,8 +225,9 @@ impl Future for ListenerFuture { #[cfg(test)] mod tests { - extern crate tokio_current_thread; + extern crate tokio; extern crate tokio_tcp; + use self::tokio::runtime::current_thread::Runtime; use self::tokio_tcp::{TcpListener, TcpStream}; use bytes::Bytes; use futures::Future; @@ -252,7 +253,8 @@ mod tests { .from_err() .and_then(move |stream| Dialer::new(stream)); - match tokio_current_thread::block_on_all(server.join(client)) { + let mut rt = Runtime::new().unwrap(); + match rt.block_on(server.join(client)) { Err(MultistreamSelectError::WrongProtocolName) => (), _ => panic!(), } diff --git a/misc/multistream-select/src/tests.rs b/misc/multistream-select/src/tests.rs index b9bd569de3d..6120bea6a23 100644 --- a/misc/multistream-select/src/tests.rs +++ b/misc/multistream-select/src/tests.rs @@ -22,9 +22,10 @@ #![cfg(test)] -extern crate tokio_current_thread; +extern crate tokio; extern crate tokio_tcp; +use self::tokio::runtime::current_thread::Runtime; use self::tokio_tcp::{TcpListener, TcpStream}; use bytes::Bytes; use dialer_select::{dialer_select_proto_parallel, dialer_select_proto_serial}; @@ -69,8 +70,8 @@ fn negotiate_with_self_succeeds() { assert_eq!(proto, "/hello/1.0.0"); Ok(()) }); - - tokio_current_thread::block_on_all(server.join(client)).unwrap(); + let mut rt = Runtime::new().unwrap(); + let _ = rt.block_on(server.join(client)).unwrap(); } #[test] @@ -100,9 +101,9 @@ fn select_proto_basic() { ].into_iter(); dialer_select_proto(connec, protos).map(|r| r.0) }); - + let mut rt = Runtime::new().unwrap(); let (dialer_chosen, listener_chosen) = - tokio_current_thread::block_on_all(client.join(server)).unwrap(); + rt.block_on(client.join(server)).unwrap(); assert_eq!(dialer_chosen, 3); assert_eq!(listener_chosen, 1); } @@ -134,8 +135,8 @@ fn no_protocol_found() { ].into_iter(); dialer_select_proto(connec, protos).map(|r| r.0) }); - - match tokio_current_thread::block_on_all(client.join(server)) { + let mut rt = Runtime::new().unwrap(); + match rt.block_on(client.join(server)) { Err(ProtocolChoiceError::NoProtocolFound) => (), _ => panic!(), } @@ -169,8 +170,9 @@ fn select_proto_parallel() { dialer_select_proto_parallel(connec, protos).map(|r| r.0) }); + let mut rt = Runtime::new().unwrap(); let (dialer_chosen, listener_chosen) = - tokio_current_thread::block_on_all(client.join(server)).unwrap(); + rt.block_on(client.join(server)).unwrap(); assert_eq!(dialer_chosen, 3); assert_eq!(listener_chosen, 1); } @@ -200,8 +202,9 @@ fn select_proto_serial() { dialer_select_proto_serial(connec, protos).map(|r| r.0) }); + let mut rt = Runtime::new().unwrap(); let (dialer_chosen, listener_chosen) = - tokio_current_thread::block_on_all(client.join(server)).unwrap(); + rt.block_on(client.join(server)).unwrap(); assert_eq!(dialer_chosen, 3); assert_eq!(listener_chosen, 1); } diff --git a/muxers/mplex/Cargo.toml b/muxers/mplex/Cargo.toml index 0f2fbf82c97..20fe408cbf7 100644 --- a/muxers/mplex/Cargo.toml +++ b/muxers/mplex/Cargo.toml @@ -17,4 +17,4 @@ unsigned-varint = { version = "0.2.1", features = ["codec"] } [dev-dependencies] libp2p-tcp-transport = { path = "../../transports/tcp" } -tokio-current-thread = "0.1" +tokio = "0.1" diff --git a/muxers/mplex/tests/two_peers.rs b/muxers/mplex/tests/two_peers.rs index 26fd1507db4..caf081a233a 100644 --- a/muxers/mplex/tests/two_peers.rs +++ b/muxers/mplex/tests/two_peers.rs @@ -23,7 +23,7 @@ extern crate futures; extern crate libp2p_mplex as multiplex; extern crate libp2p_core as swarm; extern crate libp2p_tcp_transport as tcp; -extern crate tokio_current_thread; +extern crate tokio; extern crate tokio_io; use futures::future::Future; @@ -33,6 +33,7 @@ use std::thread; use swarm::{muxing, Transport}; use tcp::TcpConfig; use tokio_io::codec::length_delimited::Framed; +use tokio::runtime::current_thread::Runtime; #[test] fn client_to_server_outbound() { @@ -67,7 +68,8 @@ fn client_to_server_outbound() { Ok(()) }); - tokio_current_thread::block_on_all(future).unwrap(); + let mut rt = Runtime::new().unwrap(); + let _ = rt.block_on(future).unwrap(); }); let transport = TcpConfig::new().with_upgrade(multiplex::MplexConfig::new()); @@ -80,7 +82,8 @@ fn client_to_server_outbound() { .and_then(|server| server.send("hello world".into())) .map(|_| ()); - tokio_current_thread::block_on_all(future).unwrap(); + let mut rt = Runtime::new().unwrap(); + let _ = rt.block_on(future).unwrap(); bg_thread.join().unwrap(); } @@ -117,7 +120,8 @@ fn client_to_server_inbound() { Ok(()) }); - tokio_current_thread::block_on_all(future).unwrap(); + let mut rt = Runtime::new().unwrap(); + let _ = rt.block_on(future).unwrap(); }); let transport = TcpConfig::new().with_upgrade(multiplex::MplexConfig::new()); @@ -130,6 +134,7 @@ fn client_to_server_inbound() { .and_then(|server| server.send("hello world".into())) .map(|_| ()); - tokio_current_thread::block_on_all(future).unwrap(); + let mut rt = Runtime::new().unwrap(); + let _ = rt.block_on(future).unwrap(); bg_thread.join().unwrap(); } diff --git a/protocols/identify/Cargo.toml b/protocols/identify/Cargo.toml index e055733ea33..b2170f5622f 100644 --- a/protocols/identify/Cargo.toml +++ b/protocols/identify/Cargo.toml @@ -22,4 +22,4 @@ void = "1.0" [dev-dependencies] libp2p-tcp-transport = { path = "../../transports/tcp" } -tokio-current-thread = "0.1" +tokio = "0.1" diff --git a/protocols/identify/src/protocol.rs b/protocols/identify/src/protocol.rs index 671dbc6bdd1..44e1987348d 100644 --- a/protocols/identify/src/protocol.rs +++ b/protocols/identify/src/protocol.rs @@ -211,8 +211,9 @@ fn parse_proto_msg(msg: BytesMut) -> Result<(IdentifyInfo, Multiaddr), IoError> #[cfg(test)] mod tests { extern crate libp2p_tcp_transport; - extern crate tokio_current_thread; + extern crate tokio; + use self::tokio::runtime::current_thread::Runtime; use self::libp2p_tcp_transport::TcpConfig; use futures::{Future, Stream}; use libp2p_core::{PublicKey, Transport}; @@ -255,8 +256,8 @@ mod tests { ), _ => panic!(), }); - - let _ = tokio_current_thread::block_on_all(future).unwrap(); + let mut rt = Runtime::new().unwrap(); + let _ = rt.block_on(future).unwrap(); }); let transport = TcpConfig::new().with_upgrade(IdentifyProtocolConfig); @@ -291,8 +292,8 @@ mod tests { } _ => panic!(), }); - - let _ = tokio_current_thread::block_on_all(future).unwrap(); + let mut rt = Runtime::new().unwrap(); + let _ = rt.block_on(future).unwrap(); bg_thread.join().unwrap(); } } diff --git a/protocols/kad/Cargo.toml b/protocols/kad/Cargo.toml index 12a85722320..1bf934264eb 100644 --- a/protocols/kad/Cargo.toml +++ b/protocols/kad/Cargo.toml @@ -30,4 +30,4 @@ unsigned-varint = { version = "0.2.1", features = ["codec"] } [dev-dependencies] libp2p-tcp-transport = { path = "../../transports/tcp" } rand = "0.4.2" -tokio-current-thread = "0.1" +tokio = "0.1" diff --git a/protocols/kad/src/protocol.rs b/protocols/kad/src/protocol.rs index 3ef816486e2..2ba18e5e786 100644 --- a/protocols/kad/src/protocol.rs +++ b/protocols/kad/src/protocol.rs @@ -409,7 +409,7 @@ fn proto_to_msg(mut message: protobuf_structs::dht::Message) -> Result unreachable!(), }) .map(|_| ()); - - tokio_current_thread::block_on_all(server.select(client).map_err(|_| panic!())).unwrap(); + let mut rt = Runtime::new().unwrap(); + let _ = rt.block_on(server.select(client).map_err(|_| panic!())).unwrap(); } #[test] @@ -489,7 +492,7 @@ mod tests { }, _ => unreachable!(), }); - - tokio_current_thread::block_on_all(server.select(client)).unwrap_or_else(|_| panic!()); + let mut rt = Runtime::new().unwrap(); + let _ = rt.block_on(server.select(client)).unwrap_or_else(|_| panic!()); } } diff --git a/protocols/secio/Cargo.toml b/protocols/secio/Cargo.toml index 3a156ba95dd..09511affbfa 100644 --- a/protocols/secio/Cargo.toml +++ b/protocols/secio/Cargo.toml @@ -40,5 +40,5 @@ aes-all = ["aesni", "lazy_static"] [dev-dependencies] libp2p-tcp-transport = { path = "../../transports/tcp" } -tokio-current-thread = "0.1" +tokio = "0.1" tokio-tcp = "0.1" diff --git a/protocols/secio/src/codec/mod.rs b/protocols/secio/src/codec/mod.rs index 5394a33e013..a15d3c867d4 100644 --- a/protocols/secio/src/codec/mod.rs +++ b/protocols/secio/src/codec/mod.rs @@ -119,8 +119,9 @@ where #[cfg(test)] mod tests { - extern crate tokio_current_thread; + extern crate tokio; extern crate tokio_tcp; + use self::tokio::runtime::current_thread::Runtime; use self::tokio_tcp::TcpListener; use self::tokio_tcp::TcpStream; use stream_cipher::{ctr, Cipher}; @@ -164,8 +165,9 @@ mod tests { let data_sent = encoder.send(BytesMut::from(data.to_vec())).from_err(); let data_received = decoder.into_future().map(|(n, _)| n).map_err(|(e, _)| e); + let mut rt = Runtime::new().unwrap(); - let (_, decoded) = tokio_current_thread::block_on_all(data_sent.join(data_received)) + let (_, decoded) = rt.block_on(data_sent.join(data_received)) .map_err(|_| ()) .unwrap(); assert_eq!(&decoded.unwrap()[..], &data[..]); @@ -223,7 +225,8 @@ mod tests { .and_then(|server| server.into_future().map_err(|(e, _)| e.into())) .map(|recved| recved.0.unwrap().to_vec()); - let received = tokio_current_thread::block_on_all(fin).unwrap(); + let mut rt = Runtime::new().unwrap(); + let received = rt.block_on(fin).unwrap(); assert_eq!(received, data); } diff --git a/protocols/secio/src/handshake.rs b/protocols/secio/src/handshake.rs index 5c5756581b8..18e2de7feac 100644 --- a/protocols/secio/src/handshake.rs +++ b/protocols/secio/src/handshake.rs @@ -646,8 +646,9 @@ where ::hmac::Hmac: Clone { #[cfg(test)] mod tests { - extern crate tokio_current_thread; + extern crate tokio; extern crate tokio_tcp; + use self::tokio::runtime::current_thread::Runtime; use self::tokio_tcp::TcpListener; use self::tokio_tcp::TcpStream; use super::handshake; @@ -712,8 +713,8 @@ mod tests { let client = TcpStream::connect(&listener_addr) .map_err(|e| e.into()) .and_then(move |stream| handshake(stream, key2)); - - tokio_current_thread::block_on_all(server.join(client)).unwrap(); + let mut rt = Runtime::new().unwrap(); + let _ = rt.block_on(server.join(client)).unwrap(); } #[test] diff --git a/protocols/secio/src/lib.rs b/protocols/secio/src/lib.rs index 8ec9991ac78..8ccc2310559 100644 --- a/protocols/secio/src/lib.rs +++ b/protocols/secio/src/lib.rs @@ -30,7 +30,7 @@ //! //! ```no_run //! extern crate futures; -//! extern crate tokio_current_thread; +//! extern crate tokio; //! extern crate tokio_io; //! extern crate libp2p_core; //! extern crate libp2p_secio; @@ -42,6 +42,7 @@ //! use libp2p_core::{Multiaddr, Transport, upgrade}; //! use libp2p_tcp_transport::TcpConfig; //! use tokio_io::io::write_all; +//! use tokio::runtime::current_thread::Runtime; //! //! let transport = TcpConfig::new() //! .with_upgrade({ @@ -63,7 +64,8 @@ //! write_all(connection, "hello world") //! }); //! -//! tokio_current_thread::block_on_all(future).unwrap(); +//! let mut rt = Runtime::new().unwrap(); +//! let _ = rt.block_on(future).unwrap(); //! # } //! ``` //! diff --git a/transports/dns/Cargo.toml b/transports/dns/Cargo.toml index c67135c9937..5f73b959dc9 100644 --- a/transports/dns/Cargo.toml +++ b/transports/dns/Cargo.toml @@ -14,3 +14,4 @@ tokio-io = "0.1" [dev-dependencies] libp2p-tcp-transport = { path = "../../transports/tcp" } +tokio = "0.1" \ No newline at end of file diff --git a/transports/tcp/Cargo.toml b/transports/tcp/Cargo.toml index 51ea0a960d4..4111e10e701 100644 --- a/transports/tcp/Cargo.toml +++ b/transports/tcp/Cargo.toml @@ -14,4 +14,4 @@ tokio-io = "0.1" tokio-tcp = "0.1" [dev-dependencies] -tokio-current-thread = "0.1" +tokio = "0.1" diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index 2064003eb39..e0b7ab42f3e 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -47,9 +47,6 @@ extern crate tk_listen; extern crate tokio_io; extern crate tokio_tcp; -#[cfg(test)] -extern crate tokio_current_thread; - use futures::{future, future::FutureResult, prelude::*, Async, Poll}; use multiaddr::{Protocol, Multiaddr, ToMultiaddr}; use std::fmt; @@ -394,6 +391,8 @@ impl Drop for TcpTransStream { #[cfg(test)] mod tests { + extern crate tokio; + use self::tokio::runtime::current_thread::Runtime; use super::{multiaddr_to_socketaddr, TcpConfig}; use futures::stream::Stream; use futures::Future; @@ -401,7 +400,6 @@ mod tests { use std; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use swarm::Transport; - use tokio_current_thread; use tokio_io; #[test] @@ -460,6 +458,8 @@ mod tests { std::thread::spawn(move || { let addr = "/ip4/127.0.0.1/tcp/12345".parse::().unwrap(); let tcp = TcpConfig::new(); + let mut rt = Runtime::new().unwrap(); + let handle = rt.handle(); let listener = tcp.listen_on(addr).unwrap().0.for_each(|(sock, _)| { sock.and_then(|sock| { // Define what to do with the socket that just connected to us @@ -469,13 +469,14 @@ mod tests { .map_err(|err| panic!("IO error {:?}", err)); // Spawn the future as a concurrent task - tokio_current_thread::spawn(handle_conn); + handle.spawn(handle_conn).unwrap(); Ok(()) }) }); - tokio_current_thread::block_on_all(listener).unwrap(); + rt.block_on(listener).unwrap(); + rt.run().unwrap(); }); std::thread::sleep(std::time::Duration::from_millis(100)); let addr = "/ip4/127.0.0.1/tcp/12345".parse::().unwrap(); @@ -488,8 +489,8 @@ mod tests { Ok(()) }); // Execute the future in our event loop - tokio_current_thread::block_on_all(action).unwrap(); - std::thread::sleep(std::time::Duration::from_millis(100)); + let mut rt = Runtime::new().unwrap(); + let _ = rt.block_on(action).unwrap(); } #[test] diff --git a/transports/uds/Cargo.toml b/transports/uds/Cargo.toml index 0b84a62a8e1..132aa3a8eb6 100644 --- a/transports/uds/Cargo.toml +++ b/transports/uds/Cargo.toml @@ -13,5 +13,5 @@ tokio-uds = "0.2" [target.'cfg(all(unix, not(target_os = "emscripten")))'.dev-dependencies] tempfile = "3.0" -tokio-current-thread = "0.1" +tokio = "0.1" tokio-io = "0.1" diff --git a/transports/uds/src/lib.rs b/transports/uds/src/lib.rs index c326fa9f7d3..9f6cb8f7069 100644 --- a/transports/uds/src/lib.rs +++ b/transports/uds/src/lib.rs @@ -56,9 +56,9 @@ extern crate tokio_uds; #[cfg(test)] extern crate tempfile; #[cfg(test)] -extern crate tokio_current_thread; -#[cfg(test)] extern crate tokio_io; +#[cfg(test)] +extern crate tokio; use futures::future::{self, Future, FutureResult}; use futures::stream::Stream; @@ -164,6 +164,7 @@ fn multiaddr_to_path(addr: &Multiaddr) -> Result { #[cfg(test)] mod tests { + use tokio::runtime::current_thread::Runtime; use super::{multiaddr_to_path, UdsConfig}; use futures::stream::Stream; use futures::Future; @@ -171,7 +172,6 @@ mod tests { use std::{self, borrow::Cow, path::Path}; use libp2p_core::Transport; use tempfile; - use tokio_current_thread; use tokio_io; #[test] @@ -194,7 +194,6 @@ mod tests { #[test] fn communicating_between_dialer_and_listener() { use std::io::Write; - let temp_dir = tempfile::tempdir().unwrap(); let socket = temp_dir.path().join("socket"); let addr = Multiaddr::from(Protocol::Unix(Cow::Owned(socket.to_string_lossy().into_owned()))); @@ -202,6 +201,9 @@ mod tests { std::thread::spawn(move || { let tcp = UdsConfig::new(); + + let mut rt = Runtime::new().unwrap(); + let handle = rt.handle(); let listener = tcp.listen_on(addr2).unwrap().0.for_each(|(sock, _)| { sock.and_then(|sock| { // Define what to do with the socket that just connected to us @@ -211,13 +213,13 @@ mod tests { .map_err(|err| panic!("IO error {:?}", err)); // Spawn the future as a concurrent task - tokio_current_thread::spawn(handle_conn); - + handle.spawn(handle_conn).unwrap(); Ok(()) }) }); - tokio_current_thread::block_on_all(listener).unwrap(); + rt.block_on(listener).unwrap(); + rt.run().unwrap(); }); std::thread::sleep(std::time::Duration::from_millis(100)); let tcp = UdsConfig::new(); @@ -229,8 +231,8 @@ mod tests { Ok(()) }); // Execute the future in our event loop - tokio_current_thread::block_on_all(action).unwrap(); - std::thread::sleep(std::time::Duration::from_millis(100)); + let mut rt = Runtime::new().unwrap(); + let _ = rt.block_on(action).unwrap(); } #[test] diff --git a/transports/websocket/Cargo.toml b/transports/websocket/Cargo.toml index 1a24209d792..addbb90cfba 100644 --- a/transports/websocket/Cargo.toml +++ b/transports/websocket/Cargo.toml @@ -22,4 +22,4 @@ stdweb = { version = "0.1.3", default-features = false } [target.'cfg(not(target_os = "emscripten"))'.dev-dependencies] libp2p-tcp-transport = { path = "../tcp" } -tokio-current-thread = "0.1" +tokio = "0.1" diff --git a/transports/websocket/src/desktop.rs b/transports/websocket/src/desktop.rs index 14275074d60..5c347fd9cdd 100644 --- a/transports/websocket/src/desktop.rs +++ b/transports/websocket/src/desktop.rs @@ -259,7 +259,8 @@ fn client_addr_to_ws(client_addr: &Multiaddr, is_wss: bool) -> String { #[cfg(test)] mod tests { extern crate libp2p_tcp_transport as tcp; - extern crate tokio_current_thread; + extern crate tokio; + use self::tokio::runtime::current_thread::Runtime; use futures::{Future, Stream}; use multiaddr::Multiaddr; use swarm::Transport; @@ -285,7 +286,8 @@ mod tests { .select(dialer) .map_err(|(e, _)| e) .and_then(|(_, n)| n); - tokio_current_thread::block_on_all(future).unwrap(); + let mut rt = Runtime::new().unwrap(); + let _ = rt.block_on(future).unwrap(); } #[test] @@ -308,7 +310,9 @@ mod tests { .select(dialer) .map_err(|(e, _)| e) .and_then(|(_, n)| n); - tokio_current_thread::block_on_all(future).unwrap(); + + let mut rt = Runtime::new().unwrap(); + let _ = rt.block_on(future).unwrap(); } #[test] From 16d5bc777a38c1d1ae1fcdc75817b24d7a690ac9 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 26 Oct 2018 11:07:59 +0200 Subject: [PATCH 13/19] Add a TransportExt trait (#533) * Add a TransportExt trait * Fix concerns * Comment out with_rate_limit * Remove example * Address concerns and restore method --- Cargo.toml | 1 + src/lib.rs | 5 +++ src/transport_ext.rs | 97 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 src/transport_ext.rs diff --git a/Cargo.toml b/Cargo.toml index 50ac9e40d71..85dd7987817 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ libp2p-uds = { path = "./transports/uds" } libp2p-websocket = { path = "./transports/websocket" } libp2p-yamux = { path = "./muxers/yamux" } tokio-codec = "0.1" +tokio-executor = "0.1" tokio-io = "0.1" [target.'cfg(not(target_os = "emscripten"))'.dependencies] diff --git a/src/lib.rs b/src/lib.rs index b43f807192f..71550220a1d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -138,6 +138,8 @@ pub extern crate multiaddr; pub extern crate tokio_io; pub extern crate tokio_codec; +extern crate tokio_executor; + pub extern crate libp2p_core as core; #[cfg(not(target_os = "emscripten"))] pub extern crate libp2p_dns as dns; @@ -157,11 +159,14 @@ pub extern crate libp2p_uds as uds; pub extern crate libp2p_websocket as websocket; pub extern crate libp2p_yamux as yamux; +mod transport_ext; + pub mod simple; pub use self::core::{Transport, ConnectionUpgrade, PeerId}; pub use self::multiaddr::Multiaddr; pub use self::simple::SimpleProtocol; +pub use self::transport_ext::TransportExt; pub use self::transport_timeout::TransportTimeout; /// Implementation of `Transport` that supports the most common protocols. diff --git a/src/transport_ext.rs b/src/transport_ext.rs new file mode 100644 index 00000000000..2d9c8e71d5a --- /dev/null +++ b/src/transport_ext.rs @@ -0,0 +1,97 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +//! Provides the `TransportExt` trait. + +use ratelimit::RateLimited; +use std::io; +use std::time::Duration; +use tokio_executor::DefaultExecutor; +use transport_timeout::TransportTimeout; +use Transport; + +/// Trait automatically implemented on all objects that implement `Transport`. Provides some +/// additional utilities. +/// +/// # Example +/// +/// ``` +/// use libp2p::TransportExt; +/// use libp2p::tcp::TcpConfig; +/// use std::time::Duration; +/// +/// let _transport = TcpConfig::new() +/// .with_timeout(Duration::from_secs(20)) +/// .with_rate_limit(1024 * 1024, 1024 * 1024); +/// ``` +/// +pub trait TransportExt: Transport { + /// Adds a timeout to the connection and upgrade steps for all the sockets created by + /// the transport. + #[inline] + fn with_timeout(self, timeout: Duration) -> TransportTimeout + where + Self: Sized, + { + TransportTimeout::new(self, timeout) + } + + /// Adds a timeout to the connection and upgrade steps for all the outgoing sockets created + /// by the transport. + #[inline] + fn with_outbound_timeout(self, timeout: Duration) -> TransportTimeout + where + Self: Sized, + { + TransportTimeout::with_outgoing_timeout(self, timeout) + } + + /// Adds a timeout to the connection and upgrade steps for all the incoming sockets created + /// by the transport. + #[inline] + fn with_inbound_timeout(self, timeout: Duration) -> TransportTimeout + where + Self: Sized, + { + TransportTimeout::with_ingoing_timeout(self, timeout) + } + + /// Adds a maximum transfer rate to the sockets created with the transport. + #[inline] + fn with_rate_limit( + self, + max_read_bytes_per_sec: usize, + max_write_bytes_per_sec: usize, + ) -> io::Result> + where + Self: Sized, + { + RateLimited::new( + &mut DefaultExecutor::current(), + self, + max_read_bytes_per_sec, + max_write_bytes_per_sec, + ) + } + + // TODO: add methods to easily upgrade for secio/mplex/yamux +} + +impl TransportExt for TTransport where TTransport: Transport {} From 585c90a33c92493e4b0208334fb4d31b6df5d47f Mon Sep 17 00:00:00 2001 From: Toralf Wittner Date: Sun, 28 Oct 2018 11:02:26 +0100 Subject: [PATCH 14/19] Add protocol to report external address view. (#566) Add protocol to report external address view. Address part of #443. --- Cargo.toml | 1 + core/src/upgrade/traits.rs | 7 +- protocols/observed/Cargo.toml | 16 ++++ protocols/observed/src/lib.rs | 158 ++++++++++++++++++++++++++++++++++ 4 files changed, 176 insertions(+), 6 deletions(-) create mode 100644 protocols/observed/Cargo.toml create mode 100644 protocols/observed/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 85dd7987817..341e829d764 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,6 +60,7 @@ members = [ "protocols/identify", "protocols/kad", "protocols/ping", + "protocols/observed", "transports/relay", "protocols/secio", "muxers/mplex", diff --git a/core/src/upgrade/traits.rs b/core/src/upgrade/traits.rs index 82efde57b7f..16493e4cf1b 100644 --- a/core/src/upgrade/traits.rs +++ b/core/src/upgrade/traits.rs @@ -75,10 +75,5 @@ pub trait ConnectionUpgrade { /// /// Because performing the upgrade may not be instantaneous (eg. it may require a handshake), /// this function returns a future instead of the direct output. - fn upgrade( - self, - socket: C, - id: Self::UpgradeIdentifier, - ty: Endpoint, - ) -> Self::Future; + fn upgrade(self, socket: C, id: Self::UpgradeIdentifier, ty: Endpoint) -> Self::Future; } diff --git a/protocols/observed/Cargo.toml b/protocols/observed/Cargo.toml new file mode 100644 index 00000000000..74f08a884ba --- /dev/null +++ b/protocols/observed/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "libp2p-observed-address" +version = "0.1.0" +authors = ["Parity Technologies "] +license = "MIT" + +[dependencies] +bytes = "0.4" +futures = "0.1" +libp2p-core = { path = "../../core" } +tokio-codec = "0.1" +tokio-io = "0.1" +unsigned-varint = { version = "0.2.1", features = ["codec"] } + +[dev-dependencies] +tokio = "0.1" diff --git a/protocols/observed/src/lib.rs b/protocols/observed/src/lib.rs new file mode 100644 index 00000000000..be17b1a4145 --- /dev/null +++ b/protocols/observed/src/lib.rs @@ -0,0 +1,158 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +//! Connection upgrade to allow retrieving the externally visible address (as dialer) or +//! to report the externally visible address (as listener). + +extern crate bytes; +extern crate futures; +extern crate libp2p_core; +extern crate tokio_codec; +extern crate tokio_io; +extern crate unsigned_varint; + +use bytes::Bytes; +use futures::{future, prelude::*}; +use libp2p_core::{ConnectionUpgrade, Endpoint, Multiaddr}; +use std::{io, iter}; +use tokio_codec::{FramedRead, FramedWrite}; +use tokio_io::{AsyncRead, AsyncWrite}; +use unsigned_varint::codec::UviBytes; + +/// The output, this connection upgrade produces. +pub enum Output { + /// As `Dialer`, we get our own externally observed address. + Address(Multiaddr), + /// As `Listener`, we return a sender which allows reporting the observed + /// address the client. + Sender(Sender) +} + +/// `Sender` allows reporting back the observed address to the remote endpoint. +pub struct Sender { + io: FramedWrite +} + +impl Sender { + /// Send address `a` to remote as the observed address. + pub fn send_address(self, a: Multiaddr) -> impl Future { + self.io.send(Bytes::from(a.into_bytes())).map(|_io| ()) + } +} + +/// The connection upgrade type to retrieve or report externally visible addresses. +pub struct Observed {} + +impl Observed { + pub fn new() -> Self { + Observed {} + } +} + +impl ConnectionUpgrade for Observed +where + C: AsyncRead + AsyncWrite + Send + 'static +{ + type NamesIter = iter::Once<(Bytes, Self::UpgradeIdentifier)>; + type UpgradeIdentifier = (); + type Output = Output; + type Future = Box + Send>; + + fn protocol_names(&self) -> Self::NamesIter { + iter::once((Bytes::from("/paritytech/observed-address/0.1.0"), ())) + } + + fn upgrade(self, conn: C, _: (), role: Endpoint) -> Self::Future { + match role { + Endpoint::Dialer => { + let io = FramedRead::new(conn, UviBytes::default()); + let future = io.into_future() + .map_err(|(e, _): (io::Error, FramedRead)| e) + .and_then(move |(bytes, _)| { + if let Some(b) = bytes { + let ma = Multiaddr::from_bytes(b.to_vec()) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + Ok(Output::Address(ma)) + } else { + Err(io::ErrorKind::InvalidData.into()) + } + }); + Box::new(future) + } + Endpoint::Listener => { + let io = FramedWrite::new(conn, UviBytes::default()); + Box::new(future::ok(Output::Sender(Sender { io }))) + } + } + } +} + +#[cfg(test)] +mod tests { + extern crate tokio; + + use libp2p_core::{ConnectionUpgrade, Endpoint, Multiaddr}; + use self::tokio::runtime::current_thread; + use self::tokio::net::{TcpListener, TcpStream}; + use super::*; + + #[test] + fn observed_address() { + let server = TcpListener::bind(&"127.0.0.1:0".parse().unwrap()).unwrap(); + let server_addr = server.local_addr().unwrap(); + + let observed_addr1: Multiaddr = "/ip4/127.0.0.1/tcp/10000".parse().unwrap(); + let observed_addr2 = observed_addr1.clone(); + + let server = server.incoming() + .into_future() + .map_err(|(e, _)| e.into()) + .and_then(move |(conn, _)| { + Observed::new().upgrade(conn.unwrap(), (), Endpoint::Listener) + }) + .and_then(move |output| { + match output { + Output::Sender(s) => s.send_address(observed_addr1), + Output::Address(_) => unreachable!() + } + }); + + let client = TcpStream::connect(&server_addr) + .map_err(|e| e.into()) + .and_then(|conn| { + Observed::new().upgrade(conn, (), Endpoint::Dialer) + }) + .map(move |output| { + match output { + Output::Address(addr) => { + eprintln!("{} {}", addr, observed_addr2); + assert_eq!(addr, observed_addr2) + } + _ => unreachable!() + } + }); + + current_thread::block_on_all(future::lazy(move || { + current_thread::spawn(server.map_err(|e| panic!("server error: {}", e)).map(|_| ())); + client.map_err(|e| panic!("client error: {}", e)) + })) + .unwrap(); + } +} From 45cd7db6e9b25dd4a79f764b433e2a85e4a058f8 Mon Sep 17 00:00:00 2001 From: James Ray <16969914+jamesray1@users.noreply.github.com> Date: Mon, 29 Oct 2018 20:38:32 +1100 Subject: [PATCH 15/19] Remove spaces before semicolons (#591) --- core/src/nodes/collection.rs | 28 +++++++++---------- core/src/nodes/handled_node.rs | 2 +- core/src/nodes/handled_node_tasks.rs | 2 +- core/src/nodes/raw_swarm.rs | 40 ++++++++++++++-------------- muxers/mplex/src/lib.rs | 4 +-- protocols/floodsub/src/lib.rs | 10 +++---- protocols/identify/src/protocol.rs | 4 +-- protocols/kad/src/high_level.rs | 8 +++--- protocols/kad/src/protocol.rs | 8 +++--- protocols/kad/src/query.rs | 8 +++--- protocols/ping/src/lib.rs | 2 +- protocols/secio/src/handshake.rs | 6 ++--- protocols/secio/src/lib.rs | 2 +- stores/datastore/src/lib.rs | 2 +- transports/dns/src/lib.rs | 2 +- transports/websocket/src/desktop.rs | 2 +- 16 files changed, 65 insertions(+), 65 deletions(-) diff --git a/core/src/nodes/collection.rs b/core/src/nodes/collection.rs index fc17f43aaf8..97c880ebf7f 100644 --- a/core/src/nodes/collection.rs +++ b/core/src/nodes/collection.rs @@ -192,8 +192,8 @@ impl<'a, TInEvent, TOutEvent, THandler> CollectionReachEvent<'a, TInEvent, TOutE let ret_value = if let Some(former_task_id) = former_task_id { self.parent.inner.task(former_task_id) .expect("whenever we receive a TaskClosed event or close a node, we remove the \ - corresponding entry from self.nodes ; therefore all elements in \ - self.nodes are valid tasks in the HandledNodesTasks ; qed") + corresponding entry from self.nodes; therefore all elements in \ + self.nodes are valid tasks in the HandledNodesTasks; qed") .close(); let _former_other_state = self.parent.tasks.remove(&former_task_id); debug_assert_eq!(_former_other_state, Some(TaskState::Connected(self.peer_id.clone()))); @@ -237,10 +237,10 @@ impl<'a, TInEvent, TOutEvent, THandler> Drop for CollectionReachEvent<'a, TInEve let task_state = self.parent.tasks.remove(&self.id); debug_assert!(if let Some(TaskState::Pending) = task_state { true } else { false }); self.parent.inner.task(self.id) - .expect("we create the CollectionReachEvent with a valid task id ; the \ + .expect("we create the CollectionReachEvent with a valid task id; the \ CollectionReachEvent mutably borrows the collection, therefore nothing \ - can delete this task during the lifetime of the CollectionReachEvent ; \ - therefore the task is still valid when we delete it ; qed") + can delete this task during the lifetime of the CollectionReachEvent; \ + therefore the task is still valid when we delete it; qed") .close(); } } @@ -304,9 +304,9 @@ impl CollectionStream CollectionStream { - // TODO: this variant shouldn't happen ; prove this + // TODO: this variant shouldn't happen; prove this panic!() }, (Some(TaskState::Connected(peer_id)), Ok(()), _handler) => { @@ -402,9 +402,9 @@ impl CollectionStream { - panic!("self.tasks is always kept in sync with the tasks in self.inner ; \ + panic!("self.tasks is always kept in sync with the tasks in self.inner; \ when we add a task in self.inner we add a corresponding entry in \ - self.tasks, and remove the entry only when the task is closed ; \ + self.tasks, and remove the entry only when the task is closed; \ qed") }, } @@ -420,9 +420,9 @@ impl CollectionStream peer_id.clone(), _ => panic!("we can only receive NodeEvent events from a task after we \ - received a corresponding NodeReached event from that same task ; \ + received a corresponding NodeReached event from that same task; \ when we receive a NodeReached event, we ensure that the entry in \ - self.tasks is switched to the Connected state ; qed"), + self.tasks is switched to the Connected state; qed"), }; Async::Ready(CollectionEvent::NodeEvent { @@ -457,8 +457,8 @@ impl<'a, TInEvent> PeerMut<'a, TInEvent> { let old_task_id = self.nodes.remove(&peer_id); debug_assert_eq!(old_task_id, Some(self.inner.id())); } else { - panic!("a PeerMut can only be created if an entry is present in nodes ; an entry in \ - nodes always matched a Connected entry in tasks ; qed"); + panic!("a PeerMut can only be created if an entry is present in nodes; an entry in \ + nodes always matched a Connected entry in tasks; qed"); }; self.inner.close(); diff --git a/core/src/nodes/handled_node.rs b/core/src/nodes/handled_node.rs index dd2f2c13b40..c7ae87528f1 100644 --- a/core/src/nodes/handled_node.rs +++ b/core/src/nodes/handled_node.rs @@ -25,7 +25,7 @@ use std::io::Error as IoError; /// Handler for the substreams of a node. // TODO: right now it is possible for a node handler to be built, then shut down right after if we -// realize we dialed the wrong peer for example ; this could be surprising and should either +// realize we dialed the wrong peer for example; this could be surprising and should either // be documented or changed (favouring the "documented" right now) pub trait NodeHandler { /// Custom event that can be received from the outside. diff --git a/core/src/nodes/handled_node_tasks.rs b/core/src/nodes/handled_node_tasks.rs index 611330d2857..9cd7e69ffcd 100644 --- a/core/src/nodes/handled_node_tasks.rs +++ b/core/src/nodes/handled_node_tasks.rs @@ -407,7 +407,7 @@ where node.inject_event(event); }, Ok(Async::Ready(None)) => { - // Node closed by the external API ; start shutdown process. + // Node closed by the external API; start shutdown process. node.shutdown(); break; } diff --git a/core/src/nodes/raw_swarm.rs b/core/src/nodes/raw_swarm.rs index 1f25fe43bc2..6498c758426 100644 --- a/core/src/nodes/raw_swarm.rs +++ b/core/src/nodes/raw_swarm.rs @@ -481,7 +481,7 @@ where if actual_peer_id == expected_peer_id { Ok((actual_peer_id, muxer)) } else { - let msg = format!("public key mismatch ; expected = {:?} ; obtained = {:?}", + let msg = format!("public key mismatch; expected = {:?}; obtained = {:?}", expected_peer_id, actual_peer_id); Err(IoError::new(IoErrorKind::Other, msg)) } @@ -573,10 +573,10 @@ where }) => { let endpoint = self.reach_attempts.connected_points.remove(&peer_id) .expect("We insert into connected_points whenever a connection is \ - opened and remove only when a connection is closed ; the \ + opened and remove only when a connection is closed; the \ underlying API is guaranteed to always deliver a connection \ closed message after it has been opened, and no two closed \ - messages ; qed"); + messages; qed"); debug_assert!(!self.reach_attempts.out_reach_attempts.contains_key(&peer_id)); action = Default::default(); out_event = RawSwarmEvent::NodeError { @@ -588,10 +588,10 @@ where Async::Ready(CollectionEvent::NodeClosed { peer_id }) => { let endpoint = self.reach_attempts.connected_points.remove(&peer_id) .expect("We insert into connected_points whenever a connection is \ - opened and remove only when a connection is closed ; the \ + opened and remove only when a connection is closed; the \ underlying API is guaranteed to always deliver a connection \ closed message after it has been opened, and no two closed \ - messages ; qed"); + messages; qed"); debug_assert!(!self.reach_attempts.out_reach_attempts.contains_key(&peer_id)); action = Default::default(); out_event = RawSwarmEvent::NodeClosed { peer_id, endpoint }; @@ -607,15 +607,15 @@ where } if let Some(interrupt) = action.interrupt { - // TODO: improve proof or remove ; this is too complicated right now + // TODO: improve proof or remove; this is too complicated right now self.active_nodes .interrupt(interrupt) - .expect("interrupt is guaranteed to be gathered from `out_reach_attempts` ; + .expect("interrupt is guaranteed to be gathered from `out_reach_attempts`; we insert in out_reach_attempts only when we call \ active_nodes.add_reach_attempt, and we remove only when we call \ - interrupt or when a reach attempt succeeds or errors ; therefore the \ + interrupt or when a reach attempt succeeds or errors; therefore the \ out_reach_attempts should always be in sync with the actual \ - attempts ; qed"); + attempts; qed"); } return Async::Ready(out_event); @@ -688,9 +688,9 @@ where if outcome == CollectionNodeAccept::ReplacedExisting { let closed_endpoint = closed_endpoint .expect("We insert into connected_points whenever a connection is opened and \ - remove only when a connection is closed ; the underlying API is \ + remove only when a connection is closed; the underlying API is \ guaranteed to always deliver a connection closed message after it has \ - been opened, and no two closed messages ; qed"); + been opened, and no two closed messages; qed"); return (action, RawSwarmEvent::Replaced { peer_id, endpoint: opened_endpoint, @@ -726,9 +726,9 @@ where if outcome == CollectionNodeAccept::ReplacedExisting { let closed_endpoint = closed_endpoint .expect("We insert into connected_points whenever a connection is opened and \ - remove only when a connection is closed ; the underlying API is guaranteed \ + remove only when a connection is closed; the underlying API is guaranteed \ to always deliver a connection closed message after it has been opened, \ - and no two closed messages ; qed"); + and no two closed messages; qed"); return (Default::default(), RawSwarmEvent::Replaced { peer_id, endpoint: opened_endpoint, @@ -740,7 +740,7 @@ where } // We didn't find any entry in neither the outgoing connections not ingoing connections. - // TODO: improve proof or remove ; this is too complicated right now + // TODO: improve proof or remove; this is too complicated right now panic!("The API of collection guarantees that the id sent back in NodeReached (which is where \ we call handle_node_reached) is one that was passed to add_reach_attempt. Whenever we \ call add_reach_attempt, we also insert at the same time an entry either in \ @@ -817,7 +817,7 @@ where TTrans: Transport } // The id was neither in the outbound list nor the inbound list. - // TODO: improve proof or remove ; this is too complicated right now + // TODO: improve proof or remove; this is too complicated right now panic!("The API of collection guarantees that the id sent back in ReachError events \ (which is where we call handle_reach_error) is one that was passed to \ add_reach_attempt. Whenever we call add_reach_attempt, we also insert \ @@ -999,7 +999,7 @@ impl<'a, TInEvent> PeerConnected<'a, TInEvent> { /// Closes the connection to this node. /// /// No `NodeClosed` message will be generated for this node. - // TODO: consider returning a `PeerNotConnected` ; however this makes all the borrows things + // TODO: consider returning a `PeerNotConnected`; however this makes all the borrows things // much more annoying to deal with pub fn close(self) { self.connected_points.remove(&self.peer_id); @@ -1011,9 +1011,9 @@ impl<'a, TInEvent> PeerConnected<'a, TInEvent> { pub fn endpoint(&self) -> &ConnectedPoint { self.connected_points.get(&self.peer_id) .expect("We insert into connected_points whenever a connection is opened and remove \ - only when a connection is closed ; the underlying API is guaranteed to always \ + only when a connection is closed; the underlying API is guaranteed to always \ deliver a connection closed message after it has been opened, and no two \ - closed messages ; qed") + closed messages; qed") } /// Sends an event to the node. @@ -1031,13 +1031,13 @@ pub struct PeerPendingConnect<'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a> { impl<'a, TInEvent, TOutEvent, THandler> PeerPendingConnect<'a, TInEvent, TOutEvent, THandler> { /// Interrupt this connection attempt. - // TODO: consider returning a PeerNotConnected ; however that is really pain in terms of + // TODO: consider returning a PeerNotConnected; however that is really pain in terms of // borrows #[inline] pub fn interrupt(self) { let attempt = self.attempt.remove(); if let Err(_) = self.active_nodes.interrupt(attempt.id) { - // TODO: improve proof or remove ; this is too complicated right now + // TODO: improve proof or remove; this is too complicated right now panic!("We retreived this attempt.id from out_reach_attempts. We insert in \ out_reach_attempts only at the same time as we call add_reach_attempt. \ Whenever we receive a NodeReached, NodeReplaced or ReachError event, which \ diff --git a/muxers/mplex/src/lib.rs b/muxers/mplex/src/lib.rs index 2de8c8b9a62..14b2445162a 100644 --- a/muxers/mplex/src/lib.rs +++ b/muxers/mplex/src/lib.rs @@ -329,7 +329,7 @@ where C: AsyncRead + AsyncWrite let mut inner = self.inner.lock(); if inner.opened_substreams.len() >= inner.config.max_substreams { - debug!("Refused substream ; reached maximum number of substreams {}", inner.config.max_substreams); + debug!("Refused substream; reached maximum number of substreams {}", inner.config.max_substreams); return Err(IoError::new(IoErrorKind::ConnectionRefused, "exceeded maximum number of open substreams")); } @@ -460,7 +460,7 @@ where C: AsyncRead + AsyncWrite Ok(Async::Ready(Some(data))) => substream.current_data = data, Ok(Async::Ready(None)) => return Ok(Async::Ready(0)), Ok(Async::NotReady) => { - // There was no data packet in the buffer about this substream ; maybe it's + // There was no data packet in the buffer about this substream; maybe it's // because it has been closed. if inner.opened_substreams.contains(&(substream.num, substream.endpoint)) { return Ok(Async::NotReady) diff --git a/protocols/floodsub/src/lib.rs b/protocols/floodsub/src/lib.rs index c84150bbce1..48e04ea34a3 100644 --- a/protocols/floodsub/src/lib.rs +++ b/protocols/floodsub/src/lib.rs @@ -345,7 +345,7 @@ impl FloodSubController { let topics = topics.into_iter(); if log_enabled!(Level::Debug) { - debug!("Queuing sub/unsub message ; sub = {:?} ; unsub = {:?}", + debug!("Queuing sub/unsub message; sub = {:?}; unsub = {:?}", topics.clone().filter(|t| t.1) .map(|t| t.0.hash().clone().into_string()) .collect::>(), @@ -389,7 +389,7 @@ impl FloodSubController { { let topics = topics.into_iter().collect::>(); - debug!("Queueing publish message ; topics = {:?} ; data_len = {:?}", + debug!("Queueing publish message; topics = {:?}; data_len = {:?}", topics.iter().map(|t| t.hash().clone().into_string()).collect::>(), data.len()); @@ -554,7 +554,7 @@ fn handle_packet_received( let mut input = match protobuf::parse_from_bytes::(&bytes) { Ok(msg) => msg, Err(err) => { - debug!("Failed to parse protobuf message ; err = {:?}", err); + debug!("Failed to parse protobuf message; err = {:?}", err); return Err(err.into()); } }; @@ -588,7 +588,7 @@ fn handle_packet_received( .lock() .insert(hash((from.clone(), publish.take_seqno()))) { - trace!("Skipping message because we had already received it ; payload = {} bytes", + trace!("Skipping message because we had already received it; payload = {} bytes", publish.get_data().len()); continue; } @@ -609,7 +609,7 @@ fn handle_packet_received( .map(|h| TopicHash::from_raw(h)) .collect::>(); - trace!("Processing message for topics {:?} ; payload = {} bytes", + trace!("Processing message for topics {:?}; payload = {} bytes", topics, publish.get_data().len()); diff --git a/protocols/identify/src/protocol.rs b/protocols/identify/src/protocol.rs index 44e1987348d..aed10431b69 100644 --- a/protocols/identify/src/protocol.rs +++ b/protocols/identify/src/protocol.rs @@ -87,7 +87,7 @@ where let bytes = message .write_to_bytes() - .expect("writing protobuf failed ; should never happen"); + .expect("writing protobuf failed; should never happen"); let future = self.inner.send(bytes).map(|_| ()); Box::new(future) as Box<_> @@ -142,7 +142,7 @@ where let (info, observed_addr) = match parse_proto_msg(msg) { Ok(v) => v, Err(err) => { - debug!("Failed to parse protobuf message ; error = {:?}", err); + debug!("Failed to parse protobuf message; error = {:?}", err); return Err(err.into()); } }; diff --git a/protocols/kad/src/high_level.rs b/protocols/kad/src/high_level.rs index 34f52315563..e086d7a29b7 100644 --- a/protocols/kad/src/high_level.rs +++ b/protocols/kad/src/high_level.rs @@ -192,7 +192,7 @@ where F: FnMut(&PeerId) -> Fut + Send + 'a, fn gen_random_id(my_id: &PeerId, bucket_num: usize) -> Result { let my_id_len = my_id.as_bytes().len(); - // TODO: this 2 is magic here ; it is the length of the hash of the multihash + // TODO: this 2 is magic here; it is the length of the hash of the multihash let bits_diff = bucket_num + 1; if bits_diff > 8 * (my_id_len - 2) { return Err(()); @@ -232,7 +232,7 @@ where F: FnMut(&PeerId) -> Fut + 'a, Fut: IntoFuture + 'a, Fut::Future: Send, { - debug!("Start query for {:?} ; num results = {}", searched_key, num_results); + debug!("Start query for {:?}; num results = {}", searched_key, num_results); // State of the current iterative process. struct State<'a, F> { @@ -322,7 +322,7 @@ where F: FnMut(&PeerId) -> Fut + 'a, to_contact }; - debug!("New query round ; {} queries in progress ; contacting {} new peers", + debug!("New query round; {} queries in progress; contacting {} new peers", state.current_attempts_fut.len(), to_contact.len()); @@ -449,7 +449,7 @@ where F: FnMut(&PeerId) -> Fut + 'a, } else { if !local_nearest_node_updated { - trace!("Loop didn't update closer node ; jumping to step 2"); + trace!("Loop didn't update closer node; jumping to step 2"); state.stage = Stage::SecondStep; } } diff --git a/protocols/kad/src/protocol.rs b/protocols/kad/src/protocol.rs index 2ba18e5e786..bad4fe75861 100644 --- a/protocols/kad/src/protocol.rs +++ b/protocols/kad/src/protocol.rs @@ -88,7 +88,7 @@ impl KadPeer { // Builds a `KadPeer` from its raw protobuf equivalent. // TODO: use TryFrom once stable fn from_peer(peer: &mut protobuf_structs::dht::Message_Peer) -> Result { - // TODO: this is in fact a CID ; not sure if this should be handled in `from_bytes` or + // TODO: this is in fact a CID; not sure if this should be handled in `from_bytes` or // as a special case here let node_id = PeerId::from_bytes(peer.get_id().to_vec()) .map_err(|_| IoError::new(IoErrorKind::InvalidData, "invalid peer id"))?; @@ -339,7 +339,7 @@ fn proto_to_msg(mut message: protobuf_structs::dht::Message) -> Result Result Result { // TODO: for now we don't parse the peer properly, so it is possible that we get - // parsing errors for peers even when they are valid ; we ignore these + // parsing errors for peers even when they are valid; we ignore these // errors for now, but ultimately we should just error altogether let provider_peer = message.mut_providerPeers() .iter_mut() diff --git a/protocols/kad/src/query.rs b/protocols/kad/src/query.rs index f78e5a1a0e3..bd6644c91e1 100644 --- a/protocols/kad/src/query.rs +++ b/protocols/kad/src/query.rs @@ -100,7 +100,7 @@ where fn gen_random_id(my_id: &PeerId, bucket_num: usize) -> Result { let my_id_len = my_id.as_bytes().len(); - // TODO: this 2 is magic here ; it is the length of the hash of the multihash + // TODO: this 2 is magic here; it is the length of the hash of the multihash let bits_diff = bucket_num + 1; if bits_diff > 8 * (my_id_len - 2) { return Err(()); @@ -137,7 +137,7 @@ where FBuckets: Fn(PeerId) -> Vec + 'a + Clone, FFindNode: Fn(Multiaddr, PeerId) -> Box, Error = IoError> + Send> + 'a + Clone, { - debug!("Start query for {:?} ; num results = {}", searched_key, num_results); + debug!("Start query for {:?}; num results = {}", searched_key, num_results); // State of the current iterative process. struct State<'a> { @@ -230,7 +230,7 @@ where to_contact }; - debug!("New query round ; {} queries in progress ; contacting {} new peers", + debug!("New query round; {} queries in progress; contacting {} new peers", state.current_attempts_fut.len(), to_contact.len()); @@ -350,7 +350,7 @@ where } else { if !local_nearest_node_updated { - trace!("Loop didn't update closer node ; jumping to step 2"); + trace!("Loop didn't update closer node; jumping to step 2"); state.stage = Stage::SecondStep; } } diff --git a/protocols/ping/src/lib.rs b/protocols/ping/src/lib.rs index dafb448cb67..e8c59a00f1a 100644 --- a/protocols/ping/src/lib.rs +++ b/protocols/ping/src/lib.rs @@ -311,7 +311,7 @@ where TSocket: AsyncRead + AsyncWrite PingListenerState::Listening => { match self.inner.poll() { Ok(Async::Ready(Some(payload))) => { - debug!("Received ping (payload={:?}) ; sending back", payload); + debug!("Received ping (payload={:?}); sending back", payload); self.state = PingListenerState::Sending(payload.freeze()) }, Ok(Async::Ready(None)) => self.state = PingListenerState::Closing, diff --git a/protocols/secio/src/handshake.rs b/protocols/secio/src/handshake.rs index 18e2de7feac..da4a5a910e6 100644 --- a/protocols/secio/src/handshake.rs +++ b/protocols/secio/src/handshake.rs @@ -324,7 +324,7 @@ where .and_then(|context| { // Generate our nonce. let context = context.with_local()?; - trace!("starting handshake ; local nonce = {:?}", context.state.nonce); + trace!("starting handshake; local nonce = {:?}", context.state.nonce); Ok(context) }) .and_then(|context| { @@ -346,7 +346,7 @@ where return Err(err.into()) }, }; - trace!("received proposition from remote ; pubkey = {:?} ; nonce = {:?}", + trace!("received proposition from remote; pubkey = {:?}; nonce = {:?}", context.state.public_key, context.state.nonce); Ok((socket, context)) }) @@ -436,7 +436,7 @@ where let remote_exch = match protobuf_parse_from_bytes::(&raw) { Ok(e) => e, Err(err) => { - debug!("failed to parse remote's exchange protobuf ; {:?}", err); + debug!("failed to parse remote's exchange protobuf; {:?}", err); return Err(SecioError::HandshakeParsingFailure); } }; diff --git a/protocols/secio/src/lib.rs b/protocols/secio/src/lib.rs index 8ccc2310559..4978110f412 100644 --- a/protocols/secio/src/lib.rs +++ b/protocols/secio/src/lib.rs @@ -306,7 +306,7 @@ impl SecioKeyPair { SecioKeyPairInner::Secp256k1 { ref private } => { let secp = secp256k1::Secp256k1::with_caps(secp256k1::ContextFlag::SignOnly); let pubkey = secp256k1::key::PublicKey::from_secret_key(&secp, private) - .expect("wrong secp256k1 private key ; type safety violated"); + .expect("wrong secp256k1 private key; type safety violated"); PublicKey::Secp256k1(pubkey.serialize_vec(&secp, true).to_vec()) } } diff --git a/stores/datastore/src/lib.rs b/stores/datastore/src/lib.rs index 616f09f129e..341aea2b146 100644 --- a/stores/datastore/src/lib.rs +++ b/stores/datastore/src/lib.rs @@ -21,7 +21,7 @@ //! General-purpose key-value storage. //! The keys are strings, and the values are of any type you want. //! -//! > **Note**: This crate is meant to be a utility for the implementation of other crates ; it +//! > **Note**: This crate is meant to be a utility for the implementation of other crates; it //! > does not directly participate in the stack of libp2p. //! //! This crate provides the `Datastore` trait, whose template parameter is the type of the value. diff --git a/transports/dns/src/lib.rs b/transports/dns/src/lib.rs index 9b7948ac2ee..b3ab759173a 100644 --- a/transports/dns/src/lib.rs +++ b/transports/dns/src/lib.rs @@ -179,7 +179,7 @@ where } } -// How to resolve ; to an IPv4 address or an IPv6 address? +// How to resolve; to an IPv4 address or an IPv6 address? #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum ResolveTy { Dns4, diff --git a/transports/websocket/src/desktop.rs b/transports/websocket/src/desktop.rs index 5c347fd9cdd..0b071df0b8c 100644 --- a/transports/websocket/src/desktop.rs +++ b/transports/websocket/src/desktop.rs @@ -206,7 +206,7 @@ where OwnedMessage::Binary(data) => Ok(data), OwnedMessage::Text(data) => Ok(data.into_bytes()), // TODO: pings and pongs and close messages need to be - // answered ; and this is really hard ; for now we produce + // answered; and this is really hard; for now we produce // an error when that happens _ => Err(IoError::new(IoErrorKind::Other, "unimplemented")), } From 7c8d8b5096d09142d8155048fd2f484b9977287b Mon Sep 17 00:00:00 2001 From: Chevdor Date: Tue, 30 Oct 2018 10:48:24 +0100 Subject: [PATCH 16/19] Add substrate to the list of projects using libp2p (#595) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index edc4282a434..b998309b2f4 100644 --- a/README.md +++ b/README.md @@ -22,3 +22,4 @@ libp2p = { git = "https://github.com/libp2p/rust-libp2p" } (open a pull request if you want your project to be added here) - https://github.com/paritytech/polkadot +- https://github.com/paritytech/substrate From 29b1b0b3bae2b350dc1cfd7daeba1e15161711ab Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 31 Oct 2018 08:31:15 +0100 Subject: [PATCH 17/19] Reexport multihash from the facade (#587) --- Cargo.toml | 1 + src/lib.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 341e829d764..9ea458b63c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ secio-secp256k1 = ["libp2p-secio/secp256k1"] bytes = "0.4" futures = "0.1" multiaddr = { path = "./misc/multiaddr" } +multihash = { path = "./misc/multihash" } libp2p-mplex = { path = "./muxers/mplex" } libp2p-identify = { path = "./protocols/identify" } libp2p-kad = { path = "./protocols/kad" } diff --git a/src/lib.rs b/src/lib.rs index 71550220a1d..1962a60c447 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -135,6 +135,7 @@ pub extern crate futures; #[cfg(not(target_os = "emscripten"))] pub extern crate tokio_current_thread; pub extern crate multiaddr; +pub extern crate multihash; pub extern crate tokio_io; pub extern crate tokio_codec; From 61acb7c13f9c3f28ee2a1a159ad454ef489edaa9 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 31 Oct 2018 09:55:59 +0100 Subject: [PATCH 18/19] Use websocket 0.21.0 (#597) --- transports/websocket/Cargo.toml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/transports/websocket/Cargo.toml b/transports/websocket/Cargo.toml index addbb90cfba..02981dda342 100644 --- a/transports/websocket/Cargo.toml +++ b/transports/websocket/Cargo.toml @@ -13,9 +13,7 @@ rw-stream-sink = { path = "../../misc/rw-stream-sink" } tokio-io = "0.1" [target.'cfg(not(target_os = "emscripten"))'.dependencies] -# TODO: restore the upstream version once the branch is merged -websocket = { git = "https://github.com/tomaka/rust-websocket", branch = "send", default-features = false, features = ["async", "async-ssl"] } -#websocket = { version = "0.20.2", default-features = false, features = ["async", "async-ssl"] } +websocket = { version = "0.21.0", default-features = false, features = ["async", "async-ssl"] } [target.'cfg(target_os = "emscripten")'.dependencies] stdweb = { version = "0.1.3", default-features = false } From 4627f2118026c3359acbc7151108f77060feb815 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 31 Oct 2018 11:17:12 +0100 Subject: [PATCH 19/19] Use paritytech/rust-secp256k1 (#598) --- protocols/secio/Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/protocols/secio/Cargo.toml b/protocols/secio/Cargo.toml index 09511affbfa..7f6e4816d4a 100644 --- a/protocols/secio/Cargo.toml +++ b/protocols/secio/Cargo.toml @@ -12,8 +12,7 @@ libp2p-core = { path = "../../core" } log = "0.4.1" protobuf = "2.0.2" rand = "0.5" -# TODO: use the paritytech repo after https://github.com/paritytech/rust-secp256k1/pull/14 -eth-secp256k1 = { git = "https://github.com/tomaka/rust-secp256k1", branch = "pub-rand", optional = true } +eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1", optional = true } aes-ctr = "0.1.0" aesni = { version = "0.4.1", features = ["nocheck"], optional = true } twofish = "0.1.0"