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 |