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..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" } @@ -28,6 +29,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] @@ -43,32 +45,10 @@ 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" -[[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", @@ -81,6 +61,7 @@ members = [ "protocols/identify", "protocols/kad", "protocols/ping", + "protocols/observed", "transports/relay", "protocols/secio", "muxers/mplex", 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 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/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/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 469b09b4021..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() @@ -142,7 +143,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) => { @@ -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(); //! # } //! ``` //! @@ -164,47 +166,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; @@ -232,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] @@ -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::transport::Transport; pub use self::upgrade::{ConnectionUpgrade, Endpoint}; diff --git a/core/src/muxing.rs b/core/src/muxing.rs index 0c81a026d65..e1e10bb448c 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/collection.rs b/core/src/nodes/collection.rs index 90384314fa3..97c880ebf7f 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 { @@ -189,8 +192,8 @@ impl<'a, TInEvent, TOutEvent> CollectionReachEvent<'a, TInEvent, TOutEvent> { 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()))); @@ -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,15 +232,15 @@ 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 }); 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(); } } @@ -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? @@ -302,9 +304,9 @@ impl CollectionStream { entry.remove(); self.inner.task(id.0) .expect("whenever we receive a TaskClosed event or interrupt a task, we \ - remove the corresponding entry from self.tasks ; therefore all \ + remove the corresponding entry from self.tasks; therefore all \ elements in self.tasks are valid tasks in the \ - HandledNodesTasks ; qed") + HandledNodesTasks; qed") .close(); Ok(()) @@ -362,73 +364,72 @@ 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(())) => { - // 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"), - })) + (Some(TaskState::Pending), _, _) => { + // TODO: this variant shouldn't happen; prove this + 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, _) => { - panic!("self.tasks is always kept in sync with the tasks in self.inner ; \ + (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 ; \ + self.tasks, and remove the entry only when the task is closed; \ qed") }, } }, - 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 \ - 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(Some(CollectionEvent::NodeEvent { + Async::Ready(CollectionEvent::NodeEvent { peer_id, event, - })) + }) } - None => Async::Ready(None), } } } @@ -456,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 65c5bac7bda..c7ae87528f1 100644 --- a/core/src/nodes/handled_node.rs +++ b/core/src/nodes/handled_node.rs @@ -20,22 +20,20 @@ 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; /// 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 +// 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,29 +134,34 @@ 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. 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, + /// 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 } -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: Some(NodeStream::new(muxer, multiaddr_future)), + node: NodeStream::new(muxer).fuse(), handler, + handler_is_done: false, + is_shutting_down: false } } @@ -151,26 +171,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,83 +198,81 @@ 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(); + for user_data in self.node.get_mut().cancel_outgoing() { + self.handler.inject_outbound_closed(user_data); } - self.handler.shutdown(); + self.is_shutting_down = true; } } -impl Stream for HandledNode +impl Stream for HandledNode where TMuxer: StreamMuxer, - THandler: NodeHandler>, - TAddrFut: Future, + THandler: NodeHandler>, { type Item = THandler::OutEvent; type Error = IoError; 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.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 => node_not_ready = true, + 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))) => { - 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); - }, + self.handler.inject_substream(substream, endpoint) + } + Async::Ready(None) => { + if !self.is_shutting_down { + self.is_shutting_down = true; + self.handler.shutdown() + } + } + 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 if self.handler_is_done { Async::Ready(None) } else { 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) => { + 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(); + } + } } } @@ -265,8 +283,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 @@ -290,15 +308,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) { @@ -309,7 +329,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); @@ -327,17 +346,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..9cd7e69ffcd 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(())); } @@ -404,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; } @@ -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 51aebd5e96b..c47a05ec6f8 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, @@ -59,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. @@ -129,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); @@ -137,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), - })); + }); } } } @@ -176,7 +227,7 @@ where #[inline] fn poll(&mut self) -> Poll, Self::Error> { - Ok(self.poll()) + Ok(self.poll().map(Option::Some)) } } @@ -246,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) => { @@ -272,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!() @@ -336,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) }); }) }); @@ -359,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) }); }) }); @@ -377,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 @@ -391,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 @@ -410,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") }) } @@ -435,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 b22384ab573..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,48 +49,42 @@ 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, { /// 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, - /// Address of the node ; can be empty if the address hasn't been resolved yet. - address: Addr, + /// Tracks the state of the muxers inbound direction. + inbound_state: StreamState, + /// Tracks the state of the muxers outbound direction. + outbound_state: StreamState, /// 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>; +// 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 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. @@ -124,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_finished: false, - outbound_finished: false, - address: Addr::Future(multiaddr_future), + inbound_state: StreamState::Open, + outbound_state: StreamState::Open, 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. @@ -161,7 +137,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 +147,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,32 +178,104 @@ 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 +impl Stream for NodeStream where TMuxer: muxing::StreamMuxer, - TAddrFut: Future, { type Item = NodeEvent; 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 +293,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 }))); } @@ -254,29 +307,12 @@ 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_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. @@ -284,22 +320,20 @@ 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_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() } } -impl Drop for NodeStream +impl Drop for NodeStream where TMuxer: muxing::StreamMuxer, { @@ -310,19 +344,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); - } - } } } @@ -355,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()); @@ -402,7 +405,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,32 +414,30 @@ 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] 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) }); - assert_eq!(ns.is_inbound_closed(), true); + assert!(!ns.is_inbound_open()); } #[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_eq!(ns.is_outbound_closed(), false); + assert!(ns.is_outbound_open()); ns.open_substream(vec![1]).unwrap(); let poll_result = ns.poll(); @@ -447,7 +448,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] @@ -467,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)); }); @@ -481,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() @@ -496,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() @@ -542,27 +523,25 @@ 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 - assert_eq!(ns.is_outbound_closed(), false); + assert!(ns.is_outbound_open()); assert!(format!("{:?}", ns).contains("outbound_substreams: 1")); } #[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 65% rename from core/src/nodes/swarm.rs rename to core/src/nodes/raw_swarm.rs index 97e96250bad..6498c758426 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,59 +557,68 @@ 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 { - // 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(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,62 +715,32 @@ 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()); + let (outcome, peer_id) = event.accept(); if outcome == CollectionNodeAccept::ReplacedExisting { - return (Default::default(), 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 (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 + // 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 \ @@ -715,11 +754,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 +780,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,19 +804,20 @@ 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 }); } } } // 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 \ @@ -786,7 +827,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 +835,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 +864,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 +873,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 +881,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 +936,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 +946,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 +979,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 +990,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, } @@ -945,17 +999,21 @@ 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_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,20 +1024,20 @@ 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 + // 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 \ @@ -1013,54 +1071,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 +1132,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 +1164,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/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/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/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/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 309dee4a522..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)) @@ -190,91 +188,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 da50b339601..7a353f1e524 100644 --- a/core/src/transport/mod.rs +++ b/core/src/transport/mod.rs @@ -29,10 +29,9 @@ //! `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 nodes::raw_swarm::ConnectedPoint; use std::io::Error as IoError; use tokio_io::{AsyncRead, AsyncWrite}; use upgrade::{ConnectionUpgrade, Endpoint}; @@ -41,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 @@ -77,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 @@ -116,8 +106,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. @@ -130,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 @@ -205,7 +182,7 @@ pub trait Transport { where Self: Sized, Self::Output: AsyncRead + AsyncWrite, - U: ConnectionUpgrade, + U: ConnectionUpgrade, { UpgradedNode::new(self, upgrade) } @@ -216,40 +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) - } - - /// 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/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/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/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 -} 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/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<_> - } -} 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..16493e4cf1b 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,20 +68,12 @@ 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. /// /// 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, - remote_addr: TAddrFut, - ) -> Self::Future; + fn upgrade(self, socket: C, id: Self::UpgradeIdentifier, ty: Endpoint) -> Self::Future; } 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 452b7af1137..00000000000 Binary files a/examples/test-rsa-private-key.pk8 and /dev/null differ diff --git a/examples/test-rsa-public-key.der b/examples/test-rsa-public-key.der deleted file mode 100644 index 9e62c93ec19..00000000000 Binary files a/examples/test-rsa-public-key.der and /dev/null differ 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/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/src/lib.rs b/muxers/mplex/src/lib.rs index 670e11c5bca..14b2445162a 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] @@ -330,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")); } @@ -461,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/muxers/mplex/tests/two_peers.rs b/muxers/mplex/tests/two_peers.rs index 7c030fa95a6..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() { @@ -52,8 +53,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 @@ -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()); @@ -75,12 +77,13 @@ 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(|_| ()); - tokio_current_thread::block_on_all(future).unwrap(); + let mut rt = Runtime::new().unwrap(); + let _ = rt.block_on(future).unwrap(); bg_thread.join().unwrap(); } @@ -102,7 +105,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| { @@ -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()); @@ -125,11 +129,12 @@ 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(|_| ()); - 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/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..48e04ea34a3 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<_> } @@ -346,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::>(), @@ -390,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()); @@ -555,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()); } }; @@ -589,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; } @@ -610,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/Cargo.toml b/protocols/identify/Cargo.toml index 365bf0995b6..b2170f5622f 100644 --- a/protocols/identify/Cargo.toml +++ b/protocols/identify/Cargo.toml @@ -16,8 +16,10 @@ 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" } -tokio-current-thread = "0.1" +tokio = "0.1" 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/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/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(); - } -} diff --git a/protocols/identify/src/protocol.rs b/protocols/identify/src/protocol.rs index 31506a02ed6..aed10431b69 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; @@ -88,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<_> @@ -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()); @@ -145,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()); } }; @@ -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<_> } } @@ -224,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}; @@ -251,7 +239,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 { @@ -268,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); @@ -277,7 +265,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, @@ -304,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/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/kad_server.rs b/protocols/kad/src/kad_server.rs index 2a9c3e4340f..521bc1a0ee0 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) }) } } @@ -361,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 diff --git a/protocols/kad/src/protocol.rs b/protocols/kad/src/protocol.rs index 64120182b34..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"))?; @@ -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)) } } @@ -340,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() @@ -410,7 +409,7 @@ fn proto_to_msg(mut message: protobuf_structs::dht::Message) -> Result 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/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(); + } +} diff --git a/protocols/ping/Cargo.toml b/protocols/ping/Cargo.toml index 9e3dd8450cd..9689d9c5bbb 100644 --- a/protocols/ping/Cargo.toml +++ b/protocols/ping/Cargo.toml @@ -18,5 +18,5 @@ tokio-io = "0.1" [dev-dependencies] libp2p-tcp-transport = { path = "../../transports/tcp" } -tokio-current-thread = "0.1" +tokio = "0.1" tokio-tcp = "0.1" diff --git a/protocols/ping/src/lib.rs b/protocols/ping/src/lib.rs index fcb8663daa4..e8c59a00f1a 100644 --- a/protocols/ping/src/lib.rs +++ b/protocols/ping/src/lib.rs @@ -53,17 +53,18 @@ //! 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() //! .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) => { @@ -75,7 +76,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(); //! # } //! ``` //! @@ -123,7 +125,7 @@ pub enum PingOutput { Ponger(PingListener), } -impl ConnectionUpgrade for Ping +impl ConnectionUpgrade for Ping where TSocket: AsyncRead + AsyncWrite, { @@ -136,8 +138,7 @@ where } type Output = PingOutput; - type MultiaddrFuture = Maf; - type Future = FutureResult<(Self::Output, Self::MultiaddrFuture), IoError>; + type Future = FutureResult; #[inline] fn upgrade( @@ -145,14 +146,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() } } @@ -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, @@ -393,15 +393,15 @@ impl Encoder for Codec { #[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::{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 +419,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 +433,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!()) @@ -445,8 +443,8 @@ mod tests { _ => 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] @@ -464,10 +462,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 +476,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); @@ -496,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..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" @@ -40,5 +39,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..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); } }; @@ -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 a7a61756872..4978110f412 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({ @@ -58,12 +59,13 @@ //! //! 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") //! }); //! -//! tokio_current_thread::block_on_all(future).unwrap(); +//! let mut rt = Runtime::new().unwrap(); +//! let _ = rt.block_on(future).unwrap(); //! # } //! ``` //! @@ -304,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()) } } @@ -349,14 +351,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 +371,6 @@ where incoming: S, _: (), _: libp2p_core::Endpoint, - remote_addr: Maf, ) -> Self::Future { debug!("Starting secio upgrade"); @@ -384,7 +383,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 9f95f032049..1962a60c447 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -135,9 +135,12 @@ 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; +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 +160,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, swarm}; +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. @@ -212,7 +218,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/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 {} 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/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/dns/src/lib.rs b/transports/dns/src/lib.rs index d0e63796f98..b3ab759173a 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)> { @@ -180,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, @@ -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/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 aa92aa2ea1b..e0b7ab42f3e 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -47,14 +47,10 @@ 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; use std::io::{Error as IoError, Read, Write}; -use std::iter; use std::net::SocketAddr; use std::time::Duration; use swarm::Transport; @@ -135,8 +131,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)> { @@ -182,7 +177,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); @@ -194,40 +188,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; - } + let mut address = Multiaddr::empty(); - // 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; + // 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 `server` is a valid TCP/IP address. - match (&server_proto1, &server_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) } - // Check that `observed` is a valid TCP/IP address. - match (&observed_proto1, &observed_proto2) { - (&Protocol::Ip4(_), &Protocol::Tcp(_)) - | (&Protocol::Ip6(_), &Protocol::Tcp(_)) => {} - _ => return None, - } - - let result = iter::once(observed_proto1.clone()) - .chain(iter::once(server_proto2.clone())) - .collect(); - Some(result) + Some(address) } } @@ -280,32 +255,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) } } @@ -320,13 +284,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 { @@ -336,28 +300,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"), } } } @@ -419,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; @@ -426,7 +400,6 @@ mod tests { use std; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use swarm::Transport; - use tokio_current_thread; use tokio_io; #[test] @@ -485,8 +458,10 @@ 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 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 // Which in this case is read 3 bytes let handle_conn = tokio_io::io::read_exact(sock, [0; 3]) @@ -494,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(); @@ -509,12 +485,12 @@ 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 - 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/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/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 c2b76e11b62..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; @@ -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)) @@ -165,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; @@ -172,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] @@ -195,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()))); @@ -203,8 +201,11 @@ 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 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 // Which in this case is read 3 bytes let handle_conn = tokio_io::io::read_exact(sock, [0; 3]) @@ -212,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(); @@ -226,12 +227,12 @@ 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 - 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..02981dda342 100644 --- a/transports/websocket/Cargo.toml +++ b/transports/websocket/Cargo.toml @@ -13,13 +13,11 @@ 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 } [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/browser.rs b/transports/websocket/src/browser.rs index d8a0bb5f54c..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 @@ -209,49 +207,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..0b071df0b8c 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) @@ -221,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")), } @@ -229,32 +214,13 @@ 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<_>) } 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) } } @@ -293,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; @@ -312,14 +279,15 @@ 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) .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] @@ -335,14 +303,16 @@ 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) .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]