p2p.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::collections::{HashMap, HashSet};
  19. use async_std::{
  20. stream::StreamExt,
  21. sync::{Arc, Mutex},
  22. };
  23. use futures::{stream::FuturesUnordered, TryFutureExt};
  24. use log::{debug, error, info, warn};
  25. use rand::{prelude::IteratorRandom, rngs::OsRng};
  26. use smol::Executor;
  27. use url::Url;
  28. use super::{
  29. channel::{ChannelInfo, ChannelPtr},
  30. hosts::{Hosts, HostsPtr},
  31. message::Message,
  32. protocol::{protocol_registry::ProtocolRegistry, register_default_protocols},
  33. session::{
  34. InboundSession, InboundSessionPtr, ManualSession, ManualSessionPtr, OutboundSession,
  35. OutboundSessionPtr, SeedSyncSession,
  36. },
  37. settings::{Settings, SettingsPtr},
  38. };
  39. use crate::{
  40. system::{Subscriber, SubscriberPtr, Subscription},
  41. Result,
  42. };
  43. /// Set of channels that are awaiting connection
  44. pub type PendingChannels = Mutex<HashSet<Url>>;
  45. /// Set of connected channels
  46. pub type ConnectedChannels = Mutex<HashMap<Url, ChannelPtr>>;
  47. /// Atomic pointer to the p2p interface
  48. pub type P2pPtr = Arc<P2p>;
  49. /// Toplevel peer-to-peer networking interface
  50. pub struct P2p {
  51. /// Channels pending connection
  52. pending: PendingChannels,
  53. /// Connected channels
  54. channels: ConnectedChannels,
  55. /// Subscriber for notifications of new channels
  56. channel_subscriber: SubscriberPtr<Result<ChannelPtr>>,
  57. /// Subscriber for stop notifications
  58. stop_subscriber: SubscriberPtr<()>,
  59. /// Known hosts (peers)
  60. hosts: HostsPtr,
  61. /// Protocol registry
  62. protocol_registry: ProtocolRegistry,
  63. /// P2P network settings
  64. settings: SettingsPtr,
  65. /// Boolean lock marking if peer discovery is active
  66. pub peer_discovery_running: Mutex<bool>,
  67. /// Reference to configured [`ManualSession`]
  68. session_manual: Mutex<Option<Arc<ManualSession>>>,
  69. /// Reference to configured [`InboundSession`]
  70. session_inbound: Mutex<Option<Arc<InboundSession>>>,
  71. /// Reference to configured [`OutboundSession`]
  72. session_outbound: Mutex<Option<Arc<OutboundSession>>>,
  73. /// Enable network debugging
  74. pub dnet_enabled: Mutex<bool>,
  75. /// The subscriber for which we can give dnet info over
  76. dnet_sub: SubscriberPtr<ChannelInfo>,
  77. }
  78. impl P2p {
  79. /// Initialize a new p2p network.
  80. ///
  81. /// Initializes all sessions and protocols. Adds the protocols to the protocol
  82. /// registry, along with a bitflag session selector that includes or excludes
  83. /// sessions from seed, version, and address protocols.
  84. ///
  85. /// Creates a weak pointer to self that is used by all sessions to access the
  86. /// p2p parent class.
  87. pub async fn new(settings: Settings) -> P2pPtr {
  88. let settings = Arc::new(settings);
  89. let self_ = Arc::new(Self {
  90. pending: Mutex::new(HashSet::new()),
  91. channels: Mutex::new(HashMap::new()),
  92. channel_subscriber: Subscriber::new(),
  93. stop_subscriber: Subscriber::new(),
  94. hosts: Hosts::new(settings.clone()),
  95. protocol_registry: ProtocolRegistry::new(),
  96. settings,
  97. peer_discovery_running: Mutex::new(false),
  98. session_manual: Mutex::new(None),
  99. session_inbound: Mutex::new(None),
  100. session_outbound: Mutex::new(None),
  101. dnet_enabled: Mutex::new(false),
  102. dnet_sub: Subscriber::new(),
  103. });
  104. let parent = Arc::downgrade(&self_);
  105. *self_.session_manual.lock().await = Some(ManualSession::new(parent.clone()));
  106. *self_.session_inbound.lock().await = Some(InboundSession::new(parent.clone()));
  107. *self_.session_outbound.lock().await = Some(OutboundSession::new(parent));
  108. register_default_protocols(self_.clone()).await;
  109. self_
  110. }
  111. /// Invoke startup and seeding sequence. Call from constructing thread.
  112. pub async fn start(self: Arc<Self>, ex: Arc<Executor<'_>>) -> Result<()> {
  113. debug!(target: "net::p2p::start()", "P2P::start() [BEGIN]");
  114. info!(target: "net::p2p::start()", "[P2P] Seeding P2P subsystem");
  115. // Start seed session
  116. let seed = SeedSyncSession::new(Arc::downgrade(&self));
  117. // This will block until all seed queries have finished
  118. seed.start(ex.clone()).await?;
  119. debug!(target: "net::p2p::start()", "P2P::start() [END]");
  120. Ok(())
  121. }
  122. /// Reseed the P2P network.
  123. pub async fn reseed(self: Arc<Self>, ex: Arc<Executor<'_>>) -> Result<()> {
  124. debug!(target: "net::p2p::reseed()", "P2P::reseed() [BEGIN]");
  125. info!(target: "net::p2p::reseed()", "[P2P] Reseeding P2P subsystem");
  126. // Start seed session
  127. let seed = SeedSyncSession::new(Arc::downgrade(&self));
  128. // This will block until all seed queries have finished
  129. seed.start(ex.clone()).await?;
  130. debug!(target: "net::p2p::reseed()", "P2P::reseed() [END]");
  131. Ok(())
  132. }
  133. /// Runs the network. Starts inbound, outbound, and manual sessions.
  134. /// Waits for a stop signal and stops the network if received.
  135. pub async fn run(self: Arc<Self>, ex: Arc<Executor<'_>>) -> Result<()> {
  136. debug!(target: "net::p2p::run()", "P2P::run() [BEGIN]");
  137. info!(target: "net::p2p::run()", "[P2P] Running P2P subsystem");
  138. // First attempt any set manual connections
  139. let manual = self.session_manual().await;
  140. for peer in &self.settings.peers {
  141. manual.clone().connect(peer.clone(), ex.clone()).await;
  142. }
  143. // Start the inbound session
  144. let inbound = self.session_inbound().await;
  145. inbound.clone().start(ex.clone()).await?;
  146. // Start the outbound session
  147. let outbound = self.session_outbound().await;
  148. outbound.clone().start(ex.clone()).await?;
  149. info!(target: "net::p2p::run()", "[P2P] P2P subsystem started");
  150. // Wait for stop signal
  151. let stop_sub = self.subscribe_stop().await;
  152. stop_sub.receive().await;
  153. info!(target: "net::p2p::run()", "[P2P] Received P2P subsystem stop signal. Shutting down.");
  154. // Stop the sessions
  155. manual.stop().await;
  156. inbound.stop().await;
  157. outbound.stop().await;
  158. debug!(target: "net::p2p::run()", "P2P::run() [END]");
  159. Ok(())
  160. }
  161. /// Subscribe to a stop signal.
  162. pub async fn subscribe_stop(&self) -> Subscription<()> {
  163. self.stop_subscriber.clone().subscribe().await
  164. }
  165. /// Stop the running P2P subsystem
  166. pub async fn stop(&self) {
  167. self.stop_subscriber.notify(()).await
  168. }
  169. /// Add a channel to the set of connected channels
  170. pub async fn store(&self, channel: ChannelPtr) {
  171. // TODO: Check the code path for this, and potentially also insert the remote
  172. // into the hosts list?
  173. self.channels.lock().await.insert(channel.address().clone(), channel.clone());
  174. self.channel_subscriber.notify(Ok(channel)).await;
  175. }
  176. /// Broadcasts a message concurrently across all active channels.
  177. pub async fn broadcast<M: Message>(&self, message: &M) {
  178. self.broadcast_with_exclude(message, &[]).await
  179. }
  180. /// Broadcasts a message concurrently across active channels, excluding
  181. /// the ones provided in `exclude_list`.
  182. pub async fn broadcast_with_exclude<M: Message>(&self, message: &M, exclude_list: &[Url]) {
  183. let chans = self.channels.lock().await;
  184. let iter = chans.values();
  185. let mut futures = FuturesUnordered::new();
  186. for channel in iter {
  187. if exclude_list.contains(channel.address()) {
  188. continue
  189. }
  190. futures.push(channel.send(message).map_err(|e| {
  191. (
  192. format!("[P2P] Broadcasting message to {} failed: {}", channel.address(), e),
  193. channel.clone(),
  194. )
  195. }));
  196. }
  197. if futures.is_empty() {
  198. warn!(target: "net::p2p::broadcast()", "[P2P] No connected channels found for broadcast");
  199. return
  200. }
  201. while let Some(entry) = futures.next().await {
  202. if let Err((e, chan)) = entry {
  203. error!(target: "net::p2p::broadcast()", "{}", e);
  204. self.remove(chan).await;
  205. }
  206. }
  207. }
  208. /// Check whether we're connected to a given address
  209. pub async fn exists(&self, addr: &Url) -> bool {
  210. self.channels.lock().await.contains_key(addr)
  211. }
  212. /// Remove a channel from the set of connected channels
  213. pub async fn remove(&self, channel: ChannelPtr) {
  214. self.channels.lock().await.remove(channel.address());
  215. }
  216. /// Add an address to the list of pending channels.
  217. pub async fn add_pending(&self, addr: &Url) -> bool {
  218. self.pending.lock().await.insert(addr.clone())
  219. }
  220. /// Remove a channel from the list of pending channels.
  221. pub async fn remove_pending(&self, addr: &Url) {
  222. self.pending.lock().await.remove(addr);
  223. }
  224. /// Return reference to connected channels map
  225. pub fn channels(&self) -> &ConnectedChannels {
  226. &self.channels
  227. }
  228. /// Retrieve a random connected channel from the
  229. pub async fn random_channel(&self) -> Option<ChannelPtr> {
  230. let channels = self.channels().lock().await;
  231. channels.values().choose(&mut OsRng).cloned()
  232. }
  233. /// Return an atomic pointer to the set network settings
  234. pub fn settings(&self) -> SettingsPtr {
  235. self.settings.clone()
  236. }
  237. /// Return an atomic pointer to the list of hosts
  238. pub fn hosts(&self) -> HostsPtr {
  239. self.hosts.clone()
  240. }
  241. /// Return a reference to the internal protocol registry
  242. pub fn protocol_registry(&self) -> &ProtocolRegistry {
  243. &self.protocol_registry
  244. }
  245. /// Get pointer to manual session
  246. pub async fn session_manual(&self) -> ManualSessionPtr {
  247. self.session_manual.lock().await.as_ref().unwrap().clone()
  248. }
  249. /// Get pointer to inbound session
  250. pub async fn session_inbound(&self) -> InboundSessionPtr {
  251. self.session_inbound.lock().await.as_ref().unwrap().clone()
  252. }
  253. /// Get pointer to outbound session
  254. pub async fn session_outbound(&self) -> OutboundSessionPtr {
  255. self.session_outbound.lock().await.as_ref().unwrap().clone()
  256. }
  257. /// Enable network debugging
  258. pub async fn dnet_enable(&self) {
  259. *self.dnet_enabled.lock().await = true;
  260. warn!("[P2P] Network debugging enabled!");
  261. }
  262. /// Disable network debugging
  263. pub async fn dnet_disable(&self) {
  264. *self.dnet_enabled.lock().await = false;
  265. warn!("[P2P] Network debugging disabled!");
  266. }
  267. /// Return a reference to the dnet subscriber
  268. pub fn dnet_sub(&self) -> SubscriberPtr<ChannelInfo> {
  269. self.dnet_sub.clone()
  270. }
  271. }
  272. macro_rules! dnet {
  273. ($self:expr, $($code:tt)*) => {
  274. {
  275. if *$self.p2p().dnet_enabled.lock().await {
  276. $($code)*
  277. }
  278. }
  279. };
  280. }
  281. pub(crate) use dnet;