1// Copyright 2013 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#ifndef NET_TOOLS_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_
6#define NET_TOOLS_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_
7
8#include <list>
9
10#include "base/basictypes.h"
11#include "base/logging.h"
12#include "base/memory/scoped_ptr.h"
13#include "base/synchronization/lock.h"
14#include "net/quic/quic_alarm.h"
15#include "net/quic/test_tools/quic_test_utils.h"
16#include "net/tools/quic/quic_epoll_clock.h"
17#include "net/tools/quic/quic_packet_writer_wrapper.h"
18#include "net/tools/quic/test_tools/quic_test_client.h"
19#include "net/tools/quic/test_tools/quic_test_utils.h"
20
21namespace net {
22namespace tools {
23namespace test {
24
25// Simulates a connection that drops packets a configured percentage of the time
26// and has a blocked socket a configured percentage of the time.  Also provides
27// the options to delay packets and reorder packets if delay is enabled.
28class PacketDroppingTestWriter : public QuicPacketWriterWrapper {
29 public:
30  class Delegate {
31   public:
32    virtual ~Delegate() {}
33    virtual void OnPacketSent(WriteResult result) = 0;
34    virtual void OnCanWrite() = 0;
35  };
36
37  PacketDroppingTestWriter();
38
39  virtual ~PacketDroppingTestWriter();
40
41  // Must be called before blocking, reordering or delaying (loss is OK). May be
42  // called after connecting if the helper is not available before.
43  // |on_can_write| will be triggered when fake-unblocking; ownership will be
44  // assumed.
45  void Initialize(QuicEpollConnectionHelper* helper, Delegate* on_can_write);
46
47  // QuicPacketWriter methods:
48  virtual WriteResult WritePacket(
49      const char* buffer,
50      size_t buf_len,
51      const IPAddressNumber& self_address,
52      const IPEndPoint& peer_address) OVERRIDE;
53
54  virtual bool IsWriteBlocked() const OVERRIDE;
55
56  virtual void SetWritable() OVERRIDE;
57
58  // Writes out any packet which should have been sent by now
59  // to the contained writer and returns the time
60  // for the next delayed packet to be written.
61  QuicTime ReleaseOldPackets();
62
63  void OnCanWrite();
64
65  // The percent of time a packet is simulated as being lost.
66  void set_fake_packet_loss_percentage(int32 fake_packet_loss_percentage) {
67    base::AutoLock locked(config_mutex_);
68    fake_packet_loss_percentage_ = fake_packet_loss_percentage;
69  }
70
71  // The percent of time WritePacket will block and set WriteResult's status
72  // to WRITE_STATUS_BLOCKED.
73  void set_fake_blocked_socket_percentage(
74      int32 fake_blocked_socket_percentage) {
75    DCHECK(clock_);
76    base::AutoLock locked(config_mutex_);
77    fake_blocked_socket_percentage_  = fake_blocked_socket_percentage;
78  }
79
80  // The percent of time a packet is simulated as being reordered.
81  void set_fake_reorder_percentage(int32 fake_packet_reorder_percentage) {
82    DCHECK(clock_);
83    base::AutoLock locked(config_mutex_);
84    DCHECK(!fake_packet_delay_.IsZero());
85    fake_packet_reorder_percentage_ = fake_packet_reorder_percentage;
86  }
87
88  // The percent of time WritePacket will block and set WriteResult's status
89  // to WRITE_STATUS_BLOCKED.
90  void set_fake_packet_delay(QuicTime::Delta fake_packet_delay) {
91    DCHECK(clock_);
92    base::AutoLock locked(config_mutex_);
93    fake_packet_delay_  = fake_packet_delay;
94  }
95
96  // The maximum bandwidth and buffer size of the connection.  When these are
97  // set, packets will be delayed until a connection with that bandwidth would
98  // transmit it.  Once the |buffer_size| is reached, all new packets are
99  // dropped.
100  void set_max_bandwidth_and_buffer_size(QuicBandwidth fake_bandwidth,
101                                         QuicByteCount buffer_size) {
102    DCHECK(clock_);
103    base::AutoLock locked(config_mutex_);
104    fake_bandwidth_ = fake_bandwidth;
105    buffer_size_ = buffer_size;
106  }
107
108  void set_seed(uint64 seed) {
109    simple_random_.set_seed(seed);
110  }
111
112 private:
113  // Writes out the next packet to the contained writer and returns the time
114  // for the next delayed packet to be written.
115  QuicTime ReleaseNextPacket();
116
117  // A single packet which will be sent at the supplied send_time.
118  struct DelayedWrite {
119   public:
120    DelayedWrite(const char* buffer,
121                 size_t buf_len,
122                 const IPAddressNumber& self_address,
123                 const IPEndPoint& peer_address,
124                 QuicTime send_time);
125    ~DelayedWrite();
126
127    string buffer;
128    const IPAddressNumber self_address;
129    const IPEndPoint peer_address;
130    QuicTime send_time;
131  };
132
133  typedef std::list<DelayedWrite> DelayedPacketList;
134
135  const QuicClock* clock_;
136  scoped_ptr<QuicAlarm> write_unblocked_alarm_;
137  scoped_ptr<QuicAlarm> delay_alarm_;
138  scoped_ptr<Delegate> on_can_write_;
139  net::test::SimpleRandom simple_random_;
140  // Stored packets delayed by fake packet delay or bandwidth restrictions.
141  DelayedPacketList delayed_packets_;
142  QuicByteCount cur_buffer_size_;
143
144  base::Lock config_mutex_;
145  int32 fake_packet_loss_percentage_;
146  int32 fake_blocked_socket_percentage_;
147  int32 fake_packet_reorder_percentage_;
148  QuicTime::Delta fake_packet_delay_;
149  QuicBandwidth fake_bandwidth_;
150  QuicByteCount buffer_size_;
151
152  DISALLOW_COPY_AND_ASSIGN(PacketDroppingTestWriter);
153};
154
155}  // namespace test
156}  // namespace tools
157}  // namespace net
158
159#endif  // NET_TOOLS_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_
160