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