xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/quic_dispatcher.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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