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