• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
163 
164   // Create connections for previously buffered CHLOs as many as allowed.
165   virtual void ProcessBufferedChlos(size_t max_connections_to_create);
166 
167   // Return true if there is CHLO buffered.
168   virtual bool HasChlosBuffered() const;
169 
170   // Start accepting new ConnectionIds.
171   void StartAcceptingNewConnections();
172 
173   // Stop accepting new ConnectionIds, either as a part of the lame
174   // duck process or because explicitly configured.
175   void StopAcceptingNewConnections();
176 
177   // Apply an operation for each session.
178   void PerformActionOnActiveSessions(
179       quiche::UnretainedCallback<void(QuicSession*)> operation) const;
180 
181   // Get a snapshot of all sessions.
182   std::vector<std::shared_ptr<QuicSession>> GetSessionsSnapshot() const;
183 
accept_new_connections()184   bool accept_new_connections() const { return accept_new_connections_; }
185 
num_packets_received()186   uint64_t num_packets_received() const { return num_packets_received_; }
187 
188  protected:
189   // Creates a QUIC session based on the given information.
190   // |alpn| is the selected ALPN from |parsed_chlo.alpns|.
191   virtual std::unique_ptr<QuicSession> CreateQuicSession(
192       QuicConnectionId server_connection_id,
193       const QuicSocketAddress& self_address,
194       const QuicSocketAddress& peer_address, absl::string_view alpn,
195       const ParsedQuicVersion& version, const ParsedClientHello& parsed_chlo,
196       ConnectionIdGeneratorInterface& connection_id_generator) = 0;
197 
198   // Tries to validate and dispatch packet based on available information.
199   // Returns true if packet is dropped or successfully dispatched (e.g.,
200   // processed by existing session, processed by time wait list, etc.),
201   // otherwise, returns false and the packet needs further processing.
202   virtual bool MaybeDispatchPacket(const ReceivedPacketInfo& packet_info);
203 
204   // Values to be returned by ValidityChecks() to indicate what should be done
205   // with a packet. Fates with greater values are considered to be higher
206   // priority. ValidityChecks should return fate based on the priority order
207   // (i.e., returns higher priority fate first)
208   enum QuicPacketFate {
209     // Process the packet normally, which is usually to establish a connection.
210     kFateProcess,
211     // Put the connection ID into time-wait state and send a public reset.
212     kFateTimeWait,
213     // Drop the packet.
214     kFateDrop,
215   };
216 
217   // This method is called by ProcessHeader on packets not associated with a
218   // known connection ID.  It applies validity checks and returns a
219   // QuicPacketFate to tell what should be done with the packet.
220   // TODO(fayang): Merge ValidityChecks into MaybeDispatchPacket.
221   virtual QuicPacketFate ValidityChecks(const ReceivedPacketInfo& packet_info);
222 
223   // Extra validity checks after the full Client Hello is parsed, this allows
224   // subclasses to reject a connection based on sni or alpn.
225   // Only called if ValidityChecks returns kFateProcess.
ValidityChecksOnFullChlo(const ReceivedPacketInfo &,const ParsedClientHello &)226   virtual QuicPacketFate ValidityChecksOnFullChlo(
227       const ReceivedPacketInfo& /*packet_info*/,
228       const ParsedClientHello& /*parsed_chlo*/) const {
229     return kFateProcess;
230   }
231 
232   // Create and return the time wait list manager for this dispatcher, which
233   // will be owned by the dispatcher as time_wait_list_manager_
234   virtual QuicTimeWaitListManager* CreateQuicTimeWaitListManager();
235 
236   // Buffers packet until it can be delivered to a connection.
237   void BufferEarlyPacket(const ReceivedPacketInfo& packet_info);
238 
239   // Called when |packet_info| is the last received packet of the client hello.
240   // |parsed_chlo| is the parsed version of the client hello. Creates a new
241   // connection and delivers any buffered packets for that connection id.
242   void ProcessChlo(ParsedClientHello parsed_chlo,
243                    ReceivedPacketInfo* packet_info);
244 
time_wait_list_manager()245   QuicTimeWaitListManager* time_wait_list_manager() {
246     return time_wait_list_manager_.get();
247   }
248 
249   const ParsedQuicVersionVector& GetSupportedVersions();
250 
config()251   const QuicConfig& config() const { return *config_; }
252 
crypto_config()253   const QuicCryptoServerConfig* crypto_config() const { return crypto_config_; }
254 
compressed_certs_cache()255   QuicCompressedCertsCache* compressed_certs_cache() {
256     return &compressed_certs_cache_;
257   }
258 
helper()259   QuicConnectionHelperInterface* helper() { return helper_.get(); }
260 
session_helper()261   QuicCryptoServerStreamBase::Helper* session_helper() {
262     return session_helper_.get();
263   }
264 
session_helper()265   const QuicCryptoServerStreamBase::Helper* session_helper() const {
266     return session_helper_.get();
267   }
268 
alarm_factory()269   QuicAlarmFactory* alarm_factory() { return alarm_factory_.get(); }
270 
writer()271   QuicPacketWriter* writer() { return writer_.get(); }
272 
273   // Returns true if a session should be created for a connection with an
274   // unknown version.
275   virtual bool ShouldCreateSessionForUnknownVersion(
276       const ReceivedPacketInfo& packet_info);
277 
278   void SetLastError(QuicErrorCode error);
279 
280   // Called by MaybeDispatchPacket when current packet cannot be dispatched.
281   // Used by subclasses to conduct specific logic to dispatch packet. Returns
282   // true if packet is successfully dispatched.
283   virtual bool OnFailedToDispatchPacket(const ReceivedPacketInfo& packet_info);
284 
285   bool HasBufferedPackets(QuicConnectionId server_connection_id);
286 
287   // Called when BufferEarlyPacket() fail to buffer the packet.
288   virtual void OnBufferPacketFailure(
289       QuicBufferedPacketStore::EnqueuePacketResult result,
290       QuicConnectionId server_connection_id);
291 
292   // Removes the session from the write blocked list, and adds the ConnectionId
293   // to the time-wait list.  The caller needs to manually remove the session
294   // from the map after that.
295   void CleanUpSession(QuicConnectionId server_connection_id,
296                       QuicConnection* connection, QuicErrorCode error,
297                       const std::string& error_details,
298                       ConnectionCloseSource source);
299 
300   // Called to terminate a connection statelessly. Depending on |format|, either
301   // 1) send connection close with |error_code| and |error_details| and add
302   // connection to time wait list or 2) directly add connection to time wait
303   // list with |action|.
304   // |self_address| and |peer_address| are passed to
305   // |OnStatelessConnectionCloseSent| when a connection close is sent.
306   void StatelesslyTerminateConnection(
307       const QuicSocketAddress& self_address,
308       const QuicSocketAddress& peer_address,
309       QuicConnectionId server_connection_id, PacketHeaderFormat format,
310       bool version_flag, bool use_length_prefix, ParsedQuicVersion version,
311       QuicErrorCode error_code, const std::string& error_details,
312       QuicTimeWaitListManager::TimeWaitAction action);
313 
314   // Save/Restore per packet context.
315   virtual std::unique_ptr<QuicPerPacketContext> GetPerPacketContext() const;
RestorePerPacketContext(std::unique_ptr<QuicPerPacketContext>)316   virtual void RestorePerPacketContext(
317       std::unique_ptr<QuicPerPacketContext> /*context*/) {}
318 
319   // If true, our framer will change its expected connection ID length
320   // to the received destination connection ID length of all IETF long headers.
SetShouldUpdateExpectedServerConnectionIdLength(bool should_update_expected_server_connection_id_length)321   void SetShouldUpdateExpectedServerConnectionIdLength(
322       bool should_update_expected_server_connection_id_length) {
323     should_update_expected_server_connection_id_length_ =
324         should_update_expected_server_connection_id_length;
325   }
326 
327   // If true, the dispatcher will allow incoming initial packets that have
328   // destination connection IDs shorter than 64 bits.
SetAllowShortInitialServerConnectionIds(bool allow_short_initial_server_connection_ids)329   void SetAllowShortInitialServerConnectionIds(
330       bool allow_short_initial_server_connection_ids) {
331     allow_short_initial_server_connection_ids_ =
332         allow_short_initial_server_connection_ids;
333   }
334 
335   // Called if a packet from an unseen connection is reset or rejected.
OnNewConnectionRejected()336   virtual void OnNewConnectionRejected() {}
337 
338   // Called by |StatelesslyTerminateConnection| when a connection close packet
339   // is generated.
OnStatelessConnectionCloseGenerated(const QuicSocketAddress &,const QuicSocketAddress &,QuicConnectionId,ParsedQuicVersion,QuicErrorCode,const std::string &)340   virtual void OnStatelessConnectionCloseGenerated(
341       const QuicSocketAddress& /*self_address*/,
342       const QuicSocketAddress& /*peer_address*/,
343       QuicConnectionId /*connection_id*/, ParsedQuicVersion /*version*/,
344       QuicErrorCode /*error_code*/, const std::string& /*error_details*/) {}
345 
346   // Selects the preferred ALPN from a vector of ALPNs.
347   // This runs through the list of ALPNs provided by the client and picks the
348   // first one it supports. If no supported versions are found, the first
349   // element of the vector is returned.
350   std::string SelectAlpn(const std::vector<std::string>& alpns);
351 
352   // Sends public/stateless reset packets with no version and unknown
353   // connection ID according to the packet's size.
354   virtual void MaybeResetPacketsWithNoVersion(
355       const quic::ReceivedPacketInfo& packet_info);
356 
357   // Called on packets with unsupported versions.
358   virtual void MaybeSendVersionNegotiationPacket(
359       const ReceivedPacketInfo& packet_info);
360 
ConnectionIdGenerator()361   virtual ConnectionIdGeneratorInterface& ConnectionIdGenerator() {
362     return connection_id_generator_;
363   }
364 
365  private:
366   friend class test::QuicDispatcherPeer;
367 
368   // TODO(fayang): Consider to rename this function to
369   // ProcessValidatedPacketWithUnknownConnectionId.
370   void ProcessHeader(ReceivedPacketInfo* packet_info);
371 
372   struct ExtractChloResult {
373     // If set, a full client hello has been successfully parsed.
374     std::optional<ParsedClientHello> parsed_chlo;
375     // If set, the TLS alert that will cause a connection close.
376     // Always empty for Google QUIC.
377     std::optional<uint8_t> tls_alert;
378   };
379 
380   // Try to extract information(sni, alpns, ...) if the full Client Hello has
381   // been parsed.
382   //
383   // Returns the parsed client hello in ExtractChloResult.parsed_chlo, if the
384   // full Client Hello has been successfully parsed.
385   //
386   // Returns the TLS alert in ExtractChloResult.tls_alert, if the extraction of
387   // Client Hello failed due to that alert.
388   //
389   // Otherwise returns a default-constructed ExtractChloResult and either buffer
390   // or (rarely) drop the packet.
391   ExtractChloResult TryExtractChloOrBufferEarlyPacket(
392       const ReceivedPacketInfo& packet_info);
393 
394   // Deliver |packets| to |session| for further processing.
395   void DeliverPacketsToSession(
396       const std::list<QuicBufferedPacketStore::BufferedPacket>& packets,
397       QuicSession* session);
398 
399   // Returns true if |version| is a supported protocol version.
400   bool IsSupportedVersion(const ParsedQuicVersion version);
401 
402   // Returns true if a server connection ID length is below all the minima
403   // required by various parameters.
404   bool IsServerConnectionIdTooShort(QuicConnectionId connection_id) const;
405 
406   // Core CHLO processing logic.
407   std::shared_ptr<QuicSession> CreateSessionFromChlo(
408       QuicConnectionId original_connection_id,
409       const ParsedClientHello& parsed_chlo, ParsedQuicVersion version,
410       QuicSocketAddress self_address, QuicSocketAddress peer_address,
411       ConnectionIdGeneratorInterface* connection_id_generator);
412 
413   const QuicConfig* config_;
414 
415   const QuicCryptoServerConfig* crypto_config_;
416 
417   // The cache for most recently compressed certs.
418   QuicCompressedCertsCache compressed_certs_cache_;
419 
420   // The list of connections waiting to write.
421   WriteBlockedList write_blocked_list_;
422 
423   ReferenceCountedSessionMap reference_counted_session_map_;
424 
425   // Entity that manages connection_ids in time wait state.
426   std::unique_ptr<QuicTimeWaitListManager> time_wait_list_manager_;
427 
428   // The list of closed but not-yet-deleted sessions.
429   std::vector<std::shared_ptr<QuicSession>> closed_session_list_;
430 
431   // The helper used for all connections.
432   std::unique_ptr<QuicConnectionHelperInterface> helper_;
433 
434   // The helper used for all sessions.
435   std::unique_ptr<QuicCryptoServerStreamBase::Helper> session_helper_;
436 
437   // Creates alarms.
438   std::unique_ptr<QuicAlarmFactory> alarm_factory_;
439 
440   // An alarm which deletes closed sessions.
441   std::unique_ptr<QuicAlarm> delete_sessions_alarm_;
442 
443   // The writer to write to the socket with.
444   std::unique_ptr<QuicPacketWriter> writer_;
445 
446   // Packets which are buffered until a connection can be created to handle
447   // them.
448   QuicBufferedPacketStore buffered_packets_;
449 
450   // Used to get the supported versions based on flag. Does not own.
451   QuicVersionManager* version_manager_;
452 
453   // The last error set by SetLastError().
454   // TODO(fayang): consider removing last_error_.
455   QuicErrorCode last_error_;
456 
457   // Number of unique session in session map.
458   size_t num_sessions_in_session_map_ = 0;
459 
460   // Total number of packets received.
461   uint64_t num_packets_received_ = 0;
462 
463   // A backward counter of how many new sessions can be create within current
464   // event loop. When reaches 0, it means can't create sessions for now.
465   int16_t new_sessions_allowed_per_event_loop_;
466 
467   // True if this dispatcher is accepting new ConnectionIds (new client
468   // connections), false otherwise.
469   bool accept_new_connections_;
470 
471   // If false, the dispatcher follows the IETF spec and rejects packets with
472   // invalid destination connection IDs lengths below 64 bits.
473   // If true they are allowed.
474   bool allow_short_initial_server_connection_ids_;
475 
476   // IETF short headers contain a destination connection ID but do not
477   // encode its length. This variable contains the length we expect to read.
478   // This is also used to signal an error when a long header packet with
479   // different destination connection ID length is received when
480   // should_update_expected_server_connection_id_length_ is false and packet's
481   // version does not allow variable length connection ID.
482   uint8_t expected_server_connection_id_length_;
483 
484   // Records client addresses that have been recently reset.
485   absl::flat_hash_set<QuicSocketAddress, QuicSocketAddressHash>
486       recent_stateless_reset_addresses_;
487 
488   // An alarm which clear recent_stateless_reset_addresses_.
489   std::unique_ptr<QuicAlarm> clear_stateless_reset_addresses_alarm_;
490 
491   // If true, change expected_server_connection_id_length_ to be the received
492   // destination connection ID length of all IETF long headers.
493   bool should_update_expected_server_connection_id_length_;
494 
495   ConnectionIdGeneratorInterface& connection_id_generator_;
496 };
497 
498 }  // namespace quic
499 
500 #endif  // QUICHE_QUIC_CORE_QUIC_DISPATCHER_H_
501