xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/quic_time_wait_list_manager.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 // Handles packets for connection_ids in time wait state by discarding the
6 // packet and sending the peers termination packets with exponential backoff.
7 
8 #ifndef QUICHE_QUIC_CORE_QUIC_TIME_WAIT_LIST_MANAGER_H_
9 #define QUICHE_QUIC_CORE_QUIC_TIME_WAIT_LIST_MANAGER_H_
10 
11 #include <cstddef>
12 #include <memory>
13 
14 #include "absl/container/flat_hash_map.h"
15 #include "quiche/quic/core/quic_blocked_writer_interface.h"
16 #include "quiche/quic/core/quic_connection_id.h"
17 #include "quiche/quic/core/quic_framer.h"
18 #include "quiche/quic/core/quic_packet_writer.h"
19 #include "quiche/quic/core/quic_packets.h"
20 #include "quiche/quic/core/quic_session.h"
21 #include "quiche/quic/core/quic_types.h"
22 #include "quiche/quic/platform/api/quic_flags.h"
23 #include "quiche/common/quiche_linked_hash_map.h"
24 
25 namespace quic {
26 
27 namespace test {
28 class QuicDispatcherPeer;
29 class QuicTimeWaitListManagerPeer;
30 }  // namespace test
31 
32 // TimeWaitConnectionInfo comprises information of a connection which is in the
33 // time wait list.
34 struct QUICHE_EXPORT TimeWaitConnectionInfo {
35   TimeWaitConnectionInfo(
36       bool ietf_quic,
37       std::vector<std::unique_ptr<QuicEncryptedPacket>>* termination_packets,
38       std::vector<QuicConnectionId> active_connection_ids);
39   TimeWaitConnectionInfo(
40       bool ietf_quic,
41       std::vector<std::unique_ptr<QuicEncryptedPacket>>* termination_packets,
42       std::vector<QuicConnectionId> active_connection_ids,
43       QuicTime::Delta srtt);
44 
45   TimeWaitConnectionInfo(const TimeWaitConnectionInfo& other) = delete;
46   TimeWaitConnectionInfo(TimeWaitConnectionInfo&& other) = default;
47 
48   ~TimeWaitConnectionInfo() = default;
49 
50   bool ietf_quic;
51   std::vector<std::unique_ptr<QuicEncryptedPacket>> termination_packets;
52   std::vector<QuicConnectionId> active_connection_ids;
53   QuicTime::Delta srtt;
54 };
55 
56 // Maintains a list of all connection_ids that have been recently closed. A
57 // connection_id lives in this state for time_wait_period_. All packets received
58 // for connection_ids in this state are handed over to the
59 // QuicTimeWaitListManager by the QuicDispatcher.  Decides whether to send a
60 // public reset packet, a copy of the previously sent connection close packet,
61 // or nothing to the peer which sent a packet with the connection_id in time
62 // wait state.  After the connection_id expires its time wait period, a new
63 // connection/session will be created if a packet is received for this
64 // connection_id.
65 class QUICHE_EXPORT QuicTimeWaitListManager
66     : public QuicBlockedWriterInterface {
67  public:
68   // Specifies what the time wait list manager should do when processing packets
69   // of a time wait connection.
70   enum TimeWaitAction : uint8_t {
71     // Send specified termination packets, error if termination packet is
72     // unavailable.
73     SEND_TERMINATION_PACKETS,
74     // The same as SEND_TERMINATION_PACKETS except that the corresponding
75     // termination packets are provided by the connection.
76     SEND_CONNECTION_CLOSE_PACKETS,
77     // Send stateless reset (public reset for GQUIC).
78     SEND_STATELESS_RESET,
79 
80     DO_NOTHING,
81   };
82 
83   class QUICHE_EXPORT Visitor : public QuicSession::Visitor {
84    public:
85     // Called after the given connection is added to the time-wait list.
86     virtual void OnConnectionAddedToTimeWaitList(
87         QuicConnectionId connection_id) = 0;
88 
OnPathDegrading()89     void OnPathDegrading() override {}
90   };
91 
92   // writer - the entity that writes to the socket. (Owned by the caller)
93   // visitor - the entity that manages blocked writers. (Owned by the caller)
94   // clock - provide a clock (Owned by the caller)
95   // alarm_factory - used to run clean up alarms. (Owned by the caller)
96   QuicTimeWaitListManager(QuicPacketWriter* writer, Visitor* visitor,
97                           const QuicClock* clock,
98                           QuicAlarmFactory* alarm_factory);
99   QuicTimeWaitListManager(const QuicTimeWaitListManager&) = delete;
100   QuicTimeWaitListManager& operator=(const QuicTimeWaitListManager&) = delete;
101   ~QuicTimeWaitListManager() override;
102 
103   // Adds the connection IDs in info to time wait state for time_wait_period_.
104   // If |info|.termination_packets are provided, copies of these packets will be
105   // sent when a packet with one of these connection IDs is processed. Any
106   // termination packets will be move from |info|.termination_packets and will
107   // become owned by the manager. |action| specifies what the time wait list
108   // manager should do when processing packets of the connection.
109   virtual void AddConnectionIdToTimeWait(TimeWaitAction action,
110                                          TimeWaitConnectionInfo info);
111 
112   // Returns true if the connection_id is in time wait state, false otherwise.
113   // Packets received for this connection_id should not lead to creation of new
114   // QuicSessions.
115   bool IsConnectionIdInTimeWait(QuicConnectionId connection_id) const;
116 
117   // Called when a packet is received for a connection_id that is in time wait
118   // state. Sends a public reset packet to the peer which sent this
119   // connection_id. Sending of the public reset packet is throttled by using
120   // exponential back off. QUICHE_DCHECKs for the connection_id to be in time
121   // wait state. virtual to override in tests.
122   // TODO(fayang): change ProcessPacket and SendPublicReset to take
123   // ReceivedPacketInfo.
124   virtual void ProcessPacket(
125       const QuicSocketAddress& self_address,
126       const QuicSocketAddress& peer_address, QuicConnectionId connection_id,
127       PacketHeaderFormat header_format, size_t received_packet_length,
128       std::unique_ptr<QuicPerPacketContext> packet_context);
129 
130   // Called by the dispatcher when the underlying socket becomes writable again,
131   // since we might need to send pending public reset packets which we didn't
132   // send because the underlying socket was write blocked.
133   void OnBlockedWriterCanWrite() override;
134 
IsWriterBlocked()135   bool IsWriterBlocked() const override {
136     return writer_ != nullptr && writer_->IsWriteBlocked();
137   }
138 
139   // Used to delete connection_id entries that have outlived their time wait
140   // period.
141   void CleanUpOldConnectionIds();
142 
143   // If necessary, trims the oldest connections from the time-wait list until
144   // the size is under the configured maximum.
145   void TrimTimeWaitListIfNeeded();
146 
147   // The number of connections on the time-wait list.
num_connections()148   size_t num_connections() const { return connection_id_map_.size(); }
149 
150   // Sends a version negotiation packet for |server_connection_id| and
151   // |client_connection_id| announcing support for |supported_versions| to
152   // |peer_address| from |self_address|.
153   virtual void SendVersionNegotiationPacket(
154       QuicConnectionId server_connection_id,
155       QuicConnectionId client_connection_id, bool ietf_quic,
156       bool use_length_prefix, const ParsedQuicVersionVector& supported_versions,
157       const QuicSocketAddress& self_address,
158       const QuicSocketAddress& peer_address,
159       std::unique_ptr<QuicPerPacketContext> packet_context);
160 
161   // Creates a public reset packet and sends it or queues it to be sent later.
162   virtual void SendPublicReset(
163       const QuicSocketAddress& self_address,
164       const QuicSocketAddress& peer_address, QuicConnectionId connection_id,
165       bool ietf_quic, size_t received_packet_length,
166       std::unique_ptr<QuicPerPacketContext> packet_context);
167 
168   // Called to send |packet|.
169   virtual void SendPacket(const QuicSocketAddress& self_address,
170                           const QuicSocketAddress& peer_address,
171                           const QuicEncryptedPacket& packet);
172 
173   // Return a non-owning pointer to the packet writer.
writer()174   QuicPacketWriter* writer() { return writer_; }
175 
176  protected:
177   virtual std::unique_ptr<QuicEncryptedPacket> BuildPublicReset(
178       const QuicPublicResetPacket& packet);
179 
GetEndpointId(std::string *)180   virtual void GetEndpointId(std::string* /*endpoint_id*/) {}
181 
182   // Returns a stateless reset token which will be included in the public reset
183   // packet.
184   virtual StatelessResetToken GetStatelessResetToken(
185       QuicConnectionId connection_id) const;
186 
187   // Internal structure to store pending termination packets.
188   class QUICHE_EXPORT QueuedPacket {
189    public:
QueuedPacket(const QuicSocketAddress & self_address,const QuicSocketAddress & peer_address,std::unique_ptr<QuicEncryptedPacket> packet)190     QueuedPacket(const QuicSocketAddress& self_address,
191                  const QuicSocketAddress& peer_address,
192                  std::unique_ptr<QuicEncryptedPacket> packet)
193         : self_address_(self_address),
194           peer_address_(peer_address),
195           packet_(std::move(packet)) {}
196     QueuedPacket(const QueuedPacket&) = delete;
197     QueuedPacket& operator=(const QueuedPacket&) = delete;
198 
self_address()199     const QuicSocketAddress& self_address() const { return self_address_; }
peer_address()200     const QuicSocketAddress& peer_address() const { return peer_address_; }
packet()201     QuicEncryptedPacket* packet() { return packet_.get(); }
202 
203    private:
204     // Server address on which a packet was received for a connection_id in
205     // time wait state.
206     const QuicSocketAddress self_address_;
207     // Address of the peer to send this packet to.
208     const QuicSocketAddress peer_address_;
209     // The pending termination packet that is to be sent to the peer.
210     std::unique_ptr<QuicEncryptedPacket> packet_;
211   };
212 
213   // Called right after |packet| is serialized. Either sends the packet and
214   // deletes it or makes pending_packets_queue_ the owner of the packet.
215   // Subclasses overriding this method should call this class's base
216   // implementation at the end of the override.
217   // Return true if |packet| is sent, false if it is queued.
218   virtual bool SendOrQueuePacket(std::unique_ptr<QueuedPacket> packet,
219                                  const QuicPerPacketContext* packet_context);
220 
221   const quiche::QuicheCircularDeque<std::unique_ptr<QueuedPacket>>&
pending_packets_queue()222   pending_packets_queue() const {
223     return pending_packets_queue_;
224   }
225 
226  private:
227   friend class test::QuicDispatcherPeer;
228   friend class test::QuicTimeWaitListManagerPeer;
229 
230   // Decides if a packet should be sent for this connection_id based on the
231   // number of received packets.
232   bool ShouldSendResponse(int received_packet_count);
233 
234   // Sends the packet out. Returns true if the packet was successfully consumed.
235   // If the writer got blocked and did not buffer the packet, we'll need to keep
236   // the packet and retry sending. In case of all other errors we drop the
237   // packet.
238   bool WriteToWire(QueuedPacket* packet);
239 
240   // Register the alarm server to wake up at appropriate time.
241   void SetConnectionIdCleanUpAlarm();
242 
243   // Removes the oldest connection from the time-wait list if it was added prior
244   // to "expiration_time".  To unconditionally remove the oldest connection, use
245   // a QuicTime::Delta:Infinity().  This function modifies the
246   // connection_id_map_.  If you plan to call this function in a loop, any
247   // iterators that you hold before the call to this function may be invalid
248   // afterward.  Returns true if the oldest connection was expired.  Returns
249   // false if the map is empty or the oldest connection has not expired.
250   bool MaybeExpireOldestConnection(QuicTime expiration_time);
251 
252   // Called when a packet is received for a connection in this time wait list.
OnPacketReceivedForKnownConnection(int,QuicTime::Delta,QuicTime::Delta)253   virtual void OnPacketReceivedForKnownConnection(
254       int /*num_packets*/, QuicTime::Delta /*delta*/,
255       QuicTime::Delta /*srtt*/) const {}
256 
257   std::unique_ptr<QuicEncryptedPacket> BuildIetfStatelessResetPacket(
258       QuicConnectionId connection_id, size_t received_packet_length);
259 
260   // A map from a recently closed connection_id to the number of packets
261   // received after the termination of the connection bound to the
262   // connection_id.
263   struct QUICHE_EXPORT ConnectionIdData {
264     ConnectionIdData(int num_packets, QuicTime time_added,
265                      TimeWaitAction action, TimeWaitConnectionInfo info);
266 
267     ConnectionIdData(const ConnectionIdData& other) = delete;
268     ConnectionIdData(ConnectionIdData&& other);
269 
270     ~ConnectionIdData();
271 
272     int num_packets;
273     QuicTime time_added;
274     TimeWaitAction action;
275     TimeWaitConnectionInfo info;
276   };
277 
278   // QuicheLinkedHashMap allows lookup by ConnectionId
279   // and traversal in add order.
280   using ConnectionIdMap =
281       quiche::QuicheLinkedHashMap<QuicConnectionId, ConnectionIdData,
282                                   QuicConnectionIdHash>;
283   // Do not use find/emplace/erase on this map directly. Use
284   // FindConnectionIdDataInMap, AddConnectionIdDateToMap,
285   // RemoveConnectionDataFromMap instead.
286   ConnectionIdMap connection_id_map_;
287 
288   // TODO(haoyuewang) Consider making connection_id_map_ a map of shared pointer
289   // and remove the indirect map.
290   // A connection can have multiple unretired ConnectionIds when it is closed.
291   // These Ids have the same ConnectionIdData entry in connection_id_map_. To
292   // find the entry, look up the cannoical ConnectionId in
293   // indirect_connection_id_map_ first, and look up connection_id_map_ with the
294   // cannoical ConnectionId.
295   absl::flat_hash_map<QuicConnectionId, QuicConnectionId, QuicConnectionIdHash>
296       indirect_connection_id_map_;
297 
298   // Find an iterator for the given connection_id. Returns
299   // connection_id_map_.end() if none found.
300   ConnectionIdMap::iterator FindConnectionIdDataInMap(
301       const QuicConnectionId& connection_id);
302   // Inserts a ConnectionIdData entry to connection_id_map_.
303   void AddConnectionIdDataToMap(const QuicConnectionId& canonical_connection_id,
304                                 int num_packets, TimeWaitAction action,
305                                 TimeWaitConnectionInfo info);
306   // Removes a ConnectionIdData entry in connection_id_map_.
307   void RemoveConnectionDataFromMap(ConnectionIdMap::iterator it);
308 
309   // Pending termination packets that need to be sent out to the peer when we
310   // are given a chance to write by the dispatcher.
311   quiche::QuicheCircularDeque<std::unique_ptr<QueuedPacket>>
312       pending_packets_queue_;
313 
314   // Time period for which connection_ids should remain in time wait state.
315   const QuicTime::Delta time_wait_period_;
316 
317   // Alarm to clean up connection_ids that have out lived their duration in
318   // time wait state.
319   std::unique_ptr<QuicAlarm> connection_id_clean_up_alarm_;
320 
321   // Clock to efficiently measure approximate time.
322   const QuicClock* clock_;
323 
324   // Interface that writes given buffer to the socket.
325   QuicPacketWriter* writer_;
326 
327   // Interface that manages blocked writers.
328   Visitor* visitor_;
329 };
330 
331 }  // namespace quic
332 
333 #endif  // QUICHE_QUIC_CORE_QUIC_TIME_WAIT_LIST_MANAGER_H_
334