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.
6 #include <linux/if_tun.h>
7 #include <linux/types.h>
10 #include <netinet/in.h>
13 #include <sys/ioctl.h>
15 #include <sys/types.h>
21 #include "base/at_exit.h"
22 #include "base/bind.h"
23 #include "base/command_line.h"
24 #include "base/logging.h"
25 #include "base/rand_util.h"
26 #include "base/single_thread_task_runner.h"
27 #include "base/synchronization/waitable_event.h"
28 #include "base/thread_task_runner_handle.h"
29 #include "base/threading/thread.h"
30 #include "base/time/default_tick_clock.h"
31 #include "media/cast/test/utility/udp_proxy.h"
32 #include "net/base/io_buffer.h"
33 #include "net/base/net_errors.h"
34 #include "net/udp/udp_socket.h"
40 const size_t kMaxPacketSize
= 4096;
42 class SendToFDPipe
: public PacketPipe
{
44 explicit SendToFDPipe(int fd
) : fd_(fd
) {
46 void Send(scoped_ptr
<Packet
> packet
) final
{
50 reinterpret_cast<char*>(&packet
->front()),
53 if (errno
== EINTR
) continue;
57 if (written
!= static_cast<int>(packet
->size())) {
58 fprintf(stderr
, "Truncated write!\n");
68 class QueueManager
: public base::MessageLoopForIO::Watcher
{
70 QueueManager(int input_fd
,
72 scoped_ptr
<PacketPipe
> pipe
) :
74 packet_pipe_(pipe
.Pass()) {
76 CHECK(base::MessageLoopForIO::current()->WatchFileDescriptor(
77 input_fd_
, true, base::MessageLoopForIO::WATCH_READ
,
78 &read_socket_watcher_
, this));
80 scoped_ptr
<PacketPipe
> tmp(new SendToFDPipe(output_fd
));
82 packet_pipe_
->AppendToPipe(tmp
.Pass());
84 packet_pipe_
= tmp
.Pass();
86 packet_pipe_
->InitOnIOThread(base::ThreadTaskRunnerHandle::Get(),
90 ~QueueManager() final
{}
92 // MessageLoopForIO::Watcher methods
93 void OnFileCanReadWithoutBlocking(int fd
) final
{
94 scoped_ptr
<Packet
> packet(new Packet(kMaxPacketSize
));
95 int nread
= read(input_fd_
,
96 reinterpret_cast<char*>(&packet
->front()),
99 if (errno
== EINTR
) return;
103 if (nread
== 0) return;
104 packet
->resize(nread
);
105 packet_pipe_
->Send(packet
.Pass());
107 void OnFileCanWriteWithoutBlocking(int fd
) final
{ NOTREACHED(); }
111 scoped_ptr
<PacketPipe
> packet_pipe_
;
112 base::MessageLoopForIO::FileDescriptorWatcher read_socket_watcher_
;
113 base::DefaultTickClock tick_clock_
;
120 base::TimeTicks last_printout
;
124 ByteCounter() : bytes_(0), packets_(0) {
125 push(base::TimeTicks::Now());
128 base::TimeDelta
time_range() {
129 return time_data_
.back() - time_data_
.front();
132 void push(base::TimeTicks now
) {
133 byte_data_
.push_back(bytes_
);
134 packet_data_
.push_back(packets_
);
135 time_data_
.push_back(now
);
136 while (time_range().InSeconds() > 10) {
137 byte_data_
.pop_front();
138 packet_data_
.pop_front();
139 time_data_
.pop_front();
143 double megabits_per_second() {
144 double megabits
= (byte_data_
.back() - byte_data_
.front()) * 8 / 1E6
;
145 return megabits
/ time_range().InSecondsF();
148 double packets_per_second() {
149 double packets
= packet_data_
.back()- packet_data_
.front();
150 return packets
/ time_range().InSecondsF();
153 void Increment(uint64 x
) {
161 std::deque
<uint64
> byte_data_
;
162 std::deque
<uint64
> packet_data_
;
163 std::deque
<base::TimeTicks
> time_data_
;
166 ByteCounter in_pipe_input_counter
;
167 ByteCounter in_pipe_output_counter
;
168 ByteCounter out_pipe_input_counter
;
169 ByteCounter out_pipe_output_counter
;
171 class ByteCounterPipe
: public media::cast::test::PacketPipe
{
173 ByteCounterPipe(ByteCounter
* counter
) : counter_(counter
) {}
174 void Send(scoped_ptr
<media::cast::Packet
> packet
) final
{
175 counter_
->Increment(packet
->size());
176 pipe_
->Send(packet
.Pass());
179 ByteCounter
* counter_
;
182 void SetupByteCounters(scoped_ptr
<media::cast::test::PacketPipe
>* pipe
,
183 ByteCounter
* pipe_input_counter
,
184 ByteCounter
* pipe_output_counter
) {
185 media::cast::test::PacketPipe
* new_pipe
=
186 new ByteCounterPipe(pipe_input_counter
);
187 new_pipe
->AppendToPipe(pipe
->Pass());
188 new_pipe
->AppendToPipe(
189 scoped_ptr
<media::cast::test::PacketPipe
>(
190 new ByteCounterPipe(pipe_output_counter
)).Pass());
191 pipe
->reset(new_pipe
);
194 void CheckByteCounters() {
195 base::TimeTicks now
= base::TimeTicks::Now();
196 in_pipe_input_counter
.push(now
);
197 in_pipe_output_counter
.push(now
);
198 out_pipe_input_counter
.push(now
);
199 out_pipe_output_counter
.push(now
);
200 if ((now
- last_printout
).InSeconds() >= 5) {
201 fprintf(stderr
, "Sending : %5.2f / %5.2f mbps %6.2f / %6.2f packets / s\n",
202 in_pipe_output_counter
.megabits_per_second(),
203 in_pipe_input_counter
.megabits_per_second(),
204 in_pipe_output_counter
.packets_per_second(),
205 in_pipe_input_counter
.packets_per_second());
206 fprintf(stderr
, "Receiving: %5.2f / %5.2f mbps %6.2f / %6.2f packets / s\n",
207 out_pipe_output_counter
.megabits_per_second(),
208 out_pipe_input_counter
.megabits_per_second(),
209 out_pipe_output_counter
.packets_per_second(),
210 out_pipe_input_counter
.packets_per_second());
214 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
216 base::Bind(&CheckByteCounters
),
217 base::TimeDelta::FromMilliseconds(100));
220 int tun_alloc(char *dev
, int flags
) {
223 const char *clonedev
= "/dev/net/tun";
225 /* Arguments taken by the function:
227 * char *dev: the name of an interface (or '\0'). MUST have enough
228 * space to hold the interface name if '\0' is passed
229 * int flags: interface flags (eg, IFF_TUN etc.)
232 /* open the clone device */
233 if( (fd
= open(clonedev
, O_RDWR
)) < 0 ) {
237 /* preparation of the struct ifr, of type "struct ifreq" */
238 memset(&ifr
, 0, sizeof(ifr
));
240 ifr
.ifr_flags
= flags
; /* IFF_TUN or IFF_TAP, plus maybe IFF_NO_PI */
243 /* if a device name was specified, put it in the structure; otherwise,
244 * the kernel will try to allocate the "next" device of the
246 strncpy(ifr
.ifr_name
, dev
, IFNAMSIZ
);
249 /* try to create the device */
250 if( (err
= ioctl(fd
, TUNSETIFF
, (void *) &ifr
)) < 0 ) {
256 /* if the operation was successful, write back the name of the
257 * interface to the variable "dev", so the caller can know
258 * it. Note that the caller MUST reserve space in *dev (see calling
260 strcpy(dev
, ifr
.ifr_name
);
263 /* this is the special file descriptor that the caller will use to talk
264 * with the virtual interface */
269 int main(int argc
, char **argv
) {
270 base::AtExitManager exit_manager
;
271 base::CommandLine::Init(argc
, argv
);
272 InitLogging(logging::LoggingSettings());
275 fprintf(stderr
, "Usage: tap_proxy tap1 tap2 type\n");
277 "Where 'type' is one of perfect, good, wifi, bad or evil\n");
281 scoped_ptr
<media::cast::test::PacketPipe
> in_pipe
, out_pipe
;
282 std::string network_type
= argv
[3];
283 if (network_type
== "perfect") {
285 } else if (network_type
== "good") {
286 in_pipe
= media::cast::test::GoodNetwork().Pass();
287 out_pipe
= media::cast::test::GoodNetwork().Pass();
288 } else if (network_type
== "wifi") {
289 in_pipe
= media::cast::test::WifiNetwork().Pass();
290 out_pipe
= media::cast::test::WifiNetwork().Pass();
291 } else if (network_type
== "bad") {
292 in_pipe
= media::cast::test::BadNetwork().Pass();
293 out_pipe
= media::cast::test::BadNetwork().Pass();
294 } else if (network_type
== "evil") {
295 in_pipe
= media::cast::test::EvilNetwork().Pass();
296 out_pipe
= media::cast::test::EvilNetwork().Pass();
298 fprintf(stderr
, "Unknown network type.\n");
302 SetupByteCounters(&in_pipe
, &in_pipe_input_counter
, &in_pipe_output_counter
);
304 &out_pipe
, &out_pipe_input_counter
, &out_pipe_output_counter
);
306 int fd1
= tun_alloc(argv
[1], IFF_TAP
);
307 int fd2
= tun_alloc(argv
[2], IFF_TAP
);
309 base::MessageLoopForIO message_loop
;
310 last_printout
= base::TimeTicks::Now();
311 media::cast::test::QueueManager
qm1(fd1
, fd2
, in_pipe
.Pass());
312 media::cast::test::QueueManager
qm2(fd2
, fd1
, out_pipe
.Pass());
314 printf("Press Ctrl-C when done.\n");