rtc_sctp/chunk/
chunk_payload_data.rs

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