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