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