xref: /aosp_15_r20/external/webrtc/p2p/base/pseudo_tcp_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright 2011 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 #include "p2p/base/pseudo_tcp.h"
12 
13 #include <string.h>
14 
15 #include <algorithm>
16 #include <cstddef>
17 #include <string>
18 #include <utility>
19 #include <vector>
20 
21 #include "api/task_queue/pending_task_safety_flag.h"
22 #include "api/task_queue/task_queue_base.h"
23 #include "api/units/time_delta.h"
24 #include "rtc_base/gunit.h"
25 #include "rtc_base/helpers.h"
26 #include "rtc_base/logging.h"
27 #include "rtc_base/memory_stream.h"
28 #include "rtc_base/time_utils.h"
29 #include "test/gtest.h"
30 
31 using ::cricket::PseudoTcp;
32 using ::webrtc::ScopedTaskSafety;
33 using ::webrtc::TaskQueueBase;
34 using ::webrtc::TimeDelta;
35 
36 static const int kConnectTimeoutMs = 10000;  // ~3 * default RTO of 3000ms
37 static const int kTransferTimeoutMs = 15000;
38 static const int kBlockSize = 4096;
39 
40 class PseudoTcpForTest : public cricket::PseudoTcp {
41  public:
PseudoTcpForTest(cricket::IPseudoTcpNotify * notify,uint32_t conv)42   PseudoTcpForTest(cricket::IPseudoTcpNotify* notify, uint32_t conv)
43       : PseudoTcp(notify, conv) {}
44 
isReceiveBufferFull() const45   bool isReceiveBufferFull() const { return PseudoTcp::isReceiveBufferFull(); }
46 
disableWindowScale()47   void disableWindowScale() { PseudoTcp::disableWindowScale(); }
48 };
49 
50 class PseudoTcpTestBase : public ::testing::Test,
51                           public cricket::IPseudoTcpNotify {
52  public:
PseudoTcpTestBase()53   PseudoTcpTestBase()
54       : local_(this, 1),
55         remote_(this, 1),
56         have_connected_(false),
57         have_disconnected_(false),
58         local_mtu_(65535),
59         remote_mtu_(65535),
60         delay_(0),
61         loss_(0) {
62     // Set use of the test RNG to get predictable loss patterns. Otherwise,
63     // this test would occasionally get really unlucky loss and time out.
64     rtc::SetRandomTestMode(true);
65   }
~PseudoTcpTestBase()66   ~PseudoTcpTestBase() {
67     // Put it back for the next test.
68     rtc::SetRandomTestMode(false);
69   }
70   // If true, both endpoints will send the "connect" segment simultaneously,
71   // rather than `local_` sending it followed by a response from `remote_`.
72   // Note that this is what chromoting ends up doing.
SetSimultaneousOpen(bool enabled)73   void SetSimultaneousOpen(bool enabled) { simultaneous_open_ = enabled; }
SetLocalMtu(int mtu)74   void SetLocalMtu(int mtu) {
75     local_.NotifyMTU(mtu);
76     local_mtu_ = mtu;
77   }
SetRemoteMtu(int mtu)78   void SetRemoteMtu(int mtu) {
79     remote_.NotifyMTU(mtu);
80     remote_mtu_ = mtu;
81   }
SetDelay(int delay)82   void SetDelay(int delay) { delay_ = delay; }
SetLoss(int percent)83   void SetLoss(int percent) { loss_ = percent; }
84   // Used to cause the initial "connect" segment to be lost, needed for a
85   // regression test.
DropNextPacket()86   void DropNextPacket() { drop_next_packet_ = true; }
SetOptNagling(bool enable_nagles)87   void SetOptNagling(bool enable_nagles) {
88     local_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles);
89     remote_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles);
90   }
SetOptAckDelay(int ack_delay)91   void SetOptAckDelay(int ack_delay) {
92     local_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay);
93     remote_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay);
94   }
SetOptSndBuf(int size)95   void SetOptSndBuf(int size) {
96     local_.SetOption(PseudoTcp::OPT_SNDBUF, size);
97     remote_.SetOption(PseudoTcp::OPT_SNDBUF, size);
98   }
SetRemoteOptRcvBuf(int size)99   void SetRemoteOptRcvBuf(int size) {
100     remote_.SetOption(PseudoTcp::OPT_RCVBUF, size);
101   }
SetLocalOptRcvBuf(int size)102   void SetLocalOptRcvBuf(int size) {
103     local_.SetOption(PseudoTcp::OPT_RCVBUF, size);
104   }
DisableRemoteWindowScale()105   void DisableRemoteWindowScale() { remote_.disableWindowScale(); }
DisableLocalWindowScale()106   void DisableLocalWindowScale() { local_.disableWindowScale(); }
107 
108  protected:
Connect()109   int Connect() {
110     int ret = local_.Connect();
111     if (ret == 0) {
112       UpdateLocalClock();
113     }
114     if (simultaneous_open_) {
115       ret = remote_.Connect();
116       if (ret == 0) {
117         UpdateRemoteClock();
118       }
119     }
120     return ret;
121   }
Close()122   void Close() {
123     local_.Close(false);
124     UpdateLocalClock();
125   }
126 
OnTcpOpen(PseudoTcp * tcp)127   virtual void OnTcpOpen(PseudoTcp* tcp) {
128     // Consider ourselves connected when the local side gets OnTcpOpen.
129     // OnTcpWriteable isn't fired at open, so we trigger it now.
130     RTC_LOG(LS_VERBOSE) << "Opened";
131     if (tcp == &local_) {
132       have_connected_ = true;
133       OnTcpWriteable(tcp);
134     }
135   }
136   // Test derived from the base should override
137   //   virtual void OnTcpReadable(PseudoTcp* tcp)
138   // and
139   //   virtual void OnTcpWritable(PseudoTcp* tcp)
OnTcpClosed(PseudoTcp * tcp,uint32_t error)140   virtual void OnTcpClosed(PseudoTcp* tcp, uint32_t error) {
141     // Consider ourselves closed when the remote side gets OnTcpClosed.
142     // TODO(?): OnTcpClosed is only ever notified in case of error in
143     // the current implementation.  Solicited close is not (yet) supported.
144     RTC_LOG(LS_VERBOSE) << "Closed";
145     EXPECT_EQ(0U, error);
146     if (tcp == &remote_) {
147       have_disconnected_ = true;
148     }
149   }
TcpWritePacket(PseudoTcp * tcp,const char * buffer,size_t len)150   virtual WriteResult TcpWritePacket(PseudoTcp* tcp,
151                                      const char* buffer,
152                                      size_t len) {
153     // Drop a packet if the test called DropNextPacket.
154     if (drop_next_packet_) {
155       drop_next_packet_ = false;
156       RTC_LOG(LS_VERBOSE) << "Dropping packet due to DropNextPacket, size="
157                           << len;
158       return WR_SUCCESS;
159     }
160     // Randomly drop the desired percentage of packets.
161     if (rtc::CreateRandomId() % 100 < static_cast<uint32_t>(loss_)) {
162       RTC_LOG(LS_VERBOSE) << "Randomly dropping packet, size=" << len;
163       return WR_SUCCESS;
164     }
165     // Also drop packets that are larger than the configured MTU.
166     if (len > static_cast<size_t>(std::min(local_mtu_, remote_mtu_))) {
167       RTC_LOG(LS_VERBOSE) << "Dropping packet that exceeds path MTU, size="
168                           << len;
169       return WR_SUCCESS;
170     }
171     PseudoTcp* other;
172     ScopedTaskSafety* timer;
173     if (tcp == &local_) {
174       other = &remote_;
175       timer = &remote_timer_;
176     } else {
177       other = &local_;
178       timer = &local_timer_;
179     }
180     std::string packet(buffer, len);
181     ++packets_in_flight_;
182     TaskQueueBase::Current()->PostDelayedTask(
183         [other, timer, packet = std::move(packet), this] {
184           --packets_in_flight_;
185           other->NotifyPacket(packet.c_str(), packet.size());
186           UpdateClock(*other, *timer);
187         },
188         TimeDelta::Millis(delay_));
189     return WR_SUCCESS;
190   }
191 
UpdateLocalClock()192   void UpdateLocalClock() { UpdateClock(local_, local_timer_); }
UpdateRemoteClock()193   void UpdateRemoteClock() { UpdateClock(remote_, remote_timer_); }
UpdateClock(PseudoTcp & tcp,ScopedTaskSafety & timer)194   static void UpdateClock(PseudoTcp& tcp, ScopedTaskSafety& timer) {
195     long interval = 0;  // NOLINT
196     tcp.GetNextClock(PseudoTcp::Now(), interval);
197     interval = std::max<int>(interval, 0L);  // sometimes interval is < 0
198     timer.reset();
199     TaskQueueBase::Current()->PostDelayedTask(
200         SafeTask(timer.flag(),
201                  [&tcp, &timer] {
202                    tcp.NotifyClock(PseudoTcp::Now());
203                    UpdateClock(tcp, timer);
204                  }),
205         TimeDelta::Millis(interval));
206   }
207 
208   rtc::AutoThread main_thread_;
209   PseudoTcpForTest local_;
210   PseudoTcpForTest remote_;
211   ScopedTaskSafety local_timer_;
212   ScopedTaskSafety remote_timer_;
213   rtc::MemoryStream send_stream_;
214   rtc::MemoryStream recv_stream_;
215   bool have_connected_;
216   bool have_disconnected_;
217   int local_mtu_;
218   int remote_mtu_;
219   int delay_;
220   int loss_;
221   bool drop_next_packet_ = false;
222   bool simultaneous_open_ = false;
223   int packets_in_flight_ = 0;
224 };
225 
226 class PseudoTcpTest : public PseudoTcpTestBase {
227  public:
TestTransfer(int size)228   void TestTransfer(int size) {
229     uint32_t start;
230     int32_t elapsed;
231     size_t received;
232     // Create some dummy data to send.
233     send_stream_.ReserveSize(size);
234     for (int i = 0; i < size; ++i) {
235       uint8_t ch = static_cast<uint8_t>(i);
236       size_t written;
237       int error;
238       send_stream_.Write(rtc::MakeArrayView(&ch, 1), written, error);
239     }
240     send_stream_.Rewind();
241     // Prepare the receive stream.
242     recv_stream_.ReserveSize(size);
243     // Connect and wait until connected.
244     start = rtc::Time32();
245     EXPECT_EQ(0, Connect());
246     EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs);
247     // Sending will start from OnTcpWriteable and complete when all data has
248     // been received.
249     EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs);
250     elapsed = rtc::Time32() - start;
251     recv_stream_.GetSize(&received);
252     // Ensure we closed down OK and we got the right data.
253     // TODO(?): Ensure the errors are cleared properly.
254     // EXPECT_EQ(0, local_.GetError());
255     // EXPECT_EQ(0, remote_.GetError());
256     EXPECT_EQ(static_cast<size_t>(size), received);
257     EXPECT_EQ(0,
258               memcmp(send_stream_.GetBuffer(), recv_stream_.GetBuffer(), size));
259     RTC_LOG(LS_INFO) << "Transferred " << received << " bytes in " << elapsed
260                      << " ms (" << size * 8 / elapsed << " Kbps)";
261   }
262 
263  private:
264   // IPseudoTcpNotify interface
265 
OnTcpReadable(PseudoTcp * tcp)266   virtual void OnTcpReadable(PseudoTcp* tcp) {
267     // Stream bytes to the recv stream as they arrive.
268     if (tcp == &remote_) {
269       ReadData();
270 
271       // TODO(?): OnTcpClosed() is currently only notified on error -
272       // there is no on-the-wire equivalent of TCP FIN.
273       // So we fake the notification when all the data has been read.
274       size_t received, required;
275       recv_stream_.GetPosition(&received);
276       send_stream_.GetSize(&required);
277       if (received == required)
278         OnTcpClosed(&remote_, 0);
279     }
280   }
OnTcpWriteable(PseudoTcp * tcp)281   virtual void OnTcpWriteable(PseudoTcp* tcp) {
282     // Write bytes from the send stream when we can.
283     // Shut down when we've sent everything.
284     if (tcp == &local_) {
285       RTC_LOG(LS_VERBOSE) << "Flow Control Lifted";
286       bool done;
287       WriteData(&done);
288       if (done) {
289         Close();
290       }
291     }
292   }
293 
ReadData()294   void ReadData() {
295     char block[kBlockSize];
296     size_t position;
297     int rcvd;
298     do {
299       rcvd = remote_.Recv(block, sizeof(block));
300       if (rcvd != -1) {
301         size_t written;
302         int error;
303         recv_stream_.Write(
304             rtc::MakeArrayView(reinterpret_cast<uint8_t*>(block), rcvd),
305             written, error);
306         recv_stream_.GetPosition(&position);
307         RTC_LOG(LS_VERBOSE) << "Received: " << position;
308       }
309     } while (rcvd > 0);
310   }
WriteData(bool * done)311   void WriteData(bool* done) {
312     size_t position, tosend;
313     int sent;
314     char block[kBlockSize];
315     do {
316       send_stream_.GetPosition(&position);
317       int error;
318       if (send_stream_.Read(
319               rtc::MakeArrayView(reinterpret_cast<uint8_t*>(block), kBlockSize),
320               tosend, error) != rtc::SR_EOS) {
321         sent = local_.Send(block, tosend);
322         UpdateLocalClock();
323         if (sent != -1) {
324           send_stream_.SetPosition(position + sent);
325           RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent;
326         } else {
327           send_stream_.SetPosition(position);
328           RTC_LOG(LS_VERBOSE) << "Flow Controlled";
329         }
330       } else {
331         sent = static_cast<int>(tosend = 0);
332       }
333     } while (sent > 0);
334     *done = (tosend == 0);
335   }
336 
337  private:
338   rtc::MemoryStream send_stream_;
339   rtc::MemoryStream recv_stream_;
340 };
341 
342 class PseudoTcpTestPingPong : public PseudoTcpTestBase {
343  public:
PseudoTcpTestPingPong()344   PseudoTcpTestPingPong()
345       : iterations_remaining_(0),
346         sender_(NULL),
347         receiver_(NULL),
348         bytes_per_send_(0) {}
SetBytesPerSend(int bytes)349   void SetBytesPerSend(int bytes) { bytes_per_send_ = bytes; }
TestPingPong(int size,int iterations)350   void TestPingPong(int size, int iterations) {
351     uint32_t start, elapsed;
352     iterations_remaining_ = iterations;
353     receiver_ = &remote_;
354     sender_ = &local_;
355     // Create some dummy data to send.
356     send_stream_.ReserveSize(size);
357     for (int i = 0; i < size; ++i) {
358       uint8_t ch = static_cast<uint8_t>(i);
359       size_t written;
360       int error;
361       send_stream_.Write(rtc::MakeArrayView(&ch, 1), written, error);
362     }
363     send_stream_.Rewind();
364     // Prepare the receive stream.
365     recv_stream_.ReserveSize(size);
366     // Connect and wait until connected.
367     start = rtc::Time32();
368     EXPECT_EQ(0, Connect());
369     EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs);
370     // Sending will start from OnTcpWriteable and stop when the required
371     // number of iterations have completed.
372     EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs);
373     elapsed = rtc::TimeSince(start);
374     RTC_LOG(LS_INFO) << "Performed " << iterations << " pings in " << elapsed
375                      << " ms";
376   }
377 
378  private:
379   // IPseudoTcpNotify interface
380 
OnTcpReadable(PseudoTcp * tcp)381   virtual void OnTcpReadable(PseudoTcp* tcp) {
382     if (tcp != receiver_) {
383       RTC_LOG_F(LS_ERROR) << "unexpected OnTcpReadable";
384       return;
385     }
386     // Stream bytes to the recv stream as they arrive.
387     ReadData();
388     // If we've received the desired amount of data, rewind things
389     // and send it back the other way!
390     size_t position, desired;
391     recv_stream_.GetPosition(&position);
392     send_stream_.GetSize(&desired);
393     if (position == desired) {
394       if (receiver_ == &local_ && --iterations_remaining_ == 0) {
395         Close();
396         // TODO(?): Fake OnTcpClosed() on the receiver for now.
397         OnTcpClosed(&remote_, 0);
398         return;
399       }
400       PseudoTcp* tmp = receiver_;
401       receiver_ = sender_;
402       sender_ = tmp;
403       recv_stream_.Rewind();
404       send_stream_.Rewind();
405       OnTcpWriteable(sender_);
406     }
407   }
OnTcpWriteable(PseudoTcp * tcp)408   virtual void OnTcpWriteable(PseudoTcp* tcp) {
409     if (tcp != sender_)
410       return;
411     // Write bytes from the send stream when we can.
412     // Shut down when we've sent everything.
413     RTC_LOG(LS_VERBOSE) << "Flow Control Lifted";
414     WriteData();
415   }
416 
ReadData()417   void ReadData() {
418     char block[kBlockSize];
419     size_t position;
420     int rcvd;
421     do {
422       rcvd = receiver_->Recv(block, sizeof(block));
423       if (rcvd != -1) {
424         size_t written;
425         int error;
426         recv_stream_.Write(
427             rtc::MakeArrayView(reinterpret_cast<const uint8_t*>(block), rcvd),
428             written, error);
429         recv_stream_.GetPosition(&position);
430         RTC_LOG(LS_VERBOSE) << "Received: " << position;
431       }
432     } while (rcvd > 0);
433   }
WriteData()434   void WriteData() {
435     size_t position, tosend;
436     int sent;
437     char block[kBlockSize];
438     do {
439       send_stream_.GetPosition(&position);
440       tosend = bytes_per_send_ ? bytes_per_send_ : sizeof(block);
441       int error;
442       if (send_stream_.Read(
443               rtc::MakeArrayView(reinterpret_cast<uint8_t*>(block), tosend),
444               tosend, error) != rtc::SR_EOS) {
445         sent = sender_->Send(block, tosend);
446         UpdateLocalClock();
447         if (sent != -1) {
448           send_stream_.SetPosition(position + sent);
449           RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent;
450         } else {
451           send_stream_.SetPosition(position);
452           RTC_LOG(LS_VERBOSE) << "Flow Controlled";
453         }
454       } else {
455         sent = static_cast<int>(tosend = 0);
456       }
457     } while (sent > 0);
458   }
459 
460  private:
461   int iterations_remaining_;
462   PseudoTcp* sender_;
463   PseudoTcp* receiver_;
464   int bytes_per_send_;
465 };
466 
467 // Fill the receiver window until it is full, drain it and then
468 // fill it with the same amount. This is to test that receiver window
469 // contracts and enlarges correctly.
470 class PseudoTcpTestReceiveWindow : public PseudoTcpTestBase {
471  public:
472   // Not all the data are transfered, `size` just need to be big enough
473   // to fill up the receiver window twice.
TestTransfer(int size)474   void TestTransfer(int size) {
475     // Create some dummy data to send.
476     send_stream_.ReserveSize(size);
477     for (int i = 0; i < size; ++i) {
478       uint8_t ch = static_cast<uint8_t>(i);
479       size_t written;
480       int error;
481       send_stream_.Write(rtc::MakeArrayView(&ch, 1), written, error);
482     }
483     send_stream_.Rewind();
484 
485     // Prepare the receive stream.
486     recv_stream_.ReserveSize(size);
487 
488     // Connect and wait until connected.
489     EXPECT_EQ(0, Connect());
490     EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs);
491 
492     TaskQueueBase::Current()->PostTask([this] { WriteData(); });
493     EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs);
494 
495     ASSERT_EQ(2u, send_position_.size());
496     ASSERT_EQ(2u, recv_position_.size());
497 
498     const size_t estimated_recv_window = EstimateReceiveWindowSize();
499 
500     // The difference in consecutive send positions should equal the
501     // receive window size or match very closely. This verifies that receive
502     // window is open after receiver drained all the data.
503     const size_t send_position_diff = send_position_[1] - send_position_[0];
504     EXPECT_GE(1024u, estimated_recv_window - send_position_diff);
505 
506     // Receiver drained the receive window twice.
507     EXPECT_EQ(2 * estimated_recv_window, recv_position_[1]);
508   }
509 
EstimateReceiveWindowSize() const510   uint32_t EstimateReceiveWindowSize() const {
511     return static_cast<uint32_t>(recv_position_[0]);
512   }
513 
EstimateSendWindowSize() const514   uint32_t EstimateSendWindowSize() const {
515     return static_cast<uint32_t>(send_position_[0] - recv_position_[0]);
516   }
517 
518  private:
519   // IPseudoTcpNotify interface
OnTcpReadable(PseudoTcp * tcp)520   virtual void OnTcpReadable(PseudoTcp* tcp) {}
521 
OnTcpWriteable(PseudoTcp * tcp)522   virtual void OnTcpWriteable(PseudoTcp* tcp) {}
523 
ReadUntilIOPending()524   void ReadUntilIOPending() {
525     char block[kBlockSize];
526     size_t position;
527     int rcvd;
528 
529     do {
530       rcvd = remote_.Recv(block, sizeof(block));
531       if (rcvd != -1) {
532         size_t written;
533         int error;
534         recv_stream_.Write(
535             rtc::MakeArrayView(reinterpret_cast<uint8_t*>(block), rcvd),
536             written, error);
537         recv_stream_.GetPosition(&position);
538         RTC_LOG(LS_VERBOSE) << "Received: " << position;
539       }
540     } while (rcvd > 0);
541 
542     recv_stream_.GetPosition(&position);
543     recv_position_.push_back(position);
544 
545     // Disconnect if we have done two transfers.
546     if (recv_position_.size() == 2u) {
547       Close();
548       OnTcpClosed(&remote_, 0);
549     } else {
550       WriteData();
551     }
552   }
553 
WriteData()554   void WriteData() {
555     size_t position, tosend;
556     int sent;
557     char block[kBlockSize];
558     do {
559       send_stream_.GetPosition(&position);
560       int error;
561       if (send_stream_.Read(
562               rtc::MakeArrayView(reinterpret_cast<uint8_t*>(block),
563                                  sizeof(block)),
564               tosend, error) != rtc::SR_EOS) {
565         sent = local_.Send(block, tosend);
566         UpdateLocalClock();
567         if (sent != -1) {
568           send_stream_.SetPosition(position + sent);
569           RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent;
570         } else {
571           send_stream_.SetPosition(position);
572           RTC_LOG(LS_VERBOSE) << "Flow Controlled";
573         }
574       } else {
575         sent = static_cast<int>(tosend = 0);
576       }
577     } while (sent > 0);
578     // At this point, we've filled up the available space in the send queue.
579 
580     if (packets_in_flight_ > 0) {
581       // If there are packet tasks, attempt to continue sending after giving
582       // those packets time to process, which should free up the send buffer.
583       rtc::Thread::Current()->PostDelayedTask([this] { WriteData(); },
584                                               TimeDelta::Millis(10));
585     } else {
586       if (!remote_.isReceiveBufferFull()) {
587         RTC_LOG(LS_ERROR) << "This shouldn't happen - the send buffer is full, "
588                              "the receive buffer is not, and there are no "
589                              "remaining messages to process.";
590       }
591       send_stream_.GetPosition(&position);
592       send_position_.push_back(position);
593 
594       // Drain the receiver buffer.
595       ReadUntilIOPending();
596     }
597   }
598 
599  private:
600   rtc::MemoryStream send_stream_;
601   rtc::MemoryStream recv_stream_;
602 
603   std::vector<size_t> send_position_;
604   std::vector<size_t> recv_position_;
605 };
606 
607 // Basic end-to-end data transfer tests
608 
609 // Test the normal case of sending data from one side to the other.
TEST_F(PseudoTcpTest,TestSend)610 TEST_F(PseudoTcpTest, TestSend) {
611   SetLocalMtu(1500);
612   SetRemoteMtu(1500);
613   TestTransfer(1000000);
614 }
615 
616 // Test sending data with a 50 ms RTT. Transmission should take longer due
617 // to a slower ramp-up in send rate.
TEST_F(PseudoTcpTest,TestSendWithDelay)618 TEST_F(PseudoTcpTest, TestSendWithDelay) {
619   SetLocalMtu(1500);
620   SetRemoteMtu(1500);
621   SetDelay(50);
622   TestTransfer(1000000);
623 }
624 
625 // Test sending data with packet loss. Transmission should take much longer due
626 // to send back-off when loss occurs.
TEST_F(PseudoTcpTest,TestSendWithLoss)627 TEST_F(PseudoTcpTest, TestSendWithLoss) {
628   SetLocalMtu(1500);
629   SetRemoteMtu(1500);
630   SetLoss(10);
631   TestTransfer(100000);  // less data so test runs faster
632 }
633 
634 // Test sending data with a 50 ms RTT and 10% packet loss. Transmission should
635 // take much longer due to send back-off and slower detection of loss.
TEST_F(PseudoTcpTest,TestSendWithDelayAndLoss)636 TEST_F(PseudoTcpTest, TestSendWithDelayAndLoss) {
637   SetLocalMtu(1500);
638   SetRemoteMtu(1500);
639   SetDelay(50);
640   SetLoss(10);
641   TestTransfer(100000);  // less data so test runs faster
642 }
643 
644 // Test sending data with 10% packet loss and Nagling disabled.  Transmission
645 // should take about the same time as with Nagling enabled.
TEST_F(PseudoTcpTest,TestSendWithLossAndOptNaglingOff)646 TEST_F(PseudoTcpTest, TestSendWithLossAndOptNaglingOff) {
647   SetLocalMtu(1500);
648   SetRemoteMtu(1500);
649   SetLoss(10);
650   SetOptNagling(false);
651   TestTransfer(100000);  // less data so test runs faster
652 }
653 
654 // Regression test for bugs.webrtc.org/9208.
655 //
656 // This bug resulted in corrupted data if a "connect" segment was received after
657 // a data segment. This is only possible if:
658 //
659 // * The initial "connect" segment is lost, and retransmitted later.
660 // * Both sides send "connect"s simultaneously, such that the local side thinks
661 //   a connection is established even before its "connect" has been
662 //   acknowledged.
663 // * Nagle algorithm disabled, allowing a data segment to be sent before the
664 //   "connect" has been acknowledged.
TEST_F(PseudoTcpTest,TestSendWhenFirstPacketLostWithOptNaglingOffAndSimultaneousOpen)665 TEST_F(PseudoTcpTest,
666        TestSendWhenFirstPacketLostWithOptNaglingOffAndSimultaneousOpen) {
667   SetLocalMtu(1500);
668   SetRemoteMtu(1500);
669   DropNextPacket();
670   SetOptNagling(false);
671   SetSimultaneousOpen(true);
672   TestTransfer(10000);
673 }
674 
675 // Test sending data with 10% packet loss and Delayed ACK disabled.
676 // Transmission should be slightly faster than with it enabled.
TEST_F(PseudoTcpTest,TestSendWithLossAndOptAckDelayOff)677 TEST_F(PseudoTcpTest, TestSendWithLossAndOptAckDelayOff) {
678   SetLocalMtu(1500);
679   SetRemoteMtu(1500);
680   SetLoss(10);
681   SetOptAckDelay(0);
682   TestTransfer(100000);
683 }
684 
685 // Test sending data with 50ms delay and Nagling disabled.
TEST_F(PseudoTcpTest,TestSendWithDelayAndOptNaglingOff)686 TEST_F(PseudoTcpTest, TestSendWithDelayAndOptNaglingOff) {
687   SetLocalMtu(1500);
688   SetRemoteMtu(1500);
689   SetDelay(50);
690   SetOptNagling(false);
691   TestTransfer(100000);  // less data so test runs faster
692 }
693 
694 // Test sending data with 50ms delay and Delayed ACK disabled.
TEST_F(PseudoTcpTest,TestSendWithDelayAndOptAckDelayOff)695 TEST_F(PseudoTcpTest, TestSendWithDelayAndOptAckDelayOff) {
696   SetLocalMtu(1500);
697   SetRemoteMtu(1500);
698   SetDelay(50);
699   SetOptAckDelay(0);
700   TestTransfer(100000);  // less data so test runs faster
701 }
702 
703 // Test a large receive buffer with a sender that doesn't support scaling.
TEST_F(PseudoTcpTest,TestSendRemoteNoWindowScale)704 TEST_F(PseudoTcpTest, TestSendRemoteNoWindowScale) {
705   SetLocalMtu(1500);
706   SetRemoteMtu(1500);
707   SetLocalOptRcvBuf(100000);
708   DisableRemoteWindowScale();
709   TestTransfer(1000000);
710 }
711 
712 // Test a large sender-side receive buffer with a receiver that doesn't support
713 // scaling.
TEST_F(PseudoTcpTest,TestSendLocalNoWindowScale)714 TEST_F(PseudoTcpTest, TestSendLocalNoWindowScale) {
715   SetLocalMtu(1500);
716   SetRemoteMtu(1500);
717   SetRemoteOptRcvBuf(100000);
718   DisableLocalWindowScale();
719   TestTransfer(1000000);
720 }
721 
722 // Test when both sides use window scaling.
TEST_F(PseudoTcpTest,TestSendBothUseWindowScale)723 TEST_F(PseudoTcpTest, TestSendBothUseWindowScale) {
724   SetLocalMtu(1500);
725   SetRemoteMtu(1500);
726   SetRemoteOptRcvBuf(100000);
727   SetLocalOptRcvBuf(100000);
728   TestTransfer(1000000);
729 }
730 
731 // Test using a large window scale value.
TEST_F(PseudoTcpTest,TestSendLargeInFlight)732 TEST_F(PseudoTcpTest, TestSendLargeInFlight) {
733   SetLocalMtu(1500);
734   SetRemoteMtu(1500);
735   SetRemoteOptRcvBuf(100000);
736   SetLocalOptRcvBuf(100000);
737   SetOptSndBuf(150000);
738   TestTransfer(1000000);
739 }
740 
TEST_F(PseudoTcpTest,TestSendBothUseLargeWindowScale)741 TEST_F(PseudoTcpTest, TestSendBothUseLargeWindowScale) {
742   SetLocalMtu(1500);
743   SetRemoteMtu(1500);
744   SetRemoteOptRcvBuf(1000000);
745   SetLocalOptRcvBuf(1000000);
746   TestTransfer(10000000);
747 }
748 
749 // Test using a small receive buffer.
TEST_F(PseudoTcpTest,TestSendSmallReceiveBuffer)750 TEST_F(PseudoTcpTest, TestSendSmallReceiveBuffer) {
751   SetLocalMtu(1500);
752   SetRemoteMtu(1500);
753   SetRemoteOptRcvBuf(10000);
754   SetLocalOptRcvBuf(10000);
755   TestTransfer(1000000);
756 }
757 
758 // Test using a very small receive buffer.
TEST_F(PseudoTcpTest,TestSendVerySmallReceiveBuffer)759 TEST_F(PseudoTcpTest, TestSendVerySmallReceiveBuffer) {
760   SetLocalMtu(1500);
761   SetRemoteMtu(1500);
762   SetRemoteOptRcvBuf(100);
763   SetLocalOptRcvBuf(100);
764   TestTransfer(100000);
765 }
766 
767 // Ping-pong (request/response) tests
768 
769 // Test sending <= 1x MTU of data in each ping/pong.  Should take <10ms.
TEST_F(PseudoTcpTestPingPong,TestPingPong1xMtu)770 TEST_F(PseudoTcpTestPingPong, TestPingPong1xMtu) {
771   SetLocalMtu(1500);
772   SetRemoteMtu(1500);
773   TestPingPong(100, 100);
774 }
775 
776 // Test sending 2x-3x MTU of data in each ping/pong.  Should take <10ms.
TEST_F(PseudoTcpTestPingPong,TestPingPong3xMtu)777 TEST_F(PseudoTcpTestPingPong, TestPingPong3xMtu) {
778   SetLocalMtu(1500);
779   SetRemoteMtu(1500);
780   TestPingPong(400, 100);
781 }
782 
783 // Test sending 1x-2x MTU of data in each ping/pong.
784 // Should take ~1s, due to interaction between Nagling and Delayed ACK.
TEST_F(PseudoTcpTestPingPong,TestPingPong2xMtu)785 TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtu) {
786   SetLocalMtu(1500);
787   SetRemoteMtu(1500);
788   TestPingPong(2000, 5);
789 }
790 
791 // Test sending 1x-2x MTU of data in each ping/pong with Delayed ACK off.
792 // Should take <10ms.
TEST_F(PseudoTcpTestPingPong,TestPingPong2xMtuWithAckDelayOff)793 TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtuWithAckDelayOff) {
794   SetLocalMtu(1500);
795   SetRemoteMtu(1500);
796   SetOptAckDelay(0);
797   TestPingPong(2000, 100);
798 }
799 
800 // Test sending 1x-2x MTU of data in each ping/pong with Nagling off.
801 // Should take <10ms.
TEST_F(PseudoTcpTestPingPong,TestPingPong2xMtuWithNaglingOff)802 TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtuWithNaglingOff) {
803   SetLocalMtu(1500);
804   SetRemoteMtu(1500);
805   SetOptNagling(false);
806   TestPingPong(2000, 5);
807 }
808 
809 // Test sending a ping as pair of short (non-full) segments.
810 // Should take ~1s, due to Delayed ACK interaction with Nagling.
TEST_F(PseudoTcpTestPingPong,TestPingPongShortSegments)811 TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegments) {
812   SetLocalMtu(1500);
813   SetRemoteMtu(1500);
814   SetOptAckDelay(5000);
815   SetBytesPerSend(50);  // i.e. two Send calls per payload
816   TestPingPong(100, 5);
817 }
818 
819 // Test sending ping as a pair of short (non-full) segments, with Nagling off.
820 // Should take <10ms.
TEST_F(PseudoTcpTestPingPong,TestPingPongShortSegmentsWithNaglingOff)821 TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegmentsWithNaglingOff) {
822   SetLocalMtu(1500);
823   SetRemoteMtu(1500);
824   SetOptNagling(false);
825   SetBytesPerSend(50);  // i.e. two Send calls per payload
826   TestPingPong(100, 5);
827 }
828 
829 // Test sending <= 1x MTU of data ping/pong, in two segments, no Delayed ACK.
830 // Should take ~1s.
TEST_F(PseudoTcpTestPingPong,TestPingPongShortSegmentsWithAckDelayOff)831 TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegmentsWithAckDelayOff) {
832   SetLocalMtu(1500);
833   SetRemoteMtu(1500);
834   SetBytesPerSend(50);  // i.e. two Send calls per payload
835   SetOptAckDelay(0);
836   TestPingPong(100, 5);
837 }
838 
839 // Test that receive window expands and contract correctly.
TEST_F(PseudoTcpTestReceiveWindow,TestReceiveWindow)840 TEST_F(PseudoTcpTestReceiveWindow, TestReceiveWindow) {
841   SetLocalMtu(1500);
842   SetRemoteMtu(1500);
843   SetOptNagling(false);
844   SetOptAckDelay(0);
845   TestTransfer(1024 * 1000);
846 }
847 
848 // Test setting send window size to a very small value.
TEST_F(PseudoTcpTestReceiveWindow,TestSetVerySmallSendWindowSize)849 TEST_F(PseudoTcpTestReceiveWindow, TestSetVerySmallSendWindowSize) {
850   SetLocalMtu(1500);
851   SetRemoteMtu(1500);
852   SetOptNagling(false);
853   SetOptAckDelay(0);
854   SetOptSndBuf(900);
855   TestTransfer(1024 * 1000);
856   EXPECT_EQ(900u, EstimateSendWindowSize());
857 }
858 
859 // Test setting receive window size to a value other than default.
TEST_F(PseudoTcpTestReceiveWindow,TestSetReceiveWindowSize)860 TEST_F(PseudoTcpTestReceiveWindow, TestSetReceiveWindowSize) {
861   SetLocalMtu(1500);
862   SetRemoteMtu(1500);
863   SetOptNagling(false);
864   SetOptAckDelay(0);
865   SetRemoteOptRcvBuf(100000);
866   SetLocalOptRcvBuf(100000);
867   TestTransfer(1024 * 1000);
868   EXPECT_EQ(100000u, EstimateReceiveWindowSize());
869 }
870 
871 /* Test sending data with mismatched MTUs. We should detect this and reduce
872 // our packet size accordingly.
873 // TODO(?): This doesn't actually work right now. The current code
874 // doesn't detect if the MTU is set too high on either side.
875 TEST_F(PseudoTcpTest, TestSendWithMismatchedMtus) {
876   SetLocalMtu(1500);
877   SetRemoteMtu(1280);
878   TestTransfer(1000000);
879 }
880 */
881