Skip to main content

rtc_stun/
error_code.rs

1//! The `ERROR-CODE` attribute.
2//!
3//! An [`ErrorCodeAttribute`](crate::error_code::ErrorCodeAttribute) is a numeric [`ErrorCode`](crate::error_code::ErrorCode) plus a reason phrase. The codes here span
4//! three specs — STUN's own (400, 401, 420, 500), ICE's role conflict (487), and TURN's
5//! allocation failures (437, 441, 486, 508) — because all three share this attribute.
6//!
7//! [`ERROR_REASONS`](crate::error_code::ERROR_REASONS) maps each known code to the phrase it is normally sent with, so a responder
8//! does not have to invent one.
9#[cfg(test)]
10mod error_code_test;
11
12use crate::attributes::*;
13use crate::checks::*;
14use crate::message::*;
15use shared::error::*;
16
17use std::collections::HashMap;
18use std::fmt;
19
20// ErrorCodeAttribute represents ERROR-CODE attribute.
21//
22// RFC 5389 Section 15.6
23#[derive(Default)]
24/// The `ERROR-CODE` attribute: a numeric code and a human-readable reason.
25pub struct ErrorCodeAttribute {
26    /// The numeric error code.
27    pub code: ErrorCode,
28    /// The reason phrase, as UTF-8 bytes.
29    pub reason: Vec<u8>,
30}
31
32impl fmt::Display for ErrorCodeAttribute {
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        write!(
35            f,
36            "{}: {}",
37            self.code.0,
38            String::from_utf8_lossy(&self.reason)
39        )
40    }
41}
42
43// constants for ERROR-CODE encoding.
44const ERROR_CODE_CLASS_BYTE: usize = 2;
45const ERROR_CODE_NUMBER_BYTE: usize = 3;
46const ERROR_CODE_REASON_START: usize = 4;
47const ERROR_CODE_REASON_MAX_B: usize = 763;
48const ERROR_CODE_MODULO: u16 = 100;
49
50impl Setter for ErrorCodeAttribute {
51    // add_to adds ERROR-CODE to m.
52    fn add_to(&self, m: &mut Message) -> Result<()> {
53        check_overflow(
54            ATTR_ERROR_CODE,
55            self.reason.len() + ERROR_CODE_REASON_START,
56            ERROR_CODE_REASON_MAX_B + ERROR_CODE_REASON_START,
57        )?;
58
59        let mut value: Vec<u8> = Vec::with_capacity(ERROR_CODE_REASON_MAX_B);
60
61        let number = (self.code.0 % ERROR_CODE_MODULO) as u8; // error code modulo 100
62        let class = (self.code.0 / ERROR_CODE_MODULO) as u8; // hundred digit
63        value.extend_from_slice(&[0, 0]);
64        value.push(class); // [ERROR_CODE_CLASS_BYTE]
65        value.push(number); //[ERROR_CODE_NUMBER_BYTE] =
66        value.extend_from_slice(&self.reason); //[ERROR_CODE_REASON_START:]
67
68        m.add(ATTR_ERROR_CODE, &value);
69
70        Ok(())
71    }
72}
73
74impl Getter for ErrorCodeAttribute {
75    // GetFrom decodes ERROR-CODE from m. Reason is valid until m.Raw is valid.
76    fn get_from(&mut self, m: &Message) -> Result<()> {
77        let v = m.get(ATTR_ERROR_CODE)?;
78
79        if v.len() < ERROR_CODE_REASON_START {
80            return Err(Error::ErrUnexpectedEof);
81        }
82
83        let class = v[ERROR_CODE_CLASS_BYTE] as u16;
84        let number = v[ERROR_CODE_NUMBER_BYTE] as u16;
85        let code = class * ERROR_CODE_MODULO + number;
86        self.code = ErrorCode(code);
87        self.reason = v[ERROR_CODE_REASON_START..].to_vec();
88
89        Ok(())
90    }
91}
92
93// ErrorCode is code for ERROR-CODE attribute.
94#[derive(PartialEq, Eq, Hash, Copy, Clone, Default)]
95/// A STUN error code, as carried in `ERROR-CODE`.
96pub struct ErrorCode(pub u16);
97
98impl Setter for ErrorCode {
99    // add_to adds ERROR-CODE with default reason to m. If there
100    // is no default reason, returns ErrNoDefaultReason.
101    fn add_to(&self, m: &mut Message) -> Result<()> {
102        if let Some(reason) = ERROR_REASONS.get(self) {
103            let a = ErrorCodeAttribute {
104                code: *self,
105                reason: reason.clone(),
106            };
107            a.add_to(m)
108        } else {
109            Err(Error::ErrNoDefaultReason)
110        }
111    }
112}
113
114/// Possible error codes.
115pub const CODE_TRY_ALTERNATE: ErrorCode = ErrorCode(300);
116/// 400 Bad Request: the request was malformed.
117pub const CODE_BAD_REQUEST: ErrorCode = ErrorCode(400);
118/// 401 Unauthorized: authentication is required, or the credentials were wrong.
119pub const CODE_UNAUTHORIZED: ErrorCode = ErrorCode(401);
120/// 420 Unknown Attribute: the request carried a comprehension-required attribute the server
121/// does not understand.
122pub const CODE_UNKNOWN_ATTRIBUTE: ErrorCode = ErrorCode(420);
123/// 438 Stale Nonce: the nonce expired; retry with the one in this response.
124pub const CODE_STALE_NONCE: ErrorCode = ErrorCode(438);
125/// 487 Role Conflict: both ICE agents claimed the same role.
126pub const CODE_ROLE_CONFLICT: ErrorCode = ErrorCode(487);
127/// 500 Server Error: a temporary failure on the server.
128pub const CODE_SERVER_ERROR: ErrorCode = ErrorCode(500);
129
130/// DEPRECATED constants.
131/// DEPRECATED, use CODE_UNAUTHORIZED.
132pub const CODE_UNAUTHORISED: ErrorCode = CODE_UNAUTHORIZED;
133
134/// Error codes from RFC 5766.
135///
136/// RFC 5766 Section 15.
137/// Forbidden.
138pub const CODE_FORBIDDEN: ErrorCode = ErrorCode(403);
139/// Allocation Mismatch.
140pub const CODE_ALLOC_MISMATCH: ErrorCode = ErrorCode(437);
141/// Wrong Credentials.
142pub const CODE_WRONG_CREDENTIALS: ErrorCode = ErrorCode(441);
143/// Unsupported Transport Protocol.
144pub const CODE_UNSUPPORTED_TRANS_PROTO: ErrorCode = ErrorCode(442);
145/// Allocation Quota Reached.
146pub const CODE_ALLOC_QUOTA_REACHED: ErrorCode = ErrorCode(486);
147/// Insufficient Capacity.
148pub const CODE_INSUFFICIENT_CAPACITY: ErrorCode = ErrorCode(508);
149
150/// Error codes from RFC 6062.
151///
152/// RFC 6062 Section 6.3.
153pub const CODE_CONN_ALREADY_EXISTS: ErrorCode = ErrorCode(446);
154/// 447 Connection Timeout or Failure: the TURN TCP connection to the peer failed.
155pub const CODE_CONN_TIMEOUT_OR_FAILURE: ErrorCode = ErrorCode(447);
156
157/// Error codes from RFC 6156.
158///
159/// RFC 6156 Section 10.2.
160/// Address Family not Supported.
161pub const CODE_ADDR_FAMILY_NOT_SUPPORTED: ErrorCode = ErrorCode(440);
162/// Peer Address Family Mismatch.
163pub const CODE_PEER_ADDR_FAMILY_MISMATCH: ErrorCode = ErrorCode(443);
164
165lazy_static! {
166    /// The reason phrase each known [`ErrorCode`] is sent with.
167    pub static ref ERROR_REASONS:HashMap<ErrorCode, Vec<u8>> =
168        [
169            (CODE_TRY_ALTERNATE,     b"Try Alternate".to_vec()),
170            (CODE_BAD_REQUEST,       b"Bad Request".to_vec()),
171            (CODE_UNAUTHORIZED,     b"Unauthorized".to_vec()),
172            (CODE_UNKNOWN_ATTRIBUTE, b"Unknown Attribute".to_vec()),
173            (CODE_STALE_NONCE,       b"Stale Nonce".to_vec()),
174            (CODE_SERVER_ERROR,      b"Server Error".to_vec()),
175            (CODE_ROLE_CONFLICT,     b"Role Conflict".to_vec()),
176
177            // RFC 5766.
178            (CODE_FORBIDDEN,             b"Forbidden".to_vec()),
179            (CODE_ALLOC_MISMATCH,         b"Allocation Mismatch".to_vec()),
180            (CODE_WRONG_CREDENTIALS,      b"Wrong Credentials".to_vec()),
181            (CODE_UNSUPPORTED_TRANS_PROTO, b"Unsupported Transport Protocol".to_vec()),
182            (CODE_ALLOC_QUOTA_REACHED,     b"Allocation Quota Reached".to_vec()),
183            (CODE_INSUFFICIENT_CAPACITY,  b"Insufficient Capacity".to_vec()),
184
185            // RFC 6062.
186            (CODE_CONN_ALREADY_EXISTS,    b"Connection Already Exists".to_vec()),
187            (CODE_CONN_TIMEOUT_OR_FAILURE, b"Connection Timeout or Failure".to_vec()),
188
189            // RFC 6156.
190            (CODE_ADDR_FAMILY_NOT_SUPPORTED, b"Address Family not Supported".to_vec()),
191            (CODE_PEER_ADDR_FAMILY_MISMATCH, b"Peer Address Family Mismatch".to_vec()),
192        ].iter().cloned().collect();
193
194}