blob: 89a6ad750f36bae66eb0adb502ba09888bc78df5 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h"
6
vasilvv872e7a32019-03-12 16:42:44 -07007#include <string>
8
QUICHE teama6ef0a62019-03-07 20:34:33 -05009#include "net/third_party/quiche/src/quic/core/quic_constants.h"
10#include "net/third_party/quiche/src/quic/core/quic_interval.h"
11#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
12#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
13#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
14#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
15#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050016
17namespace quic {
18namespace {
19
20size_t CalculateBlockCount(size_t max_capacity_bytes) {
21 return (max_capacity_bytes + QuicStreamSequencerBuffer::kBlockSizeBytes - 1) /
22 QuicStreamSequencerBuffer::kBlockSizeBytes;
23}
24
25// Upper limit of how many gaps allowed in buffer, which ensures a reasonable
26// number of iterations needed to find the right gap to fill when a frame
27// arrives.
28const size_t kMaxNumDataIntervalsAllowed = 2 * kMaxPacketGap;
29
30} // namespace
31
32QuicStreamSequencerBuffer::QuicStreamSequencerBuffer(size_t max_capacity_bytes)
33 : max_buffer_capacity_bytes_(max_capacity_bytes),
34 blocks_count_(CalculateBlockCount(max_capacity_bytes)),
35 total_bytes_read_(0),
bncc16be362019-08-28 08:07:29 -070036 blocks_(nullptr) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050037 Clear();
38}
39
40QuicStreamSequencerBuffer::~QuicStreamSequencerBuffer() {
41 Clear();
42}
43
44void QuicStreamSequencerBuffer::Clear() {
45 if (blocks_ != nullptr) {
46 for (size_t i = 0; i < blocks_count_; ++i) {
47 if (blocks_[i] != nullptr) {
48 RetireBlock(i);
49 }
50 }
51 }
52 num_bytes_buffered_ = 0;
53 bytes_received_.Clear();
54 bytes_received_.Add(0, total_bytes_read_);
55}
56
57bool QuicStreamSequencerBuffer::RetireBlock(size_t idx) {
58 if (blocks_[idx] == nullptr) {
59 QUIC_BUG << "Try to retire block twice";
60 return false;
61 }
62 delete blocks_[idx];
63 blocks_[idx] = nullptr;
64 QUIC_DVLOG(1) << "Retired block with index: " << idx;
65 return true;
66}
67
68QuicErrorCode QuicStreamSequencerBuffer::OnStreamData(
69 QuicStreamOffset starting_offset,
70 QuicStringPiece data,
71 size_t* const bytes_buffered,
vasilvvc48c8712019-03-11 13:38:16 -070072 std::string* error_details) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050073 *bytes_buffered = 0;
74 size_t size = data.size();
75 if (size == 0) {
76 *error_details = "Received empty stream frame without FIN.";
77 return QUIC_EMPTY_STREAM_FRAME_NO_FIN;
78 }
79 // Write beyond the current range this buffer is covering.
80 if (starting_offset + size > total_bytes_read_ + max_buffer_capacity_bytes_ ||
81 starting_offset + size < starting_offset) {
82 *error_details = "Received data beyond available range.";
83 return QUIC_INTERNAL_ERROR;
84 }
85 if (bytes_received_.Empty() ||
86 starting_offset >= bytes_received_.rbegin()->max() ||
87 bytes_received_.IsDisjoint(QuicInterval<QuicStreamOffset>(
88 starting_offset, starting_offset + size))) {
89 // Optimization for the typical case, when all data is newly received.
wub8d8dc242019-05-21 14:29:36 -070090 bytes_received_.AddOptimizedForAppend(starting_offset,
91 starting_offset + size);
92 if (bytes_received_.Size() >= kMaxNumDataIntervalsAllowed) {
93 // This frame is going to create more intervals than allowed. Stop
94 // processing.
95 *error_details = "Too many data intervals received for this stream.";
96 return QUIC_TOO_MANY_STREAM_DATA_INTERVALS;
QUICHE teama6ef0a62019-03-07 20:34:33 -050097 }
wub8d8dc242019-05-21 14:29:36 -070098
QUICHE teama6ef0a62019-03-07 20:34:33 -050099 size_t bytes_copy = 0;
100 if (!CopyStreamData(starting_offset, data, &bytes_copy, error_details)) {
101 return QUIC_STREAM_SEQUENCER_INVALID_STATE;
102 }
103 *bytes_buffered += bytes_copy;
104 num_bytes_buffered_ += *bytes_buffered;
105 return QUIC_NO_ERROR;
106 }
107 // Slow path, received data overlaps with received data.
108 QuicIntervalSet<QuicStreamOffset> newly_received(starting_offset,
109 starting_offset + size);
110 newly_received.Difference(bytes_received_);
111 if (newly_received.Empty()) {
112 return QUIC_NO_ERROR;
113 }
114 bytes_received_.Add(starting_offset, starting_offset + size);
115 if (bytes_received_.Size() >= kMaxNumDataIntervalsAllowed) {
116 // This frame is going to create more intervals than allowed. Stop
117 // processing.
118 *error_details = "Too many data intervals received for this stream.";
119 return QUIC_TOO_MANY_STREAM_DATA_INTERVALS;
120 }
121 for (const auto& interval : newly_received) {
122 const QuicStreamOffset copy_offset = interval.min();
123 const QuicByteCount copy_length = interval.max() - interval.min();
124 size_t bytes_copy = 0;
125 if (!CopyStreamData(copy_offset,
126 data.substr(copy_offset - starting_offset, copy_length),
127 &bytes_copy, error_details)) {
128 return QUIC_STREAM_SEQUENCER_INVALID_STATE;
129 }
130 *bytes_buffered += bytes_copy;
131 }
132 num_bytes_buffered_ += *bytes_buffered;
133 return QUIC_NO_ERROR;
134}
135
136bool QuicStreamSequencerBuffer::CopyStreamData(QuicStreamOffset offset,
137 QuicStringPiece data,
138 size_t* bytes_copy,
vasilvvc48c8712019-03-11 13:38:16 -0700139 std::string* error_details) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500140 *bytes_copy = 0;
141 size_t source_remaining = data.size();
142 if (source_remaining == 0) {
143 return true;
144 }
145 const char* source = data.data();
146 // Write data block by block. If corresponding block has not created yet,
147 // create it first.
148 // Stop when all data are written or reaches the logical end of the buffer.
149 while (source_remaining > 0) {
150 const size_t write_block_num = GetBlockIndex(offset);
151 const size_t write_block_offset = GetInBlockOffset(offset);
152 DCHECK_GT(blocks_count_, write_block_num);
153
154 size_t block_capacity = GetBlockCapacity(write_block_num);
155 size_t bytes_avail = block_capacity - write_block_offset;
156
157 // If this write meets the upper boundary of the buffer,
158 // reduce the available free bytes.
159 if (offset + bytes_avail > total_bytes_read_ + max_buffer_capacity_bytes_) {
160 bytes_avail = total_bytes_read_ + max_buffer_capacity_bytes_ - offset;
161 }
162
163 if (blocks_ == nullptr) {
164 blocks_.reset(new BufferBlock*[blocks_count_]());
165 for (size_t i = 0; i < blocks_count_; ++i) {
166 blocks_[i] = nullptr;
167 }
168 }
169
170 if (write_block_num >= blocks_count_) {
171 *error_details = QuicStrCat(
172 "QuicStreamSequencerBuffer error: OnStreamData() exceed array bounds."
173 "write offset = ",
174 offset, " write_block_num = ", write_block_num,
175 " blocks_count_ = ", blocks_count_);
176 return false;
177 }
178 if (blocks_ == nullptr) {
179 *error_details =
180 "QuicStreamSequencerBuffer error: OnStreamData() blocks_ is null";
181 return false;
182 }
183 if (blocks_[write_block_num] == nullptr) {
184 // TODO(danzh): Investigate if using a freelist would improve performance.
185 // Same as RetireBlock().
186 blocks_[write_block_num] = new BufferBlock();
187 }
188
189 const size_t bytes_to_copy =
190 std::min<size_t>(bytes_avail, source_remaining);
191 char* dest = blocks_[write_block_num]->buffer + write_block_offset;
192 QUIC_DVLOG(1) << "Write at offset: " << offset
193 << " length: " << bytes_to_copy;
194
195 if (dest == nullptr || source == nullptr) {
196 *error_details = QuicStrCat(
197 "QuicStreamSequencerBuffer error: OnStreamData()"
198 " dest == nullptr: ",
199 (dest == nullptr), " source == nullptr: ", (source == nullptr),
200 " Writing at offset ", offset, " Gaps: ", GapsDebugString(),
201 " Remaining frames: ", ReceivedFramesDebugString(),
202 " total_bytes_read_ = ", total_bytes_read_);
203 return false;
204 }
205 memcpy(dest, source, bytes_to_copy);
206 source += bytes_to_copy;
207 source_remaining -= bytes_to_copy;
208 offset += bytes_to_copy;
209 *bytes_copy += bytes_to_copy;
210 }
211 return true;
212}
213
214QuicErrorCode QuicStreamSequencerBuffer::Readv(const iovec* dest_iov,
215 size_t dest_count,
216 size_t* bytes_read,
vasilvvc48c8712019-03-11 13:38:16 -0700217 std::string* error_details) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500218 *bytes_read = 0;
219 for (size_t i = 0; i < dest_count && ReadableBytes() > 0; ++i) {
220 char* dest = reinterpret_cast<char*>(dest_iov[i].iov_base);
221 DCHECK(dest != nullptr);
222 size_t dest_remaining = dest_iov[i].iov_len;
223 while (dest_remaining > 0 && ReadableBytes() > 0) {
224 size_t block_idx = NextBlockToRead();
225 size_t start_offset_in_block = ReadOffset();
226 size_t block_capacity = GetBlockCapacity(block_idx);
227 size_t bytes_available_in_block = std::min<size_t>(
228 ReadableBytes(), block_capacity - start_offset_in_block);
229 size_t bytes_to_copy =
230 std::min<size_t>(bytes_available_in_block, dest_remaining);
231 DCHECK_GT(bytes_to_copy, 0u);
232 if (blocks_[block_idx] == nullptr || dest == nullptr) {
233 *error_details = QuicStrCat(
234 "QuicStreamSequencerBuffer error:"
235 " Readv() dest == nullptr: ",
236 (dest == nullptr), " blocks_[", block_idx,
237 "] == nullptr: ", (blocks_[block_idx] == nullptr),
238 " Gaps: ", GapsDebugString(),
239 " Remaining frames: ", ReceivedFramesDebugString(),
240 " total_bytes_read_ = ", total_bytes_read_);
241 return QUIC_STREAM_SEQUENCER_INVALID_STATE;
242 }
243 memcpy(dest, blocks_[block_idx]->buffer + start_offset_in_block,
244 bytes_to_copy);
245 dest += bytes_to_copy;
246 dest_remaining -= bytes_to_copy;
247 num_bytes_buffered_ -= bytes_to_copy;
248 total_bytes_read_ += bytes_to_copy;
249 *bytes_read += bytes_to_copy;
250
251 // Retire the block if all the data is read out and no other data is
252 // stored in this block.
253 // In case of failing to retire a block which is ready to retire, return
254 // immediately.
255 if (bytes_to_copy == bytes_available_in_block) {
256 bool retire_successfully = RetireBlockIfEmpty(block_idx);
257 if (!retire_successfully) {
258 *error_details = QuicStrCat(
259 "QuicStreamSequencerBuffer error: fail to retire block ",
260 block_idx,
261 " as the block is already released, total_bytes_read_ = ",
262 total_bytes_read_, " Gaps: ", GapsDebugString());
263 return QUIC_STREAM_SEQUENCER_INVALID_STATE;
264 }
265 }
266 }
267 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500268
269 return QUIC_NO_ERROR;
270}
271
272int QuicStreamSequencerBuffer::GetReadableRegions(struct iovec* iov,
273 int iov_count) const {
274 DCHECK(iov != nullptr);
275 DCHECK_GT(iov_count, 0);
276
277 if (ReadableBytes() == 0) {
278 iov[0].iov_base = nullptr;
279 iov[0].iov_len = 0;
280 return 0;
281 }
282
283 size_t start_block_idx = NextBlockToRead();
284 QuicStreamOffset readable_offset_end = FirstMissingByte() - 1;
285 DCHECK_GE(readable_offset_end + 1, total_bytes_read_);
286 size_t end_block_offset = GetInBlockOffset(readable_offset_end);
287 size_t end_block_idx = GetBlockIndex(readable_offset_end);
288
289 // If readable region is within one block, deal with it seperately.
290 if (start_block_idx == end_block_idx && ReadOffset() <= end_block_offset) {
291 iov[0].iov_base = blocks_[start_block_idx]->buffer + ReadOffset();
292 iov[0].iov_len = ReadableBytes();
293 QUIC_DVLOG(1) << "Got only a single block with index: " << start_block_idx;
294 return 1;
295 }
296
297 // Get first block
298 iov[0].iov_base = blocks_[start_block_idx]->buffer + ReadOffset();
299 iov[0].iov_len = GetBlockCapacity(start_block_idx) - ReadOffset();
300 QUIC_DVLOG(1) << "Got first block " << start_block_idx << " with len "
301 << iov[0].iov_len;
302 DCHECK_GT(readable_offset_end + 1, total_bytes_read_ + iov[0].iov_len)
303 << "there should be more available data";
304
305 // Get readable regions of the rest blocks till either 2nd to last block
306 // before gap is met or |iov| is filled. For these blocks, one whole block is
307 // a region.
308 int iov_used = 1;
309 size_t block_idx = (start_block_idx + iov_used) % blocks_count_;
310 while (block_idx != end_block_idx && iov_used < iov_count) {
311 DCHECK(nullptr != blocks_[block_idx]);
312 iov[iov_used].iov_base = blocks_[block_idx]->buffer;
313 iov[iov_used].iov_len = GetBlockCapacity(block_idx);
314 QUIC_DVLOG(1) << "Got block with index: " << block_idx;
315 ++iov_used;
316 block_idx = (start_block_idx + iov_used) % blocks_count_;
317 }
318
319 // Deal with last block if |iov| can hold more.
320 if (iov_used < iov_count) {
321 DCHECK(nullptr != blocks_[block_idx]);
322 iov[iov_used].iov_base = blocks_[end_block_idx]->buffer;
323 iov[iov_used].iov_len = end_block_offset + 1;
324 QUIC_DVLOG(1) << "Got last block with index: " << end_block_idx;
325 ++iov_used;
326 }
327 return iov_used;
328}
329
330bool QuicStreamSequencerBuffer::GetReadableRegion(iovec* iov) const {
331 return GetReadableRegions(iov, 1) == 1;
332}
333
bnc7b3e0a92019-06-24 16:06:45 -0700334bool QuicStreamSequencerBuffer::PeekRegion(QuicStreamOffset offset,
335 iovec* iov) const {
336 DCHECK(iov);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500337
bnc7b3e0a92019-06-24 16:06:45 -0700338 if (offset < total_bytes_read_) {
339 // Data at |offset| has already been consumed.
340 return false;
341 }
342
343 if (offset >= FirstMissingByte()) {
344 // Data at |offset| has not been received yet.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500345 return false;
346 }
347
bnc8ee28242019-06-24 10:17:11 -0700348 // Beginning of region.
bnc7b3e0a92019-06-24 16:06:45 -0700349 size_t block_idx = GetBlockIndex(offset);
350 size_t block_offset = GetInBlockOffset(offset);
bnc8ee28242019-06-24 10:17:11 -0700351 iov->iov_base = blocks_[block_idx]->buffer + block_offset;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500352
bnc8ee28242019-06-24 10:17:11 -0700353 // Determine if entire block has been received.
354 size_t end_block_idx = GetBlockIndex(FirstMissingByte());
355 if (block_idx == end_block_idx) {
356 // Only read part of block before FirstMissingByte().
357 iov->iov_len = GetInBlockOffset(FirstMissingByte()) - block_offset;
358 } else {
359 // Read entire block.
360 iov->iov_len = GetBlockCapacity(block_idx) - block_offset;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500361 }
bnc8ee28242019-06-24 10:17:11 -0700362
bnc7b3e0a92019-06-24 16:06:45 -0700363 return true;
364}
365
QUICHE teama6ef0a62019-03-07 20:34:33 -0500366bool QuicStreamSequencerBuffer::MarkConsumed(size_t bytes_used) {
367 if (bytes_used > ReadableBytes()) {
368 return false;
369 }
370 size_t bytes_to_consume = bytes_used;
371 while (bytes_to_consume > 0) {
372 size_t block_idx = NextBlockToRead();
373 size_t offset_in_block = ReadOffset();
374 size_t bytes_available = std::min<size_t>(
375 ReadableBytes(), GetBlockCapacity(block_idx) - offset_in_block);
376 size_t bytes_read = std::min<size_t>(bytes_to_consume, bytes_available);
377 total_bytes_read_ += bytes_read;
378 num_bytes_buffered_ -= bytes_read;
379 bytes_to_consume -= bytes_read;
380 // If advanced to the end of current block and end of buffer hasn't wrapped
381 // to this block yet.
382 if (bytes_available == bytes_read) {
383 RetireBlockIfEmpty(block_idx);
384 }
385 }
bncc16be362019-08-28 08:07:29 -0700386
QUICHE teama6ef0a62019-03-07 20:34:33 -0500387 return true;
388}
389
390size_t QuicStreamSequencerBuffer::FlushBufferedFrames() {
391 size_t prev_total_bytes_read = total_bytes_read_;
392 total_bytes_read_ = NextExpectedByte();
393 Clear();
394 return total_bytes_read_ - prev_total_bytes_read;
395}
396
397void QuicStreamSequencerBuffer::ReleaseWholeBuffer() {
398 Clear();
399 blocks_.reset(nullptr);
400}
401
402size_t QuicStreamSequencerBuffer::ReadableBytes() const {
403 return FirstMissingByte() - total_bytes_read_;
404}
405
406bool QuicStreamSequencerBuffer::HasBytesToRead() const {
407 return ReadableBytes() > 0;
408}
409
410QuicStreamOffset QuicStreamSequencerBuffer::BytesConsumed() const {
411 return total_bytes_read_;
412}
413
414size_t QuicStreamSequencerBuffer::BytesBuffered() const {
415 return num_bytes_buffered_;
416}
417
418size_t QuicStreamSequencerBuffer::GetBlockIndex(QuicStreamOffset offset) const {
419 return (offset % max_buffer_capacity_bytes_) / kBlockSizeBytes;
420}
421
422size_t QuicStreamSequencerBuffer::GetInBlockOffset(
423 QuicStreamOffset offset) const {
424 return (offset % max_buffer_capacity_bytes_) % kBlockSizeBytes;
425}
426
427size_t QuicStreamSequencerBuffer::ReadOffset() const {
428 return GetInBlockOffset(total_bytes_read_);
429}
430
431size_t QuicStreamSequencerBuffer::NextBlockToRead() const {
432 return GetBlockIndex(total_bytes_read_);
433}
434
435bool QuicStreamSequencerBuffer::RetireBlockIfEmpty(size_t block_index) {
436 DCHECK(ReadableBytes() == 0 || GetInBlockOffset(total_bytes_read_) == 0)
437 << "RetireBlockIfEmpty() should only be called when advancing to next "
438 << "block or a gap has been reached.";
439 // If the whole buffer becomes empty, the last piece of data has been read.
440 if (Empty()) {
441 return RetireBlock(block_index);
442 }
443
444 // Check where the logical end of this buffer is.
445 // Not empty if the end of circular buffer has been wrapped to this block.
446 if (GetBlockIndex(NextExpectedByte() - 1) == block_index) {
447 return true;
448 }
449
450 // Read index remains in this block, which means a gap has been reached.
451 if (NextBlockToRead() == block_index) {
452 if (bytes_received_.Size() > 1) {
453 auto it = bytes_received_.begin();
454 ++it;
455 if (GetBlockIndex(it->min()) == block_index) {
456 // Do not retire the block if next data interval is in this block.
457 return true;
458 }
459 } else {
460 QUIC_BUG << "Read stopped at where it shouldn't.";
461 return false;
462 }
463 }
464 return RetireBlock(block_index);
465}
466
467bool QuicStreamSequencerBuffer::Empty() const {
468 return bytes_received_.Empty() ||
469 (bytes_received_.Size() == 1 && total_bytes_read_ > 0 &&
470 bytes_received_.begin()->max() == total_bytes_read_);
471}
472
473size_t QuicStreamSequencerBuffer::GetBlockCapacity(size_t block_index) const {
474 if ((block_index + 1) == blocks_count_) {
475 size_t result = max_buffer_capacity_bytes_ % kBlockSizeBytes;
476 if (result == 0) { // whole block
477 result = kBlockSizeBytes;
478 }
479 return result;
480 } else {
481 return kBlockSizeBytes;
482 }
483}
484
bnc198aa992019-06-25 10:37:43 -0700485std::string QuicStreamSequencerBuffer::GapsDebugString() const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500486 // TODO(vasilvv): this should return the complement of |bytes_received_|.
487 return bytes_received_.ToString();
488}
489
bnc198aa992019-06-25 10:37:43 -0700490std::string QuicStreamSequencerBuffer::ReceivedFramesDebugString() const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500491 return bytes_received_.ToString();
492}
493
494QuicStreamOffset QuicStreamSequencerBuffer::FirstMissingByte() const {
495 if (bytes_received_.Empty() || bytes_received_.begin()->min() > 0) {
496 // Offset 0 is not received yet.
497 return 0;
498 }
499 return bytes_received_.begin()->max();
500}
501
502QuicStreamOffset QuicStreamSequencerBuffer::NextExpectedByte() const {
503 if (bytes_received_.Empty()) {
504 return 0;
505 }
506 return bytes_received_.rbegin()->max();
507}
508
509} // namespace quic