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