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