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