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 // A server side dispatcher which dispatches a given client's data to their 6 // stream. 7 8 #ifndef QUICHE_QUIC_CORE_QUIC_DISPATCHER_H_ 9 #define QUICHE_QUIC_CORE_QUIC_DISPATCHER_H_ 10 11 #include <cstddef> 12 #include <memory> 13 #include <string> 14 #include <vector> 15 16 #include "absl/container/flat_hash_map.h" 17 #include "absl/strings/string_view.h" 18 #include "quiche/quic/core/connection_id_generator.h" 19 #include "quiche/quic/core/crypto/quic_compressed_certs_cache.h" 20 #include "quiche/quic/core/crypto/quic_random.h" 21 #include "quiche/quic/core/quic_blocked_writer_interface.h" 22 #include "quiche/quic/core/quic_buffered_packet_store.h" 23 #include "quiche/quic/core/quic_connection.h" 24 #include "quiche/quic/core/quic_connection_id.h" 25 #include "quiche/quic/core/quic_crypto_server_stream_base.h" 26 #include "quiche/quic/core/quic_packets.h" 27 #include "quiche/quic/core/quic_process_packet_interface.h" 28 #include "quiche/quic/core/quic_session.h" 29 #include "quiche/quic/core/quic_time_wait_list_manager.h" 30 #include "quiche/quic/core/quic_version_manager.h" 31 #include "quiche/quic/platform/api/quic_socket_address.h" 32 #include "quiche/common/platform/api/quiche_reference_counted.h" 33 #include "quiche/common/quiche_linked_hash_map.h" 34 35 namespace quic { 36 namespace test { 37 class QuicDispatcherPeer; 38 } // namespace test 39 40 class QuicConfig; 41 class QuicCryptoServerConfig; 42 43 class QUIC_NO_EXPORT QuicDispatcher 44 : public QuicTimeWaitListManager::Visitor, 45 public ProcessPacketInterface, 46 public QuicBufferedPacketStore::VisitorInterface { 47 public: 48 // Ideally we'd have a linked_hash_set: the boolean is unused. 49 using WriteBlockedList = 50 quiche::QuicheLinkedHashMap<QuicBlockedWriterInterface*, bool>; 51 52 QuicDispatcher( 53 const QuicConfig* config, const QuicCryptoServerConfig* crypto_config, 54 QuicVersionManager* version_manager, 55 std::unique_ptr<QuicConnectionHelperInterface> helper, 56 std::unique_ptr<QuicCryptoServerStreamBase::Helper> session_helper, 57 std::unique_ptr<QuicAlarmFactory> alarm_factory, 58 uint8_t expected_server_connection_id_length, 59 ConnectionIdGeneratorInterface& connection_id_generator); 60 QuicDispatcher(const QuicDispatcher&) = delete; 61 QuicDispatcher& operator=(const QuicDispatcher&) = delete; 62 63 ~QuicDispatcher() override; 64 65 // Takes ownership of |writer|. 66 void InitializeWithWriter(QuicPacketWriter* writer); 67 68 // Process the incoming packet by creating a new session, passing it to 69 // an existing session, or passing it to the time wait list. 70 void ProcessPacket(const QuicSocketAddress& self_address, 71 const QuicSocketAddress& peer_address, 72 const QuicReceivedPacket& packet) override; 73 74 // Called when the socket becomes writable to allow queued writes to happen. 75 virtual void OnCanWrite(); 76 77 // Returns true if there's anything in the blocked writer list. 78 virtual bool HasPendingWrites() const; 79 80 // Sends ConnectionClose frames to all connected clients. 81 void Shutdown(); 82 83 // QuicSession::Visitor interface implementation (via inheritance of 84 // QuicTimeWaitListManager::Visitor): 85 // Ensure that the closed connection is cleaned up asynchronously. 86 void OnConnectionClosed(QuicConnectionId server_connection_id, 87 QuicErrorCode error, const std::string& error_details, 88 ConnectionCloseSource source) override; 89 90 // QuicSession::Visitor interface implementation (via inheritance of 91 // QuicTimeWaitListManager::Visitor): 92 // Queues the blocked writer for later resumption. 93 void OnWriteBlocked(QuicBlockedWriterInterface* blocked_writer) override; 94 95 // QuicSession::Visitor interface implementation (via inheritance of 96 // QuicTimeWaitListManager::Visitor): 97 // Collects reset error code received on streams. 98 void OnRstStreamReceived(const QuicRstStreamFrame& frame) override; 99 100 // QuicSession::Visitor interface implementation (via inheritance of 101 // QuicTimeWaitListManager::Visitor): 102 // Collects reset error code received on streams. 103 void OnStopSendingReceived(const QuicStopSendingFrame& frame) override; 104 105 // QuicSession::Visitor interface implementation (via inheritance of 106 // QuicTimeWaitListManager::Visitor): 107 // Try to add the new connection ID to the session map. Returns true on 108 // success. 109 bool TryAddNewConnectionId( 110 const QuicConnectionId& server_connection_id, 111 const QuicConnectionId& new_connection_id) override; 112 113 // QuicSession::Visitor interface implementation (via inheritance of 114 // QuicTimeWaitListManager::Visitor): 115 // Remove the retired connection ID from the session map. 116 void OnConnectionIdRetired( 117 const QuicConnectionId& server_connection_id) override; 118 OnServerPreferredAddressAvailable(const QuicSocketAddress &)119 void OnServerPreferredAddressAvailable( 120 const QuicSocketAddress& /*server_preferred_address*/) override { 121 QUICHE_DCHECK(false); 122 } 123 124 // QuicTimeWaitListManager::Visitor interface implementation 125 // Called whenever the time wait list manager adds a new connection to the 126 // time-wait list. 127 void OnConnectionAddedToTimeWaitList( 128 QuicConnectionId server_connection_id) override; 129 130 using ReferenceCountedSessionMap = 131 absl::flat_hash_map<QuicConnectionId, std::shared_ptr<QuicSession>, 132 QuicConnectionIdHash>; 133 134 size_t NumSessions() const; 135 136 // Deletes all sessions on the closed session list and clears the list. 137 virtual void DeleteSessions(); 138 139 // Clear recent_stateless_reset_addresses_. 140 void ClearStatelessResetAddresses(); 141 142 using ConnectionIdMap = 143 absl::flat_hash_map<QuicConnectionId, QuicConnectionId, 144 QuicConnectionIdHash>; 145 146 // QuicBufferedPacketStore::VisitorInterface implementation. 147 void OnExpiredPackets(QuicConnectionId server_connection_id, 148 QuicBufferedPacketStore::BufferedPacketList 149 early_arrived_packets) override; 150 151 // Create connections for previously buffered CHLOs as many as allowed. 152 virtual void ProcessBufferedChlos(size_t max_connections_to_create); 153 154 // Return true if there is CHLO buffered. 155 virtual bool HasChlosBuffered() const; 156 157 // Start accepting new ConnectionIds. 158 void StartAcceptingNewConnections(); 159 160 // Stop accepting new ConnectionIds, either as a part of the lame 161 // duck process or because explicitly configured. 162 void StopAcceptingNewConnections(); 163 164 // Apply an operation for each session. 165 void PerformActionOnActiveSessions( 166 std::function<void(QuicSession*)> operation) const; 167 168 // Get a snapshot of all sessions. 169 std::vector<std::shared_ptr<QuicSession>> GetSessionsSnapshot() const; 170 accept_new_connections()171 bool accept_new_connections() const { return accept_new_connections_; } 172 173 protected: 174 // Creates a QUIC session based on the given information. 175 // |alpn| is the selected ALPN from |parsed_chlo.alpns|. 176 virtual std::unique_ptr<QuicSession> CreateQuicSession( 177 QuicConnectionId server_connection_id, 178 const QuicSocketAddress& self_address, 179 const QuicSocketAddress& peer_address, absl::string_view alpn, 180 const ParsedQuicVersion& version, 181 const ParsedClientHello& parsed_chlo) = 0; 182 183 // Tries to validate and dispatch packet based on available information. 184 // Returns true if packet is dropped or successfully dispatched (e.g., 185 // processed by existing session, processed by time wait list, etc.), 186 // otherwise, returns false and the packet needs further processing. 187 virtual bool MaybeDispatchPacket(const ReceivedPacketInfo& packet_info); 188 189 // Values to be returned by ValidityChecks() to indicate what should be done 190 // with a packet. Fates with greater values are considered to be higher 191 // priority. ValidityChecks should return fate based on the priority order 192 // (i.e., returns higher priority fate first) 193 enum QuicPacketFate { 194 // Process the packet normally, which is usually to establish a connection. 195 kFateProcess, 196 // Put the connection ID into time-wait state and send a public reset. 197 kFateTimeWait, 198 // Drop the packet. 199 kFateDrop, 200 }; 201 202 // This method is called by ProcessHeader on packets not associated with a 203 // known connection ID. It applies validity checks and returns a 204 // QuicPacketFate to tell what should be done with the packet. 205 // TODO(fayang): Merge ValidityChecks into MaybeDispatchPacket. 206 virtual QuicPacketFate ValidityChecks(const ReceivedPacketInfo& packet_info); 207 208 // Extra validity checks after the full Client Hello is parsed, this allows 209 // subclasses to reject a connection based on sni or alpn. 210 // Only called if ValidityChecks returns kFateProcess. ValidityChecksOnFullChlo(const ReceivedPacketInfo &,const ParsedClientHello &)211 virtual QuicPacketFate ValidityChecksOnFullChlo( 212 const ReceivedPacketInfo& /*packet_info*/, 213 const ParsedClientHello& /*parsed_chlo*/) const { 214 return kFateProcess; 215 } 216 217 // Create and return the time wait list manager for this dispatcher, which 218 // will be owned by the dispatcher as time_wait_list_manager_ 219 virtual QuicTimeWaitListManager* CreateQuicTimeWaitListManager(); 220 221 // Buffers packet until it can be delivered to a connection. 222 void BufferEarlyPacket(const ReceivedPacketInfo& packet_info); 223 224 // Called when |packet_info| is the last received packet of the client hello. 225 // |parsed_chlo| is the parsed version of the client hello. Creates a new 226 // connection and delivers any buffered packets for that connection id. 227 void ProcessChlo(ParsedClientHello parsed_chlo, 228 ReceivedPacketInfo* packet_info); 229 time_wait_list_manager()230 QuicTimeWaitListManager* time_wait_list_manager() { 231 return time_wait_list_manager_.get(); 232 } 233 234 const ParsedQuicVersionVector& GetSupportedVersions(); 235 config()236 const QuicConfig& config() const { return *config_; } 237 crypto_config()238 const QuicCryptoServerConfig* crypto_config() const { return crypto_config_; } 239 compressed_certs_cache()240 QuicCompressedCertsCache* compressed_certs_cache() { 241 return &compressed_certs_cache_; 242 } 243 helper()244 QuicConnectionHelperInterface* helper() { return helper_.get(); } 245 session_helper()246 QuicCryptoServerStreamBase::Helper* session_helper() { 247 return session_helper_.get(); 248 } 249 session_helper()250 const QuicCryptoServerStreamBase::Helper* session_helper() const { 251 return session_helper_.get(); 252 } 253 alarm_factory()254 QuicAlarmFactory* alarm_factory() { return alarm_factory_.get(); } 255 writer()256 QuicPacketWriter* writer() { return writer_.get(); } 257 258 // Returns true if a session should be created for a connection with an 259 // unknown version identified by |version_label|. 260 virtual bool ShouldCreateSessionForUnknownVersion( 261 QuicVersionLabel version_label); 262 263 void SetLastError(QuicErrorCode error); 264 265 // Called by MaybeDispatchPacket when current packet cannot be dispatched. 266 // Used by subclasses to conduct specific logic to dispatch packet. Returns 267 // true if packet is successfully dispatched. 268 virtual bool OnFailedToDispatchPacket(const ReceivedPacketInfo& packet_info); 269 270 bool HasBufferedPackets(QuicConnectionId server_connection_id); 271 272 // Called when BufferEarlyPacket() fail to buffer the packet. 273 virtual void OnBufferPacketFailure( 274 QuicBufferedPacketStore::EnqueuePacketResult result, 275 QuicConnectionId server_connection_id); 276 277 // Removes the session from the write blocked list, and adds the ConnectionId 278 // to the time-wait list. The caller needs to manually remove the session 279 // from the map after that. 280 void CleanUpSession(QuicConnectionId server_connection_id, 281 QuicConnection* connection, QuicErrorCode error, 282 const std::string& error_details, 283 ConnectionCloseSource source); 284 285 // Called to terminate a connection statelessly. Depending on |format|, either 286 // 1) send connection close with |error_code| and |error_details| and add 287 // connection to time wait list or 2) directly add connection to time wait 288 // list with |action|. 289 void StatelesslyTerminateConnection( 290 QuicConnectionId server_connection_id, PacketHeaderFormat format, 291 bool version_flag, bool use_length_prefix, ParsedQuicVersion version, 292 QuicErrorCode error_code, const std::string& error_details, 293 QuicTimeWaitListManager::TimeWaitAction action); 294 295 // Save/Restore per packet context. 296 virtual std::unique_ptr<QuicPerPacketContext> GetPerPacketContext() const; RestorePerPacketContext(std::unique_ptr<QuicPerPacketContext>)297 virtual void RestorePerPacketContext( 298 std::unique_ptr<QuicPerPacketContext> /*context*/) {} 299 300 // If true, our framer will change its expected connection ID length 301 // to the received destination connection ID length of all IETF long headers. SetShouldUpdateExpectedServerConnectionIdLength(bool should_update_expected_server_connection_id_length)302 void SetShouldUpdateExpectedServerConnectionIdLength( 303 bool should_update_expected_server_connection_id_length) { 304 should_update_expected_server_connection_id_length_ = 305 should_update_expected_server_connection_id_length; 306 } 307 308 // If true, the dispatcher will allow incoming initial packets that have 309 // destination connection IDs shorter than 64 bits. SetAllowShortInitialServerConnectionIds(bool allow_short_initial_server_connection_ids)310 void SetAllowShortInitialServerConnectionIds( 311 bool allow_short_initial_server_connection_ids) { 312 allow_short_initial_server_connection_ids_ = 313 allow_short_initial_server_connection_ids; 314 } 315 316 // Called if a packet from an unseen connection is reset or rejected. OnNewConnectionRejected()317 virtual void OnNewConnectionRejected() {} 318 319 // Selects the preferred ALPN from a vector of ALPNs. 320 // This runs through the list of ALPNs provided by the client and picks the 321 // first one it supports. If no supported versions are found, the first 322 // element of the vector is returned. 323 std::string SelectAlpn(const std::vector<std::string>& alpns); 324 325 // Sends public/stateless reset packets with no version and unknown 326 // connection ID according to the packet's size. 327 virtual void MaybeResetPacketsWithNoVersion( 328 const quic::ReceivedPacketInfo& packet_info); 329 330 // Called on packets with unsupported versions. 331 virtual void MaybeSendVersionNegotiationPacket( 332 const ReceivedPacketInfo& packet_info); 333 connection_id_generator()334 ConnectionIdGeneratorInterface& connection_id_generator() { 335 return connection_id_generator_; 336 } 337 338 private: 339 friend class test::QuicDispatcherPeer; 340 341 // TODO(fayang): Consider to rename this function to 342 // ProcessValidatedPacketWithUnknownConnectionId. 343 void ProcessHeader(ReceivedPacketInfo* packet_info); 344 345 struct ExtractChloResult { 346 // If set, a full client hello has been successfully parsed. 347 absl::optional<ParsedClientHello> parsed_chlo; 348 // If set, the TLS alert that will cause a connection close. 349 // Always empty for Google QUIC. 350 absl::optional<uint8_t> tls_alert; 351 }; 352 353 // Try to extract information(sni, alpns, ...) if the full Client Hello has 354 // been parsed. 355 // 356 // Returns the parsed client hello in ExtractChloResult.parsed_chlo, if the 357 // full Client Hello has been successfully parsed. 358 // 359 // Returns the TLS alert in ExtractChloResult.tls_alert, if the extraction of 360 // Client Hello failed due to that alert. 361 // 362 // Otherwise returns a default-constructed ExtractChloResult and either buffer 363 // or (rarely) drop the packet. 364 ExtractChloResult TryExtractChloOrBufferEarlyPacket( 365 const ReceivedPacketInfo& packet_info); 366 367 // Deliver |packets| to |session| for further processing. 368 void DeliverPacketsToSession( 369 const std::list<QuicBufferedPacketStore::BufferedPacket>& packets, 370 QuicSession* session); 371 372 // Returns true if |version| is a supported protocol version. 373 bool IsSupportedVersion(const ParsedQuicVersion version); 374 375 // Returns true if a server connection ID length is below all the minima 376 // required by various parameters. 377 bool IsServerConnectionIdTooShort(QuicConnectionId connection_id) const; 378 379 // Core CHLO processing logic. 380 std::shared_ptr<QuicSession> CreateSessionFromChlo( 381 const QuicConnectionId original_connection_id, 382 const ParsedClientHello& parsed_chlo, const ParsedQuicVersion version, 383 const QuicSocketAddress self_address, 384 const QuicSocketAddress peer_address); 385 386 const QuicConfig* config_; 387 388 const QuicCryptoServerConfig* crypto_config_; 389 390 // The cache for most recently compressed certs. 391 QuicCompressedCertsCache compressed_certs_cache_; 392 393 // The list of connections waiting to write. 394 WriteBlockedList write_blocked_list_; 395 396 ReferenceCountedSessionMap reference_counted_session_map_; 397 398 // Entity that manages connection_ids in time wait state. 399 std::unique_ptr<QuicTimeWaitListManager> time_wait_list_manager_; 400 401 // The list of closed but not-yet-deleted sessions. 402 std::vector<std::shared_ptr<QuicSession>> closed_session_list_; 403 404 // The helper used for all connections. 405 std::unique_ptr<QuicConnectionHelperInterface> helper_; 406 407 // The helper used for all sessions. 408 std::unique_ptr<QuicCryptoServerStreamBase::Helper> session_helper_; 409 410 // Creates alarms. 411 std::unique_ptr<QuicAlarmFactory> alarm_factory_; 412 413 // An alarm which deletes closed sessions. 414 std::unique_ptr<QuicAlarm> delete_sessions_alarm_; 415 416 // The writer to write to the socket with. 417 std::unique_ptr<QuicPacketWriter> writer_; 418 419 // Packets which are buffered until a connection can be created to handle 420 // them. 421 QuicBufferedPacketStore buffered_packets_; 422 423 // Used to get the supported versions based on flag. Does not own. 424 QuicVersionManager* version_manager_; 425 426 // The last error set by SetLastError(). 427 // TODO(fayang): consider removing last_error_. 428 QuicErrorCode last_error_; 429 430 // Number of unique session in session map. 431 size_t num_sessions_in_session_map_ = 0; 432 433 // A backward counter of how many new sessions can be create within current 434 // event loop. When reaches 0, it means can't create sessions for now. 435 int16_t new_sessions_allowed_per_event_loop_; 436 437 // True if this dispatcher is accepting new ConnectionIds (new client 438 // connections), false otherwise. 439 bool accept_new_connections_; 440 441 // If false, the dispatcher follows the IETF spec and rejects packets with 442 // invalid destination connection IDs lengths below 64 bits. 443 // If true they are allowed. 444 bool allow_short_initial_server_connection_ids_; 445 446 // IETF short headers contain a destination connection ID but do not 447 // encode its length. This variable contains the length we expect to read. 448 // This is also used to signal an error when a long header packet with 449 // different destination connection ID length is received when 450 // should_update_expected_server_connection_id_length_ is false and packet's 451 // version does not allow variable length connection ID. 452 uint8_t expected_server_connection_id_length_; 453 454 // Records client addresses that have been recently reset. 455 absl::flat_hash_set<QuicSocketAddress, QuicSocketAddressHash> 456 recent_stateless_reset_addresses_; 457 458 // An alarm which clear recent_stateless_reset_addresses_. 459 std::unique_ptr<QuicAlarm> clear_stateless_reset_addresses_alarm_; 460 461 // If true, change expected_server_connection_id_length_ to be the received 462 // destination connection ID length of all IETF long headers. 463 bool should_update_expected_server_connection_id_length_; 464 465 ConnectionIdGeneratorInterface& connection_id_generator_; 466 }; 467 468 } // namespace quic 469 470 #endif // QUICHE_QUIC_CORE_QUIC_DISPATCHER_H_ 471