1 /*
2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #ifndef WEBRTC_TEST_FAKE_NETWORK_PIPE_H_
12 #define WEBRTC_TEST_FAKE_NETWORK_PIPE_H_
13 
14 #include <memory>
15 #include <set>
16 #include <string.h>
17 #include <queue>
18 
19 #include "webrtc/base/constructormagic.h"
20 #include "webrtc/base/criticalsection.h"
21 #include "webrtc/base/random.h"
22 #include "webrtc/typedefs.h"
23 
24 namespace webrtc {
25 
26 class Clock;
27 class CriticalSectionWrapper;
28 class PacketReceiver;
29 
30 class NetworkPacket {
31  public:
NetworkPacket(const uint8_t * data,size_t length,int64_t send_time,int64_t arrival_time)32   NetworkPacket(const uint8_t* data,
33                 size_t length,
34                 int64_t send_time,
35                 int64_t arrival_time)
36       : data_(new uint8_t[length]),
37         data_length_(length),
38         send_time_(send_time),
39         arrival_time_(arrival_time) {
40     memcpy(data_.get(), data, length);
41   }
42 
data()43   uint8_t* data() const { return data_.get(); }
data_length()44   size_t data_length() const { return data_length_; }
send_time()45   int64_t send_time() const { return send_time_; }
arrival_time()46   int64_t arrival_time() const { return arrival_time_; }
IncrementArrivalTime(int64_t extra_delay)47   void IncrementArrivalTime(int64_t extra_delay) {
48     arrival_time_ += extra_delay;
49   }
50 
51  private:
52   // The packet data.
53   std::unique_ptr<uint8_t[]> data_;
54   // Length of data_.
55   size_t data_length_;
56   // The time the packet was sent out on the network.
57   const int64_t send_time_;
58   // The time the packet should arrive at the receiver.
59   int64_t arrival_time_;
60 };
61 
62 // Class faking a network link. This is a simple and naive solution just faking
63 // capacity and adding an extra transport delay in addition to the capacity
64 // introduced delay.
65 
66 class FakeNetworkPipe {
67  public:
68   struct Config {
ConfigConfig69     Config() {}
70     // Queue length in number of packets.
71     size_t queue_length_packets = 0;
72     // Delay in addition to capacity induced delay.
73     int queue_delay_ms = 0;
74     // Standard deviation of the extra delay.
75     int delay_standard_deviation_ms = 0;
76     // Link capacity in kbps.
77     int link_capacity_kbps = 0;
78     // Random packet loss.
79     int loss_percent = 0;
80     // If packets are allowed to be reordered.
81     bool allow_reordering = false;
82     // The average length of a burst of lost packets.
83     int avg_burst_loss_length = -1;
84   };
85 
86   FakeNetworkPipe(Clock* clock, const FakeNetworkPipe::Config& config);
87   FakeNetworkPipe(Clock* clock,
88                   const FakeNetworkPipe::Config& config,
89                   uint64_t seed);
90   ~FakeNetworkPipe();
91 
92   // Must not be called in parallel with SendPacket or Process.
93   void SetReceiver(PacketReceiver* receiver);
94 
95   // Sets a new configuration. This won't affect packets already in the pipe.
96   void SetConfig(const FakeNetworkPipe::Config& config);
97 
98   // Sends a new packet to the link.
99   void SendPacket(const uint8_t* packet, size_t packet_length);
100 
101   // Processes the network queues and trigger PacketReceiver::IncomingPacket for
102   // packets ready to be delivered.
103   void Process();
104   int64_t TimeUntilNextProcess() const;
105 
106   // Get statistics.
107   float PercentageLoss();
108   int AverageDelay();
dropped_packets()109   size_t dropped_packets() { return dropped_packets_; }
sent_packets()110   size_t sent_packets() { return sent_packets_; }
111 
112  private:
113   Clock* const clock_;
114   rtc::CriticalSection lock_;
115   PacketReceiver* packet_receiver_;
116   std::queue<NetworkPacket*> capacity_link_;
117   Random random_;
118 
119   // Since we need to access both the packet with the earliest and latest
120   // arrival time we need to use a multiset to keep all packets sorted,
121   // hence, we cannot use a priority queue.
122   struct PacketArrivalTimeComparator {
operatorPacketArrivalTimeComparator123     bool operator()(const NetworkPacket* p1, const NetworkPacket* p2) {
124       return p1->arrival_time() < p2->arrival_time();
125     }
126   };
127   std::multiset<NetworkPacket*, PacketArrivalTimeComparator> delay_link_;
128 
129   // Link configuration.
130   Config config_;
131 
132   // Statistics.
133   size_t dropped_packets_;
134   size_t sent_packets_;
135   int64_t total_packet_delay_;
136 
137   // Are we currently dropping a burst of packets?
138   bool bursting_;
139 
140   // The probability to drop the packet if we are currently dropping a
141   // burst of packet
142   double prob_loss_bursting_;
143 
144   // The probability to drop a burst of packets.
145   double prob_start_bursting_;
146 
147   int64_t next_process_time_;
148 
149   RTC_DISALLOW_COPY_AND_ASSIGN(FakeNetworkPipe);
150 };
151 
152 }  // namespace webrtc
153 
154 #endif  // WEBRTC_TEST_FAKE_NETWORK_PIPE_H_
155