rtc_stun/message.rs
1//! The STUN message: header, attributes, and encoding.
2//!
3//! A [`Message`](crate::message::Message) is a class and method ([`MessageType`](crate::message::MessageType)), a 96-bit [`TransactionId`](crate::message::TransactionId), and a
4//! list of attributes. Build one by applying [`Setter`](crate::message::Setter)s, read one back with [`Getter`](crate::message::Getter)s, and
5//! move it across the wire with `marshal`/`unmarshal`.
6//!
7//! Two attributes are special, because their value covers the *encoded* message: `FINGERPRINT`
8//! and `MESSAGE-INTEGRITY` must be appended last and are validated through [`Checker`](crate::message::Checker). That is
9//! why [`Message::raw`](crate::message::Message::raw) is kept alongside the parsed attributes — those checks are computed over
10//! it rather than over a re-encoding.
11
12#[cfg(test)]
13mod message_test;
14
15use crate::attributes::*;
16use shared::error::*;
17
18use base64::prelude::*;
19use rand::RngExt;
20use std::fmt;
21use std::io::{Read, Write};
22
23/// Fixed value that aids in distinguishing STUN packets
24/// from packets of other protocols when STUN is multiplexed with those
25/// other protocols on the same Port.
26///
27/// The magic cookie field MUST contain the fixed value 0x2112A442 in
28/// network byte order.
29///
30/// Defined in "STUN Message Structure", section 6.
31pub const MAGIC_COOKIE: u32 = 0x2112A442;
32/// Bytes of type and length preceding each attribute value.
33pub const ATTRIBUTE_HEADER_SIZE: usize = 4;
34/// Bytes in the STUN message header.
35pub const MESSAGE_HEADER_SIZE: usize = 20;
36
37/// Length of transaction id array (in bytes).
38/// 96 bit.
39pub const TRANSACTION_ID_SIZE: usize = 12;
40
41#[derive(PartialEq, Eq, Hash, Copy, Clone, Default, Debug)]
42/// A 96-bit transaction id, which pairs a response with its request.
43pub struct TransactionId(pub [u8; TRANSACTION_ID_SIZE]);
44
45impl TransactionId {
46 /// Creates a random transaction ID with `rand`'s cryptographically secure thread RNG.
47 ///
48 /// Transaction IDs remain independent of [`crypto::RTCCryptoProvider`] because ordinary STUN
49 /// message construction does not otherwise own a provider.
50 pub fn new() -> Self {
51 let mut b = TransactionId([0u8; TRANSACTION_ID_SIZE]);
52 rand::rng().fill(&mut b.0);
53 b
54 }
55}
56
57impl Setter for TransactionId {
58 fn add_to(&self, m: &mut Message) -> Result<()> {
59 m.transaction_id = *self;
60 m.write_transaction_id();
61 Ok(())
62 }
63}
64
65/// Interfaces that are implemented by message attributes, shorthands for them,
66/// or helpers for message fields as type or transaction id.
67pub trait Setter {
68 // Setter sets *Message attribute.
69 /// Encodes this value into `m` as an attribute.
70 ///
71 /// # Errors
72 ///
73 /// Fails if the value cannot be encoded, or the message has no room for it.
74 fn add_to(&self, m: &mut Message) -> Result<()>;
75}
76
77/// Getter parses attribute from *Message.
78pub trait Getter {
79 /// Decodes this value from the corresponding attribute of `m`.
80 ///
81 /// # Errors
82 ///
83 /// Fails if the attribute is absent or malformed.
84 fn get_from(&mut self, m: &Message) -> Result<()>;
85}
86
87/// Checker checks *Message attribute.
88pub trait Checker {
89 /// Validates this value against `m`.
90 ///
91 /// Used by attributes whose value depends on the encoded message, such as
92 /// `MESSAGE-INTEGRITY` and `FINGERPRINT`.
93 ///
94 /// # Errors
95 ///
96 /// Fails if the check does not hold.
97 fn check(&self, m: &Message) -> Result<()>;
98}
99
100/// Is_stun_message returns true if b looks like STUN message.
101/// Useful for multiplexing. is_stun_message does not guarantee
102/// that decoding will be successful.
103pub fn is_stun_message(b: &[u8]) -> bool {
104 b.len() >= MESSAGE_HEADER_SIZE && u32::from_be_bytes([b[4], b[5], b[6], b[7]]) == MAGIC_COOKIE
105}
106// Message represents a single STUN packet. It uses aggressive internal
107// buffering to enable zero-allocation encoding and decoding,
108// so there are some usage constraints:
109//
110// Message, its fields, results of m.Get or any attribute a.GetFrom
111// are valid only until Message.Raw is not modified.
112#[derive(Default, Debug, Clone)]
113/// A STUN message: type, transaction id, and attributes, plus the encoded bytes.
114pub struct Message {
115 /// The message class and method — request, response or indication, and which method.
116 pub typ: MessageType,
117 /// The attribute section's length in bytes, header excluded.
118 pub length: u32, // len(Raw) not including header
119 /// The transaction id, echoed by the responder.
120 pub transaction_id: TransactionId,
121 /// The message's attributes.
122 pub attributes: Attributes,
123 /// The encoded message. Attributes whose value covers the message are computed over this.
124 pub raw: Vec<u8>,
125}
126
127impl fmt::Display for Message {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 let t_id = BASE64_STANDARD.encode(self.transaction_id.0);
130 write!(
131 f,
132 "{} l={} attrs={} id={}",
133 self.typ,
134 self.length,
135 self.attributes.0.len(),
136 t_id
137 )
138 }
139}
140
141// Equal returns true if Message b equals to m.
142// Ignores m.Raw.
143impl PartialEq for Message {
144 fn eq(&self, other: &Self) -> bool {
145 if self.typ != other.typ {
146 return false;
147 }
148 if self.transaction_id != other.transaction_id {
149 return false;
150 }
151 if self.length != other.length {
152 return false;
153 }
154 if self.attributes != other.attributes {
155 return false;
156 }
157 true
158 }
159}
160
161const DEFAULT_RAW_CAPACITY: usize = 120;
162
163impl Setter for Message {
164 // add_to sets b.TransactionID to m.TransactionID.
165 //
166 // Implements Setter to aid in crafting responses.
167 fn add_to(&self, b: &mut Message) -> Result<()> {
168 b.transaction_id = self.transaction_id;
169 b.write_transaction_id();
170 Ok(())
171 }
172}
173
174impl Message {
175 /// New returns *Message with pre-allocated Raw.
176 pub fn new() -> Self {
177 Message {
178 raw: {
179 let mut raw = Vec::with_capacity(DEFAULT_RAW_CAPACITY);
180 raw.extend_from_slice(&[0; MESSAGE_HEADER_SIZE]);
181 raw
182 },
183 ..Default::default()
184 }
185 }
186
187 /// Marshal_binary implements the encoding.BinaryMarshaler interface.
188 pub fn marshal_binary(&self) -> Result<Vec<u8>> {
189 // We can't return m.Raw, allocation is expected by implicit interface
190 // contract induced by other implementations.
191 Ok(self.raw.clone())
192 }
193
194 /// Unmarshal_binary implements the encoding.BinaryUnmarshaler interface.
195 pub fn unmarshal_binary(&mut self, data: &[u8]) -> Result<()> {
196 // We can't retain data, copy is expected by interface contract.
197 self.raw.clear();
198 self.raw.extend_from_slice(data);
199 self.decode()
200 }
201
202 /// Replaces the transaction ID using `rand`'s cryptographically secure thread RNG.
203 ///
204 /// Transaction IDs remain independent of [`crypto::RTCCryptoProvider`] because a general
205 /// [`Message`] does not otherwise own a provider.
206 pub fn new_transaction_id(&mut self) -> Result<()> {
207 rand::rng().fill(&mut self.transaction_id.0);
208 self.write_transaction_id();
209 Ok(())
210 }
211
212 /// Reset resets Message, attributes and underlying buffer length.
213 pub fn reset(&mut self) {
214 self.raw.clear();
215 self.length = 0;
216 self.attributes.0.clear();
217 }
218
219 // grow ensures that internal buffer has n length.
220 fn grow(&mut self, n: usize, resize: bool) {
221 if self.raw.len() >= n {
222 if resize {
223 self.raw.resize(n, 0);
224 }
225 return;
226 }
227 self.raw.extend_from_slice(&vec![0; n - self.raw.len()]);
228 }
229
230 /// Add appends new attribute to message. Not goroutine-safe.
231 ///
232 /// Value of attribute is copied to internal buffer so
233 /// it is safe to reuse v.
234 pub fn add(&mut self, t: AttrType, v: &[u8]) {
235 // Allocating buffer for TLV (type-length-value).
236 // T = t, L = len(v), V = v.
237 // m.Raw will look like:
238 // [0:20] <- message header
239 // [20:20+m.Length] <- existing message attributes
240 // [20+m.Length:20+m.Length+len(v) + 4] <- allocated buffer for new TLV
241 // [first:last] <- same as previous
242 // [0 1|2 3|4 4 + len(v)] <- mapping for allocated buffer
243 // T L V
244 let alloc_size = ATTRIBUTE_HEADER_SIZE + v.len(); // ~ len(TLV) = len(TL) + len(V)
245 let first = MESSAGE_HEADER_SIZE + self.length as usize; // first byte number
246 let mut last = first + alloc_size; // last byte number
247 self.grow(last, true); // growing cap(Raw) to fit TLV
248 self.length += alloc_size as u32; // rendering length change
249
250 // Encoding attribute TLV to allocated buffer.
251 let buf = &mut self.raw[first..last];
252 buf[0..2].copy_from_slice(&t.value().to_be_bytes()); // T
253 buf[2..4].copy_from_slice(&(v.len() as u16).to_be_bytes()); // L
254
255 let value = &mut buf[ATTRIBUTE_HEADER_SIZE..];
256 value.copy_from_slice(v); // V
257
258 let attr = RawAttribute {
259 typ: t, // T
260 length: v.len() as u16, // L
261 value: value.to_vec(), // V
262 };
263
264 // Checking that attribute value needs padding.
265 if !(attr.length as usize).is_multiple_of(PADDING) {
266 // Performing padding.
267 let bytes_to_add = nearest_padded_value_length(v.len()) - v.len();
268 last += bytes_to_add;
269 self.grow(last, true);
270 // setting all padding bytes to zero
271 // to prevent data leak from previous
272 // data in next bytes_to_add bytes
273 let buf = &mut self.raw[last - bytes_to_add..last];
274 for b in buf {
275 *b = 0;
276 }
277 self.length += bytes_to_add as u32; // rendering length change
278 }
279 self.attributes.0.push(attr);
280 self.write_length();
281 }
282
283 /// WriteLength writes m.Length to m.Raw.
284 pub fn write_length(&mut self) {
285 self.grow(4, false);
286 self.raw[2..4].copy_from_slice(&(self.length as u16).to_be_bytes());
287 }
288
289 /// WriteHeader writes header to underlying buffer. Not goroutine-safe.
290 pub fn write_header(&mut self) {
291 self.grow(MESSAGE_HEADER_SIZE, false);
292
293 self.write_type();
294 self.write_length();
295 self.raw[4..8].copy_from_slice(&MAGIC_COOKIE.to_be_bytes()); // magic cookie
296 self.raw[8..MESSAGE_HEADER_SIZE].copy_from_slice(&self.transaction_id.0);
297 // transaction ID
298 }
299
300 /// WriteTransactionID writes m.TransactionID to m.Raw.
301 pub fn write_transaction_id(&mut self) {
302 self.raw[8..MESSAGE_HEADER_SIZE].copy_from_slice(&self.transaction_id.0);
303 // transaction ID
304 }
305
306 /// WriteAttributes encodes all m.Attributes to m.
307 pub fn write_attributes(&mut self) {
308 let attributes: Vec<RawAttribute> = self.attributes.0.drain(..).collect();
309 for a in &attributes {
310 self.add(a.typ, &a.value);
311 }
312 self.attributes = Attributes(attributes);
313 }
314
315 /// WriteType writes m.Type to m.Raw.
316 pub fn write_type(&mut self) {
317 self.grow(2, false);
318 self.raw[..2].copy_from_slice(&self.typ.value().to_be_bytes()); // message type
319 }
320
321 /// SetType sets m.Type and writes it to m.Raw.
322 pub fn set_type(&mut self, t: MessageType) {
323 self.typ = t;
324 self.write_type();
325 }
326
327 /// Encode re-encodes message into m.Raw.
328 pub fn encode(&mut self) {
329 self.raw.clear();
330 self.write_header();
331 self.length = 0;
332 self.write_attributes();
333 }
334
335 /// Decode decodes m.Raw into m.
336 pub fn decode(&mut self) -> Result<()> {
337 // decoding message header
338 let buf = &self.raw;
339 if buf.len() < MESSAGE_HEADER_SIZE {
340 return Err(Error::ErrUnexpectedHeaderEof);
341 }
342
343 let t = u16::from_be_bytes([buf[0], buf[1]]); // first 2 bytes
344 let size = u16::from_be_bytes([buf[2], buf[3]]) as usize; // second 2 bytes
345 let cookie = u32::from_be_bytes([buf[4], buf[5], buf[6], buf[7]]); // last 4 bytes
346 let full_size = MESSAGE_HEADER_SIZE + size; // len(m.Raw)
347
348 if cookie != MAGIC_COOKIE {
349 return Err(Error::Other(format!(
350 "{cookie:x} is invalid magic cookie (should be {MAGIC_COOKIE:x})"
351 )));
352 }
353 if buf.len() < full_size {
354 return Err(Error::Other(format!(
355 "buffer length {} is less than {} (expected message size)",
356 buf.len(),
357 full_size
358 )));
359 }
360
361 // saving header data
362 self.typ.read_value(t);
363 self.length = size as u32;
364 self.transaction_id
365 .0
366 .copy_from_slice(&buf[8..MESSAGE_HEADER_SIZE]);
367
368 self.attributes.0.clear();
369 let mut offset = 0;
370 let mut b = &buf[MESSAGE_HEADER_SIZE..full_size];
371
372 while offset < size {
373 // checking that we have enough bytes to read header
374 if b.len() < ATTRIBUTE_HEADER_SIZE {
375 return Err(Error::Other(format!(
376 "buffer length {} is less than {} (expected header size)",
377 b.len(),
378 ATTRIBUTE_HEADER_SIZE
379 )));
380 }
381
382 let mut a = RawAttribute {
383 typ: compat_attr_type(u16::from_be_bytes([b[0], b[1]])), // first 2 bytes
384 length: u16::from_be_bytes([b[2], b[3]]), // second 2 bytes
385 ..Default::default()
386 };
387 let a_l = a.length as usize; // attribute length
388 let a_buff_l = nearest_padded_value_length(a_l); // expected buffer length (with padding)
389
390 b = &b[ATTRIBUTE_HEADER_SIZE..]; // slicing again to simplify value read
391 offset += ATTRIBUTE_HEADER_SIZE;
392 if b.len() < a_buff_l {
393 // checking size
394 return Err(Error::Other(format!(
395 "buffer length {} is less than {} (expected value size for {})",
396 b.len(),
397 a_buff_l,
398 a.typ
399 )));
400 }
401 a.value = b[..a_l].to_vec();
402 offset += a_buff_l;
403 b = &b[a_buff_l..];
404
405 self.attributes.0.push(a);
406 }
407
408 Ok(())
409 }
410
411 /// WriteTo implements WriterTo via calling Write(m.Raw) on w and returning
412 /// call result.
413 pub fn write_to<W: Write>(&self, writer: &mut W) -> Result<usize> {
414 let n = writer.write(&self.raw)?;
415 Ok(n)
416 }
417
418 /// ReadFrom implements ReaderFrom. Reads message from r into m.Raw,
419 /// Decodes it and return error if any. If m.Raw is too small, will return
420 /// ErrUnexpectedEOF, ErrUnexpectedHeaderEOF or *DecodeErr.
421 ///
422 /// Can return *DecodeErr while decoding too.
423 pub fn read_from<R: Read>(&mut self, reader: &mut R) -> Result<usize> {
424 let mut t_buf = vec![0; DEFAULT_RAW_CAPACITY];
425 let n = reader.read(&mut t_buf)?;
426 self.raw = t_buf[..n].to_vec();
427 self.decode()?;
428 Ok(n)
429 }
430
431 /// Write decodes message and return error if any.
432 ///
433 /// Any error is unrecoverable, but message could be partially decoded.
434 pub fn write(&mut self, t_buf: &[u8]) -> Result<usize> {
435 self.raw.clear();
436 self.raw.extend_from_slice(t_buf);
437 self.decode()?;
438 Ok(t_buf.len())
439 }
440
441 /// CloneTo clones m to b securing any further m mutations.
442 pub fn clone_to(&self, b: &mut Message) -> Result<()> {
443 b.raw.clear();
444 b.raw.extend_from_slice(&self.raw);
445 b.decode()
446 }
447
448 /// Contains return true if message contain t attribute.
449 pub fn contains(&self, t: AttrType) -> bool {
450 for a in &self.attributes.0 {
451 if a.typ == t {
452 return true;
453 }
454 }
455 false
456 }
457
458 /// Get returns byte slice that represents attribute value,
459 /// if there is no attribute with such type,
460 /// ErrAttributeNotFound is returned.
461 pub fn get(&self, t: AttrType) -> Result<Vec<u8>> {
462 let (v, ok) = self.attributes.get(t);
463 if ok {
464 Ok(v.value)
465 } else {
466 Err(Error::ErrAttributeNotFound)
467 }
468 }
469
470 /// Resets the message and applies `setters` to it in order, returning on the first
471 /// error.
472 ///
473 /// Each setter writes its attribute into the message as it is applied, so the encoded
474 /// [`raw`](Self::raw) bytes are complete once this returns. Order matters for setters
475 /// that cover the attributes before them — a
476 /// [`MessageIntegrity`](crate::integrity::MessageIntegrity) or
477 /// [`FINGERPRINT`](crate::fingerprint::FINGERPRINT) therefore goes last.
478 ///
479 /// ```
480 /// use rtc_stun::attributes::ATTR_SOFTWARE;
481 /// use rtc_stun::message::{BINDING_REQUEST, Message, TransactionId};
482 /// use rtc_stun::textattrs::TextAttribute;
483 ///
484 /// # fn example() -> Result<(), Box<dyn std::error::Error>> {
485 /// let mut m = Message::new();
486 /// m.build(&[
487 /// Box::new(BINDING_REQUEST),
488 /// Box::new(TransactionId::new()),
489 /// Box::new(TextAttribute::new(ATTR_SOFTWARE, "webrtc-rs".to_owned())),
490 /// ])?;
491 ///
492 /// assert!(!m.raw.is_empty());
493 /// # Ok(())
494 /// # }
495 /// ```
496 pub fn build(&mut self, setters: &[Box<dyn Setter + '_>]) -> Result<()> {
497 self.reset();
498 self.write_header();
499 for s in setters {
500 s.add_to(self)?;
501 }
502 Ok(())
503 }
504
505 /// Check applies checkers to message in batch, returning on first error.
506 pub fn check<C: Checker>(&self, checkers: &[C]) -> Result<()> {
507 for c in checkers {
508 c.check(self)?;
509 }
510 Ok(())
511 }
512
513 /// Parse applies getters to message in batch, returning on first error.
514 pub fn parse<G: Getter>(&self, getters: &mut [G]) -> Result<()> {
515 for c in getters {
516 c.get_from(self)?;
517 }
518 Ok(())
519 }
520}
521
522// MessageClass is 8-bit representation of 2-bit class of STUN Message Class.
523#[derive(Default, PartialEq, Eq, Debug, Copy, Clone)]
524/// A STUN message class: request, indication, success response or error response.
525pub struct MessageClass(u8);
526
527/// Possible values for message class in STUN Message Type.
528/// 0b00.
529pub const CLASS_REQUEST: MessageClass = MessageClass(0x00);
530/// 0b01.
531pub const CLASS_INDICATION: MessageClass = MessageClass(0x01);
532/// 0b10.
533pub const CLASS_SUCCESS_RESPONSE: MessageClass = MessageClass(0x02);
534/// 0b11.
535pub const CLASS_ERROR_RESPONSE: MessageClass = MessageClass(0x03);
536
537impl fmt::Display for MessageClass {
538 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
539 let s = match *self {
540 CLASS_REQUEST => "request",
541 CLASS_INDICATION => "indication",
542 CLASS_SUCCESS_RESPONSE => "success response",
543 CLASS_ERROR_RESPONSE => "error response",
544 _ => "unknown message class",
545 };
546
547 write!(f, "{s}")
548 }
549}
550
551// Method is uint16 representation of 12-bit STUN method.
552#[derive(Default, PartialEq, Eq, Debug, Copy, Clone)]
553/// A STUN method, such as Binding or one of TURN's.
554pub struct Method(u16);
555
556/// Possible methods for STUN Message.
557pub const METHOD_BINDING: Method = Method(0x001);
558/// TURN Allocate: asks a relay for a public address.
559pub const METHOD_ALLOCATE: Method = Method(0x003);
560/// TURN Refresh: extends or releases an allocation.
561pub const METHOD_REFRESH: Method = Method(0x004);
562/// TURN Send: an indication carrying data to a peer through the relay.
563pub const METHOD_SEND: Method = Method(0x006);
564/// TURN Data: an indication carrying data from a peer through the relay.
565pub const METHOD_DATA: Method = Method(0x007);
566/// TURN CreatePermission: authorizes traffic to and from a peer address.
567pub const METHOD_CREATE_PERMISSION: Method = Method(0x008);
568/// TURN ChannelBind: binds a channel number to a peer for compact framing.
569pub const METHOD_CHANNEL_BIND: Method = Method(0x009);
570
571/// Methods from RFC 6062.
572pub const METHOD_CONNECT: Method = Method(0x000a);
573/// TURN-TCP ConnectionBind: associates a new TCP connection with an allocation.
574pub const METHOD_CONNECTION_BIND: Method = Method(0x000b);
575/// TURN-TCP ConnectionAttempt: notifies the client of an inbound TCP connection.
576pub const METHOD_CONNECTION_ATTEMPT: Method = Method(0x000c);
577
578impl fmt::Display for Method {
579 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
580 let unknown = format!("0x{:x}", self.0);
581
582 let s = match *self {
583 METHOD_BINDING => "Binding",
584 METHOD_ALLOCATE => "Allocate",
585 METHOD_REFRESH => "Refresh",
586 METHOD_SEND => "Send",
587 METHOD_DATA => "Data",
588 METHOD_CREATE_PERMISSION => "CreatePermission",
589 METHOD_CHANNEL_BIND => "ChannelBind",
590
591 // RFC 6062.
592 METHOD_CONNECT => "Connect",
593 METHOD_CONNECTION_BIND => "ConnectionBind",
594 METHOD_CONNECTION_ATTEMPT => "ConnectionAttempt",
595 _ => unknown.as_str(),
596 };
597
598 write!(f, "{s}")
599 }
600}
601
602// MessageType is STUN Message Type Field.
603#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
604/// A message's class and method together, as encoded in the first two header bytes.
605pub struct MessageType {
606 /// The method, such as Binding or Allocate.
607 pub method: Method, // e.g. binding
608 /// The class: request, indication, success response, or error response.
609 pub class: MessageClass, // e.g. request
610}
611
612/// Common STUN message types.
613/// Binding request message type.
614pub const BINDING_REQUEST: MessageType = MessageType {
615 method: METHOD_BINDING,
616 class: CLASS_REQUEST,
617};
618/// Binding success response message type.
619pub const BINDING_SUCCESS: MessageType = MessageType {
620 method: METHOD_BINDING,
621 class: CLASS_SUCCESS_RESPONSE,
622};
623/// Binding error response message type.
624pub const BINDING_ERROR: MessageType = MessageType {
625 method: METHOD_BINDING,
626 class: CLASS_ERROR_RESPONSE,
627};
628
629impl fmt::Display for MessageType {
630 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
631 write!(f, "{} {}", self.method, self.class)
632 }
633}
634
635const METHOD_ABITS: u16 = 0xf; // 0b0000000000001111
636const METHOD_BBITS: u16 = 0x70; // 0b0000000001110000
637const METHOD_DBITS: u16 = 0xf80; // 0b0000111110000000
638
639const METHOD_BSHIFT: u16 = 1;
640const METHOD_DSHIFT: u16 = 2;
641
642const FIRST_BIT: u16 = 0x1;
643const SECOND_BIT: u16 = 0x2;
644
645const C0BIT: u16 = FIRST_BIT;
646const C1BIT: u16 = SECOND_BIT;
647
648const CLASS_C0SHIFT: u16 = 4;
649const CLASS_C1SHIFT: u16 = 7;
650
651impl Setter for MessageType {
652 // add_to sets m type to t.
653 fn add_to(&self, m: &mut Message) -> Result<()> {
654 m.set_type(*self);
655 Ok(())
656 }
657}
658
659impl MessageType {
660 /// NewType returns new message type with provided method and class.
661 pub fn new(method: Method, class: MessageClass) -> Self {
662 MessageType { method, class }
663 }
664
665 /// Value returns bit representation of messageType.
666 pub fn value(&self) -> u16 {
667 // 0 1
668 // 2 3 4 5 6 7 8 9 0 1 2 3 4 5
669 // +--+--+-+-+-+-+-+-+-+-+-+-+-+-+
670 // |M |M |M|M|M|C|M|M|M|C|M|M|M|M|
671 // |11|10|9|8|7|1|6|5|4|0|3|2|1|0|
672 // +--+--+-+-+-+-+-+-+-+-+-+-+-+-+
673 // Figure 3: Format of STUN Message Type Field
674
675 // Warning: Abandon all hope ye who enter here.
676 // Splitting M into A(M0-M3), B(M4-M6), D(M7-M11).
677 let method = self.method.0;
678 let a = method & METHOD_ABITS; // A = M * 0b0000000000001111 (right 4 bits)
679 let b = method & METHOD_BBITS; // B = M * 0b0000000001110000 (3 bits after A)
680 let d = method & METHOD_DBITS; // D = M * 0b0000111110000000 (5 bits after B)
681
682 // Shifting to add "holes" for C0 (at 4 bit) and C1 (8 bit).
683 let method = a + (b << METHOD_BSHIFT) + (d << METHOD_DSHIFT);
684
685 // C0 is zero bit of C, C1 is first bit.
686 // C0 = C * 0b01, C1 = (C * 0b10) >> 1
687 // Ct = C0 << 4 + C1 << 8.
688 // Optimizations: "((C * 0b10) >> 1) << 8" as "(C * 0b10) << 7"
689 // We need C0 shifted by 4, and C1 by 8 to fit "11" and "7" positions
690 // (see figure 3).
691 let c = self.class.0 as u16;
692 let c0 = (c & C0BIT) << CLASS_C0SHIFT;
693 let c1 = (c & C1BIT) << CLASS_C1SHIFT;
694 let class = c0 + c1;
695
696 method + class
697 }
698
699 /// ReadValue decodes uint16 into MessageType.
700 pub fn read_value(&mut self, value: u16) {
701 // Decoding class.
702 // We are taking first bit from v >> 4 and second from v >> 7.
703 let c0 = (value >> CLASS_C0SHIFT) & C0BIT;
704 let c1 = (value >> CLASS_C1SHIFT) & C1BIT;
705 let class = c0 + c1;
706 self.class = MessageClass(class as u8);
707
708 // Decoding method.
709 let a = value & METHOD_ABITS; // A(M0-M3)
710 let b = (value >> METHOD_BSHIFT) & METHOD_BBITS; // B(M4-M6)
711 let d = (value >> METHOD_DSHIFT) & METHOD_DBITS; // D(M7-M11)
712 let m = a + b + d;
713 self.method = Method(m);
714 }
715}