atm0s_sdn_network/base/
control.rs1use atm0s_sdn_identity::NodeId;
2use bincode::Options;
3use serde::{Deserialize, Serialize};
4
5use super::Authorization;
6
7const MSG_TIMEOUT_MS: u64 = 10000;
8
9#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
10pub enum NeighboursConnectError {
11 AlreadyConnected,
12 InvalidSignature,
13 InvalidData,
14 InvalidState,
15 Timeout,
16}
17
18#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
19pub enum NeighboursDisconnectReason {
20 Shutdown,
21 Other,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
25pub enum NeighboursControlCmds {
26 ConnectRequest { to: NodeId, session: u64, handshake: Vec<u8> },
27 ConnectResponse { session: u64, result: Result<Vec<u8>, NeighboursConnectError> },
28 Ping { session: u64, seq: u64, sent_ms: u64 },
29 Pong { session: u64, seq: u64, sent_ms: u64 },
30 DisconnectRequest { session: u64, reason: NeighboursDisconnectReason },
31 DisconnectResponse { session: u64 },
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct NeighboursControl {
36 pub from: NodeId,
37 pub cmd: Vec<u8>,
38 pub signature: Vec<u8>,
39}
40
41impl NeighboursControl {
42 #[allow(clippy::result_unit_err)]
43 pub fn validate(&self, now: u64, auth: &dyn Authorization) -> Result<NeighboursControlCmds, ()> {
44 auth.validate(self.from, &self.cmd, &self.signature).ok_or(())?;
45 let (ts, cmd) = bincode::DefaultOptions::new().with_limit(1499).deserialize::<(u64, NeighboursControlCmds)>(&self.cmd).map_err(|_| ())?;
46 if ts + MSG_TIMEOUT_MS < now {
47 return Err(());
48 }
49 Ok(cmd)
50 }
51
52 pub fn build(now: u64, from: NodeId, cmd: NeighboursControlCmds, auth: &dyn Authorization) -> Self {
53 let cmd = bincode::DefaultOptions::new().with_limit(1499).serialize(&(now, cmd)).unwrap();
54 let signature = auth.sign(&cmd);
55 Self { from, cmd, signature }
56 }
57}
58
59impl TryFrom<&[u8]> for NeighboursControl {
60 type Error = ();
61
62 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
63 if value.first() == Some(&255) {
64 bincode::DefaultOptions::new().with_limit(1499).deserialize(&value[1..]).map_err(|_| ())
65 } else {
66 Err(())
67 }
68 }
69}
70
71impl TryInto<Vec<u8>> for &NeighboursControl {
72 type Error = ();
73
74 fn try_into(self) -> Result<Vec<u8>, Self::Error> {
75 let mut buf = Vec::with_capacity(1500);
76 buf.push(255);
77 bincode::DefaultOptions::new().with_limit(1499).serialize_into(&mut buf, &self).map_err(|_| ())?;
78 Ok(buf)
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use crate::secure::StaticKeyAuthorization;
85
86 use super::*;
87
88 #[test]
89 fn test_neighbours_control() {
90 let auth = StaticKeyAuthorization::new("demo_key");
91 let cmd = NeighboursControlCmds::Ping {
92 session: 1000,
93 seq: 100,
94 sent_ms: 100,
95 };
96 let control = NeighboursControl::build(0, 1, cmd.clone(), &auth);
97 assert_eq!(control.validate(0, &auth), Ok(cmd));
98 assert_eq!(control.validate(MSG_TIMEOUT_MS + 1, &auth), Err(()));
99 }
100}