• 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 <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