Connect PPAPI IPC channels for non-SFI mode.
[chromium-blink-merge.git] / net / tools / quic / quic_time_wait_list_manager.cc
blobb145e8af14f3a2a9eb785ae821eba9e537211513
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.
5 #include "net/tools/quic/quic_time_wait_list_manager.h"
7 #include <errno.h>
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"
22 using base::StringPiece;
23 using std::make_pair;
25 namespace net {
26 namespace tools {
28 namespace {
30 // Time period for which the guid should live in time wait state..
31 const int kTimeWaitSeconds = 5;
33 } // namespace
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) {
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;
51 private:
52 // Not owned.
53 QuicTimeWaitListManager* time_wait_list_manager_;
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) {
73 const IPEndPoint& server_address() const { return server_address_; }
74 const IPEndPoint& client_address() const { return client_address_; }
75 QuicEncryptedPacket* packet() { return packet_.get(); }
77 private:
78 const IPEndPoint server_address_;
79 const IPEndPoint client_address_;
80 scoped_ptr<QuicEncryptedPacket> packet_;
82 DISALLOW_COPY_AND_ASSIGN(QueuedPacket);
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();
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;
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);
118 GuidData data(num_packets, version, clock_.ApproximateNow(), close_packet);
119 guid_map_.insert(make_pair(guid, data));
122 bool QuicTimeWaitListManager::IsGuidInTimeWait(QuicGuid guid) const {
123 return guid_map_.find(guid) != guid_map_.end();
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;
132 void QuicTimeWaitListManager::OnCanWrite() {
133 while (!pending_packets_queue_.empty()) {
134 QueuedPacket* queued_packet = pending_packets_queue_.front();
135 if (!WriteToWire(queued_packet)) {
136 return;
138 pending_packets_queue_.pop_front();
139 delete queued_packet;
143 void QuicTimeWaitListManager::ProcessPacket(
144 const IPEndPoint& server_address,
145 const IPEndPoint& client_address,
146 QuicGuid guid,
147 QuicPacketSequenceNumber sequence_number) {
148 DCHECK(IsGuidInTimeWait(guid));
149 // TODO(satyamshekhar): Think about handling packets from different client
150 // addresses.
151 GuidMap::iterator it = guid_map_.find(guid);
152 DCHECK(it != guid_map_.end());
153 // Increment the received packet count.
154 ++((it->second).num_packets);
155 if (!ShouldSendResponse((it->second).num_packets)) {
156 return;
158 if (it->second.close_packet) {
159 QueuedPacket* queued_packet =
160 new QueuedPacket(server_address,
161 client_address,
162 it->second.close_packet->Clone());
163 // Takes ownership of the packet.
164 SendOrQueuePacket(queued_packet);
165 } else {
166 SendPublicReset(server_address, client_address, guid, sequence_number);
170 // Returns true if the number of packets received for this guid is a power of 2
171 // to throttle the number of public reset packets we send to a client.
172 bool QuicTimeWaitListManager::ShouldSendResponse(int received_packet_count) {
173 return (received_packet_count & (received_packet_count - 1)) == 0;
176 void QuicTimeWaitListManager::SendPublicReset(
177 const IPEndPoint& server_address,
178 const IPEndPoint& client_address,
179 QuicGuid guid,
180 QuicPacketSequenceNumber rejected_sequence_number) {
181 QuicPublicResetPacket packet;
182 packet.public_header.guid = guid;
183 packet.public_header.reset_flag = true;
184 packet.public_header.version_flag = false;
185 packet.rejected_sequence_number = rejected_sequence_number;
186 // TODO(satyamshekhar): generate a valid nonce for this guid.
187 packet.nonce_proof = 1010101;
188 packet.client_address = client_address;
189 QueuedPacket* queued_packet = new QueuedPacket(
190 server_address,
191 client_address,
192 QuicFramer::BuildPublicResetPacket(packet));
193 // Takes ownership of the packet.
194 SendOrQueuePacket(queued_packet);
197 // Either sends the packet and deletes it or makes pending queue the
198 // owner of the packet.
199 void QuicTimeWaitListManager::SendOrQueuePacket(QueuedPacket* packet) {
200 if (WriteToWire(packet)) {
201 delete packet;
202 } else {
203 // pending_packets_queue takes the ownership of the queued packet.
204 pending_packets_queue_.push_back(packet);
208 bool QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) {
209 if (writer_->IsWriteBlocked()) {
210 visitor_->OnWriteBlocked(this);
211 return false;
213 WriteResult result = writer_->WritePacket(
214 queued_packet->packet()->data(),
215 queued_packet->packet()->length(),
216 queued_packet->server_address().address(),
217 queued_packet->client_address());
218 if (result.status == WRITE_STATUS_BLOCKED) {
219 // If blocked and unbuffered, return false to retry sending.
220 DCHECK(writer_->IsWriteBlocked());
221 visitor_->OnWriteBlocked(this);
222 return writer_->IsWriteBlockedDataBuffered();
223 } else if (result.status == WRITE_STATUS_ERROR) {
224 LOG(WARNING) << "Received unknown error while sending reset packet to "
225 << queued_packet->client_address().ToString() << ": "
226 << strerror(result.error_code);
228 return true;
231 void QuicTimeWaitListManager::SetGuidCleanUpAlarm() {
232 guid_clean_up_alarm_->UnregisterIfRegistered();
233 int64 next_alarm_interval;
234 if (!guid_map_.empty()) {
235 QuicTime oldest_guid = guid_map_.begin()->second.time_added;
236 QuicTime now = clock_.ApproximateNow();
237 if (now.Subtract(oldest_guid) < kTimeWaitPeriod_) {
238 next_alarm_interval = oldest_guid.Add(kTimeWaitPeriod_)
239 .Subtract(now)
240 .ToMicroseconds();
241 } else {
242 LOG(ERROR) << "GUID lingered for longer than kTimeWaitPeriod";
243 next_alarm_interval = 0;
245 } else {
246 // No guids added so none will expire before kTimeWaitPeriod_.
247 next_alarm_interval = kTimeWaitPeriod_.ToMicroseconds();
250 epoll_server_->RegisterAlarmApproximateDelta(next_alarm_interval,
251 guid_clean_up_alarm_.get());
254 void QuicTimeWaitListManager::CleanUpOldGuids() {
255 QuicTime now = clock_.ApproximateNow();
256 while (!guid_map_.empty()) {
257 GuidMap::iterator it = guid_map_.begin();
258 QuicTime oldest_guid = it->second.time_added;
259 if (now.Subtract(oldest_guid) < kTimeWaitPeriod_) {
260 break;
262 // This guid has lived its age, retire it now.
263 delete it->second.close_packet;
264 guid_map_.erase(it);
266 SetGuidCleanUpAlarm();
269 } // namespace tools
270 } // namespace net