1 // Copyright 2014 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 MEDIA_CAST_TEST_UTILITY_UDP_PROXY_H_ 6 #define MEDIA_CAST_TEST_UTILITY_UDP_PROXY_H_ 7 8 #include <vector> 9 10 #include "base/basictypes.h" 11 #include "base/memory/linked_ptr.h" 12 #include "base/memory/ref_counted.h" 13 #include "base/memory/scoped_ptr.h" 14 #include "base/memory/weak_ptr.h" 15 #include "base/single_thread_task_runner.h" 16 #include "media/cast/net/cast_transport_config.h" 17 #include "net/base/ip_endpoint.h" 18 #include "third_party/mt19937ar/mt19937ar.h" 19 20 namespace net { 21 class NetLog; 22 }; 23 24 namespace base { 25 class TickClock; 26 }; 27 28 namespace media { 29 namespace cast { 30 namespace test { 31 32 class PacketPipe { 33 public: 34 PacketPipe(); 35 virtual ~PacketPipe(); 36 virtual void Send(scoped_ptr<Packet> packet) = 0; 37 // Allows injection of fake test runner for testing. 38 virtual void InitOnIOThread( 39 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 40 base::TickClock* clock); 41 virtual void AppendToPipe(scoped_ptr<PacketPipe> pipe); 42 protected: 43 scoped_ptr<PacketPipe> pipe_; 44 // Allows injection of fake task runner for testing. 45 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 46 base::TickClock* clock_; 47 }; 48 49 // Implements a Interrupted Poisson Process for packet delivery. 50 // The process has 2 states: ON and OFF, the rate of switching between 51 // these two states are defined. 52 // When in ON state packets are sent according to a defined rate. 53 // When in OFF state packets are not sent. 54 // The rate above is the average rate of a poisson distribution. 55 class InterruptedPoissonProcess { 56 public: 57 InterruptedPoissonProcess( 58 const std::vector<double>& average_rates, 59 double coef_burstiness, 60 double coef_variance, 61 uint32 rand_seed); 62 ~InterruptedPoissonProcess(); 63 64 scoped_ptr<PacketPipe> NewBuffer(size_t size); 65 66 private: 67 class InternalBuffer; 68 69 // |task_runner| is the executor of the IO thread. 70 // |clock| is the system clock. 71 void InitOnIOThread( 72 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 73 base::TickClock* clock); 74 75 base::TimeDelta NextEvent(double rate); 76 double RandDouble(); 77 void ComputeRates(); 78 void UpdateRates(); 79 void SwitchOff(); 80 void SwitchOn(); 81 void SendPacket(); 82 83 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 84 base::TickClock* clock_; 85 const std::vector<double> average_rates_; 86 const double coef_burstiness_; 87 const double coef_variance_; 88 int rate_index_; 89 90 // The following rates are per milliseconds. 91 double send_rate_; 92 double switch_off_rate_; 93 double switch_on_rate_; 94 bool on_state_; 95 96 std::vector<base::WeakPtr<InternalBuffer> > send_buffers_; 97 98 // Fast pseudo random number generator. 99 MersenneTwister mt_rand_; 100 101 base::WeakPtrFactory<InterruptedPoissonProcess> weak_factory_; 102 103 DISALLOW_COPY_AND_ASSIGN(InterruptedPoissonProcess); 104 }; 105 106 // A UDPProxy will set up a UDP socket and bind to |local_port|. 107 // Packets send to that port will be forwarded to |destination|. 108 // Packets send from |destination| to |local_port| will be returned 109 // to whoever sent a packet to |local_port| last. (Not counting packets 110 // from |destination|.) The UDPProxy will run a separate thread to 111 // do the forwarding of packets, and will keep doing so until destroyed. 112 // You can insert delays and packet drops by supplying a PacketPipe. 113 // The PacketPipes may also be NULL if you just want to forward packets. 114 class UDPProxy { 115 public: 116 virtual ~UDPProxy() {} 117 static scoped_ptr<UDPProxy> Create(const net::IPEndPoint& local_port, 118 const net::IPEndPoint& destination, 119 scoped_ptr<PacketPipe> to_dest_pipe, 120 scoped_ptr<PacketPipe> from_dest_pipe, 121 net::NetLog* net_log); 122 }; 123 124 // The following functions create PacketPipes which can be linked 125 // together (with AppendToPipe) and passed into UdpProxy::Create below. 126 127 // This PacketPipe emulates a buffer of a given size. Limits our output 128 // from the buffer at a rate given by |bandwidth| (in megabits per second). 129 // Packets entering the buffer will be dropped if there is not enough 130 // room for them. 131 scoped_ptr<PacketPipe> NewBuffer(size_t buffer_size, double bandwidth); 132 133 // Randomly drops |drop_fraction|*100% of packets. 134 scoped_ptr<PacketPipe> NewRandomDrop(double drop_fraction); 135 136 // Delays each packet by |delay_seconds|. 137 scoped_ptr<PacketPipe> NewConstantDelay(double delay_seconds); 138 139 // Delays packets by a random amount between zero and |delay|. 140 // This PacketPipe can reorder packets. 141 scoped_ptr<PacketPipe> NewRandomUnsortedDelay(double delay); 142 143 // Duplicates every packet, one is transmitted immediately, 144 // one is transmitted after a random delay between |delay_min| 145 // and |delay_min + random_delay|. 146 // This PacketPipe will reorder packets. 147 scoped_ptr<PacketPipe> NewDuplicateAndDelay(double delay_min, 148 double random_delay); 149 150 // This PacketPipe inserts a random delay between each packet. 151 // This PacketPipe cannot re-order packets. The delay between each 152 // packet is asically |min_delay| + random( |random_delay| ) 153 // However, every now and then a delay of |big_delay| will be 154 // inserted (roughly every |seconds_between_big_delay| seconds). 155 scoped_ptr<PacketPipe> NewRandomSortedDelay(double random_delay, 156 double big_delay, 157 double seconds_between_big_delay); 158 159 // This PacketPipe emulates network outages. It basically waits 160 // for 0-2*|average_work_time| seconds, then kills the network for 161 // 0-|2*average_outage_time| seconds. Then it starts over again. 162 scoped_ptr<PacketPipe> NewNetworkGlitchPipe(double average_work_time, 163 double average_outage_time); 164 165 // This method builds a stack of PacketPipes to emulate a reasonably 166 // good network. ~50mbit, ~3ms latency, no packet loss unless saturated. 167 scoped_ptr<PacketPipe> GoodNetwork(); 168 169 // This method builds a stack of PacketPipes to emulate a reasonably 170 // good wifi network. ~20mbit, 1% packet loss, ~3ms latency. 171 scoped_ptr<PacketPipe> WifiNetwork(); 172 173 // This method builds a stack of PacketPipes to emulate a 174 // bad wifi network. ~5mbit, 5% packet loss, ~7ms latency 175 // 40ms dropouts every ~2 seconds. Can reorder packets. 176 scoped_ptr<PacketPipe> BadNetwork(); 177 178 // This method builds a stack of PacketPipes to emulate a crappy wifi network. 179 // ~2mbit, 20% packet loss, ~40ms latency and packets can get reordered. 180 // 300ms drouputs every ~2 seconds. 181 scoped_ptr<PacketPipe> EvilNetwork(); 182 183 } // namespace test 184 } // namespace cast 185 } // namespace media 186 187 #endif // MEDIA_CAST_TEST_UTILITY_UDP_PROXY_H_ 188