23
23
mod test;
24
24
25
25
use crate :: addresses:: Addresses ;
26
- use crate :: handler:: {
27
- KademliaHandler , KademliaHandlerConfig , KademliaHandlerEvent , KademliaHandlerIn ,
28
- KademliaRequestId ,
29
- } ;
26
+ use crate :: handler:: { KademliaHandler , KademliaHandlerEvent , KademliaHandlerIn , KademliaRequestId } ;
30
27
use crate :: jobs:: * ;
31
28
use crate :: kbucket:: { self , Distance , KBucketsTable , NodeStatus } ;
32
29
use crate :: protocol:: { KadConnectionType , KadPeer , KademliaProtocolConfig } ;
@@ -52,7 +49,7 @@ use libp2p_swarm::{
52
49
} ;
53
50
use log:: { debug, info, warn} ;
54
51
use smallvec:: SmallVec ;
55
- use std:: collections:: { BTreeMap , HashSet , VecDeque } ;
52
+ use std:: collections:: { BTreeMap , HashMap , HashSet , VecDeque } ;
56
53
use std:: fmt;
57
54
use std:: num:: NonZeroUsize ;
58
55
use std:: task:: { Context , Poll } ;
@@ -109,11 +106,15 @@ pub struct Kademlia<TStore> {
109
106
110
107
external_addresses : ExternalAddresses ,
111
108
109
+ connections : HashMap < ConnectionId , PeerId > ,
110
+
112
111
/// See [`KademliaConfig::caching`].
113
112
caching : KademliaCaching ,
114
113
115
114
local_peer_id : PeerId ,
116
115
116
+ mode : Mode ,
117
+
117
118
/// The record storage.
118
119
store : TStore ,
119
120
}
@@ -453,6 +454,8 @@ where
453
454
connection_idle_timeout : config. connection_idle_timeout ,
454
455
external_addresses : Default :: default ( ) ,
455
456
local_peer_id : id,
457
+ connections : Default :: default ( ) ,
458
+ mode : Mode :: Client ,
456
459
}
457
460
}
458
461
@@ -1937,9 +1940,12 @@ where
1937
1940
ConnectionClosed {
1938
1941
peer_id,
1939
1942
remaining_established,
1943
+ connection_id,
1940
1944
..
1941
1945
} : ConnectionClosed < <Self as NetworkBehaviour >:: ConnectionHandler > ,
1942
1946
) {
1947
+ self . connections . remove ( & connection_id) ;
1948
+
1943
1949
if remaining_established == 0 {
1944
1950
for query in self . queries . iter_mut ( ) {
1945
1951
query. on_failure ( & peer_id) ;
@@ -1964,43 +1970,45 @@ where
1964
1970
1965
1971
fn handle_established_inbound_connection (
1966
1972
& mut self ,
1967
- _connection_id : ConnectionId ,
1973
+ connection_id : ConnectionId ,
1968
1974
peer : PeerId ,
1969
1975
local_addr : & Multiaddr ,
1970
1976
remote_addr : & Multiaddr ,
1971
1977
) -> Result < THandler < Self > , ConnectionDenied > {
1978
+ let connected_point = ConnectedPoint :: Listener {
1979
+ local_addr : local_addr. clone ( ) ,
1980
+ send_back_addr : remote_addr. clone ( ) ,
1981
+ } ;
1982
+ self . connections . insert ( connection_id, peer) ;
1983
+
1972
1984
Ok ( KademliaHandler :: new (
1973
- KademliaHandlerConfig {
1974
- protocol_config : self . protocol_config . clone ( ) ,
1975
- allow_listening : true ,
1976
- idle_timeout : self . connection_idle_timeout ,
1977
- } ,
1978
- ConnectedPoint :: Listener {
1979
- local_addr : local_addr. clone ( ) ,
1980
- send_back_addr : remote_addr. clone ( ) ,
1981
- } ,
1985
+ self . protocol_config . clone ( ) ,
1986
+ self . connection_idle_timeout ,
1987
+ connected_point,
1982
1988
peer,
1989
+ self . mode ,
1983
1990
) )
1984
1991
}
1985
1992
1986
1993
fn handle_established_outbound_connection (
1987
1994
& mut self ,
1988
- _connection_id : ConnectionId ,
1995
+ connection_id : ConnectionId ,
1989
1996
peer : PeerId ,
1990
1997
addr : & Multiaddr ,
1991
1998
role_override : Endpoint ,
1992
1999
) -> Result < THandler < Self > , ConnectionDenied > {
2000
+ let connected_point = ConnectedPoint :: Dialer {
2001
+ address : addr. clone ( ) ,
2002
+ role_override,
2003
+ } ;
2004
+ self . connections . insert ( connection_id, peer) ;
2005
+
1993
2006
Ok ( KademliaHandler :: new (
1994
- KademliaHandlerConfig {
1995
- protocol_config : self . protocol_config . clone ( ) ,
1996
- allow_listening : true ,
1997
- idle_timeout : self . connection_idle_timeout ,
1998
- } ,
1999
- ConnectedPoint :: Dialer {
2000
- address : addr. clone ( ) ,
2001
- role_override,
2002
- } ,
2007
+ self . protocol_config . clone ( ) ,
2008
+ self . connection_idle_timeout ,
2009
+ connected_point,
2003
2010
peer,
2011
+ self . mode ,
2004
2012
) )
2005
2013
}
2006
2014
@@ -2055,9 +2063,18 @@ where
2055
2063
ConnectedPoint :: Dialer { address, .. } => Some ( address) ,
2056
2064
ConnectedPoint :: Listener { .. } => None ,
2057
2065
} ;
2066
+
2058
2067
self . connection_updated ( source, address, NodeStatus :: Connected ) ;
2059
2068
}
2060
2069
2070
+ KademliaHandlerEvent :: ProtocolNotSupported { endpoint } => {
2071
+ let address = match endpoint {
2072
+ ConnectedPoint :: Dialer { address, .. } => Some ( address) ,
2073
+ ConnectedPoint :: Listener { .. } => None ,
2074
+ } ;
2075
+ self . connection_updated ( source, address, NodeStatus :: Disconnected ) ;
2076
+ }
2077
+
2061
2078
KademliaHandlerEvent :: FindNodeReq { key, request_id } => {
2062
2079
let closer_peers = self . find_closest ( & kbucket:: Key :: new ( key) , & source) ;
2063
2080
@@ -2419,7 +2436,63 @@ where
2419
2436
2420
2437
fn on_swarm_event ( & mut self , event : FromSwarm < Self :: ConnectionHandler > ) {
2421
2438
self . listen_addresses . on_swarm_event ( & event) ;
2422
- self . external_addresses . on_swarm_event ( & event) ;
2439
+ let external_addresses_changed = self . external_addresses . on_swarm_event ( & event) ;
2440
+
2441
+ self . mode = match ( self . external_addresses . as_slice ( ) , self . mode ) {
2442
+ ( [ ] , Mode :: Server ) => {
2443
+ log:: debug!( "Switching to client-mode because we no longer have any confirmed external addresses" ) ;
2444
+
2445
+ Mode :: Client
2446
+ }
2447
+ ( [ ] , Mode :: Client ) => {
2448
+ // Previously client-mode, now also client-mode because no external addresses.
2449
+
2450
+ Mode :: Client
2451
+ }
2452
+ ( confirmed_external_addresses, Mode :: Client ) => {
2453
+ if log:: log_enabled!( log:: Level :: Debug ) {
2454
+ let confirmed_external_addresses =
2455
+ to_comma_separated_list ( confirmed_external_addresses) ;
2456
+
2457
+ log:: debug!( "Switching to server-mode assuming that one of [{confirmed_external_addresses}] is externally reachable" ) ;
2458
+ }
2459
+
2460
+ Mode :: Server
2461
+ }
2462
+ ( confirmed_external_addresses, Mode :: Server ) => {
2463
+ debug_assert ! (
2464
+ !confirmed_external_addresses. is_empty( ) ,
2465
+ "Previous match arm handled empty list"
2466
+ ) ;
2467
+
2468
+ // Previously, server-mode, now also server-mode because > 1 external address. Don't log anything to avoid spam.
2469
+
2470
+ Mode :: Server
2471
+ }
2472
+ } ;
2473
+
2474
+ if external_addresses_changed && !self . connections . is_empty ( ) {
2475
+ let num_connections = self . connections . len ( ) ;
2476
+
2477
+ log:: debug!(
2478
+ "External addresses changed, re-configuring {} established connection{}" ,
2479
+ num_connections,
2480
+ if num_connections > 1 { "s" } else { "" }
2481
+ ) ;
2482
+
2483
+ self . queued_events
2484
+ . extend (
2485
+ self . connections
2486
+ . iter ( )
2487
+ . map ( |( conn_id, peer_id) | ToSwarm :: NotifyHandler {
2488
+ peer_id : * peer_id,
2489
+ handler : NotifyHandler :: One ( * conn_id) ,
2490
+ event : KademliaHandlerIn :: ReconfigureMode {
2491
+ new_mode : self . mode ,
2492
+ } ,
2493
+ } ) ,
2494
+ ) ;
2495
+ }
2423
2496
2424
2497
match event {
2425
2498
FromSwarm :: ConnectionEstablished ( connection_established) => {
@@ -3187,3 +3260,29 @@ pub enum RoutingUpdate {
3187
3260
/// peer ID).
3188
3261
Failed ,
3189
3262
}
3263
+
3264
+ #[ derive( PartialEq , Copy , Clone , Debug ) ]
3265
+ pub enum Mode {
3266
+ Client ,
3267
+ Server ,
3268
+ }
3269
+
3270
+ impl fmt:: Display for Mode {
3271
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
3272
+ match self {
3273
+ Mode :: Client => write ! ( f, "client" ) ,
3274
+ Mode :: Server => write ! ( f, "server" ) ,
3275
+ }
3276
+ }
3277
+ }
3278
+
3279
+ fn to_comma_separated_list < T > ( confirmed_external_addresses : & [ T ] ) -> String
3280
+ where
3281
+ T : ToString ,
3282
+ {
3283
+ confirmed_external_addresses
3284
+ . iter ( )
3285
+ . map ( |addr| addr. to_string ( ) )
3286
+ . collect :: < Vec < _ > > ( )
3287
+ . join ( ", " )
3288
+ }
0 commit comments