Project import generated by Copybara.
PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/core/quic_dispatcher.h b/quic/core/quic_dispatcher.h
new file mode 100644
index 0000000..85e6da6
--- /dev/null
+++ b/quic/core/quic_dispatcher.h
@@ -0,0 +1,478 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A server side dispatcher which dispatches a given client's data to their
+// stream.
+
+#ifndef QUICHE_QUIC_CORE_QUIC_DISPATCHER_H_
+#define QUICHE_QUIC_CORE_QUIC_DISPATCHER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_compressed_certs_cache.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
+#include "net/third_party/quiche/src/quic/core/quic_blocked_writer_interface.h"
+#include "net/third_party/quiche/src/quic/core/quic_buffered_packet_store.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection.h"
+#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/core/quic_process_packet_interface.h"
+#include "net/third_party/quiche/src/quic/core/quic_session.h"
+#include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h"
+#include "net/third_party/quiche/src/quic/core/quic_version_manager.h"
+#include "net/third_party/quiche/src/quic/core/stateless_rejector.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
+
+namespace quic {
+namespace test {
+class QuicDispatcherPeer;
+} // namespace test
+
+class QuicConfig;
+class QuicCryptoServerConfig;
+
+class QuicDispatcher : public QuicTimeWaitListManager::Visitor,
+ public ProcessPacketInterface,
+ public QuicFramerVisitorInterface,
+ public QuicBufferedPacketStore::VisitorInterface {
+ public:
+ // Ideally we'd have a linked_hash_set: the boolean is unused.
+ typedef QuicLinkedHashMap<QuicBlockedWriterInterface*, bool> WriteBlockedList;
+
+ QuicDispatcher(const QuicConfig* config,
+ const QuicCryptoServerConfig* crypto_config,
+ QuicVersionManager* version_manager,
+ std::unique_ptr<QuicConnectionHelperInterface> helper,
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
+ std::unique_ptr<QuicAlarmFactory> alarm_factory,
+ uint8_t expected_connection_id_length);
+ QuicDispatcher(const QuicDispatcher&) = delete;
+ QuicDispatcher& operator=(const QuicDispatcher&) = delete;
+
+ ~QuicDispatcher() override;
+
+ // Takes ownership of |writer|.
+ void InitializeWithWriter(QuicPacketWriter* writer);
+
+ // Process the incoming packet by creating a new session, passing it to
+ // an existing session, or passing it to the time wait list.
+ void ProcessPacket(const QuicSocketAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ const QuicReceivedPacket& packet) override;
+
+ // Called when the socket becomes writable to allow queued writes to happen.
+ virtual void OnCanWrite();
+
+ // Returns true if there's anything in the blocked writer list.
+ virtual bool HasPendingWrites() const;
+
+ // Sends ConnectionClose frames to all connected clients.
+ void Shutdown();
+
+ // QuicSession::Visitor interface implementation (via inheritance of
+ // QuicTimeWaitListManager::Visitor):
+ // Ensure that the closed connection is cleaned up asynchronously.
+ void OnConnectionClosed(QuicConnectionId connection_id,
+ QuicErrorCode error,
+ const QuicString& error_details,
+ ConnectionCloseSource source) override;
+
+ // QuicSession::Visitor interface implementation (via inheritance of
+ // QuicTimeWaitListManager::Visitor):
+ // Queues the blocked writer for later resumption.
+ void OnWriteBlocked(QuicBlockedWriterInterface* blocked_writer) override;
+
+ // QuicSession::Visitor interface implementation (via inheritance of
+ // QuicTimeWaitListManager::Visitor):
+ // Collects reset error code received on streams.
+ void OnRstStreamReceived(const QuicRstStreamFrame& frame) override;
+
+ // QuicSession::Visitor interface implementation (via inheritance of
+ // QuicTimeWaitListManager::Visitor):
+ // Collects reset error code received on streams.
+ void OnStopSendingReceived(const QuicStopSendingFrame& frame) override;
+
+ // QuicTimeWaitListManager::Visitor interface implementation
+ // Called whenever the time wait list manager adds a new connection to the
+ // time-wait list.
+ void OnConnectionAddedToTimeWaitList(QuicConnectionId connection_id) override;
+
+ using SessionMap = QuicUnorderedMap<QuicConnectionId,
+ std::unique_ptr<QuicSession>,
+ QuicConnectionIdHash>;
+
+ const SessionMap& session_map() const { return session_map_; }
+
+ // Deletes all sessions on the closed session list and clears the list.
+ virtual void DeleteSessions();
+
+ // The largest packet number we expect to receive with a connection
+ // ID for a connection that is not established yet. The current design will
+ // send a handshake and then up to 50 or so data packets, and then it may
+ // resend the handshake packet up to 10 times. (Retransmitted packets are
+ // sent with unique packet numbers.)
+ static const uint64_t kMaxReasonableInitialPacketNumber = 100;
+ static_assert(kMaxReasonableInitialPacketNumber >=
+ kInitialCongestionWindow + 10,
+ "kMaxReasonableInitialPacketNumber is unreasonably small "
+ "relative to kInitialCongestionWindow.");
+
+ // QuicFramerVisitorInterface implementation. Not expected to be called
+ // outside of this class.
+ void OnPacket() override;
+ // Called when the public header has been parsed.
+ bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override;
+ // Called when the private header has been parsed of a data packet that is
+ // destined for the time wait manager.
+ bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override;
+ void OnError(QuicFramer* framer) override;
+ bool OnProtocolVersionMismatch(ParsedQuicVersion received_version,
+ PacketHeaderFormat form) override;
+
+ // The following methods should never get called because
+ // OnUnauthenticatedPublicHeader() or OnUnauthenticatedHeader() (whichever
+ // was called last), will return false and prevent a subsequent invocation
+ // of these methods. Thus, the payload of the packet is never processed in
+ // the dispatcher.
+ void OnPublicResetPacket(const QuicPublicResetPacket& packet) override;
+ void OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) override;
+ void OnDecryptedPacket(EncryptionLevel level) override;
+ bool OnPacketHeader(const QuicPacketHeader& header) override;
+ void OnCoalescedPacket(const QuicEncryptedPacket& packet) override;
+ bool OnStreamFrame(const QuicStreamFrame& frame) override;
+ bool OnCryptoFrame(const QuicCryptoFrame& frame) override;
+ bool OnAckFrameStart(QuicPacketNumber largest_acked,
+ QuicTime::Delta ack_delay_time) override;
+ bool OnAckRange(QuicPacketNumber start, QuicPacketNumber end) override;
+ bool OnAckTimestamp(QuicPacketNumber packet_number,
+ QuicTime timestamp) override;
+ bool OnAckFrameEnd(QuicPacketNumber start) override;
+ bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override;
+ bool OnPaddingFrame(const QuicPaddingFrame& frame) override;
+ bool OnPingFrame(const QuicPingFrame& frame) override;
+ bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override;
+ bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override;
+ bool OnApplicationCloseFrame(const QuicApplicationCloseFrame& frame) override;
+ bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override;
+ bool OnPathChallengeFrame(const QuicPathChallengeFrame& frame) override;
+ bool OnPathResponseFrame(const QuicPathResponseFrame& frame) override;
+ bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override;
+ bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override;
+ bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override;
+ bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
+ bool OnBlockedFrame(const QuicBlockedFrame& frame) override;
+ bool OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame) override;
+ bool OnRetireConnectionIdFrame(
+ const QuicRetireConnectionIdFrame& frame) override;
+ bool OnNewTokenFrame(const QuicNewTokenFrame& frame) override;
+ bool OnMessageFrame(const QuicMessageFrame& frame) override;
+ void OnPacketComplete() override;
+ bool IsValidStatelessResetToken(QuicUint128 token) const override;
+ void OnAuthenticatedIetfStatelessResetPacket(
+ const QuicIetfStatelessResetPacket& packet) override;
+
+ // QuicBufferedPacketStore::VisitorInterface implementation.
+ void OnExpiredPackets(QuicConnectionId connection_id,
+ QuicBufferedPacketStore::BufferedPacketList
+ early_arrived_packets) override;
+
+ // Create connections for previously buffered CHLOs as many as allowed.
+ virtual void ProcessBufferedChlos(size_t max_connections_to_create);
+
+ // Return true if there is CHLO buffered.
+ virtual bool HasChlosBuffered() const;
+
+ protected:
+ virtual QuicSession* CreateQuicSession(QuicConnectionId connection_id,
+ const QuicSocketAddress& peer_address,
+ QuicStringPiece alpn,
+ const ParsedQuicVersion& version) = 0;
+
+ // Called when a connection is rejected statelessly.
+ virtual void OnConnectionRejectedStatelessly();
+
+ // Called when a connection is closed statelessly.
+ virtual void OnConnectionClosedStatelessly(QuicErrorCode error);
+
+ // Returns true if cheap stateless rejection should be attempted.
+ virtual bool ShouldAttemptCheapStatelessRejection();
+
+ // Values to be returned by ValidityChecks() to indicate what should be done
+ // with a packet. Fates with greater values are considered to be higher
+ // priority, in that if one validity check indicates a lower-valued fate and
+ // another validity check indicates a higher-valued fate, the higher-valued
+ // fate should be obeyed.
+ enum QuicPacketFate {
+ // Process the packet normally, which is usually to establish a connection.
+ kFateProcess,
+ // Put the connection ID into time-wait state and send a public reset.
+ kFateTimeWait,
+ // Buffer the packet.
+ kFateBuffer,
+ // Drop the packet (ignore and give no response).
+ kFateDrop,
+ };
+
+ // This method is called by OnUnauthenticatedHeader on packets not associated
+ // with a known connection ID. It applies validity checks and returns a
+ // QuicPacketFate to tell what should be done with the packet.
+ virtual QuicPacketFate ValidityChecks(const QuicPacketHeader& header);
+
+ // Create and return the time wait list manager for this dispatcher, which
+ // will be owned by the dispatcher as time_wait_list_manager_
+ virtual QuicTimeWaitListManager* CreateQuicTimeWaitListManager();
+
+ // Called when |connection_id| doesn't have an open connection yet, to buffer
+ // |current_packet_| until it can be delivered to the connection.
+ void BufferEarlyPacket(QuicConnectionId connection_id,
+ bool ietf_quic,
+ ParsedQuicVersion version);
+
+ // Called when |current_packet_| is a CHLO packet. Creates a new connection
+ // and delivers any buffered packets for that connection id.
+ void ProcessChlo(PacketHeaderFormat form, ParsedQuicVersion version);
+
+ // Returns the actual client address of the current packet.
+ // This function should only be called once per packet at the very beginning
+ // of ProcessPacket(), its result is saved to |current_client_address_|, which
+ // is guaranteed to be valid even in the stateless rejector's callback(i.e.
+ // OnStatelessRejectorProcessDone).
+ // By default, this function returns |current_peer_address_|, subclasses have
+ // the option to override this function to return a different address.
+ virtual const QuicSocketAddress GetClientAddress() const;
+
+ // Return true if dispatcher wants to destroy session outside of
+ // OnConnectionClosed() call stack.
+ virtual bool ShouldDestroySessionAsynchronously();
+
+ QuicTimeWaitListManager* time_wait_list_manager() {
+ return time_wait_list_manager_.get();
+ }
+
+ const QuicTransportVersionVector& GetSupportedTransportVersions();
+
+ const ParsedQuicVersionVector& GetSupportedVersions();
+
+ QuicConnectionId current_connection_id() const {
+ return current_connection_id_;
+ }
+ const QuicSocketAddress& current_self_address() const {
+ return current_self_address_;
+ }
+ const QuicSocketAddress& current_peer_address() const {
+ return current_peer_address_;
+ }
+ const QuicSocketAddress& current_client_address() const {
+ return current_client_address_;
+ }
+ const QuicReceivedPacket& current_packet() const { return *current_packet_; }
+
+ const QuicConfig& config() const { return *config_; }
+
+ const QuicCryptoServerConfig* crypto_config() const { return crypto_config_; }
+
+ QuicCompressedCertsCache* compressed_certs_cache() {
+ return &compressed_certs_cache_;
+ }
+
+ QuicConnectionHelperInterface* helper() { return helper_.get(); }
+
+ QuicCryptoServerStream::Helper* session_helper() {
+ return session_helper_.get();
+ }
+
+ QuicAlarmFactory* alarm_factory() { return alarm_factory_.get(); }
+
+ QuicPacketWriter* writer() { return writer_.get(); }
+
+ // Returns true if a session should be created for a connection with an
+ // unknown version identified by |version_label|.
+ virtual bool ShouldCreateSessionForUnknownVersion(
+ QuicVersionLabel version_label);
+
+ void SetLastError(QuicErrorCode error);
+
+ // Called when the public header has been parsed and the session has been
+ // looked up, and the session was not found in the active list of sessions.
+ // Returns false if processing should stop after this call.
+ virtual bool OnUnauthenticatedUnknownPublicHeader(
+ const QuicPacketHeader& header);
+
+ // Called when a new connection starts to be handled by this dispatcher.
+ // Either this connection is created or its packets is buffered while waiting
+ // for CHLO. Returns true if a new connection should be created or its packets
+ // should be buffered, false otherwise.
+ virtual bool ShouldCreateOrBufferPacketForConnection(
+ QuicConnectionId connection_id,
+ bool ietf_quic);
+
+ bool HasBufferedPackets(QuicConnectionId connection_id);
+
+ // Called when BufferEarlyPacket() fail to buffer the packet.
+ virtual void OnBufferPacketFailure(
+ QuicBufferedPacketStore::EnqueuePacketResult result,
+ QuicConnectionId connection_id);
+
+ // Removes the session from the session map and write blocked list, and adds
+ // the ConnectionId to the time-wait list. If |session_closed_statelessly| is
+ // true, any future packets for the ConnectionId will be black-holed.
+ virtual void CleanUpSession(SessionMap::iterator it,
+ QuicConnection* connection,
+ bool session_closed_statelessly,
+ ConnectionCloseSource source);
+
+ void StopAcceptingNewConnections();
+
+ // Called to terminate a connection statelessly. Depending on |format|, either
+ // 1) send connection close with |error_code| and |error_details| and add
+ // connection to time wait list or 2) directly add connection to time wait
+ // list with |action|.
+ void StatelesslyTerminateConnection(
+ QuicConnectionId connection_id,
+ PacketHeaderFormat format,
+ ParsedQuicVersion version,
+ QuicErrorCode error_code,
+ const QuicString& error_details,
+ QuicTimeWaitListManager::TimeWaitAction action);
+
+ // Save/Restore per packet context. Used by async stateless rejector.
+ virtual std::unique_ptr<QuicPerPacketContext> GetPerPacketContext() const;
+ virtual void RestorePerPacketContext(
+ std::unique_ptr<QuicPerPacketContext> /*context*/) {}
+
+ // Skip validating that the public flags are set to legal values.
+ void DisableFlagValidation();
+
+ private:
+ friend class test::QuicDispatcherPeer;
+ friend class StatelessRejectorProcessDoneCallback;
+
+ typedef QuicUnorderedSet<QuicConnectionId, QuicConnectionIdHash>
+ QuicConnectionIdSet;
+
+ // Attempts to reject the connection statelessly, if stateless rejects are
+ // possible and if the current packet contains a CHLO message. Determines a
+ // fate which describes what subsequent processing should be performed on the
+ // packets, like ValidityChecks, and invokes ProcessUnauthenticatedHeaderFate.
+ void MaybeRejectStatelessly(QuicConnectionId connection_id,
+ PacketHeaderFormat form,
+ ParsedQuicVersion version);
+
+ // Deliver |packets| to |session| for further processing.
+ void DeliverPacketsToSession(
+ const std::list<QuicBufferedPacketStore::BufferedPacket>& packets,
+ QuicSession* session);
+
+ // Perform the appropriate actions on the current packet based on |fate| -
+ // either process, buffer, or drop it.
+ void ProcessUnauthenticatedHeaderFate(QuicPacketFate fate,
+ QuicConnectionId connection_id,
+ PacketHeaderFormat form,
+ ParsedQuicVersion version);
+
+ // Invoked when StatelessRejector::Process completes. |first_version| is the
+ // version of the packet which initiated the stateless reject.
+ // WARNING: This function can be called when a async proof returns, i.e. not
+ // from a stack traceable to ProcessPacket().
+ // TODO(fayang): maybe consider not using callback when there is no crypto
+ // involved.
+ void OnStatelessRejectorProcessDone(
+ std::unique_ptr<StatelessRejector> rejector,
+ const QuicSocketAddress& current_client_address,
+ const QuicSocketAddress& current_peer_address,
+ const QuicSocketAddress& current_self_address,
+ std::unique_ptr<QuicReceivedPacket> current_packet,
+ ParsedQuicVersion first_version,
+ PacketHeaderFormat current_packet_format);
+
+ // Examine the state of the rejector and decide what to do with the current
+ // packet.
+ void ProcessStatelessRejectorState(
+ std::unique_ptr<StatelessRejector> rejector,
+ QuicTransportVersion first_version,
+ PacketHeaderFormat form);
+
+ void set_new_sessions_allowed_per_event_loop(
+ int16_t new_sessions_allowed_per_event_loop) {
+ new_sessions_allowed_per_event_loop_ = new_sessions_allowed_per_event_loop;
+ }
+
+ const QuicConfig* config_;
+
+ const QuicCryptoServerConfig* crypto_config_;
+
+ // The cache for most recently compressed certs.
+ QuicCompressedCertsCache compressed_certs_cache_;
+
+ // The list of connections waiting to write.
+ WriteBlockedList write_blocked_list_;
+
+ SessionMap session_map_;
+
+ // Entity that manages connection_ids in time wait state.
+ std::unique_ptr<QuicTimeWaitListManager> time_wait_list_manager_;
+
+ // The list of closed but not-yet-deleted sessions.
+ std::vector<std::unique_ptr<QuicSession>> closed_session_list_;
+
+ // The helper used for all connections.
+ std::unique_ptr<QuicConnectionHelperInterface> helper_;
+
+ // The helper used for all sessions.
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper_;
+
+ // Creates alarms.
+ std::unique_ptr<QuicAlarmFactory> alarm_factory_;
+
+ // An alarm which deletes closed sessions.
+ std::unique_ptr<QuicAlarm> delete_sessions_alarm_;
+
+ // The writer to write to the socket with.
+ std::unique_ptr<QuicPacketWriter> writer_;
+
+ // Packets which are buffered until a connection can be created to handle
+ // them.
+ QuicBufferedPacketStore buffered_packets_;
+
+ // Set of connection IDs for which asynchronous CHLO processing is in
+ // progress, making it necessary to buffer any other packets which arrive on
+ // that connection until CHLO processing is complete.
+ QuicConnectionIdSet temporarily_buffered_connections_;
+
+ // Information about the packet currently being handled.
+
+ // Used for stateless rejector to generate and validate source address token.
+ QuicSocketAddress current_client_address_;
+ QuicSocketAddress current_peer_address_;
+ QuicSocketAddress current_self_address_;
+ const QuicReceivedPacket* current_packet_;
+ // If |current_packet_| is a CHLO packet, the extracted alpn.
+ QuicString current_alpn_;
+ QuicConnectionId current_connection_id_;
+
+ // Used to get the supported versions based on flag. Does not own.
+ QuicVersionManager* version_manager_;
+
+ QuicFramer framer_;
+
+ // The last error set by SetLastError(), which is called by
+ // framer_visitor_->OnError().
+ QuicErrorCode last_error_;
+
+ // A backward counter of how many new sessions can be create within current
+ // event loop. When reaches 0, it means can't create sessions for now.
+ int16_t new_sessions_allowed_per_event_loop_;
+
+ // True if this dispatcher is not draining.
+ bool accept_new_connections_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_CORE_QUIC_DISPATCHER_H_