hopr_transport_network/
messaging.rs1use crate::errors::NetworkingError::MessagingError;
2use hopr_crypto_sphinx::derivation::derive_ping_pong;
3use hopr_primitive_types::errors::GeneralError;
4use hopr_primitive_types::prelude::BytesEncodable;
5use serde::{Deserialize, Serialize};
6
7use crate::errors::Result;
8
9#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
12pub enum ControlMessage {
13 Ping(PingMessage),
15 Pong(PingMessage),
17}
18
19impl ControlMessage {
20 pub fn generate_ping_request() -> Self {
22 let mut ping = PingMessage::default();
23 ping.nonce.copy_from_slice(&derive_ping_pong(None));
24
25 Self::Ping(ping)
26 }
27
28 pub fn generate_pong_response(request: &ControlMessage) -> Result<Self> {
30 match request {
31 ControlMessage::Ping(ping) => {
32 let mut pong = PingMessage::default();
33 pong.nonce.copy_from_slice(&derive_ping_pong(Some(ping.nonce())));
34 Ok(Self::Pong(pong))
35 }
36 ControlMessage::Pong(_) => Err(MessagingError("invalid ping message".into())),
37 }
38 }
39
40 pub fn validate_pong_response(request: &ControlMessage, response: &ControlMessage) -> Result<()> {
43 if let Self::Pong(expected_pong) = Self::generate_pong_response(request).unwrap() {
44 match response {
45 ControlMessage::Pong(received_pong) => match expected_pong.nonce.eq(&received_pong.nonce) {
46 true => Ok(()),
47 false => Err(MessagingError("pong response does not match the challenge".into())),
48 },
49 ControlMessage::Ping(_) => Err(MessagingError("invalid pong response".into())),
50 }
51 } else {
52 Err(MessagingError("request is not a valid ping message".into()))
53 }
54 }
55
56 pub fn get_ping_message(&self) -> Result<&PingMessage> {
59 match self {
60 ControlMessage::Ping(m) | ControlMessage::Pong(m) => Ok(m),
61 }
62 }
63}
64
65#[derive(Clone, Debug, Eq, PartialEq, Default, Serialize, Deserialize)]
66pub struct PingMessage {
67 nonce: [u8; hopr_crypto_sphinx::derivation::PING_PONG_NONCE_SIZE],
68}
69
70impl PingMessage {
71 pub fn nonce(&self) -> &[u8] {
73 &self.nonce
74 }
75}
76
77impl From<PingMessage> for [u8; PING_MESSAGE_LEN] {
78 fn from(value: PingMessage) -> Self {
79 let mut ret = [0u8; PING_MESSAGE_LEN];
80 ret[0..PING_MESSAGE_LEN].copy_from_slice(&value.nonce);
81 ret
82 }
83}
84
85impl TryFrom<&[u8]> for PingMessage {
86 type Error = GeneralError;
87
88 fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
89 if value.len() >= Self::SIZE {
90 let mut ret = PingMessage::default();
91 ret.nonce.copy_from_slice(&value[0..Self::SIZE]);
92 Ok(ret)
93 } else {
94 Err(GeneralError::ParseError("PingMessage".into()))
95 }
96 }
97}
98
99const PING_MESSAGE_LEN: usize = hopr_crypto_sphinx::derivation::PING_PONG_NONCE_SIZE;
100impl BytesEncodable<PING_MESSAGE_LEN> for PingMessage {}
101
102#[cfg(test)]
103mod tests {
104 use crate::messaging::ControlMessage::{Ping, Pong};
105 use crate::messaging::{ControlMessage, PingMessage};
106 use hopr_primitive_types::prelude::BytesEncodable;
107
108 #[test]
109 fn test_ping_pong_roundtrip() {
110 let sent_req_s: Box<[u8]>;
112 let sent_req: ControlMessage;
113 {
114 sent_req = ControlMessage::generate_ping_request();
115 sent_req_s = sent_req.get_ping_message().unwrap().clone().into_boxed();
116 }
117
118 let sent_resp_s: Box<[u8]>;
120 {
121 let recv_req = PingMessage::try_from(sent_req_s.as_ref()).unwrap();
122 let send_resp = ControlMessage::generate_pong_response(&Ping(recv_req)).unwrap();
123 sent_resp_s = send_resp.get_ping_message().unwrap().clone().into_boxed();
124 }
125
126 {
128 let recv_resp = PingMessage::try_from(sent_resp_s.as_ref()).unwrap();
129 assert!(ControlMessage::validate_pong_response(&sent_req, &Pong(recv_resp)).is_ok());
130 }
131 }
132}