sctp_async/
error_cause.rs

1use crate::error::{Error, Result};
2
3use bytes::{Buf, BufMut, Bytes, BytesMut};
4use std::fmt;
5
6/// errorCauseCode is a cause code that appears in either a ERROR or ABORT chunk
7#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
8pub(crate) struct ErrorCauseCode(pub(crate) u16);
9
10pub(crate) const INVALID_STREAM_IDENTIFIER: ErrorCauseCode = ErrorCauseCode(1);
11pub(crate) const MISSING_MANDATORY_PARAMETER: ErrorCauseCode = ErrorCauseCode(2);
12pub(crate) const STALE_COOKIE_ERROR: ErrorCauseCode = ErrorCauseCode(3);
13pub(crate) const OUT_OF_RESOURCE: ErrorCauseCode = ErrorCauseCode(4);
14pub(crate) const UNRESOLVABLE_ADDRESS: ErrorCauseCode = ErrorCauseCode(5);
15pub(crate) const UNRECOGNIZED_CHUNK_TYPE: ErrorCauseCode = ErrorCauseCode(6);
16pub(crate) const INVALID_MANDATORY_PARAMETER: ErrorCauseCode = ErrorCauseCode(7);
17pub(crate) const UNRECOGNIZED_PARAMETERS: ErrorCauseCode = ErrorCauseCode(8);
18pub(crate) const NO_USER_DATA: ErrorCauseCode = ErrorCauseCode(9);
19pub(crate) const COOKIE_RECEIVED_WHILE_SHUTTING_DOWN: ErrorCauseCode = ErrorCauseCode(10);
20pub(crate) const RESTART_OF_AN_ASSOCIATION_WITH_NEW_ADDRESSES: ErrorCauseCode = ErrorCauseCode(11);
21pub(crate) const USER_INITIATED_ABORT: ErrorCauseCode = ErrorCauseCode(12);
22pub(crate) const PROTOCOL_VIOLATION: ErrorCauseCode = ErrorCauseCode(13);
23
24impl fmt::Display for ErrorCauseCode {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        let others = format!("Unknown CauseCode: {}", self.0);
27        let s = match *self {
28            INVALID_STREAM_IDENTIFIER => "Invalid Stream Identifier",
29            MISSING_MANDATORY_PARAMETER => "Missing Mandatory Parameter",
30            STALE_COOKIE_ERROR => "Stale Cookie Error",
31            OUT_OF_RESOURCE => "Out Of Resource",
32            UNRESOLVABLE_ADDRESS => "Unresolvable IP",
33            UNRECOGNIZED_CHUNK_TYPE => "Unrecognized Chunk Type",
34            INVALID_MANDATORY_PARAMETER => "Invalid Mandatory Parameter",
35            UNRECOGNIZED_PARAMETERS => "Unrecognized Parameters",
36            NO_USER_DATA => "No User Data",
37            COOKIE_RECEIVED_WHILE_SHUTTING_DOWN => "Cookie Received While Shutting Down",
38            RESTART_OF_AN_ASSOCIATION_WITH_NEW_ADDRESSES => {
39                "Restart Of An Association With New Addresses"
40            }
41            USER_INITIATED_ABORT => "User Initiated Abort",
42            PROTOCOL_VIOLATION => "Protocol Violation",
43            _ => others.as_str(),
44        };
45        write!(f, "{}", s)
46    }
47}
48
49/// ErrorCauseHeader represents the shared header that is shared by all error causes
50#[derive(Debug, Clone, Default)]
51pub(crate) struct ErrorCause {
52    pub(crate) code: ErrorCauseCode,
53    pub(crate) raw: Bytes,
54}
55
56/// ErrorCauseInvalidMandatoryParameter represents an SCTP error cause
57pub(crate) type ErrorCauseInvalidMandatoryParameter = ErrorCause;
58
59/// ErrorCauseUnrecognizedChunkType represents an SCTP error cause
60pub(crate) type ErrorCauseUnrecognizedChunkType = ErrorCause;
61
62///
63/// This error cause MAY be included in ABORT chunks that are sent
64/// because an SCTP endpoint detects a protocol violation of the peer
65/// that is not covered by the error causes described in Section 3.3.10.1
66/// to Section 3.3.10.12.  An implementation MAY provide additional
67/// information specifying what kind of protocol violation has been
68/// detected.
69///      0                   1                   2                   3
70///      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
71///     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
72///     |         Cause Code=13         |      Cause Length=Variable    |
73///     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74///     /                    Additional Information                     /
75///     \                                                               \
76///     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
77///
78pub(crate) type ErrorCauseProtocolViolation = ErrorCause;
79
80pub(crate) const ERROR_CAUSE_HEADER_LENGTH: usize = 4;
81
82/// makes ErrorCauseHeader printable
83impl fmt::Display for ErrorCause {
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        write!(f, "{}", self.code)
86    }
87}
88
89impl ErrorCause {
90    pub(crate) fn unmarshal(buf: &Bytes) -> Result<Self> {
91        if buf.len() < ERROR_CAUSE_HEADER_LENGTH {
92            return Err(Error::ErrErrorCauseTooSmall);
93        }
94
95        let reader = &mut buf.clone();
96
97        let code = ErrorCauseCode(reader.get_u16());
98        let len = reader.get_u16();
99
100        if len < ERROR_CAUSE_HEADER_LENGTH as u16 {
101            return Err(Error::ErrErrorCauseTooSmall);
102        }
103
104        let value_length = len as usize - ERROR_CAUSE_HEADER_LENGTH;
105        let raw = buf.slice(ERROR_CAUSE_HEADER_LENGTH..ERROR_CAUSE_HEADER_LENGTH + value_length);
106
107        Ok(ErrorCause { code, raw })
108    }
109
110    pub(crate) fn marshal(&self) -> Bytes {
111        let mut buf = BytesMut::with_capacity(self.length());
112        let _ = self.marshal_to(&mut buf);
113        buf.freeze()
114    }
115
116    pub(crate) fn marshal_to(&self, writer: &mut BytesMut) -> usize {
117        let len = self.raw.len() + ERROR_CAUSE_HEADER_LENGTH;
118        writer.put_u16(self.code.0);
119        writer.put_u16(len as u16);
120        writer.extend(self.raw.clone());
121        writer.len()
122    }
123
124    pub(crate) fn length(&self) -> usize {
125        self.raw.len() + ERROR_CAUSE_HEADER_LENGTH
126    }
127
128    pub(crate) fn error_cause_code(&self) -> ErrorCauseCode {
129        self.code
130    }
131}