Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / net / tools / quic / quic_time_wait_list_manager.cc
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 #include "net/tools/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_framer.h"
18 #include "net/quic/quic_protocol.h"
19 #include "net/quic/quic_utils.h"
20 #include "net/tools/quic/quic_server_session.h"
21
22 using base::StringPiece;
23 using std::make_pair;
24
25 namespace net {
26 namespace tools {
27
28 namespace {
29
30 // Time period for which the guid should live in time wait state..
31 const int kTimeWaitSeconds = 5;
32
33 }  // namespace
34
35 // A very simple alarm that just informs the QuicTimeWaitListManager to clean
36 // up old guids. This alarm should be unregistered and deleted before the
37 // QuicTimeWaitListManager is deleted.
38 class GuidCleanUpAlarm : public EpollAlarm {
39  public:
40   explicit GuidCleanUpAlarm(QuicTimeWaitListManager* time_wait_list_manager)
41       : time_wait_list_manager_(time_wait_list_manager) {
42   }
43
44   virtual int64 OnAlarm() OVERRIDE {
45     EpollAlarm::OnAlarm();
46     time_wait_list_manager_->CleanUpOldGuids();
47     // Let the time wait manager register the alarm at appropriate time.
48     return 0;
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 guid 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
73   const IPEndPoint& server_address() const { return server_address_; }
74   const IPEndPoint& client_address() const { return client_address_; }
75   QuicEncryptedPacket* packet() { return packet_.get(); }
76
77  private:
78   const IPEndPoint server_address_;
79   const IPEndPoint client_address_;
80   scoped_ptr<QuicEncryptedPacket> packet_;
81
82   DISALLOW_COPY_AND_ASSIGN(QueuedPacket);
83 };
84
85 QuicTimeWaitListManager::QuicTimeWaitListManager(
86     QuicPacketWriter* writer,
87     QuicServerSessionVisitor* visitor,
88     EpollServer* epoll_server,
89     const QuicVersionVector& supported_versions)
90     : epoll_server_(epoll_server),
91       kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)),
92       guid_clean_up_alarm_(new GuidCleanUpAlarm(this)),
93       clock_(epoll_server_),
94       writer_(writer),
95       visitor_(visitor) {
96   SetGuidCleanUpAlarm();
97 }
98
99 QuicTimeWaitListManager::~QuicTimeWaitListManager() {
100   guid_clean_up_alarm_->UnregisterIfRegistered();
101   STLDeleteElements(&pending_packets_queue_);
102   for (GuidMap::iterator it = guid_map_.begin(); it != guid_map_.end(); ++it) {
103     delete it->second.close_packet;
104   }
105 }
106
107 void QuicTimeWaitListManager::AddGuidToTimeWait(
108     QuicGuid guid,
109     QuicVersion version,
110     QuicEncryptedPacket* close_packet) {
111   int num_packets = 0;
112   GuidMap::iterator it = guid_map_.find(guid);
113   if (it != guid_map_.end()) {  // Replace record if it is reinserted.
114     num_packets = it->second.num_packets;
115     delete it->second.close_packet;
116     guid_map_.erase(it);
117   }
118   GuidData data(num_packets, version, clock_.ApproximateNow(), close_packet);
119   guid_map_.insert(make_pair(guid, data));
120 }
121
122 bool QuicTimeWaitListManager::IsGuidInTimeWait(QuicGuid guid) const {
123   return guid_map_.find(guid) != guid_map_.end();
124 }
125
126 QuicVersion QuicTimeWaitListManager::GetQuicVersionFromGuid(QuicGuid guid) {
127   GuidMap::iterator it = guid_map_.find(guid);
128   DCHECK(it != guid_map_.end());
129   return (it->second).version;
130 }
131
132 bool QuicTimeWaitListManager::OnCanWrite() {
133   while (!pending_packets_queue_.empty()) {
134     QueuedPacket* queued_packet = pending_packets_queue_.front();
135     if (WriteToWire(queued_packet)) {
136       pending_packets_queue_.pop_front();
137       delete queued_packet;
138     } else {
139       break;
140     }
141   }
142
143   return !writer_->IsWriteBlocked();
144 }
145
146 void QuicTimeWaitListManager::ProcessPacket(
147     const IPEndPoint& server_address,
148     const IPEndPoint& client_address,
149     QuicGuid guid,
150     QuicPacketSequenceNumber sequence_number) {
151   DCHECK(IsGuidInTimeWait(guid));
152   // TODO(satyamshekhar): Think about handling packets from different client
153   // addresses.
154   GuidMap::iterator it = guid_map_.find(guid);
155   DCHECK(it != guid_map_.end());
156   // Increment the received packet count.
157   ++((it->second).num_packets);
158   if (!ShouldSendResponse((it->second).num_packets)) {
159     return;
160   }
161   if (it->second.close_packet) {
162      QueuedPacket* queued_packet =
163          new QueuedPacket(server_address,
164                           client_address,
165                           it->second.close_packet->Clone());
166      // Takes ownership of the packet.
167      SendOrQueuePacket(queued_packet);
168   } else {
169     SendPublicReset(server_address, client_address, guid, sequence_number);
170   }
171 }
172
173 // Returns true if the number of packets received for this guid is a power of 2
174 // to throttle the number of public reset packets we send to a client.
175 bool QuicTimeWaitListManager::ShouldSendResponse(int received_packet_count) {
176   return (received_packet_count & (received_packet_count - 1)) == 0;
177 }
178
179 void QuicTimeWaitListManager::SendPublicReset(
180     const IPEndPoint& server_address,
181     const IPEndPoint& client_address,
182     QuicGuid guid,
183     QuicPacketSequenceNumber rejected_sequence_number) {
184   QuicPublicResetPacket packet;
185   packet.public_header.guid = guid;
186   packet.public_header.reset_flag = true;
187   packet.public_header.version_flag = false;
188   packet.rejected_sequence_number = rejected_sequence_number;
189   // TODO(satyamshekhar): generate a valid nonce for this guid.
190   packet.nonce_proof = 1010101;
191   packet.client_address = client_address;
192   QueuedPacket* queued_packet = new QueuedPacket(
193       server_address,
194       client_address,
195       QuicFramer::BuildPublicResetPacket(packet));
196   // Takes ownership of the packet.
197   SendOrQueuePacket(queued_packet);
198 }
199
200 // Either sends the packet and deletes it or makes pending queue the
201 // owner of the packet.
202 void QuicTimeWaitListManager::SendOrQueuePacket(QueuedPacket* packet) {
203   if (WriteToWire(packet)) {
204     delete packet;
205   } else {
206     // pending_packets_queue takes the ownership of the queued packet.
207     pending_packets_queue_.push_back(packet);
208   }
209 }
210
211 bool QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) {
212   if (writer_->IsWriteBlocked()) {
213     visitor_->OnWriteBlocked(this);
214     return false;
215   }
216   WriteResult result = writer_->WritePacket(
217       queued_packet->packet()->data(),
218       queued_packet->packet()->length(),
219       queued_packet->server_address().address(),
220       queued_packet->client_address());
221   if (result.status == WRITE_STATUS_BLOCKED) {
222     // If blocked and unbuffered, return false to retry sending.
223     DCHECK(writer_->IsWriteBlocked());
224     visitor_->OnWriteBlocked(this);
225     return writer_->IsWriteBlockedDataBuffered();
226   } else if (result.status == WRITE_STATUS_ERROR) {
227     LOG(WARNING) << "Received unknown error while sending reset packet to "
228                  << queued_packet->client_address().ToString() << ": "
229                  << strerror(result.error_code);
230   }
231   return true;
232 }
233
234 void QuicTimeWaitListManager::SetGuidCleanUpAlarm() {
235   guid_clean_up_alarm_->UnregisterIfRegistered();
236   int64 next_alarm_interval;
237   if (!guid_map_.empty()) {
238     QuicTime oldest_guid = guid_map_.begin()->second.time_added;
239     QuicTime now = clock_.ApproximateNow();
240     if (now.Subtract(oldest_guid) < kTimeWaitPeriod_) {
241       next_alarm_interval = oldest_guid.Add(kTimeWaitPeriod_)
242                                        .Subtract(now)
243                                        .ToMicroseconds();
244     } else {
245       LOG(ERROR) << "GUID lingered for longer than kTimeWaitPeriod";
246       next_alarm_interval = 0;
247     }
248   } else {
249     // No guids added so none will expire before kTimeWaitPeriod_.
250     next_alarm_interval = kTimeWaitPeriod_.ToMicroseconds();
251   }
252
253   epoll_server_->RegisterAlarmApproximateDelta(next_alarm_interval,
254                                                guid_clean_up_alarm_.get());
255 }
256
257 void QuicTimeWaitListManager::CleanUpOldGuids() {
258   QuicTime now = clock_.ApproximateNow();
259   while (!guid_map_.empty()) {
260     GuidMap::iterator it = guid_map_.begin();
261     QuicTime oldest_guid = it->second.time_added;
262     if (now.Subtract(oldest_guid) < kTimeWaitPeriod_) {
263       break;
264     }
265     // This guid has lived its age, retire it now.
266     delete it->second.close_packet;
267     guid_map_.erase(it);
268   }
269   SetGuidCleanUpAlarm();
270 }
271
272 }  // namespace tools
273 }  // namespace net