blob: 9ae4d22335e359ebbb18c84acff27049990e8b0f [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2018 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/test_tools/simple_session_notifier.h"
6
7#include "net/third_party/quiche/src/quic/core/quic_utils.h"
bnc5de87052019-05-03 14:21:53 -07008#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -05009#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
10#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
11
12namespace quic {
13
14namespace test {
15
16SimpleSessionNotifier::SimpleSessionNotifier(QuicConnection* connection)
17 : last_control_frame_id_(kInvalidControlFrameId),
18 least_unacked_(1),
19 least_unsent_(1),
20 connection_(connection) {}
21
22SimpleSessionNotifier::~SimpleSessionNotifier() {
23 while (!control_frames_.empty()) {
24 DeleteFrame(&control_frames_.front());
25 control_frames_.pop_front();
26 }
27}
28
29SimpleSessionNotifier::StreamState::StreamState()
30 : bytes_total(0),
31 bytes_sent(0),
32 fin_buffered(false),
33 fin_sent(false),
34 fin_outstanding(false),
35 fin_lost(false) {}
36
37SimpleSessionNotifier::StreamState::~StreamState() {}
38
39QuicConsumedData SimpleSessionNotifier::WriteOrBufferData(
40 QuicStreamId id,
41 QuicByteCount data_length,
42 StreamSendingState state) {
43 if (!QuicContainsKey(stream_map_, id)) {
44 stream_map_[id] = StreamState();
45 }
46 StreamState& stream_state = stream_map_.find(id)->second;
47 const bool had_buffered_data =
48 HasBufferedStreamData() || HasBufferedControlFrames();
49 QuicConsumedData total_consumed(0, false);
50 QuicStreamOffset offset = stream_state.bytes_sent;
51 QUIC_DVLOG(1) << "WriteOrBuffer stream_id: " << id << " [" << offset << ", "
52 << offset + data_length << "), fin: " << (state != NO_FIN);
53 stream_state.bytes_total += data_length;
54 stream_state.fin_buffered = state != NO_FIN;
55 if (had_buffered_data) {
56 QUIC_DLOG(WARNING) << "Connection is write blocked";
57 return {0, false};
58 }
59 const size_t length = stream_state.bytes_total - stream_state.bytes_sent;
60 connection_->SetTransmissionType(NOT_RETRANSMISSION);
61 QuicConsumedData consumed =
62 connection_->SendStreamData(id, length, stream_state.bytes_sent,
63 stream_state.fin_buffered ? FIN : NO_FIN);
64 QUIC_DVLOG(1) << "consumed: " << consumed;
65 OnStreamDataConsumed(id, stream_state.bytes_sent, consumed.bytes_consumed,
66 consumed.fin_consumed);
67 return consumed;
68}
69
70void SimpleSessionNotifier::OnStreamDataConsumed(QuicStreamId id,
71 QuicStreamOffset offset,
72 QuicByteCount data_length,
73 bool fin) {
74 StreamState& state = stream_map_.find(id)->second;
75 if (id == QuicUtils::GetCryptoStreamId(connection_->transport_version()) &&
76 data_length > 0) {
77 crypto_bytes_transferred_[connection_->encryption_level()].Add(
78 offset, offset + data_length);
79 }
80 state.bytes_sent += data_length;
81 state.fin_sent = fin;
82 state.fin_outstanding = fin;
83}
84
85size_t SimpleSessionNotifier::WriteCryptoData(EncryptionLevel level,
86 QuicByteCount data_length,
87 QuicStreamOffset offset) {
88 crypto_state_[level].bytes_total += data_length;
89 size_t bytes_written =
90 connection_->SendCryptoData(level, data_length, offset);
91 crypto_state_[level].bytes_sent += bytes_written;
92 crypto_bytes_transferred_[level].Add(offset, offset + bytes_written);
93 return bytes_written;
94}
95
96void SimpleSessionNotifier::WriteOrBufferRstStream(
97 QuicStreamId id,
98 QuicRstStreamErrorCode error,
99 QuicStreamOffset bytes_written) {
100 QUIC_DVLOG(1) << "Writing RST_STREAM_FRAME";
101 const bool had_buffered_data =
102 HasBufferedStreamData() || HasBufferedControlFrames();
103 control_frames_.emplace_back((QuicFrame(new QuicRstStreamFrame(
104 ++last_control_frame_id_, id, error, bytes_written))));
105 if (error != QUIC_STREAM_NO_ERROR) {
106 // Delete stream to avoid retransmissions.
107 stream_map_.erase(id);
108 }
109 if (had_buffered_data) {
110 QUIC_DLOG(WARNING) << "Connection is write blocked";
111 return;
112 }
113 WriteBufferedControlFrames();
114}
115
zhongyifbb25772019-04-10 16:54:08 -0700116void SimpleSessionNotifier::WriteOrBufferPing() {
117 QUIC_DVLOG(1) << "Writing PING_FRAME";
118 const bool had_buffered_data =
119 HasBufferedStreamData() || HasBufferedControlFrames();
120 control_frames_.emplace_back(
121 (QuicFrame(QuicPingFrame(++last_control_frame_id_))));
122 if (had_buffered_data) {
123 QUIC_DLOG(WARNING) << "Connection is write blocked";
124 return;
125 }
126 WriteBufferedControlFrames();
127}
128
QUICHE teama6ef0a62019-03-07 20:34:33 -0500129void SimpleSessionNotifier::NeuterUnencryptedData() {
QUICHE team6987b4a2019-03-15 16:23:04 -0700130 for (const auto& interval : crypto_bytes_transferred_[ENCRYPTION_INITIAL]) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500131 // TODO(nharper): Handle CRYPTO frame case.
132 QuicStreamFrame stream_frame(
133 QuicUtils::GetCryptoStreamId(connection_->transport_version()), false,
134 interval.min(), interval.max() - interval.min());
135 OnFrameAcked(QuicFrame(stream_frame), QuicTime::Delta::Zero());
136 }
137}
138
139void SimpleSessionNotifier::OnCanWrite() {
140 if (!RetransmitLostCryptoData() || !RetransmitLostControlFrames() ||
141 !RetransmitLostStreamData()) {
142 return;
143 }
144 // Write buffered control frames.
145 if (!WriteBufferedControlFrames()) {
146 return;
147 }
148 // Write new data.
149 // TODO(nharper): Write CRYPTO frames.
150 for (const auto& pair : stream_map_) {
151 const auto& state = pair.second;
152 if (!StreamHasBufferedData(pair.first)) {
153 continue;
154 }
155
156 const size_t length = state.bytes_total - state.bytes_sent;
157 const bool can_bundle_fin =
158 state.fin_buffered && (state.bytes_sent + length == state.bytes_total);
159 connection_->SetTransmissionType(NOT_RETRANSMISSION);
160 QuicConsumedData consumed = connection_->SendStreamData(
161 pair.first, length, state.bytes_sent, can_bundle_fin ? FIN : NO_FIN);
162 QUIC_DVLOG(1) << "Tries to write stream_id: " << pair.first << " ["
163 << state.bytes_sent << ", " << state.bytes_sent + length
164 << "), fin: " << can_bundle_fin
165 << ", and consumed: " << consumed;
166 OnStreamDataConsumed(pair.first, state.bytes_sent, consumed.bytes_consumed,
167 consumed.fin_consumed);
168 if (length != consumed.bytes_consumed ||
169 (can_bundle_fin && !consumed.fin_consumed)) {
170 break;
171 }
172 }
173}
174
175bool SimpleSessionNotifier::WillingToWrite() const {
176 QUIC_DVLOG(1) << "has_buffered_control_frames: " << HasBufferedControlFrames()
177 << " as_lost_control_frames: " << !lost_control_frames_.empty()
178 << " has_buffered_stream_data: " << HasBufferedStreamData()
179 << " has_lost_stream_data: " << HasLostStreamData();
180 return HasBufferedControlFrames() || !lost_control_frames_.empty() ||
181 HasBufferedStreamData() || HasLostStreamData();
182}
183
184QuicByteCount SimpleSessionNotifier::StreamBytesSent() const {
185 QuicByteCount bytes_sent = 0;
186 for (const auto& pair : stream_map_) {
187 const auto& state = pair.second;
188 bytes_sent += state.bytes_sent;
189 }
190 return bytes_sent;
191}
192
193QuicByteCount SimpleSessionNotifier::StreamBytesToSend() const {
194 QuicByteCount bytes_to_send = 0;
195 for (const auto& pair : stream_map_) {
196 const auto& state = pair.second;
197 bytes_to_send += (state.bytes_total - state.bytes_sent);
198 }
199 return bytes_to_send;
200}
201
202bool SimpleSessionNotifier::OnFrameAcked(const QuicFrame& frame,
203 QuicTime::Delta /*ack_delay_time*/) {
204 QUIC_DVLOG(1) << "Acking " << frame;
205 if (frame.type == CRYPTO_FRAME) {
206 StreamState* state = &crypto_state_[frame.crypto_frame->level];
207 QuicStreamOffset offset = frame.crypto_frame->offset;
208 QuicByteCount data_length = frame.crypto_frame->data_length;
209 QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length);
210 newly_acked.Difference(state->bytes_acked);
211 if (newly_acked.Empty()) {
212 return false;
213 }
214 state->bytes_acked.Add(offset, offset + data_length);
215 state->pending_retransmissions.Difference(offset, offset + data_length);
216 return true;
217 }
218 if (frame.type != STREAM_FRAME) {
219 return OnControlFrameAcked(frame);
220 }
221 if (!QuicContainsKey(stream_map_, frame.stream_frame.stream_id)) {
222 return false;
223 }
224 auto* state = &stream_map_.find(frame.stream_frame.stream_id)->second;
225 QuicStreamOffset offset = frame.stream_frame.offset;
226 QuicByteCount data_length = frame.stream_frame.data_length;
227 QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length);
228 newly_acked.Difference(state->bytes_acked);
229 const bool fin_newly_acked = frame.stream_frame.fin && state->fin_outstanding;
230 if (newly_acked.Empty() && !fin_newly_acked) {
231 return false;
232 }
233 state->bytes_acked.Add(offset, offset + data_length);
234 if (fin_newly_acked) {
235 state->fin_outstanding = false;
236 state->fin_lost = false;
237 }
238 state->pending_retransmissions.Difference(offset, offset + data_length);
239 return true;
240}
241
242void SimpleSessionNotifier::OnFrameLost(const QuicFrame& frame) {
243 QUIC_DVLOG(1) << "Losting " << frame;
244 if (frame.type == CRYPTO_FRAME) {
245 StreamState* state = &crypto_state_[frame.crypto_frame->level];
246 QuicStreamOffset offset = frame.crypto_frame->offset;
247 QuicByteCount data_length = frame.crypto_frame->data_length;
248 QuicIntervalSet<QuicStreamOffset> bytes_lost(offset, offset + data_length);
249 bytes_lost.Difference(state->bytes_acked);
250 if (bytes_lost.Empty()) {
251 return;
252 }
253 for (const auto& lost : bytes_lost) {
254 state->pending_retransmissions.Add(lost.min(), lost.max());
255 }
256 return;
257 }
258 if (frame.type != STREAM_FRAME) {
259 OnControlFrameLost(frame);
260 return;
261 }
262 if (!QuicContainsKey(stream_map_, frame.stream_frame.stream_id)) {
263 return;
264 }
265 auto* state = &stream_map_.find(frame.stream_frame.stream_id)->second;
266 QuicStreamOffset offset = frame.stream_frame.offset;
267 QuicByteCount data_length = frame.stream_frame.data_length;
268 QuicIntervalSet<QuicStreamOffset> bytes_lost(offset, offset + data_length);
269 bytes_lost.Difference(state->bytes_acked);
270 const bool fin_lost = state->fin_outstanding && frame.stream_frame.fin;
271 if (bytes_lost.Empty() && !fin_lost) {
272 return;
273 }
274 for (const auto& lost : bytes_lost) {
275 state->pending_retransmissions.Add(lost.min(), lost.max());
276 }
277 state->fin_lost = fin_lost;
278}
279
280void SimpleSessionNotifier::RetransmitFrames(const QuicFrames& frames,
281 TransmissionType type) {
282 QuicConnection::ScopedPacketFlusher retransmission_flusher(
283 connection_, QuicConnection::SEND_ACK_IF_QUEUED);
284 connection_->SetTransmissionType(type);
285 for (const QuicFrame& frame : frames) {
286 if (frame.type == CRYPTO_FRAME) {
287 const StreamState& state = crypto_state_[frame.crypto_frame->level];
288 QuicIntervalSet<QuicStreamOffset> retransmission(
289 frame.crypto_frame->offset,
290 frame.crypto_frame->offset + frame.crypto_frame->data_length);
291 retransmission.Difference(state.bytes_acked);
292 for (const auto& interval : retransmission) {
293 QuicStreamOffset offset = interval.min();
294 QuicByteCount length = interval.max() - interval.min();
295 size_t consumed = connection_->SendCryptoData(frame.crypto_frame->level,
296 length, offset);
297 // CRYPTO frames should never be write blocked.
298 DCHECK_EQ(consumed, length);
299 }
300 }
301 if (frame.type != STREAM_FRAME) {
302 if (GetControlFrameId(frame) == kInvalidControlFrameId) {
303 continue;
304 }
305 QuicFrame copy = CopyRetransmittableControlFrame(frame);
306 if (!connection_->SendControlFrame(copy)) {
307 // Connection is write blocked.
308 DeleteFrame(&copy);
309 return;
310 }
311 continue;
312 }
313 if (!QuicContainsKey(stream_map_, frame.stream_frame.stream_id)) {
314 continue;
315 }
316 const auto& state = stream_map_.find(frame.stream_frame.stream_id)->second;
317 QuicIntervalSet<QuicStreamOffset> retransmission(
318 frame.stream_frame.offset,
319 frame.stream_frame.offset + frame.stream_frame.data_length);
320 EncryptionLevel retransmission_encryption_level =
321 connection_->encryption_level();
322 EncryptionLevel current_encryption_level = connection_->encryption_level();
323 if (frame.stream_frame.stream_id ==
324 QuicUtils::GetCryptoStreamId(connection_->transport_version())) {
325 for (size_t i = 0; i < NUM_ENCRYPTION_LEVELS; ++i) {
326 if (retransmission.Intersects(crypto_bytes_transferred_[i])) {
327 retransmission_encryption_level = static_cast<EncryptionLevel>(i);
328 retransmission.Intersection(crypto_bytes_transferred_[i]);
329 break;
330 }
331 }
332 }
333 retransmission.Difference(state.bytes_acked);
334 bool retransmit_fin = frame.stream_frame.fin && state.fin_outstanding;
335 QuicConsumedData consumed(0, false);
336 for (const auto& interval : retransmission) {
337 QuicStreamOffset retransmission_offset = interval.min();
338 QuicByteCount retransmission_length = interval.max() - interval.min();
339 const bool can_bundle_fin =
340 retransmit_fin &&
341 (retransmission_offset + retransmission_length == state.bytes_sent);
342 if (frame.stream_frame.stream_id ==
343 QuicUtils::GetCryptoStreamId(connection_->transport_version())) {
344 // Set appropriate encryption level for crypto stream.
345 connection_->SetDefaultEncryptionLevel(retransmission_encryption_level);
346 }
347 consumed = connection_->SendStreamData(
348 frame.stream_frame.stream_id, retransmission_length,
349 retransmission_offset, can_bundle_fin ? FIN : NO_FIN);
350 QUIC_DVLOG(1) << "stream " << frame.stream_frame.stream_id
351 << " is forced to retransmit stream data ["
352 << retransmission_offset << ", "
353 << retransmission_offset + retransmission_length
354 << ") and fin: " << can_bundle_fin
355 << ", consumed: " << consumed;
356 if (can_bundle_fin) {
357 retransmit_fin = !consumed.fin_consumed;
358 }
359 if (frame.stream_frame.stream_id ==
360 QuicUtils::GetCryptoStreamId(connection_->transport_version())) {
361 // Restore encryption level.
362 connection_->SetDefaultEncryptionLevel(current_encryption_level);
363 }
364 if (consumed.bytes_consumed < retransmission_length ||
365 (can_bundle_fin && !consumed.fin_consumed)) {
366 // Connection is write blocked.
367 return;
368 }
369 }
370 if (retransmit_fin) {
371 QUIC_DVLOG(1) << "stream " << frame.stream_frame.stream_id
372 << " retransmits fin only frame.";
373 consumed = connection_->SendStreamData(frame.stream_frame.stream_id, 0,
374 state.bytes_sent, FIN);
375 }
376 }
377}
378
379bool SimpleSessionNotifier::IsFrameOutstanding(const QuicFrame& frame) const {
380 if (frame.type == CRYPTO_FRAME) {
381 QuicStreamOffset offset = frame.crypto_frame->offset;
382 QuicByteCount data_length = frame.crypto_frame->data_length;
383 bool ret = data_length > 0 &&
384 !crypto_state_[frame.crypto_frame->level].bytes_acked.Contains(
385 offset, offset + data_length);
386 return ret;
387 }
388 if (frame.type != STREAM_FRAME) {
389 return IsControlFrameOutstanding(frame);
390 }
391 if (!QuicContainsKey(stream_map_, frame.stream_frame.stream_id)) {
392 return false;
393 }
394 const auto& state = stream_map_.find(frame.stream_frame.stream_id)->second;
395 QuicStreamOffset offset = frame.stream_frame.offset;
396 QuicByteCount data_length = frame.stream_frame.data_length;
397 return (data_length > 0 &&
398 !state.bytes_acked.Contains(offset, offset + data_length)) ||
399 (frame.stream_frame.fin && state.fin_outstanding);
400}
401
402bool SimpleSessionNotifier::HasUnackedCryptoData() const {
QUICHE teamea740082019-03-11 17:58:43 -0700403 if (QuicVersionUsesCryptoFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500404 for (size_t i = 0; i < NUM_ENCRYPTION_LEVELS; ++i) {
405 const StreamState& state = crypto_state_[i];
406 if (state.bytes_total > state.bytes_sent) {
407 return true;
408 }
409 QuicIntervalSet<QuicStreamOffset> bytes_to_ack(0, state.bytes_total);
410 bytes_to_ack.Difference(state.bytes_acked);
411 if (!bytes_to_ack.Empty()) {
412 return true;
413 }
414 }
415 return false;
416 }
417 if (!QuicContainsKey(stream_map_, QuicUtils::GetCryptoStreamId(
418 connection_->transport_version()))) {
419 return false;
420 }
421 const auto& state =
422 stream_map_
423 .find(QuicUtils::GetCryptoStreamId(connection_->transport_version()))
424 ->second;
425 if (state.bytes_total > state.bytes_sent) {
426 return true;
427 }
428 QuicIntervalSet<QuicStreamOffset> bytes_to_ack(0, state.bytes_total);
429 bytes_to_ack.Difference(state.bytes_acked);
430 return !bytes_to_ack.Empty();
431}
432
433bool SimpleSessionNotifier::OnControlFrameAcked(const QuicFrame& frame) {
434 QuicControlFrameId id = GetControlFrameId(frame);
435 if (id == kInvalidControlFrameId) {
436 return false;
437 }
438 DCHECK(id < least_unacked_ + control_frames_.size());
439 if (id < least_unacked_ ||
440 GetControlFrameId(control_frames_.at(id - least_unacked_)) ==
441 kInvalidControlFrameId) {
442 return false;
443 }
444 SetControlFrameId(kInvalidControlFrameId,
445 &control_frames_.at(id - least_unacked_));
446 lost_control_frames_.erase(id);
447 while (!control_frames_.empty() &&
448 GetControlFrameId(control_frames_.front()) == kInvalidControlFrameId) {
449 DeleteFrame(&control_frames_.front());
450 control_frames_.pop_front();
451 ++least_unacked_;
452 }
453 return true;
454}
455
456void SimpleSessionNotifier::OnControlFrameLost(const QuicFrame& frame) {
457 QuicControlFrameId id = GetControlFrameId(frame);
458 if (id == kInvalidControlFrameId) {
459 return;
460 }
461 DCHECK(id < least_unacked_ + control_frames_.size());
462 if (id < least_unacked_ ||
463 GetControlFrameId(control_frames_.at(id - least_unacked_)) ==
464 kInvalidControlFrameId) {
465 return;
466 }
467 if (!QuicContainsKey(lost_control_frames_, id)) {
468 lost_control_frames_[id] = true;
469 }
470}
471
472bool SimpleSessionNotifier::IsControlFrameOutstanding(
473 const QuicFrame& frame) const {
474 QuicControlFrameId id = GetControlFrameId(frame);
475 if (id == kInvalidControlFrameId) {
476 return false;
477 }
478 return id < least_unacked_ + control_frames_.size() && id >= least_unacked_ &&
479 GetControlFrameId(control_frames_.at(id - least_unacked_)) !=
480 kInvalidControlFrameId;
481}
482
483bool SimpleSessionNotifier::RetransmitLostControlFrames() {
484 while (!lost_control_frames_.empty()) {
485 QuicFrame pending = control_frames_.at(lost_control_frames_.begin()->first -
486 least_unacked_);
487 QuicFrame copy = CopyRetransmittableControlFrame(pending);
488 connection_->SetTransmissionType(LOSS_RETRANSMISSION);
489 if (!connection_->SendControlFrame(copy)) {
490 // Connection is write blocked.
491 DeleteFrame(&copy);
492 break;
493 }
494 lost_control_frames_.pop_front();
495 }
496 return lost_control_frames_.empty();
497}
498
499bool SimpleSessionNotifier::RetransmitLostCryptoData() {
500 // TODO(nharper): Handle CRYPTO frame case.
501 if (!QuicContainsKey(stream_map_, QuicUtils::GetCryptoStreamId(
502 connection_->transport_version()))) {
503 return true;
504 }
505 auto& state =
506 stream_map_
507 .find(QuicUtils::GetCryptoStreamId(connection_->transport_version()))
508 ->second;
509 while (!state.pending_retransmissions.Empty()) {
510 connection_->SetTransmissionType(HANDSHAKE_RETRANSMISSION);
511 QuicIntervalSet<QuicStreamOffset> retransmission(
512 state.pending_retransmissions.begin()->min(),
513 state.pending_retransmissions.begin()->max());
QUICHE team6987b4a2019-03-15 16:23:04 -0700514 EncryptionLevel retransmission_encryption_level = ENCRYPTION_INITIAL;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500515 for (size_t i = 0; i < NUM_ENCRYPTION_LEVELS; ++i) {
516 if (retransmission.Intersects(crypto_bytes_transferred_[i])) {
517 retransmission_encryption_level = static_cast<EncryptionLevel>(i);
518 retransmission.Intersection(crypto_bytes_transferred_[i]);
519 break;
520 }
521 }
522 QuicStreamOffset retransmission_offset = retransmission.begin()->min();
523 QuicByteCount retransmission_length =
524 retransmission.begin()->max() - retransmission.begin()->min();
525 EncryptionLevel current_encryption_level = connection_->encryption_level();
526 // Set appropriate encryption level.
527 connection_->SetDefaultEncryptionLevel(retransmission_encryption_level);
528 QuicConsumedData consumed = connection_->SendStreamData(
529 QuicUtils::GetCryptoStreamId(connection_->transport_version()),
530 retransmission_length, retransmission_offset, NO_FIN);
531 // Restore encryption level.
532 connection_->SetDefaultEncryptionLevel(current_encryption_level);
533 state.pending_retransmissions.Difference(
534 retransmission_offset, retransmission_offset + consumed.bytes_consumed);
535 if (consumed.bytes_consumed < retransmission_length) {
536 break;
537 }
538 }
539 return state.pending_retransmissions.Empty();
540}
541
542bool SimpleSessionNotifier::RetransmitLostStreamData() {
543 for (auto& pair : stream_map_) {
544 StreamState& state = pair.second;
545 QuicConsumedData consumed(0, false);
546 while (!state.pending_retransmissions.Empty() || state.fin_lost) {
547 connection_->SetTransmissionType(LOSS_RETRANSMISSION);
548 if (state.pending_retransmissions.Empty()) {
549 QUIC_DVLOG(1) << "stream " << pair.first
550 << " retransmits fin only frame.";
551 consumed =
552 connection_->SendStreamData(pair.first, 0, state.bytes_sent, FIN);
553 state.fin_lost = !consumed.fin_consumed;
554 if (state.fin_lost) {
bnc5de87052019-05-03 14:21:53 -0700555 QUIC_DLOG(INFO) << "Connection is write blocked";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500556 return false;
557 }
558 } else {
559 QuicStreamOffset offset = state.pending_retransmissions.begin()->min();
560 QuicByteCount length = state.pending_retransmissions.begin()->max() -
561 state.pending_retransmissions.begin()->min();
562 const bool can_bundle_fin =
563 state.fin_lost && (offset + length == state.bytes_sent);
564 consumed = connection_->SendStreamData(pair.first, length, offset,
565 can_bundle_fin ? FIN : NO_FIN);
566 QUIC_DVLOG(1) << "stream " << pair.first
567 << " tries to retransmit stream data [" << offset << ", "
568 << offset + length << ") and fin: " << can_bundle_fin
569 << ", consumed: " << consumed;
570 state.pending_retransmissions.Difference(
571 offset, offset + consumed.bytes_consumed);
572 if (consumed.fin_consumed) {
573 state.fin_lost = false;
574 }
575 if (length > consumed.bytes_consumed ||
576 (can_bundle_fin && !consumed.fin_consumed)) {
bnc5de87052019-05-03 14:21:53 -0700577 QUIC_DVLOG(1) << "Connection is write blocked";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500578 break;
579 }
580 }
581 }
582 }
583 return !HasLostStreamData();
584}
585
586bool SimpleSessionNotifier::WriteBufferedControlFrames() {
587 while (HasBufferedControlFrames()) {
588 QuicFrame frame_to_send =
589 control_frames_.at(least_unsent_ - least_unacked_);
590 QuicFrame copy = CopyRetransmittableControlFrame(frame_to_send);
591 connection_->SetTransmissionType(NOT_RETRANSMISSION);
592 if (!connection_->SendControlFrame(copy)) {
593 // Connection is write blocked.
594 DeleteFrame(&copy);
595 break;
596 }
597 ++least_unsent_;
598 }
599 return !HasBufferedControlFrames();
600}
601
602bool SimpleSessionNotifier::HasBufferedControlFrames() const {
603 return least_unsent_ < least_unacked_ + control_frames_.size();
604}
605
606bool SimpleSessionNotifier::HasBufferedStreamData() const {
607 for (const auto& pair : stream_map_) {
608 const auto& state = pair.second;
609 if (state.bytes_total > state.bytes_sent ||
610 (state.fin_buffered && !state.fin_sent)) {
611 return true;
612 }
613 }
614 return false;
615}
616
617bool SimpleSessionNotifier::StreamIsWaitingForAcks(QuicStreamId id) const {
618 if (!QuicContainsKey(stream_map_, id)) {
619 return false;
620 }
621 const StreamState& state = stream_map_.find(id)->second;
622 return !state.bytes_acked.Contains(0, state.bytes_sent) ||
623 state.fin_outstanding;
624}
625
626bool SimpleSessionNotifier::StreamHasBufferedData(QuicStreamId id) const {
627 if (!QuicContainsKey(stream_map_, id)) {
628 return false;
629 }
630 const StreamState& state = stream_map_.find(id)->second;
631 return state.bytes_total > state.bytes_sent ||
632 (state.fin_buffered && !state.fin_sent);
633}
634
635bool SimpleSessionNotifier::HasLostStreamData() const {
636 for (const auto& pair : stream_map_) {
637 const auto& state = pair.second;
638 if (!state.pending_retransmissions.Empty() || state.fin_lost) {
639 return true;
640 }
641 }
642 return false;
643}
644
645} // namespace test
646
647} // namespace quic