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