sctp_proto/chunk/
chunk_payload_data.rs

1use super::{chunk_header::*, chunk_type::*, *};
2
3use std::time::Instant;
4
5pub(crate) const PAYLOAD_DATA_ENDING_FRAGMENT_BITMASK: u8 = 1;
6pub(crate) const PAYLOAD_DATA_BEGINING_FRAGMENT_BITMASK: u8 = 2;
7pub(crate) const PAYLOAD_DATA_UNORDERED_BITMASK: u8 = 4;
8pub(crate) const PAYLOAD_DATA_IMMEDIATE_SACK: u8 = 8;
9pub(crate) const PAYLOAD_DATA_HEADER_SIZE: usize = 12;
10
11/// PayloadProtocolIdentifier is an enum for DataChannel payload types
12// PayloadProtocolIdentifier enums
13// <https://www.iana.org/assignments/sctp-parameters/sctp-parameters.xhtml#sctp-parameters-25>
14#[derive(Debug, Copy, Clone, PartialEq)]
15#[repr(C)]
16#[derive(Default)]
17pub enum PayloadProtocolIdentifier {
18    Dcep = 50,
19    String = 51,
20    Binary = 53,
21    StringEmpty = 56,
22    BinaryEmpty = 57,
23    #[default]
24    Unknown,
25}
26
27impl fmt::Display for PayloadProtocolIdentifier {
28    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        let s = match *self {
30            PayloadProtocolIdentifier::Dcep => "WebRTC DCEP",
31            PayloadProtocolIdentifier::String => "WebRTC String",
32            PayloadProtocolIdentifier::Binary => "WebRTC Binary",
33            PayloadProtocolIdentifier::StringEmpty => "WebRTC String (Empty)",
34            PayloadProtocolIdentifier::BinaryEmpty => "WebRTC Binary (Empty)",
35            _ => "Unknown Payload Protocol Identifier",
36        };
37        write!(f, "{}", s)
38    }
39}
40
41impl From<u32> for PayloadProtocolIdentifier {
42    fn from(v: u32) -> PayloadProtocolIdentifier {
43        match v {
44            50 => PayloadProtocolIdentifier::Dcep,
45            51 => PayloadProtocolIdentifier::String,
46            53 => PayloadProtocolIdentifier::Binary,
47            56 => PayloadProtocolIdentifier::StringEmpty,
48            57 => PayloadProtocolIdentifier::BinaryEmpty,
49            _ => PayloadProtocolIdentifier::Unknown,
50        }
51    }
52}
53
54/// ChunkPayloadData represents an SCTP Chunk of type DATA
55//
56// 0                   1                   2                   3
57// 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
58//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59//|   Type = 0    | Reserved|U|B|E|    Length                     |
60//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
61//|                              TSN                              |
62//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
63//|      Stream Identifier S      |   Stream Sequence Number n    |
64//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65//|                  Payload Protocol Identifier                  |
66//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
67//|                                                               |
68//|                 User Data (seq n of Stream S)                 |
69//|                                                               |
70//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
71//
72//
73//An unfragmented user message shall have both the B and E bits set to
74//'1'.  Setting both B and E bits to '0' indicates a middle fragment of
75//a multi-fragment user message, as summarized in the following table:
76//   B E                  Description
77//============================================================
78//|  1 0 | First piece of a fragmented user message          |
79//+----------------------------------------------------------+
80//|  0 0 | Middle piece of a fragmented user message         |
81//+----------------------------------------------------------+
82//|  0 1 | Last piece of a fragmented user message           |
83//+----------------------------------------------------------+
84//|  1 1 | Unfragmented message                              |
85//============================================================
86//|             Table 1: Fragment Description Flags          |
87//============================================================
88#[derive(Debug, Clone)]
89pub struct ChunkPayloadData {
90    pub(crate) unordered: bool,
91    pub(crate) beginning_fragment: bool,
92    pub(crate) ending_fragment: bool,
93    pub(crate) immediate_sack: bool,
94
95    pub(crate) tsn: u32,
96    pub(crate) stream_identifier: u16,
97    pub(crate) stream_sequence_number: u16,
98    pub(crate) payload_type: PayloadProtocolIdentifier,
99    pub(crate) user_data: Bytes,
100
101    /// Whether this data chunk was acknowledged (received by peer)
102    pub(crate) acked: bool,
103    pub(crate) miss_indicator: u32,
104
105    /// Partial-reliability parameters used only by sender
106    pub(crate) since: Option<Instant>,
107    /// number of transmission made for this chunk
108    pub(crate) nsent: u32,
109
110    /// valid only with the first fragment
111    pub(crate) abandoned: bool,
112    /// valid only with the first fragment
113    pub(crate) all_inflight: bool,
114
115    /// Retransmission flag set when T1-RTX timeout occurred and this
116    /// chunk is still in the inflight queue
117    pub(crate) retransmit: bool,
118}
119
120impl Default for ChunkPayloadData {
121    fn default() -> Self {
122        ChunkPayloadData {
123            unordered: false,
124            beginning_fragment: false,
125            ending_fragment: false,
126            immediate_sack: false,
127            tsn: 0,
128            stream_identifier: 0,
129            stream_sequence_number: 0,
130            payload_type: PayloadProtocolIdentifier::default(),
131            user_data: Bytes::new(),
132            acked: false,
133            miss_indicator: 0,
134            since: None,
135            nsent: 0,
136            abandoned: false,
137            all_inflight: false,
138            retransmit: false,
139        }
140    }
141}
142
143/// makes chunkPayloadData printable
144impl fmt::Display for ChunkPayloadData {
145    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146        write!(f, "{}\n{}", self.header(), self.tsn)
147    }
148}
149
150impl Chunk for ChunkPayloadData {
151    fn header(&self) -> ChunkHeader {
152        let mut flags: u8 = 0;
153        if self.ending_fragment {
154            flags = 1;
155        }
156        if self.beginning_fragment {
157            flags |= 1 << 1;
158        }
159        if self.unordered {
160            flags |= 1 << 2;
161        }
162        if self.immediate_sack {
163            flags |= 1 << 3;
164        }
165
166        ChunkHeader {
167            typ: CT_PAYLOAD_DATA,
168            flags,
169            value_length: self.value_length() as u16,
170        }
171    }
172
173    fn unmarshal(raw: &Bytes) -> Result<Self> {
174        let header = ChunkHeader::unmarshal(raw)?;
175
176        if header.typ != CT_PAYLOAD_DATA {
177            return Err(Error::ErrChunkTypeNotPayloadData);
178        }
179
180        let immediate_sack = (header.flags & PAYLOAD_DATA_IMMEDIATE_SACK) != 0;
181        let unordered = (header.flags & PAYLOAD_DATA_UNORDERED_BITMASK) != 0;
182        let beginning_fragment = (header.flags & PAYLOAD_DATA_BEGINING_FRAGMENT_BITMASK) != 0;
183        let ending_fragment = (header.flags & PAYLOAD_DATA_ENDING_FRAGMENT_BITMASK) != 0;
184
185        if raw.len() < PAYLOAD_DATA_HEADER_SIZE {
186            return Err(Error::ErrChunkPayloadSmall);
187        }
188
189        let reader = &mut raw.slice(CHUNK_HEADER_SIZE..CHUNK_HEADER_SIZE + header.value_length());
190
191        let tsn = reader.get_u32();
192        let stream_identifier = reader.get_u16();
193        let stream_sequence_number = reader.get_u16();
194        let payload_type: PayloadProtocolIdentifier = reader.get_u32().into();
195        let user_data = raw.slice(
196            CHUNK_HEADER_SIZE + PAYLOAD_DATA_HEADER_SIZE..CHUNK_HEADER_SIZE + header.value_length(),
197        );
198
199        Ok(ChunkPayloadData {
200            unordered,
201            beginning_fragment,
202            ending_fragment,
203            immediate_sack,
204            tsn,
205            stream_identifier,
206            stream_sequence_number,
207            payload_type,
208            user_data,
209
210            acked: false,
211            miss_indicator: 0,
212            since: None,
213            nsent: 0,
214            abandoned: false,
215            all_inflight: false,
216            retransmit: false,
217        })
218    }
219
220    fn marshal_to(&self, writer: &mut BytesMut) -> Result<usize> {
221        self.header().marshal_to(writer)?;
222
223        writer.put_u32(self.tsn);
224        writer.put_u16(self.stream_identifier);
225        writer.put_u16(self.stream_sequence_number);
226        writer.put_u32(self.payload_type as u32);
227        writer.extend_from_slice(&self.user_data);
228
229        Ok(writer.len())
230    }
231
232    fn check(&self) -> Result<()> {
233        Ok(())
234    }
235
236    fn value_length(&self) -> usize {
237        PAYLOAD_DATA_HEADER_SIZE + self.user_data.len()
238    }
239
240    fn as_any(&self) -> &(dyn Any + Send + Sync) {
241        self
242    }
243}
244
245impl ChunkPayloadData {
246    pub(crate) fn abandoned(&self) -> bool {
247        self.abandoned && self.all_inflight
248    }
249
250    pub(crate) fn set_abandoned(&mut self, abandoned: bool) {
251        self.abandoned = abandoned;
252    }
253
254    pub(crate) fn set_all_inflight(&mut self) {
255        if self.ending_fragment {
256            self.all_inflight = true;
257        }
258    }
259}