libp2p_ping/
lib.rs

1// Copyright 2017-2018 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21//! This module implements the `/ipfs/ping/1.0.0` protocol.
22//!
23//! The ping protocol can be used as a simple application-layer health check
24//! for connections of any [`Transport`] as well as to measure and record
25//! round-trip times.
26//!
27//! # Usage
28//!
29//! The [`Behaviour`] struct implements the [`NetworkBehaviour`] trait.
30//! It will respond to inbound ping requests and periodically send outbound ping requests on every established connection.
31//!
32//! It is up to the user to implement a health-check / connection management policy based on the ping protocol.
33//!
34//! For example:
35//!
36//! - Disconnect from peers with an RTT > 200ms
37//! - Disconnect from peers which don't support the ping protocol
38//! - Disconnect from peers upon the first ping failure
39//!
40//! Users should inspect emitted [`Event`]s and call APIs on [`Swarm`]:
41//!
42//! - [`Swarm::close_connection`](libp2p_swarm::Swarm::close_connection) to close a specific connection
43//! - [`Swarm::disconnect_peer_id`](libp2p_swarm::Swarm::disconnect_peer_id) to close all connections to a peer
44//!
45//! [`Swarm`]: libp2p_swarm::Swarm
46//! [`Transport`]: libp2p_core::Transport
47
48#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
49
50mod handler;
51mod protocol;
52
53use handler::Handler;
54use libp2p_core::{Endpoint, Multiaddr};
55use libp2p_identity::PeerId;
56use libp2p_swarm::{
57    behaviour::FromSwarm, ConnectionDenied, ConnectionId, NetworkBehaviour, PollParameters,
58    THandler, THandlerInEvent, THandlerOutEvent, ToSwarm,
59};
60use std::time::Duration;
61use std::{
62    collections::VecDeque,
63    task::{Context, Poll},
64};
65
66pub use self::protocol::PROTOCOL_NAME;
67pub use handler::{Config, Failure};
68
69/// A [`NetworkBehaviour`] that responds to inbound pings and
70/// periodically sends outbound pings on every established connection.
71///
72/// See the crate root documentation for more information.
73pub struct Behaviour {
74    /// Configuration for outbound pings.
75    config: Config,
76    /// Queue of events to yield to the swarm.
77    events: VecDeque<Event>,
78}
79
80/// Event generated by the `Ping` network behaviour.
81#[derive(Debug)]
82pub struct Event {
83    /// The peer ID of the remote.
84    pub peer: PeerId,
85    /// The connection the ping was executed on.
86    pub connection: ConnectionId,
87    /// The result of an inbound or outbound ping.
88    pub result: Result<Duration, Failure>,
89}
90
91impl Behaviour {
92    /// Creates a new `Ping` network behaviour with the given configuration.
93    pub fn new(config: Config) -> Self {
94        Self {
95            config,
96            events: VecDeque::new(),
97        }
98    }
99}
100
101impl Default for Behaviour {
102    fn default() -> Self {
103        Self::new(Config::new())
104    }
105}
106
107impl NetworkBehaviour for Behaviour {
108    type ConnectionHandler = Handler;
109    type ToSwarm = Event;
110
111    fn handle_established_inbound_connection(
112        &mut self,
113        _: ConnectionId,
114        peer: PeerId,
115        _: &Multiaddr,
116        _: &Multiaddr,
117    ) -> Result<THandler<Self>, ConnectionDenied> {
118        Ok(Handler::new(self.config.clone(), peer))
119    }
120
121    fn handle_established_outbound_connection(
122        &mut self,
123        _: ConnectionId,
124        peer: PeerId,
125        _: &Multiaddr,
126        _: Endpoint,
127    ) -> Result<THandler<Self>, ConnectionDenied> {
128        Ok(Handler::new(self.config.clone(), peer))
129    }
130
131    fn on_connection_handler_event(
132        &mut self,
133        peer: PeerId,
134        connection: ConnectionId,
135        result: THandlerOutEvent<Self>,
136    ) {
137        self.events.push_front(Event {
138            peer,
139            connection,
140            result,
141        })
142    }
143
144    fn poll(
145        &mut self,
146        _: &mut Context<'_>,
147        _: &mut impl PollParameters,
148    ) -> Poll<ToSwarm<Self::ToSwarm, THandlerInEvent<Self>>> {
149        if let Some(e) = self.events.pop_back() {
150            Poll::Ready(ToSwarm::GenerateEvent(e))
151        } else {
152            Poll::Pending
153        }
154    }
155
156    fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
157        match event {
158            FromSwarm::ConnectionEstablished(_)
159            | FromSwarm::ConnectionClosed(_)
160            | FromSwarm::AddressChange(_)
161            | FromSwarm::DialFailure(_)
162            | FromSwarm::ListenFailure(_)
163            | FromSwarm::NewListener(_)
164            | FromSwarm::NewListenAddr(_)
165            | FromSwarm::ExpiredListenAddr(_)
166            | FromSwarm::ListenerError(_)
167            | FromSwarm::ListenerClosed(_)
168            | FromSwarm::NewExternalAddrCandidate(_)
169            | FromSwarm::ExternalAddrExpired(_)
170            | FromSwarm::ExternalAddrConfirmed(_) => {}
171        }
172    }
173}