@@ -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
@@ -130,6 +147,7 @@ impl Handler {
130
147
remote_peer_id,
131
148
inbound_identify_push : Default :: default ( ) ,
132
149
events : SmallVec :: new ( ) ,
150
+ pending_replies : VecDeque :: new ( ) ,
133
151
trigger_next_identify : Delay :: new ( initial_delay) ,
134
152
keep_alive : KeepAlive :: Yes ,
135
153
interval,
@@ -231,8 +249,15 @@ impl ConnectionHandler for Handler {
231
249
) ,
232
250
} ) ;
233
251
}
234
- InEvent :: Identify ( _) => {
235
- todo ! ( )
252
+ InEvent :: Identify ( reply) => {
253
+ if !self . pending_replies . is_empty ( ) {
254
+ warn ! (
255
+ "New inbound identify request from {} while a previous one \
256
+ is still pending. Queueing the new one.",
257
+ reply. peer,
258
+ ) ;
259
+ }
260
+ self . pending_replies . push_back ( Pending :: Queued ( reply) ) ;
236
261
}
237
262
}
238
263
}
@@ -275,6 +300,39 @@ impl ConnectionHandler for Handler {
275
300
}
276
301
}
277
302
303
+ // Check for pending replies to send.
304
+ if let Some ( mut pending) = self . pending_replies . pop_front ( ) {
305
+ loop {
306
+ match pending {
307
+ Pending :: Queued ( Reply { peer, io, info } ) => {
308
+ let io = Box :: pin ( io. send ( info) ) ;
309
+ pending = Pending :: Sending { peer, io } ;
310
+ }
311
+ Pending :: Sending { peer, mut io } => {
312
+ match Future :: poll ( Pin :: new ( & mut io) , cx) {
313
+ Poll :: Pending => {
314
+ self . pending_replies
315
+ . push_front ( Pending :: Sending { peer, io } ) ;
316
+ return Poll :: Pending ;
317
+ }
318
+ Poll :: Ready ( Ok ( ( ) ) ) => {
319
+ return Poll :: Ready ( ConnectionHandlerEvent :: Custom (
320
+ Event :: Identification ( peer) ,
321
+ ) ) ;
322
+ }
323
+ Poll :: Ready ( Err ( err) ) => {
324
+ return Poll :: Ready ( ConnectionHandlerEvent :: Custom (
325
+ Event :: IdentificationError ( ConnectionHandlerUpgrErr :: Upgrade (
326
+ libp2p_core:: upgrade:: UpgradeError :: Apply ( err) ,
327
+ ) ) ,
328
+ ) )
329
+ }
330
+ }
331
+ }
332
+ }
333
+ }
334
+ }
335
+
278
336
Poll :: Pending
279
337
}
280
338
0 commit comments