2018-03-07 10:49:11 +01:00
|
|
|
// 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 bytes::{Bytes, BytesMut};
|
|
|
|
use futures::{future, Future, Sink, Stream};
|
2018-06-25 14:54:55 +02:00
|
|
|
use libp2p_core::{ConnectionUpgrade, Endpoint, PublicKey};
|
2018-03-07 10:49:11 +01:00
|
|
|
use multiaddr::Multiaddr;
|
|
|
|
use protobuf::Message as ProtobufMessage;
|
2018-05-21 17:32:59 +02:00
|
|
|
use protobuf::parse_from_bytes as protobuf_parse_from_bytes;
|
|
|
|
use protobuf::RepeatedField;
|
2018-03-07 10:49:11 +01:00
|
|
|
use std::io::{Error as IoError, ErrorKind as IoErrorKind};
|
|
|
|
use std::iter;
|
|
|
|
use structs_proto;
|
2018-06-22 16:12:23 +02:00
|
|
|
use tokio_codec::Framed;
|
2018-05-14 15:55:16 +02:00
|
|
|
use tokio_io::{AsyncRead, AsyncWrite};
|
2018-08-10 16:35:41 +02:00
|
|
|
use unsigned_varint::codec;
|
2018-03-07 10:49:11 +01:00
|
|
|
|
|
|
|
/// Configuration for an upgrade to the identity protocol.
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct IdentifyProtocolConfig;
|
|
|
|
|
|
|
|
/// Output of the connection upgrade.
|
|
|
|
pub enum IdentifyOutput<T> {
|
2018-03-07 16:20:55 +01:00
|
|
|
/// We obtained information from the remote. Happens when we are the dialer.
|
|
|
|
RemoteInfo {
|
2018-06-25 14:54:55 +02:00
|
|
|
/// Information about the remote.
|
2018-03-07 16:20:55 +01:00
|
|
|
info: IdentifyInfo,
|
|
|
|
/// Address the remote sees for us.
|
|
|
|
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>,
|
|
|
|
},
|
2018-03-07 10:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Object used to send back information to the client.
|
|
|
|
pub struct IdentifySender<T> {
|
2018-08-10 16:35:41 +02:00
|
|
|
inner: Framed<T, codec::UviBytes<Vec<u8>>>,
|
2018-03-07 10:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T> IdentifySender<T>
|
|
|
|
where
|
2018-03-07 16:20:55 +01:00
|
|
|
T: AsyncWrite + 'a,
|
2018-03-07 10:49:11 +01:00
|
|
|
{
|
2018-03-07 16:20:55 +01:00
|
|
|
/// 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> + 'a> {
|
2018-05-17 15:14:13 +02:00
|
|
|
debug!("Sending identify info to client");
|
|
|
|
trace!("Sending: {:?}", info);
|
2018-03-07 16:20:55 +01:00
|
|
|
|
|
|
|
let listen_addrs = info.listen_addrs
|
|
|
|
.into_iter()
|
|
|
|
.map(|addr| addr.into_bytes())
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
let mut message = structs_proto::Identify::new();
|
|
|
|
message.set_agentVersion(info.agent_version);
|
|
|
|
message.set_protocolVersion(info.protocol_version);
|
2018-06-25 17:56:36 +02:00
|
|
|
message.set_publicKey(info.public_key.into_protobuf_encoding());
|
2018-03-07 16:20:55 +01:00
|
|
|
message.set_listenAddrs(listen_addrs);
|
|
|
|
message.set_observedAddr(observed_addr.to_bytes());
|
|
|
|
message.set_protocols(RepeatedField::from_vec(info.protocols));
|
|
|
|
|
|
|
|
let bytes = message
|
|
|
|
.write_to_bytes()
|
|
|
|
.expect("writing protobuf failed ; should never happen");
|
|
|
|
|
|
|
|
let future = self.inner.send(bytes).map(|_| ());
|
|
|
|
Box::new(future) as Box<_>
|
|
|
|
}
|
2018-03-07 10:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Information sent from the listener to the dialer.
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct IdentifyInfo {
|
2018-06-05 12:29:59 +02:00
|
|
|
/// Public key of the node.
|
2018-06-25 14:54:55 +02:00
|
|
|
pub public_key: PublicKey,
|
2018-03-07 16:20:55 +01:00
|
|
|
/// Version of the "global" protocol, eg. `ipfs/1.0.0` or `polkadot/1.0.0`.
|
|
|
|
pub protocol_version: String,
|
|
|
|
/// Name and version of the client. Can be thought as similar to the `User-Agent` header
|
|
|
|
/// of HTTP.
|
|
|
|
pub agent_version: String,
|
|
|
|
/// Addresses that the node is listening on.
|
|
|
|
pub listen_addrs: Vec<Multiaddr>,
|
|
|
|
/// Protocols supported by the node, eg. `/ipfs/ping/1.0.0`.
|
|
|
|
pub protocols: Vec<String>,
|
2018-03-07 10:49:11 +01:00
|
|
|
}
|
|
|
|
|
2018-06-19 14:38:55 +02:00
|
|
|
impl<C, Maf> ConnectionUpgrade<C, Maf> for IdentifyProtocolConfig
|
2018-03-07 10:49:11 +01:00
|
|
|
where
|
2018-03-07 16:20:55 +01:00
|
|
|
C: AsyncRead + AsyncWrite + 'static,
|
2018-06-19 14:38:55 +02:00
|
|
|
Maf: Future<Item = Multiaddr, Error = IoError> + 'static,
|
2018-03-07 10:49:11 +01:00
|
|
|
{
|
2018-03-07 16:20:55 +01:00
|
|
|
type NamesIter = iter::Once<(Bytes, Self::UpgradeIdentifier)>;
|
|
|
|
type UpgradeIdentifier = ();
|
|
|
|
type Output = IdentifyOutput<C>;
|
2018-06-19 16:14:27 +02:00
|
|
|
type MultiaddrFuture = future::Either<future::FutureResult<Multiaddr, IoError>, Maf>;
|
2018-06-19 14:38:55 +02:00
|
|
|
type Future = Box<Future<Item = (Self::Output, Self::MultiaddrFuture), Error = IoError>>;
|
2018-03-07 16:20:55 +01:00
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn protocol_names(&self) -> Self::NamesIter {
|
|
|
|
iter::once((Bytes::from("/ipfs/id/1.0.0"), ()))
|
|
|
|
}
|
|
|
|
|
2018-06-19 16:14:27 +02:00
|
|
|
fn upgrade(self, socket: C, _: (), ty: Endpoint, remote_addr: Maf) -> Self::Future {
|
2018-06-19 14:38:55 +02:00
|
|
|
trace!("Upgrading connection as {:?}", ty);
|
2018-03-07 16:20:55 +01:00
|
|
|
|
2018-08-10 16:35:41 +02:00
|
|
|
let socket = Framed::new(socket, codec::UviBytes::default());
|
2018-03-07 16:20:55 +01:00
|
|
|
|
|
|
|
match ty {
|
|
|
|
Endpoint::Dialer => {
|
|
|
|
let future = socket
|
|
|
|
.into_future()
|
|
|
|
.map(|(msg, _)| msg)
|
|
|
|
.map_err(|(err, _)| err)
|
|
|
|
.and_then(|msg| {
|
2018-06-19 14:38:55 +02:00
|
|
|
debug!("Received identify message");
|
2018-03-15 18:03:39 +01:00
|
|
|
|
2018-03-07 16:20:55 +01:00
|
|
|
if let Some(msg) = msg {
|
|
|
|
let (info, observed_addr) = match parse_proto_msg(msg) {
|
|
|
|
Ok(v) => v,
|
|
|
|
Err(err) => {
|
2018-05-17 15:14:13 +02:00
|
|
|
debug!("Failed to parse protobuf message ; error = {:?}", err);
|
2018-03-07 16:20:55 +01:00
|
|
|
return Err(err.into());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-05-17 15:14:13 +02:00
|
|
|
trace!("Remote observes us as {:?}", observed_addr);
|
|
|
|
trace!("Information received: {:?}", info);
|
2018-03-07 16:20:55 +01:00
|
|
|
|
2018-06-19 14:38:55 +02:00
|
|
|
let out = IdentifyOutput::RemoteInfo {
|
2018-03-07 16:20:55 +01:00
|
|
|
info,
|
2018-06-19 14:38:55 +02:00
|
|
|
observed_addr: observed_addr.clone(),
|
|
|
|
};
|
|
|
|
|
2018-06-19 16:14:27 +02:00
|
|
|
Ok((out, future::Either::A(future::ok(observed_addr))))
|
2018-03-07 16:20:55 +01:00
|
|
|
} else {
|
2018-05-17 15:14:13 +02:00
|
|
|
debug!("Identify protocol stream closed before receiving info");
|
2018-03-07 16:20:55 +01:00
|
|
|
Err(IoErrorKind::InvalidData.into())
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
Box::new(future) as Box<_>
|
|
|
|
}
|
|
|
|
|
|
|
|
Endpoint::Listener => {
|
|
|
|
let sender = IdentifySender { inner: socket };
|
|
|
|
|
2018-06-19 16:14:27 +02:00
|
|
|
let future = future::ok({
|
2018-06-19 14:38:55 +02:00
|
|
|
let io = IdentifyOutput::Sender {
|
|
|
|
sender,
|
|
|
|
};
|
|
|
|
|
2018-06-19 16:14:27 +02:00
|
|
|
(io, future::Either::B(remote_addr))
|
2018-03-07 16:20:55 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
Box::new(future) as Box<_>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-03-07 10:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Turns a protobuf message into an `IdentifyInfo` and an observed address. If something bad
|
|
|
|
// happens, turn it into an `IoError`.
|
|
|
|
fn parse_proto_msg(msg: BytesMut) -> Result<(IdentifyInfo, Multiaddr), IoError> {
|
2018-03-07 16:20:55 +01:00
|
|
|
match protobuf_parse_from_bytes::<structs_proto::Identify>(&msg) {
|
|
|
|
Ok(mut msg) => {
|
|
|
|
// Turn a `Vec<u8>` into a `Multiaddr`. If something bad happens, turn it into
|
|
|
|
// an `IoError`.
|
|
|
|
fn bytes_to_multiaddr(bytes: Vec<u8>) -> Result<Multiaddr, IoError> {
|
|
|
|
Multiaddr::from_bytes(bytes)
|
|
|
|
.map_err(|err| IoError::new(IoErrorKind::InvalidData, err))
|
|
|
|
}
|
|
|
|
|
|
|
|
let listen_addrs = {
|
|
|
|
let mut addrs = Vec::new();
|
|
|
|
for addr in msg.take_listenAddrs().into_iter() {
|
|
|
|
addrs.push(bytes_to_multiaddr(addr)?);
|
|
|
|
}
|
|
|
|
addrs
|
|
|
|
};
|
|
|
|
|
|
|
|
let observed_addr = bytes_to_multiaddr(msg.take_observedAddr())?;
|
|
|
|
let info = IdentifyInfo {
|
2018-06-25 17:56:36 +02:00
|
|
|
public_key: PublicKey::from_protobuf_encoding(msg.get_publicKey())?,
|
2018-03-07 16:20:55 +01:00
|
|
|
protocol_version: msg.take_protocolVersion(),
|
|
|
|
agent_version: msg.take_agentVersion(),
|
|
|
|
listen_addrs: listen_addrs,
|
|
|
|
protocols: msg.take_protocols().into_vec(),
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok((info, observed_addr))
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(err) => Err(IoError::new(IoErrorKind::InvalidData, err)),
|
|
|
|
}
|
2018-03-07 10:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2018-03-07 16:20:55 +01:00
|
|
|
extern crate libp2p_tcp_transport;
|
2018-07-16 12:15:27 +02:00
|
|
|
extern crate tokio_current_thread;
|
2018-03-07 16:20:55 +01:00
|
|
|
|
|
|
|
use self::libp2p_tcp_transport::TcpConfig;
|
|
|
|
use futures::{Future, Stream};
|
2018-06-25 17:56:36 +02:00
|
|
|
use libp2p_core::{PublicKey, Transport};
|
2018-03-07 16:20:55 +01:00
|
|
|
use std::sync::mpsc;
|
|
|
|
use std::thread;
|
2018-05-14 15:55:16 +02:00
|
|
|
use {IdentifyInfo, IdentifyOutput, IdentifyProtocolConfig};
|
2018-03-07 16:20:55 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn correct_transfer() {
|
|
|
|
// We open a server and a client, send info from the server to the client, and check that
|
|
|
|
// they were successfully received.
|
|
|
|
|
|
|
|
let (tx, rx) = mpsc::channel();
|
|
|
|
|
|
|
|
let bg_thread = thread::spawn(move || {
|
2018-07-16 12:15:27 +02:00
|
|
|
let transport = TcpConfig::new().with_upgrade(IdentifyProtocolConfig);
|
2018-03-07 16:20:55 +01:00
|
|
|
|
|
|
|
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().map(|v| v.0))
|
|
|
|
.and_then(|identify| match identify {
|
|
|
|
IdentifyOutput::Sender { sender, .. } => sender.send(
|
|
|
|
IdentifyInfo {
|
2018-06-25 14:54:55 +02:00
|
|
|
public_key: PublicKey::Ed25519(vec![1, 2, 3, 4, 5, 7]),
|
2018-03-07 16:20:55 +01:00
|
|
|
protocol_version: "proto_version".to_owned(),
|
|
|
|
agent_version: "agent_version".to_owned(),
|
|
|
|
listen_addrs: vec![
|
|
|
|
"/ip4/80.81.82.83/tcp/500".parse().unwrap(),
|
|
|
|
"/ip6/::1/udp/1000".parse().unwrap(),
|
|
|
|
],
|
|
|
|
protocols: vec!["proto1".to_string(), "proto2".to_string()],
|
|
|
|
},
|
|
|
|
&"/ip4/100.101.102.103/tcp/5000".parse().unwrap(),
|
|
|
|
),
|
|
|
|
_ => panic!(),
|
|
|
|
});
|
|
|
|
|
2018-07-16 12:15:27 +02:00
|
|
|
let _ = tokio_current_thread::block_on_all(future).unwrap();
|
2018-03-07 16:20:55 +01:00
|
|
|
});
|
|
|
|
|
2018-07-16 12:15:27 +02:00
|
|
|
let transport = TcpConfig::new().with_upgrade(IdentifyProtocolConfig);
|
2018-03-07 16:20:55 +01:00
|
|
|
|
|
|
|
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()
|
|
|
|
);
|
2018-06-25 17:56:36 +02:00
|
|
|
assert_eq!(info.public_key, PublicKey::Ed25519(vec![1, 2, 3, 4, 5, 7]));
|
2018-03-07 16:20:55 +01:00
|
|
|
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!(),
|
|
|
|
});
|
|
|
|
|
2018-07-16 12:15:27 +02:00
|
|
|
let _ = tokio_current_thread::block_on_all(future).unwrap();
|
2018-03-07 16:20:55 +01:00
|
|
|
bg_thread.join().unwrap();
|
|
|
|
}
|
2018-03-07 10:49:11 +01:00
|
|
|
}
|