outbound_session.rs 7.6 KB

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