@@ -18,12 +18,44 @@ use crate::logger::{log_debug, log_error, log_info, LdkLogger};
1818use crate :: types:: { KeysManager , PeerManager } ;
1919use crate :: Error ;
2020
21+ type PendingConnections =
22+ Mutex < HashMap < PublicKey , Vec < tokio:: sync:: oneshot:: Sender < Result < ( ) , Error > > > > > ;
23+
24+ struct PendingConnectionGuard < ' a > {
25+ pending_connections : & ' a PendingConnections ,
26+ node_id : PublicKey ,
27+ active : bool ,
28+ }
29+
30+ impl < ' a > PendingConnectionGuard < ' a > {
31+ fn new ( pending_connections : & ' a PendingConnections , node_id : PublicKey ) -> Self {
32+ Self { pending_connections, node_id, active : true }
33+ }
34+
35+ fn disarm ( & mut self ) {
36+ self . active = false ;
37+ }
38+ }
39+
40+ impl Drop for PendingConnectionGuard < ' _ > {
41+ fn drop ( & mut self ) {
42+ if !self . active {
43+ return ;
44+ }
45+ let mut pending_connections = self . pending_connections . lock ( ) . expect ( "lock" ) ;
46+ if let Some ( subscribers) = pending_connections. remove ( & self . node_id ) {
47+ for subscriber in subscribers {
48+ let _ = subscriber. send ( Err ( Error :: ConnectionFailed ) ) ;
49+ }
50+ }
51+ }
52+ }
53+
2154pub ( crate ) struct ConnectionManager < L : Deref + Clone + Sync + Send >
2255where
2356 L :: Target : LdkLogger ,
2457{
25- pending_connections :
26- Mutex < HashMap < PublicKey , Vec < tokio:: sync:: oneshot:: Sender < Result < ( ) , Error > > > > > ,
58+ pending_connections : PendingConnections ,
2759 peer_manager : Arc < PeerManager > ,
2860 tor_proxy_config : Option < TorConfig > ,
2961 keys_manager : Arc < KeysManager > ,
@@ -60,26 +92,29 @@ where
6092 pub ( crate ) async fn do_connect_peer (
6193 & self , node_id : PublicKey , addr : SocketAddress ,
6294 ) -> Result < ( ) , Error > {
95+ // If another task is already connecting, subscribe to its result instead of starting a
96+ // duplicate attempt.
97+ if let Some ( pending_connection_ready_receiver) =
98+ self . register_or_subscribe_pending_connection ( & node_id)
99+ {
100+ return pending_connection_ready_receiver. await . map_err ( |e| {
101+ debug_assert ! ( false , "Failed to receive connection result: {:?}" , e) ;
102+ log_error ! ( self . logger, "Failed to receive connection result: {:?}" , e) ;
103+ Error :: ConnectionFailed
104+ } ) ?;
105+ }
106+
107+ let mut pending_connection =
108+ PendingConnectionGuard :: new ( & self . pending_connections , node_id) ;
63109 let res = self . do_connect_peer_internal ( node_id, addr) . await ;
64110 self . propagate_result_to_subscribers ( & node_id, res) ;
111+ pending_connection. disarm ( ) ;
65112 res
66113 }
67114
68115 async fn do_connect_peer_internal (
69116 & self , node_id : PublicKey , addr : SocketAddress ,
70117 ) -> Result < ( ) , Error > {
71- // First, we check if there is already an outbound connection in flight, if so, we just
72- // await on the corresponding watch channel. The task driving the connection future will
73- // send us the result..
74- let pending_ready_receiver_opt = self . register_or_subscribe_pending_connection ( & node_id) ;
75- if let Some ( pending_connection_ready_receiver) = pending_ready_receiver_opt {
76- return pending_connection_ready_receiver. await . map_err ( |e| {
77- debug_assert ! ( false , "Failed to receive connection result: {:?}" , e) ;
78- log_error ! ( self . logger, "Failed to receive connection result: {:?}" , e) ;
79- Error :: ConnectionFailed
80- } ) ?;
81- }
82-
83118 log_info ! ( self . logger, "Connecting to peer: {}@{}" , node_id, addr) ;
84119
85120 match addr {
@@ -246,6 +281,7 @@ where
246281 match pending_connections_lock. entry ( * node_id) {
247282 hash_map:: Entry :: Occupied ( mut entry) => {
248283 let ( tx, rx) = tokio:: sync:: oneshot:: channel ( ) ;
284+ entry. get_mut ( ) . retain ( |subscriber| !subscriber. is_closed ( ) ) ;
249285 entry. get_mut ( ) . push ( tx) ;
250286 Some ( rx)
251287 } ,
@@ -277,3 +313,26 @@ where
277313 }
278314 }
279315}
316+
317+ #[ cfg( test) ]
318+ mod tests {
319+ use super :: * ;
320+
321+ #[ test]
322+ fn pending_connection_guard_notifies_subscribers_when_abandoned ( ) {
323+ let node_id: PublicKey =
324+ "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798" . parse ( ) . unwrap ( ) ;
325+ let pending_connections = Mutex :: new ( HashMap :: new ( ) ) ;
326+ let ( sender, mut receiver) = tokio:: sync:: oneshot:: channel ( ) ;
327+ pending_connections. lock ( ) . expect ( "lock" ) . insert ( node_id, vec ! [ sender] ) ;
328+
329+ let connection_guard = PendingConnectionGuard :: new ( & pending_connections, node_id) ;
330+ drop ( connection_guard) ;
331+
332+ assert ! (
333+ pending_connections. lock( ) . expect( "lock" ) . is_empty( ) ,
334+ "abandoned connection attempt should remove pending state"
335+ ) ;
336+ assert_eq ! ( receiver. try_recv( ) , Ok ( Err ( Error :: ConnectionFailed ) ) ) ;
337+ }
338+ }
0 commit comments