Split ConnectionUpgrade. (#642)

Introduce `InboundUpgrade` and `OutboundUpgrade`.
This commit is contained in:
Toralf Wittner
2018-11-15 17:41:11 +01:00
committed by Pierre Krieger
parent 466385a58a
commit 2e549884ef
52 changed files with 2010 additions and 1658 deletions

View File

@ -19,8 +19,12 @@
// DEALINGS IN THE SOFTWARE.
use bytes::{Bytes, BytesMut};
use futures::{future, Future, Sink, Stream};
use libp2p_core::{ConnectionUpgrade, Endpoint, Multiaddr, PublicKey};
use futures::{future::{self, FutureResult}, Future, Sink, Stream};
use libp2p_core::{
Multiaddr, PublicKey,
upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo}
};
use log::{debug, trace};
use protobuf::Message as ProtobufMessage;
use protobuf::parse_from_bytes as protobuf_parse_from_bytes;
use protobuf::RepeatedField;
@ -35,22 +39,14 @@ use unsigned_varint::codec;
#[derive(Debug, Clone)]
pub struct IdentifyProtocolConfig;
/// Output of the connection upgrade.
pub enum IdentifyOutput<T> {
/// We obtained information from the remote. Happens when we are the dialer.
RemoteInfo {
/// Information about the remote.
info: IdentifyInfo,
/// Address the remote sees for us.
observed_addr: Multiaddr,
},
#[derive(Debug, Clone)]
pub struct RemoteInfo {
/// Information about the remote.
pub info: IdentifyInfo,
/// Address the remote sees for us.
pub observed_addr: Multiaddr,
/// We opened a connection to the remote and need to send it information. Happens when we are
/// the listener.
Sender {
/// Object used to send identify info to the client.
sender: IdentifySender<T>,
},
_priv: ()
}
/// Object used to send back information to the client.
@ -64,11 +60,9 @@ where
{
/// Sends back information to the client. Returns a future that is signalled whenever the
/// info have been sent.
pub fn send(
self,
info: IdentifyInfo,
observed_addr: &Multiaddr,
) -> Box<Future<Item = (), Error = IoError> + Send + 'a> {
pub fn send(self, info: IdentifyInfo, observed_addr: &Multiaddr)
-> Box<Future<Item = (), Error = IoError> + Send + 'a>
{
debug!("Sending identify info to client");
trace!("Sending: {:?}", info);
@ -108,67 +102,73 @@ pub struct IdentifyInfo {
pub listen_addrs: Vec<Multiaddr>,
/// Protocols supported by the node, e.g. `/ipfs/ping/1.0.0`.
pub protocols: Vec<String>,
_priv: ()
}
impl<C> ConnectionUpgrade<C> for IdentifyProtocolConfig
where
C: AsyncRead + AsyncWrite + Send + 'static,
{
type NamesIter = iter::Once<(Bytes, Self::UpgradeIdentifier)>;
type UpgradeIdentifier = ();
type Output = IdentifyOutput<C>;
type Future = Box<Future<Item = Self::Output, Error = IoError> + Send>;
impl UpgradeInfo for IdentifyProtocolConfig {
type UpgradeId = ();
type NamesIter = iter::Once<(Bytes, Self::UpgradeId)>;
#[inline]
fn protocol_names(&self) -> Self::NamesIter {
iter::once((Bytes::from("/ipfs/id/1.0.0"), ()))
}
}
fn upgrade(self, socket: C, _: (), ty: Endpoint) -> Self::Future {
trace!("Upgrading connection as {:?}", ty);
impl<C> InboundUpgrade<C> for IdentifyProtocolConfig
where
C: AsyncRead + AsyncWrite + Send + 'static,
{
type Output = IdentifySender<C>;
type Error = IoError;
type Future = FutureResult<Self::Output, IoError>;
fn upgrade_inbound(self, socket: C, _: ()) -> Self::Future {
trace!("Upgrading inbound connection");
let socket = Framed::new(socket, codec::UviBytes::default());
let sender = IdentifySender { inner: socket };
future::ok(sender)
}
}
match ty {
Endpoint::Dialer => {
let future = socket
.into_future()
.map(|(msg, _)| msg)
.map_err(|(err, _)| err)
.and_then(|msg| {
debug!("Received identify message");
impl<C> OutboundUpgrade<C> for IdentifyProtocolConfig
where
C: AsyncRead + AsyncWrite + Send + 'static,
{
type Output = RemoteInfo;
type Error = IoError;
type Future = Box<dyn Future<Item=Self::Output, Error=IoError> + Send>;
if let Some(msg) = msg {
let (info, observed_addr) = match parse_proto_msg(msg) {
Ok(v) => v,
Err(err) => {
debug!("Failed to parse protobuf message; error = {:?}", err);
return Err(err.into());
}
};
trace!("Remote observes us as {:?}", observed_addr);
trace!("Information received: {:?}", info);
Ok(IdentifyOutput::RemoteInfo {
info,
observed_addr: observed_addr.clone(),
})
} else {
debug!("Identify protocol stream closed before receiving info");
Err(IoErrorKind::InvalidData.into())
fn upgrade_outbound(self, socket: C, _: ()) -> Self::Future {
let socket = Framed::new(socket, codec::UviBytes::<BytesMut>::default());
let future = socket
.into_future()
.map(|(msg, _)| msg)
.map_err(|(err, _)| err)
.and_then(|msg| {
debug!("Received identify message");
if let Some(msg) = msg {
let (info, observed_addr) = match parse_proto_msg(msg) {
Ok(v) => v,
Err(err) => {
debug!("Failed to parse protobuf message; error = {:?}", err);
return Err(err.into());
}
});
Box::new(future) as Box<_>
}
Endpoint::Listener => {
let sender = IdentifySender { inner: socket };
let future = future::ok(IdentifyOutput::Sender { sender });
Box::new(future) as Box<_>
}
}
};
trace!("Remote observes us as {:?}", observed_addr);
trace!("Information received: {:?}", info);
Ok(RemoteInfo {
info,
observed_addr: observed_addr.clone(),
_priv: ()
})
} else {
debug!("Identify protocol stream closed before receiving info");
Err(IoErrorKind::InvalidData.into())
}
});
Box::new(future) as Box<_>
}
}
@ -199,6 +199,7 @@ fn parse_proto_msg(msg: BytesMut) -> Result<(IdentifyInfo, Multiaddr), IoError>
agent_version: msg.take_agentVersion(),
listen_addrs: listen_addrs,
protocols: msg.take_protocols().into_vec(),
_priv: ()
};
Ok((info, observed_addr))
@ -216,10 +217,10 @@ mod tests {
use self::tokio::runtime::current_thread::Runtime;
use self::libp2p_tcp_transport::TcpConfig;
use futures::{Future, Stream};
use libp2p_core::{PublicKey, Transport};
use libp2p_core::{PublicKey, Transport, upgrade::{apply_outbound, apply_inbound}};
use std::sync::mpsc;
use std::thread;
use {IdentifyInfo, IdentifyOutput, IdentifyProtocolConfig};
use {IdentifyInfo, RemoteInfo, IdentifyProtocolConfig};
#[test]
fn correct_transfer() {
@ -229,19 +230,23 @@ mod tests {
let (tx, rx) = mpsc::channel();
let bg_thread = thread::spawn(move || {
let transport = TcpConfig::new().with_upgrade(IdentifyProtocolConfig);
let transport = TcpConfig::new();
let (listener, addr) = transport
.listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap())
.unwrap();
tx.send(addr).unwrap();
let future = listener
.into_future()
.map_err(|(err, _)| err)
.and_then(|(client, _)| client.unwrap().0)
.and_then(|identify| match identify {
IdentifyOutput::Sender { sender, .. } => sender.send(
.and_then(|socket| {
apply_inbound(socket, IdentifyProtocolConfig).map_err(|e| e.into_io_error())
})
.and_then(|sender| {
sender.send(
IdentifyInfo {
public_key: PublicKey::Ed25519(vec![1, 2, 3, 4, 5, 7]),
protocol_version: "proto_version".to_owned(),
@ -251,47 +256,34 @@ mod tests {
"/ip6/::1/udp/1000".parse().unwrap(),
],
protocols: vec!["proto1".to_string(), "proto2".to_string()],
_priv: ()
},
&"/ip4/100.101.102.103/tcp/5000".parse().unwrap(),
),
_ => panic!(),
)
});
let mut rt = Runtime::new().unwrap();
let _ = rt.block_on(future).unwrap();
});
let transport = TcpConfig::new().with_upgrade(IdentifyProtocolConfig);
let transport = TcpConfig::new();
let future = transport
.dial(rx.recv().unwrap())
let future = transport.dial(rx.recv().unwrap())
.unwrap_or_else(|_| panic!())
.and_then(|identify| match identify {
IdentifyOutput::RemoteInfo {
info,
observed_addr,
} => {
assert_eq!(
observed_addr,
"/ip4/100.101.102.103/tcp/5000".parse().unwrap()
);
assert_eq!(info.public_key, PublicKey::Ed25519(vec![1, 2, 3, 4, 5, 7]));
assert_eq!(info.protocol_version, "proto_version");
assert_eq!(info.agent_version, "agent_version");
assert_eq!(
info.listen_addrs,
&[
"/ip4/80.81.82.83/tcp/500".parse().unwrap(),
"/ip6/::1/udp/1000".parse().unwrap()
]
);
assert_eq!(
info.protocols,
&["proto1".to_string(), "proto2".to_string()]
);
Ok(())
}
_ => panic!(),
.and_then(|socket| {
apply_outbound(socket, IdentifyProtocolConfig).map_err(|e| e.into_io_error())
})
.and_then(|RemoteInfo { info, observed_addr, .. }| {
assert_eq!(observed_addr, "/ip4/100.101.102.103/tcp/5000".parse().unwrap());
assert_eq!(info.public_key, PublicKey::Ed25519(vec![1, 2, 3, 4, 5, 7]));
assert_eq!(info.protocol_version, "proto_version");
assert_eq!(info.agent_version, "agent_version");
assert_eq!(info.listen_addrs,
&["/ip4/80.81.82.83/tcp/500".parse().unwrap(),
"/ip6/::1/udp/1000".parse().unwrap()]);
assert_eq!(info.protocols, &["proto1".to_string(), "proto2".to_string()]);
Ok(())
});
let mut rt = Runtime::new().unwrap();
let _ = rt.block_on(future).unwrap();
bg_thread.join().unwrap();