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 #include <cstdio> 6 #include <cstdlib> 7 #include <deque> 8 #include <string> 9 10 #include "base/at_exit.h" 11 #include "base/bind.h" 12 #include "base/command_line.h" 13 #include "base/logging.h" 14 #include "base/message_loop/message_loop.h" 15 #include "media/cast/test/utility/udp_proxy.h" 16 17 base::TimeTicks last_printout; 18 19 class ByteCounter { 20 public: 21 ByteCounter() : bytes_(0), packets_(0) { 22 push(base::TimeTicks::Now()); 23 } 24 25 base::TimeDelta time_range() { 26 return time_data_.back() - time_data_.front(); 27 } 28 29 void push(base::TimeTicks now) { 30 byte_data_.push_back(bytes_); 31 packet_data_.push_back(packets_); 32 time_data_.push_back(now); 33 while (time_range().InSeconds() > 10) { 34 byte_data_.pop_front(); 35 packet_data_.pop_front(); 36 time_data_.pop_front(); 37 } 38 } 39 40 double megabits_per_second() { 41 double megabits = (byte_data_.back() - byte_data_.front()) * 8 / 1E6; 42 return megabits / time_range().InSecondsF(); 43 } 44 45 double packets_per_second() { 46 double packets = packet_data_.back()- packet_data_.front(); 47 return packets / time_range().InSecondsF(); 48 } 49 50 void Increment(uint64 x) { 51 bytes_ += x; 52 packets_ ++; 53 } 54 55 private: 56 uint64 bytes_; 57 uint64 packets_; 58 std::deque<uint64> byte_data_; 59 std::deque<uint64> packet_data_; 60 std::deque<base::TimeTicks> time_data_; 61 }; 62 63 ByteCounter in_pipe_input_counter; 64 ByteCounter in_pipe_output_counter; 65 ByteCounter out_pipe_input_counter; 66 ByteCounter out_pipe_output_counter; 67 68 class ByteCounterPipe : public media::cast::test::PacketPipe { 69 public: 70 ByteCounterPipe(ByteCounter* counter) : counter_(counter) {} 71 virtual void Send(scoped_ptr<media::cast::Packet> packet) 72 OVERRIDE { 73 counter_->Increment(packet->size()); 74 pipe_->Send(packet.Pass()); 75 } 76 private: 77 ByteCounter* counter_; 78 }; 79 80 void SetupByteCounters(scoped_ptr<media::cast::test::PacketPipe>* pipe, 81 ByteCounter* pipe_input_counter, 82 ByteCounter* pipe_output_counter) { 83 media::cast::test::PacketPipe* new_pipe = 84 new ByteCounterPipe(pipe_input_counter); 85 new_pipe->AppendToPipe(pipe->Pass()); 86 new_pipe->AppendToPipe( 87 scoped_ptr<media::cast::test::PacketPipe>( 88 new ByteCounterPipe(pipe_output_counter)).Pass()); 89 pipe->reset(new_pipe); 90 } 91 92 void CheckByteCounters() { 93 base::TimeTicks now = base::TimeTicks::Now(); 94 in_pipe_input_counter.push(now); 95 in_pipe_output_counter.push(now); 96 out_pipe_input_counter.push(now); 97 out_pipe_output_counter.push(now); 98 if ((now - last_printout).InSeconds() >= 5) { 99 fprintf(stderr, "Sending : %5.2f / %5.2f mbps %6.2f / %6.2f packets / s\n", 100 in_pipe_output_counter.megabits_per_second(), 101 in_pipe_input_counter.megabits_per_second(), 102 in_pipe_output_counter.packets_per_second(), 103 in_pipe_input_counter.packets_per_second()); 104 fprintf(stderr, "Receiving: %5.2f / %5.2f mbps %6.2f / %6.2f packets / s\n", 105 out_pipe_output_counter.megabits_per_second(), 106 out_pipe_input_counter.megabits_per_second(), 107 out_pipe_output_counter.packets_per_second(), 108 out_pipe_input_counter.packets_per_second()); 109 110 last_printout = now; 111 } 112 base::MessageLoopProxy::current()->PostDelayedTask( 113 FROM_HERE, 114 base::Bind(&CheckByteCounters), 115 base::TimeDelta::FromMilliseconds(100)); 116 } 117 118 int main(int argc, char** argv) { 119 if (argc != 5 && argc != 3) { 120 fprintf(stderr, 121 "Usage: udp_proxy <localport> <remotehost> <remoteport> <type>\n" 122 "or:\n" 123 " udp_proxy <localport> <type>\n" 124 "Where type is one of: perfect, wifi, bad, evil\n"); 125 exit(1); 126 } 127 128 base::AtExitManager exit_manager; 129 CommandLine::Init(argc, argv); 130 InitLogging(logging::LoggingSettings()); 131 132 net::IPAddressNumber remote_ip_number; 133 net::IPAddressNumber local_ip_number; 134 std::string network_type; 135 int local_port = atoi(argv[1]); 136 int remote_port = 0; 137 CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &local_ip_number)); 138 139 if (argc == 5) { 140 // V2 proxy 141 CHECK(net::ParseIPLiteralToNumber(argv[2], &remote_ip_number)); 142 remote_port = atoi(argv[3]); 143 network_type = argv[4]; 144 } else { 145 // V1 proxy 146 network_type = argv[2]; 147 } 148 net::IPEndPoint remote_endpoint(remote_ip_number, remote_port); 149 net::IPEndPoint local_endpoint(local_ip_number, local_port); 150 scoped_ptr<media::cast::test::PacketPipe> in_pipe, out_pipe; 151 152 if (network_type == "perfect") { 153 // No action needed. 154 } else if (network_type == "wifi") { 155 in_pipe = media::cast::test::WifiNetwork().Pass(); 156 out_pipe = media::cast::test::WifiNetwork().Pass(); 157 } else if (network_type == "bad") { 158 in_pipe = media::cast::test::BadNetwork().Pass(); 159 out_pipe = media::cast::test::BadNetwork().Pass(); 160 } else if (network_type == "evil") { 161 in_pipe = media::cast::test::EvilNetwork().Pass(); 162 out_pipe = media::cast::test::EvilNetwork().Pass(); 163 } else { 164 fprintf(stderr, "Unknown network type.\n"); 165 exit(1); 166 } 167 168 SetupByteCounters(&in_pipe, &in_pipe_input_counter, &in_pipe_output_counter); 169 SetupByteCounters( 170 &out_pipe, &out_pipe_input_counter, &out_pipe_output_counter); 171 172 printf("Press Ctrl-C when done.\n"); 173 scoped_ptr<media::cast::test::UDPProxy> proxy( 174 media::cast::test::UDPProxy::Create(local_endpoint, 175 remote_endpoint, 176 in_pipe.Pass(), 177 out_pipe.Pass(), 178 NULL)); 179 base::MessageLoop message_loop; 180 last_printout = base::TimeTicks::Now(); 181 CheckByteCounters(); 182 message_loop.Run(); 183 return 1; 184 } 185