protocol_ping.rs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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::{
  19. sync::Arc,
  20. time::{Duration, Instant},
  21. };
  22. use async_trait::async_trait;
  23. use log::{debug, error, warn};
  24. use rand::{rngs::OsRng, Rng};
  25. use smol::Executor;
  26. use super::{
  27. super::{
  28. channel::ChannelPtr,
  29. message::{PingMessage, PongMessage},
  30. message_subscriber::MessageSubscription,
  31. p2p::P2pPtr,
  32. settings::SettingsPtr,
  33. },
  34. protocol_base::{ProtocolBase, ProtocolBasePtr},
  35. protocol_jobs_manager::{ProtocolJobsManager, ProtocolJobsManagerPtr},
  36. };
  37. use crate::{
  38. system::{sleep, timeout::timeout},
  39. Error, Result,
  40. };
  41. /// Defines ping and pong messages
  42. pub struct ProtocolPing {
  43. channel: ChannelPtr,
  44. ping_sub: MessageSubscription<PingMessage>,
  45. pong_sub: MessageSubscription<PongMessage>,
  46. settings: SettingsPtr,
  47. jobsman: ProtocolJobsManagerPtr,
  48. }
  49. const PROTO_NAME: &str = "ProtocolPing";
  50. impl ProtocolPing {
  51. /// Create a new ping-pong protocol.
  52. pub async fn init(channel: ChannelPtr, p2p: P2pPtr) -> ProtocolBasePtr {
  53. let settings = p2p.settings();
  54. // Creates a subscription to ping message
  55. let ping_sub =
  56. channel.subscribe_msg::<PingMessage>().await.expect("Missing ping dispatcher!");
  57. // Creates a subscription to pong message
  58. let pong_sub =
  59. channel.subscribe_msg::<PongMessage>().await.expect("Missing pong dispatcher!");
  60. Arc::new(Self {
  61. channel: channel.clone(),
  62. ping_sub,
  63. pong_sub,
  64. settings,
  65. jobsman: ProtocolJobsManager::new(PROTO_NAME, channel),
  66. })
  67. }
  68. /// Runs the ping-pong protocol. Creates a subscription to pong, then
  69. /// starts a loop. Loop sleeps for the duration of the channel heartbeat,
  70. /// then sends a ping message with a random nonce. Loop starts a timer,
  71. /// waits for the pong reply and ensures the nonce is the same.
  72. async fn run_ping_pong(self: Arc<Self>) -> Result<()> {
  73. debug!(
  74. target: "net::protocol_ping::run_ping_pong()",
  75. "START => address={}", self.channel.address(),
  76. );
  77. loop {
  78. // Create a random nonce.
  79. let nonce = Self::random_nonce();
  80. // Send ping message.
  81. let ping = PingMessage { nonce };
  82. self.channel.send(&ping).await?;
  83. // Start the timer for the ping timer
  84. let timer = Instant::now();
  85. // Wait for pong, check nonce matches.
  86. let pong_msg = match timeout(
  87. Duration::from_secs(self.settings.outbound_connect_timeout),
  88. self.pong_sub.receive(),
  89. )
  90. .await
  91. {
  92. Ok(msg) => {
  93. // msg will be an error when the channel is stopped
  94. // so just yield out of this function.
  95. msg?
  96. }
  97. Err(_e) => {
  98. // Pong timeout. We didn't receive any message back
  99. // so close the connection.
  100. warn!(
  101. target: "net::protocol_ping::run_ping_pong()",
  102. "[P2P] Ping-Pong protocol timed out for {}", self.channel.address(),
  103. );
  104. self.channel.stop().await;
  105. return Err(Error::ChannelStopped)
  106. }
  107. };
  108. if pong_msg.nonce != nonce {
  109. error!(
  110. target: "net::protocol_ping::run_ping_pong()",
  111. "[P2P] Wrong nonce in pingpong, disconnecting {}",
  112. self.channel.address(),
  113. );
  114. self.channel.stop().await;
  115. return Err(Error::ChannelStopped)
  116. }
  117. debug!(
  118. target: "net::protocol_ping::run_ping_pong()",
  119. "Received Pong from {}: {:?}",
  120. self.channel.address(),
  121. timer.elapsed(),
  122. );
  123. // Sleep until next heartbeat
  124. sleep(self.settings.channel_heartbeat_interval).await;
  125. }
  126. }
  127. /// Waits for ping, then replies with pong.
  128. /// Copies ping's nonce into the pong reply.
  129. async fn reply_to_ping(self: Arc<Self>) -> Result<()> {
  130. debug!(
  131. target: "net::protocol_ping::reply_to_ping()",
  132. "START => address={}", self.channel.address(),
  133. );
  134. loop {
  135. // Wait for ping, reply with pong that has a matching nonce.
  136. let ping = self.ping_sub.receive().await?;
  137. debug!(
  138. target: "net::protocol_ping::reply_to_ping()",
  139. "Received Ping from {}", self.channel.address(),
  140. );
  141. // Send pong message
  142. let pong = PongMessage { nonce: ping.nonce };
  143. self.channel.send(&pong).await?;
  144. debug!(
  145. target: "net::protocol_ping::reply_to_ping()",
  146. "Sent Pong reply to {}", self.channel.address(),
  147. );
  148. }
  149. }
  150. fn random_nonce() -> u16 {
  151. OsRng::gen(&mut OsRng)
  152. }
  153. }
  154. #[async_trait]
  155. impl ProtocolBase for ProtocolPing {
  156. /// Starts ping-pong keepalive messages exchange. Runs ping-pong in the
  157. /// protocol task manager, then queues the reply. Sends out a ping and
  158. /// waits for pong reply. Waits for ping and replies with a pong.
  159. async fn start(self: Arc<Self>, ex: Arc<Executor<'_>>) -> Result<()> {
  160. debug!(target: "net::protocol_ping::start()", "START => address={}", self.channel.address());
  161. self.jobsman.clone().start(ex.clone());
  162. self.jobsman.clone().spawn(self.clone().run_ping_pong(), ex.clone()).await;
  163. self.jobsman.clone().spawn(self.clone().reply_to_ping(), ex).await;
  164. debug!(target: "net::protocol_ping::start()", "END => address={}", self.channel.address());
  165. Ok(())
  166. }
  167. fn name(&self) -> &'static str {
  168. PROTO_NAME
  169. }
  170. }