xref: /aosp_15_r20/external/webrtc/test/network/cross_traffic.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "test/network/cross_traffic.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <math.h>
14*d9f75844SAndroid Build Coastguard Worker 
15*d9f75844SAndroid Build Coastguard Worker #include <utility>
16*d9f75844SAndroid Build Coastguard Worker 
17*d9f75844SAndroid Build Coastguard Worker #include "absl/memory/memory.h"
18*d9f75844SAndroid Build Coastguard Worker #include "absl/types/optional.h"
19*d9f75844SAndroid Build Coastguard Worker #include "cross_traffic.h"
20*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
21*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/numerics/safe_minmax.h"
22*d9f75844SAndroid Build Coastguard Worker 
23*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
24*d9f75844SAndroid Build Coastguard Worker namespace test {
25*d9f75844SAndroid Build Coastguard Worker 
RandomWalkCrossTraffic(RandomWalkConfig config,CrossTrafficRoute * traffic_route)26*d9f75844SAndroid Build Coastguard Worker RandomWalkCrossTraffic::RandomWalkCrossTraffic(RandomWalkConfig config,
27*d9f75844SAndroid Build Coastguard Worker                                                CrossTrafficRoute* traffic_route)
28*d9f75844SAndroid Build Coastguard Worker     : config_(config),
29*d9f75844SAndroid Build Coastguard Worker       traffic_route_(traffic_route),
30*d9f75844SAndroid Build Coastguard Worker       random_(config_.random_seed) {
31*d9f75844SAndroid Build Coastguard Worker   sequence_checker_.Detach();
32*d9f75844SAndroid Build Coastguard Worker }
33*d9f75844SAndroid Build Coastguard Worker RandomWalkCrossTraffic::~RandomWalkCrossTraffic() = default;
34*d9f75844SAndroid Build Coastguard Worker 
Process(Timestamp at_time)35*d9f75844SAndroid Build Coastguard Worker void RandomWalkCrossTraffic::Process(Timestamp at_time) {
36*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&sequence_checker_);
37*d9f75844SAndroid Build Coastguard Worker   if (last_process_time_.IsMinusInfinity()) {
38*d9f75844SAndroid Build Coastguard Worker     last_process_time_ = at_time;
39*d9f75844SAndroid Build Coastguard Worker   }
40*d9f75844SAndroid Build Coastguard Worker   TimeDelta delta = at_time - last_process_time_;
41*d9f75844SAndroid Build Coastguard Worker   last_process_time_ = at_time;
42*d9f75844SAndroid Build Coastguard Worker 
43*d9f75844SAndroid Build Coastguard Worker   if (at_time - last_update_time_ >= config_.update_interval) {
44*d9f75844SAndroid Build Coastguard Worker     intensity_ += random_.Gaussian(config_.bias, config_.variance) *
45*d9f75844SAndroid Build Coastguard Worker                   sqrt((at_time - last_update_time_).seconds<double>());
46*d9f75844SAndroid Build Coastguard Worker     intensity_ = rtc::SafeClamp(intensity_, 0.0, 1.0);
47*d9f75844SAndroid Build Coastguard Worker     last_update_time_ = at_time;
48*d9f75844SAndroid Build Coastguard Worker   }
49*d9f75844SAndroid Build Coastguard Worker   pending_size_ += TrafficRate() * delta;
50*d9f75844SAndroid Build Coastguard Worker 
51*d9f75844SAndroid Build Coastguard Worker   if (pending_size_ >= config_.min_packet_size &&
52*d9f75844SAndroid Build Coastguard Worker       at_time >= last_send_time_ + config_.min_packet_interval) {
53*d9f75844SAndroid Build Coastguard Worker     traffic_route_->SendPacket(pending_size_.bytes());
54*d9f75844SAndroid Build Coastguard Worker     pending_size_ = DataSize::Zero();
55*d9f75844SAndroid Build Coastguard Worker     last_send_time_ = at_time;
56*d9f75844SAndroid Build Coastguard Worker   }
57*d9f75844SAndroid Build Coastguard Worker }
58*d9f75844SAndroid Build Coastguard Worker 
GetProcessInterval() const59*d9f75844SAndroid Build Coastguard Worker TimeDelta RandomWalkCrossTraffic::GetProcessInterval() const {
60*d9f75844SAndroid Build Coastguard Worker   return config_.min_packet_interval;
61*d9f75844SAndroid Build Coastguard Worker }
62*d9f75844SAndroid Build Coastguard Worker 
TrafficRate() const63*d9f75844SAndroid Build Coastguard Worker DataRate RandomWalkCrossTraffic::TrafficRate() const {
64*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&sequence_checker_);
65*d9f75844SAndroid Build Coastguard Worker   return config_.peak_rate * intensity_;
66*d9f75844SAndroid Build Coastguard Worker }
67*d9f75844SAndroid Build Coastguard Worker 
StatsPrinter()68*d9f75844SAndroid Build Coastguard Worker ColumnPrinter RandomWalkCrossTraffic::StatsPrinter() {
69*d9f75844SAndroid Build Coastguard Worker   return ColumnPrinter::Lambda(
70*d9f75844SAndroid Build Coastguard Worker       "random_walk_cross_traffic_rate",
71*d9f75844SAndroid Build Coastguard Worker       [this](rtc::SimpleStringBuilder& sb) {
72*d9f75844SAndroid Build Coastguard Worker         sb.AppendFormat("%.0lf", TrafficRate().bps() / 8.0);
73*d9f75844SAndroid Build Coastguard Worker       },
74*d9f75844SAndroid Build Coastguard Worker       32);
75*d9f75844SAndroid Build Coastguard Worker }
76*d9f75844SAndroid Build Coastguard Worker 
PulsedPeaksCrossTraffic(PulsedPeaksConfig config,CrossTrafficRoute * traffic_route)77*d9f75844SAndroid Build Coastguard Worker PulsedPeaksCrossTraffic::PulsedPeaksCrossTraffic(
78*d9f75844SAndroid Build Coastguard Worker     PulsedPeaksConfig config,
79*d9f75844SAndroid Build Coastguard Worker     CrossTrafficRoute* traffic_route)
80*d9f75844SAndroid Build Coastguard Worker     : config_(config), traffic_route_(traffic_route) {
81*d9f75844SAndroid Build Coastguard Worker   sequence_checker_.Detach();
82*d9f75844SAndroid Build Coastguard Worker }
83*d9f75844SAndroid Build Coastguard Worker PulsedPeaksCrossTraffic::~PulsedPeaksCrossTraffic() = default;
84*d9f75844SAndroid Build Coastguard Worker 
Process(Timestamp at_time)85*d9f75844SAndroid Build Coastguard Worker void PulsedPeaksCrossTraffic::Process(Timestamp at_time) {
86*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&sequence_checker_);
87*d9f75844SAndroid Build Coastguard Worker   TimeDelta time_since_toggle = at_time - last_update_time_;
88*d9f75844SAndroid Build Coastguard Worker   if (time_since_toggle.IsInfinite() ||
89*d9f75844SAndroid Build Coastguard Worker       (sending_ && time_since_toggle >= config_.send_duration)) {
90*d9f75844SAndroid Build Coastguard Worker     sending_ = false;
91*d9f75844SAndroid Build Coastguard Worker     last_update_time_ = at_time;
92*d9f75844SAndroid Build Coastguard Worker   } else if (!sending_ && time_since_toggle >= config_.hold_duration) {
93*d9f75844SAndroid Build Coastguard Worker     sending_ = true;
94*d9f75844SAndroid Build Coastguard Worker     last_update_time_ = at_time;
95*d9f75844SAndroid Build Coastguard Worker     // Start sending period.
96*d9f75844SAndroid Build Coastguard Worker     last_send_time_ = at_time;
97*d9f75844SAndroid Build Coastguard Worker   }
98*d9f75844SAndroid Build Coastguard Worker 
99*d9f75844SAndroid Build Coastguard Worker   if (sending_) {
100*d9f75844SAndroid Build Coastguard Worker     DataSize pending_size = config_.peak_rate * (at_time - last_send_time_);
101*d9f75844SAndroid Build Coastguard Worker 
102*d9f75844SAndroid Build Coastguard Worker     if (pending_size >= config_.min_packet_size &&
103*d9f75844SAndroid Build Coastguard Worker         at_time >= last_send_time_ + config_.min_packet_interval) {
104*d9f75844SAndroid Build Coastguard Worker       traffic_route_->SendPacket(pending_size.bytes());
105*d9f75844SAndroid Build Coastguard Worker       last_send_time_ = at_time;
106*d9f75844SAndroid Build Coastguard Worker     }
107*d9f75844SAndroid Build Coastguard Worker   }
108*d9f75844SAndroid Build Coastguard Worker }
109*d9f75844SAndroid Build Coastguard Worker 
GetProcessInterval() const110*d9f75844SAndroid Build Coastguard Worker TimeDelta PulsedPeaksCrossTraffic::GetProcessInterval() const {
111*d9f75844SAndroid Build Coastguard Worker   return config_.min_packet_interval;
112*d9f75844SAndroid Build Coastguard Worker }
113*d9f75844SAndroid Build Coastguard Worker 
TrafficRate() const114*d9f75844SAndroid Build Coastguard Worker DataRate PulsedPeaksCrossTraffic::TrafficRate() const {
115*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&sequence_checker_);
116*d9f75844SAndroid Build Coastguard Worker   return sending_ ? config_.peak_rate : DataRate::Zero();
117*d9f75844SAndroid Build Coastguard Worker }
118*d9f75844SAndroid Build Coastguard Worker 
StatsPrinter()119*d9f75844SAndroid Build Coastguard Worker ColumnPrinter PulsedPeaksCrossTraffic::StatsPrinter() {
120*d9f75844SAndroid Build Coastguard Worker   return ColumnPrinter::Lambda(
121*d9f75844SAndroid Build Coastguard Worker       "pulsed_peaks_cross_traffic_rate",
122*d9f75844SAndroid Build Coastguard Worker       [this](rtc::SimpleStringBuilder& sb) {
123*d9f75844SAndroid Build Coastguard Worker         sb.AppendFormat("%.0lf", TrafficRate().bps() / 8.0);
124*d9f75844SAndroid Build Coastguard Worker       },
125*d9f75844SAndroid Build Coastguard Worker       32);
126*d9f75844SAndroid Build Coastguard Worker }
127*d9f75844SAndroid Build Coastguard Worker 
TcpMessageRouteImpl(Clock * clock,TaskQueueBase * task_queue,EmulatedRoute * send_route,EmulatedRoute * ret_route)128*d9f75844SAndroid Build Coastguard Worker TcpMessageRouteImpl::TcpMessageRouteImpl(Clock* clock,
129*d9f75844SAndroid Build Coastguard Worker                                          TaskQueueBase* task_queue,
130*d9f75844SAndroid Build Coastguard Worker                                          EmulatedRoute* send_route,
131*d9f75844SAndroid Build Coastguard Worker                                          EmulatedRoute* ret_route)
132*d9f75844SAndroid Build Coastguard Worker     : clock_(clock),
133*d9f75844SAndroid Build Coastguard Worker       task_queue_(task_queue),
134*d9f75844SAndroid Build Coastguard Worker       request_route_(send_route,
135*d9f75844SAndroid Build Coastguard Worker                      [this](TcpPacket packet, Timestamp) {
136*d9f75844SAndroid Build Coastguard Worker                        OnRequest(std::move(packet));
137*d9f75844SAndroid Build Coastguard Worker                      }),
138*d9f75844SAndroid Build Coastguard Worker       response_route_(ret_route,
__anon0369fb610402(TcpPacket packet, Timestamp arrival_time) 139*d9f75844SAndroid Build Coastguard Worker                       [this](TcpPacket packet, Timestamp arrival_time) {
140*d9f75844SAndroid Build Coastguard Worker                         OnResponse(std::move(packet), arrival_time);
141*d9f75844SAndroid Build Coastguard Worker                       }) {}
142*d9f75844SAndroid Build Coastguard Worker 
SendMessage(size_t size,std::function<void ()> on_received)143*d9f75844SAndroid Build Coastguard Worker void TcpMessageRouteImpl::SendMessage(size_t size,
144*d9f75844SAndroid Build Coastguard Worker                                       std::function<void()> on_received) {
145*d9f75844SAndroid Build Coastguard Worker   task_queue_->PostTask(
146*d9f75844SAndroid Build Coastguard Worker       [this, size, handler = std::move(on_received)] {
147*d9f75844SAndroid Build Coastguard Worker         // If we are currently sending a message we won't reset the connection,
148*d9f75844SAndroid Build Coastguard Worker         // we'll act as if the messages are sent in the same TCP stream. This is
149*d9f75844SAndroid Build Coastguard Worker         // intended to simulate recreation of a TCP session for each message
150*d9f75844SAndroid Build Coastguard Worker         // in the typical case while avoiding the complexity overhead of
151*d9f75844SAndroid Build Coastguard Worker         // maintaining multiple virtual TCP sessions in parallel.
152*d9f75844SAndroid Build Coastguard Worker         if (pending_.empty() && in_flight_.empty()) {
153*d9f75844SAndroid Build Coastguard Worker           cwnd_ = 10;
154*d9f75844SAndroid Build Coastguard Worker           ssthresh_ = INFINITY;
155*d9f75844SAndroid Build Coastguard Worker         }
156*d9f75844SAndroid Build Coastguard Worker         int64_t data_left = static_cast<int64_t>(size);
157*d9f75844SAndroid Build Coastguard Worker         int64_t kMaxPacketSize = 1200;
158*d9f75844SAndroid Build Coastguard Worker         int64_t kMinPacketSize = 4;
159*d9f75844SAndroid Build Coastguard Worker         Message message{std::move(handler)};
160*d9f75844SAndroid Build Coastguard Worker         while (data_left > 0) {
161*d9f75844SAndroid Build Coastguard Worker           int64_t packet_size = std::min(data_left, kMaxPacketSize);
162*d9f75844SAndroid Build Coastguard Worker           int fragment_id = next_fragment_id_++;
163*d9f75844SAndroid Build Coastguard Worker           pending_.push_back(MessageFragment{
164*d9f75844SAndroid Build Coastguard Worker               fragment_id,
165*d9f75844SAndroid Build Coastguard Worker               static_cast<size_t>(std::max(kMinPacketSize, packet_size))});
166*d9f75844SAndroid Build Coastguard Worker           message.pending_fragment_ids.insert(fragment_id);
167*d9f75844SAndroid Build Coastguard Worker           data_left -= packet_size;
168*d9f75844SAndroid Build Coastguard Worker         }
169*d9f75844SAndroid Build Coastguard Worker         messages_.emplace_back(message);
170*d9f75844SAndroid Build Coastguard Worker         SendPackets(clock_->CurrentTime());
171*d9f75844SAndroid Build Coastguard Worker       });
172*d9f75844SAndroid Build Coastguard Worker }
173*d9f75844SAndroid Build Coastguard Worker 
OnRequest(TcpPacket packet_info)174*d9f75844SAndroid Build Coastguard Worker void TcpMessageRouteImpl::OnRequest(TcpPacket packet_info) {
175*d9f75844SAndroid Build Coastguard Worker   for (auto it = messages_.begin(); it != messages_.end(); ++it) {
176*d9f75844SAndroid Build Coastguard Worker     if (it->pending_fragment_ids.count(packet_info.fragment.fragment_id) != 0) {
177*d9f75844SAndroid Build Coastguard Worker       it->pending_fragment_ids.erase(packet_info.fragment.fragment_id);
178*d9f75844SAndroid Build Coastguard Worker       if (it->pending_fragment_ids.empty()) {
179*d9f75844SAndroid Build Coastguard Worker         it->handler();
180*d9f75844SAndroid Build Coastguard Worker         messages_.erase(it);
181*d9f75844SAndroid Build Coastguard Worker       }
182*d9f75844SAndroid Build Coastguard Worker       break;
183*d9f75844SAndroid Build Coastguard Worker     }
184*d9f75844SAndroid Build Coastguard Worker   }
185*d9f75844SAndroid Build Coastguard Worker   const size_t kAckPacketSize = 20;
186*d9f75844SAndroid Build Coastguard Worker   response_route_.SendPacket(kAckPacketSize, packet_info);
187*d9f75844SAndroid Build Coastguard Worker }
188*d9f75844SAndroid Build Coastguard Worker 
OnResponse(TcpPacket packet_info,Timestamp at_time)189*d9f75844SAndroid Build Coastguard Worker void TcpMessageRouteImpl::OnResponse(TcpPacket packet_info, Timestamp at_time) {
190*d9f75844SAndroid Build Coastguard Worker   auto it = in_flight_.find(packet_info.sequence_number);
191*d9f75844SAndroid Build Coastguard Worker   if (it != in_flight_.end()) {
192*d9f75844SAndroid Build Coastguard Worker     last_rtt_ = at_time - packet_info.send_time;
193*d9f75844SAndroid Build Coastguard Worker     in_flight_.erase(it);
194*d9f75844SAndroid Build Coastguard Worker   }
195*d9f75844SAndroid Build Coastguard Worker   auto lost_end = in_flight_.lower_bound(packet_info.sequence_number);
196*d9f75844SAndroid Build Coastguard Worker   for (auto lost_it = in_flight_.begin(); lost_it != lost_end;
197*d9f75844SAndroid Build Coastguard Worker        lost_it = in_flight_.erase(lost_it)) {
198*d9f75844SAndroid Build Coastguard Worker     pending_.push_front(lost_it->second.fragment);
199*d9f75844SAndroid Build Coastguard Worker   }
200*d9f75844SAndroid Build Coastguard Worker 
201*d9f75844SAndroid Build Coastguard Worker   if (packet_info.sequence_number - last_acked_seq_num_ > 1) {
202*d9f75844SAndroid Build Coastguard Worker     HandleLoss(at_time);
203*d9f75844SAndroid Build Coastguard Worker   } else if (cwnd_ <= ssthresh_) {
204*d9f75844SAndroid Build Coastguard Worker     cwnd_ += 1;
205*d9f75844SAndroid Build Coastguard Worker   } else {
206*d9f75844SAndroid Build Coastguard Worker     cwnd_ += 1.0f / cwnd_;
207*d9f75844SAndroid Build Coastguard Worker   }
208*d9f75844SAndroid Build Coastguard Worker   last_acked_seq_num_ =
209*d9f75844SAndroid Build Coastguard Worker       std::max(packet_info.sequence_number, last_acked_seq_num_);
210*d9f75844SAndroid Build Coastguard Worker   SendPackets(at_time);
211*d9f75844SAndroid Build Coastguard Worker }
212*d9f75844SAndroid Build Coastguard Worker 
HandleLoss(Timestamp at_time)213*d9f75844SAndroid Build Coastguard Worker void TcpMessageRouteImpl::HandleLoss(Timestamp at_time) {
214*d9f75844SAndroid Build Coastguard Worker   if (at_time - last_reduction_time_ < last_rtt_)
215*d9f75844SAndroid Build Coastguard Worker     return;
216*d9f75844SAndroid Build Coastguard Worker   last_reduction_time_ = at_time;
217*d9f75844SAndroid Build Coastguard Worker   ssthresh_ = std::max(static_cast<int>(in_flight_.size() / 2), 2);
218*d9f75844SAndroid Build Coastguard Worker   cwnd_ = ssthresh_;
219*d9f75844SAndroid Build Coastguard Worker }
220*d9f75844SAndroid Build Coastguard Worker 
SendPackets(Timestamp at_time)221*d9f75844SAndroid Build Coastguard Worker void TcpMessageRouteImpl::SendPackets(Timestamp at_time) {
222*d9f75844SAndroid Build Coastguard Worker   const TimeDelta kPacketTimeout = TimeDelta::Seconds(1);
223*d9f75844SAndroid Build Coastguard Worker   int cwnd = std::ceil(cwnd_);
224*d9f75844SAndroid Build Coastguard Worker   int packets_to_send = std::max(cwnd - static_cast<int>(in_flight_.size()), 0);
225*d9f75844SAndroid Build Coastguard Worker   while (packets_to_send-- > 0 && !pending_.empty()) {
226*d9f75844SAndroid Build Coastguard Worker     auto seq_num = next_sequence_number_++;
227*d9f75844SAndroid Build Coastguard Worker     TcpPacket send;
228*d9f75844SAndroid Build Coastguard Worker     send.sequence_number = seq_num;
229*d9f75844SAndroid Build Coastguard Worker     send.send_time = at_time;
230*d9f75844SAndroid Build Coastguard Worker     send.fragment = pending_.front();
231*d9f75844SAndroid Build Coastguard Worker     pending_.pop_front();
232*d9f75844SAndroid Build Coastguard Worker     request_route_.SendPacket(send.fragment.size, send);
233*d9f75844SAndroid Build Coastguard Worker     in_flight_.insert({seq_num, send});
234*d9f75844SAndroid Build Coastguard Worker     task_queue_->PostDelayedTask(
235*d9f75844SAndroid Build Coastguard Worker         [this, seq_num] {
236*d9f75844SAndroid Build Coastguard Worker           HandlePacketTimeout(seq_num, clock_->CurrentTime());
237*d9f75844SAndroid Build Coastguard Worker         },
238*d9f75844SAndroid Build Coastguard Worker         kPacketTimeout);
239*d9f75844SAndroid Build Coastguard Worker   }
240*d9f75844SAndroid Build Coastguard Worker }
241*d9f75844SAndroid Build Coastguard Worker 
HandlePacketTimeout(int seq_num,Timestamp at_time)242*d9f75844SAndroid Build Coastguard Worker void TcpMessageRouteImpl::HandlePacketTimeout(int seq_num, Timestamp at_time) {
243*d9f75844SAndroid Build Coastguard Worker   auto lost = in_flight_.find(seq_num);
244*d9f75844SAndroid Build Coastguard Worker   if (lost != in_flight_.end()) {
245*d9f75844SAndroid Build Coastguard Worker     pending_.push_front(lost->second.fragment);
246*d9f75844SAndroid Build Coastguard Worker     in_flight_.erase(lost);
247*d9f75844SAndroid Build Coastguard Worker     HandleLoss(at_time);
248*d9f75844SAndroid Build Coastguard Worker     SendPackets(at_time);
249*d9f75844SAndroid Build Coastguard Worker   }
250*d9f75844SAndroid Build Coastguard Worker }
251*d9f75844SAndroid Build Coastguard Worker 
FakeTcpCrossTraffic(FakeTcpConfig config,EmulatedRoute * send_route,EmulatedRoute * ret_route)252*d9f75844SAndroid Build Coastguard Worker FakeTcpCrossTraffic::FakeTcpCrossTraffic(FakeTcpConfig config,
253*d9f75844SAndroid Build Coastguard Worker                                          EmulatedRoute* send_route,
254*d9f75844SAndroid Build Coastguard Worker                                          EmulatedRoute* ret_route)
255*d9f75844SAndroid Build Coastguard Worker     : conf_(config), route_(this, send_route, ret_route) {}
256*d9f75844SAndroid Build Coastguard Worker 
GetProcessInterval() const257*d9f75844SAndroid Build Coastguard Worker TimeDelta FakeTcpCrossTraffic::GetProcessInterval() const {
258*d9f75844SAndroid Build Coastguard Worker   return conf_.process_interval;
259*d9f75844SAndroid Build Coastguard Worker }
260*d9f75844SAndroid Build Coastguard Worker 
Process(Timestamp at_time)261*d9f75844SAndroid Build Coastguard Worker void FakeTcpCrossTraffic::Process(Timestamp at_time) {
262*d9f75844SAndroid Build Coastguard Worker   SendPackets(at_time);
263*d9f75844SAndroid Build Coastguard Worker }
264*d9f75844SAndroid Build Coastguard Worker 
OnRequest(int sequence_number,Timestamp at_time)265*d9f75844SAndroid Build Coastguard Worker void FakeTcpCrossTraffic::OnRequest(int sequence_number, Timestamp at_time) {
266*d9f75844SAndroid Build Coastguard Worker   const size_t kAckPacketSize = 20;
267*d9f75844SAndroid Build Coastguard Worker   route_.SendResponse(kAckPacketSize, sequence_number);
268*d9f75844SAndroid Build Coastguard Worker }
269*d9f75844SAndroid Build Coastguard Worker 
OnResponse(int sequence_number,Timestamp at_time)270*d9f75844SAndroid Build Coastguard Worker void FakeTcpCrossTraffic::OnResponse(int sequence_number, Timestamp at_time) {
271*d9f75844SAndroid Build Coastguard Worker   ack_received_ = true;
272*d9f75844SAndroid Build Coastguard Worker   auto it = in_flight_.find(sequence_number);
273*d9f75844SAndroid Build Coastguard Worker   if (it != in_flight_.end()) {
274*d9f75844SAndroid Build Coastguard Worker     last_rtt_ = at_time - in_flight_.at(sequence_number);
275*d9f75844SAndroid Build Coastguard Worker     in_flight_.erase(sequence_number);
276*d9f75844SAndroid Build Coastguard Worker   }
277*d9f75844SAndroid Build Coastguard Worker   if (sequence_number - last_acked_seq_num_ > 1) {
278*d9f75844SAndroid Build Coastguard Worker     HandleLoss(at_time);
279*d9f75844SAndroid Build Coastguard Worker   } else if (cwnd_ <= ssthresh_) {
280*d9f75844SAndroid Build Coastguard Worker     cwnd_ += 1;
281*d9f75844SAndroid Build Coastguard Worker   } else {
282*d9f75844SAndroid Build Coastguard Worker     cwnd_ += 1.0f / cwnd_;
283*d9f75844SAndroid Build Coastguard Worker   }
284*d9f75844SAndroid Build Coastguard Worker   last_acked_seq_num_ = std::max(sequence_number, last_acked_seq_num_);
285*d9f75844SAndroid Build Coastguard Worker   SendPackets(at_time);
286*d9f75844SAndroid Build Coastguard Worker }
287*d9f75844SAndroid Build Coastguard Worker 
HandleLoss(Timestamp at_time)288*d9f75844SAndroid Build Coastguard Worker void FakeTcpCrossTraffic::HandleLoss(Timestamp at_time) {
289*d9f75844SAndroid Build Coastguard Worker   if (at_time - last_reduction_time_ < last_rtt_)
290*d9f75844SAndroid Build Coastguard Worker     return;
291*d9f75844SAndroid Build Coastguard Worker   last_reduction_time_ = at_time;
292*d9f75844SAndroid Build Coastguard Worker   ssthresh_ = std::max(static_cast<int>(in_flight_.size() / 2), 2);
293*d9f75844SAndroid Build Coastguard Worker   cwnd_ = ssthresh_;
294*d9f75844SAndroid Build Coastguard Worker }
295*d9f75844SAndroid Build Coastguard Worker 
SendPackets(Timestamp at_time)296*d9f75844SAndroid Build Coastguard Worker void FakeTcpCrossTraffic::SendPackets(Timestamp at_time) {
297*d9f75844SAndroid Build Coastguard Worker   int cwnd = std::ceil(cwnd_);
298*d9f75844SAndroid Build Coastguard Worker   int packets_to_send = std::max(cwnd - static_cast<int>(in_flight_.size()), 0);
299*d9f75844SAndroid Build Coastguard Worker   bool timeouts = false;
300*d9f75844SAndroid Build Coastguard Worker   for (auto it = in_flight_.begin(); it != in_flight_.end();) {
301*d9f75844SAndroid Build Coastguard Worker     if (it->second < at_time - conf_.packet_timeout) {
302*d9f75844SAndroid Build Coastguard Worker       it = in_flight_.erase(it);
303*d9f75844SAndroid Build Coastguard Worker       timeouts = true;
304*d9f75844SAndroid Build Coastguard Worker     } else {
305*d9f75844SAndroid Build Coastguard Worker       ++it;
306*d9f75844SAndroid Build Coastguard Worker     }
307*d9f75844SAndroid Build Coastguard Worker   }
308*d9f75844SAndroid Build Coastguard Worker   if (timeouts)
309*d9f75844SAndroid Build Coastguard Worker     HandleLoss(at_time);
310*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < packets_to_send; ++i) {
311*d9f75844SAndroid Build Coastguard Worker     if ((total_sent_ + conf_.packet_size) > conf_.send_limit) {
312*d9f75844SAndroid Build Coastguard Worker       break;
313*d9f75844SAndroid Build Coastguard Worker     }
314*d9f75844SAndroid Build Coastguard Worker     in_flight_.insert({next_sequence_number_, at_time});
315*d9f75844SAndroid Build Coastguard Worker     route_.SendRequest(conf_.packet_size.bytes<size_t>(),
316*d9f75844SAndroid Build Coastguard Worker                        next_sequence_number_++);
317*d9f75844SAndroid Build Coastguard Worker     total_sent_ += conf_.packet_size;
318*d9f75844SAndroid Build Coastguard Worker   }
319*d9f75844SAndroid Build Coastguard Worker }
320*d9f75844SAndroid Build Coastguard Worker 
321*d9f75844SAndroid Build Coastguard Worker }  // namespace test
322*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
323