@@ -36,6 +36,7 @@ use libp2p_swarm::{
36
36
} ;
37
37
use log:: warn;
38
38
use smallvec:: SmallVec ;
39
+ use std:: collections:: VecDeque ;
39
40
use std:: { io, pin:: Pin , task:: Context , task:: Poll , time:: Duration } ;
40
41
41
42
pub struct Proto {
@@ -64,6 +65,17 @@ impl IntoConnectionHandler for Proto {
64
65
}
65
66
}
66
67
68
+ /// A pending reply to an inbound identification request.
69
+ enum Pending {
70
+ /// The reply is queued for sending.
71
+ Queued ( Reply ) ,
72
+ /// The reply is being sent.
73
+ Sending {
74
+ peer : PeerId ,
75
+ io : Pin < Box < dyn Future < Output = Result < ( ) , UpgradeError > > + Send > > ,
76
+ } ,
77
+ }
78
+
67
79
/// A reply to an inbound identification request.
68
80
#[ derive( Debug ) ]
69
81
pub struct Reply {
@@ -90,6 +102,9 @@ pub struct Handler {
90
102
> ; 4 ] ,
91
103
> ,
92
104
105
+ /// Pending replies to send.
106
+ pending_replies : VecDeque < Pending > ,
107
+
93
108
/// Future that fires when we need to identify the node again.
94
109
trigger_next_identify : Delay ,
95
110
@@ -106,11 +121,13 @@ pub struct Handler {
106
121
pub enum Event {
107
122
/// We obtained identification information from the remote.
108
123
Identified ( Info ) ,
124
+ /// We replied to an identification request from the remote.
125
+ Identification ( PeerId ) ,
109
126
/// We actively pushed our identification information to the remote.
110
127
IdentificationPushed ,
111
128
/// We received a request for identification.
112
129
Identify ( ReplySubstream < NegotiatedSubstream > ) ,
113
- /// Failed to identify the remote.
130
+ /// Failed to identify the remote, or to reply to an identification request .
114
131
IdentificationError ( ConnectionHandlerUpgrErr < UpgradeError > ) ,
115
132
}
116
133
@@ -129,6 +146,7 @@ impl Handler {
129
146
remote_peer_id,
130
147
inbound_identify_push : Default :: default ( ) ,
131
148
events : SmallVec :: new ( ) ,
149
+ pending_replies : VecDeque :: new ( ) ,
132
150
trigger_next_identify : Delay :: new ( initial_delay) ,
133
151
keep_alive : KeepAlive :: Yes ,
134
152
interval,
@@ -230,8 +248,15 @@ impl ConnectionHandler for Handler {
230
248
) ,
231
249
} ) ;
232
250
}
233
- InEvent :: Identify ( _) => {
234
- todo ! ( )
251
+ InEvent :: Identify ( reply) => {
252
+ if !self . pending_replies . is_empty ( ) {
253
+ warn ! (
254
+ "New inbound identify request from {} while a previous one \
255
+ is still pending. Queueing the new one.",
256
+ reply. peer,
257
+ ) ;
258
+ }
259
+ self . pending_replies . push_back ( Pending :: Queued ( reply) ) ;
235
260
}
236
261
}
237
262
}
@@ -274,6 +299,39 @@ impl ConnectionHandler for Handler {
274
299
}
275
300
}
276
301
302
+ // Check for pending replies to send.
303
+ if let Some ( mut pending) = self . pending_replies . pop_front ( ) {
304
+ loop {
305
+ match pending {
306
+ Pending :: Queued ( Reply { peer, io, info } ) => {
307
+ let io = Box :: pin ( io. send ( info) ) ;
308
+ pending = Pending :: Sending { peer, io } ;
309
+ }
310
+ Pending :: Sending { peer, mut io } => {
311
+ match Future :: poll ( Pin :: new ( & mut io) , cx) {
312
+ Poll :: Pending => {
313
+ self . pending_replies
314
+ . push_front ( Pending :: Sending { peer, io } ) ;
315
+ return Poll :: Pending ;
316
+ }
317
+ Poll :: Ready ( Ok ( ( ) ) ) => {
318
+ return Poll :: Ready ( ConnectionHandlerEvent :: Custom (
319
+ Event :: Identification ( peer) ,
320
+ ) ) ;
321
+ }
322
+ Poll :: Ready ( Err ( err) ) => {
323
+ return Poll :: Ready ( ConnectionHandlerEvent :: Custom (
324
+ Event :: IdentificationError ( ConnectionHandlerUpgrErr :: Upgrade (
325
+ libp2p_core:: upgrade:: UpgradeError :: Apply ( err) ,
326
+ ) ) ,
327
+ ) )
328
+ }
329
+ }
330
+ }
331
+ }
332
+ }
333
+ }
334
+
277
335
Poll :: Pending
278
336
}
279
337
0 commit comments