Skip to content

Commit 0bac554

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 0bac554

File tree

3 files changed

+79
-62
lines changed

3 files changed

+79
-62
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: 60 additions & 43 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;
@@ -97,39 +96,48 @@ 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+
for proxy_addr in resolved_addrs {
124+
let connection_future = lightning_net_tokio::tor_connect_outbound(
125+
Arc::clone(&self.peer_manager),
126+
node_id,
127+
addr.clone(),
128+
proxy_addr,
129+
Arc::clone(&self.keys_manager),
130+
);
131+
res = self.await_connection(connection_future, node_id, addr.clone()).await;
132+
if res.is_ok() {
133+
break;
134+
}
135+
}
136+
res
129137
},
130138
_ => {
131-
let socket_addr = addr
132-
.to_socket_addrs()
139+
let resolved_addrs: Vec<_> = tokio::net::lookup_host(addr.to_string())
140+
.await
133141
.map_err(|e| {
134142
log_error!(
135143
self.logger,
@@ -139,17 +147,26 @@ where
139147
);
140148
Error::InvalidSocketAddress
141149
})?
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
150+
.collect();
151+
152+
if resolved_addrs.is_empty() {
153+
log_error!(self.logger, "Failed to resolve network address {}", addr);
154+
return Err(Error::InvalidSocketAddress);
155+
}
156+
157+
let mut res = Err(Error::ConnectionFailed);
158+
for socket_addr in resolved_addrs {
159+
let connection_future = lightning_net_tokio::connect_outbound(
160+
Arc::clone(&self.peer_manager),
161+
node_id,
162+
socket_addr,
163+
);
164+
res = self.await_connection(connection_future, node_id, addr.clone()).await;
165+
if res.is_ok() {
166+
break;
167+
}
168+
}
169+
res
153170
},
154171
}
155172
}

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)