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