Skip to content

Commit 105f835

Browse files
committed
Replace to_socket_addrs() with tokio::net::lookup_host
Replace the synchronous, blocking `std::net::ToSocketAddrs::to_socket_addrs()` calls with async `tokio::net::lookup_host` to avoid blocking the tokio runtime during DNS resolution. Additionally, instead of only using the first resolved address, we now iterate over all resolved addresses and try connecting to each in sequence until one succeeds. This improves connectivity for hostnames that resolve to multiple addresses (e.g., dual-stack IPv4/IPv6). Co-Authored-By: HAL 9000
1 parent c442e8e commit 105f835

File tree

3 files changed

+112
-63
lines changed

3 files changed

+112
-63
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ bip21 = { version = "0.5", features = ["std"], default-features = false }
6666
base64 = { version = "0.22.1", default-features = false, features = ["std"] }
6767
getrandom = { version = "0.3", default-features = false }
6868
chrono = { version = "0.4", default-features = false, features = ["clock"] }
69-
tokio = { version = "1.37", default-features = false, features = [ "rt-multi-thread", "time", "sync", "macros" ] }
69+
tokio = { version = "1.37", default-features = false, features = [ "rt-multi-thread", "time", "sync", "macros", "net" ] }
7070
esplora-client = { version = "0.12", default-features = false, features = ["tokio", "async-https-rustls"] }
7171
electrum-client = { version = "0.24.0", default-features = false, features = ["proxy", "use-rustls-ring"] }
7272
libc = "0.2"

src/connection.rs

Lines changed: 93 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
// accordance with one or both of these licenses.
77

88
use std::collections::hash_map::{self, HashMap};
9-
use std::net::ToSocketAddrs;
109
use std::ops::Deref;
1110
use std::sync::{Arc, Mutex};
1211
use std::time::Duration;
@@ -15,7 +14,7 @@ use bitcoin::secp256k1::PublicKey;
1514
use lightning::ln::msgs::SocketAddress;
1615

1716
use crate::config::TorConfig;
18-
use crate::logger::{log_error, log_info, LdkLogger};
17+
use crate::logger::{log_debug, log_error, log_info, LdkLogger};
1918
use crate::types::{KeysManager, PeerManager};
2019
use crate::Error;
2120

