message.rs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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 darkfi_serial::{Decodable, Encodable, SerialDecodable, SerialEncodable, VarInt};
  19. use futures::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
  20. use log::debug;
  21. use url::Url;
  22. use crate::{Error, Result};
  23. const MAGIC_BYTES: [u8; 4] = [0xd9, 0xef, 0xb6, 0x7d];
  24. /// Generic message template.
  25. pub trait Message: 'static + Send + Sync + Encodable + Decodable {
  26. const NAME: &'static str;
  27. }
  28. #[macro_export]
  29. macro_rules! impl_p2p_message {
  30. ($st:ty, $nm:expr) => {
  31. impl Message for $st {
  32. const NAME: &'static str = $nm;
  33. }
  34. };
  35. }
  36. /// Outbound keepalive message.
  37. #[derive(Debug, Copy, Clone, SerialEncodable, SerialDecodable)]
  38. pub struct PingMessage {
  39. pub nonce: u16,
  40. }
  41. impl_p2p_message!(PingMessage, "ping");
  42. /// Inbound keepalive message.
  43. #[derive(Debug, Copy, Clone, SerialEncodable, SerialDecodable)]
  44. pub struct PongMessage {
  45. pub nonce: u16,
  46. }
  47. impl_p2p_message!(PongMessage, "pong");
  48. /// Requests address of outbound connecction.
  49. #[derive(Debug, Copy, Clone, SerialEncodable, SerialDecodable)]
  50. pub struct GetAddrsMessage {
  51. /// Maximum number of addresses to receive
  52. pub max: u32,
  53. }
  54. impl_p2p_message!(GetAddrsMessage, "getaddr");
  55. /// Sends address information to inbound connection.
  56. /// Response to `GetAddrsMessage`.
  57. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  58. pub struct AddrsMessage {
  59. pub addrs: Vec<Url>,
  60. }
  61. impl_p2p_message!(AddrsMessage, "addr");
  62. /// Requests version information of outbound connection.
  63. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  64. pub struct VersionMessage {
  65. /// Only used for debugging. Compromises privacy when set.
  66. pub node_id: String,
  67. }
  68. impl_p2p_message!(VersionMessage, "version");
  69. /// Sends version information to inbound connection.
  70. /// Response to `VersionMessage`.
  71. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  72. pub struct VerackMessage {
  73. /// App version
  74. pub app_version: semver::Version,
  75. }
  76. impl_p2p_message!(VerackMessage, "verack");
  77. /// Packets are the base type read from the network.
  78. /// Converted to messages and passed to event loop.
  79. #[derive(Debug, SerialEncodable, SerialDecodable)]
  80. pub struct Packet {
  81. pub command: String,
  82. pub payload: Vec<u8>,
  83. }
  84. /// Reads and decodes an inbound payload from the given async stream.
  85. /// Returns decoded [`Packet`].
  86. pub async fn read_packet<R: AsyncRead + Unpin + Sized>(stream: &mut R) -> Result<Packet> {
  87. // Packets should have a 4 byte header of magic digits.
  88. // This is used for network debugging.
  89. let mut magic = [0u8; 4];
  90. debug!(target: "net::message", "Reading magic...");
  91. stream.read_exact(&mut magic).await?;
  92. debug!(target: "net::message", "Read magic {:?}", magic);
  93. if magic != MAGIC_BYTES {
  94. debug!(target: "net::message", "Error: Magic bytes mismatch");
  95. return Err(Error::MalformedPacket)
  96. }
  97. // The type of the message.
  98. let command_len = VarInt::decode_async(stream).await?.0 as usize;
  99. let mut cmd = vec![0u8; command_len];
  100. stream.read_exact(&mut cmd).await?;
  101. let command = String::from_utf8(cmd)?;
  102. debug!(target: "net::message", "Read command: {}", command);
  103. // The message-dependent data (see message types)
  104. let payload_len = VarInt::decode_async(stream).await?.0 as usize;
  105. let mut payload = vec![0u8; payload_len];
  106. stream.read_exact(&mut payload).await?;
  107. debug!(target: "net::message", "Read payload {} bytes", payload_len);
  108. Ok(Packet { command, payload })
  109. }
  110. /// Sends an outbound packet by writing data to the given async stream.
  111. /// Returns the total written bytes.
  112. pub async fn send_packet<W: AsyncWrite + Unpin + Sized>(
  113. stream: &mut W,
  114. packet: Packet,
  115. ) -> Result<usize> {
  116. assert!(!packet.command.is_empty());
  117. assert!(!packet.payload.is_empty());
  118. assert!(std::mem::size_of::<usize>() <= std::mem::size_of::<u64>());
  119. let mut written: usize = 0;
  120. debug!(target: "net::message", "Sending magic...");
  121. stream.write_all(&MAGIC_BYTES).await?;
  122. written += MAGIC_BYTES.len();
  123. debug!(target: "net::message", "Sent magic");
  124. debug!(target: "net::message", "Sending command...");
  125. written += VarInt(packet.command.len() as u64).encode_async(stream).await?;
  126. let cmd_ref = packet.command.as_bytes();
  127. stream.write_all(cmd_ref).await?;
  128. written += cmd_ref.len();
  129. debug!(target: "net::message", "Sent command: {}", packet.command);
  130. debug!(target: "net::message", "Sending payload...");
  131. written += VarInt(packet.payload.len() as u64).encode_async(stream).await?;
  132. stream.write_all(&packet.payload).await?;
  133. written += packet.payload.len();
  134. debug!(target: "net::message", "Sent payload {} bytes", packet.payload.len() as u64);
  135. Ok(written)
  136. }