- add sources.
[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
21 using std::make_pair;
22
23 namespace net {
24 namespace tools {
25
26 namespace {
27
28 // Time period for which the guid should live in time wait state..
29 const int kTimeWaitSeconds = 5;
30
31 }  // namespace
32
33 // A very simple alarm that just informs the QuicTimeWaitListManager to clean
34 // up old guids. This alarm should be unregistered and deleted before the
35 // QuicTimeWaitListManager is deleted.
36 class GuidCleanUpAlarm : public EpollAlarm {
37  public:
38   explicit GuidCleanUpAlarm(QuicTimeWaitListManager* time_wait_list_manager)
39       : time_wait_list_manager_(time_wait_list_manager) {
40   }
41
42   virtual int64 OnAlarm() OVERRIDE {
43     EpollAlarm::OnAlarm();
44     time_wait_list_manager_->CleanUpOldGuids();
45     // Let the time wait manager register the alarm at appropriate time.
46     return 0;
47   }
48
49  private:
50   // Not owned.
51   QuicTimeWaitListManager* time_wait_list_manager_;
52 };
53
54 struct QuicTimeWaitListManager::GuidAddTime {
55   GuidAddTime(QuicGuid guid, const QuicTime& time)
56       : guid(guid),
57         time_added(time) {
58   }
59
60   QuicGuid guid;
61   QuicTime time_added;
62 };
63
64 // This class stores pending public reset packets to be sent to clients.
65 // server_address - server address on which a packet what was received for
66 //                  a guid in time wait state.
67 // client_address - address of the client that sent that packet. Needed to send
68 //                  the public reset packet back to the client.
69 // packet - the pending public reset packet that is to be sent to the client.
70 //          created instance takes the ownership of this packet.
71 class QuicTimeWaitListManager::QueuedPacket {
72  public:
73   QueuedPacket(const IPEndPoint& server_address,
74                const IPEndPoint& client_address,
75                QuicEncryptedPacket* packet)
76       : server_address_(server_address),
77         client_address_(client_address),
78         packet_(packet) {
79   }
80
81   const IPEndPoint& server_address() const { return server_address_; }
82   const IPEndPoint& client_address() const { return client_address_; }
83   QuicEncryptedPacket* packet() { return packet_.get(); }
84
85  private:
86   const IPEndPoint server_address_;
87   const IPEndPoint client_address_;
88   scoped_ptr<QuicEncryptedPacket> packet_;
89
90   DISALLOW_COPY_AND_ASSIGN(QueuedPacket);
91 };
92
93 QuicTimeWaitListManager::QuicTimeWaitListManager(
94     QuicPacketWriter* writer,
95     EpollServer* epoll_server,
96     const QuicVersionVector& supported_versions)
97     : framer_(supported_versions,
98               QuicTime::Zero(),  // unused
99               true),
100       epoll_server_(epoll_server),
101       kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)),
102       guid_clean_up_alarm_(new GuidCleanUpAlarm(this)),
103       clock_(epoll_server),
104       writer_(writer),
105       is_write_blocked_(false) {
106   framer_.set_visitor(this);
107   SetGuidCleanUpAlarm();
108 }
109
110 QuicTimeWaitListManager::~QuicTimeWaitListManager() {
111   guid_clean_up_alarm_->UnregisterIfRegistered();
112   STLDeleteElements(&time_ordered_guid_list_);
113   STLDeleteElements(&pending_packets_queue_);
114 }
115
116 void QuicTimeWaitListManager::AddGuidToTimeWait(QuicGuid guid,
117                                                 QuicVersion version) {
118   DCHECK(!IsGuidInTimeWait(guid));
119   // Initialize the guid with 0 packets received.
120   GuidData data(0, version);
121   guid_map_.insert(make_pair(guid, data));
122   time_ordered_guid_list_.push_back(new GuidAddTime(guid,
123                                                     clock_.ApproximateNow()));
124 }
125
126 bool QuicTimeWaitListManager::IsGuidInTimeWait(QuicGuid guid) const {
127   return guid_map_.find(guid) != guid_map_.end();
128 }
129
130 void QuicTimeWaitListManager::ProcessPacket(
131     const IPEndPoint& server_address,
132     const IPEndPoint& client_address,
133     QuicGuid guid,
134     const QuicEncryptedPacket& packet) {
135   DCHECK(IsGuidInTimeWait(guid));
136   server_address_ = server_address;
137   client_address_ = client_address;
138
139   // Set the framer to the appropriate version for this GUID, before processing.
140   QuicVersion version = GetQuicVersionFromGuid(guid);
141   framer_.set_version(version);
142
143   framer_.ProcessPacket(packet);
144 }
145
146 QuicVersion QuicTimeWaitListManager::GetQuicVersionFromGuid(QuicGuid guid) {
147   GuidMapIterator it = guid_map_.find(guid);
148   DCHECK(it != guid_map_.end());
149   return (it->second).version;
150 }
151
152 bool QuicTimeWaitListManager::OnCanWrite() {
153   is_write_blocked_ = false;
154   while (!is_write_blocked_ && !pending_packets_queue_.empty()) {
155     QueuedPacket* queued_packet = pending_packets_queue_.front();
156     WriteToWire(queued_packet);
157     if (!is_write_blocked_) {
158       pending_packets_queue_.pop_front();
159       delete queued_packet;
160     }
161   }
162
163   return !is_write_blocked_;
164 }
165
166 void QuicTimeWaitListManager::OnError(QuicFramer* framer) {
167   DLOG(INFO) << QuicUtils::ErrorToString(framer->error());
168 }
169
170 bool QuicTimeWaitListManager::OnProtocolVersionMismatch(
171     QuicVersion received_version) {
172   // Drop such packets whose version don't match.
173   return false;
174 }
175
176 bool QuicTimeWaitListManager::OnStreamFrame(const QuicStreamFrame& frame) {
177   return false;
178 }
179
180 bool QuicTimeWaitListManager::OnAckFrame(const QuicAckFrame& frame) {
181   return false;
182 }
183
184 bool QuicTimeWaitListManager::OnCongestionFeedbackFrame(
185     const QuicCongestionFeedbackFrame& frame) {
186   return false;
187 }
188
189 bool QuicTimeWaitListManager::OnRstStreamFrame(
190     const QuicRstStreamFrame& frame) {
191   return false;
192 }
193
194 bool QuicTimeWaitListManager::OnConnectionCloseFrame(
195     const QuicConnectionCloseFrame & frame) {
196   return false;
197 }
198
199 bool QuicTimeWaitListManager::OnGoAwayFrame(const QuicGoAwayFrame& frame) {
200   return false;
201 }
202
203 bool QuicTimeWaitListManager::OnPacketHeader(const QuicPacketHeader& header) {
204   // TODO(satyamshekhar): Think about handling packets from different client
205   // addresses.
206   GuidMapIterator it = guid_map_.find(header.public_header.guid);
207   DCHECK(it != guid_map_.end());
208   // Increment the received packet count.
209   ++((it->second).num_packets);
210   if (ShouldSendPublicReset((it->second).num_packets)) {
211     // We don't need the packet anymore. Just tell the client what sequence
212     // number we rejected.
213     SendPublicReset(server_address_,
214                     client_address_,
215                     header.public_header.guid,
216                     header.packet_sequence_number);
217   }
218   // Never process the body of the packet in time wait state.
219   return false;
220 }
221
222 // Returns true if the number of packets received for this guid is a power of 2
223 // to throttle the number of public reset packets we send to a client.
224 bool QuicTimeWaitListManager::ShouldSendPublicReset(int received_packet_count) {
225   return (received_packet_count & (received_packet_count - 1)) == 0;
226 }
227
228 void QuicTimeWaitListManager::SendPublicReset(
229     const IPEndPoint& server_address,
230     const IPEndPoint& client_address,
231     QuicGuid guid,
232     QuicPacketSequenceNumber rejected_sequence_number) {
233   QuicPublicResetPacket packet;
234   packet.public_header.guid = guid;
235   packet.public_header.reset_flag = true;
236   packet.public_header.version_flag = false;
237   packet.rejected_sequence_number = rejected_sequence_number;
238   // TODO(satyamshekhar): generate a valid nonce for this guid.
239   packet.nonce_proof = 1010101;
240   QueuedPacket* queued_packet = new QueuedPacket(
241       server_address,
242       client_address,
243       framer_.BuildPublicResetPacket(packet));
244   // Takes ownership of the packet.
245   SendOrQueuePacket(queued_packet);
246 }
247
248 // Either sends the packet and deletes it or makes pending queue the
249 // owner of the packet.
250 void QuicTimeWaitListManager::SendOrQueuePacket(QueuedPacket* packet) {
251   if (!is_write_blocked_) {
252     // TODO(satyamshekhar): Handle packets that fail due to error other than
253     // EAGAIN or EWOULDBLOCK.
254     WriteToWire(packet);
255   }
256
257   if (is_write_blocked_) {
258     // pending_packets_queue takes the ownership of the queued packet.
259     pending_packets_queue_.push_back(packet);
260   } else {
261     delete packet;
262   }
263 }
264
265 void QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) {
266   DCHECK(!is_write_blocked_);
267   WriteResult result = writer_->WritePacket(
268       queued_packet->packet()->data(),
269       queued_packet->packet()->length(),
270       queued_packet->server_address().address(),
271       queued_packet->client_address(),
272       this);
273
274   if (result.status == WRITE_STATUS_BLOCKED) {
275     is_write_blocked_ = true;
276   } else if (result.status == WRITE_STATUS_ERROR) {
277     LOG(WARNING) << "Received unknown error while sending reset packet to "
278                  << queued_packet->client_address().ToString() << ": "
279                  << strerror(result.error_code);
280   }
281 }
282
283 void QuicTimeWaitListManager::SetGuidCleanUpAlarm() {
284   guid_clean_up_alarm_->UnregisterIfRegistered();
285   int64 next_alarm_interval;
286   if (!time_ordered_guid_list_.empty()) {
287     GuidAddTime* oldest_guid = time_ordered_guid_list_.front();
288     QuicTime now = clock_.ApproximateNow();
289     DCHECK(now.Subtract(oldest_guid->time_added) < kTimeWaitPeriod_);
290     next_alarm_interval = oldest_guid->time_added
291         .Add(kTimeWaitPeriod_)
292         .Subtract(now)
293         .ToMicroseconds();
294   } else {
295     // No guids added so none will expire before kTimeWaitPeriod_.
296     next_alarm_interval = kTimeWaitPeriod_.ToMicroseconds();
297   }
298
299   epoll_server_->RegisterAlarmApproximateDelta(next_alarm_interval,
300                                                guid_clean_up_alarm_.get());
301 }
302
303 void QuicTimeWaitListManager::CleanUpOldGuids() {
304   QuicTime now = clock_.ApproximateNow();
305   while (time_ordered_guid_list_.size() > 0) {
306     DCHECK_EQ(time_ordered_guid_list_.size(), guid_map_.size());
307     GuidAddTime* oldest_guid = time_ordered_guid_list_.front();
308     if (now.Subtract(oldest_guid->time_added) < kTimeWaitPeriod_) {
309       break;
310     }
311     // This guid has lived its age, retire it now.
312     guid_map_.erase(oldest_guid->guid);
313     time_ordered_guid_list_.pop_front();
314     delete oldest_guid;
315   }
316   SetGuidCleanUpAlarm();
317 }
318
319 }  // namespace tools
320 }  // namespace net