Upstream version 6.35.121.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 connection_id 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 connection_ids. This alarm should be unregistered and deleted before
37 // the QuicTimeWaitListManager is deleted.
38 class ConnectionIdCleanUpAlarm : public EpollAlarm {
39  public:
40   explicit ConnectionIdCleanUpAlarm(
41       QuicTimeWaitListManager* time_wait_list_manager)
42       : time_wait_list_manager_(time_wait_list_manager) {
43   }
44
45   virtual int64 OnAlarm() OVERRIDE {
46     EpollAlarm::OnAlarm();
47     time_wait_list_manager_->CleanUpOldConnectionIds();
48     // Let the time wait manager register the alarm at appropriate time.
49     return 0;
50   }
51
52  private:
53   // Not owned.
54   QuicTimeWaitListManager* time_wait_list_manager_;
55 };
56
57 // This class stores pending public reset packets to be sent to clients.
58 // server_address - server address on which a packet what was received for
59 //                  a connection_id in time wait state.
60 // client_address - address of the client that sent that packet. Needed to send
61 //                  the public reset packet back to the client.
62 // packet - the pending public reset packet that is to be sent to the client.
63 //          created instance takes the ownership of this packet.
64 class QuicTimeWaitListManager::QueuedPacket {
65  public:
66   QueuedPacket(const IPEndPoint& server_address,
67                const IPEndPoint& client_address,
68                QuicEncryptedPacket* packet)
69       : server_address_(server_address),
70         client_address_(client_address),
71         packet_(packet) {
72   }
73
74   const IPEndPoint& server_address() const { return server_address_; }
75   const IPEndPoint& client_address() const { return client_address_; }
76   QuicEncryptedPacket* packet() { return packet_.get(); }
77
78  private:
79   const IPEndPoint server_address_;
80   const IPEndPoint client_address_;
81   scoped_ptr<QuicEncryptedPacket> packet_;
82
83   DISALLOW_COPY_AND_ASSIGN(QueuedPacket);
84 };
85
86 QuicTimeWaitListManager::QuicTimeWaitListManager(
87     QuicPacketWriter* writer,
88     QuicServerSessionVisitor* visitor,
89     EpollServer* epoll_server,
90     const QuicVersionVector& supported_versions)
91     : epoll_server_(epoll_server),
92       kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)),
93       connection_id_clean_up_alarm_(new ConnectionIdCleanUpAlarm(this)),
94       clock_(epoll_server_),
95       writer_(writer),
96       visitor_(visitor) {
97   SetConnectionIdCleanUpAlarm();
98 }
99
100 QuicTimeWaitListManager::~QuicTimeWaitListManager() {
101   connection_id_clean_up_alarm_->UnregisterIfRegistered();
102   STLDeleteElements(&pending_packets_queue_);
103   for (ConnectionIdMap::iterator it = connection_id_map_.begin();
104        it != connection_id_map_.end();
105        ++it) {
106     delete it->second.close_packet;
107   }
108 }
109
110 void QuicTimeWaitListManager::AddConnectionIdToTimeWait(
111     QuicConnectionId connection_id,
112     QuicVersion version,
113     QuicEncryptedPacket* close_packet) {
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, version, clock_.ApproximateNow(),
122                         close_packet);
123   connection_id_map_.insert(make_pair(connection_id, data));
124 }
125
126 bool QuicTimeWaitListManager::IsConnectionIdInTimeWait(
127     QuicConnectionId connection_id) const {
128   return ContainsKey(connection_id_map_, connection_id);
129 }
130
131 QuicVersion QuicTimeWaitListManager::GetQuicVersionFromConnectionId(
132     QuicConnectionId connection_id) {
133   ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
134   DCHECK(it != connection_id_map_.end());
135   return (it->second).version;
136 }
137
138 void QuicTimeWaitListManager::OnCanWrite() {
139   while (!pending_packets_queue_.empty()) {
140     QueuedPacket* queued_packet = pending_packets_queue_.front();
141     if (!WriteToWire(queued_packet)) {
142       return;
143     }
144     pending_packets_queue_.pop_front();
145     delete queued_packet;
146   }
147 }
148
149 void QuicTimeWaitListManager::ProcessPacket(
150     const IPEndPoint& server_address,
151     const IPEndPoint& client_address,
152     QuicConnectionId connection_id,
153     QuicPacketSequenceNumber sequence_number) {
154   DCHECK(IsConnectionIdInTimeWait(connection_id));
155   // TODO(satyamshekhar): Think about handling packets from different client
156   // addresses.
157   ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
158   DCHECK(it != connection_id_map_.end());
159   // Increment the received packet count.
160   ++((it->second).num_packets);
161   if (!ShouldSendResponse((it->second).num_packets)) {
162     return;
163   }
164   if (it->second.close_packet) {
165      QueuedPacket* queued_packet =
166          new QueuedPacket(server_address,
167                           client_address,
168                           it->second.close_packet->Clone());
169      // Takes ownership of the packet.
170      SendOrQueuePacket(queued_packet);
171   } else {
172     SendPublicReset(server_address,
173                     client_address,
174                     connection_id,
175                     sequence_number);
176   }
177 }
178
179 // Returns true if the number of packets received for this connection_id is a
180 // power of 2 to throttle the number of public reset packets we send to a
181 // client.
182 bool QuicTimeWaitListManager::ShouldSendResponse(int received_packet_count) {
183   return (received_packet_count & (received_packet_count - 1)) == 0;
184 }
185
186 void QuicTimeWaitListManager::SendPublicReset(
187     const IPEndPoint& server_address,
188     const IPEndPoint& client_address,
189     QuicConnectionId connection_id,
190     QuicPacketSequenceNumber rejected_sequence_number) {
191   QuicPublicResetPacket packet;
192   packet.public_header.connection_id = connection_id;
193   packet.public_header.reset_flag = true;
194   packet.public_header.version_flag = false;
195   packet.rejected_sequence_number = rejected_sequence_number;
196   // TODO(satyamshekhar): generate a valid nonce for this connection_id.
197   packet.nonce_proof = 1010101;
198   packet.client_address = client_address;
199   QueuedPacket* queued_packet = new QueuedPacket(
200       server_address,
201       client_address,
202       QuicFramer::BuildPublicResetPacket(packet));
203   // Takes ownership of the packet.
204   SendOrQueuePacket(queued_packet);
205 }
206
207 // Either sends the packet and deletes it or makes pending queue the
208 // owner of the packet.
209 void QuicTimeWaitListManager::SendOrQueuePacket(QueuedPacket* packet) {
210   if (WriteToWire(packet)) {
211     delete packet;
212   } else {
213     // pending_packets_queue takes the ownership of the queued packet.
214     pending_packets_queue_.push_back(packet);
215   }
216 }
217
218 bool QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) {
219   if (writer_->IsWriteBlocked()) {
220     visitor_->OnWriteBlocked(this);
221     return false;
222   }
223   WriteResult result = writer_->WritePacket(
224       queued_packet->packet()->data(),
225       queued_packet->packet()->length(),
226       queued_packet->server_address().address(),
227       queued_packet->client_address());
228   if (result.status == WRITE_STATUS_BLOCKED) {
229     // If blocked and unbuffered, return false to retry sending.
230     DCHECK(writer_->IsWriteBlocked());
231     visitor_->OnWriteBlocked(this);
232     return writer_->IsWriteBlockedDataBuffered();
233   } else if (result.status == WRITE_STATUS_ERROR) {
234     LOG(WARNING) << "Received unknown error while sending reset packet to "
235                  << queued_packet->client_address().ToString() << ": "
236                  << strerror(result.error_code);
237   }
238   return true;
239 }
240
241 void QuicTimeWaitListManager::SetConnectionIdCleanUpAlarm() {
242   connection_id_clean_up_alarm_->UnregisterIfRegistered();
243   int64 next_alarm_interval;
244   if (!connection_id_map_.empty()) {
245     QuicTime oldest_connection_id =
246         connection_id_map_.begin()->second.time_added;
247     QuicTime now = clock_.ApproximateNow();
248     if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) {
249       next_alarm_interval = oldest_connection_id.Add(kTimeWaitPeriod_)
250                                                 .Subtract(now)
251                                                 .ToMicroseconds();
252     } else {
253       LOG(ERROR) << "ConnectionId lingered for longer than kTimeWaitPeriod";
254       next_alarm_interval = 0;
255     }
256   } else {
257     // No connection_ids added so none will expire before kTimeWaitPeriod_.
258     next_alarm_interval = kTimeWaitPeriod_.ToMicroseconds();
259   }
260
261   epoll_server_->RegisterAlarmApproximateDelta(
262       next_alarm_interval, connection_id_clean_up_alarm_.get());
263 }
264
265 void QuicTimeWaitListManager::CleanUpOldConnectionIds() {
266   QuicTime now = clock_.ApproximateNow();
267   while (!connection_id_map_.empty()) {
268     ConnectionIdMap::iterator it = connection_id_map_.begin();
269     QuicTime oldest_connection_id = it->second.time_added;
270     if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) {
271       break;
272     }
273     // This connection_id has lived its age, retire it now.
274     delete it->second.close_packet;
275     connection_id_map_.erase(it);
276   }
277   SetConnectionIdCleanUpAlarm();
278 }
279
280 }  // namespace tools
281 }  // namespace net