File
Blob: firmware/vendor/sctp-proto/src/association/stream.rs
| 1 | use crate::association::Association; |
| 2 | use crate::association::state::AssociationState; |
| 3 | use crate::chunk::chunk_payload_data::{ChunkPayloadData, PayloadProtocolIdentifier}; |
| 4 | use crate::error::{Error, Result}; |
| 5 | use crate::queue::reassembly_queue::{Chunks, ReassemblyQueue}; |
| 6 | use crate::{ErrorCauseCode, Side}; |
| 7 | |
| 8 | use crate::util::{ByteSlice, BytesArray, BytesSource}; |
| 9 | use alloc::vec; |
| 10 | use alloc::vec::Vec; |
| 11 | use bytes::Bytes; |
| 12 | use core::fmt; |
| 13 | use log::{debug, error, trace}; |
| 14 | |
| 15 | /// Identifier for a stream within a particular association |
| 16 | pub type StreamId = u16; |
| 17 | |
| 18 | /// Why a stream reset did not complete successfully. |
| 19 | #[non_exhaustive] |
| 20 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 21 | pub enum StreamResetError { |
| 22 | /// The peer explicitly denied the reset request. |
| 23 | Denied, |
| 24 | /// The reset failed because of a protocol error or exhausted retransmissions. |
| 25 | Failed, |
| 26 | } |
| 27 | |
| 28 | /// Application events about streams |
| 29 | #[non_exhaustive] |
| 30 | #[derive(Debug, PartialEq, Eq)] |
| 31 | pub enum StreamEvent { |
| 32 | /// One or more new streams has been opened |
| 33 | Opened { |
| 34 | /// Which stream was opened |
| 35 | id: StreamId, |
| 36 | }, |
| 37 | /// A currently open stream has data or errors waiting to be read |
| 38 | Readable { |
| 39 | /// Which stream is now readable |
| 40 | id: StreamId, |
| 41 | }, |
| 42 | /// A formerly write-blocked stream might be ready for a write or have been stopped |
| 43 | /// |
| 44 | /// Only generated for streams that are currently open. |
| 45 | Writable { |
| 46 | /// Which stream is now writable |
| 47 | id: StreamId, |
| 48 | }, |
| 49 | /// The stream was torn down by a reset, an inbound reset |
| 50 | /// request from the peer naming the id was processed or |
| 51 | /// its reciprocal to a locally-initiated one. |
| 52 | /// |
| 53 | /// No more data can be read from or written to it. |
| 54 | /// |
| 55 | /// Once this fires, either [`StreamEvent::ResetComplete`] or |
| 56 | /// [`StreamEvent::ResetFailed`] for the same id is guaranteed to eventually |
| 57 | /// follow, unless the association closes first. |
| 58 | Finished { |
| 59 | /// Which stream has been finished |
| 60 | id: StreamId, |
| 61 | }, |
| 62 | /// A reset handshake involving this stream id completed successfully. |
| 63 | /// |
| 64 | /// The id can be reused unless a newer reset for the same id has since |
| 65 | /// started or failed. |
| 66 | ResetComplete { |
| 67 | /// Which stream id completed its reset. |
| 68 | id: StreamId, |
| 69 | }, |
| 70 | /// A reset handshake involving this stream id did not complete. |
| 71 | /// |
| 72 | /// The id remains unavailable for reuse until a later reset succeeds or |
| 73 | /// the association closes. |
| 74 | ResetFailed { |
| 75 | /// Which stream id failed to reset. |
| 76 | id: StreamId, |
| 77 | /// Why the reset did not complete. |
| 78 | reason: StreamResetError, |
| 79 | }, |
| 80 | /// The peer asked us to stop sending on an outgoing stream |
| 81 | Stopped { |
| 82 | /// Which stream has been stopped |
| 83 | id: StreamId, |
| 84 | /// Error code supplied by the peer |
| 85 | error_code: ErrorCauseCode, |
| 86 | }, |
| 87 | /// At least one new stream of a certain directionality may be opened |
| 88 | Available, |
| 89 | /// The number of bytes of outgoing data buffered is lower than the threshold. |
| 90 | BufferedAmountLow { |
| 91 | /// Which stream is now readable |
| 92 | id: StreamId, |
| 93 | }, |
| 94 | /// The number of bytes of outgoing data buffered is higher than the threshold. |
| 95 | BufferedAmountHigh { |
| 96 | /// Which stream has crossed the high threshold |
| 97 | id: StreamId, |
| 98 | }, |
| 99 | } |
| 100 | |
| 101 | /// Reliability type for stream |
| 102 | #[derive(Debug, Copy, Clone, PartialEq, Default)] |
| 103 | pub enum ReliabilityType { |
| 104 | /// ReliabilityTypeReliable is used for reliable transmission |
| 105 | #[default] |
| 106 | Reliable = 0, |
| 107 | /// ReliabilityTypeRexmit is used for partial reliability by retransmission count |
| 108 | Rexmit = 1, |
| 109 | /// ReliabilityTypeTimed is used for partial reliability by retransmission duration |
| 110 | Timed = 2, |
| 111 | } |
| 112 | |
| 113 | impl fmt::Display for ReliabilityType { |
| 114 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 115 | let s = match *self { |
| 116 | ReliabilityType::Reliable => "Reliable", |
| 117 | ReliabilityType::Rexmit => "Rexmit", |
| 118 | ReliabilityType::Timed => "Timed", |
| 119 | }; |
| 120 | write!(f, "{}", s) |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | impl From<u8> for ReliabilityType { |
| 125 | fn from(v: u8) -> ReliabilityType { |
| 126 | match v { |
| 127 | 1 => ReliabilityType::Rexmit, |
| 128 | 2 => ReliabilityType::Timed, |
| 129 | _ => ReliabilityType::Reliable, |
| 130 | } |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | /// Stream represents an SCTP stream |
| 135 | pub struct Stream<'a> { |
| 136 | pub(crate) stream_identifier: StreamId, |
| 137 | pub(crate) association: &'a mut Association, |
| 138 | } |
| 139 | |
| 140 | impl<'a> Stream<'a> { |
| 141 | /// read reads a packet of len(p) bytes, dropping the Payload Protocol Identifier. |
| 142 | /// Returns EOF when the stream is reset or an error if the stream is closed |
| 143 | /// otherwise. |
| 144 | pub fn read(&mut self) -> Result<Option<Chunks>> { |
| 145 | self.read_sctp() |
| 146 | } |
| 147 | |
| 148 | /// read_sctp reads a packet of len(p) bytes and returns the associated Payload |
| 149 | /// Protocol Identifier. |
| 150 | /// Returns EOF when the stream is reset or an error if the stream is closed |
| 151 | /// otherwise. |
| 152 | pub fn read_sctp(&mut self) -> Result<Option<Chunks>> { |
| 153 | let (message, drained) = |
| 154 | if let Some(s) = self.association.streams.get_mut(&self.stream_identifier) { |
| 155 | if s.state != RecvSendState::ReadWritable && s.state != RecvSendState::Readable { |
| 156 | return Err(Error::ErrStreamClosed); |
| 157 | } |
| 158 | |
| 159 | let message = s.reassembly_queue.read(); |
| 160 | let drained = message.is_some() && s.reassembly_queue.get_num_bytes() == 0; |
| 161 | (message, drained) |
| 162 | } else { |
| 163 | return Err(Error::ErrStreamClosed); |
| 164 | }; |
| 165 | |
| 166 | if drained { |
| 167 | self.association |
| 168 | .finish_retiring_stream(self.stream_identifier)?; |
| 169 | } |
| 170 | |
| 171 | Ok(message) |
| 172 | } |
| 173 | |
| 174 | /// write_sctp writes len(p) bytes from p to the DTLS connection |
| 175 | pub fn write_sctp(&mut self, p: &Bytes, ppi: PayloadProtocolIdentifier) -> Result<usize> { |
| 176 | self.write_source(&mut ByteSlice::from_slice(p), ppi) |
| 177 | } |
| 178 | |
| 179 | /// Send data on the given stream. |
| 180 | /// |
| 181 | /// Uses the deafult payload protocol (PPI). |
| 182 | /// |
| 183 | /// Returns the number of bytes successfully written. |
| 184 | pub fn write(&mut self, data: &[u8]) -> Result<usize> { |
| 185 | self.write_with_ppi(data, self.get_default_payload_type()?) |
| 186 | } |
| 187 | |
| 188 | /// Send data on the given stream, with a specific payload protocol. |
| 189 | /// |
| 190 | /// Returns the number of bytes successfully written. |
| 191 | pub fn write_with_ppi(&mut self, data: &[u8], ppi: PayloadProtocolIdentifier) -> Result<usize> { |
| 192 | self.write_source(&mut ByteSlice::from_slice(data), ppi) |
| 193 | } |
| 194 | |
| 195 | /// write writes len(p) bytes from p with the default Payload Protocol Identifier |
| 196 | pub fn write_chunk(&mut self, p: &Bytes) -> Result<usize> { |
| 197 | self.write_source( |
| 198 | &mut ByteSlice::from_slice(p), |
| 199 | self.get_default_payload_type()?, |
| 200 | ) |
| 201 | } |
| 202 | |
| 203 | /// Send data on the given stream |
| 204 | /// |
| 205 | /// Returns the number of bytes and chunks successfully written. |
| 206 | /// Note that this method might also write a partial chunk. In this case |
| 207 | /// it will not count this chunk as fully written. However |
| 208 | /// the chunk will be advanced and contain only non-written data after the call. |
| 209 | pub fn write_chunks(&mut self, data: &mut [Bytes]) -> Result<usize> { |
| 210 | self.write_source( |
| 211 | &mut BytesArray::from_chunks(data), |
| 212 | self.get_default_payload_type()?, |
| 213 | ) |
| 214 | } |
| 215 | |
| 216 | /// write_source writes BytesSource to the DTLS connection |
| 217 | fn write_source<B: BytesSource>( |
| 218 | &mut self, |
| 219 | source: &mut B, |
| 220 | ppi: PayloadProtocolIdentifier, |
| 221 | ) -> Result<usize> { |
| 222 | if !self.is_writable() { |
| 223 | return Err(Error::ErrStreamClosed); |
| 224 | } |
| 225 | |
| 226 | if source.remaining() > self.association.max_send_message_size() as usize { |
| 227 | return Err(Error::ErrOutboundPacketTooLarge); |
| 228 | } |
| 229 | |
| 230 | let state: AssociationState = self.association.state(); |
| 231 | match state { |
| 232 | AssociationState::ShutdownSent |
| 233 | | AssociationState::ShutdownAckSent |
| 234 | | AssociationState::ShutdownPending |
| 235 | | AssociationState::ShutdownReceived => return Err(Error::ErrStreamClosed), |
| 236 | _ => {} |
| 237 | }; |
| 238 | |
| 239 | let (p, _) = source.pop_chunk(self.association.max_send_message_size() as usize); |
| 240 | |
| 241 | if let Some(s) = self.association.streams.get_mut(&self.stream_identifier) { |
| 242 | let (is_buffered_amount_high, chunks) = s.packetize(&p, ppi); |
| 243 | self.association.send_payload_data(chunks)?; |
| 244 | |
| 245 | if is_buffered_amount_high { |
| 246 | trace!("StreamEvent::BufferedAmountHigh"); |
| 247 | self.association |
| 248 | .events |
| 249 | .push_back(crate::association::Event::Stream( |
| 250 | StreamEvent::BufferedAmountHigh { |
| 251 | id: self.stream_identifier, |
| 252 | }, |
| 253 | )); |
| 254 | } |
| 255 | |
| 256 | Ok(p.len()) |
| 257 | } else { |
| 258 | Err(Error::ErrStreamClosed) |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | pub fn is_readable(&self) -> bool { |
| 263 | if let Some(s) = self.association.streams.get(&self.stream_identifier) { |
| 264 | s.state == RecvSendState::Readable || s.state == RecvSendState::ReadWritable |
| 265 | } else { |
| 266 | false |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | pub fn is_writable(&self) -> bool { |
| 271 | // RFC 6525 section 5.1.2 A1 forbids assigning new SSNs while an |
| 272 | // Outgoing SSN Reset Request for this stream is pending. A failed |
| 273 | // reset also quarantines the outgoing direction because the peer may |
| 274 | // already have reset its corresponding incoming stream. |
| 275 | if self |
| 276 | .association |
| 277 | .stream_reset_blocked(self.stream_identifier) |
| 278 | { |
| 279 | return false; |
| 280 | } |
| 281 | if let Some(s) = self.association.streams.get(&self.stream_identifier) { |
| 282 | s.state == RecvSendState::Writable || s.state == RecvSendState::ReadWritable |
| 283 | } else { |
| 284 | false |
| 285 | } |
| 286 | } |
| 287 | |
| 288 | /// stop closes the read-direction of the stream. |
| 289 | /// Future calls to read are not permitted after calling stop. |
| 290 | /// |
| 291 | /// NOTE: a stream closed without a queued reset never produces |
| 292 | /// `StreamEvent::Finished` followed by `StreamEvent::ResetComplete` or |
| 293 | /// `StreamEvent::ResetFailed`. |
| 294 | pub fn stop(&mut self) -> Result<()> { |
| 295 | let retiring = self |
| 296 | .association |
| 297 | .retiring_streams |
| 298 | .contains_key(&self.stream_identifier); |
| 299 | let reset = self |
| 300 | .association |
| 301 | .streams |
| 302 | .get(&self.stream_identifier) |
| 303 | .is_some_and(|s| { |
| 304 | s.state == RecvSendState::Readable || s.state == RecvSendState::ReadWritable |
| 305 | }); |
| 306 | |
| 307 | if reset |
| 308 | && !retiring |
| 309 | && !self |
| 310 | .association |
| 311 | .stream_reset_in_progress(self.stream_identifier) |
| 312 | { |
| 313 | // Reset the outgoing stream |
| 314 | // https://tools.ietf.org/html/rfc6525 |
| 315 | // |
| 316 | // Queued before clearing the read bit below, send_reset_request |
| 317 | // is the only fallible step, and failing after the state |
| 318 | // mutation would leave the stream half-closed with the reset |
| 319 | // silently dropped and unretryable. |
| 320 | self.association |
| 321 | .send_reset_request(self.stream_identifier)?; |
| 322 | } |
| 323 | |
| 324 | if let Some(s) = self.association.streams.get_mut(&self.stream_identifier) { |
| 325 | s.state = ((s.state as u8) & 0x2).into(); |
| 326 | } |
| 327 | |
| 328 | // stop() promises that future reads are not permitted. If a reset was |
| 329 | // preserving unread boundary DATA, discard that old generation now so |
| 330 | // its Finished event and unrelated association events cannot stall. |
| 331 | if retiring { |
| 332 | self.association |
| 333 | .discard_retiring_streams(self.stream_identifier); |
| 334 | } |
| 335 | |
| 336 | Ok(()) |
| 337 | } |
| 338 | |
| 339 | /// finish closes the write-direction of the stream. |
| 340 | /// Future calls to write are not permitted after calling Close. |
| 341 | pub fn finish(&mut self) -> Result<()> { |
| 342 | if let Some(s) = self.association.streams.get_mut(&self.stream_identifier) { |
| 343 | s.state = ((s.state as u8) & 0x1).into(); |
| 344 | } |
| 345 | Ok(()) |
| 346 | } |
| 347 | |
| 348 | /// close shuts down both the read and write halves of this stream. |
| 349 | /// |
| 350 | /// This is a convenience method that calls `finish()` followed by `stop()`. |
| 351 | /// Resets the stream when both halves are shutdown. |
| 352 | /// |
| 353 | /// The single failure mode is `stop()`'s, if the association is not |
| 354 | /// established, no reset was queued, retrying `close()` will |
| 355 | /// attempt the reset again. |
| 356 | pub fn close(&mut self) -> Result<()> { |
| 357 | self.finish()?; |
| 358 | self.stop() |
| 359 | } |
| 360 | |
| 361 | /// stream_identifier returns the Stream identifier associated to the stream. |
| 362 | pub fn stream_identifier(&self) -> StreamId { |
| 363 | self.stream_identifier |
| 364 | } |
| 365 | |
| 366 | /// set_default_payload_type sets the default payload type used by write. |
| 367 | pub fn set_default_payload_type( |
| 368 | &mut self, |
| 369 | default_payload_type: PayloadProtocolIdentifier, |
| 370 | ) -> Result<()> { |
| 371 | if let Some(s) = self.association.streams.get_mut(&self.stream_identifier) { |
| 372 | s.default_payload_type = default_payload_type; |
| 373 | Ok(()) |
| 374 | } else { |
| 375 | Err(Error::ErrStreamClosed) |
| 376 | } |
| 377 | } |
| 378 | |
| 379 | /// get_default_payload_type returns the payload type associated to the stream. |
| 380 | pub fn get_default_payload_type(&self) -> Result<PayloadProtocolIdentifier> { |
| 381 | if let Some(s) = self.association.streams.get(&self.stream_identifier) { |
| 382 | Ok(s.default_payload_type) |
| 383 | } else { |
| 384 | Err(Error::ErrStreamClosed) |
| 385 | } |
| 386 | } |
| 387 | |
| 388 | /// set_reliability_params sets reliability parameters for this stream. |
| 389 | pub fn set_reliability_params( |
| 390 | &mut self, |
| 391 | unordered: bool, |
| 392 | rel_type: ReliabilityType, |
| 393 | rel_val: u32, |
| 394 | ) -> Result<()> { |
| 395 | if let Some(s) = self.association.streams.get_mut(&self.stream_identifier) { |
| 396 | debug!( |
| 397 | "[{}] reliability params: ordered={} type={} value={}", |
| 398 | s.side, !unordered, rel_type, rel_val |
| 399 | ); |
| 400 | s.unordered = unordered; |
| 401 | s.reliability_type = rel_type; |
| 402 | s.reliability_value = rel_val; |
| 403 | Ok(()) |
| 404 | } else { |
| 405 | Err(Error::ErrStreamClosed) |
| 406 | } |
| 407 | } |
| 408 | |
| 409 | /// buffered_amount returns the number of bytes of data currently queued to be sent over this stream. |
| 410 | pub fn buffered_amount(&self) -> Result<usize> { |
| 411 | if let Some(s) = self.association.streams.get(&self.stream_identifier) { |
| 412 | Ok(s.buffered_amount) |
| 413 | } else { |
| 414 | Err(Error::ErrStreamClosed) |
| 415 | } |
| 416 | } |
| 417 | |
| 418 | /// buffered_amount_low_threshold returns the number of bytes of buffered outgoing data that is |
| 419 | /// considered "low." Defaults to 0. |
| 420 | pub fn buffered_amount_low_threshold(&self) -> Result<usize> { |
| 421 | if let Some(s) = self.association.streams.get(&self.stream_identifier) { |
| 422 | Ok(s.buffered_amount_low) |
| 423 | } else { |
| 424 | Err(Error::ErrStreamClosed) |
| 425 | } |
| 426 | } |
| 427 | |
| 428 | /// set_buffered_amount_low_threshold is used to update the threshold. |
| 429 | /// See buffered_amount_low_threshold(). |
| 430 | pub fn set_buffered_amount_low_threshold(&mut self, th: usize) -> Result<()> { |
| 431 | if let Some(s) = self.association.streams.get_mut(&self.stream_identifier) { |
| 432 | s.buffered_amount_low = th; |
| 433 | Ok(()) |
| 434 | } else { |
| 435 | Err(Error::ErrStreamClosed) |
| 436 | } |
| 437 | } |
| 438 | |
| 439 | /// buffered_amount_high_threshold returns the number of bytes of buffered outgoing data that is |
| 440 | /// considered "high." Defaults to usize::MAX (effectively disabled). |
| 441 | pub fn buffered_amount_high_threshold(&self) -> Result<usize> { |
| 442 | if let Some(s) = self.association.streams.get(&self.stream_identifier) { |
| 443 | Ok(s.buffered_amount_high) |
| 444 | } else { |
| 445 | Err(Error::ErrStreamClosed) |
| 446 | } |
| 447 | } |
| 448 | |
| 449 | /// set_buffered_amount_high_threshold is used to update the threshold. |
| 450 | /// See buffered_amount_high_threshold(). |
| 451 | pub fn set_buffered_amount_high_threshold(&mut self, th: usize) -> Result<()> { |
| 452 | if let Some(s) = self.association.streams.get_mut(&self.stream_identifier) { |
| 453 | s.buffered_amount_high = th; |
| 454 | Ok(()) |
| 455 | } else { |
| 456 | Err(Error::ErrStreamClosed) |
| 457 | } |
| 458 | } |
| 459 | } |
| 460 | |
| 461 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Default)] |
| 462 | pub enum RecvSendState { |
| 463 | #[default] |
| 464 | Closed = 0, |
| 465 | Readable = 1, |
| 466 | Writable = 2, |
| 467 | ReadWritable = 3, |
| 468 | } |
| 469 | |
| 470 | impl From<u8> for RecvSendState { |
| 471 | fn from(v: u8) -> Self { |
| 472 | match v { |
| 473 | 1 => RecvSendState::Readable, |
| 474 | 2 => RecvSendState::Writable, |
| 475 | 3 => RecvSendState::ReadWritable, |
| 476 | _ => RecvSendState::Closed, |
| 477 | } |
| 478 | } |
| 479 | } |
| 480 | |
| 481 | /// StreamState represents the state of an SCTP stream |
| 482 | #[derive(Default, Debug)] |
| 483 | pub struct StreamState { |
| 484 | pub(crate) side: Side, |
| 485 | pub(crate) max_payload_size: u32, |
| 486 | pub(crate) stream_identifier: StreamId, |
| 487 | pub(crate) default_payload_type: PayloadProtocolIdentifier, |
| 488 | pub(crate) reassembly_queue: ReassemblyQueue, |
| 489 | pub(crate) sequence_number: u16, |
| 490 | pub(crate) state: RecvSendState, |
| 491 | pub(crate) unordered: bool, |
| 492 | pub(crate) reliability_type: ReliabilityType, |
| 493 | pub(crate) reliability_value: u32, |
| 494 | pub(crate) buffered_amount: usize, |
| 495 | pub(crate) buffered_amount_low: usize, |
| 496 | pub(crate) buffered_amount_high: usize, |
| 497 | } |
| 498 | impl StreamState { |
| 499 | pub(crate) fn new( |
| 500 | side: Side, |
| 501 | stream_identifier: StreamId, |
| 502 | max_payload_size: u32, |
| 503 | max_receive_message_size: u32, |
| 504 | default_payload_type: PayloadProtocolIdentifier, |
| 505 | ) -> Self { |
| 506 | StreamState { |
| 507 | side, |
| 508 | stream_identifier, |
| 509 | max_payload_size, |
| 510 | default_payload_type, |
| 511 | reassembly_queue: ReassemblyQueue::new(stream_identifier, max_receive_message_size), |
| 512 | sequence_number: 0, |
| 513 | state: RecvSendState::ReadWritable, |
| 514 | unordered: false, |
| 515 | reliability_type: ReliabilityType::Reliable, |
| 516 | reliability_value: 0, |
| 517 | buffered_amount: 0, |
| 518 | buffered_amount_low: 0, |
| 519 | buffered_amount_high: usize::MAX, |
| 520 | } |
| 521 | } |
| 522 | |
| 523 | pub(crate) fn handle_data(&mut self, pd: &ChunkPayloadData) -> Result<bool> { |
| 524 | self.reassembly_queue.push(pd.clone()) |
| 525 | } |
| 526 | |
| 527 | fn packetize( |
| 528 | &mut self, |
| 529 | raw: &Bytes, |
| 530 | ppi: PayloadProtocolIdentifier, |
| 531 | ) -> (bool, Vec<ChunkPayloadData>) { |
| 532 | let mut i = 0; |
| 533 | let mut remaining = raw.len(); |
| 534 | |
| 535 | // From draft-ietf-rtcweb-data-protocol-09, section 6: |
| 536 | // All Data Channel Establishment Protocol messages MUST be sent using |
| 537 | // ordered delivery and reliable transmission. |
| 538 | let unordered = ppi != PayloadProtocolIdentifier::Dcep && self.unordered; |
| 539 | |
| 540 | let mut chunks = vec![]; |
| 541 | |
| 542 | let head_abandoned = false; |
| 543 | let head_all_inflight = false; |
| 544 | while remaining != 0 { |
| 545 | // self.association.max_payload_size |
| 546 | let fragment_size = core::cmp::min(self.max_payload_size as usize, remaining); |
| 547 | |
| 548 | // Copy the userdata since we'll have to store it until acked |
| 549 | // and the caller may re-use the buffer in the mean time |
| 550 | let user_data = raw.slice(i..i + fragment_size); |
| 551 | |
| 552 | let chunk = ChunkPayloadData { |
| 553 | stream_identifier: self.stream_identifier, |
| 554 | user_data, |
| 555 | unordered, |
| 556 | beginning_fragment: i == 0, |
| 557 | ending_fragment: remaining - fragment_size == 0, |
| 558 | immediate_sack: false, |
| 559 | payload_type: ppi, |
| 560 | stream_sequence_number: self.sequence_number, |
| 561 | abandoned: head_abandoned, // all fragmented chunks use the same abandoned |
| 562 | all_inflight: head_all_inflight, // all fragmented chunks use the same all_inflight |
| 563 | ..Default::default() |
| 564 | }; |
| 565 | |
| 566 | chunks.push(chunk); |
| 567 | |
| 568 | remaining -= fragment_size; |
| 569 | i += fragment_size; |
| 570 | } |
| 571 | |
| 572 | // RFC 4960 Sec 6.6 |
| 573 | // Note: When transmitting ordered and unordered data, an endpoint does |
| 574 | // not increment its Stream Sequence Number when transmitting a DATA |
| 575 | // chunk with U flag set to 1. |
| 576 | if !unordered { |
| 577 | self.sequence_number = self.sequence_number.wrapping_add(1); |
| 578 | } |
| 579 | |
| 580 | let old_amount = self.buffered_amount; |
| 581 | self.buffered_amount += raw.len(); |
| 582 | let new_amount = self.buffered_amount; |
| 583 | |
| 584 | // Check if we crossed the high threshold |
| 585 | let is_buffered_amount_high = |
| 586 | old_amount < self.buffered_amount_high && new_amount >= self.buffered_amount_high; |
| 587 | |
| 588 | (is_buffered_amount_high, chunks) |
| 589 | } |
| 590 | |
| 591 | /// This method is called by association's read_loop (go-)routine to notify this stream |
| 592 | /// of the specified amount of outgoing data has been delivered to the peer. |
| 593 | pub(crate) fn on_buffer_released(&mut self, n_bytes_released: i64) -> bool { |
| 594 | if n_bytes_released <= 0 { |
| 595 | return false; |
| 596 | } |
| 597 | |
| 598 | let from_amount = self.buffered_amount; |
| 599 | let new_amount = if from_amount < n_bytes_released as usize { |
| 600 | self.buffered_amount = 0; |
| 601 | error!( |
| 602 | "[{}] released buffer size {} should be <= {}", |
| 603 | self.side, n_bytes_released, 0, |
| 604 | ); |
| 605 | 0 |
| 606 | } else { |
| 607 | self.buffered_amount -= n_bytes_released as usize; |
| 608 | |
| 609 | from_amount - n_bytes_released as usize |
| 610 | }; |
| 611 | |
| 612 | let buffered_amount_low = self.buffered_amount_low; |
| 613 | |
| 614 | trace!( |
| 615 | "[{}] bufferedAmount = {}, from_amount = {}, buffered_amount_low = {}", |
| 616 | self.side, new_amount, from_amount, buffered_amount_low, |
| 617 | ); |
| 618 | |
| 619 | from_amount > buffered_amount_low && new_amount <= buffered_amount_low |
| 620 | } |
| 621 | |
| 622 | pub(crate) fn get_num_bytes_in_reassembly_queue(&self) -> usize { |
| 623 | // No lock is required as it reads the size with atomic load function. |
| 624 | self.reassembly_queue.get_num_bytes() |
| 625 | } |
| 626 | } |