atm0s_sdn_network/base/
control.rs

1use 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}