Home | History | Annotate | Download | only in utility
      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