twamp_rs/twamp_control/
server_start.rs

1use super::accept::Accept;
2use crate::timestamp::timestamp::TimeStamp;
3use deku::prelude::*;
4use rand::random;
5use std::time::Duration;
6
7/// Sent by Server to Control-Client after receiving a [Set-Up-Response](crate::set_up_response::SetUpResponse) command.
8#[derive(Clone, Debug, PartialEq, DekuRead, DekuWrite)]
9#[deku(endian = "big")]
10pub struct ServerStart {
11    /// MBZ (Must Be Zero).
12    #[deku(assert_eq = "[0u8; 15]")]
13    mbz_start: [u8; 15],
14
15    /// Indicates Server's willingness to continue. See [list of possible values](Accept).
16    accept: Accept,
17
18    /// Generated randomly. Unused in
19    /// [unauthenticated mode](crate::security_mode::Mode::Unauthenticated).
20    server_iv: [u8; 16],
21
22    /// The time when the Server binary was executed.
23    start_time: TimeStamp,
24
25    /// MBZ (Must Be Zero).
26    #[deku(assert_eq = "[0u8; 8]")]
27    mbz_end: [u8; 8],
28}
29
30impl ServerStart {
31    /// Create instance with provided accept value.
32    pub fn new(accept: Accept, start_time: Duration) -> Self {
33        ServerStart {
34            mbz_start: [0; 15],
35            accept,
36            server_iv: Vec::from([0; 16])
37                .iter()
38                .map(|_| random())
39                .collect::<Vec<u8>>()
40                .try_into()
41                .unwrap(),
42            start_time: TimeStamp::try_from(start_time)
43                .expect("should have converted duration to timestamp."),
44            mbz_end: [0; 8],
45        }
46    }
47
48    /// Returns the value of Accept field.
49    pub fn accept(&self) -> &Accept {
50        &self.accept
51    }
52
53    /// Returns the value of Start-Time field.
54    pub fn start_time(&self) -> &TimeStamp {
55        &self.start_time
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use std::collections::HashSet;
63
64    const SERVER_START_LENGTH_IN_BYTES: usize = 48;
65    const TIME: Duration = Duration::new(1713023152, 123456789);
66
67    #[test]
68    fn create_server_start_with_accept_ok() {
69        let accept = Accept::Ok;
70        let server_start = ServerStart::new(accept, TIME);
71        let server_start_accept: u8 = server_start.accept.into();
72        assert_eq!(server_start_accept, accept.into());
73    }
74
75    #[test]
76    fn create_server_start_with_accept_failure() {
77        let accept = Accept::Failure;
78        let server_start = ServerStart::new(accept, TIME);
79        let server_start_accept: u8 = server_start.accept.into();
80        assert_eq!(server_start_accept, accept.into());
81    }
82
83    #[test]
84    fn create_server_start_with_accept_internal_error() {
85        let accept = Accept::InternalError;
86        let server_start = ServerStart::new(accept, TIME);
87        let server_start_accept: u8 = server_start.accept.into();
88        assert_eq!(server_start_accept, accept.into());
89    }
90
91    #[test]
92    fn create_server_start_with_accept_not_supported() {
93        let accept = Accept::NotSupported;
94        let server_start = ServerStart::new(accept, TIME);
95        let server_start_accept: u8 = server_start.accept.into();
96        assert_eq!(server_start_accept, accept.into());
97    }
98
99    #[test]
100    fn create_server_start_with_accept_permanent_resource_limitation() {
101        let accept = Accept::PermanentResourceLimitation;
102        let server_start = ServerStart::new(accept, TIME);
103        let server_start_accept: u8 = server_start.accept.into();
104        assert_eq!(server_start_accept, accept.into());
105    }
106
107    #[test]
108    fn create_server_start_with_accept_temporary_resource_limitation() {
109        let accept = Accept::TemporaryResourceLimitation;
110        let server_start = ServerStart::new(accept, TIME);
111        let server_start_accept: u8 = server_start.accept.into();
112        assert_eq!(server_start_accept, accept.into());
113    }
114
115    #[test]
116    fn first_mbz_are_zeros() {
117        let server_start = ServerStart::new(Accept::Ok, TIME);
118        assert!(server_start.mbz_start == [0; 15]);
119    }
120
121    #[test]
122    fn last_mbz_are_zeros() {
123        let server_start = ServerStart::new(Accept::Ok, TIME);
124        assert!(server_start.mbz_end == [0; 8]);
125    }
126
127    #[test]
128    fn server_iv_is_random() {
129        let server_start = ServerStart::new(Accept::Ok, TIME);
130        let server_iv_bytes_unique = server_start.server_iv.iter().collect::<HashSet<_>>();
131        assert!(server_iv_bytes_unique.len() > 1);
132    }
133
134    #[test]
135    fn should_serialize_to_correct_bytes() {
136        let server_start = ServerStart::new(Accept::Ok, TIME);
137        let encoded = server_start.to_bytes().unwrap();
138        assert_eq!(encoded.len(), SERVER_START_LENGTH_IN_BYTES);
139    }
140
141    #[test]
142    fn should_deserialize_to_correct_struct() {
143        let server_start = ServerStart::new(Accept::Ok, TIME);
144        let encoded = server_start.to_bytes().unwrap();
145        let (_rest, val) = ServerStart::from_bytes((&encoded, 0)).unwrap();
146        assert_eq!(val, server_start);
147    }
148}