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.
10 #include "base/at_exit.h"
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/lazy_instance.h"
14 #include "base/logging.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/thread_task_runner_handle.h"
18 #include "media/cast/test/utility/udp_proxy.h"
22 ByteCounter() : bytes_(0), packets_(0) {
23 push(base::TimeTicks::Now());
26 base::TimeDelta
time_range() {
27 return time_data_
.back() - time_data_
.front();
30 void push(base::TimeTicks now
) {
31 byte_data_
.push_back(bytes_
);
32 packet_data_
.push_back(packets_
);
33 time_data_
.push_back(now
);
34 while (time_range().InSeconds() > 10) {
35 byte_data_
.pop_front();
36 packet_data_
.pop_front();
37 time_data_
.pop_front();
41 double megabits_per_second() {
42 double megabits
= (byte_data_
.back() - byte_data_
.front()) * 8 / 1E6
;
43 return megabits
/ time_range().InSecondsF();
46 double packets_per_second() {
47 double packets
= packet_data_
.back()- packet_data_
.front();
48 return packets
/ time_range().InSecondsF();
51 void Increment(uint64 x
) {
59 std::deque
<uint64
> byte_data_
;
60 std::deque
<uint64
> packet_data_
;
61 std::deque
<base::TimeTicks
> time_data_
;
65 struct GlobalCounter
{
66 base::TimeTicks last_printout
;
67 ByteCounter in_pipe_input_counter
;
68 ByteCounter in_pipe_output_counter
;
69 ByteCounter out_pipe_input_counter
;
70 ByteCounter out_pipe_output_counter
;
74 base::LazyInstance
<GlobalCounter
>::Leaky g_counter
=
75 LAZY_INSTANCE_INITIALIZER
;
77 class ByteCounterPipe
: public media::cast::test::PacketPipe
{
79 ByteCounterPipe(ByteCounter
* counter
) : counter_(counter
) {}
80 void Send(scoped_ptr
<media::cast::Packet
> packet
) final
{
81 counter_
->Increment(packet
->size());
82 pipe_
->Send(packet
.Pass());
85 ByteCounter
* counter_
;
88 void SetupByteCounters(scoped_ptr
<media::cast::test::PacketPipe
>* pipe
,
89 ByteCounter
* pipe_input_counter
,
90 ByteCounter
* pipe_output_counter
) {
91 media::cast::test::PacketPipe
* new_pipe
=
92 new ByteCounterPipe(pipe_input_counter
);
93 new_pipe
->AppendToPipe(pipe
->Pass());
94 new_pipe
->AppendToPipe(
95 scoped_ptr
<media::cast::test::PacketPipe
>(
96 new ByteCounterPipe(pipe_output_counter
)).Pass());
97 pipe
->reset(new_pipe
);
100 void CheckByteCounters() {
101 base::TimeTicks now
= base::TimeTicks::Now();
102 g_counter
.Get().in_pipe_input_counter
.push(now
);
103 g_counter
.Get().in_pipe_output_counter
.push(now
);
104 g_counter
.Get().out_pipe_input_counter
.push(now
);
105 g_counter
.Get().out_pipe_output_counter
.push(now
);
106 if ((now
- g_counter
.Get().last_printout
).InSeconds() >= 5) {
107 fprintf(stderr
, "Sending : %5.2f / %5.2f mbps %6.2f / %6.2f packets / s\n",
108 g_counter
.Get().in_pipe_output_counter
.megabits_per_second(),
109 g_counter
.Get().in_pipe_input_counter
.megabits_per_second(),
110 g_counter
.Get().in_pipe_output_counter
.packets_per_second(),
111 g_counter
.Get().in_pipe_input_counter
.packets_per_second());
112 fprintf(stderr
, "Receiving: %5.2f / %5.2f mbps %6.2f / %6.2f packets / s\n",
113 g_counter
.Get().out_pipe_output_counter
.megabits_per_second(),
114 g_counter
.Get().out_pipe_input_counter
.megabits_per_second(),
115 g_counter
.Get().out_pipe_output_counter
.packets_per_second(),
116 g_counter
.Get().out_pipe_input_counter
.packets_per_second());
118 g_counter
.Get().last_printout
= now
;
120 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
122 base::Bind(&CheckByteCounters
),
123 base::TimeDelta::FromMilliseconds(100));
126 int main(int argc
, char** argv
) {
127 base::AtExitManager at_exit
;
128 base::CommandLine::Init(argc
, argv
);
129 logging::LoggingSettings settings
;
130 settings
.logging_dest
= logging::LOG_TO_SYSTEM_DEBUG_LOG
;
131 InitLogging(settings
);
133 if (argc
!= 5 && argc
!= 3) {
135 "Usage: udp_proxy <localport> <remotehost> <remoteport> <type>\n"
137 " udp_proxy <localport> <type>\n"
138 "Where type is one of: perfect, wifi, bad, evil, poisson-wifi\n");
142 net::IPAddressNumber remote_ip_number
;
143 net::IPAddressNumber local_ip_number
;
144 std::string network_type
;
145 int local_port
= atoi(argv
[1]);
147 CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &local_ip_number
));
151 CHECK(net::ParseIPLiteralToNumber(argv
[2], &remote_ip_number
));
152 remote_port
= atoi(argv
[3]);
153 network_type
= argv
[4];
156 network_type
= argv
[2];
158 if (local_port
< 0 || local_port
> 65535 || remote_port
< 0 ||
159 remote_port
> 65535) {
160 fprintf(stderr
, "Port numbers must be between 0 and 65535\n");
163 net::IPEndPoint
remote_endpoint(remote_ip_number
,
164 static_cast<uint16
>(remote_port
));
165 net::IPEndPoint
local_endpoint(local_ip_number
,
166 static_cast<uint16
>(local_port
));
167 scoped_ptr
<media::cast::test::PacketPipe
> in_pipe
, out_pipe
;
168 scoped_ptr
<media::cast::test::InterruptedPoissonProcess
> ipp(
169 media::cast::test::DefaultInterruptedPoissonProcess());
171 if (network_type
== "perfect") {
173 } else if (network_type
== "wifi") {
174 in_pipe
= media::cast::test::WifiNetwork().Pass();
175 out_pipe
= media::cast::test::WifiNetwork().Pass();
176 } else if (network_type
== "bad") {
177 in_pipe
= media::cast::test::BadNetwork().Pass();
178 out_pipe
= media::cast::test::BadNetwork().Pass();
179 } else if (network_type
== "evil") {
180 in_pipe
= media::cast::test::EvilNetwork().Pass();
181 out_pipe
= media::cast::test::EvilNetwork().Pass();
182 } else if (network_type
== "poisson-wifi") {
183 in_pipe
= ipp
->NewBuffer(128 * 1024).Pass();
184 out_pipe
= ipp
->NewBuffer(128 * 1024).Pass();
186 fprintf(stderr
, "Unknown network type.\n");
190 SetupByteCounters(&in_pipe
, &(g_counter
.Get().in_pipe_input_counter
),
191 &(g_counter
.Get().in_pipe_output_counter
));
193 &out_pipe
, &(g_counter
.Get().out_pipe_input_counter
),
194 &(g_counter
.Get().out_pipe_output_counter
));
196 printf("Press Ctrl-C when done.\n");
197 scoped_ptr
<media::cast::test::UDPProxy
> proxy(
198 media::cast::test::UDPProxy::Create(local_endpoint
,
203 base::MessageLoop message_loop
;
204 g_counter
.Get().last_printout
= base::TimeTicks::Now();