Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / net / quic / quic_time_wait_list_manager.cc
1 // Copyright 2014 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 #include "net/quic/quic_time_wait_list_manager.h"
6
7 #include <errno.h>
8
9 #include "base/containers/hash_tables.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/stl_util.h"
12 #include "net/base/ip_endpoint.h"
13 #include "net/quic/crypto/crypto_protocol.h"
14 #include "net/quic/crypto/quic_decrypter.h"
15 #include "net/quic/crypto/quic_encrypter.h"
16 #include "net/quic/quic_clock.h"
17 #include "net/quic/quic_connection_helper.h"
18 #include "net/quic/quic_framer.h"
19 #include "net/quic/quic_protocol.h"
20 #include "net/quic/quic_server_session.h"
21 #include "net/quic/quic_utils.h"
22
23 using base::StringPiece;
24 using std::make_pair;
25
26 namespace net {
27
28 namespace {
29
30 // Time period for which a given connection_id should live in the time-wait
31 // state.
32 int64 FLAGS_quic_time_wait_list_seconds = 5;
33
34 }  // namespace
35
36 // A very simple alarm that just informs the QuicTimeWaitListManager to clean
37 // up old connection_ids. This alarm should be unregistered and deleted before
38 // the QuicTimeWaitListManager is deleted.
39 class ConnectionIdCleanUpAlarm : public QuicAlarm::Delegate {
40  public:
41   explicit ConnectionIdCleanUpAlarm(
42       QuicTimeWaitListManager* time_wait_list_manager)
43       : time_wait_list_manager_(time_wait_list_manager) {}
44
45   QuicTime OnAlarm() override {
46     time_wait_list_manager_->CleanUpOldConnectionIds();
47     // Let the time wait manager register the alarm at appropriate time.
48     return QuicTime::Zero();
49   }
50
51  private:
52   // Not owned.
53   QuicTimeWaitListManager* time_wait_list_manager_;
54 };
55
56 // This class stores pending public reset packets to be sent to clients.
57 // server_address - server address on which a packet what was received for
58 //                  a connection_id in time wait state.
59 // client_address - address of the client that sent that packet. Needed to send
60 //                  the public reset packet back to the client.
61 // packet - the pending public reset packet that is to be sent to the client.
62 //          created instance takes the ownership of this packet.
63 class QuicTimeWaitListManager::QueuedPacket {
64  public:
65   QueuedPacket(const IPEndPoint& server_address,
66                const IPEndPoint& client_address,
67                QuicEncryptedPacket* packet)
68       : server_address_(server_address),
69         client_address_(client_address),
70         packet_(packet) {}
71
72   const IPEndPoint& server_address() const { return server_address_; }
73   const IPEndPoint& client_address() const { return client_address_; }
74   QuicEncryptedPacket* packet() { return packet_.get(); }
75
76  private:
77   const IPEndPoint server_address_;
78   const IPEndPoint client_address_;
79   scoped_ptr<QuicEncryptedPacket> packet_;
80
81   DISALLOW_COPY_AND_ASSIGN(QueuedPacket);
82 };
83
84 QuicTimeWaitListManager::QuicTimeWaitListManager(
85     QuicPacketWriter* writer,
86     QuicServerSessionVisitor* visitor,
87     QuicConnectionHelperInterface* helper,
88     const QuicVersionVector& supported_versions)
89     : helper_(helper),
90       kTimeWaitPeriod_(
91           QuicTime::Delta::FromSeconds(FLAGS_quic_time_wait_list_seconds)),
92       connection_id_clean_up_alarm_(
93           helper_->CreateAlarm(new ConnectionIdCleanUpAlarm(this))),
94       writer_(writer),
95       visitor_(visitor) {
96   SetConnectionIdCleanUpAlarm();
97 }
98
99 QuicTimeWaitListManager::~QuicTimeWaitListManager() {
100   connection_id_clean_up_alarm_->Cancel();
101   STLDeleteElements(&pending_packets_queue_);
102   for (ConnectionIdMap::iterator it = connection_id_map_.begin();
103        it != connection_id_map_.end();
104        ++it) {
105     delete it->second.close_packet;
106   }
107 }
108
109 void QuicTimeWaitListManager::AddConnectionIdToTimeWait(
110     QuicConnectionId connection_id,
111     QuicVersion version,
112     QuicEncryptedPacket* close_packet) {
113   DVLOG(1) << "Adding " << connection_id << " to the time wait list.";
114   int num_packets = 0;
115   ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
116   if (it != connection_id_map_.end()) {  // Replace record if it is reinserted.
117     num_packets = it->second.num_packets;
118     delete it->second.close_packet;
119     connection_id_map_.erase(it);
120   }
121   ConnectionIdData data(num_packets,
122                         version,
123                         helper_->GetClock()->ApproximateNow(),
124                         close_packet);
125   connection_id_map_.insert(make_pair(connection_id, data));
126 }
127
128 bool QuicTimeWaitListManager::IsConnectionIdInTimeWait(
129     QuicConnectionId connection_id) const {
130   return ContainsKey(connection_id_map_, connection_id);
131 }
132
133 QuicVersion QuicTimeWaitListManager::GetQuicVersionFromConnectionId(
134     QuicConnectionId connection_id) {
135   ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
136   DCHECK(it != connection_id_map_.end());
137   return (it->second).version;
138 }
139
140 void QuicTimeWaitListManager::OnCanWrite() {
141   while (!pending_packets_queue_.empty()) {
142     QueuedPacket* queued_packet = pending_packets_queue_.front();
143     if (!WriteToWire(queued_packet)) {
144       return;
145     }
146     pending_packets_queue_.pop_front();
147     delete queued_packet;
148   }
149 }
150
151 void QuicTimeWaitListManager::ProcessPacket(
152     const IPEndPoint& server_address,
153     const IPEndPoint& client_address,
154     QuicConnectionId connection_id,
155     QuicPacketSequenceNumber sequence_number,
156     const QuicEncryptedPacket& /*packet*/) {
157   DCHECK(IsConnectionIdInTimeWait(connection_id));
158   DVLOG(1) << "Processing " << connection_id << " in time wait state.";
159   // TODO(satyamshekhar): Think about handling packets from different client
160   // addresses.
161   ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
162   DCHECK(it != connection_id_map_.end());
163   // Increment the received packet count.
164   ++((it->second).num_packets);
165   if (!ShouldSendResponse((it->second).num_packets)) {
166     return;
167   }
168   if (it->second.close_packet) {
169     QueuedPacket* queued_packet =
170         new QueuedPacket(server_address,
171                          client_address,
172                          it->second.close_packet->Clone());
173     // Takes ownership of the packet.
174     SendOrQueuePacket(queued_packet);
175   } else {
176     SendPublicReset(server_address,
177                     client_address,
178                     connection_id,
179                     sequence_number);
180   }
181 }
182
183 // Returns true if the number of packets received for this connection_id is a
184 // power of 2 to throttle the number of public reset packets we send to a
185 // client.
186 bool QuicTimeWaitListManager::ShouldSendResponse(int received_packet_count) {
187   return (received_packet_count & (received_packet_count - 1)) == 0;
188 }
189
190 void QuicTimeWaitListManager::SendPublicReset(
191     const IPEndPoint& server_address,
192     const IPEndPoint& client_address,
193     QuicConnectionId connection_id,
194     QuicPacketSequenceNumber rejected_sequence_number) {
195   QuicPublicResetPacket packet;
196   packet.public_header.connection_id = connection_id;
197   packet.public_header.reset_flag = true;
198   packet.public_header.version_flag = false;
199   packet.rejected_sequence_number = rejected_sequence_number;
200   // TODO(satyamshekhar): generate a valid nonce for this connection_id.
201   packet.nonce_proof = 1010101;
202   packet.client_address = client_address;
203   QueuedPacket* queued_packet = new QueuedPacket(
204       server_address,
205       client_address,
206       BuildPublicReset(packet));
207   // Takes ownership of the packet.
208   SendOrQueuePacket(queued_packet);
209 }
210
211 QuicEncryptedPacket* QuicTimeWaitListManager::BuildPublicReset(
212     const QuicPublicResetPacket& packet) {
213   return QuicFramer::BuildPublicResetPacket(packet);
214 }
215
216 // Either sends the packet and deletes it or makes pending queue the
217 // owner of the packet.
218 void QuicTimeWaitListManager::SendOrQueuePacket(QueuedPacket* packet) {
219   if (WriteToWire(packet)) {
220     delete packet;
221   } else {
222     // pending_packets_queue takes the ownership of the queued packet.
223     pending_packets_queue_.push_back(packet);
224   }
225 }
226
227 bool QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) {
228   if (writer_->IsWriteBlocked()) {
229     visitor_->OnWriteBlocked(this);
230     return false;
231   }
232   WriteResult result = writer_->WritePacket(
233       queued_packet->packet()->data(),
234       queued_packet->packet()->length(),
235       queued_packet->server_address().address(),
236       queued_packet->client_address());
237   if (result.status == WRITE_STATUS_BLOCKED) {
238     // If blocked and unbuffered, return false to retry sending.
239     DCHECK(writer_->IsWriteBlocked());
240     visitor_->OnWriteBlocked(this);
241     return writer_->IsWriteBlockedDataBuffered();
242   } else if (result.status == WRITE_STATUS_ERROR) {
243     LOG(WARNING) << "Received unknown error while sending reset packet to "
244                  << queued_packet->client_address().ToString() << ": "
245                  << strerror(result.error_code);
246   }
247   return true;
248 }
249
250 void QuicTimeWaitListManager::SetConnectionIdCleanUpAlarm() {
251   connection_id_clean_up_alarm_->Cancel();
252   QuicTime now = helper_->GetClock()->ApproximateNow();
253   QuicTime next_alarm_time = now;
254   if (!connection_id_map_.empty()) {
255     QuicTime oldest_connection_id =
256         connection_id_map_.begin()->second.time_added;
257     if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) {
258       next_alarm_time = oldest_connection_id.Add(kTimeWaitPeriod_);
259     } else {
260       LOG(ERROR) << "ConnectionId lingered for longer than kTimeWaitPeriod";
261     }
262   } else {
263     // No connection_ids added so none will expire before kTimeWaitPeriod_.
264     next_alarm_time = now.Add(kTimeWaitPeriod_);
265   }
266
267   connection_id_clean_up_alarm_->Set(next_alarm_time);
268 }
269
270 void QuicTimeWaitListManager::CleanUpOldConnectionIds() {
271   QuicTime now = helper_->GetClock()->ApproximateNow();
272   while (!connection_id_map_.empty()) {
273     ConnectionIdMap::iterator it = connection_id_map_.begin();
274     QuicTime oldest_connection_id = it->second.time_added;
275     if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) {
276       break;
277     }
278     // This connection_id has lived its age, retire it now.
279     DVLOG(1) << "Retiring " << it->first << " from the time-wait state.";
280     delete it->second.close_packet;
281     connection_id_map_.erase(it);
282   }
283   SetConnectionIdCleanUpAlarm();
284 }
285
286 }  // namespace net