1 // Copyright (c) 2012 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 "quiche/quic/core/quic_crypto_stream.h"
6
7 #include <optional>
8 #include <string>
9
10 #include "absl/strings/str_cat.h"
11 #include "absl/strings/string_view.h"
12 #include "quiche/quic/core/crypto/crypto_handshake.h"
13 #include "quiche/quic/core/frames/quic_crypto_frame.h"
14 #include "quiche/quic/core/quic_connection.h"
15 #include "quiche/quic/core/quic_error_codes.h"
16 #include "quiche/quic/core/quic_session.h"
17 #include "quiche/quic/core/quic_types.h"
18 #include "quiche/quic/core/quic_utils.h"
19 #include "quiche/quic/platform/api/quic_flag_utils.h"
20 #include "quiche/quic/platform/api/quic_flags.h"
21 #include "quiche/quic/platform/api/quic_logging.h"
22
23 namespace quic {
24
25 #define ENDPOINT \
26 (session()->perspective() == Perspective::IS_SERVER ? "Server: " \
27 : "Client:" \
28 " ")
29
QuicCryptoStream(QuicSession * session)30 QuicCryptoStream::QuicCryptoStream(QuicSession* session)
31 : QuicStream(
32 QuicVersionUsesCryptoFrames(session->transport_version())
33 ? QuicUtils::GetInvalidStreamId(session->transport_version())
34 : QuicUtils::GetCryptoStreamId(session->transport_version()),
35 session,
36 /*is_static=*/true,
37 QuicVersionUsesCryptoFrames(session->transport_version())
38 ? CRYPTO
39 : BIDIRECTIONAL),
40 substreams_{{{this}, {this}, {this}}} {
41 // The crypto stream is exempt from connection level flow control.
42 DisableConnectionFlowControlForThisStream();
43 }
44
~QuicCryptoStream()45 QuicCryptoStream::~QuicCryptoStream() {}
46
47 // static
CryptoMessageFramingOverhead(QuicTransportVersion version,QuicConnectionId connection_id)48 QuicByteCount QuicCryptoStream::CryptoMessageFramingOverhead(
49 QuicTransportVersion version, QuicConnectionId connection_id) {
50 QUICHE_DCHECK(
51 QuicUtils::IsConnectionIdValidForVersion(connection_id, version));
52 quiche::QuicheVariableLengthIntegerLength retry_token_length_length =
53 quiche::VARIABLE_LENGTH_INTEGER_LENGTH_1;
54 quiche::QuicheVariableLengthIntegerLength length_length =
55 quiche::VARIABLE_LENGTH_INTEGER_LENGTH_2;
56 if (!QuicVersionHasLongHeaderLengths(version)) {
57 retry_token_length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0;
58 length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0;
59 }
60 return QuicPacketCreator::StreamFramePacketOverhead(
61 version, connection_id.length(), 0, /*include_version=*/true,
62 /*include_diversification_nonce=*/true, PACKET_4BYTE_PACKET_NUMBER,
63 retry_token_length_length, length_length,
64 /*offset=*/0);
65 }
66
OnCryptoFrame(const QuicCryptoFrame & frame)67 void QuicCryptoStream::OnCryptoFrame(const QuicCryptoFrame& frame) {
68 QUIC_BUG_IF(quic_bug_12573_1,
69 !QuicVersionUsesCryptoFrames(session()->transport_version()))
70 << "Versions less than 47 shouldn't receive CRYPTO frames";
71 EncryptionLevel level = session()->connection()->last_decrypted_level();
72 if (!IsCryptoFrameExpectedForEncryptionLevel(level)) {
73 OnUnrecoverableError(
74 IETF_QUIC_PROTOCOL_VIOLATION,
75 absl::StrCat("CRYPTO_FRAME is unexpectedly received at level ", level));
76 return;
77 }
78 CryptoSubstream& substream =
79 substreams_[QuicUtils::GetPacketNumberSpace(level)];
80 substream.sequencer.OnCryptoFrame(frame);
81 EncryptionLevel frame_level = level;
82 if (substream.sequencer.NumBytesBuffered() >
83 BufferSizeLimitForLevel(frame_level)) {
84 OnUnrecoverableError(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
85 "Too much crypto data received");
86 }
87 }
88
OnStreamFrame(const QuicStreamFrame & frame)89 void QuicCryptoStream::OnStreamFrame(const QuicStreamFrame& frame) {
90 if (QuicVersionUsesCryptoFrames(session()->transport_version())) {
91 QUIC_PEER_BUG(quic_peer_bug_12573_2)
92 << "Crypto data received in stream frame instead of crypto frame";
93 OnUnrecoverableError(QUIC_INVALID_STREAM_DATA, "Unexpected stream frame");
94 }
95 QuicStream::OnStreamFrame(frame);
96 }
97
OnDataAvailable()98 void QuicCryptoStream::OnDataAvailable() {
99 EncryptionLevel level = session()->connection()->last_decrypted_level();
100 if (!QuicVersionUsesCryptoFrames(session()->transport_version())) {
101 // Versions less than 47 only support QUIC crypto, which ignores the
102 // EncryptionLevel passed into CryptoMessageParser::ProcessInput (and
103 // OnDataAvailableInSequencer).
104 OnDataAvailableInSequencer(sequencer(), level);
105 return;
106 }
107 OnDataAvailableInSequencer(
108 &substreams_[QuicUtils::GetPacketNumberSpace(level)].sequencer, level);
109 }
110
OnDataAvailableInSequencer(QuicStreamSequencer * sequencer,EncryptionLevel level)111 void QuicCryptoStream::OnDataAvailableInSequencer(
112 QuicStreamSequencer* sequencer, EncryptionLevel level) {
113 struct iovec iov;
114 while (sequencer->GetReadableRegion(&iov)) {
115 absl::string_view data(static_cast<char*>(iov.iov_base), iov.iov_len);
116 if (!crypto_message_parser()->ProcessInput(data, level)) {
117 OnUnrecoverableError(crypto_message_parser()->error(),
118 crypto_message_parser()->error_detail());
119 return;
120 }
121 sequencer->MarkConsumed(iov.iov_len);
122 if (one_rtt_keys_available() &&
123 crypto_message_parser()->InputBytesRemaining() == 0) {
124 // If the handshake is complete and the current message has been fully
125 // processed then no more handshake messages are likely to arrive soon
126 // so release the memory in the stream sequencer.
127 sequencer->ReleaseBufferIfEmpty();
128 }
129 }
130 }
131
WriteCryptoData(EncryptionLevel level,absl::string_view data)132 void QuicCryptoStream::WriteCryptoData(EncryptionLevel level,
133 absl::string_view data) {
134 if (!QuicVersionUsesCryptoFrames(session()->transport_version())) {
135 WriteOrBufferDataAtLevel(data, /*fin=*/false, level,
136 /*ack_listener=*/nullptr);
137 return;
138 }
139 if (data.empty()) {
140 QUIC_BUG(quic_bug_10322_1) << "Empty crypto data being written";
141 return;
142 }
143 const bool had_buffered_data = HasBufferedCryptoFrames();
144 QuicStreamSendBuffer* send_buffer =
145 &substreams_[QuicUtils::GetPacketNumberSpace(level)].send_buffer;
146 QuicStreamOffset offset = send_buffer->stream_offset();
147
148 // Ensure this data does not cause the send buffer for this encryption level
149 // to exceed its size limit.
150 if (GetQuicFlag(quic_bounded_crypto_send_buffer)) {
151 QUIC_BUG_IF(quic_crypto_stream_offset_lt_bytes_written,
152 offset < send_buffer->stream_bytes_written());
153 uint64_t current_buffer_size =
154 offset - std::min(offset, send_buffer->stream_bytes_written());
155 if (current_buffer_size > 0) {
156 QUIC_CODE_COUNT(quic_received_crypto_data_with_non_empty_send_buffer);
157 if (BufferSizeLimitForLevel(level) <
158 (current_buffer_size + data.length())) {
159 QUIC_BUG(quic_crypto_send_buffer_overflow)
160 << absl::StrCat("Too much data for crypto send buffer with level: ",
161 EncryptionLevelToString(level),
162 ", current_buffer_size: ", current_buffer_size,
163 ", data length: ", data.length(),
164 ", SNI: ", crypto_negotiated_params().sni);
165 OnUnrecoverableError(QUIC_INTERNAL_ERROR,
166 "Too much data for crypto send buffer");
167 return;
168 }
169 }
170 }
171
172 // Append |data| to the send buffer for this encryption level.
173 send_buffer->SaveStreamData(data);
174 if (kMaxStreamLength - offset < data.length()) {
175 QUIC_BUG(quic_bug_10322_2) << "Writing too much crypto handshake data";
176 OnUnrecoverableError(QUIC_INTERNAL_ERROR,
177 "Writing too much crypto handshake data");
178 return;
179 }
180 if (had_buffered_data) {
181 // Do not try to write if there is buffered data.
182 return;
183 }
184
185 size_t bytes_consumed = stream_delegate()->SendCryptoData(
186 level, data.length(), offset, NOT_RETRANSMISSION);
187 send_buffer->OnStreamDataConsumed(bytes_consumed);
188 }
189
BufferSizeLimitForLevel(EncryptionLevel) const190 size_t QuicCryptoStream::BufferSizeLimitForLevel(EncryptionLevel) const {
191 return GetQuicFlag(quic_max_buffered_crypto_bytes);
192 }
193
OnCryptoFrameAcked(const QuicCryptoFrame & frame,QuicTime::Delta)194 bool QuicCryptoStream::OnCryptoFrameAcked(const QuicCryptoFrame& frame,
195 QuicTime::Delta /*ack_delay_time*/) {
196 QuicByteCount newly_acked_length = 0;
197 if (!substreams_[QuicUtils::GetPacketNumberSpace(frame.level)]
198 .send_buffer.OnStreamDataAcked(frame.offset, frame.data_length,
199 &newly_acked_length)) {
200 OnUnrecoverableError(QUIC_INTERNAL_ERROR,
201 "Trying to ack unsent crypto data.");
202 return false;
203 }
204 return newly_acked_length > 0;
205 }
206
OnStreamReset(const QuicRstStreamFrame &)207 void QuicCryptoStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
208 stream_delegate()->OnStreamError(QUIC_INVALID_STREAM_ID,
209 "Attempt to reset crypto stream");
210 }
211
NeuterUnencryptedStreamData()212 void QuicCryptoStream::NeuterUnencryptedStreamData() {
213 NeuterStreamDataOfEncryptionLevel(ENCRYPTION_INITIAL);
214 }
215
NeuterStreamDataOfEncryptionLevel(EncryptionLevel level)216 void QuicCryptoStream::NeuterStreamDataOfEncryptionLevel(
217 EncryptionLevel level) {
218 if (!QuicVersionUsesCryptoFrames(session()->transport_version())) {
219 for (const auto& interval : bytes_consumed_[level]) {
220 QuicByteCount newly_acked_length = 0;
221 send_buffer().OnStreamDataAcked(
222 interval.min(), interval.max() - interval.min(), &newly_acked_length);
223 }
224 return;
225 }
226 QuicStreamSendBuffer* send_buffer =
227 &substreams_[QuicUtils::GetPacketNumberSpace(level)].send_buffer;
228 // TODO(nharper): Consider adding a Clear() method to QuicStreamSendBuffer
229 // to replace the following code.
230 QuicIntervalSet<QuicStreamOffset> to_ack = send_buffer->bytes_acked();
231 to_ack.Complement(0, send_buffer->stream_offset());
232 for (const auto& interval : to_ack) {
233 QuicByteCount newly_acked_length = 0;
234 send_buffer->OnStreamDataAcked(
235 interval.min(), interval.max() - interval.min(), &newly_acked_length);
236 }
237 }
238
OnStreamDataConsumed(QuicByteCount bytes_consumed)239 void QuicCryptoStream::OnStreamDataConsumed(QuicByteCount bytes_consumed) {
240 if (QuicVersionUsesCryptoFrames(session()->transport_version())) {
241 QUIC_BUG(quic_bug_10322_3)
242 << "Stream data consumed when CRYPTO frames should be in use";
243 }
244 if (bytes_consumed > 0) {
245 bytes_consumed_[session()->connection()->encryption_level()].Add(
246 stream_bytes_written(), stream_bytes_written() + bytes_consumed);
247 }
248 QuicStream::OnStreamDataConsumed(bytes_consumed);
249 }
250
HasPendingCryptoRetransmission() const251 bool QuicCryptoStream::HasPendingCryptoRetransmission() const {
252 if (!QuicVersionUsesCryptoFrames(session()->transport_version())) {
253 return false;
254 }
255 for (const auto& substream : substreams_) {
256 if (substream.send_buffer.HasPendingRetransmission()) {
257 return true;
258 }
259 }
260 return false;
261 }
262
WritePendingCryptoRetransmission()263 void QuicCryptoStream::WritePendingCryptoRetransmission() {
264 QUIC_BUG_IF(quic_bug_12573_3,
265 !QuicVersionUsesCryptoFrames(session()->transport_version()))
266 << "Versions less than 47 don't write CRYPTO frames";
267 for (uint8_t i = INITIAL_DATA; i <= APPLICATION_DATA; ++i) {
268 auto packet_number_space = static_cast<PacketNumberSpace>(i);
269 QuicStreamSendBuffer* send_buffer =
270 &substreams_[packet_number_space].send_buffer;
271 while (send_buffer->HasPendingRetransmission()) {
272 auto pending = send_buffer->NextPendingRetransmission();
273 size_t bytes_consumed = stream_delegate()->SendCryptoData(
274 GetEncryptionLevelToSendCryptoDataOfSpace(packet_number_space),
275 pending.length, pending.offset, HANDSHAKE_RETRANSMISSION);
276 send_buffer->OnStreamDataRetransmitted(pending.offset, bytes_consumed);
277 if (bytes_consumed < pending.length) {
278 return;
279 }
280 }
281 }
282 }
283
WritePendingRetransmission()284 void QuicCryptoStream::WritePendingRetransmission() {
285 while (HasPendingRetransmission()) {
286 StreamPendingRetransmission pending =
287 send_buffer().NextPendingRetransmission();
288 QuicIntervalSet<QuicStreamOffset> retransmission(
289 pending.offset, pending.offset + pending.length);
290 EncryptionLevel retransmission_encryption_level = ENCRYPTION_INITIAL;
291 // Determine the encryption level to write the retransmission
292 // at. The retransmission should be written at the same encryption level
293 // as the original transmission.
294 for (size_t i = 0; i < NUM_ENCRYPTION_LEVELS; ++i) {
295 if (retransmission.Intersects(bytes_consumed_[i])) {
296 retransmission_encryption_level = static_cast<EncryptionLevel>(i);
297 retransmission.Intersection(bytes_consumed_[i]);
298 break;
299 }
300 }
301 pending.offset = retransmission.begin()->min();
302 pending.length =
303 retransmission.begin()->max() - retransmission.begin()->min();
304 QuicConsumedData consumed = RetransmitStreamDataAtLevel(
305 pending.offset, pending.length, retransmission_encryption_level,
306 HANDSHAKE_RETRANSMISSION);
307 if (consumed.bytes_consumed < pending.length) {
308 // The connection is write blocked.
309 break;
310 }
311 }
312 }
313
RetransmitStreamData(QuicStreamOffset offset,QuicByteCount data_length,bool,TransmissionType type)314 bool QuicCryptoStream::RetransmitStreamData(QuicStreamOffset offset,
315 QuicByteCount data_length,
316 bool /*fin*/,
317 TransmissionType type) {
318 QUICHE_DCHECK(type == HANDSHAKE_RETRANSMISSION || type == PTO_RETRANSMISSION);
319 QuicIntervalSet<QuicStreamOffset> retransmission(offset,
320 offset + data_length);
321 // Determine the encryption level to send data. This only needs to be once as
322 // [offset, offset + data_length) is guaranteed to be in the same packet.
323 EncryptionLevel send_encryption_level = ENCRYPTION_INITIAL;
324 for (size_t i = 0; i < NUM_ENCRYPTION_LEVELS; ++i) {
325 if (retransmission.Intersects(bytes_consumed_[i])) {
326 send_encryption_level = static_cast<EncryptionLevel>(i);
327 break;
328 }
329 }
330 retransmission.Difference(bytes_acked());
331 for (const auto& interval : retransmission) {
332 QuicStreamOffset retransmission_offset = interval.min();
333 QuicByteCount retransmission_length = interval.max() - interval.min();
334 QuicConsumedData consumed = RetransmitStreamDataAtLevel(
335 retransmission_offset, retransmission_length, send_encryption_level,
336 type);
337 if (consumed.bytes_consumed < retransmission_length) {
338 // The connection is write blocked.
339 return false;
340 }
341 }
342
343 return true;
344 }
345
RetransmitStreamDataAtLevel(QuicStreamOffset retransmission_offset,QuicByteCount retransmission_length,EncryptionLevel encryption_level,TransmissionType type)346 QuicConsumedData QuicCryptoStream::RetransmitStreamDataAtLevel(
347 QuicStreamOffset retransmission_offset, QuicByteCount retransmission_length,
348 EncryptionLevel encryption_level, TransmissionType type) {
349 QUICHE_DCHECK(type == HANDSHAKE_RETRANSMISSION || type == PTO_RETRANSMISSION);
350 const auto consumed = stream_delegate()->WritevData(
351 id(), retransmission_length, retransmission_offset, NO_FIN, type,
352 encryption_level);
353 QUIC_DVLOG(1) << ENDPOINT << "stream " << id()
354 << " is forced to retransmit stream data ["
355 << retransmission_offset << ", "
356 << retransmission_offset + retransmission_length
357 << "), with encryption level: " << encryption_level
358 << ", consumed: " << consumed;
359 OnStreamFrameRetransmitted(retransmission_offset, consumed.bytes_consumed,
360 consumed.fin_consumed);
361
362 return consumed;
363 }
364
crypto_bytes_read() const365 uint64_t QuicCryptoStream::crypto_bytes_read() const {
366 if (!QuicVersionUsesCryptoFrames(session()->transport_version())) {
367 return stream_bytes_read();
368 }
369 uint64_t bytes_read = 0;
370 for (const CryptoSubstream& substream : substreams_) {
371 bytes_read += substream.sequencer.NumBytesConsumed();
372 }
373 return bytes_read;
374 }
375
376 // TODO(haoyuewang) Move this test-only method under
377 // quiche/quic/test_tools.
BytesReadOnLevel(EncryptionLevel level) const378 uint64_t QuicCryptoStream::BytesReadOnLevel(EncryptionLevel level) const {
379 return substreams_[QuicUtils::GetPacketNumberSpace(level)]
380 .sequencer.NumBytesConsumed();
381 }
382
BytesSentOnLevel(EncryptionLevel level) const383 uint64_t QuicCryptoStream::BytesSentOnLevel(EncryptionLevel level) const {
384 return substreams_[QuicUtils::GetPacketNumberSpace(level)]
385 .send_buffer.stream_bytes_written();
386 }
387
WriteCryptoFrame(EncryptionLevel level,QuicStreamOffset offset,QuicByteCount data_length,QuicDataWriter * writer)388 bool QuicCryptoStream::WriteCryptoFrame(EncryptionLevel level,
389 QuicStreamOffset offset,
390 QuicByteCount data_length,
391 QuicDataWriter* writer) {
392 QUIC_BUG_IF(quic_bug_12573_4,
393 !QuicVersionUsesCryptoFrames(session()->transport_version()))
394 << "Versions less than 47 don't write CRYPTO frames (2)";
395 return substreams_[QuicUtils::GetPacketNumberSpace(level)]
396 .send_buffer.WriteStreamData(offset, data_length, writer);
397 }
398
OnCryptoFrameLost(QuicCryptoFrame * crypto_frame)399 void QuicCryptoStream::OnCryptoFrameLost(QuicCryptoFrame* crypto_frame) {
400 QUIC_BUG_IF(quic_bug_12573_5,
401 !QuicVersionUsesCryptoFrames(session()->transport_version()))
402 << "Versions less than 47 don't lose CRYPTO frames";
403 substreams_[QuicUtils::GetPacketNumberSpace(crypto_frame->level)]
404 .send_buffer.OnStreamDataLost(crypto_frame->offset,
405 crypto_frame->data_length);
406 }
407
RetransmitData(QuicCryptoFrame * crypto_frame,TransmissionType type)408 bool QuicCryptoStream::RetransmitData(QuicCryptoFrame* crypto_frame,
409 TransmissionType type) {
410 QUIC_BUG_IF(quic_bug_12573_6,
411 !QuicVersionUsesCryptoFrames(session()->transport_version()))
412 << "Versions less than 47 don't retransmit CRYPTO frames";
413 QuicIntervalSet<QuicStreamOffset> retransmission(
414 crypto_frame->offset, crypto_frame->offset + crypto_frame->data_length);
415 QuicStreamSendBuffer* send_buffer =
416 &substreams_[QuicUtils::GetPacketNumberSpace(crypto_frame->level)]
417 .send_buffer;
418 retransmission.Difference(send_buffer->bytes_acked());
419 if (retransmission.Empty()) {
420 return true;
421 }
422 for (const auto& interval : retransmission) {
423 size_t retransmission_offset = interval.min();
424 size_t retransmission_length = interval.max() - interval.min();
425 EncryptionLevel retransmission_encryption_level =
426 GetEncryptionLevelToSendCryptoDataOfSpace(
427 QuicUtils::GetPacketNumberSpace(crypto_frame->level));
428 size_t bytes_consumed = stream_delegate()->SendCryptoData(
429 retransmission_encryption_level, retransmission_length,
430 retransmission_offset, type);
431 send_buffer->OnStreamDataRetransmitted(retransmission_offset,
432 bytes_consumed);
433 if (bytes_consumed < retransmission_length) {
434 return false;
435 }
436 }
437 return true;
438 }
439
WriteBufferedCryptoFrames()440 void QuicCryptoStream::WriteBufferedCryptoFrames() {
441 QUIC_BUG_IF(quic_bug_12573_7,
442 !QuicVersionUsesCryptoFrames(session()->transport_version()))
443 << "Versions less than 47 don't use CRYPTO frames";
444 for (uint8_t i = INITIAL_DATA; i <= APPLICATION_DATA; ++i) {
445 auto packet_number_space = static_cast<PacketNumberSpace>(i);
446 QuicStreamSendBuffer* send_buffer =
447 &substreams_[packet_number_space].send_buffer;
448 const size_t data_length =
449 send_buffer->stream_offset() - send_buffer->stream_bytes_written();
450 if (data_length == 0) {
451 // No buffered data for this encryption level.
452 continue;
453 }
454 size_t bytes_consumed = stream_delegate()->SendCryptoData(
455 GetEncryptionLevelToSendCryptoDataOfSpace(packet_number_space),
456 data_length, send_buffer->stream_bytes_written(), NOT_RETRANSMISSION);
457 send_buffer->OnStreamDataConsumed(bytes_consumed);
458 if (bytes_consumed < data_length) {
459 // Connection is write blocked.
460 break;
461 }
462 }
463 }
464
HasBufferedCryptoFrames() const465 bool QuicCryptoStream::HasBufferedCryptoFrames() const {
466 QUIC_BUG_IF(quic_bug_12573_8,
467 !QuicVersionUsesCryptoFrames(session()->transport_version()))
468 << "Versions less than 47 don't use CRYPTO frames";
469 for (const CryptoSubstream& substream : substreams_) {
470 const QuicStreamSendBuffer& send_buffer = substream.send_buffer;
471 QUICHE_DCHECK_GE(send_buffer.stream_offset(),
472 send_buffer.stream_bytes_written());
473 if (send_buffer.stream_offset() > send_buffer.stream_bytes_written()) {
474 return true;
475 }
476 }
477 return false;
478 }
479
IsFrameOutstanding(EncryptionLevel level,size_t offset,size_t length) const480 bool QuicCryptoStream::IsFrameOutstanding(EncryptionLevel level, size_t offset,
481 size_t length) const {
482 if (!QuicVersionUsesCryptoFrames(session()->transport_version())) {
483 // This only happens if a client was originally configured for a version
484 // greater than 45, but received a version negotiation packet and is
485 // attempting to retransmit for a version less than 47. Outside of tests,
486 // this is a misconfiguration of the client, and this connection will be
487 // doomed. Return false here to avoid trying to retransmit CRYPTO frames on
488 // the wrong transport version.
489 return false;
490 }
491 return substreams_[QuicUtils::GetPacketNumberSpace(level)]
492 .send_buffer.IsStreamDataOutstanding(offset, length);
493 }
494
IsWaitingForAcks() const495 bool QuicCryptoStream::IsWaitingForAcks() const {
496 if (!QuicVersionUsesCryptoFrames(session()->transport_version())) {
497 return QuicStream::IsWaitingForAcks();
498 }
499 for (const CryptoSubstream& substream : substreams_) {
500 if (substream.send_buffer.stream_bytes_outstanding()) {
501 return true;
502 }
503 }
504 return false;
505 }
506
CryptoSubstream(QuicCryptoStream * crypto_stream)507 QuicCryptoStream::CryptoSubstream::CryptoSubstream(
508 QuicCryptoStream* crypto_stream)
509 : sequencer(crypto_stream),
510 send_buffer(crypto_stream->session()
511 ->connection()
512 ->helper()
513 ->GetStreamSendBufferAllocator()) {}
514
515 #undef ENDPOINT // undef for jumbo builds
516 } // namespace quic
517