stun_rs/attributes/mobility/
mobility_ticket.rs1use std::sync::Arc;
2
3use crate::attributes::{stunt_attribute, DecodeAttributeValue, EncodeAttributeValue};
4use crate::common::check_buffer_boundaries;
5use crate::context::{AttributeDecoderContext, AttributeEncoderContext};
6use crate::error::StunError;
7
8const MOBILITY_TICKET: u16 = 0x8030;
9
10#[derive(Debug, PartialEq, Eq, Clone)]
24pub struct MobilityTicket(Arc<Vec<u8>>);
25
26impl MobilityTicket {
27 pub fn new<T>(ticket: T) -> Self
33 where
34 T: AsRef<[u8]>,
35 {
36 let vec = ticket.as_ref().to_vec();
37 Self(Arc::new(vec))
38 }
39
40 pub fn value(&self) -> &[u8] {
42 self.0.as_slice()
43 }
44}
45
46impl<const N: usize> PartialEq<[u8; N]> for MobilityTicket {
47 fn eq(&self, other: &[u8; N]) -> bool {
48 self.value() == other
49 }
50}
51
52impl AsRef<[u8]> for MobilityTicket {
53 fn as_ref(&self) -> &[u8] {
54 self.0.as_ref()
55 }
56}
57
58impl From<&[u8]> for MobilityTicket {
59 fn from(value: &[u8]) -> Self {
60 MobilityTicket::new(value)
61 }
62}
63
64impl crate::attributes::AsVerifiable for MobilityTicket {}
65
66impl DecodeAttributeValue for MobilityTicket {
67 fn decode(ctx: AttributeDecoderContext) -> Result<(Self, usize), StunError> {
68 let raw_value = ctx.raw_value();
69
70 Ok((MobilityTicket::new(raw_value), raw_value.len()))
71 }
72}
73
74impl EncodeAttributeValue for MobilityTicket {
75 fn encode(&self, mut ctx: AttributeEncoderContext) -> Result<usize, StunError> {
76 let ticket = self.value();
77 let ticket_len = ticket.len();
78 let buffer = ctx.raw_value_mut();
79 check_buffer_boundaries(buffer, ticket_len)?;
80 buffer[..ticket_len].clone_from_slice(self.value());
81
82 Ok(ticket_len)
83 }
84}
85
86stunt_attribute!(MobilityTicket, MOBILITY_TICKET);
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use crate::error::StunErrorType;
92 use crate::StunAttribute;
93
94 #[test]
95 fn constructor() {
96 let ticket = MobilityTicket::new([0x0; 0]);
97 assert_eq!(ticket.value().len(), 0);
98
99 let ticket = MobilityTicket::new([0x1; 1]);
100 assert_eq!(ticket.value().len(), 1);
101 assert_eq!(ticket, [0x1; 1]);
102
103 let ticket = MobilityTicket::new([0x1; 10]);
104 assert_eq!(ticket.value().len(), 10);
105 assert_eq!(ticket, [0x1; 10]);
106 assert_eq!(ticket.as_ref(), [0x1; 10]);
107
108 let ticket2 = MobilityTicket::from(ticket.value());
109 assert_eq!(ticket, ticket2);
110
111 let ticket2 = MobilityTicket::new([0x2; 5]);
112 assert_ne!(ticket, ticket2);
113 }
114
115 #[test]
116 fn decode_mobility_ticket_value() {
117 let dummy_msg = [];
118 let buffer = [];
119 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
120
121 let (mobility_ticket, size) =
122 MobilityTicket::decode(ctx).expect("Can not decode MOBILITY-TICKET");
123 assert_eq!(size, 0);
124 assert_eq!(mobility_ticket.value().len(), 0);
125
126 let buffer = [0x01];
127 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
128
129 let (mobility_ticket, size) =
130 MobilityTicket::decode(ctx).expect("Can not decode MOBILITY-TICKET");
131 assert_eq!(size, 1);
132 assert_eq!(mobility_ticket.value().len(), 1);
133 assert_eq!(mobility_ticket, [0x1]);
134
135 let buffer = [0x1, 0x2, 0x3, 0x4, 0x5];
136 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
137
138 let (mobility_ticket, size) =
139 MobilityTicket::decode(ctx).expect("Can not decode MOBILITY-TICKET");
140 assert_eq!(size, 5);
141 assert_eq!(mobility_ticket.value().len(), 5);
142 assert_eq!(mobility_ticket, buffer);
143 }
144
145 #[test]
146 fn encode_mobility_ticket_value() {
147 let dummy_msg: [u8; 0] = [0x0; 0];
148 let ticket = MobilityTicket::new([0x0; 0]);
149 let mut buffer = [];
150 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
151
152 let size = ticket.encode(ctx).expect("Can not encode MOBILITY-TICKET");
153 assert_eq!(size, 0);
154
155 let ticket = MobilityTicket::new([0x1; 1]);
156 let mut buffer = [0x1];
157 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
158
159 let size = ticket.encode(ctx).expect("Can not encode MOBILITY-TICKET");
160 assert_eq!(size, 1);
161 assert_eq!(buffer, [0x1]);
162
163 let ticket = MobilityTicket::new([0x1; 10]);
164 let mut buffer = [0x1; 10];
165 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
166
167 let size = ticket.encode(ctx).expect("Can not encode MOBILITY-TICKET");
168 assert_eq!(size, 10);
169 assert_eq!(buffer, [0x1; 10]);
170
171 let value = [0x1, 0x2, 0x3, 0x4, 0x5];
172 let ticket = MobilityTicket::new(value);
173 let mut buffer = [0x0; 5];
174 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
175
176 let size = ticket.encode(ctx).expect("Can not encode MOBILITY-TICKET");
177 assert_eq!(size, 5);
178 assert_eq!(buffer, value);
179
180 let ticket = MobilityTicket::new([0x1; 10]);
181 let mut buffer = [0x0; 5];
182 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
183
184 let result = ticket.encode(ctx);
185 assert_eq!(
186 result.expect_err("Error expected"),
187 StunErrorType::SmallBuffer
188 );
189 }
190
191 #[test]
192 fn mobility_stun_attribute() {
193 let attr = StunAttribute::MobilityTicket(MobilityTicket::new([0x1; 10]));
194 assert!(attr.is_mobility_ticket());
195 assert!(attr.as_mobility_ticket().is_ok());
196 assert!(attr.as_unknown().is_err());
197
198 assert!(!attr.attribute_type().is_comprehension_required());
199 assert!(attr.attribute_type().is_comprehension_optional());
200
201 let dbg_fmt = format!("{:?}", attr);
202 assert_eq!(
203 "MobilityTicket(MobilityTicket([1, 1, 1, 1, 1, 1, 1, 1, 1, 1]))",
204 dbg_fmt
205 );
206 }
207}