OLD | NEW |
(Empty) | |
| 1 // 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/quic/quic_frame_list.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 |
| 9 namespace net { |
| 10 |
| 11 QuicFrameList::FrameData::FrameData(QuicStreamOffset offset, string segment) |
| 12 : offset(offset), segment(segment) {} |
| 13 |
| 14 QuicFrameList::QuicFrameList() {} |
| 15 |
| 16 QuicFrameList::~QuicFrameList() { |
| 17 Clear(); |
| 18 } |
| 19 |
| 20 QuicErrorCode QuicFrameList::WriteAtOffset(QuicStreamOffset offset, |
| 21 StringPiece data, |
| 22 size_t* const bytes_written) { |
| 23 *bytes_written = 0; |
| 24 const size_t data_len = data.size(); |
| 25 auto insertion_point = FindInsertionPoint(offset, data_len); |
| 26 if (IsDuplicate(offset, data_len, insertion_point)) { |
| 27 return QUIC_NO_ERROR; |
| 28 } |
| 29 |
| 30 if (FrameOverlapsBufferedData(offset, data_len, insertion_point)) { |
| 31 return QUIC_INVALID_STREAM_DATA; |
| 32 } |
| 33 |
| 34 DVLOG(1) << "Buffering stream data at offset " << offset; |
| 35 // Inserting an empty string and then copying to avoid the extra copy. |
| 36 insertion_point = frame_list_.insert(insertion_point, FrameData(offset, "")); |
| 37 data.CopyToString(&insertion_point->segment); |
| 38 *bytes_written = data_len; |
| 39 return QUIC_NO_ERROR; |
| 40 } |
| 41 |
| 42 // Finds the place the frame should be inserted. If an identical frame is |
| 43 // present, stops on the identical frame. |
| 44 list<QuicFrameList::FrameData>::iterator QuicFrameList::FindInsertionPoint( |
| 45 QuicStreamOffset offset, |
| 46 size_t len) { |
| 47 if (frame_list_.empty()) { |
| 48 return frame_list_.begin(); |
| 49 } |
| 50 // If it's after all buffered_frames, return the end. |
| 51 if (offset >= |
| 52 (frame_list_.rbegin()->offset + frame_list_.rbegin()->segment.length())) { |
| 53 return frame_list_.end(); |
| 54 } |
| 55 auto iter = frame_list_.begin(); |
| 56 // Only advance the iterator if the data begins after the already received |
| 57 // frame. If the new frame overlaps with an existing frame, the iterator will |
| 58 // still point to the frame it overlaps with. |
| 59 while (iter != frame_list_.end() && |
| 60 offset >= iter->offset + iter->segment.length()) { |
| 61 ++iter; |
| 62 } |
| 63 return iter; |
| 64 } |
| 65 |
| 66 // Returns true if |frame| contains data which overlaps buffered data |
| 67 // (indicating an invalid stream frame has been received). |
| 68 bool QuicFrameList::FrameOverlapsBufferedData( |
| 69 QuicStreamOffset offset, |
| 70 size_t data_len, |
| 71 list<FrameData>::const_iterator insertion_point) const { |
| 72 if (frame_list_.empty() || insertion_point == frame_list_.end()) { |
| 73 return false; |
| 74 } |
| 75 // If there is a buffered frame with a higher starting offset, then check to |
| 76 // see if the new frame overlaps the beginning of the higher frame. |
| 77 if (offset < insertion_point->offset && |
| 78 offset + data_len > insertion_point->offset) { |
| 79 DVLOG(1) << "New frame overlaps next frame: " << offset << " + " << data_len |
| 80 << " > " << insertion_point->offset; |
| 81 return true; |
| 82 } |
| 83 // If there is a buffered frame with a lower starting offset, then check to |
| 84 // see if the buffered frame runs into the new frame. |
| 85 if (offset >= insertion_point->offset && |
| 86 offset < insertion_point->offset + insertion_point->segment.length()) { |
| 87 DVLOG(1) << "Preceeding frame overlaps new frame: " |
| 88 << insertion_point->offset << " + " |
| 89 << insertion_point->segment.length() << " > " << offset; |
| 90 return true; |
| 91 } |
| 92 |
| 93 return false; |
| 94 } |
| 95 |
| 96 // Returns true if the sequencer has received this frame before. |
| 97 bool QuicFrameList::IsDuplicate( |
| 98 QuicStreamOffset offset, |
| 99 size_t data_len, |
| 100 list<FrameData>::const_iterator insertion_point) const { |
| 101 // A frame is duplicate if the frame offset is smaller than the bytes consumed |
| 102 // or identical to an already received frame. |
| 103 return offset < total_bytes_read_ || (insertion_point != frame_list_.end() && |
| 104 offset == insertion_point->offset); |
| 105 } |
| 106 |
| 107 int QuicFrameList::GetReadableRegions(struct iovec* iov, int iov_len) const { |
| 108 list<FrameData>::const_iterator it = frame_list_.begin(); |
| 109 int index = 0; |
| 110 QuicStreamOffset offset = total_bytes_read_; |
| 111 while (it != frame_list_.end() && index < iov_len) { |
| 112 if (it->offset != offset) { |
| 113 return index; |
| 114 } |
| 115 |
| 116 iov[index].iov_base = |
| 117 static_cast<void*>(const_cast<char*>(it->segment.data())); |
| 118 iov[index].iov_len = it->segment.size(); |
| 119 offset += it->segment.size(); |
| 120 |
| 121 ++index; |
| 122 ++it; |
| 123 } |
| 124 return index; |
| 125 } |
| 126 |
| 127 bool QuicFrameList::IncreaseTotalReadAndInvalidate(size_t bytes_used) { |
| 128 size_t end_offset = total_bytes_read_ + bytes_used; |
| 129 while (!frame_list_.empty() && end_offset != total_bytes_read_) { |
| 130 list<FrameData>::iterator it = frame_list_.begin(); |
| 131 if (it->offset != total_bytes_read_) { |
| 132 return false; |
| 133 } |
| 134 |
| 135 if (it->offset + it->segment.length() <= end_offset) { |
| 136 total_bytes_read_ += it->segment.length(); |
| 137 // This chunk is entirely consumed. |
| 138 frame_list_.erase(it); |
| 139 continue; |
| 140 } |
| 141 |
| 142 // Partially consume this frame. |
| 143 size_t delta = end_offset - it->offset; |
| 144 total_bytes_read_ += delta; |
| 145 string new_data = it->segment.substr(delta); |
| 146 frame_list_.erase(it); |
| 147 frame_list_.push_front(FrameData(total_bytes_read_, new_data)); |
| 148 break; |
| 149 } |
| 150 return true; |
| 151 } |
| 152 |
| 153 size_t QuicFrameList::ReadvAndInvalidate(const struct iovec* iov, |
| 154 size_t iov_len) { |
| 155 list<FrameData>::iterator it = frame_list_.begin(); |
| 156 size_t iov_index = 0; |
| 157 size_t iov_offset = 0; |
| 158 size_t frame_offset = 0; |
| 159 QuicStreamOffset initial_bytes_consumed = total_bytes_read_; |
| 160 |
| 161 while (iov_index < iov_len && it != frame_list_.end() && |
| 162 it->offset == total_bytes_read_) { |
| 163 int bytes_to_read = std::min(iov[iov_index].iov_len - iov_offset, |
| 164 it->segment.size() - frame_offset); |
| 165 |
| 166 char* iov_ptr = static_cast<char*>(iov[iov_index].iov_base) + iov_offset; |
| 167 memcpy(iov_ptr, it->segment.data() + frame_offset, bytes_to_read); |
| 168 frame_offset += bytes_to_read; |
| 169 iov_offset += bytes_to_read; |
| 170 |
| 171 if (iov[iov_index].iov_len == iov_offset) { |
| 172 // We've filled this buffer. |
| 173 iov_offset = 0; |
| 174 ++iov_index; |
| 175 } |
| 176 if (it->segment.size() == frame_offset) { |
| 177 // We've copied this whole frame |
| 178 total_bytes_read_ += it->segment.size(); |
| 179 frame_list_.erase(it); |
| 180 it = frame_list_.begin(); |
| 181 frame_offset = 0; |
| 182 } |
| 183 } |
| 184 // Done copying. If there is a partial frame, update it. |
| 185 if (frame_offset != 0) { |
| 186 frame_list_.push_front( |
| 187 FrameData(it->offset + frame_offset, it->segment.substr(frame_offset))); |
| 188 frame_list_.erase(it); |
| 189 total_bytes_read_ += frame_offset; |
| 190 } |
| 191 return total_bytes_read_ - initial_bytes_consumed; |
| 192 } |
| 193 |
| 194 bool QuicFrameList::HasBytesToRead() const { |
| 195 return !frame_list_.empty() && |
| 196 frame_list_.begin()->offset == total_bytes_read_; |
| 197 } |
| 198 } // namespace net_quic |
OLD | NEW |