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