p2p.rs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2024 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::sync::Arc;
  19. use futures::{stream::FuturesUnordered, TryFutureExt};
  20. use log::{debug, error, info, warn};
  21. use smol::{lock::Mutex, stream::StreamExt};
  22. use url::Url;
  23. use super::{
  24. channel::ChannelPtr,
  25. dnet::DnetEvent,
  26. hosts::{Hosts, HostsPtr},
  27. message::Message,
  28. protocol::{protocol_registry::ProtocolRegistry, register_default_protocols},
  29. session::{
  30. InboundSession, InboundSessionPtr, ManualSession, ManualSessionPtr, OutboundSession,
  31. OutboundSessionPtr, RefineSession, RefineSessionPtr, SeedSyncSession,
  32. },
  33. settings::{Settings, SettingsPtr},
  34. };
  35. use crate::{
  36. system::{ExecutorPtr, Subscriber, SubscriberPtr, Subscription},
  37. Result,
  38. };
  39. /// Atomic pointer to the p2p interface
  40. pub type P2pPtr = Arc<P2p>;
  41. /// Toplevel peer-to-peer networking interface
  42. pub struct P2p {
  43. /// Global multithreaded executor reference
  44. executor: ExecutorPtr,
  45. /// Known hosts (peers)
  46. hosts: HostsPtr,
  47. /// Protocol registry
  48. protocol_registry: ProtocolRegistry,
  49. /// P2P network settings
  50. settings: SettingsPtr,
  51. /// Reference to configured [`ManualSession`]
  52. session_manual: ManualSessionPtr,
  53. /// Reference to configured [`InboundSession`]
  54. session_inbound: InboundSessionPtr,
  55. /// Reference to configured [`OutboundSession`]
  56. session_outbound: OutboundSessionPtr,
  57. /// Reference to configured [`RefineSession`]
  58. session_refine: RefineSessionPtr,
  59. /// Enable network debugging
  60. pub dnet_enabled: Mutex<bool>,
  61. /// The subscriber for which we can give dnet info over
  62. dnet_subscriber: SubscriberPtr<DnetEvent>,
  63. }
  64. impl P2p {
  65. /// Initialize a new p2p network.
  66. ///
  67. /// Initializes all sessions and protocols. Adds the protocols to the protocol
  68. /// registry, along with a bitflag session selector that includes or excludes
  69. /// sessions from seed, version, and address protocols.
  70. ///
  71. /// Creates a weak pointer to self that is used by all sessions to access the
  72. /// p2p parent class.
  73. pub async fn new(settings: Settings, executor: ExecutorPtr) -> P2pPtr {
  74. let settings = Arc::new(settings);
  75. let self_ = Arc::new(Self {
  76. executor,
  77. hosts: Hosts::new(settings.clone()),
  78. protocol_registry: ProtocolRegistry::new(),
  79. settings,
  80. session_manual: ManualSession::new(),
  81. session_inbound: InboundSession::new(),
  82. session_outbound: OutboundSession::new(),
  83. session_refine: RefineSession::new(),
  84. dnet_enabled: Mutex::new(false),
  85. dnet_subscriber: Subscriber::new(),
  86. });
  87. self_.session_manual.p2p.init(self_.clone());
  88. self_.session_inbound.p2p.init(self_.clone());
  89. self_.session_outbound.p2p.init(self_.clone());
  90. self_.session_refine.p2p.init(self_.clone());
  91. register_default_protocols(self_.clone()).await;
  92. self_
  93. }
  94. /// Starts inbound, outbound, and manual sessions.
  95. pub async fn start(self: Arc<Self>) -> Result<()> {
  96. debug!(target: "net::p2p::start()", "P2P::start() [BEGIN]");
  97. info!(target: "net::p2p::start()", "[P2P] Starting P2P subsystem");
  98. // First attempt any set manual connections
  99. for peer in &self.settings.peers {
  100. self.session_manual().connect(peer.clone()).await;
  101. }
  102. // Start the inbound session
  103. if let Err(err) = self.session_inbound().start().await {
  104. error!(target: "net::p2p::start()", "Failed to start inbound session!: {}", err);
  105. self.session_manual().stop().await;
  106. return Err(err)
  107. }
  108. // Start the refine session
  109. self.session_refine().start().await;
  110. // Start the outbound session
  111. self.session_outbound().start().await;
  112. info!(target: "net::p2p::start()", "[P2P] P2P subsystem started");
  113. Ok(())
  114. }
  115. /// Reseed the P2P network.
  116. pub async fn seed(self: Arc<Self>) -> Result<()> {
  117. debug!(target: "net::p2p::seed()", "P2P::seed() [BEGIN]");
  118. info!(target: "net::p2p::seed()", "[P2P] Seeding P2P subsystem");
  119. // Start seed session
  120. let seed = SeedSyncSession::new(Arc::downgrade(&self));
  121. // This will block until all seed queries have finished
  122. seed.start().await?;
  123. debug!(target: "net::p2p::seed()", "P2P::seed() [END]");
  124. Ok(())
  125. }
  126. /// Stop the running P2P subsystem
  127. pub async fn stop(&self) {
  128. // Stop all channels
  129. for channel in self.hosts.channels().await {
  130. channel.stop().await;
  131. }
  132. // Stop the sessions
  133. self.session_manual().stop().await;
  134. self.session_inbound().stop().await;
  135. self.session_refine().stop().await;
  136. self.session_outbound().stop().await;
  137. }
  138. /// Broadcasts a message concurrently across all active channels.
  139. pub async fn broadcast<M: Message>(&self, message: &M) {
  140. self.broadcast_with_exclude(message, &[]).await
  141. }
  142. /// Broadcasts a message concurrently across active channels, excluding
  143. /// the ones provided in `exclude_list`.
  144. pub async fn broadcast_with_exclude<M: Message>(&self, message: &M, exclude_list: &[Url]) {
  145. let mut channels = Vec::new();
  146. for channel in self.hosts().channels().await {
  147. if exclude_list.contains(channel.address()) {
  148. continue
  149. }
  150. channels.push(channel);
  151. }
  152. self.broadcast_to(message, &channels).await
  153. }
  154. /// Broadcast a message concurrently to all given peers.
  155. pub async fn broadcast_to<M: Message>(&self, message: &M, channel_list: &[ChannelPtr]) {
  156. if channel_list.is_empty() {
  157. warn!(target: "net::p2p::broadcast()", "[P2P] No connected channels found for broadcast");
  158. return
  159. }
  160. let futures = FuturesUnordered::new();
  161. for channel in channel_list {
  162. futures.push(channel.send(message).map_err(|e| {
  163. error!(
  164. target: "net::p2p::broadcast()",
  165. "[P2P] Broadcasting message to {} failed: {}",
  166. channel.address(), e
  167. );
  168. // If the channel is stopped then it should automatically die
  169. // and the session will remove it from p2p.
  170. assert!(channel.is_stopped());
  171. }));
  172. }
  173. let _results: Vec<_> = futures.collect().await;
  174. }
  175. pub async fn is_connected(&self) -> bool {
  176. !self.hosts().channels().await.is_empty()
  177. }
  178. /// Return an atomic pointer to the set network settings
  179. pub fn settings(&self) -> SettingsPtr {
  180. self.settings.clone()
  181. }
  182. /// Return an atomic pointer to the list of hosts
  183. pub fn hosts(&self) -> HostsPtr {
  184. self.hosts.clone()
  185. }
  186. /// Reference the global executor
  187. pub fn executor(&self) -> ExecutorPtr {
  188. self.executor.clone()
  189. }
  190. /// Return a reference to the internal protocol registry
  191. pub fn protocol_registry(&self) -> &ProtocolRegistry {
  192. &self.protocol_registry
  193. }
  194. /// Get pointer to manual session
  195. pub fn session_manual(&self) -> ManualSessionPtr {
  196. self.session_manual.clone()
  197. }
  198. /// Get pointer to inbound session
  199. pub fn session_inbound(&self) -> InboundSessionPtr {
  200. self.session_inbound.clone()
  201. }
  202. /// Get pointer to outbound session
  203. pub fn session_outbound(&self) -> OutboundSessionPtr {
  204. self.session_outbound.clone()
  205. }
  206. /// Get pointer to refine session
  207. pub fn session_refine(&self) -> RefineSessionPtr {
  208. self.session_refine.clone()
  209. }
  210. /// Enable network debugging
  211. pub async fn dnet_enable(&self) {
  212. *self.dnet_enabled.lock().await = true;
  213. warn!("[P2P] Network debugging enabled!");
  214. }
  215. /// Disable network debugging
  216. pub async fn dnet_disable(&self) {
  217. *self.dnet_enabled.lock().await = false;
  218. warn!("[P2P] Network debugging disabled!");
  219. }
  220. /// Subscribe to dnet events
  221. pub async fn dnet_subscribe(&self) -> Subscription<DnetEvent> {
  222. self.dnet_subscriber.clone().subscribe().await
  223. }
  224. /// Send a dnet notification over the subscriber
  225. pub(super) async fn dnet_notify(&self, event: DnetEvent) {
  226. self.dnet_subscriber.notify(event).await;
  227. }
  228. }