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