@@ -36,12 +36,13 @@ use libp2p_swarm::{
36
36
KeepAlive , NegotiatedSubstream , SubstreamProtocol ,
37
37
} ;
38
38
use log:: trace;
39
+ use std:: collections:: VecDeque ;
39
40
use std:: task:: Waker ;
40
41
use std:: {
41
42
error, fmt, io, marker:: PhantomData , pin:: Pin , task:: Context , task:: Poll , time:: Duration ,
42
43
} ;
43
44
44
- const MAX_NUM_INBOUND_SUBSTREAMS : usize = 32 ;
45
+ const MAX_NUM_SUBSTREAMS : usize = 32 ;
45
46
46
47
/// A prototype from which [`KademliaHandler`]s can be constructed.
47
48
pub struct KademliaHandlerProto < T > {
@@ -93,6 +94,14 @@ pub struct KademliaHandler<TUserData> {
93
94
/// List of active outbound substreams with the state they are in.
94
95
outbound_substreams : SelectAll < OutboundSubstreamState < TUserData > > ,
95
96
97
+ /// Number of outbound streams being upgraded right now.
98
+ num_requested_outbound_streams : usize ,
99
+
100
+ /// List of outbound substreams that are waiting to become active next.
101
+ /// Contains the request we want to send, and the user data if we expect an answer.
102
+ requested_streams :
103
+ VecDeque < SubstreamProtocol < KademliaProtocolConfig , ( KadRequestMsg , Option < TUserData > ) > > ,
104
+
96
105
/// List of active inbound substreams with the state they are in.
97
106
inbound_substreams : SelectAll < InboundSubstreamState < TUserData > > ,
98
107
@@ -139,9 +148,6 @@ pub struct KademliaHandlerConfig {
139
148
140
149
/// State of an active outbound substream.
141
150
enum OutboundSubstreamState < TUserData > {
142
- /// We haven't started opening the outgoing substream yet.
143
- /// Contains the request we want to send, and the user data if we expect an answer.
144
- PendingOpen ( SubstreamProtocol < KademliaProtocolConfig , ( KadRequestMsg , Option < TUserData > ) > ) ,
145
151
/// Waiting to send a message to the remote.
146
152
PendingSend (
147
153
KadOutStreamSink < NegotiatedSubstream > ,
@@ -524,6 +530,8 @@ where
524
530
next_connec_unique_id : UniqueConnecId ( 0 ) ,
525
531
inbound_substreams : Default :: default ( ) ,
526
532
outbound_substreams : Default :: default ( ) ,
533
+ num_requested_outbound_streams : 0 ,
534
+ requested_streams : Default :: default ( ) ,
527
535
keep_alive,
528
536
protocol_status : ProtocolStatus :: Unconfirmed ,
529
537
}
@@ -543,6 +551,7 @@ where
543
551
. push ( OutboundSubstreamState :: PendingSend (
544
552
protocol, msg, user_data,
545
553
) ) ;
554
+ self . num_requested_outbound_streams -= 1 ;
546
555
if let ProtocolStatus :: Unconfirmed = self . protocol_status {
547
556
// Upon the first successfully negotiated substream, we know that the
548
557
// remote is configured with the same protocol name and we want
@@ -572,7 +581,7 @@ where
572
581
self . protocol_status = ProtocolStatus :: Confirmed ;
573
582
}
574
583
575
- if self . inbound_substreams . len ( ) == MAX_NUM_INBOUND_SUBSTREAMS {
584
+ if self . inbound_substreams . len ( ) == MAX_NUM_SUBSTREAMS {
576
585
if let Some ( s) = self . inbound_substreams . iter_mut ( ) . find ( |s| {
577
586
matches ! (
578
587
s,
@@ -624,6 +633,7 @@ where
624
633
self . outbound_substreams
625
634
. push ( OutboundSubstreamState :: ReportError ( error. into ( ) , user_data) ) ;
626
635
}
636
+ self . num_requested_outbound_streams -= 1 ;
627
637
}
628
638
}
629
639
@@ -667,23 +677,21 @@ where
667
677
}
668
678
KademliaHandlerIn :: FindNodeReq { key, user_data } => {
669
679
let msg = KadRequestMsg :: FindNode { key } ;
670
- self . outbound_substreams
671
- . push ( OutboundSubstreamState :: PendingOpen ( SubstreamProtocol :: new (
672
- self . config . protocol_config . clone ( ) ,
673
- ( msg, Some ( user_data) ) ,
674
- ) ) ) ;
680
+ self . requested_streams . push_back ( SubstreamProtocol :: new (
681
+ self . config . protocol_config . clone ( ) ,
682
+ ( msg, Some ( user_data) ) ,
683
+ ) ) ;
675
684
}
676
685
KademliaHandlerIn :: FindNodeRes {
677
686
closer_peers,
678
687
request_id,
679
688
} => self . answer_pending_request ( request_id, KadResponseMsg :: FindNode { closer_peers } ) ,
680
689
KademliaHandlerIn :: GetProvidersReq { key, user_data } => {
681
690
let msg = KadRequestMsg :: GetProviders { key } ;
682
- self . outbound_substreams
683
- . push ( OutboundSubstreamState :: PendingOpen ( SubstreamProtocol :: new (
684
- self . config . protocol_config . clone ( ) ,
685
- ( msg, Some ( user_data) ) ,
686
- ) ) ) ;
691
+ self . requested_streams . push_back ( SubstreamProtocol :: new (
692
+ self . config . protocol_config . clone ( ) ,
693
+ ( msg, Some ( user_data) ) ,
694
+ ) ) ;
687
695
}
688
696
KademliaHandlerIn :: GetProvidersRes {
689
697
closer_peers,
@@ -698,27 +706,24 @@ where
698
706
) ,
699
707
KademliaHandlerIn :: AddProvider { key, provider } => {
700
708
let msg = KadRequestMsg :: AddProvider { key, provider } ;
701
- self . outbound_substreams
702
- . push ( OutboundSubstreamState :: PendingOpen ( SubstreamProtocol :: new (
703
- self . config . protocol_config . clone ( ) ,
704
- ( msg, None ) ,
705
- ) ) ) ;
709
+ self . requested_streams . push_back ( SubstreamProtocol :: new (
710
+ self . config . protocol_config . clone ( ) ,
711
+ ( msg, None ) ,
712
+ ) ) ;
706
713
}
707
714
KademliaHandlerIn :: GetRecord { key, user_data } => {
708
715
let msg = KadRequestMsg :: GetValue { key } ;
709
- self . outbound_substreams
710
- . push ( OutboundSubstreamState :: PendingOpen ( SubstreamProtocol :: new (
711
- self . config . protocol_config . clone ( ) ,
712
- ( msg, Some ( user_data) ) ,
713
- ) ) ) ;
716
+ self . requested_streams . push_back ( SubstreamProtocol :: new (
717
+ self . config . protocol_config . clone ( ) ,
718
+ ( msg, Some ( user_data) ) ,
719
+ ) ) ;
714
720
}
715
721
KademliaHandlerIn :: PutRecord { record, user_data } => {
716
722
let msg = KadRequestMsg :: PutValue { record } ;
717
- self . outbound_substreams
718
- . push ( OutboundSubstreamState :: PendingOpen ( SubstreamProtocol :: new (
719
- self . config . protocol_config . clone ( ) ,
720
- ( msg, Some ( user_data) ) ,
721
- ) ) ) ;
723
+ self . requested_streams . push_back ( SubstreamProtocol :: new (
724
+ self . config . protocol_config . clone ( ) ,
725
+ ( msg, Some ( user_data) ) ,
726
+ ) ) ;
722
727
}
723
728
KademliaHandlerIn :: GetRecordRes {
724
729
record,
@@ -775,6 +780,15 @@ where
775
780
return Poll :: Ready ( event) ;
776
781
}
777
782
783
+ let num_in_progress_outbound_substreams =
784
+ self . outbound_substreams . len ( ) + self . num_requested_outbound_streams ;
785
+ if num_in_progress_outbound_substreams < MAX_NUM_SUBSTREAMS {
786
+ if let Some ( protocol) = self . requested_streams . pop_front ( ) {
787
+ self . num_requested_outbound_streams += 1 ;
788
+ return Poll :: Ready ( ConnectionHandlerEvent :: OutboundSubstreamRequest { protocol } ) ;
789
+ }
790
+ }
791
+
778
792
if self . outbound_substreams . is_empty ( ) && self . inbound_substreams . is_empty ( ) {
779
793
// We destroyed all substreams in this function.
780
794
self . keep_alive = KeepAlive :: Until ( Instant :: now ( ) + self . config . idle_timeout ) ;
@@ -853,12 +867,6 @@ where
853
867
854
868
loop {
855
869
match std:: mem:: replace ( this, OutboundSubstreamState :: Poisoned ) {
856
- OutboundSubstreamState :: PendingOpen ( protocol) => {
857
- * this = OutboundSubstreamState :: Done ;
858
- return Poll :: Ready ( Some ( ConnectionHandlerEvent :: OutboundSubstreamRequest {
859
- protocol,
860
- } ) ) ;
861
- }
862
870
OutboundSubstreamState :: PendingSend ( mut substream, msg, user_data) => {
863
871
match substream. poll_ready_unpin ( cx) {
864
872
Poll :: Ready ( Ok ( ( ) ) ) => match substream. start_send_unpin ( msg) {
0 commit comments