| OLD | NEW |
| 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/quic/core/quic_buffered_packet_store.h" | 5 #include "net/quic/core/quic_buffered_packet_store.h" |
| 6 | 6 |
| 7 #include <list> | 7 #include <list> |
| 8 | 8 |
| 9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
| 10 #include "net/quic/core/quic_bug_tracker.h" |
| 10 | 11 |
| 11 using std::list; | 12 using std::list; |
| 12 | 13 |
| 13 namespace net { | 14 namespace net { |
| 14 | 15 |
| 15 typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket; | 16 typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket; |
| 16 typedef QuicBufferedPacketStore::EnqueuePacketResult EnqueuePacketResult; | 17 typedef QuicBufferedPacketStore::EnqueuePacketResult EnqueuePacketResult; |
| 17 typedef QuicBufferedPacketStore::BufferedPacketList BufferedPacketList; | 18 typedef QuicBufferedPacketStore::BufferedPacketList BufferedPacketList; |
| 18 | 19 |
| 19 // Max number of connections this store can keep track. | 20 // Max number of connections this store can keep track. |
| 20 static const size_t kDefaultMaxConnectionsInStore = 100; | 21 static const size_t kDefaultMaxConnectionsInStore = 100; |
| 22 // Up to half of the capacity can be used for storing non-CHLO packets. |
| 23 static const size_t kMaxConnectionsWithoutCHLO = |
| 24 kDefaultMaxConnectionsInStore / 2; |
| 21 | 25 |
| 22 namespace { | 26 namespace { |
| 23 | 27 |
| 24 // This alarm removes expired entries in map each time this alarm fires. | 28 // This alarm removes expired entries in map each time this alarm fires. |
| 25 class ConnectionExpireAlarm : public QuicAlarm::Delegate { | 29 class ConnectionExpireAlarm : public QuicAlarm::Delegate { |
| 26 public: | 30 public: |
| 27 explicit ConnectionExpireAlarm(QuicBufferedPacketStore* store) | 31 explicit ConnectionExpireAlarm(QuicBufferedPacketStore* store) |
| 28 : connection_store_(store) {} | 32 : connection_store_(store) {} |
| 29 | 33 |
| 30 void OnAlarm() override { connection_store_->OnExpirationTimeout(); } | 34 void OnAlarm() override { connection_store_->OnExpirationTimeout(); } |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 clock_(clock), | 75 clock_(clock), |
| 72 expiration_alarm_( | 76 expiration_alarm_( |
| 73 alarm_factory->CreateAlarm(new ConnectionExpireAlarm(this))) {} | 77 alarm_factory->CreateAlarm(new ConnectionExpireAlarm(this))) {} |
| 74 | 78 |
| 75 QuicBufferedPacketStore::~QuicBufferedPacketStore() {} | 79 QuicBufferedPacketStore::~QuicBufferedPacketStore() {} |
| 76 | 80 |
| 77 EnqueuePacketResult QuicBufferedPacketStore::EnqueuePacket( | 81 EnqueuePacketResult QuicBufferedPacketStore::EnqueuePacket( |
| 78 QuicConnectionId connection_id, | 82 QuicConnectionId connection_id, |
| 79 const QuicReceivedPacket& packet, | 83 const QuicReceivedPacket& packet, |
| 80 IPEndPoint server_address, | 84 IPEndPoint server_address, |
| 81 IPEndPoint client_address) { | 85 IPEndPoint client_address, |
| 82 if (!base::ContainsKey(undecryptable_packets_, connection_id) && IsFull()) { | 86 bool is_chlo) { |
| 83 // Drop the packet if store can't keep track of more connections. | 87 QUIC_BUG_IF(is_chlo && |
| 88 base::ContainsKey(connections_with_chlo_, connection_id)) |
| 89 << "Shouldn't buffer duplicated CHLO on connection " << connection_id; |
| 90 |
| 91 if (!base::ContainsKey(undecryptable_packets_, connection_id) && |
| 92 ShouldBufferPacket(is_chlo)) { |
| 93 // Drop the packet if the upper limit of undecryptable packets has been |
| 94 // reached or the whole capacity of the store has been reached. |
| 84 return TOO_MANY_CONNECTIONS; | 95 return TOO_MANY_CONNECTIONS; |
| 85 } else if (!base::ContainsKey(undecryptable_packets_, connection_id)) { | 96 } else if (!base::ContainsKey(undecryptable_packets_, connection_id)) { |
| 86 undecryptable_packets_.emplace( | 97 undecryptable_packets_.emplace( |
| 87 std::make_pair(connection_id, BufferedPacketList())); | 98 std::make_pair(connection_id, BufferedPacketList())); |
| 88 } | 99 } |
| 89 CHECK(base::ContainsKey(undecryptable_packets_, connection_id)); | 100 CHECK(base::ContainsKey(undecryptable_packets_, connection_id)); |
| 90 BufferedPacketList& queue = | 101 BufferedPacketList& queue = |
| 91 undecryptable_packets_.find(connection_id)->second; | 102 undecryptable_packets_.find(connection_id)->second; |
| 92 | 103 |
| 93 if (queue.buffered_packets.size() >= kDefaultMaxUndecryptablePackets) { | 104 if (!is_chlo) { |
| 94 // If there are kMaxBufferedPacketsPerConnection packets buffered up for | 105 // If current packet is not CHLO, it might not be buffered because store |
| 95 // this connection, drop the current packet. | 106 // only buffers certain number of undecryptable packets per connection. |
| 96 return TOO_MANY_PACKETS; | 107 size_t num_non_chlo_packets = |
| 108 base::ContainsKey(connections_with_chlo_, connection_id) |
| 109 ? (queue.buffered_packets.size() - 1) |
| 110 : queue.buffered_packets.size(); |
| 111 if (num_non_chlo_packets >= kDefaultMaxUndecryptablePackets) { |
| 112 // If there are kMaxBufferedPacketsPerConnection packets buffered up for |
| 113 // this connection, drop the current packet. |
| 114 return TOO_MANY_PACKETS; |
| 115 } |
| 97 } | 116 } |
| 98 | 117 |
| 99 if (queue.buffered_packets.empty()) { | 118 if (queue.buffered_packets.empty()) { |
| 100 // If this is the first packet arrived on a new connection, initialize the | 119 // If this is the first packet arrived on a new connection, initialize the |
| 101 // creation time. | 120 // creation time. |
| 102 queue.creation_time = clock_->ApproximateNow(); | 121 queue.creation_time = clock_->ApproximateNow(); |
| 103 } | 122 } |
| 104 | 123 |
| 105 BufferedPacket new_entry(std::unique_ptr<QuicReceivedPacket>(packet.Clone()), | 124 BufferedPacket new_entry(std::unique_ptr<QuicReceivedPacket>(packet.Clone()), |
| 106 server_address, client_address); | 125 server_address, client_address); |
| 107 | 126 if (is_chlo) { |
| 108 queue.buffered_packets.push_back(std::move(new_entry)); | 127 // Add CHLO to the beginning of buffered packets so that it can be delivered |
| 109 | 128 // first later. |
| 129 queue.buffered_packets.push_front(std::move(new_entry)); |
| 130 connections_with_chlo_[connection_id] = false; // Dummy value. |
| 131 } else { |
| 132 // Buffer non-CHLO packets in arrival order. |
| 133 queue.buffered_packets.push_back(std::move(new_entry)); |
| 134 } |
| 110 MaybeSetExpirationAlarm(); | 135 MaybeSetExpirationAlarm(); |
| 111 return SUCCESS; | 136 return SUCCESS; |
| 112 } | 137 } |
| 113 | 138 |
| 114 bool QuicBufferedPacketStore::HasBufferedPackets( | 139 bool QuicBufferedPacketStore::HasBufferedPackets( |
| 115 QuicConnectionId connection_id) const { | 140 QuicConnectionId connection_id) const { |
| 116 return base::ContainsKey(undecryptable_packets_, connection_id); | 141 return base::ContainsKey(undecryptable_packets_, connection_id); |
| 117 } | 142 } |
| 118 | 143 |
| 144 bool QuicBufferedPacketStore::HasChlosBuffered() const { |
| 145 return !connections_with_chlo_.empty(); |
| 146 } |
| 147 |
| 119 list<BufferedPacket> QuicBufferedPacketStore::DeliverPackets( | 148 list<BufferedPacket> QuicBufferedPacketStore::DeliverPackets( |
| 120 QuicConnectionId connection_id) { | 149 QuicConnectionId connection_id) { |
| 121 list<BufferedPacket> packets_to_deliver; | 150 list<BufferedPacket> packets_to_deliver; |
| 122 auto it = undecryptable_packets_.find(connection_id); | 151 auto it = undecryptable_packets_.find(connection_id); |
| 123 if (it != undecryptable_packets_.end()) { | 152 if (it != undecryptable_packets_.end()) { |
| 124 packets_to_deliver = std::move(it->second.buffered_packets); | 153 packets_to_deliver = std::move(it->second.buffered_packets); |
| 125 undecryptable_packets_.erase(connection_id); | 154 undecryptable_packets_.erase(connection_id); |
| 126 } | 155 } |
| 127 return packets_to_deliver; | 156 return packets_to_deliver; |
| 128 } | 157 } |
| 129 | 158 |
| 130 void QuicBufferedPacketStore::OnExpirationTimeout() { | 159 void QuicBufferedPacketStore::OnExpirationTimeout() { |
| 131 QuicTime expiration_time = clock_->ApproximateNow() - connection_life_span_; | 160 QuicTime expiration_time = clock_->ApproximateNow() - connection_life_span_; |
| 132 while (!undecryptable_packets_.empty()) { | 161 while (!undecryptable_packets_.empty()) { |
| 133 auto& entry = undecryptable_packets_.front(); | 162 auto& entry = undecryptable_packets_.front(); |
| 134 if (entry.second.creation_time > expiration_time) { | 163 if (entry.second.creation_time > expiration_time) { |
| 135 break; | 164 break; |
| 136 } | 165 } |
| 137 visitor_->OnExpiredPackets(entry.first, std::move(entry.second)); | 166 QuicConnectionId connection_id = entry.first; |
| 167 visitor_->OnExpiredPackets(connection_id, std::move(entry.second)); |
| 138 undecryptable_packets_.erase(undecryptable_packets_.begin()); | 168 undecryptable_packets_.erase(undecryptable_packets_.begin()); |
| 169 connections_with_chlo_.erase(connection_id); |
| 139 } | 170 } |
| 140 if (!undecryptable_packets_.empty()) { | 171 if (!undecryptable_packets_.empty()) { |
| 141 expiration_alarm_->Set(clock_->ApproximateNow() + connection_life_span_); | 172 expiration_alarm_->Set(clock_->ApproximateNow() + connection_life_span_); |
| 142 } | 173 } |
| 143 } | 174 } |
| 144 | 175 |
| 145 void QuicBufferedPacketStore::MaybeSetExpirationAlarm() { | 176 void QuicBufferedPacketStore::MaybeSetExpirationAlarm() { |
| 146 if (!expiration_alarm_->IsSet()) { | 177 if (!expiration_alarm_->IsSet()) { |
| 147 expiration_alarm_->Set(clock_->ApproximateNow() + connection_life_span_); | 178 expiration_alarm_->Set(clock_->ApproximateNow() + connection_life_span_); |
| 148 } | 179 } |
| 149 } | 180 } |
| 150 | 181 |
| 151 bool QuicBufferedPacketStore::IsFull() { | 182 bool QuicBufferedPacketStore::ShouldBufferPacket(bool is_chlo) { |
| 152 return undecryptable_packets_.size() >= kDefaultMaxConnectionsInStore; | 183 bool is_store_full = |
| 184 undecryptable_packets_.size() >= kDefaultMaxConnectionsInStore; |
| 185 |
| 186 if (is_chlo) { |
| 187 return is_store_full; |
| 188 } |
| 189 |
| 190 size_t num_connections_without_chlo = |
| 191 undecryptable_packets_.size() - connections_with_chlo_.size(); |
| 192 bool reach_non_chlo_limit = |
| 193 FLAGS_quic_limit_num_new_sessions_per_epoll_loop && |
| 194 num_connections_without_chlo >= kMaxConnectionsWithoutCHLO; |
| 195 |
| 196 return is_store_full || reach_non_chlo_limit; |
| 197 } |
| 198 |
| 199 list<BufferedPacket> QuicBufferedPacketStore::DeliverPacketsForNextConnection( |
| 200 QuicConnectionId* connection_id) { |
| 201 if (connections_with_chlo_.empty()) { |
| 202 // Returns empty list if no CHLO has been buffered. |
| 203 return list<BufferedPacket>(); |
| 204 } |
| 205 *connection_id = connections_with_chlo_.front().first; |
| 206 connections_with_chlo_.erase(connections_with_chlo_.begin()); |
| 207 |
| 208 list<BufferedPacket> packets = DeliverPackets(*connection_id); |
| 209 DCHECK(!packets.empty()) << "Try to deliver connectons without CHLO"; |
| 210 return packets; |
| 211 } |
| 212 |
| 213 bool QuicBufferedPacketStore::HasChloForConnection( |
| 214 QuicConnectionId connection_id) { |
| 215 return base::ContainsKey(connections_with_chlo_, connection_id); |
| 153 } | 216 } |
| 154 | 217 |
| 155 } // namespace net | 218 } // namespace net |
| OLD | NEW |