@@ -6,64 +6,142 @@ use lightning::ln::msgs::SocketAddress;
6
6
7
7
use bitcoin:: secp256k1:: PublicKey ;
8
8
9
+ use std:: collections:: hash_map:: { self , HashMap } ;
9
10
use std:: net:: ToSocketAddrs ;
10
11
use std:: ops:: Deref ;
11
- use std:: sync:: Arc ;
12
+ use std:: sync:: { Arc , Mutex } ;
12
13
use std:: time:: Duration ;
13
14
14
- pub ( crate ) async fn connect_peer_if_necessary < L : Deref + Clone + Sync + Send > (
15
- node_id : PublicKey , addr : SocketAddress , peer_manager : Arc < PeerManager > , logger : L ,
16
- ) -> Result < ( ) , Error >
15
+ pub ( crate ) struct ConnectionManager < L : Deref + Clone + Sync + Send >
17
16
where
18
17
L :: Target : Logger ,
19
18
{
20
- if peer_manager. peer_by_node_id ( & node_id) . is_some ( ) {
21
- return Ok ( ( ) ) ;
22
- }
23
-
24
- do_connect_peer ( node_id, addr, peer_manager, logger) . await
19
+ pending_connections :
20
+ Mutex < HashMap < PublicKey , Vec < tokio:: sync:: oneshot:: Sender < Result < ( ) , Error > > > > > ,
21
+ peer_manager : Arc < PeerManager > ,
22
+ logger : L ,
25
23
}
26
24
27
- pub ( crate ) async fn do_connect_peer < L : Deref + Clone + Sync + Send > (
28
- node_id : PublicKey , addr : SocketAddress , peer_manager : Arc < PeerManager > , logger : L ,
29
- ) -> Result < ( ) , Error >
25
+ impl < L : Deref + Clone + Sync + Send > ConnectionManager < L >
30
26
where
31
27
L :: Target : Logger ,
32
28
{
33
- log_info ! ( logger, "Connecting to peer: {}@{}" , node_id, addr) ;
34
-
35
- let socket_addr = addr
36
- . to_socket_addrs ( )
37
- . map_err ( |e| {
38
- log_error ! ( logger, "Failed to resolve network address: {}" , e) ;
39
- Error :: InvalidSocketAddress
40
- } ) ?
41
- . next ( )
42
- . ok_or ( Error :: ConnectionFailed ) ?;
43
-
44
- match lightning_net_tokio:: connect_outbound ( Arc :: clone ( & peer_manager) , node_id, socket_addr)
45
- . await
46
- {
47
- Some ( connection_closed_future) => {
48
- let mut connection_closed_future = Box :: pin ( connection_closed_future) ;
49
- loop {
50
- tokio:: select! {
51
- _ = & mut connection_closed_future => {
52
- log_info!( logger, "Peer connection closed: {}@{}" , node_id, addr) ;
53
- return Err ( Error :: ConnectionFailed ) ;
54
- } ,
55
- _ = tokio:: time:: sleep( Duration :: from_millis( 10 ) ) => { } ,
56
- } ;
57
-
58
- match peer_manager. peer_by_node_id ( & node_id) {
59
- Some ( _) => return Ok ( ( ) ) ,
60
- None => continue ,
29
+ pub ( crate ) fn new ( peer_manager : Arc < PeerManager > , logger : L ) -> Self {
30
+ let pending_connections = Mutex :: new ( HashMap :: new ( ) ) ;
31
+ Self { pending_connections, peer_manager, logger }
32
+ }
33
+
34
+ pub ( crate ) async fn connect_peer_if_necessary (
35
+ & self , node_id : PublicKey , addr : SocketAddress ,
36
+ ) -> Result < ( ) , Error > {
37
+ if self . peer_manager . peer_by_node_id ( & node_id) . is_some ( ) {
38
+ return Ok ( ( ) ) ;
39
+ }
40
+
41
+ self . do_connect_peer ( node_id, addr) . await
42
+ }
43
+
44
+ pub ( crate ) async fn do_connect_peer (
45
+ & self , node_id : PublicKey , addr : SocketAddress ,
46
+ ) -> Result < ( ) , Error > {
47
+ // First, we check if there is already an outbound connection in flight, if so, we just
48
+ // await on the corresponding watch channel. The task driving the connection future will
49
+ // send us the result..
50
+ let pending_ready_receiver_opt = self . register_or_subscribe_pending_connection ( & node_id) ;
51
+ if let Some ( pending_connection_ready_receiver) = pending_ready_receiver_opt {
52
+ return pending_connection_ready_receiver. await . map_err ( |e| {
53
+ debug_assert ! ( false , "Failed to receive connection result: {:?}" , e) ;
54
+ log_error ! ( self . logger, "Failed to receive connection result: {:?}" , e) ;
55
+ Error :: ConnectionFailed
56
+ } ) ?;
57
+ }
58
+
59
+ log_info ! ( self . logger, "Connecting to peer: {}@{}" , node_id, addr) ;
60
+
61
+ let socket_addr = addr
62
+ . to_socket_addrs ( )
63
+ . map_err ( |e| {
64
+ log_error ! ( self . logger, "Failed to resolve network address {}: {}" , addr, e) ;
65
+ self . propagate_result_to_subscribers ( & node_id, Err ( Error :: InvalidSocketAddress ) ) ;
66
+ Error :: InvalidSocketAddress
67
+ } ) ?
68
+ . next ( )
69
+ . ok_or_else ( || {
70
+ log_error ! ( self . logger, "Failed to resolve network address {}" , addr) ;
71
+ self . propagate_result_to_subscribers ( & node_id, Err ( Error :: InvalidSocketAddress ) ) ;
72
+ Error :: InvalidSocketAddress
73
+ } ) ?;
74
+
75
+ let connection_future = lightning_net_tokio:: connect_outbound (
76
+ Arc :: clone ( & self . peer_manager ) ,
77
+ node_id,
78
+ socket_addr,
79
+ ) ;
80
+
81
+ let res = match connection_future. await {
82
+ Some ( connection_closed_future) => {
83
+ let mut connection_closed_future = Box :: pin ( connection_closed_future) ;
84
+ loop {
85
+ tokio:: select! {
86
+ _ = & mut connection_closed_future => {
87
+ log_info!( self . logger, "Peer connection closed: {}@{}" , node_id, addr) ;
88
+ break Err ( Error :: ConnectionFailed ) ;
89
+ } ,
90
+ _ = tokio:: time:: sleep( Duration :: from_millis( 10 ) ) => { } ,
91
+ } ;
92
+
93
+ match self . peer_manager . peer_by_node_id ( & node_id) {
94
+ Some ( _) => break Ok ( ( ) ) ,
95
+ None => continue ,
96
+ }
61
97
}
98
+ } ,
99
+ None => {
100
+ log_error ! ( self . logger, "Failed to connect to peer: {}@{}" , node_id, addr) ;
101
+ Err ( Error :: ConnectionFailed )
102
+ } ,
103
+ } ;
104
+
105
+ self . propagate_result_to_subscribers ( & node_id, res) ;
106
+
107
+ res
108
+ }
109
+
110
+ fn register_or_subscribe_pending_connection (
111
+ & self , node_id : & PublicKey ,
112
+ ) -> Option < tokio:: sync:: oneshot:: Receiver < Result < ( ) , Error > > > {
113
+ let mut pending_connections_lock = self . pending_connections . lock ( ) . unwrap ( ) ;
114
+ match pending_connections_lock. entry ( * node_id) {
115
+ hash_map:: Entry :: Occupied ( mut entry) => {
116
+ let ( tx, rx) = tokio:: sync:: oneshot:: channel ( ) ;
117
+ entry. get_mut ( ) . push ( tx) ;
118
+ Some ( rx)
119
+ } ,
120
+ hash_map:: Entry :: Vacant ( entry) => {
121
+ entry. insert ( Vec :: new ( ) ) ;
122
+ None
123
+ } ,
124
+ }
125
+ }
126
+
127
+ fn propagate_result_to_subscribers ( & self , node_id : & PublicKey , res : Result < ( ) , Error > ) {
128
+ // Send the result to any other tasks that might be waiting on it by now.
129
+ let mut pending_connections_lock = self . pending_connections . lock ( ) . unwrap ( ) ;
130
+ if let Some ( connection_ready_senders) = pending_connections_lock. remove ( node_id) {
131
+ for sender in connection_ready_senders {
132
+ let _ = sender. send ( res) . map_err ( |e| {
133
+ debug_assert ! (
134
+ false ,
135
+ "Failed to send connection result to subscribers: {:?}" ,
136
+ e
137
+ ) ;
138
+ log_error ! (
139
+ self . logger,
140
+ "Failed to send connection result to subscribers: {:?}" ,
141
+ e
142
+ ) ;
143
+ } ) ;
62
144
}
63
- } ,
64
- None => {
65
- log_error ! ( logger, "Failed to connect to peer: {}@{}" , node_id, addr) ;
66
- Err ( Error :: ConnectionFailed )
67
- } ,
145
+ }
68
146
}
69
147
}
0 commit comments