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