diff --git a/src/net/session/outbound_session.rs b/src/net/session/outbound_session.rs index 210754e6c..8ace911e2 100644 --- a/src/net/session/outbound_session.rs +++ b/src/net/session/outbound_session.rs @@ -3,13 +3,14 @@ use std::fmt; use async_executor::Executor; use async_trait::async_trait; -use log::{error, info}; +use log::{info, warn}; use rand::seq::SliceRandom; use serde_json::json; use url::Url; use crate::{ system::{StoppableTask, StoppableTaskPtr}, + util::async_util, Error, Result, }; @@ -191,37 +192,41 @@ impl OutboundSession { /// (exists) or connecting (pending). Keeps looping until address is /// found that passes all checks. async fn load_address(&self, slot_number: u32) -> Result { - let p2p = self.p2p(); - let self_inbound_addr = p2p.settings().external_addr.clone(); + loop { + let p2p = self.p2p(); + let self_inbound_addr = p2p.settings().external_addr.clone(); - let mut addrs; + let mut addrs; - { - let hosts = p2p.hosts().load_all().await; - addrs = hosts; + { + let hosts = p2p.hosts().load_all().await; + addrs = hosts; + } + + addrs.shuffle(&mut rand::thread_rng()); + + for addr in addrs { + if p2p.exists(&addr).await { + continue + } + + // Obtain a lock on this address to prevent duplicate connections + if !p2p.add_pending(addr.clone()).await { + continue + } + + if Self::is_self_inbound(&addr, &self_inbound_addr) { + continue + } + + return Ok(addr) + } + + warn!(target: "net", "Hosts address pool is empty. Retrying connect slot #{}", slot_number); + + let retry_time = p2p.settings().outbound_retry_seconds.clone(); + async_util::sleep(retry_time).await; } - - addrs.shuffle(&mut rand::thread_rng()); - - for addr in addrs { - if p2p.exists(&addr).await { - continue - } - - // Obtain a lock on this address to prevent duplicate connections - if !p2p.add_pending(addr.clone()).await { - continue - } - - if Self::is_self_inbound(&addr, &self_inbound_addr) { - continue - } - - return Ok(addr) - } - - error!(target: "net", "Hosts address pool is empty. Closing connect slot #{}", slot_number); - Err(Error::NetworkServiceStopped) } /// Checks whether an address is our own inbound address to avoid connecting diff --git a/src/net/settings.rs b/src/net/settings.rs index 15b7b810f..d7c8b9803 100644 --- a/src/net/settings.rs +++ b/src/net/settings.rs @@ -18,6 +18,7 @@ pub struct Settings { pub connect_timeout_seconds: u32, pub channel_handshake_seconds: u32, pub channel_heartbeat_seconds: u32, + pub outbound_retry_seconds: u64, pub external_addr: Option, pub peers: Vec, pub seeds: Vec, @@ -34,6 +35,7 @@ impl Default for Settings { connect_timeout_seconds: 10, channel_handshake_seconds: 4, channel_heartbeat_seconds: 10, + outbound_retry_seconds: 20, external_addr: None, peers: Vec::new(), seeds: Vec::new(), @@ -78,6 +80,8 @@ pub struct SettingsOpt { pub channel_handshake_seconds: Option, #[structopt(skip)] pub channel_heartbeat_seconds: Option, + #[structopt(skip)] + pub outbound_retry_seconds: Option, #[serde(default)] #[structopt(skip)] @@ -94,6 +98,7 @@ impl From for Settings { connect_timeout_seconds: settings_opt.connect_timeout_seconds.unwrap_or(10), channel_handshake_seconds: settings_opt.channel_handshake_seconds.unwrap_or(4), channel_heartbeat_seconds: settings_opt.channel_heartbeat_seconds.unwrap_or(10), + outbound_retry_seconds: settings_opt.outbound_retry_seconds.unwrap_or(20), external_addr: settings_opt.external_addr, peers: settings_opt.peers, seeds: settings_opt.seeds,