2018-11-02 10:06:59 +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.
|
|
|
|
|
2021-03-18 12:47:01 +01:00
|
|
|
use crate::protocol::{
|
2022-12-13 20:24:31 +00:00
|
|
|
self, Identify, InboundPush, Info, OutboundPush, Protocol, Push, UpgradeError,
|
2021-03-18 12:47:01 +01:00
|
|
|
};
|
2023-01-18 10:05:59 +11:00
|
|
|
use either::Either;
|
2022-06-07 13:42:34 +02:00
|
|
|
use futures::future::BoxFuture;
|
2018-11-02 10:06:59 +01:00
|
|
|
use futures::prelude::*;
|
2022-12-13 20:24:31 +00:00
|
|
|
use futures::stream::FuturesUnordered;
|
2021-10-30 12:41:30 +02:00
|
|
|
use futures_timer::Delay;
|
2023-01-18 13:35:07 +11:00
|
|
|
use libp2p_core::upgrade::SelectUpgrade;
|
2023-03-13 01:46:58 +11:00
|
|
|
use libp2p_core::Multiaddr;
|
|
|
|
use libp2p_identity::PeerId;
|
|
|
|
use libp2p_identity::PublicKey;
|
2022-11-17 17:19:36 +00:00
|
|
|
use libp2p_swarm::handler::{
|
|
|
|
ConnectionEvent, DialUpgradeError, FullyNegotiatedInbound, FullyNegotiatedOutbound,
|
|
|
|
};
|
2019-07-04 14:47:59 +02:00
|
|
|
use libp2p_swarm::{
|
2023-05-08 10:55:17 +02:00
|
|
|
ConnectionHandler, ConnectionHandlerEvent, KeepAlive, NegotiatedSubstream, StreamProtocol,
|
|
|
|
StreamUpgradeError, SubstreamProtocol,
|
2018-11-15 17:41:11 +01:00
|
|
|
};
|
2022-06-07 13:42:34 +02:00
|
|
|
use log::warn;
|
2019-09-02 11:16:52 +02:00
|
|
|
use smallvec::SmallVec;
|
2023-05-08 05:39:34 +02:00
|
|
|
use std::collections::{HashSet, VecDeque};
|
2021-03-18 12:47:01 +01:00
|
|
|
use std::{io, pin::Pin, task::Context, task::Poll, time::Duration};
|
2018-11-02 10:06:59 +01:00
|
|
|
|
2019-09-02 11:16:52 +02:00
|
|
|
/// Protocol handler for sending and receiving identification requests.
|
|
|
|
///
|
|
|
|
/// Outbound requests are sent periodically. The handler performs expects
|
|
|
|
/// at least one identification request to be answered by the remote before
|
|
|
|
/// permitting the underlying connection to be closed.
|
2022-10-04 01:17:31 +01:00
|
|
|
pub struct Handler {
|
2022-06-26 10:37:29 +02:00
|
|
|
remote_peer_id: PeerId,
|
2022-10-04 01:17:31 +01:00
|
|
|
inbound_identify_push: Option<BoxFuture<'static, Result<Info, UpgradeError>>>,
|
2019-09-02 11:16:52 +02:00
|
|
|
/// Pending events to yield.
|
2021-08-11 13:12:12 +02:00
|
|
|
events: SmallVec<
|
2023-01-18 13:35:07 +11:00
|
|
|
[ConnectionHandlerEvent<Either<Identify, Push<OutboundPush>>, (), Event, io::Error>; 4],
|
2021-08-11 13:12:12 +02:00
|
|
|
>,
|
2018-11-02 10:06:59 +01:00
|
|
|
|
2022-12-13 20:24:31 +00:00
|
|
|
/// Streams awaiting `BehaviourInfo` to then send identify requests.
|
|
|
|
reply_streams: VecDeque<NegotiatedSubstream>,
|
|
|
|
|
|
|
|
/// Pending identification replies, awaiting being sent.
|
|
|
|
pending_replies: FuturesUnordered<BoxFuture<'static, Result<PeerId, UpgradeError>>>,
|
|
|
|
|
2019-03-11 17:19:50 +01:00
|
|
|
/// Future that fires when we need to identify the node again.
|
2022-05-11 03:18:20 +02:00
|
|
|
trigger_next_identify: Delay,
|
2018-11-02 10:06:59 +01:00
|
|
|
|
2022-05-11 03:18:20 +02:00
|
|
|
/// The interval of `trigger_next_identify`, i.e. the recurrent delay.
|
2021-03-18 12:47:01 +01:00
|
|
|
interval: Duration,
|
2022-12-13 20:24:31 +00:00
|
|
|
|
|
|
|
/// The public key of the local peer.
|
|
|
|
public_key: PublicKey,
|
|
|
|
|
|
|
|
/// Application-specific version of the protocol family used by the peer,
|
|
|
|
/// e.g. `ipfs/1.0.0` or `polkadot/1.0.0`.
|
|
|
|
protocol_version: String,
|
|
|
|
|
|
|
|
/// Name and version of the peer, similar to the `User-Agent` header in
|
|
|
|
/// the HTTP protocol.
|
|
|
|
agent_version: String,
|
|
|
|
|
|
|
|
/// Address observed by or for the remote.
|
|
|
|
observed_addr: Multiaddr,
|
2018-11-02 10:06:59 +01:00
|
|
|
}
|
|
|
|
|
2022-12-13 20:24:31 +00:00
|
|
|
/// An event from `Behaviour` with the information requested by the `Handler`.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct InEvent {
|
|
|
|
/// The addresses that the peer is listening on.
|
2023-05-08 05:39:34 +02:00
|
|
|
pub listen_addrs: HashSet<Multiaddr>,
|
2022-12-13 20:24:31 +00:00
|
|
|
|
|
|
|
/// The list of protocols supported by the peer, e.g. `/ipfs/ping/1.0.0`.
|
2023-05-04 05:47:11 +01:00
|
|
|
pub supported_protocols: Vec<StreamProtocol>,
|
2022-12-13 20:24:31 +00:00
|
|
|
|
|
|
|
/// The protocol w.r.t. the information requested.
|
|
|
|
pub protocol: Protocol,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Event produced by the `Handler`.
|
2018-11-02 10:06:59 +01:00
|
|
|
#[derive(Debug)]
|
2022-11-04 20:40:09 +11:00
|
|
|
#[allow(clippy::large_enum_variant)]
|
2022-10-04 01:17:31 +01:00
|
|
|
pub enum Event {
|
2021-03-18 12:47:01 +01:00
|
|
|
/// We obtained identification information from the remote.
|
2022-10-04 01:17:31 +01:00
|
|
|
Identified(Info),
|
2022-12-13 20:24:31 +00:00
|
|
|
/// We replied to an identification request from the remote.
|
|
|
|
Identification(PeerId),
|
2021-04-10 19:46:57 +02:00
|
|
|
/// We actively pushed our identification information to the remote.
|
|
|
|
IdentificationPushed,
|
2019-09-02 11:16:52 +02:00
|
|
|
/// We received a request for identification.
|
2022-12-13 20:24:31 +00:00
|
|
|
Identify,
|
|
|
|
/// Failed to identify the remote, or to reply to an identification request.
|
2023-05-08 10:55:17 +02:00
|
|
|
IdentificationError(StreamUpgradeError<UpgradeError>),
|
2018-11-02 10:06:59 +01:00
|
|
|
}
|
|
|
|
|
2022-10-04 01:17:31 +01:00
|
|
|
impl Handler {
|
2022-12-13 20:24:31 +00:00
|
|
|
/// Creates a new `Handler`.
|
|
|
|
pub fn new(
|
|
|
|
initial_delay: Duration,
|
|
|
|
interval: Duration,
|
|
|
|
remote_peer_id: PeerId,
|
|
|
|
public_key: PublicKey,
|
|
|
|
protocol_version: String,
|
|
|
|
agent_version: String,
|
|
|
|
observed_addr: Multiaddr,
|
|
|
|
) -> Self {
|
2022-10-04 01:17:31 +01:00
|
|
|
Self {
|
2022-06-26 10:37:29 +02:00
|
|
|
remote_peer_id,
|
2022-06-07 13:42:34 +02:00
|
|
|
inbound_identify_push: Default::default(),
|
2019-09-02 11:16:52 +02:00
|
|
|
events: SmallVec::new(),
|
2022-12-13 20:24:31 +00:00
|
|
|
reply_streams: VecDeque::new(),
|
|
|
|
pending_replies: FuturesUnordered::new(),
|
2022-05-11 03:18:20 +02:00
|
|
|
trigger_next_identify: Delay::new(initial_delay),
|
2021-03-18 12:47:01 +01:00
|
|
|
interval,
|
2022-12-13 20:24:31 +00:00
|
|
|
public_key,
|
|
|
|
protocol_version,
|
|
|
|
agent_version,
|
|
|
|
observed_addr,
|
2018-11-02 10:06:59 +01:00
|
|
|
}
|
|
|
|
}
|
2018-11-15 17:41:11 +01:00
|
|
|
|
2022-11-17 17:19:36 +00:00
|
|
|
fn on_fully_negotiated_inbound(
|
2019-09-02 11:16:52 +02:00
|
|
|
&mut self,
|
2022-11-17 17:19:36 +00:00
|
|
|
FullyNegotiatedInbound {
|
|
|
|
protocol: output, ..
|
|
|
|
}: FullyNegotiatedInbound<
|
|
|
|
<Self as ConnectionHandler>::InboundProtocol,
|
|
|
|
<Self as ConnectionHandler>::InboundOpenInfo,
|
|
|
|
>,
|
2019-09-02 11:16:52 +02:00
|
|
|
) {
|
2021-03-18 12:47:01 +01:00
|
|
|
match output {
|
2023-01-23 23:31:30 +11:00
|
|
|
future::Either::Left(substream) => {
|
2022-12-13 20:24:31 +00:00
|
|
|
self.events
|
|
|
|
.push(ConnectionHandlerEvent::Custom(Event::Identify));
|
|
|
|
if !self.reply_streams.is_empty() {
|
|
|
|
warn!(
|
|
|
|
"New inbound identify request from {} while a previous one \
|
|
|
|
is still pending. Queueing the new one.",
|
|
|
|
self.remote_peer_id,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
self.reply_streams.push_back(substream);
|
|
|
|
}
|
2023-01-23 23:31:30 +11:00
|
|
|
future::Either::Right(fut) => {
|
2022-06-07 13:42:34 +02:00
|
|
|
if self.inbound_identify_push.replace(fut).is_some() {
|
|
|
|
warn!(
|
2022-06-26 10:37:29 +02:00
|
|
|
"New inbound identify push stream from {} while still \
|
|
|
|
upgrading previous one. Replacing previous with new.",
|
|
|
|
self.remote_peer_id,
|
2022-06-07 13:42:34 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2021-03-18 12:47:01 +01:00
|
|
|
}
|
2018-11-15 17:41:11 +01:00
|
|
|
}
|
|
|
|
|
2022-11-17 17:19:36 +00:00
|
|
|
fn on_fully_negotiated_outbound(
|
2018-11-02 10:06:59 +01:00
|
|
|
&mut self,
|
2022-11-17 17:19:36 +00:00
|
|
|
FullyNegotiatedOutbound {
|
|
|
|
protocol: output, ..
|
|
|
|
}: FullyNegotiatedOutbound<
|
|
|
|
<Self as ConnectionHandler>::OutboundProtocol,
|
|
|
|
<Self as ConnectionHandler>::OutboundOpenInfo,
|
|
|
|
>,
|
2018-11-02 10:06:59 +01:00
|
|
|
) {
|
2021-03-18 12:47:01 +01:00
|
|
|
match output {
|
2023-01-23 23:31:30 +11:00
|
|
|
future::Either::Left(remote_info) => {
|
2022-10-04 01:17:31 +01:00
|
|
|
self.events
|
|
|
|
.push(ConnectionHandlerEvent::Custom(Event::Identified(
|
|
|
|
remote_info,
|
|
|
|
)));
|
2021-03-18 12:47:01 +01:00
|
|
|
}
|
2023-01-23 23:31:30 +11:00
|
|
|
future::Either::Right(()) => self
|
2022-10-04 01:17:31 +01:00
|
|
|
.events
|
|
|
|
.push(ConnectionHandlerEvent::Custom(Event::IdentificationPushed)),
|
2021-03-18 12:47:01 +01:00
|
|
|
}
|
2018-11-02 10:06:59 +01:00
|
|
|
}
|
|
|
|
|
2022-11-17 17:19:36 +00:00
|
|
|
fn on_dial_upgrade_error(
|
2019-09-02 11:16:52 +02:00
|
|
|
&mut self,
|
2022-11-17 17:19:36 +00:00
|
|
|
DialUpgradeError { error: err, .. }: DialUpgradeError<
|
|
|
|
<Self as ConnectionHandler>::OutboundOpenInfo,
|
|
|
|
<Self as ConnectionHandler>::OutboundProtocol,
|
2021-08-11 13:12:12 +02:00
|
|
|
>,
|
2019-09-02 11:16:52 +02:00
|
|
|
) {
|
2023-05-08 10:55:17 +02:00
|
|
|
let err = err.map_upgrade_err(|e| e.into_inner());
|
2022-10-04 01:17:31 +01:00
|
|
|
self.events
|
|
|
|
.push(ConnectionHandlerEvent::Custom(Event::IdentificationError(
|
|
|
|
err,
|
|
|
|
)));
|
2022-05-11 03:18:20 +02:00
|
|
|
self.trigger_next_identify.reset(self.interval);
|
2018-11-02 10:06:59 +01:00
|
|
|
}
|
2022-11-17 17:19:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ConnectionHandler for Handler {
|
2022-12-13 20:24:31 +00:00
|
|
|
type InEvent = InEvent;
|
2022-11-17 17:19:36 +00:00
|
|
|
type OutEvent = Event;
|
|
|
|
type Error = io::Error;
|
2022-12-13 20:24:31 +00:00
|
|
|
type InboundProtocol = SelectUpgrade<Identify, Push<InboundPush>>;
|
2023-01-18 13:35:07 +11:00
|
|
|
type OutboundProtocol = Either<Identify, Push<OutboundPush>>;
|
2022-11-17 17:19:36 +00:00
|
|
|
type OutboundOpenInfo = ();
|
|
|
|
type InboundOpenInfo = ();
|
|
|
|
|
|
|
|
fn listen_protocol(&self) -> SubstreamProtocol<Self::InboundProtocol, Self::InboundOpenInfo> {
|
2022-12-13 20:24:31 +00:00
|
|
|
SubstreamProtocol::new(SelectUpgrade::new(Identify, Push::inbound()), ())
|
2022-11-17 17:19:36 +00:00
|
|
|
}
|
|
|
|
|
2022-12-13 20:24:31 +00:00
|
|
|
fn on_behaviour_event(
|
|
|
|
&mut self,
|
|
|
|
InEvent {
|
|
|
|
listen_addrs,
|
|
|
|
supported_protocols,
|
|
|
|
protocol,
|
|
|
|
}: Self::InEvent,
|
|
|
|
) {
|
|
|
|
let info = Info {
|
|
|
|
public_key: self.public_key.clone(),
|
|
|
|
protocol_version: self.protocol_version.clone(),
|
|
|
|
agent_version: self.agent_version.clone(),
|
2023-05-08 05:39:34 +02:00
|
|
|
listen_addrs: Vec::from_iter(listen_addrs),
|
2022-12-13 20:24:31 +00:00
|
|
|
protocols: supported_protocols,
|
|
|
|
observed_addr: self.observed_addr.clone(),
|
|
|
|
};
|
|
|
|
|
|
|
|
match protocol {
|
|
|
|
Protocol::Push => {
|
|
|
|
self.events
|
|
|
|
.push(ConnectionHandlerEvent::OutboundSubstreamRequest {
|
2023-01-18 13:35:07 +11:00
|
|
|
protocol: SubstreamProtocol::new(Either::Right(Push::outbound(info)), ()),
|
2022-12-13 20:24:31 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
Protocol::Identify(_) => {
|
|
|
|
let substream = self
|
|
|
|
.reply_streams
|
|
|
|
.pop_front()
|
|
|
|
.expect("A BehaviourInfo reply should have a matching substream.");
|
|
|
|
let peer = self.remote_peer_id;
|
|
|
|
let fut = Box::pin(async move {
|
|
|
|
protocol::send(substream, info).await?;
|
|
|
|
Ok(peer)
|
|
|
|
});
|
|
|
|
self.pending_replies.push(fut);
|
|
|
|
}
|
|
|
|
}
|
2022-11-17 17:19:36 +00:00
|
|
|
}
|
2018-11-02 10:06:59 +01:00
|
|
|
|
2019-01-30 16:37:34 +01:00
|
|
|
fn connection_keep_alive(&self) -> KeepAlive {
|
2023-05-08 11:31:25 +02:00
|
|
|
if self.inbound_identify_push.is_some() {
|
|
|
|
return KeepAlive::Yes;
|
|
|
|
}
|
|
|
|
|
|
|
|
if !self.pending_replies.is_empty() {
|
|
|
|
return KeepAlive::Yes;
|
|
|
|
}
|
|
|
|
|
|
|
|
if !self.reply_streams.is_empty() {
|
|
|
|
return KeepAlive::Yes;
|
|
|
|
}
|
|
|
|
|
|
|
|
KeepAlive::No
|
2019-01-04 12:02:39 +01:00
|
|
|
}
|
|
|
|
|
2021-08-11 13:12:12 +02:00
|
|
|
fn poll(
|
|
|
|
&mut self,
|
|
|
|
cx: &mut Context<'_>,
|
|
|
|
) -> Poll<
|
2022-10-04 01:17:31 +01:00
|
|
|
ConnectionHandlerEvent<Self::OutboundProtocol, Self::OutboundOpenInfo, Event, Self::Error>,
|
2018-11-02 10:06:59 +01:00
|
|
|
> {
|
2019-09-02 11:16:52 +02:00
|
|
|
if !self.events.is_empty() {
|
2021-08-11 13:12:12 +02:00
|
|
|
return Poll::Ready(self.events.remove(0));
|
2018-11-02 10:06:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Poll the future that fires when we need to identify the node again.
|
2022-05-11 03:18:20 +02:00
|
|
|
match Future::poll(Pin::new(&mut self.trigger_next_identify), cx) {
|
2022-06-07 13:42:34 +02:00
|
|
|
Poll::Pending => {}
|
2021-10-30 12:41:30 +02:00
|
|
|
Poll::Ready(()) => {
|
2022-05-11 03:18:20 +02:00
|
|
|
self.trigger_next_identify.reset(self.interval);
|
2022-02-21 13:32:24 +01:00
|
|
|
let ev = ConnectionHandlerEvent::OutboundSubstreamRequest {
|
2023-01-18 13:35:07 +11:00
|
|
|
protocol: SubstreamProtocol::new(Either::Left(Identify), ()),
|
2019-04-16 15:57:29 +02:00
|
|
|
};
|
2022-06-07 13:42:34 +02:00
|
|
|
return Poll::Ready(ev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(Poll::Ready(res)) = self
|
|
|
|
.inbound_identify_push
|
|
|
|
.as_mut()
|
|
|
|
.map(|f| f.poll_unpin(cx))
|
|
|
|
{
|
|
|
|
self.inbound_identify_push.take();
|
|
|
|
|
|
|
|
if let Ok(info) = res {
|
2022-10-04 01:17:31 +01:00
|
|
|
return Poll::Ready(ConnectionHandlerEvent::Custom(Event::Identified(info)));
|
2018-11-02 10:06:59 +01:00
|
|
|
}
|
|
|
|
}
|
2022-06-07 13:42:34 +02:00
|
|
|
|
2022-12-13 20:24:31 +00:00
|
|
|
// Check for pending replies to send.
|
|
|
|
match self.pending_replies.poll_next_unpin(cx) {
|
|
|
|
Poll::Ready(Some(Ok(peer_id))) => Poll::Ready(ConnectionHandlerEvent::Custom(
|
|
|
|
Event::Identification(peer_id),
|
|
|
|
)),
|
|
|
|
Poll::Ready(Some(Err(err))) => Poll::Ready(ConnectionHandlerEvent::Custom(
|
2023-05-08 10:55:17 +02:00
|
|
|
Event::IdentificationError(StreamUpgradeError::Apply(err)),
|
2022-12-13 20:24:31 +00:00
|
|
|
)),
|
|
|
|
Poll::Ready(None) | Poll::Pending => Poll::Pending,
|
|
|
|
}
|
2018-11-02 10:06:59 +01:00
|
|
|
}
|
2022-11-17 17:19:36 +00:00
|
|
|
|
|
|
|
fn on_connection_event(
|
|
|
|
&mut self,
|
|
|
|
event: ConnectionEvent<
|
|
|
|
Self::InboundProtocol,
|
|
|
|
Self::OutboundProtocol,
|
|
|
|
Self::InboundOpenInfo,
|
|
|
|
Self::OutboundOpenInfo,
|
|
|
|
>,
|
|
|
|
) {
|
|
|
|
match event {
|
|
|
|
ConnectionEvent::FullyNegotiatedInbound(fully_negotiated_inbound) => {
|
|
|
|
self.on_fully_negotiated_inbound(fully_negotiated_inbound)
|
|
|
|
}
|
|
|
|
ConnectionEvent::FullyNegotiatedOutbound(fully_negotiated_outbound) => {
|
|
|
|
self.on_fully_negotiated_outbound(fully_negotiated_outbound)
|
|
|
|
}
|
|
|
|
ConnectionEvent::DialUpgradeError(dial_upgrade_error) => {
|
|
|
|
self.on_dial_upgrade_error(dial_upgrade_error)
|
|
|
|
}
|
|
|
|
ConnectionEvent::AddressChange(_) | ConnectionEvent::ListenUpgradeError(_) => {}
|
|
|
|
}
|
|
|
|
}
|
2018-11-02 10:06:59 +01:00
|
|
|
}
|