Skip to content
File

Blob: firmware/vendor/sctp-proto/src/queue/payload_queue.rs

rust192 lines
1use crate::chunk::chunk_payload_data::ChunkPayloadData;
2use crate::chunk::chunk_selective_ack::GapAckBlock;
3use crate::util::*;
4 
5use alloc::string::String;
6use alloc::vec::Vec;
7use std::collections::HashMap;
8 
9#[derive(Default, Debug)]
10pub(crate) struct PayloadQueue {
11 // length: usize,
12 chunk_map: HashMap<u32, ChunkPayloadData>,
13 pub(crate) sorted: Vec<u32>,
14 dup_tsn: Vec<u32>,
15 n_bytes: usize,
16}
17 
18impl PayloadQueue {
19 pub(crate) fn new() -> Self {
20 PayloadQueue::default()
21 }
22 
23 pub(crate) fn update_sorted_keys(&mut self) {
24 self.sorted.sort_by(|a, b| {
25 if sna32lt(*a, *b) {
26 core::cmp::Ordering::Less
27 } else {
28 core::cmp::Ordering::Greater
29 }
30 });
31 }
32 
33 pub(crate) fn can_push(&self, p: &ChunkPayloadData, cumulative_tsn: u32) -> bool {
34 !(self.chunk_map.contains_key(&p.tsn) || sna32lte(p.tsn, cumulative_tsn))
35 }
36 
37 pub(crate) fn push_no_check(&mut self, p: ChunkPayloadData) {
38 self.n_bytes += p.user_data.len();
39 self.sorted.push(p.tsn);
40 self.chunk_map.insert(p.tsn, p);
41 //self.length += 1;
42 self.update_sorted_keys();
43 }
44 
45 /// push pushes a payload data. If the payload data is already in our queue or
46 /// older than our cumulative_tsn marker, it will be recored as duplications,
47 /// which can later be retrieved using popDuplicates.
48 pub(crate) fn push(&mut self, p: ChunkPayloadData, cumulative_tsn: u32) -> bool {
49 let ok = self.chunk_map.contains_key(&p.tsn);
50 if ok || sna32lte(p.tsn, cumulative_tsn) {
51 // Found the packet, log in dups
52 self.dup_tsn.push(p.tsn);
53 return false;
54 }
55 
56 self.n_bytes += p.user_data.len();
57 self.sorted.push(p.tsn);
58 self.chunk_map.insert(p.tsn, p);
59 //self.length += 1;
60 self.update_sorted_keys();
61 
62 true
63 }
64 
65 /// pop pops only if the oldest chunk's TSN matches the given TSN.
66 pub(crate) fn pop(&mut self, tsn: u32) -> Option<ChunkPayloadData> {
67 if !self.sorted.is_empty() && tsn == self.sorted[0] {
68 self.sorted.remove(0);
69 if let Some(c) = self.chunk_map.remove(&tsn) {
70 //self.length -= 1;
71 self.n_bytes = self.n_bytes.saturating_sub(c.user_data.len());
72 return Some(c);
73 }
74 }
75 
76 None
77 }
78 
79 /// Removes every queued chunk with a TSN at or before `cumulative_tsn`.
80 ///
81 /// Used when a FORWARD-TSN moves the cumulative TSN point past chunks the
82 /// peer abandoned. The cost is proportional to the number of queued chunks,
83 /// not to the size of the TSN jump: `cumulative_tsn` comes off the wire and
84 /// may be up to 2^31 ahead of the current point.
85 pub(crate) fn pop_up_to(&mut self, cumulative_tsn: u32) {
86 let chunk_map = &mut self.chunk_map;
87 let n_bytes = &mut self.n_bytes;
88 self.sorted.retain(|tsn| {
89 if sna32lte(*tsn, cumulative_tsn) {
90 if let Some(c) = chunk_map.remove(tsn) {
91 *n_bytes = n_bytes.saturating_sub(c.user_data.len());
92 }
93 false
94 } else {
95 true
96 }
97 });
98 }
99 
100 /// get returns reference to chunkPayloadData with the given TSN value.
101 pub(crate) fn get(&self, tsn: u32) -> Option<&ChunkPayloadData> {
102 self.chunk_map.get(&tsn)
103 }
104 pub(crate) fn get_mut(&mut self, tsn: u32) -> Option<&mut ChunkPayloadData> {
105 self.chunk_map.get_mut(&tsn)
106 }
107 
108 /// popDuplicates returns an array of TSN values that were found duplicate.
109 pub(crate) fn pop_duplicates(&mut self) -> Vec<u32> {
110 core::mem::take(&mut self.dup_tsn)
111 }
112 
113 pub(crate) fn get_gap_ack_blocks(&self, cumulative_tsn: u32) -> Vec<GapAckBlock> {
114 if self.chunk_map.is_empty() {
115 return vec![];
116 }
117 
118 let mut b = GapAckBlock::default();
119 let mut gap_ack_blocks = vec![];
120 for (i, tsn) in self.sorted.iter().enumerate() {
121 let diff = if *tsn >= cumulative_tsn {
122 (*tsn - cumulative_tsn) as u16
123 } else {
124 0
125 };
126 
127 if i == 0 {
128 b.start = diff;
129 b.end = b.start;
130 } else if b.end + 1 == diff {
131 b.end += 1;
132 } else {
133 gap_ack_blocks.push(b);
134 
135 b.start = diff;
136 b.end = diff;
137 }
138 }
139 
140 gap_ack_blocks.push(b);
141 
142 gap_ack_blocks
143 }
144 
145 pub(crate) fn get_gap_ack_blocks_string(&self, cumulative_tsn: u32) -> String {
146 let mut s = format!("cumTSN={}", cumulative_tsn);
147 for b in self.get_gap_ack_blocks(cumulative_tsn) {
148 s += format!(",{}-{}", b.start, b.end).as_str();
149 }
150 s
151 }
152 
153 pub(crate) fn mark_as_acked(&mut self, tsn: u32) -> usize {
154 if let Some(c) = self.chunk_map.get_mut(&tsn) {
155 c.acked = true;
156 c.retransmit = false;
157 let n = c.user_data.len();
158 self.n_bytes -= n;
159 c.user_data.clear();
160 n
161 } else {
162 0
163 }
164 }
165 
166 pub(crate) fn get_last_tsn_received(&self) -> Option<&u32> {
167 self.sorted.last()
168 }
169 
170 pub(crate) fn mark_all_to_retrasmit(&mut self) {
171 for c in self.chunk_map.values_mut() {
172 if c.acked || c.abandoned() {
173 continue;
174 }
175 c.retransmit = true;
176 }
177 }
178 
179 pub(crate) fn get_num_bytes(&self) -> usize {
180 self.n_bytes
181 }
182 
183 pub(crate) fn len(&self) -> usize {
184 //assert_eq!(self.chunk_map.len(), self.length);
185 self.chunk_map.len()
186 }
187 
188 pub(crate) fn is_empty(&self) -> bool {
189 self.len() == 0
190 }
191}