sctp_async/chunk/
chunk_payload_data.rs

1use super::{chunk_header::*, chunk_type::*, *};
2
3use bytes::{Buf, BufMut, Bytes, BytesMut};
4use std::fmt;
5use std::sync::atomic::{AtomicBool, Ordering};
6use std::sync::Arc;
7use std::time::SystemTime;
8
9pub(crate) const PAYLOAD_DATA_ENDING_FRAGMENT_BITMASK: u8 = 1;
10pub(crate) const PAYLOAD_DATA_BEGINING_FRAGMENT_BITMASK: u8 = 2;
11pub(crate) const PAYLOAD_DATA_UNORDERED_BITMASK: u8 = 4;
12pub(crate) const PAYLOAD_DATA_IMMEDIATE_SACK: u8 = 8;
13pub(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)]
19#[repr(C)]
20pub enum PayloadProtocolIdentifier {
21    Dcep = 50,
22    String = 51,
23    Binary = 53,
24    StringEmpty = 56,
25    BinaryEmpty = 57,
26    Unknown,
27}
28
29impl Default for PayloadProtocolIdentifier {
30    fn default() -> Self {
31        PayloadProtocolIdentifier::Unknown
32    }
33}
34
35impl 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
49impl 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)]
97pub 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
128impl 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
152impl 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
158impl 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        if raw.len() < PAYLOAD_DATA_HEADER_SIZE {
194            return Err(Error::ErrChunkPayloadSmall);
195        }
196
197        let reader = &mut raw.slice(CHUNK_HEADER_SIZE..CHUNK_HEADER_SIZE + header.value_length());
198
199        let tsn = reader.get_u32();
200        let stream_identifier = reader.get_u16();
201        let stream_sequence_number = reader.get_u16();
202        let payload_type: PayloadProtocolIdentifier = reader.get_u32().into();
203        let user_data = raw.slice(
204            CHUNK_HEADER_SIZE + PAYLOAD_DATA_HEADER_SIZE..CHUNK_HEADER_SIZE + header.value_length(),
205        );
206
207        Ok(ChunkPayloadData {
208            unordered,
209            beginning_fragment,
210            ending_fragment,
211            immediate_sack,
212
213            tsn,
214            stream_identifier,
215            stream_sequence_number,
216            payload_type,
217            user_data,
218            acked: false,
219            miss_indicator: 0,
220            since: SystemTime::now(),
221            nsent: 0,
222            abandoned: Arc::new(AtomicBool::new(false)),
223            all_inflight: Arc::new(AtomicBool::new(false)),
224            retransmit: false,
225        })
226    }
227
228    fn marshal_to(&self, writer: &mut BytesMut) -> Result<usize> {
229        self.header().marshal_to(writer)?;
230
231        writer.put_u32(self.tsn);
232        writer.put_u16(self.stream_identifier);
233        writer.put_u16(self.stream_sequence_number);
234        writer.put_u32(self.payload_type as u32);
235        writer.extend(self.user_data.clone());
236
237        Ok(writer.len())
238    }
239
240    fn check(&self) -> Result<()> {
241        Ok(())
242    }
243
244    fn value_length(&self) -> usize {
245        PAYLOAD_DATA_HEADER_SIZE + self.user_data.len()
246    }
247
248    fn as_any(&self) -> &(dyn Any + Send + Sync) {
249        self
250    }
251}
252
253impl ChunkPayloadData {
254    pub(crate) fn abandoned(&self) -> bool {
255        let (abandoned, all_inflight) = (
256            self.abandoned.load(Ordering::SeqCst),
257            self.all_inflight.load(Ordering::SeqCst),
258        );
259
260        abandoned && all_inflight
261    }
262
263    pub(crate) fn set_abandoned(&self, abandoned: bool) {
264        self.abandoned.store(abandoned, Ordering::SeqCst);
265    }
266
267    pub(crate) fn set_all_inflight(&mut self) {
268        if self.ending_fragment {
269            self.all_inflight.store(true, Ordering::SeqCst);
270        }
271    }
272}