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 <fcntl.h> 6 #include <linux/if_tun.h> 7 #include <linux/types.h> 8 #include <math.h> 9 #include <net/if.h> 10 #include <netinet/in.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <sys/ioctl.h> 14 #include <sys/stat.h> 15 #include <sys/types.h> 16 #include <unistd.h> 17 18 #include <deque> 19 #include <map> 20 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/synchronization/waitable_event.h" 27 #include "base/threading/thread.h" 28 #include "base/time/default_tick_clock.h" 29 #include "media/cast/test/utility/udp_proxy.h" 30 #include "net/base/io_buffer.h" 31 #include "net/base/net_errors.h" 32 #include "net/udp/udp_socket.h" 33 34 namespace media { 35 namespace cast { 36 namespace test { 37 38 const size_t kMaxPacketSize = 4096; 39 40 class SendToFDPipe : public PacketPipe { 41 public: 42 explicit SendToFDPipe(int fd) : fd_(fd) { 43 } 44 virtual void Send(scoped_ptr<Packet> packet) OVERRIDE { 45 while (1) { 46 int written = write( 47 fd_, 48 reinterpret_cast<char*>(&packet->front()), 49 packet->size()); 50 if (written < 0) { 51 if (errno == EINTR) continue; 52 perror("write"); 53 exit(1); 54 } 55 if (written != static_cast<int>(packet->size())) { 56 fprintf(stderr, "Truncated write!\n"); 57 exit(1); 58 } 59 break; 60 } 61 } 62 private: 63 int fd_; 64 }; 65 66 class QueueManager : public base::MessageLoopForIO::Watcher { 67 public: 68 QueueManager(int input_fd, 69 int output_fd, 70 scoped_ptr<PacketPipe> pipe) : 71 input_fd_(input_fd), 72 packet_pipe_(pipe.Pass()) { 73 74 CHECK(base::MessageLoopForIO::current()->WatchFileDescriptor( 75 input_fd_, true, base::MessageLoopForIO::WATCH_READ, 76 &read_socket_watcher_, this)); 77 78 scoped_ptr<PacketPipe> tmp(new SendToFDPipe(output_fd)); 79 if (packet_pipe_) { 80 packet_pipe_->AppendToPipe(tmp.Pass()); 81 } else { 82 packet_pipe_ = tmp.Pass(); 83 } 84 packet_pipe_->InitOnIOThread(base::MessageLoopProxy::current(), 85 &tick_clock_); 86 } 87 88 virtual ~QueueManager() { 89 } 90 91 // MessageLoopForIO::Watcher methods 92 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE { 93 scoped_ptr<Packet> packet(new Packet(kMaxPacketSize)); 94 int nread = read(input_fd_, 95 reinterpret_cast<char*>(&packet->front()), 96 kMaxPacketSize); 97 if (nread < 0) { 98 if (errno == EINTR) return; 99 perror("read"); 100 exit(1); 101 } 102 if (nread == 0) return; 103 packet->resize(nread); 104 packet_pipe_->Send(packet.Pass()); 105 } 106 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE { 107 NOTREACHED(); 108 } 109 110 private: 111 int input_fd_; 112 scoped_ptr<PacketPipe> packet_pipe_; 113 base::MessageLoopForIO::FileDescriptorWatcher read_socket_watcher_; 114 base::DefaultTickClock tick_clock_; 115 }; 116 117 } // namespace test 118 } // namespace cast 119 } // namespace media 120 121 base::TimeTicks last_printout; 122 123 class ByteCounter { 124 public: 125 ByteCounter() : bytes_(0), packets_(0) { 126 push(base::TimeTicks::Now()); 127 } 128 129 base::TimeDelta time_range() { 130 return time_data_.back() - time_data_.front(); 131 } 132 133 void push(base::TimeTicks now) { 134 byte_data_.push_back(bytes_); 135 packet_data_.push_back(packets_); 136 time_data_.push_back(now); 137 while (time_range().InSeconds() > 10) { 138 byte_data_.pop_front(); 139 packet_data_.pop_front(); 140 time_data_.pop_front(); 141 } 142 } 143 144 double megabits_per_second() { 145 double megabits = (byte_data_.back() - byte_data_.front()) * 8 / 1E6; 146 return megabits / time_range().InSecondsF(); 147 } 148 149 double packets_per_second() { 150 double packets = packet_data_.back()- packet_data_.front(); 151 return packets / time_range().InSecondsF(); 152 } 153 154 void Increment(uint64 x) { 155 bytes_ += x; 156 packets_ ++; 157 } 158 159 private: 160 uint64 bytes_; 161 uint64 packets_; 162 std::deque<uint64> byte_data_; 163 std::deque<uint64> packet_data_; 164 std::deque<base::TimeTicks> time_data_; 165 }; 166 167 ByteCounter in_pipe_input_counter; 168 ByteCounter in_pipe_output_counter; 169 ByteCounter out_pipe_input_counter; 170 ByteCounter out_pipe_output_counter; 171 172 class ByteCounterPipe : public media::cast::test::PacketPipe { 173 public: 174 ByteCounterPipe(ByteCounter* counter) : counter_(counter) {} 175 virtual void Send(scoped_ptr<media::cast::Packet> packet) 176 OVERRIDE { 177 counter_->Increment(packet->size()); 178 pipe_->Send(packet.Pass()); 179 } 180 private: 181 ByteCounter* counter_; 182 }; 183 184 void SetupByteCounters(scoped_ptr<media::cast::test::PacketPipe>* pipe, 185 ByteCounter* pipe_input_counter, 186 ByteCounter* pipe_output_counter) { 187 media::cast::test::PacketPipe* new_pipe = 188 new ByteCounterPipe(pipe_input_counter); 189 new_pipe->AppendToPipe(pipe->Pass()); 190 new_pipe->AppendToPipe( 191 scoped_ptr<media::cast::test::PacketPipe>( 192 new ByteCounterPipe(pipe_output_counter)).Pass()); 193 pipe->reset(new_pipe); 194 } 195 196 void CheckByteCounters() { 197 base::TimeTicks now = base::TimeTicks::Now(); 198 in_pipe_input_counter.push(now); 199 in_pipe_output_counter.push(now); 200 out_pipe_input_counter.push(now); 201 out_pipe_output_counter.push(now); 202 if ((now - last_printout).InSeconds() >= 5) { 203 fprintf(stderr, "Sending : %5.2f / %5.2f mbps %6.2f / %6.2f packets / s\n", 204 in_pipe_output_counter.megabits_per_second(), 205 in_pipe_input_counter.megabits_per_second(), 206 in_pipe_output_counter.packets_per_second(), 207 in_pipe_input_counter.packets_per_second()); 208 fprintf(stderr, "Receiving: %5.2f / %5.2f mbps %6.2f / %6.2f packets / s\n", 209 out_pipe_output_counter.megabits_per_second(), 210 out_pipe_input_counter.megabits_per_second(), 211 out_pipe_output_counter.packets_per_second(), 212 out_pipe_input_counter.packets_per_second()); 213 214 last_printout = now; 215 } 216 base::MessageLoopProxy::current()->PostDelayedTask( 217 FROM_HERE, 218 base::Bind(&CheckByteCounters), 219 base::TimeDelta::FromMilliseconds(100)); 220 } 221 222 int tun_alloc(char *dev, int flags) { 223 struct ifreq ifr; 224 int fd, err; 225 const char *clonedev = "/dev/net/tun"; 226 227 /* Arguments taken by the function: 228 * 229 * char *dev: the name of an interface (or '\0'). MUST have enough 230 * space to hold the interface name if '\0' is passed 231 * int flags: interface flags (eg, IFF_TUN etc.) 232 */ 233 234 /* open the clone device */ 235 if( (fd = open(clonedev, O_RDWR)) < 0 ) { 236 return fd; 237 } 238 239 /* preparation of the struct ifr, of type "struct ifreq" */ 240 memset(&ifr, 0, sizeof(ifr)); 241 242 ifr.ifr_flags = flags; /* IFF_TUN or IFF_TAP, plus maybe IFF_NO_PI */ 243 244 if (*dev) { 245 /* if a device name was specified, put it in the structure; otherwise, 246 * the kernel will try to allocate the "next" device of the 247 * specified type */ 248 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 249 } 250 251 /* try to create the device */ 252 if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) { 253 close(fd); 254 return err; 255 } 256 257 if (!*dev) { 258 /* if the operation was successful, write back the name of the 259 * interface to the variable "dev", so the caller can know 260 * it. Note that the caller MUST reserve space in *dev (see calling 261 * code below) */ 262 strcpy(dev, ifr.ifr_name); 263 } 264 265 /* this is the special file descriptor that the caller will use to talk 266 * with the virtual interface */ 267 return fd; 268 } 269 270 271 int main(int argc, char **argv) { 272 base::AtExitManager exit_manager; 273 CommandLine::Init(argc, argv); 274 InitLogging(logging::LoggingSettings()); 275 276 if (argc < 4) { 277 fprintf(stderr, "Usage: tap_proxy tap1 tap2 type\n"); 278 fprintf(stderr, 279 "Where 'type' is one of perfect, good, wifi, bad or evil\n"); 280 exit(1); 281 } 282 283 scoped_ptr<media::cast::test::PacketPipe> in_pipe, out_pipe; 284 std::string network_type = argv[3]; 285 if (network_type == "perfect") { 286 // No action needed. 287 } else if (network_type == "good") { 288 in_pipe = media::cast::test::GoodNetwork().Pass(); 289 out_pipe = media::cast::test::GoodNetwork().Pass(); 290 } else if (network_type == "wifi") { 291 in_pipe = media::cast::test::WifiNetwork().Pass(); 292 out_pipe = media::cast::test::WifiNetwork().Pass(); 293 } else if (network_type == "bad") { 294 in_pipe = media::cast::test::BadNetwork().Pass(); 295 out_pipe = media::cast::test::BadNetwork().Pass(); 296 } else if (network_type == "evil") { 297 in_pipe = media::cast::test::EvilNetwork().Pass(); 298 out_pipe = media::cast::test::EvilNetwork().Pass(); 299 } else { 300 fprintf(stderr, "Unknown network type.\n"); 301 exit(1); 302 } 303 304 SetupByteCounters(&in_pipe, &in_pipe_input_counter, &in_pipe_output_counter); 305 SetupByteCounters( 306 &out_pipe, &out_pipe_input_counter, &out_pipe_output_counter); 307 308 int fd1 = tun_alloc(argv[1], IFF_TAP); 309 int fd2 = tun_alloc(argv[2], IFF_TAP); 310 311 base::MessageLoopForIO message_loop; 312 last_printout = base::TimeTicks::Now(); 313 media::cast::test::QueueManager qm1(fd1, fd2, in_pipe.Pass()); 314 media::cast::test::QueueManager qm2(fd2, fd1, out_pipe.Pass()); 315 CheckByteCounters(); 316 printf("Press Ctrl-C when done.\n"); 317 message_loop.Run(); 318 } 319