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_dispatcher.h" |
| 6 | |
vasilvv | 872e7a3 | 2019-03-12 16:42:44 -0700 | [diff] [blame] | 7 | #include <string> |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 8 | #include <utility> |
| 9 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 10 | #include "net/third_party/quiche/src/quic/core/chlo_extractor.h" |
| 11 | #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" |
| 12 | #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 13 | #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 14 | #include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h" |
| 15 | #include "net/third_party/quiche/src/quic/core/quic_types.h" |
| 16 | #include "net/third_party/quiche/src/quic/core/quic_utils.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 17 | #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" |
| 18 | #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" |
| 19 | #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" |
| 20 | #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" |
| 21 | #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" |
| 22 | #include "net/third_party/quiche/src/quic/platform/api/quic_stack_trace.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 23 | #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" |
dschinazi | 965ce09 | 2019-05-23 06:29:01 -0700 | [diff] [blame] | 24 | #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 25 | |
| 26 | namespace quic { |
| 27 | |
| 28 | typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket; |
| 29 | typedef QuicBufferedPacketStore::BufferedPacketList BufferedPacketList; |
| 30 | typedef QuicBufferedPacketStore::EnqueuePacketResult EnqueuePacketResult; |
| 31 | |
| 32 | namespace { |
| 33 | |
| 34 | // An alarm that informs the QuicDispatcher to delete old sessions. |
| 35 | class DeleteSessionsAlarm : public QuicAlarm::Delegate { |
| 36 | public: |
| 37 | explicit DeleteSessionsAlarm(QuicDispatcher* dispatcher) |
| 38 | : dispatcher_(dispatcher) {} |
| 39 | DeleteSessionsAlarm(const DeleteSessionsAlarm&) = delete; |
| 40 | DeleteSessionsAlarm& operator=(const DeleteSessionsAlarm&) = delete; |
| 41 | |
| 42 | void OnAlarm() override { dispatcher_->DeleteSessions(); } |
| 43 | |
| 44 | private: |
| 45 | // Not owned. |
| 46 | QuicDispatcher* dispatcher_; |
| 47 | }; |
| 48 | |
| 49 | // Collects packets serialized by a QuicPacketCreator in order |
| 50 | // to be handed off to the time wait list manager. |
| 51 | class PacketCollector : public QuicPacketCreator::DelegateInterface, |
| 52 | public QuicStreamFrameDataProducer { |
| 53 | public: |
| 54 | explicit PacketCollector(QuicBufferAllocator* allocator) |
| 55 | : send_buffer_(allocator) {} |
| 56 | ~PacketCollector() override = default; |
| 57 | |
| 58 | // QuicPacketCreator::DelegateInterface methods: |
| 59 | void OnSerializedPacket(SerializedPacket* serialized_packet) override { |
| 60 | // Make a copy of the serialized packet to send later. |
| 61 | packets_.emplace_back( |
| 62 | new QuicEncryptedPacket(CopyBuffer(*serialized_packet), |
| 63 | serialized_packet->encrypted_length, true)); |
| 64 | serialized_packet->encrypted_buffer = nullptr; |
| 65 | DeleteFrames(&(serialized_packet->retransmittable_frames)); |
| 66 | serialized_packet->retransmittable_frames.clear(); |
| 67 | } |
| 68 | |
| 69 | char* GetPacketBuffer() override { |
| 70 | // Let QuicPacketCreator to serialize packets on stack buffer. |
| 71 | return nullptr; |
| 72 | } |
| 73 | |
| 74 | void OnUnrecoverableError(QuicErrorCode error, |
fkastenholz | 85f1890 | 2019-05-28 12:47:00 -0700 | [diff] [blame] | 75 | const std::string& error_details) override {} |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 76 | |
| 77 | void SaveStatelessRejectFrameData(QuicStringPiece reject) { |
| 78 | struct iovec iovec; |
| 79 | iovec.iov_base = const_cast<char*>(reject.data()); |
| 80 | iovec.iov_len = reject.length(); |
| 81 | send_buffer_.SaveStreamData(&iovec, 1, 0, iovec.iov_len); |
| 82 | } |
| 83 | |
| 84 | // QuicStreamFrameDataProducer |
| 85 | WriteStreamDataResult WriteStreamData(QuicStreamId id, |
| 86 | QuicStreamOffset offset, |
| 87 | QuicByteCount data_length, |
| 88 | QuicDataWriter* writer) override { |
| 89 | if (send_buffer_.WriteStreamData(offset, data_length, writer)) { |
| 90 | return WRITE_SUCCESS; |
| 91 | } |
| 92 | return WRITE_FAILED; |
| 93 | } |
| 94 | bool WriteCryptoData(EncryptionLevel level, |
| 95 | QuicStreamOffset offset, |
| 96 | QuicByteCount data_length, |
| 97 | QuicDataWriter* writer) override { |
| 98 | return send_buffer_.WriteStreamData(offset, data_length, writer); |
| 99 | } |
| 100 | |
| 101 | std::vector<std::unique_ptr<QuicEncryptedPacket>>* packets() { |
| 102 | return &packets_; |
| 103 | } |
| 104 | |
| 105 | private: |
| 106 | std::vector<std::unique_ptr<QuicEncryptedPacket>> packets_; |
| 107 | // This is only needed until the packets are encrypted. Once packets are |
| 108 | // encrypted, the stream data is no longer required. |
| 109 | QuicStreamSendBuffer send_buffer_; |
| 110 | }; |
| 111 | |
| 112 | // Helper for statelessly closing connections by generating the |
| 113 | // correct termination packets and adding the connection to the time wait |
| 114 | // list manager. |
| 115 | class StatelessConnectionTerminator { |
| 116 | public: |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 117 | StatelessConnectionTerminator(QuicConnectionId server_connection_id, |
fayang | f7c569c | 2019-05-07 11:56:51 -0700 | [diff] [blame] | 118 | const ParsedQuicVersion version, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 119 | QuicConnectionHelperInterface* helper, |
| 120 | QuicTimeWaitListManager* time_wait_list_manager) |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 121 | : server_connection_id_(server_connection_id), |
fayang | f7c569c | 2019-05-07 11:56:51 -0700 | [diff] [blame] | 122 | framer_(ParsedQuicVersionVector{version}, |
| 123 | /*unused*/ QuicTime::Zero(), |
| 124 | Perspective::IS_SERVER, |
| 125 | /*unused*/ kQuicDefaultConnectionIdLength), |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 126 | collector_(helper->GetStreamSendBufferAllocator()), |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 127 | creator_(server_connection_id, &framer_, &collector_), |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 128 | time_wait_list_manager_(time_wait_list_manager) { |
fayang | f7c569c | 2019-05-07 11:56:51 -0700 | [diff] [blame] | 129 | framer_.set_data_producer(&collector_); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 130 | } |
| 131 | |
| 132 | ~StatelessConnectionTerminator() { |
| 133 | // Clear framer's producer. |
fayang | f7c569c | 2019-05-07 11:56:51 -0700 | [diff] [blame] | 134 | framer_.set_data_producer(nullptr); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 135 | } |
| 136 | |
| 137 | // Generates a packet containing a CONNECTION_CLOSE frame specifying |
| 138 | // |error_code| and |error_details| and add the connection to time wait. |
| 139 | void CloseConnection(QuicErrorCode error_code, |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 140 | const std::string& error_details, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 141 | bool ietf_quic) { |
fkastenholz | e9d71a8 | 2019-04-09 05:12:13 -0700 | [diff] [blame] | 142 | QuicConnectionCloseFrame* frame = |
| 143 | new QuicConnectionCloseFrame(error_code, error_details); |
fayang | f7c569c | 2019-05-07 11:56:51 -0700 | [diff] [blame] | 144 | if (framer_.transport_version() == QUIC_VERSION_99) { |
fkastenholz | 72f509b | 2019-04-10 09:17:49 -0700 | [diff] [blame] | 145 | frame->close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE; |
| 146 | } |
| 147 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 148 | if (!creator_.AddSavedFrame(QuicFrame(frame), NOT_RETRANSMISSION)) { |
| 149 | QUIC_BUG << "Unable to add frame to an empty packet"; |
| 150 | delete frame; |
| 151 | return; |
| 152 | } |
| 153 | creator_.Flush(); |
| 154 | DCHECK_EQ(1u, collector_.packets()->size()); |
| 155 | time_wait_list_manager_->AddConnectionIdToTimeWait( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 156 | server_connection_id_, ietf_quic, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 157 | QuicTimeWaitListManager::SEND_TERMINATION_PACKETS, |
QUICHE team | 6987b4a | 2019-03-15 16:23:04 -0700 | [diff] [blame] | 158 | quic::ENCRYPTION_INITIAL, collector_.packets()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 159 | } |
| 160 | |
| 161 | // Generates a series of termination packets containing the crypto handshake |
| 162 | // message |reject|. Adds the connection to time wait list with the |
| 163 | // generated packets. |
| 164 | void RejectConnection(QuicStringPiece reject, bool ietf_quic) { |
| 165 | QuicStreamOffset offset = 0; |
| 166 | collector_.SaveStatelessRejectFrameData(reject); |
| 167 | while (offset < reject.length()) { |
| 168 | QuicFrame frame; |
fayang | f7c569c | 2019-05-07 11:56:51 -0700 | [diff] [blame] | 169 | if (!QuicVersionUsesCryptoFrames(framer_.transport_version())) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 170 | if (!creator_.ConsumeData( |
fayang | f7c569c | 2019-05-07 11:56:51 -0700 | [diff] [blame] | 171 | QuicUtils::GetCryptoStreamId(framer_.transport_version()), |
ianswett | e28f022 | 2019-04-04 13:31:22 -0700 | [diff] [blame] | 172 | reject.length() - offset, offset, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 173 | /*fin=*/false, |
| 174 | /*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame)) { |
| 175 | QUIC_BUG << "Unable to consume data into an empty packet."; |
| 176 | return; |
| 177 | } |
| 178 | offset += frame.stream_frame.data_length; |
| 179 | } else { |
nharper | 51961cf | 2019-05-13 13:23:24 -0700 | [diff] [blame] | 180 | if (!creator_.ConsumeCryptoData( |
| 181 | ENCRYPTION_INITIAL, reject.length() - offset, offset, |
| 182 | /*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame)) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 183 | QUIC_BUG << "Unable to consume crypto data into an empty packet."; |
| 184 | return; |
| 185 | } |
| 186 | offset += frame.crypto_frame->data_length; |
| 187 | } |
nharper | 46833c3 | 2019-05-15 21:33:05 -0700 | [diff] [blame] | 188 | if (offset < reject.length() && |
| 189 | !QuicVersionUsesCryptoFrames(framer_.transport_version())) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 190 | DCHECK(!creator_.HasRoomForStreamFrame( |
fayang | f7c569c | 2019-05-07 11:56:51 -0700 | [diff] [blame] | 191 | QuicUtils::GetCryptoStreamId(framer_.transport_version()), offset, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 192 | frame.stream_frame.data_length)); |
| 193 | } |
| 194 | creator_.Flush(); |
| 195 | } |
| 196 | time_wait_list_manager_->AddConnectionIdToTimeWait( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 197 | server_connection_id_, ietf_quic, |
QUICHE team | 6987b4a | 2019-03-15 16:23:04 -0700 | [diff] [blame] | 198 | QuicTimeWaitListManager::SEND_TERMINATION_PACKETS, ENCRYPTION_INITIAL, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 199 | collector_.packets()); |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 200 | DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait( |
| 201 | server_connection_id_)); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 202 | } |
| 203 | |
| 204 | private: |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 205 | QuicConnectionId server_connection_id_; |
fayang | f7c569c | 2019-05-07 11:56:51 -0700 | [diff] [blame] | 206 | QuicFramer framer_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 207 | // Set as the visitor of |creator_| to collect any generated packets. |
| 208 | PacketCollector collector_; |
| 209 | QuicPacketCreator creator_; |
| 210 | QuicTimeWaitListManager* time_wait_list_manager_; |
| 211 | }; |
| 212 | |
| 213 | // Class which extracts the ALPN from a CHLO packet. |
| 214 | class ChloAlpnExtractor : public ChloExtractor::Delegate { |
| 215 | public: |
| 216 | void OnChlo(QuicTransportVersion version, |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 217 | QuicConnectionId server_connection_id, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 218 | const CryptoHandshakeMessage& chlo) override { |
| 219 | QuicStringPiece alpn_value; |
| 220 | if (chlo.GetStringPiece(kALPN, &alpn_value)) { |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 221 | alpn_ = std::string(alpn_value); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 222 | } |
| 223 | } |
| 224 | |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 225 | std::string&& ConsumeAlpn() { return std::move(alpn_); } |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 226 | |
| 227 | private: |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 228 | std::string alpn_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 229 | }; |
| 230 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 231 | } // namespace |
| 232 | |
| 233 | QuicDispatcher::QuicDispatcher( |
| 234 | const QuicConfig* config, |
| 235 | const QuicCryptoServerConfig* crypto_config, |
| 236 | QuicVersionManager* version_manager, |
| 237 | std::unique_ptr<QuicConnectionHelperInterface> helper, |
| 238 | std::unique_ptr<QuicCryptoServerStream::Helper> session_helper, |
| 239 | std::unique_ptr<QuicAlarmFactory> alarm_factory, |
dschinazi | 8ff7482 | 2019-05-28 16:37:20 -0700 | [diff] [blame] | 240 | uint8_t expected_server_connection_id_length) |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 241 | : config_(config), |
| 242 | crypto_config_(crypto_config), |
| 243 | compressed_certs_cache_( |
| 244 | QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), |
| 245 | helper_(std::move(helper)), |
| 246 | session_helper_(std::move(session_helper)), |
| 247 | alarm_factory_(std::move(alarm_factory)), |
| 248 | delete_sessions_alarm_( |
| 249 | alarm_factory_->CreateAlarm(new DeleteSessionsAlarm(this))), |
| 250 | buffered_packets_(this, helper_->GetClock(), alarm_factory_.get()), |
| 251 | current_packet_(nullptr), |
| 252 | version_manager_(version_manager), |
| 253 | framer_(GetSupportedVersions(), |
| 254 | /*unused*/ QuicTime::Zero(), |
| 255 | Perspective::IS_SERVER, |
dschinazi | 8ff7482 | 2019-05-28 16:37:20 -0700 | [diff] [blame] | 256 | expected_server_connection_id_length), |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 257 | last_error_(QUIC_NO_ERROR), |
| 258 | new_sessions_allowed_per_event_loop_(0u), |
QUICHE team | 963d57e | 2019-03-21 10:58:47 -0700 | [diff] [blame] | 259 | accept_new_connections_(true), |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 260 | allow_short_initial_server_connection_ids_(false), |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 261 | last_version_label_(0), |
dschinazi | 8ff7482 | 2019-05-28 16:37:20 -0700 | [diff] [blame] | 262 | expected_server_connection_id_length_( |
| 263 | expected_server_connection_id_length), |
| 264 | should_update_expected_server_connection_id_length_(false), |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 265 | no_framer_(GetQuicRestartFlag(quic_no_framer_object_in_dispatcher)) { |
| 266 | if (!no_framer_) { |
| 267 | framer_.set_visitor(this); |
| 268 | } |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 269 | } |
| 270 | |
| 271 | QuicDispatcher::~QuicDispatcher() { |
| 272 | session_map_.clear(); |
| 273 | closed_session_list_.clear(); |
| 274 | } |
| 275 | |
| 276 | void QuicDispatcher::InitializeWithWriter(QuicPacketWriter* writer) { |
| 277 | DCHECK(writer_ == nullptr); |
| 278 | writer_.reset(writer); |
| 279 | time_wait_list_manager_.reset(CreateQuicTimeWaitListManager()); |
| 280 | } |
| 281 | |
| 282 | void QuicDispatcher::ProcessPacket(const QuicSocketAddress& self_address, |
| 283 | const QuicSocketAddress& peer_address, |
| 284 | const QuicReceivedPacket& packet) { |
dschinazi | 965ce09 | 2019-05-23 06:29:01 -0700 | [diff] [blame] | 285 | QUIC_DVLOG(2) << "Dispatcher received encrypted " << packet.length() |
| 286 | << " bytes:" << std::endl |
| 287 | << QuicTextUtils::HexDump( |
| 288 | QuicStringPiece(packet.data(), packet.length())); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 289 | current_self_address_ = self_address; |
| 290 | current_peer_address_ = peer_address; |
| 291 | // GetClientAddress must be called after current_peer_address_ is set. |
| 292 | current_client_address_ = GetClientAddress(); |
| 293 | current_packet_ = &packet; |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 294 | if (!no_framer_) { |
| 295 | // ProcessPacket will cause the packet to be dispatched in |
| 296 | // OnUnauthenticatedPublicHeader, or sent to the time wait list manager |
| 297 | // in OnUnauthenticatedHeader. |
| 298 | framer_.ProcessPacket(packet); |
| 299 | // TODO(rjshade): Return a status describing if/why a packet was dropped, |
| 300 | // and log somehow. Maybe expose as a varz. |
| 301 | return; |
| 302 | } |
| 303 | QUIC_RESTART_FLAG_COUNT(quic_no_framer_object_in_dispatcher); |
| 304 | QuicPacketHeader header; |
fayang | 1f12350 | 2019-05-14 08:05:16 -0700 | [diff] [blame] | 305 | std::string detailed_error; |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 306 | const QuicErrorCode error = QuicFramer::ProcessPacketDispatcher( |
dschinazi | 8ff7482 | 2019-05-28 16:37:20 -0700 | [diff] [blame] | 307 | packet, expected_server_connection_id_length_, &header.form, |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 308 | &header.version_flag, &last_version_label_, |
dschinazi | b42a8c5 | 2019-05-30 09:45:01 -0700 | [diff] [blame] | 309 | &header.destination_connection_id, &header.source_connection_id, |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 310 | &detailed_error); |
| 311 | if (error != QUIC_NO_ERROR) { |
| 312 | // Packet has framing error. |
| 313 | SetLastError(error); |
| 314 | QUIC_DLOG(ERROR) << detailed_error; |
| 315 | return; |
| 316 | } |
| 317 | header.version = ParseQuicVersionLabel(last_version_label_); |
dschinazi | b42a8c5 | 2019-05-30 09:45:01 -0700 | [diff] [blame] | 318 | if (header.destination_connection_id.length() != |
dschinazi | 8ff7482 | 2019-05-28 16:37:20 -0700 | [diff] [blame] | 319 | expected_server_connection_id_length_ && |
| 320 | !should_update_expected_server_connection_id_length_ && |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 321 | !QuicUtils::VariableLengthConnectionIdAllowedForVersion( |
| 322 | header.version.transport_version)) { |
| 323 | SetLastError(QUIC_INVALID_PACKET_HEADER); |
| 324 | QUIC_DLOG(ERROR) << "Invalid Connection Id Length"; |
| 325 | return; |
| 326 | } |
dschinazi | 8ff7482 | 2019-05-28 16:37:20 -0700 | [diff] [blame] | 327 | if (should_update_expected_server_connection_id_length_) { |
dschinazi | b42a8c5 | 2019-05-30 09:45:01 -0700 | [diff] [blame] | 328 | expected_server_connection_id_length_ = |
| 329 | header.destination_connection_id.length(); |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 330 | } |
| 331 | // TODO(fayang): Instead of passing in QuicPacketHeader, pass format, |
| 332 | // version_flag, version and destination_connection_id. Combine |
| 333 | // OnUnauthenticatedPublicHeader and OnUnauthenticatedHeader to a single |
| 334 | // function when deprecating quic_no_framer_object_in_dispatcher. |
| 335 | if (!OnUnauthenticatedPublicHeader(header)) { |
| 336 | return; |
| 337 | } |
| 338 | OnUnauthenticatedHeader(header); |
| 339 | // TODO(wub): Consider invalidate the current_* variables so processing of |
| 340 | // the next packet does not use them incorrectly. |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 341 | } |
| 342 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 343 | QuicConnectionId QuicDispatcher::MaybeReplaceServerConnectionId( |
| 344 | QuicConnectionId server_connection_id, |
QUICHE team | c65d1d1 | 2019-03-19 20:58:04 -0700 | [diff] [blame] | 345 | ParsedQuicVersion version) { |
dschinazi | 8ff7482 | 2019-05-28 16:37:20 -0700 | [diff] [blame] | 346 | const uint8_t expected_server_connection_id_length = |
| 347 | no_framer_ ? expected_server_connection_id_length_ |
| 348 | : framer_.GetExpectedServerConnectionIdLength(); |
| 349 | if (server_connection_id.length() == expected_server_connection_id_length) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 350 | return server_connection_id; |
QUICHE team | c65d1d1 | 2019-03-19 20:58:04 -0700 | [diff] [blame] | 351 | } |
| 352 | DCHECK(QuicUtils::VariableLengthConnectionIdAllowedForVersion( |
| 353 | version.transport_version)); |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 354 | auto it = connection_id_map_.find(server_connection_id); |
QUICHE team | c65d1d1 | 2019-03-19 20:58:04 -0700 | [diff] [blame] | 355 | if (it != connection_id_map_.end()) { |
| 356 | return it->second; |
| 357 | } |
| 358 | QuicConnectionId new_connection_id = |
| 359 | session_helper_->GenerateConnectionIdForReject(version.transport_version, |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 360 | server_connection_id); |
dschinazi | 8ff7482 | 2019-05-28 16:37:20 -0700 | [diff] [blame] | 361 | DCHECK_EQ(expected_server_connection_id_length, new_connection_id.length()); |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 362 | connection_id_map_.insert( |
| 363 | std::make_pair(server_connection_id, new_connection_id)); |
| 364 | QUIC_DLOG(INFO) << "Replacing incoming connection ID " << server_connection_id |
QUICHE team | c65d1d1 | 2019-03-19 20:58:04 -0700 | [diff] [blame] | 365 | << " with " << new_connection_id; |
| 366 | return new_connection_id; |
| 367 | } |
| 368 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 369 | bool QuicDispatcher::OnUnauthenticatedPublicHeader( |
| 370 | const QuicPacketHeader& header) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 371 | current_server_connection_id_ = header.destination_connection_id; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 372 | |
| 373 | // Port zero is only allowed for unidirectional UDP, so is disallowed by QUIC. |
| 374 | // Given that we can't even send a reply rejecting the packet, just drop the |
| 375 | // packet. |
| 376 | if (current_peer_address_.port() == 0) { |
| 377 | return false; |
| 378 | } |
| 379 | |
| 380 | // The dispatcher requires the connection ID to be present in order to |
| 381 | // look up the matching QuicConnection, so we error out if it is absent. |
| 382 | if (header.destination_connection_id_included != CONNECTION_ID_PRESENT) { |
| 383 | return false; |
| 384 | } |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 385 | QuicConnectionId server_connection_id = header.destination_connection_id; |
QUICHE team | 8e2e453 | 2019-03-14 14:37:56 -0700 | [diff] [blame] | 386 | |
QUICHE team | 963d57e | 2019-03-21 10:58:47 -0700 | [diff] [blame] | 387 | // The IETF spec requires the client to generate an initial server |
| 388 | // connection ID that is at least 64 bits long. After that initial |
| 389 | // connection ID, the dispatcher picks a new one of its expected length. |
| 390 | // Therefore we should never receive a connection ID that is smaller |
| 391 | // than 64 bits and smaller than what we expect. |
dschinazi | 8ff7482 | 2019-05-28 16:37:20 -0700 | [diff] [blame] | 392 | const uint8_t expected_server_connection_id_length = |
| 393 | no_framer_ ? expected_server_connection_id_length_ |
| 394 | : framer_.GetExpectedServerConnectionIdLength(); |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 395 | if (server_connection_id.length() < kQuicMinimumInitialConnectionIdLength && |
dschinazi | 8ff7482 | 2019-05-28 16:37:20 -0700 | [diff] [blame] | 396 | server_connection_id.length() < expected_server_connection_id_length && |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 397 | !allow_short_initial_server_connection_ids_) { |
QUICHE team | 963d57e | 2019-03-21 10:58:47 -0700 | [diff] [blame] | 398 | DCHECK(header.version_flag); |
| 399 | DCHECK(QuicUtils::VariableLengthConnectionIdAllowedForVersion( |
| 400 | header.version.transport_version)); |
| 401 | QUIC_DLOG(INFO) << "Packet with short destination connection ID " |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 402 | << server_connection_id << " expected " |
dschinazi | 8ff7482 | 2019-05-28 16:37:20 -0700 | [diff] [blame] | 403 | << static_cast<int>(expected_server_connection_id_length); |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 404 | ProcessUnauthenticatedHeaderFate(kFateTimeWait, server_connection_id, |
| 405 | header.form, header.version_flag, |
| 406 | header.version); |
QUICHE team | 963d57e | 2019-03-21 10:58:47 -0700 | [diff] [blame] | 407 | return false; |
| 408 | } |
| 409 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 410 | // Packets with connection IDs for active connections are processed |
| 411 | // immediately. |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 412 | auto it = session_map_.find(server_connection_id); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 413 | if (it != session_map_.end()) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 414 | DCHECK(!buffered_packets_.HasBufferedPackets(server_connection_id)); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 415 | it->second->ProcessUdpPacket(current_self_address_, current_peer_address_, |
| 416 | *current_packet_); |
| 417 | return false; |
| 418 | } |
| 419 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 420 | if (buffered_packets_.HasChloForConnection(server_connection_id)) { |
| 421 | BufferEarlyPacket(server_connection_id, header.form != GOOGLE_QUIC_PACKET, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 422 | header.version); |
| 423 | return false; |
| 424 | } |
| 425 | |
| 426 | // Check if we are buffering packets for this connection ID |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 427 | if (temporarily_buffered_connections_.find(server_connection_id) != |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 428 | temporarily_buffered_connections_.end()) { |
| 429 | // This packet was received while the a CHLO for the same connection ID was |
| 430 | // being processed. Buffer it. |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 431 | BufferEarlyPacket(server_connection_id, header.form != GOOGLE_QUIC_PACKET, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 432 | header.version); |
| 433 | return false; |
| 434 | } |
| 435 | |
| 436 | if (!OnUnauthenticatedUnknownPublicHeader(header)) { |
| 437 | return false; |
| 438 | } |
| 439 | |
| 440 | // If the packet is a public reset for a connection ID that is not active, |
| 441 | // there is nothing we must do or can do. |
| 442 | if (header.reset_flag) { |
| 443 | return false; |
| 444 | } |
| 445 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 446 | if (time_wait_list_manager_->IsConnectionIdInTimeWait(server_connection_id)) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 447 | // This connection ID is already in time-wait state. |
| 448 | time_wait_list_manager_->ProcessPacket( |
| 449 | current_self_address_, current_peer_address_, |
| 450 | header.destination_connection_id, header.form, GetPerPacketContext()); |
| 451 | return false; |
| 452 | } |
| 453 | |
| 454 | // The packet has an unknown connection ID. |
| 455 | |
| 456 | // Unless the packet provides a version, assume that we can continue |
| 457 | // processing using our preferred version. |
| 458 | ParsedQuicVersion version = GetSupportedVersions().front(); |
| 459 | if (header.version_flag) { |
| 460 | ParsedQuicVersion packet_version = header.version; |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 461 | if (!no_framer_ && framer_.supported_versions() != GetSupportedVersions()) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 462 | // Reset framer's version if version flags change in flight. |
| 463 | framer_.SetSupportedVersions(GetSupportedVersions()); |
| 464 | } |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 465 | if (!IsSupportedVersion(packet_version)) { |
| 466 | if (ShouldCreateSessionForUnknownVersion( |
| 467 | no_framer_ ? last_version_label_ |
| 468 | : framer_.last_version_label())) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 469 | return true; |
| 470 | } |
| 471 | if (!crypto_config()->validate_chlo_size() || |
| 472 | current_packet_->length() >= kMinPacketSizeForVersionNegotiation) { |
| 473 | // Since the version is not supported, send a version negotiation |
| 474 | // packet and stop processing the current packet. |
dschinazi | 346b7ce | 2019-06-05 01:38:18 -0700 | [diff] [blame] | 475 | QuicConnectionId client_connection_id = header.source_connection_id; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 476 | time_wait_list_manager()->SendVersionNegotiationPacket( |
dschinazi | 346b7ce | 2019-06-05 01:38:18 -0700 | [diff] [blame] | 477 | server_connection_id, client_connection_id, |
dschinazi | b417d60 | 2019-05-29 13:08:45 -0700 | [diff] [blame] | 478 | header.form != GOOGLE_QUIC_PACKET, GetSupportedVersions(), |
| 479 | current_self_address_, current_peer_address_, |
| 480 | GetPerPacketContext()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 481 | } |
| 482 | return false; |
| 483 | } |
| 484 | version = packet_version; |
| 485 | } |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 486 | if (!no_framer_) { |
| 487 | // Set the framer's version and continue processing. |
| 488 | framer_.set_version(version); |
| 489 | } |
nharper | 55fa613 | 2019-05-07 19:37:21 -0700 | [diff] [blame] | 490 | |
| 491 | if (version.HasHeaderProtection()) { |
| 492 | ProcessHeader(header); |
| 493 | return false; |
| 494 | } |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 495 | return true; |
| 496 | } |
| 497 | |
| 498 | bool QuicDispatcher::OnUnauthenticatedHeader(const QuicPacketHeader& header) { |
nharper | 55fa613 | 2019-05-07 19:37:21 -0700 | [diff] [blame] | 499 | ProcessHeader(header); |
| 500 | return false; |
| 501 | } |
| 502 | |
| 503 | void QuicDispatcher::ProcessHeader(const QuicPacketHeader& header) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 504 | QuicConnectionId server_connection_id = header.destination_connection_id; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 505 | // Packet's connection ID is unknown. Apply the validity checks. |
| 506 | QuicPacketFate fate = ValidityChecks(header); |
| 507 | if (fate == kFateProcess) { |
wub | 0a4b9c5 | 2019-05-28 13:18:58 -0700 | [diff] [blame] | 508 | ProcessOrBufferPacket(server_connection_id, header.form, |
| 509 | header.version_flag, header.version); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 510 | } else { |
| 511 | // If the fate is already known, process it without executing stateless |
| 512 | // rejection logic. |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 513 | ProcessUnauthenticatedHeaderFate(fate, server_connection_id, header.form, |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 514 | header.version_flag, header.version); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 515 | } |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 516 | } |
| 517 | |
| 518 | void QuicDispatcher::ProcessUnauthenticatedHeaderFate( |
| 519 | QuicPacketFate fate, |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 520 | QuicConnectionId server_connection_id, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 521 | PacketHeaderFormat form, |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 522 | bool version_flag, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 523 | ParsedQuicVersion version) { |
| 524 | switch (fate) { |
| 525 | case kFateProcess: { |
| 526 | ProcessChlo(form, version); |
| 527 | break; |
| 528 | } |
| 529 | case kFateTimeWait: |
wub | 0a4b9c5 | 2019-05-28 13:18:58 -0700 | [diff] [blame] | 530 | // Add this connection_id to the time-wait state, to safely reject |
| 531 | // future packets. |
| 532 | QUIC_DLOG(INFO) << "Adding connection ID " << server_connection_id |
| 533 | << " to time-wait list."; |
| 534 | QUIC_CODE_COUNT(quic_reject_fate_time_wait); |
| 535 | StatelesslyTerminateConnection( |
| 536 | server_connection_id, form, version_flag, version, |
| 537 | QUIC_HANDSHAKE_FAILED, "Reject connection", |
| 538 | quic::QuicTimeWaitListManager::SEND_STATELESS_RESET); |
| 539 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 540 | DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait( |
| 541 | server_connection_id)); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 542 | time_wait_list_manager_->ProcessPacket( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 543 | current_self_address_, current_peer_address_, server_connection_id, |
| 544 | form, GetPerPacketContext()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 545 | |
| 546 | // Any packets which were buffered while the stateless rejector logic was |
| 547 | // running should be discarded. Do not inform the time wait list manager, |
| 548 | // which should already have a made a decision about sending a reject |
| 549 | // based on the CHLO alone. |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 550 | buffered_packets_.DiscardPackets(server_connection_id); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 551 | break; |
| 552 | case kFateBuffer: |
| 553 | // This packet is a non-CHLO packet which has arrived before the |
| 554 | // corresponding CHLO, *or* this packet was received while the |
| 555 | // corresponding CHLO was being processed. Buffer it. |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 556 | BufferEarlyPacket(server_connection_id, form != GOOGLE_QUIC_PACKET, |
| 557 | version); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 558 | break; |
| 559 | case kFateDrop: |
| 560 | // Do nothing with the packet. |
| 561 | break; |
| 562 | } |
| 563 | } |
| 564 | |
| 565 | QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks( |
| 566 | const QuicPacketHeader& header) { |
| 567 | // To have all the checks work properly without tears, insert any new check |
| 568 | // into the framework of this method in the section for checks that return the |
| 569 | // check's fate value. The sections for checks must be ordered with the |
| 570 | // highest priority fate first. |
| 571 | |
| 572 | // Checks that return kFateDrop. |
| 573 | |
| 574 | // Checks that return kFateTimeWait. |
| 575 | |
| 576 | // All packets within a connection sent by a client before receiving a |
| 577 | // response from the server are required to have the version negotiation flag |
| 578 | // set. Since this may be a client continuing a connection we lost track of |
| 579 | // via server restart, send a rejection to fast-fail the connection. |
| 580 | if (!header.version_flag) { |
| 581 | QUIC_DLOG(INFO) |
| 582 | << "Packet without version arrived for unknown connection ID " |
| 583 | << header.destination_connection_id; |
| 584 | return kFateTimeWait; |
| 585 | } |
| 586 | |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 587 | if (no_framer_) { |
| 588 | // Let the connection parse and validate packet number. |
| 589 | return kFateProcess; |
| 590 | } |
| 591 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 592 | // initial packet number of 0 is always invalid. |
nharper | 55fa613 | 2019-05-07 19:37:21 -0700 | [diff] [blame] | 593 | if (!framer_.version().HasHeaderProtection()) { |
| 594 | if (!header.packet_number.IsInitialized()) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 595 | return kFateTimeWait; |
| 596 | } |
nharper | 55fa613 | 2019-05-07 19:37:21 -0700 | [diff] [blame] | 597 | if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { |
| 598 | QUIC_RESTART_FLAG_COUNT_N(quic_enable_accept_random_ipn, 1, 2); |
| 599 | // Accepting Initial Packet Numbers in 1...((2^31)-1) range... check |
| 600 | // maximum accordingly. |
| 601 | if (header.packet_number > MaxRandomInitialPacketNumber()) { |
| 602 | return kFateTimeWait; |
| 603 | } |
| 604 | } else { |
| 605 | // Count those that would have been accepted if FLAGS..random_ipn |
| 606 | // were true -- to detect/diagnose potential issues prior to |
| 607 | // enabling the flag. |
| 608 | if ((header.packet_number > |
| 609 | QuicPacketNumber(kMaxReasonableInitialPacketNumber)) && |
| 610 | (header.packet_number <= MaxRandomInitialPacketNumber())) { |
| 611 | QUIC_CODE_COUNT_N(had_possibly_random_ipn, 1, 2); |
| 612 | } |
| 613 | // Check that the sequence number is within the range that the client is |
| 614 | // expected to send before receiving a response from the server. |
| 615 | if (header.packet_number > |
| 616 | QuicPacketNumber(kMaxReasonableInitialPacketNumber)) { |
| 617 | return kFateTimeWait; |
| 618 | } |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 619 | } |
| 620 | } |
| 621 | return kFateProcess; |
| 622 | } |
| 623 | |
| 624 | void QuicDispatcher::CleanUpSession(SessionMap::iterator it, |
| 625 | QuicConnection* connection, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 626 | ConnectionCloseSource source) { |
| 627 | write_blocked_list_.erase(connection); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 628 | QuicTimeWaitListManager::TimeWaitAction action = |
| 629 | QuicTimeWaitListManager::SEND_STATELESS_RESET; |
| 630 | if (connection->termination_packets() != nullptr && |
| 631 | !connection->termination_packets()->empty()) { |
| 632 | action = QuicTimeWaitListManager::SEND_TERMINATION_PACKETS; |
fayang | d4291e4 | 2019-05-30 10:31:21 -0700 | [diff] [blame] | 633 | } else if (VersionHasIetfInvariantHeader(connection->transport_version()) || |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 634 | GetQuicReloadableFlag(quic_terminate_gquic_connection_as_ietf)) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 635 | if (!connection->IsHandshakeConfirmed()) { |
fayang | d4291e4 | 2019-05-30 10:31:21 -0700 | [diff] [blame] | 636 | if (!VersionHasIetfInvariantHeader(connection->transport_version())) { |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 637 | QUIC_CODE_COUNT(gquic_add_to_time_wait_list_with_handshake_failed); |
| 638 | } else { |
| 639 | QUIC_CODE_COUNT(quic_v44_add_to_time_wait_list_with_handshake_failed); |
| 640 | } |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 641 | action = QuicTimeWaitListManager::SEND_TERMINATION_PACKETS; |
| 642 | // This serializes a connection close termination packet with error code |
| 643 | // QUIC_HANDSHAKE_FAILED and adds the connection to the time wait list. |
| 644 | StatelesslyTerminateConnection( |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 645 | connection->connection_id(), |
fayang | d4291e4 | 2019-05-30 10:31:21 -0700 | [diff] [blame] | 646 | VersionHasIetfInvariantHeader(connection->transport_version()) |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 647 | ? IETF_QUIC_LONG_HEADER_PACKET |
| 648 | : GOOGLE_QUIC_PACKET, |
| 649 | /*version_flag=*/true, connection->version(), QUIC_HANDSHAKE_FAILED, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 650 | "Connection is closed by server before handshake confirmed", |
| 651 | // Although it is our intention to send termination packets, the |
| 652 | // |action| argument is not used by this call to |
| 653 | // StatelesslyTerminateConnection(). |
| 654 | action); |
| 655 | session_map_.erase(it); |
| 656 | return; |
| 657 | } |
| 658 | QUIC_CODE_COUNT(quic_v44_add_to_time_wait_list_with_stateless_reset); |
| 659 | } |
| 660 | time_wait_list_manager_->AddConnectionIdToTimeWait( |
fayang | d4291e4 | 2019-05-30 10:31:21 -0700 | [diff] [blame] | 661 | it->first, VersionHasIetfInvariantHeader(connection->transport_version()), |
| 662 | action, connection->encryption_level(), |
| 663 | connection->termination_packets()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 664 | session_map_.erase(it); |
| 665 | } |
| 666 | |
| 667 | void QuicDispatcher::StopAcceptingNewConnections() { |
| 668 | accept_new_connections_ = false; |
| 669 | } |
| 670 | |
| 671 | std::unique_ptr<QuicPerPacketContext> QuicDispatcher::GetPerPacketContext() |
| 672 | const { |
| 673 | return nullptr; |
| 674 | } |
| 675 | |
| 676 | void QuicDispatcher::DeleteSessions() { |
QUICHE team | aa1d6a8 | 2019-03-13 09:14:13 -0700 | [diff] [blame] | 677 | if (!write_blocked_list_.empty()) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 678 | for (const std::unique_ptr<QuicSession>& session : closed_session_list_) { |
| 679 | if (write_blocked_list_.erase(session->connection()) != 0) { |
| 680 | QUIC_BUG << "QuicConnection was in WriteBlockedList before destruction"; |
| 681 | } |
| 682 | } |
| 683 | } |
| 684 | closed_session_list_.clear(); |
| 685 | } |
| 686 | |
| 687 | void QuicDispatcher::OnCanWrite() { |
| 688 | // The socket is now writable. |
| 689 | writer_->SetWritable(); |
| 690 | |
| 691 | // Move every blocked writer in |write_blocked_list_| to a temporary list. |
| 692 | const size_t num_blocked_writers_before = write_blocked_list_.size(); |
| 693 | WriteBlockedList temp_list; |
| 694 | temp_list.swap(write_blocked_list_); |
| 695 | DCHECK(write_blocked_list_.empty()); |
| 696 | |
| 697 | // Give each blocked writer a chance to write what they indended to write. |
| 698 | // If they are blocked again, they will call |OnWriteBlocked| to add |
| 699 | // themselves back into |write_blocked_list_|. |
| 700 | while (!temp_list.empty()) { |
| 701 | QuicBlockedWriterInterface* blocked_writer = temp_list.begin()->first; |
| 702 | temp_list.erase(temp_list.begin()); |
| 703 | blocked_writer->OnBlockedWriterCanWrite(); |
| 704 | } |
| 705 | const size_t num_blocked_writers_after = write_blocked_list_.size(); |
| 706 | if (num_blocked_writers_after != 0) { |
| 707 | if (num_blocked_writers_before == num_blocked_writers_after) { |
| 708 | QUIC_CODE_COUNT(quic_zero_progress_on_can_write); |
| 709 | } else { |
| 710 | QUIC_CODE_COUNT(quic_blocked_again_on_can_write); |
| 711 | } |
| 712 | } |
| 713 | } |
| 714 | |
| 715 | bool QuicDispatcher::HasPendingWrites() const { |
| 716 | return !write_blocked_list_.empty(); |
| 717 | } |
| 718 | |
| 719 | void QuicDispatcher::Shutdown() { |
| 720 | while (!session_map_.empty()) { |
| 721 | QuicSession* session = session_map_.begin()->second.get(); |
| 722 | session->connection()->CloseConnection( |
| 723 | QUIC_PEER_GOING_AWAY, "Server shutdown imminent", |
| 724 | ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); |
| 725 | // Validate that the session removes itself from the session map on close. |
| 726 | DCHECK(session_map_.empty() || |
| 727 | session_map_.begin()->second.get() != session); |
| 728 | } |
| 729 | DeleteSessions(); |
| 730 | } |
| 731 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 732 | void QuicDispatcher::OnConnectionClosed(QuicConnectionId server_connection_id, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 733 | QuicErrorCode error, |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 734 | const std::string& error_details, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 735 | ConnectionCloseSource source) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 736 | auto it = session_map_.find(server_connection_id); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 737 | if (it == session_map_.end()) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 738 | QUIC_BUG << "ConnectionId " << server_connection_id |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 739 | << " does not exist in the session map. Error: " |
| 740 | << QuicErrorCodeToString(error); |
| 741 | QUIC_BUG << QuicStackTrace(); |
| 742 | return; |
| 743 | } |
| 744 | |
| 745 | QUIC_DLOG_IF(INFO, error != QUIC_NO_ERROR) |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 746 | << "Closing connection (" << server_connection_id |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 747 | << ") due to error: " << QuicErrorCodeToString(error) |
| 748 | << ", with details: " << error_details; |
| 749 | |
| 750 | QuicConnection* connection = it->second->connection(); |
| 751 | if (ShouldDestroySessionAsynchronously()) { |
| 752 | // Set up alarm to fire immediately to bring destruction of this session |
| 753 | // out of current call stack. |
| 754 | if (closed_session_list_.empty()) { |
| 755 | delete_sessions_alarm_->Update(helper()->GetClock()->ApproximateNow(), |
| 756 | QuicTime::Delta::Zero()); |
| 757 | } |
| 758 | closed_session_list_.push_back(std::move(it->second)); |
| 759 | } |
wub | 5f64ec4 | 2019-06-06 07:31:19 -0700 | [diff] [blame] | 760 | CleanUpSession(it, connection, source); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 761 | } |
| 762 | |
| 763 | void QuicDispatcher::OnWriteBlocked( |
| 764 | QuicBlockedWriterInterface* blocked_writer) { |
| 765 | if (!blocked_writer->IsWriterBlocked()) { |
| 766 | // It is a programming error if this ever happens. When we are sure it is |
| 767 | // not happening, replace it with a DCHECK. |
| 768 | QUIC_BUG |
| 769 | << "Tried to add writer into blocked list when it shouldn't be added"; |
| 770 | // Return without adding the connection to the blocked list, to avoid |
| 771 | // infinite loops in OnCanWrite. |
| 772 | return; |
| 773 | } |
| 774 | |
| 775 | write_blocked_list_.insert(std::make_pair(blocked_writer, true)); |
| 776 | } |
| 777 | |
| 778 | void QuicDispatcher::OnRstStreamReceived(const QuicRstStreamFrame& frame) {} |
| 779 | |
| 780 | void QuicDispatcher::OnStopSendingReceived(const QuicStopSendingFrame& frame) {} |
| 781 | |
| 782 | void QuicDispatcher::OnConnectionAddedToTimeWaitList( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 783 | QuicConnectionId server_connection_id) { |
| 784 | QUIC_DLOG(INFO) << "Connection " << server_connection_id |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 785 | << " added to time wait list."; |
| 786 | } |
| 787 | |
| 788 | void QuicDispatcher::StatelesslyTerminateConnection( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 789 | QuicConnectionId server_connection_id, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 790 | PacketHeaderFormat format, |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 791 | bool version_flag, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 792 | ParsedQuicVersion version, |
| 793 | QuicErrorCode error_code, |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 794 | const std::string& error_details, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 795 | QuicTimeWaitListManager::TimeWaitAction action) { |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 796 | if (format != IETF_QUIC_LONG_HEADER_PACKET && |
| 797 | (!GetQuicReloadableFlag(quic_terminate_gquic_connection_as_ietf) || |
| 798 | !version_flag)) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 799 | QUIC_DVLOG(1) << "Statelessly terminating " << server_connection_id |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 800 | << " based on a non-ietf-long packet, action:" << action |
| 801 | << ", error_code:" << error_code |
| 802 | << ", error_details:" << error_details; |
| 803 | time_wait_list_manager_->AddConnectionIdToTimeWait( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 804 | server_connection_id, format != GOOGLE_QUIC_PACKET, action, |
| 805 | ENCRYPTION_INITIAL, nullptr); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 806 | return; |
| 807 | } |
| 808 | |
| 809 | // If the version is known and supported by framer, send a connection close. |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 810 | if (IsSupportedVersion(version)) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 811 | QUIC_DVLOG(1) |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 812 | << "Statelessly terminating " << server_connection_id |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 813 | << " based on an ietf-long packet, which has a supported version:" |
| 814 | << version << ", error_code:" << error_code |
| 815 | << ", error_details:" << error_details; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 816 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 817 | StatelessConnectionTerminator terminator(server_connection_id, version, |
| 818 | helper_.get(), |
| 819 | time_wait_list_manager_.get()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 820 | // This also adds the connection to time wait list. |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 821 | if (format == GOOGLE_QUIC_PACKET) { |
| 822 | QUIC_RELOADABLE_FLAG_COUNT_N(quic_terminate_gquic_connection_as_ietf, 1, |
| 823 | 2); |
| 824 | } |
| 825 | terminator.CloseConnection(error_code, error_details, |
| 826 | format != GOOGLE_QUIC_PACKET); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 827 | return; |
| 828 | } |
| 829 | |
| 830 | QUIC_DVLOG(1) |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 831 | << "Statelessly terminating " << server_connection_id |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 832 | << " based on an ietf-long packet, which has an unsupported version:" |
| 833 | << version << ", error_code:" << error_code |
| 834 | << ", error_details:" << error_details; |
| 835 | // Version is unknown or unsupported by framer, send a version negotiation |
| 836 | // with an empty version list, which can be understood by the client. |
| 837 | std::vector<std::unique_ptr<QuicEncryptedPacket>> termination_packets; |
| 838 | termination_packets.push_back(QuicFramer::BuildVersionNegotiationPacket( |
dschinazi | b417d60 | 2019-05-29 13:08:45 -0700 | [diff] [blame] | 839 | server_connection_id, EmptyQuicConnectionId(), |
| 840 | /*ietf_quic=*/format != GOOGLE_QUIC_PACKET, |
nharper | 4fd1105 | 2019-06-04 14:23:22 -0700 | [diff] [blame] | 841 | ParsedQuicVersionVector{QuicVersionReservedForNegotiation()})); |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 842 | if (format == GOOGLE_QUIC_PACKET) { |
| 843 | QUIC_RELOADABLE_FLAG_COUNT_N(quic_terminate_gquic_connection_as_ietf, 2, 2); |
| 844 | } |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 845 | time_wait_list_manager()->AddConnectionIdToTimeWait( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 846 | server_connection_id, /*ietf_quic=*/format != GOOGLE_QUIC_PACKET, |
QUICHE team | 6987b4a | 2019-03-15 16:23:04 -0700 | [diff] [blame] | 847 | QuicTimeWaitListManager::SEND_TERMINATION_PACKETS, ENCRYPTION_INITIAL, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 848 | &termination_packets); |
| 849 | } |
| 850 | |
| 851 | void QuicDispatcher::OnPacket() {} |
| 852 | |
| 853 | void QuicDispatcher::OnError(QuicFramer* framer) { |
| 854 | QuicErrorCode error = framer->error(); |
| 855 | SetLastError(error); |
| 856 | QUIC_DLOG(INFO) << QuicErrorCodeToString(error); |
| 857 | } |
| 858 | |
| 859 | bool QuicDispatcher::ShouldCreateSessionForUnknownVersion( |
| 860 | QuicVersionLabel /*version_label*/) { |
| 861 | return false; |
| 862 | } |
| 863 | |
| 864 | bool QuicDispatcher::OnProtocolVersionMismatch( |
| 865 | ParsedQuicVersion /*received_version*/, |
| 866 | PacketHeaderFormat /*form*/) { |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 867 | DCHECK(!no_framer_); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 868 | QUIC_BUG_IF( |
| 869 | !time_wait_list_manager_->IsConnectionIdInTimeWait( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 870 | current_server_connection_id_) && |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 871 | !ShouldCreateSessionForUnknownVersion(framer_.last_version_label())) |
| 872 | << "Unexpected version mismatch: " |
| 873 | << QuicVersionLabelToString(framer_.last_version_label()); |
| 874 | |
| 875 | // Keep processing after protocol mismatch - this will be dealt with by the |
| 876 | // time wait list or connection that we will create. |
| 877 | return true; |
| 878 | } |
| 879 | |
| 880 | void QuicDispatcher::OnPublicResetPacket( |
| 881 | const QuicPublicResetPacket& /*packet*/) { |
| 882 | DCHECK(false); |
| 883 | } |
| 884 | |
| 885 | void QuicDispatcher::OnVersionNegotiationPacket( |
| 886 | const QuicVersionNegotiationPacket& /*packet*/) { |
| 887 | DCHECK(false); |
| 888 | } |
| 889 | |
dschinazi | 244f6dc | 2019-05-06 15:45:16 -0700 | [diff] [blame] | 890 | void QuicDispatcher::OnRetryPacket(QuicConnectionId /*original_connection_id*/, |
| 891 | QuicConnectionId /*new_connection_id*/, |
| 892 | QuicStringPiece /*retry_token*/) { |
| 893 | DCHECK(false); |
| 894 | } |
| 895 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 896 | void QuicDispatcher::OnDecryptedPacket(EncryptionLevel level) { |
| 897 | DCHECK(false); |
| 898 | } |
| 899 | |
| 900 | bool QuicDispatcher::OnPacketHeader(const QuicPacketHeader& /*header*/) { |
| 901 | DCHECK(false); |
| 902 | return false; |
| 903 | } |
| 904 | |
| 905 | void QuicDispatcher::OnCoalescedPacket(const QuicEncryptedPacket& /*packet*/) { |
| 906 | DCHECK(false); |
| 907 | } |
| 908 | |
| 909 | bool QuicDispatcher::OnStreamFrame(const QuicStreamFrame& /*frame*/) { |
| 910 | DCHECK(false); |
| 911 | return false; |
| 912 | } |
| 913 | |
| 914 | bool QuicDispatcher::OnCryptoFrame(const QuicCryptoFrame& /*frame*/) { |
| 915 | DCHECK(false); |
| 916 | return false; |
| 917 | } |
| 918 | |
| 919 | bool QuicDispatcher::OnAckFrameStart(QuicPacketNumber /*largest_acked*/, |
| 920 | QuicTime::Delta /*ack_delay_time*/) { |
| 921 | DCHECK(false); |
| 922 | return false; |
| 923 | } |
| 924 | |
| 925 | bool QuicDispatcher::OnAckRange(QuicPacketNumber /*start*/, |
| 926 | QuicPacketNumber /*end*/) { |
| 927 | DCHECK(false); |
| 928 | return false; |
| 929 | } |
| 930 | |
| 931 | bool QuicDispatcher::OnAckTimestamp(QuicPacketNumber /*packet_number*/, |
| 932 | QuicTime /*timestamp*/) { |
| 933 | DCHECK(false); |
| 934 | return false; |
| 935 | } |
| 936 | |
| 937 | bool QuicDispatcher::OnAckFrameEnd(QuicPacketNumber /*start*/) { |
| 938 | DCHECK(false); |
| 939 | return false; |
| 940 | } |
| 941 | |
| 942 | bool QuicDispatcher::OnStopWaitingFrame(const QuicStopWaitingFrame& /*frame*/) { |
| 943 | DCHECK(false); |
| 944 | return false; |
| 945 | } |
| 946 | |
| 947 | bool QuicDispatcher::OnPaddingFrame(const QuicPaddingFrame& /*frame*/) { |
| 948 | DCHECK(false); |
| 949 | return false; |
| 950 | } |
| 951 | |
| 952 | bool QuicDispatcher::OnPingFrame(const QuicPingFrame& /*frame*/) { |
| 953 | DCHECK(false); |
| 954 | return false; |
| 955 | } |
| 956 | |
| 957 | bool QuicDispatcher::OnRstStreamFrame(const QuicRstStreamFrame& /*frame*/) { |
| 958 | DCHECK(false); |
| 959 | return false; |
| 960 | } |
| 961 | |
| 962 | bool QuicDispatcher::OnConnectionCloseFrame( |
| 963 | const QuicConnectionCloseFrame& /*frame*/) { |
| 964 | DCHECK(false); |
| 965 | return false; |
| 966 | } |
| 967 | |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 968 | bool QuicDispatcher::OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 969 | return true; |
| 970 | } |
| 971 | |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 972 | bool QuicDispatcher::OnStreamsBlockedFrame( |
| 973 | const QuicStreamsBlockedFrame& frame) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 974 | return true; |
| 975 | } |
| 976 | |
| 977 | bool QuicDispatcher::OnStopSendingFrame(const QuicStopSendingFrame& /*frame*/) { |
| 978 | DCHECK(false); |
| 979 | return false; |
| 980 | } |
| 981 | |
| 982 | bool QuicDispatcher::OnPathChallengeFrame( |
| 983 | const QuicPathChallengeFrame& /*frame*/) { |
| 984 | DCHECK(false); |
| 985 | return false; |
| 986 | } |
| 987 | |
| 988 | bool QuicDispatcher::OnPathResponseFrame( |
| 989 | const QuicPathResponseFrame& /*frame*/) { |
| 990 | DCHECK(false); |
| 991 | return false; |
| 992 | } |
| 993 | |
| 994 | bool QuicDispatcher::OnGoAwayFrame(const QuicGoAwayFrame& /*frame*/) { |
| 995 | DCHECK(false); |
| 996 | return false; |
| 997 | } |
| 998 | |
| 999 | bool QuicDispatcher::OnWindowUpdateFrame( |
| 1000 | const QuicWindowUpdateFrame& /*frame*/) { |
| 1001 | DCHECK(false); |
| 1002 | return false; |
| 1003 | } |
| 1004 | |
| 1005 | bool QuicDispatcher::OnBlockedFrame(const QuicBlockedFrame& frame) { |
| 1006 | DCHECK(false); |
| 1007 | return false; |
| 1008 | } |
| 1009 | |
| 1010 | bool QuicDispatcher::OnNewConnectionIdFrame( |
| 1011 | const QuicNewConnectionIdFrame& frame) { |
| 1012 | DCHECK(false); |
| 1013 | return false; |
| 1014 | } |
| 1015 | |
| 1016 | bool QuicDispatcher::OnRetireConnectionIdFrame( |
| 1017 | const QuicRetireConnectionIdFrame& frame) { |
| 1018 | DCHECK(false); |
| 1019 | return false; |
| 1020 | } |
| 1021 | |
| 1022 | bool QuicDispatcher::OnNewTokenFrame(const QuicNewTokenFrame& frame) { |
| 1023 | DCHECK(false); |
| 1024 | return false; |
| 1025 | } |
| 1026 | |
| 1027 | bool QuicDispatcher::OnMessageFrame(const QuicMessageFrame& frame) { |
| 1028 | DCHECK(false); |
| 1029 | return false; |
| 1030 | } |
| 1031 | |
| 1032 | void QuicDispatcher::OnPacketComplete() { |
| 1033 | DCHECK(false); |
| 1034 | } |
| 1035 | |
| 1036 | bool QuicDispatcher::IsValidStatelessResetToken(QuicUint128 token) const { |
| 1037 | DCHECK(false); |
| 1038 | return false; |
| 1039 | } |
| 1040 | |
| 1041 | void QuicDispatcher::OnAuthenticatedIetfStatelessResetPacket( |
| 1042 | const QuicIetfStatelessResetPacket& packet) { |
| 1043 | DCHECK(false); |
| 1044 | } |
| 1045 | |
| 1046 | void QuicDispatcher::OnExpiredPackets( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1047 | QuicConnectionId server_connection_id, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1048 | BufferedPacketList early_arrived_packets) { |
| 1049 | QUIC_CODE_COUNT(quic_reject_buffered_packets_expired); |
| 1050 | StatelesslyTerminateConnection( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1051 | server_connection_id, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1052 | early_arrived_packets.ietf_quic ? IETF_QUIC_LONG_HEADER_PACKET |
| 1053 | : GOOGLE_QUIC_PACKET, |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 1054 | /*version_flag=*/true, early_arrived_packets.version, |
| 1055 | QUIC_HANDSHAKE_FAILED, "Packets buffered for too long", |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1056 | quic::QuicTimeWaitListManager::SEND_STATELESS_RESET); |
| 1057 | } |
| 1058 | |
| 1059 | void QuicDispatcher::ProcessBufferedChlos(size_t max_connections_to_create) { |
| 1060 | // Reset the counter before starting creating connections. |
| 1061 | new_sessions_allowed_per_event_loop_ = max_connections_to_create; |
| 1062 | for (; new_sessions_allowed_per_event_loop_ > 0; |
| 1063 | --new_sessions_allowed_per_event_loop_) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1064 | QuicConnectionId server_connection_id; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1065 | BufferedPacketList packet_list = |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1066 | buffered_packets_.DeliverPacketsForNextConnection( |
| 1067 | &server_connection_id); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1068 | const std::list<BufferedPacket>& packets = packet_list.buffered_packets; |
| 1069 | if (packets.empty()) { |
| 1070 | return; |
| 1071 | } |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1072 | QuicConnectionId original_connection_id = server_connection_id; |
| 1073 | server_connection_id = MaybeReplaceServerConnectionId(server_connection_id, |
| 1074 | packet_list.version); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1075 | QuicSession* session = |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1076 | CreateQuicSession(server_connection_id, packets.front().peer_address, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1077 | packet_list.alpn, packet_list.version); |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1078 | if (original_connection_id != server_connection_id) { |
QUICHE team | c65d1d1 | 2019-03-19 20:58:04 -0700 | [diff] [blame] | 1079 | session->connection()->AddIncomingConnectionId(original_connection_id); |
| 1080 | } |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1081 | QUIC_DLOG(INFO) << "Created new session for " << server_connection_id; |
| 1082 | session_map_.insert( |
| 1083 | std::make_pair(server_connection_id, QuicWrapUnique(session))); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1084 | DeliverPacketsToSession(packets, session); |
| 1085 | } |
| 1086 | } |
| 1087 | |
| 1088 | bool QuicDispatcher::HasChlosBuffered() const { |
| 1089 | return buffered_packets_.HasChlosBuffered(); |
| 1090 | } |
| 1091 | |
| 1092 | bool QuicDispatcher::ShouldCreateOrBufferPacketForConnection( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1093 | QuicConnectionId server_connection_id, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1094 | bool ietf_quic) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1095 | QUIC_VLOG(1) << "Received packet from new connection " |
| 1096 | << server_connection_id; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1097 | return true; |
| 1098 | } |
| 1099 | |
| 1100 | // Return true if there is any packet buffered in the store. |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1101 | bool QuicDispatcher::HasBufferedPackets(QuicConnectionId server_connection_id) { |
| 1102 | return buffered_packets_.HasBufferedPackets(server_connection_id); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1103 | } |
| 1104 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1105 | void QuicDispatcher::OnBufferPacketFailure( |
| 1106 | EnqueuePacketResult result, |
| 1107 | QuicConnectionId server_connection_id) { |
| 1108 | QUIC_DLOG(INFO) << "Fail to buffer packet on connection " |
| 1109 | << server_connection_id << " because of " << result; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1110 | } |
| 1111 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1112 | QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() { |
| 1113 | return new QuicTimeWaitListManager(writer_.get(), this, helper_->GetClock(), |
| 1114 | alarm_factory_.get()); |
| 1115 | } |
| 1116 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1117 | void QuicDispatcher::BufferEarlyPacket(QuicConnectionId server_connection_id, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1118 | bool ietf_quic, |
| 1119 | ParsedQuicVersion version) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1120 | bool is_new_connection = |
| 1121 | !buffered_packets_.HasBufferedPackets(server_connection_id); |
| 1122 | if (is_new_connection && !ShouldCreateOrBufferPacketForConnection( |
| 1123 | server_connection_id, ietf_quic)) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1124 | return; |
| 1125 | } |
| 1126 | |
| 1127 | EnqueuePacketResult rs = buffered_packets_.EnqueuePacket( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1128 | server_connection_id, ietf_quic, *current_packet_, current_self_address_, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1129 | current_peer_address_, /*is_chlo=*/false, |
| 1130 | /*alpn=*/"", version); |
| 1131 | if (rs != EnqueuePacketResult::SUCCESS) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1132 | OnBufferPacketFailure(rs, server_connection_id); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1133 | } |
| 1134 | } |
| 1135 | |
| 1136 | void QuicDispatcher::ProcessChlo(PacketHeaderFormat form, |
| 1137 | ParsedQuicVersion version) { |
| 1138 | if (!accept_new_connections_) { |
| 1139 | // Don't any create new connection. |
| 1140 | QUIC_CODE_COUNT(quic_reject_stop_accepting_new_connections); |
| 1141 | StatelesslyTerminateConnection( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1142 | current_server_connection_id(), form, /*version_flag=*/true, version, |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 1143 | QUIC_HANDSHAKE_FAILED, "Stop accepting new connections", |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1144 | quic::QuicTimeWaitListManager::SEND_STATELESS_RESET); |
| 1145 | // Time wait list will reject the packet correspondingly. |
| 1146 | time_wait_list_manager()->ProcessPacket( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1147 | current_self_address(), current_peer_address(), |
| 1148 | current_server_connection_id(), form, GetPerPacketContext()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1149 | return; |
| 1150 | } |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1151 | if (!buffered_packets_.HasBufferedPackets(current_server_connection_id_) && |
| 1152 | !ShouldCreateOrBufferPacketForConnection(current_server_connection_id_, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1153 | form != GOOGLE_QUIC_PACKET)) { |
| 1154 | return; |
| 1155 | } |
QUICHE team | f356d9e | 2019-06-12 15:34:32 -0700 | [diff] [blame^] | 1156 | if (FLAGS_quic_allow_chlo_buffering && |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1157 | new_sessions_allowed_per_event_loop_ <= 0) { |
| 1158 | // Can't create new session any more. Wait till next event loop. |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1159 | QUIC_BUG_IF( |
| 1160 | buffered_packets_.HasChloForConnection(current_server_connection_id_)); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1161 | EnqueuePacketResult rs = buffered_packets_.EnqueuePacket( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1162 | current_server_connection_id_, form != GOOGLE_QUIC_PACKET, |
| 1163 | *current_packet_, current_self_address_, current_peer_address_, |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 1164 | /*is_chlo=*/true, current_alpn_, version); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1165 | if (rs != EnqueuePacketResult::SUCCESS) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1166 | OnBufferPacketFailure(rs, current_server_connection_id_); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1167 | } |
| 1168 | return; |
| 1169 | } |
QUICHE team | c65d1d1 | 2019-03-19 20:58:04 -0700 | [diff] [blame] | 1170 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1171 | QuicConnectionId original_connection_id = current_server_connection_id_; |
| 1172 | current_server_connection_id_ = |
| 1173 | MaybeReplaceServerConnectionId(current_server_connection_id_, version); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1174 | // Creates a new session and process all buffered packets for this connection. |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1175 | QuicSession* session = |
| 1176 | CreateQuicSession(current_server_connection_id_, current_peer_address_, |
| 1177 | current_alpn_, version); |
| 1178 | if (original_connection_id != current_server_connection_id_) { |
QUICHE team | c65d1d1 | 2019-03-19 20:58:04 -0700 | [diff] [blame] | 1179 | session->connection()->AddIncomingConnectionId(original_connection_id); |
| 1180 | } |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1181 | QUIC_DLOG(INFO) << "Created new session for " |
| 1182 | << current_server_connection_id_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1183 | session_map_.insert( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1184 | std::make_pair(current_server_connection_id_, QuicWrapUnique(session))); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1185 | std::list<BufferedPacket> packets = |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1186 | buffered_packets_.DeliverPackets(current_server_connection_id_) |
| 1187 | .buffered_packets; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1188 | // Process CHLO at first. |
| 1189 | session->ProcessUdpPacket(current_self_address_, current_peer_address_, |
| 1190 | *current_packet_); |
| 1191 | // Deliver queued-up packets in the same order as they arrived. |
| 1192 | // Do this even when flag is off because there might be still some packets |
| 1193 | // buffered in the store before flag is turned off. |
| 1194 | DeliverPacketsToSession(packets, session); |
| 1195 | --new_sessions_allowed_per_event_loop_; |
| 1196 | } |
| 1197 | |
| 1198 | const QuicSocketAddress QuicDispatcher::GetClientAddress() const { |
| 1199 | return current_peer_address_; |
| 1200 | } |
| 1201 | |
| 1202 | bool QuicDispatcher::ShouldDestroySessionAsynchronously() { |
| 1203 | return true; |
| 1204 | } |
| 1205 | |
| 1206 | void QuicDispatcher::SetLastError(QuicErrorCode error) { |
| 1207 | last_error_ = error; |
| 1208 | } |
| 1209 | |
| 1210 | bool QuicDispatcher::OnUnauthenticatedUnknownPublicHeader( |
| 1211 | const QuicPacketHeader& header) { |
| 1212 | return true; |
| 1213 | } |
| 1214 | |
wub | 0a4b9c5 | 2019-05-28 13:18:58 -0700 | [diff] [blame] | 1215 | void QuicDispatcher::ProcessOrBufferPacket( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1216 | QuicConnectionId server_connection_id, |
| 1217 | PacketHeaderFormat form, |
| 1218 | bool version_flag, |
| 1219 | ParsedQuicVersion version) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1220 | if (version.handshake_protocol == PROTOCOL_TLS1_3) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1221 | ProcessUnauthenticatedHeaderFate(kFateProcess, server_connection_id, form, |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 1222 | version_flag, version); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1223 | return; |
| 1224 | // TODO(nharper): Support buffering non-ClientHello packets when using TLS. |
| 1225 | } |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1226 | |
wub | 0a4b9c5 | 2019-05-28 13:18:58 -0700 | [diff] [blame] | 1227 | ChloAlpnExtractor alpn_extractor; |
QUICHE team | f356d9e | 2019-06-12 15:34:32 -0700 | [diff] [blame^] | 1228 | if (FLAGS_quic_allow_chlo_buffering && |
wub | 0a4b9c5 | 2019-05-28 13:18:58 -0700 | [diff] [blame] | 1229 | !ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1230 | config_->create_session_tag_indicators(), |
wub | 0a4b9c5 | 2019-05-28 13:18:58 -0700 | [diff] [blame] | 1231 | &alpn_extractor, server_connection_id.length())) { |
| 1232 | // Buffer non-CHLO packets. |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 1233 | ProcessUnauthenticatedHeaderFate(kFateBuffer, server_connection_id, form, |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 1234 | version_flag, version); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1235 | return; |
| 1236 | } |
wub | 0a4b9c5 | 2019-05-28 13:18:58 -0700 | [diff] [blame] | 1237 | current_alpn_ = alpn_extractor.ConsumeAlpn(); |
| 1238 | ProcessUnauthenticatedHeaderFate(kFateProcess, server_connection_id, form, |
| 1239 | version_flag, version); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1240 | } |
| 1241 | |
| 1242 | const QuicTransportVersionVector& |
| 1243 | QuicDispatcher::GetSupportedTransportVersions() { |
| 1244 | return version_manager_->GetSupportedTransportVersions(); |
| 1245 | } |
| 1246 | |
| 1247 | const ParsedQuicVersionVector& QuicDispatcher::GetSupportedVersions() { |
| 1248 | return version_manager_->GetSupportedVersions(); |
| 1249 | } |
| 1250 | |
| 1251 | void QuicDispatcher::DeliverPacketsToSession( |
| 1252 | const std::list<BufferedPacket>& packets, |
| 1253 | QuicSession* session) { |
| 1254 | for (const BufferedPacket& packet : packets) { |
| 1255 | session->ProcessUdpPacket(packet.self_address, packet.peer_address, |
| 1256 | *(packet.packet)); |
| 1257 | } |
| 1258 | } |
| 1259 | |
| 1260 | void QuicDispatcher::DisableFlagValidation() { |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 1261 | if (!no_framer_) { |
| 1262 | framer_.set_validate_flags(false); |
| 1263 | } |
| 1264 | } |
| 1265 | |
| 1266 | bool QuicDispatcher::IsSupportedVersion(const ParsedQuicVersion version) { |
| 1267 | if (!no_framer_) { |
| 1268 | return framer_.IsSupportedVersion(version); |
| 1269 | } |
| 1270 | for (const ParsedQuicVersion& supported_version : |
| 1271 | version_manager_->GetSupportedVersions()) { |
| 1272 | if (version == supported_version) { |
| 1273 | return true; |
| 1274 | } |
| 1275 | } |
| 1276 | return false; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1277 | } |
| 1278 | |
| 1279 | } // namespace quic |