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