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