2121use crate :: protocol;
2222use futures:: prelude:: * ;
2323use futures:: future:: BoxFuture ;
24+ use libp2p_core:: { UpgradeError , upgrade:: NegotiationError } ;
2425use libp2p_swarm:: {
2526 KeepAlive ,
2627 NegotiatedSubstream ,
@@ -140,6 +141,8 @@ pub enum PingFailure {
140141 /// The ping timed out, i.e. no response was received within the
141142 /// configured ping timeout.
142143 Timeout ,
144+ /// The peer does not support the ping protocol.
145+ Unsupported ,
143146 /// The ping failed for reasons other than a timeout.
144147 Other { error : Box < dyn std:: error:: Error + Send + ' static > }
145148}
@@ -148,7 +151,8 @@ impl fmt::Display for PingFailure {
148151 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
149152 match self {
150153 PingFailure :: Timeout => f. write_str ( "Ping timeout" ) ,
151- PingFailure :: Other { error } => write ! ( f, "Ping error: {}" , error)
154+ PingFailure :: Other { error } => write ! ( f, "Ping error: {}" , error) ,
155+ PingFailure :: Unsupported => write ! ( f, "Ping protocol not supported" ) ,
152156 }
153157 }
154158}
@@ -157,7 +161,8 @@ impl Error for PingFailure {
157161 fn source ( & self ) -> Option < & ( dyn Error + ' static ) > {
158162 match self {
159163 PingFailure :: Timeout => None ,
160- PingFailure :: Other { error } => Some ( & * * error)
164+ PingFailure :: Other { error } => Some ( & * * error) ,
165+ PingFailure :: Unsupported => None ,
161166 }
162167 }
163168}
@@ -184,6 +189,21 @@ pub struct PingHandler {
184189 /// substream, this is always a future that waits for the
185190 /// next inbound ping to be answered.
186191 inbound : Option < PongFuture > ,
192+ /// Tracks the state of our handler.
193+ state : State
194+ }
195+
196+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
197+ enum State {
198+ /// We are inactive because the other peer doesn't support ping.
199+ Inactive {
200+ /// Whether or not we've reported the missing support yet.
201+ ///
202+ /// This is used to avoid repeated events being emitted for a specific connection.
203+ reported : bool
204+ } ,
205+ /// We are actively pinging the other peer.
206+ Active ,
187207}
188208
189209impl PingHandler {
@@ -196,6 +216,7 @@ impl PingHandler {
196216 failures : 0 ,
197217 outbound : None ,
198218 inbound : None ,
219+ state : State :: Active ,
199220 }
200221 }
201222}
@@ -226,12 +247,22 @@ impl ProtocolsHandler for PingHandler {
226247
227248 fn inject_dial_upgrade_error ( & mut self , _info : ( ) , error : ProtocolsHandlerUpgrErr < Void > ) {
228249 self . outbound = None ; // Request a new substream on the next `poll`.
229- self . pending_errors . push_front (
230- match error {
231- // Note: This timeout only covers protocol negotiation.
232- ProtocolsHandlerUpgrErr :: Timeout => PingFailure :: Timeout ,
233- e => PingFailure :: Other { error : Box :: new ( e) } ,
234- } )
250+
251+ let error = match error {
252+ ProtocolsHandlerUpgrErr :: Upgrade ( UpgradeError :: Select ( NegotiationError :: Failed ) ) => {
253+ debug_assert_eq ! ( self . state, State :: Active ) ;
254+
255+ self . state = State :: Inactive {
256+ reported : false
257+ } ;
258+ return ;
259+ } ,
260+ // Note: This timeout only covers protocol negotiation.
261+ ProtocolsHandlerUpgrErr :: Timeout => PingFailure :: Timeout ,
262+ e => PingFailure :: Other { error : Box :: new ( e) } ,
263+ } ;
264+
265+ self . pending_errors . push_front ( error) ;
235266 }
236267
237268 fn connection_keep_alive ( & self ) -> KeepAlive {
@@ -243,6 +274,17 @@ impl ProtocolsHandler for PingHandler {
243274 }
244275
245276 fn poll ( & mut self , cx : & mut Context < ' _ > ) -> Poll < ProtocolsHandlerEvent < protocol:: Ping , ( ) , PingResult , Self :: Error > > {
277+ match self . state {
278+ State :: Inactive { reported : true } => {
279+ return Poll :: Pending // nothing to do on this connection
280+ } ,
281+ State :: Inactive { reported : false } => {
282+ self . state = State :: Inactive { reported : true } ;
283+ return Poll :: Ready ( ProtocolsHandlerEvent :: Custom ( Err ( PingFailure :: Unsupported ) ) ) ;
284+ } ,
285+ State :: Active => { }
286+ }
287+
246288 // Respond to inbound pings.
247289 if let Some ( fut) = self . inbound . as_mut ( ) {
248290 match fut. poll_unpin ( cx) {
@@ -355,4 +397,3 @@ enum PingState {
355397 /// A ping is being sent and the response awaited.
356398 Ping ( PingFuture ) ,
357399}
358-
0 commit comments