Skip to content
File

Blob: firmware/vendor/sctp-proto/src/chunk/chunk_payload_data.rs

rust260 lines
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 header.value_length() < 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}