1use crate::attributes::{stunt_attribute, DecodeAttributeValue, EncodeAttributeValue};
2use crate::common::check_buffer_boundaries;
3use crate::context::{AttributeDecoderContext, AttributeEncoderContext};
4use crate::StunError;
5use std::convert::TryFrom;
6
7const RESERVATION_TOKEN: u16 = 0x0022;
8const RESERVATION_TOKEN_SIZE: usize = 8;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct ReservationToken([u8; RESERVATION_TOKEN_SIZE]);
25
26impl ReservationToken {
27 pub fn token(&self) -> &[u8] {
29 &self.0
30 }
31}
32
33impl AsRef<[u8]> for ReservationToken {
34 fn as_ref(&self) -> &[u8] {
35 &self.0[..]
36 }
37}
38
39impl From<&[u8; RESERVATION_TOKEN_SIZE]> for ReservationToken {
40 fn from(buff: &[u8; RESERVATION_TOKEN_SIZE]) -> Self {
41 Self(*buff)
42 }
43}
44
45impl From<[u8; RESERVATION_TOKEN_SIZE]> for ReservationToken {
46 fn from(buff: [u8; RESERVATION_TOKEN_SIZE]) -> Self {
47 Self(buff)
48 }
49}
50
51impl DecodeAttributeValue for ReservationToken {
52 fn decode(ctx: AttributeDecoderContext) -> Result<(Self, usize), StunError> {
53 let raw_value = ctx.raw_value();
54 check_buffer_boundaries(raw_value, RESERVATION_TOKEN_SIZE)?;
55 let token =
56 <&[u8; RESERVATION_TOKEN_SIZE]>::try_from(&raw_value[..RESERVATION_TOKEN_SIZE])?;
57 Ok((ReservationToken::from(token), RESERVATION_TOKEN_SIZE))
58 }
59}
60
61impl EncodeAttributeValue for ReservationToken {
62 fn encode(&self, mut ctx: AttributeEncoderContext) -> Result<usize, StunError> {
63 let raw_value = ctx.raw_value_mut();
64 check_buffer_boundaries(raw_value, RESERVATION_TOKEN_SIZE)?;
65 raw_value[..RESERVATION_TOKEN_SIZE].clone_from_slice(&self.0);
66 Ok(RESERVATION_TOKEN_SIZE)
67 }
68}
69
70impl crate::attributes::AsVerifiable for ReservationToken {}
71
72stunt_attribute!(ReservationToken, RESERVATION_TOKEN);
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77 use crate::error::StunErrorType;
78 use crate::StunAttribute;
79
80 #[test]
81 fn constructor() {
82 let token = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
83 let attr = ReservationToken::from(token);
84 assert_eq!(attr.as_ref(), token);
85 }
86
87 #[test]
88 fn decode_reservation_token_constructor() {
89 let token = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
90 let attr = ReservationToken::from(token);
91 assert_eq!(token, attr.token());
92 }
93
94 #[test]
95 fn decode_reservation_token_value() {
96 let dummy_msg = [];
97 let buffer = [];
98 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
99 let result = ReservationToken::decode(ctx);
100 assert_eq!(
101 result.expect_err("Error expected"),
102 StunErrorType::SmallBuffer
103 );
104
105 let buffer = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
106 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
107 let result = ReservationToken::decode(ctx);
108 assert_eq!(
109 result.expect_err("Error expected"),
110 StunErrorType::SmallBuffer
111 );
112
113 let buffer = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
114 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
115 let (attr, size) = ReservationToken::decode(ctx).expect("Can not decode ReservationToken");
116 assert_eq!(size, 8);
117 assert_eq!(attr.token(), buffer);
118 }
119
120 #[test]
121 fn encode_reservation_token_value() {
122 let token = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
123 let attr = ReservationToken::from(token);
124 let dummy_msg = [];
125
126 let mut buffer = [];
127 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
128 let result = attr.encode(ctx);
129 assert_eq!(
130 result.expect_err("Error expected"),
131 StunErrorType::SmallBuffer
132 );
133
134 let mut buffer: [u8; 7] = [0xFF; 7];
135 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
136 let result = attr.encode(ctx);
137 assert_eq!(
138 result.expect_err("Error expected"),
139 StunErrorType::SmallBuffer
140 );
141
142 let mut buffer: [u8; 8] = [0xFF; 8];
143 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
144 let result = attr.encode(ctx);
145 assert_eq!(result, Ok(8));
146 assert_eq!(buffer, token);
147 }
148
149 #[test]
150 fn reservatiom_token_stunt_attribute() {
151 let token = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
152 let attr = StunAttribute::ReservationToken(ReservationToken::from(token));
153 assert!(attr.is_reservation_token());
154 assert!(attr.as_reservation_token().is_ok());
155 assert!(attr.as_unknown().is_err());
156
157 assert!(attr.attribute_type().is_comprehension_required());
158 assert!(!attr.attribute_type().is_comprehension_optional());
159
160 let dbg_fmt = format!("{:?}", attr);
161 assert_eq!(
162 "ReservationToken(ReservationToken([1, 2, 3, 4, 5, 6, 7, 8]))",
163 dbg_fmt
164 );
165 }
166}