outbound_session.rs 8.7 KB

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