| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/quic/quic_stream_sequencer.h" | 5 #include "net/quic/quic_stream_sequencer.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <limits> | 8 #include <limits> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 close_offset_(numeric_limits<QuicStreamOffset>::max()), | 23 close_offset_(numeric_limits<QuicStreamOffset>::max()), |
| 24 blocked_(false), | 24 blocked_(false), |
| 25 num_bytes_buffered_(0), | 25 num_bytes_buffered_(0), |
| 26 num_frames_received_(0), | 26 num_frames_received_(0), |
| 27 num_duplicate_frames_received_(0) { | 27 num_duplicate_frames_received_(0) { |
| 28 } | 28 } |
| 29 | 29 |
| 30 QuicStreamSequencer::~QuicStreamSequencer() { | 30 QuicStreamSequencer::~QuicStreamSequencer() { |
| 31 } | 31 } |
| 32 | 32 |
| 33 bool QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) { | 33 void QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) { |
| 34 ++num_frames_received_; | 34 ++num_frames_received_; |
| 35 if (IsDuplicate(frame)) { | 35 if (IsDuplicate(frame)) { |
| 36 ++num_duplicate_frames_received_; | 36 ++num_duplicate_frames_received_; |
| 37 // Silently ignore duplicates. | 37 // Silently ignore duplicates. |
| 38 return true; | 38 return; |
| 39 } | 39 } |
| 40 | 40 |
| 41 if (FrameOverlapsBufferedData(frame)) { | 41 if (FrameOverlapsBufferedData(frame)) { |
| 42 stream_->CloseConnectionWithDetails( | 42 stream_->CloseConnectionWithDetails( |
| 43 QUIC_INVALID_STREAM_FRAME, "Stream frame overlaps with buffered data."); | 43 QUIC_INVALID_STREAM_FRAME, "Stream frame overlaps with buffered data."); |
| 44 return false; | 44 return; |
| 45 } | 45 } |
| 46 | 46 |
| 47 QuicStreamOffset byte_offset = frame.offset; | 47 QuicStreamOffset byte_offset = frame.offset; |
| 48 size_t data_len = frame.data.TotalBufferSize(); | 48 size_t data_len = frame.data.TotalBufferSize(); |
| 49 if (data_len == 0 && !frame.fin) { | 49 if (data_len == 0 && !frame.fin) { |
| 50 // Stream frames must have data or a fin flag. | 50 // Stream frames must have data or a fin flag. |
| 51 stream_->CloseConnectionWithDetails(QUIC_INVALID_STREAM_FRAME, | 51 stream_->CloseConnectionWithDetails(QUIC_INVALID_STREAM_FRAME, |
| 52 "Empty stream frame without FIN set."); | 52 "Empty stream frame without FIN set."); |
| 53 return false; | 53 return; |
| 54 } | 54 } |
| 55 | 55 |
| 56 if (frame.fin) { | 56 if (frame.fin) { |
| 57 CloseStreamAtOffset(frame.offset + data_len); | 57 CloseStreamAtOffset(frame.offset + data_len); |
| 58 if (data_len == 0) { | 58 if (data_len == 0) { |
| 59 return true; | 59 return; |
| 60 } | 60 } |
| 61 } | 61 } |
| 62 | 62 |
| 63 IOVector data; | 63 IOVector data; |
| 64 data.AppendIovec(frame.data.iovec(), frame.data.Size()); | 64 data.AppendIovec(frame.data.iovec(), frame.data.Size()); |
| 65 | 65 |
| 66 // If the frame has arrived in-order then we can process it immediately, only | 66 // If the frame has arrived in-order then we can process it immediately, only |
| 67 // buffering if the stream is unable to process it. | 67 // buffering if the stream is unable to process it. |
| 68 if (!blocked_ && byte_offset == num_bytes_consumed_) { | 68 if (!blocked_ && byte_offset == num_bytes_consumed_) { |
| 69 DVLOG(1) << "Processing byte offset " << byte_offset; | 69 DVLOG(1) << "Processing byte offset " << byte_offset; |
| 70 size_t bytes_consumed = 0; | 70 size_t bytes_consumed = 0; |
| 71 for (size_t i = 0; i < data.Size(); ++i) { | 71 for (size_t i = 0; i < data.Size(); ++i) { |
| 72 bytes_consumed += stream_->ProcessRawData( | 72 bytes_consumed += stream_->ProcessRawData( |
| 73 static_cast<char*>(data.iovec()[i].iov_base), | 73 static_cast<char*>(data.iovec()[i].iov_base), |
| 74 data.iovec()[i].iov_len); | 74 data.iovec()[i].iov_len); |
| 75 } | 75 } |
| 76 num_bytes_consumed_ += bytes_consumed; | 76 num_bytes_consumed_ += bytes_consumed; |
| 77 stream_->AddBytesConsumed(bytes_consumed); | 77 stream_->AddBytesConsumed(bytes_consumed); |
| 78 | 78 |
| 79 if (MaybeCloseStream()) { | 79 if (MaybeCloseStream()) { |
| 80 return true; | 80 return; |
| 81 } | 81 } |
| 82 if (bytes_consumed > data_len) { | 82 if (bytes_consumed > data_len) { |
| 83 stream_->Reset(QUIC_ERROR_PROCESSING_STREAM); | 83 stream_->Reset(QUIC_ERROR_PROCESSING_STREAM); |
| 84 return false; | 84 return; |
| 85 } else if (bytes_consumed == data_len) { | 85 } else if (bytes_consumed == data_len) { |
| 86 FlushBufferedFrames(); | 86 FlushBufferedFrames(); |
| 87 return true; // it's safe to ack this frame. | 87 return; // it's safe to ack this frame. |
| 88 } else { | 88 } else { |
| 89 // Set ourselves up to buffer what's left. | 89 // Set ourselves up to buffer what's left. |
| 90 data_len -= bytes_consumed; | 90 data_len -= bytes_consumed; |
| 91 data.Consume(bytes_consumed); | 91 data.Consume(bytes_consumed); |
| 92 byte_offset += bytes_consumed; | 92 byte_offset += bytes_consumed; |
| 93 } | 93 } |
| 94 } | 94 } |
| 95 | 95 |
| 96 // Buffer any remaining data to be consumed by the stream when ready. | 96 // Buffer any remaining data to be consumed by the stream when ready. |
| 97 for (size_t i = 0; i < data.Size(); ++i) { | 97 for (size_t i = 0; i < data.Size(); ++i) { |
| 98 DVLOG(1) << "Buffering stream data at offset " << byte_offset; | 98 DVLOG(1) << "Buffering stream data at offset " << byte_offset; |
| 99 const iovec& iov = data.iovec()[i]; | 99 const iovec& iov = data.iovec()[i]; |
| 100 buffered_frames_.insert(make_pair( | 100 buffered_frames_.insert(make_pair( |
| 101 byte_offset, string(static_cast<char*>(iov.iov_base), iov.iov_len))); | 101 byte_offset, string(static_cast<char*>(iov.iov_base), iov.iov_len))); |
| 102 byte_offset += iov.iov_len; | 102 byte_offset += iov.iov_len; |
| 103 num_bytes_buffered_ += iov.iov_len; | 103 num_bytes_buffered_ += iov.iov_len; |
| 104 } | 104 } |
| 105 return true; | 105 return; |
| 106 } | 106 } |
| 107 | 107 |
| 108 void QuicStreamSequencer::CloseStreamAtOffset(QuicStreamOffset offset) { | 108 void QuicStreamSequencer::CloseStreamAtOffset(QuicStreamOffset offset) { |
| 109 const QuicStreamOffset kMaxOffset = numeric_limits<QuicStreamOffset>::max(); | 109 const QuicStreamOffset kMaxOffset = numeric_limits<QuicStreamOffset>::max(); |
| 110 | 110 |
| 111 // If we have a scheduled termination or close, any new offset should match | 111 // If we have a scheduled termination or close, any new offset should match |
| 112 // it. | 112 // it. |
| 113 if (close_offset_ != kMaxOffset && offset != close_offset_) { | 113 if (close_offset_ != kMaxOffset && offset != close_offset_) { |
| 114 stream_->Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS); | 114 stream_->Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS); |
| 115 return; | 115 return; |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 } | 285 } |
| 286 | 286 |
| 287 void QuicStreamSequencer::RecordBytesConsumed(size_t bytes_consumed) { | 287 void QuicStreamSequencer::RecordBytesConsumed(size_t bytes_consumed) { |
| 288 num_bytes_consumed_ += bytes_consumed; | 288 num_bytes_consumed_ += bytes_consumed; |
| 289 num_bytes_buffered_ -= bytes_consumed; | 289 num_bytes_buffered_ -= bytes_consumed; |
| 290 | 290 |
| 291 stream_->AddBytesConsumed(bytes_consumed); | 291 stream_->AddBytesConsumed(bytes_consumed); |
| 292 } | 292 } |
| 293 | 293 |
| 294 } // namespace net | 294 } // namespace net |
| OLD | NEW |