@@ -97,39 +96,64 @@ where
9796
);
9897
Error::InvalidSocketAddress
9998
})?;
100-
let proxy_addr = proxy_config
101-
.proxy_address
102-
.to_socket_addrs()
103-
.map_err(|e| {
104-
log_error!(
105-
self.logger,
106-
"Failed to resolve Tor proxy network address {}: {}",
107-
proxy_config.proxy_address,
108-
e
109-
);
110-
Error::InvalidSocketAddress
111-
})?
112-
.next()
113-
.ok_or_else(|| {
114-
log_error!(
115-
self.logger,
116-
"Failed to resolve Tor proxy network address {}",
117-
proxy_config.proxy_address
118-
);
119-
Error::InvalidSocketAddress
120-
})?;
121-
let connection_future = lightning_net_tokio::tor_connect_outbound(
122-
Arc::clone(&self.peer_manager),
123-
node_id,
124-
addr.clone(),
125-
proxy_addr,
126-
Arc::clone(&self.keys_manager),
127-
);
128-
self.await_connection(connection_future, node_id, addr).await
99+
let resolved_addrs: Vec<_> =
100+
tokio::net::lookup_host(proxy_config.proxy_address.to_string())
101+
.await
102+
.map_err(|e| {
103+
log_error!(
104+
self.logger,
105+
"Failed to resolve Tor proxy network address {}: {}",
106+
proxy_config.proxy_address,
107+
e
108+
);
109+
Error::InvalidSocketAddress
110+
})?
111+
.collect();
112+
113+
if resolved_addrs.is_empty() {
114+
log_error!(
115+
self.logger,
116+
"Failed to resolve Tor proxy network address {}",
117+
proxy_config.proxy_address
118+
);
119+
return Err(Error::InvalidSocketAddress);
120+
}
121+
122+
let mut res = Err(Error::ConnectionFailed);
123+
let mut had_failures = false;
124+
for proxy_addr in resolved_addrs {
125+
let connection_future = lightning_net_tokio::tor_connect_outbound(
126+
Arc::clone(&self.peer_manager),
127+
node_id,
128+
addr.clone(),
129+
proxy_addr,
130+
Arc::clone(&self.keys_manager),
131+
);
132+
res = self.await_connection(connection_future, node_id, addr.clone()).await;
133+
if res.is_ok() {
134+
if had_failures {
135+
log_info!(
136+
self.logger,
137+
"Successfully connected to peer {}@{} via resolved proxy address {} after previous attempts failed.",
138+
node_id, addr, proxy_addr
139+
);
140+
}
141+
break;
142+
}
143+
had_failures = true;
144+
log_debug!(
145+
self.logger,
146+
"Failed to connect to peer {}@{} via resolved proxy address {}.",
147+
node_id,
148+
addr,
149+
proxy_addr
150+
);
151+
}
152+
res
129153
},
130154
_ => {
131-
let socket_addr = addr
132-
.to_socket_addrs()
155+
let resolved_addrs: Vec<_> = tokio::net::lookup_host(addr.to_string())
156+
.await
133157
.map_err(|e| {
134158
log_error!(
135159
self.logger,
@@ -139,17 +163,42 @@ where
139163
);
140164
Error::InvalidSocketAddress
141165
})?
142-
.next()
143-
.ok_or_else(|| {
144-
log_error!(self.logger, "Failed to resolve network address {}", addr);
145-
Error::InvalidSocketAddress
146-
})?;
147-
let connection_future = lightning_net_tokio::connect_outbound(
148-
Arc::clone(&self.peer_manager),
149-
node_id,
150-
socket_addr,
151-
);
152-
self.await_connection(connection_future, node_id, addr).await
166+
.collect();
167+
168+
if resolved_addrs.is_empty() {
169+
log_error!(self.logger, "Failed to resolve network address {}", addr);
170+
return Err(Error::InvalidSocketAddress);
171+
}
172+
173+
let mut res = Err(Error::ConnectionFailed);
174+
let mut had_failures = false;
175+
for socket_addr in resolved_addrs {
176+
let connection_future = lightning_net_tokio::connect_outbound(
177+
Arc::clone(&self.peer_manager),
178+
node_id,
179+
socket_addr,
180+
);
181+
res = self.await_connection(connection_future, node_id, addr.clone()).await;
182+
if res.is_ok() {
183+
if had_failures {
184+
log_info!(
185+
self.logger,
186+
"Successfully connected to peer {}@{} via resolved address {} after previous attempts failed.",
187+
node_id, addr, socket_addr
188+
);
189+
}
190+
break;
191+
}
192+
had_failures = true;
193+
log_debug!(
194+
self.logger,
195+
"Failed to connect to peer {}@{} via resolved address {}.",
196+
node_id,
197+
addr,
198+
socket_addr
199+
);
200+
}
201+
res
153202
},
154203
}
155204
}

src/lib.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ mod types;
108108
mod wallet;
109109

110110
use std::default::Default;
111-
use std::net::ToSocketAddrs;
112111
use std::sync::{Arc, Mutex, RwLock};
113112
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
114113
#[cfg(cycle_tests)]
@@ -361,28 +360,29 @@ impl Node {
361360
let peer_manager_connection_handler = Arc::clone(&self.peer_manager);
362361
let listening_logger = Arc::clone(&self.logger);
363362

364-
let mut bind_addrs = Vec::with_capacity(listening_addresses.len());
365-
366-
for listening_addr in listening_addresses {
367-
let resolved_address = listening_addr.to_socket_addrs().map_err(|e| {
368-
log_error!(
369-
self.logger,
370-
"Unable to resolve listening address: {:?}. Error details: {}",
371-
listening_addr,
372-
e,
373-
);
374-
Error::InvalidSocketAddress
375-
})?;
376-
377-
bind_addrs.extend(resolved_address);
378-
}
379-
380363
let logger = Arc::clone(&listening_logger);
364+
let listening_addrs = listening_addresses.clone();
381365
let listeners = self.runtime.block_on(async move {
366+
let mut bind_addrs = Vec::with_capacity(listening_addrs.len());
367+
368+
for listening_addr in &listening_addrs {
369+
let resolved =
370+
tokio::net::lookup_host(listening_addr.to_string()).await.map_err(|e| {
371+
log_error!(
372+
logger,
373+
"Unable to resolve listening address: {:?}. Error details: {}",
374+
listening_addr,
375+
e,
376+
);
377+
Error::InvalidSocketAddress
378+
})?;
379+
bind_addrs.extend(resolved);
380+
}
381+
382382
let mut listeners = Vec::new();
383383

384384
// Try to bind to all addresses
385-
for addr in &*bind_addrs {
385+
for addr in &bind_addrs {
386386
match tokio::net::TcpListener::bind(addr).await {
387387
Ok(listener) => {
388388
log_trace!(logger, "Listener bound to {}", addr);

0 commit comments

Comments
 (0)