outbound_session.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. use async_std::sync::{Arc, Mutex, Weak};
  2. use std::fmt;
  3. use async_executor::Executor;
  4. use async_trait::async_trait;
  5. use log::{debug, info, warn};
  6. use rand::seq::SliceRandom;
  7. use serde_json::{json, Value};
  8. use url::Url;
  9. use crate::{
  10. net::TransportName,
  11. system::{StoppableTask, StoppableTaskPtr, Subscriber, SubscriberPtr, Subscription},
  12. util::async_util,
  13. Error, Result,
  14. };
  15. use super::{
  16. super::{ChannelPtr, Connector, P2p},
  17. Session, SessionBitflag, SESSION_OUTBOUND,
  18. };
  19. #[derive(Clone)]
  20. enum OutboundState {
  21. Open,
  22. Pending,
  23. Connected,
  24. }
  25. impl fmt::Display for OutboundState {
  26. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  27. write!(
  28. f,
  29. "{}",
  30. match self {
  31. Self::Open => "open",
  32. Self::Pending => "pending",
  33. Self::Connected => "connected",
  34. }
  35. )
  36. }
  37. }
  38. #[derive(Clone)]
  39. struct OutboundInfo {
  40. addr: Option<Url>,
  41. channel: Option<ChannelPtr>,
  42. state: OutboundState,
  43. }
  44. impl OutboundInfo {
  45. async fn get_info(&self) -> serde_json::Value {
  46. let addr = match self.addr.as_ref() {
  47. Some(addr) => serde_json::Value::String(addr.to_string()),
  48. None => serde_json::Value::Null,
  49. };
  50. let channel = match &self.channel {
  51. Some(channel) => channel.get_info().await,
  52. None => serde_json::Value::Null,
  53. };
  54. json!({
  55. "addr": addr,
  56. "state": self.state.to_string(),
  57. "channel": channel,
  58. })
  59. }
  60. }
  61. impl Default for OutboundInfo {
  62. fn default() -> Self {
  63. Self { addr: None, channel: None, state: OutboundState::Open }
  64. }
  65. }
  66. /// Defines outbound connections session.
  67. pub struct OutboundSession {
  68. p2p: Weak<P2p>,
  69. connect_slots: Mutex<Vec<StoppableTaskPtr>>,
  70. slot_info: Mutex<Vec<OutboundInfo>>,
  71. /// Subscriber used to signal channels processing
  72. channel_subscriber: SubscriberPtr<Result<ChannelPtr>>,
  73. /// Flag to toggle channel_subscriber notifications
  74. notify: Mutex<bool>,
  75. }
  76. impl OutboundSession {
  77. /// Create a new outbound session.
  78. pub fn new(p2p: Weak<P2p>) -> Arc<Self> {
  79. Arc::new(Self {
  80. p2p,
  81. connect_slots: Mutex::new(Vec::new()),
  82. slot_info: Mutex::new(Vec::new()),
  83. channel_subscriber: Subscriber::new(),
  84. notify: Mutex::new(false),
  85. })
  86. }
  87. /// Start the outbound session. Runs the channel connect loop.
  88. pub async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
  89. let slots_count = self.p2p().settings().outbound_connections;
  90. info!(target: "net", "Starting {} outbound connection slots.", slots_count);
  91. // Activate mutex lock on connection slots.
  92. let mut connect_slots = self.connect_slots.lock().await;
  93. self.slot_info.lock().await.resize(slots_count as usize, Default::default());
  94. for i in 0..slots_count {
  95. let task = StoppableTask::new();
  96. task.clone().start(
  97. self.clone().channel_connect_loop(i, executor.clone()),
  98. // Ignore stop handler
  99. |_| async {},
  100. Error::NetworkServiceStopped,
  101. executor.clone(),
  102. );
  103. connect_slots.push(task);
  104. }
  105. Ok(())
  106. }
  107. /// Stop the outbound session.
  108. pub async fn stop(&self) {
  109. let connect_slots = &*self.connect_slots.lock().await;
  110. for slot in connect_slots {
  111. slot.stop().await;
  112. }
  113. }
  114. /// Start making outbound connections. Creates a connector object, then
  115. /// starts a connect loop. Loads a valid address then tries to connect.
  116. /// Once connected, registers the channel, removes it from the list of
  117. /// pending channels, and starts sending messages across the channel.
  118. /// Otherwise returns a network error.
  119. pub async fn channel_connect_loop(
  120. self: Arc<Self>,
  121. slot_number: u32,
  122. executor: Arc<Executor<'_>>,
  123. ) -> Result<()> {
  124. let parent = Arc::downgrade(&self);
  125. let connector = Connector::new(self.p2p().settings(), Arc::new(parent));
  126. // Retrieve preferent outbound transports
  127. let outbound_transports = &self.p2p().settings().outbound_transports;
  128. loop {
  129. let addr = self.load_address(slot_number).await?;
  130. info!(target: "net", "#{} processing outbound [{}]", slot_number, addr);
  131. {
  132. let info = &mut self.slot_info.lock().await[slot_number as usize];
  133. info.addr = Some(addr.clone());
  134. info.state = OutboundState::Pending;
  135. }
  136. // Check that addr transport is in configured outbound transport
  137. let addr_transport = TransportName::try_from(addr.clone())?;
  138. let transports = if outbound_transports.contains(&addr_transport) {
  139. vec![addr_transport]
  140. } else {
  141. warn!(target: "net", "#{} address {} transport is not in accepted outbound transports, will try with: {:?}", slot_number, addr, outbound_transports);
  142. outbound_transports.clone()
  143. };
  144. for transport in transports {
  145. // Replace addr transport
  146. let mut transport_addr = addr.clone();
  147. transport_addr.set_scheme(&transport.to_scheme())?;
  148. info!(target: "net", "#{} connecting to outbound [{}]", slot_number, transport_addr);
  149. match connector.connect(transport_addr.clone()).await {
  150. Ok(channel) => {
  151. // Blacklist goes here
  152. info!(target: "net", "#{} connected to outbound [{}]", slot_number, transport_addr);
  153. let stop_sub = channel.subscribe_stop().await;
  154. if stop_sub.is_err() {
  155. continue
  156. }
  157. self.clone().register_channel(channel.clone(), executor.clone()).await?;
  158. // Channel is now connected but not yet setup
  159. // Remove pending lock since register_channel will add the channel to p2p
  160. self.p2p().remove_pending(&addr).await;
  161. {
  162. let info = &mut self.slot_info.lock().await[slot_number as usize];
  163. info.channel = Some(channel.clone());
  164. info.state = OutboundState::Connected;
  165. }
  166. // Notify that channel processing has been finished
  167. if *self.notify.lock().await {
  168. self.channel_subscriber.notify(Ok(channel)).await;
  169. }
  170. // Wait for channel to close
  171. stop_sub.unwrap().receive().await;
  172. }
  173. Err(err) => {
  174. info!(target: "net", "Unable to connect to outbound [{}]: {}", &transport_addr, err);
  175. }
  176. }
  177. }
  178. {
  179. let info = &mut self.slot_info.lock().await[slot_number as usize];
  180. info.addr = None;
  181. info.channel = None;
  182. info.state = OutboundState::Open;
  183. }
  184. // Notify that channel processing has been finished (failed)
  185. if *self.notify.lock().await {
  186. self.channel_subscriber.notify(Err(Error::ConnectFailed)).await;
  187. }
  188. }
  189. }
  190. /// Loops through host addresses to find a outbound address that we can
  191. /// connect to. Checks whether address is valid by making sure it isn't
  192. /// our own inbound address, then checks whether it is already connected
  193. /// (exists) or connecting (pending). Keeps looping until address is
  194. /// found that passes all checks.
  195. async fn load_address(&self, slot_number: u32) -> Result<Url> {
  196. loop {
  197. let p2p = self.p2p();
  198. let self_inbound_addr = p2p.settings().external_addr.clone();
  199. let mut addrs;
  200. {
  201. let hosts = p2p.hosts().load_all().await;
  202. addrs = hosts;
  203. }
  204. addrs.shuffle(&mut rand::thread_rng());
  205. for addr in addrs {
  206. if p2p.exists(&addr).await? {
  207. continue
  208. }
  209. // Check if address is in peers list
  210. if p2p.settings().peers.contains(&addr) {
  211. continue
  212. }
  213. // Obtain a lock on this address to prevent duplicate connections
  214. if !p2p.add_pending(addr.clone()).await {
  215. continue
  216. }
  217. if self_inbound_addr.contains(&addr) {
  218. continue
  219. }
  220. return Ok(addr)
  221. }
  222. debug!(target: "net", "Hosts address pool is empty. Retrying connect slot #{}", slot_number);
  223. async_util::sleep(p2p.settings().outbound_retry_seconds).await;
  224. }
  225. }
  226. /// Subscribe to a channel.
  227. pub async fn subscribe_channel(&self) -> Subscription<Result<ChannelPtr>> {
  228. self.channel_subscriber.clone().subscribe().await
  229. }
  230. /// Enable channel_subscriber notifications.
  231. pub async fn enable_notify(self: Arc<Self>) {
  232. *self.notify.lock().await = true;
  233. }
  234. /// Disable channel_subscriber notifications.
  235. pub async fn disable_notify(self: Arc<Self>) {
  236. *self.notify.lock().await = false;
  237. }
  238. }
  239. #[async_trait]
  240. impl Session for OutboundSession {
  241. async fn get_info(&self) -> serde_json::Value {
  242. let mut slots = Vec::new();
  243. for info in &*self.slot_info.lock().await {
  244. slots.push(info.get_info().await);
  245. }
  246. let hosts = self.p2p().hosts().load_all().await;
  247. let addrs: Vec<Value> =
  248. hosts.iter().map(|addr| serde_json::Value::String(addr.to_string())).collect();
  249. json!({
  250. "slots": slots,
  251. "hosts": serde_json::Value::Array(addrs),
  252. })
  253. }
  254. fn p2p(&self) -> Arc<P2p> {
  255. self.p2p.upgrade().unwrap()
  256. }
  257. fn type_id(&self) -> SessionBitflag {
  258. SESSION_OUTBOUND
  259. }
  260. }