use crate::attributes::*;
use crate::checks::*;
use crate::message::*;
use shared::error::*;
use std::collections::HashMap;
use std::fmt;
#[derive(Default)]
pub struct ErrorCodeAttribute {
pub code: ErrorCode,
pub reason: Vec<u8>,
}
impl fmt::Display for ErrorCodeAttribute {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let reason = match String::from_utf8(self.reason.clone()) {
Ok(reason) => reason,
Err(_) => return Err(fmt::Error {}),
};
write!(f, "{}: {}", self.code.0, reason)
}
}
const ERROR_CODE_CLASS_BYTE: usize = 2;
const ERROR_CODE_NUMBER_BYTE: usize = 3;
const ERROR_CODE_REASON_START: usize = 4;
const ERROR_CODE_REASON_MAX_B: usize = 763;
const ERROR_CODE_MODULO: u16 = 100;
impl Setter for ErrorCodeAttribute {
fn add_to(&self, m: &mut Message) -> Result<()> {
check_overflow(
ATTR_ERROR_CODE,
self.reason.len() + ERROR_CODE_REASON_START,
ERROR_CODE_REASON_MAX_B + ERROR_CODE_REASON_START,
)?;
let mut value: Vec<u8> = Vec::with_capacity(ERROR_CODE_REASON_MAX_B);
let number = (self.code.0 % ERROR_CODE_MODULO) as u8; let class = (self.code.0 / ERROR_CODE_MODULO) as u8; value.extend_from_slice(&[0, 0]);
value.push(class); value.push(number); value.extend_from_slice(&self.reason);
m.add(ATTR_ERROR_CODE, &value);
Ok(())
}
}
impl Getter for ErrorCodeAttribute {
fn get_from(&mut self, m: &Message) -> Result<()> {
let v = m.get(ATTR_ERROR_CODE)?;
if v.len() < ERROR_CODE_REASON_START {
return Err(Error::ErrUnexpectedEof);
}
let class = v[ERROR_CODE_CLASS_BYTE] as u16;
let number = v[ERROR_CODE_NUMBER_BYTE] as u16;
let code = class * ERROR_CODE_MODULO + number;
self.code = ErrorCode(code);
self.reason = v[ERROR_CODE_REASON_START..].to_vec();
Ok(())
}
}
#[derive(PartialEq, Eq, Hash, Copy, Clone, Default)]
pub struct ErrorCode(pub u16);
impl Setter for ErrorCode {
fn add_to(&self, m: &mut Message) -> Result<()> {
if let Some(reason) = ERROR_REASONS.get(self) {
let a = ErrorCodeAttribute {
code: *self,
reason: reason.clone(),
};
a.add_to(m)
} else {
Err(Error::ErrNoDefaultReason)
}
}
}
pub const CODE_TRY_ALTERNATE: ErrorCode = ErrorCode(300);
pub const CODE_BAD_REQUEST: ErrorCode = ErrorCode(400);
pub const CODE_UNAUTHORIZED: ErrorCode = ErrorCode(401);
pub const CODE_UNKNOWN_ATTRIBUTE: ErrorCode = ErrorCode(420);
pub const CODE_STALE_NONCE: ErrorCode = ErrorCode(438);
pub const CODE_ROLE_CONFLICT: ErrorCode = ErrorCode(487);
pub const CODE_SERVER_ERROR: ErrorCode = ErrorCode(500);
pub const CODE_UNAUTHORISED: ErrorCode = CODE_UNAUTHORIZED;
pub const CODE_FORBIDDEN: ErrorCode = ErrorCode(403); pub const CODE_ALLOC_MISMATCH: ErrorCode = ErrorCode(437); pub const CODE_WRONG_CREDENTIALS: ErrorCode = ErrorCode(441); pub const CODE_UNSUPPORTED_TRANS_PROTO: ErrorCode = ErrorCode(442); pub const CODE_ALLOC_QUOTA_REACHED: ErrorCode = ErrorCode(486); pub const CODE_INSUFFICIENT_CAPACITY: ErrorCode = ErrorCode(508);
pub const CODE_CONN_ALREADY_EXISTS: ErrorCode = ErrorCode(446);
pub const CODE_CONN_TIMEOUT_OR_FAILURE: ErrorCode = ErrorCode(447);
pub const CODE_ADDR_FAMILY_NOT_SUPPORTED: ErrorCode = ErrorCode(440); pub const CODE_PEER_ADDR_FAMILY_MISMATCH: ErrorCode = ErrorCode(443);
lazy_static! {
pub static ref ERROR_REASONS:HashMap<ErrorCode, Vec<u8>> =
[
(CODE_TRY_ALTERNATE, b"Try Alternate".to_vec()),
(CODE_BAD_REQUEST, b"Bad Request".to_vec()),
(CODE_UNAUTHORIZED, b"Unauthorized".to_vec()),
(CODE_UNKNOWN_ATTRIBUTE, b"Unknown Attribute".to_vec()),
(CODE_STALE_NONCE, b"Stale Nonce".to_vec()),
(CODE_SERVER_ERROR, b"Server Error".to_vec()),
(CODE_ROLE_CONFLICT, b"Role Conflict".to_vec()),
(CODE_FORBIDDEN, b"Forbidden".to_vec()),
(CODE_ALLOC_MISMATCH, b"Allocation Mismatch".to_vec()),
(CODE_WRONG_CREDENTIALS, b"Wrong Credentials".to_vec()),
(CODE_UNSUPPORTED_TRANS_PROTO, b"Unsupported Transport Protocol".to_vec()),
(CODE_ALLOC_QUOTA_REACHED, b"Allocation Quota Reached".to_vec()),
(CODE_INSUFFICIENT_CAPACITY, b"Insufficient Capacity".to_vec()),
(CODE_CONN_ALREADY_EXISTS, b"Connection Already Exists".to_vec()),
(CODE_CONN_TIMEOUT_OR_FAILURE, b"Connection Timeout or Failure".to_vec()),
(CODE_ADDR_FAMILY_NOT_SUPPORTED, b"Address Family not Supported".to_vec()),
(CODE_PEER_ADDR_FAMILY_MISMATCH, b"Peer Address Family Mismatch".to_vec()),
].iter().cloned().collect();
}