protocol_ping.rs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. use async_trait::async_trait;
  2. use log::{debug, error};
  3. use rand::Rng;
  4. use smol::Executor;
  5. use std::{sync::Arc, time::Instant};
  6. use crate::{
  7. error::{Error, Result},
  8. net::{
  9. message,
  10. message_subscriber::MessageSubscription,
  11. protocol::{ProtocolBase, ProtocolBasePtr, ProtocolJobsManager, ProtocolJobsManagerPtr},
  12. ChannelPtr, P2pPtr, SettingsPtr,
  13. },
  14. util::sleep,
  15. };
  16. /// Defines ping and pong messages.
  17. pub struct ProtocolPing {
  18. channel: ChannelPtr,
  19. ping_sub: MessageSubscription<message::PingMessage>,
  20. pong_sub: MessageSubscription<message::PongMessage>,
  21. settings: SettingsPtr,
  22. jobsman: ProtocolJobsManagerPtr,
  23. }
  24. impl ProtocolPing {
  25. /// Create a new ping-pong protocol.
  26. pub async fn new(channel: ChannelPtr, p2p: P2pPtr) -> ProtocolBasePtr {
  27. let settings = p2p.settings();
  28. // Creates a subscription to ping message.
  29. let ping_sub = channel
  30. .clone()
  31. .subscribe_msg::<message::PingMessage>()
  32. .await
  33. .expect("Missing ping dispatcher!");
  34. // Creates a subscription to pong message.
  35. let pong_sub = channel
  36. .clone()
  37. .subscribe_msg::<message::PongMessage>()
  38. .await
  39. .expect("Missing pong dispatcher!");
  40. Arc::new(Self {
  41. channel: channel.clone(),
  42. ping_sub,
  43. pong_sub,
  44. settings,
  45. jobsman: ProtocolJobsManager::new("ProtocolPing", channel),
  46. })
  47. }
  48. /// Runs ping-pong protocol. Creates a subscription to pong, then starts a
  49. /// loop. Loop sleeps for the duration of the channel heartbeat, then
  50. /// sends a ping message with a random nonce. Loop starts a timer, waits
  51. /// for the pong reply and insures the nonce is the same.
  52. async fn run_ping_pong(self: Arc<Self>) -> Result<()> {
  53. debug!(target: "net", "ProtocolPing::run_ping_pong() [START]");
  54. loop {
  55. // Wait channel_heartbeat amount of time.
  56. sleep(self.settings.channel_heartbeat_seconds).await;
  57. // Create a random nonce.
  58. let nonce = Self::random_nonce();
  59. // Send ping message.
  60. let ping = message::PingMessage { nonce };
  61. self.channel.clone().send(ping).await?;
  62. debug!(target: "net", "ProtocolPing::run_ping_pong() send Ping message");
  63. // Start the timer for ping timer.
  64. let start = Instant::now();
  65. // Wait for pong, check nonce matches.
  66. let pong_msg = self.pong_sub.receive().await?;
  67. if pong_msg.nonce != nonce {
  68. error!("Wrong nonce for ping reply. Disconnecting from channel.");
  69. self.channel.stop().await;
  70. return Err(Error::ChannelStopped)
  71. }
  72. let duration = start.elapsed().as_millis();
  73. debug!(target: "net", "Received Pong message {}ms from [{:?}]", duration, self.channel.address());
  74. }
  75. }
  76. /// Waits for ping, then replies with pong. Copies ping's nonce into the
  77. /// pong reply.
  78. async fn reply_to_ping(self: Arc<Self>) -> Result<()> {
  79. debug!(target: "net", "ProtocolPing::reply_to_ping() [START]");
  80. loop {
  81. // Wait for ping, reply with pong that has a matching nonce.
  82. let ping = self.ping_sub.receive().await?;
  83. debug!(target: "net", "ProtocolPing::reply_to_ping() received Ping message");
  84. // Send pong message.
  85. let pong = message::PongMessage { nonce: ping.nonce };
  86. self.channel.clone().send(pong).await?;
  87. debug!(target: "net", "ProtocolPing::reply_to_ping() sent Pong reply");
  88. }
  89. }
  90. fn random_nonce() -> u32 {
  91. let mut rng = rand::thread_rng();
  92. rng.gen()
  93. }
  94. }
  95. #[async_trait]
  96. impl ProtocolBase for ProtocolPing {
  97. /// Starts ping-pong keep-alive messages exchange. Runs ping-pong in the
  98. /// protocol task manager, then queues the reply. Sends out a ping and
  99. /// waits for pong reply. Waits for ping and replies with a pong.
  100. async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
  101. debug!(target: "net", "ProtocolPing::start() [START]");
  102. self.jobsman.clone().start(executor.clone());
  103. self.jobsman.clone().spawn(self.clone().run_ping_pong(), executor.clone()).await;
  104. self.jobsman.clone().spawn(self.reply_to_ping(), executor).await;
  105. debug!(target: "net", "ProtocolPing::start() [END]");
  106. Ok(())
  107. }
  108. fn name(&self) -> &'static str {
  109. "ProtocolPing"
  110. }
  111. }