blob: c9ccbca1d9515cdfc8ba8afe847400a1b86cca58 [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001/*
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
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000011#include <algorithm>
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000012#include <vector>
13
pthatcher@webrtc.orge9db7fe2014-12-13 01:56:39 +000014#include "webrtc/p2p/base/pseudotcp.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000015#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
22using cricket::PseudoTcp;
23
24static const int kConnectTimeoutMs = 10000; // ~3 * default RTO of 3000ms
25static const int kTransferTimeoutMs = 15000;
26static const int kBlockSize = 4096;
27
28class PseudoTcpForTest : public cricket::PseudoTcp {
29 public:
Peter Boström0c4e06b2015-10-07 12:23:21 +020030 PseudoTcpForTest(cricket::IPseudoTcpNotify* notify, uint32_t conv)
31 : PseudoTcp(notify, conv) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000032
33 bool isReceiveBufferFull() const {
34 return PseudoTcp::isReceiveBufferFull();
35 }
36
37 void disableWindowScale() {
38 PseudoTcp::disableWindowScale();
39 }
40};
41
42class PseudoTcpTestBase : public testing::Test,
43 public rtc::MessageHandler,
44 public cricket::IPseudoTcpNotify {
45 public:
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 }
58 ~PseudoTcpTestBase() {
59 // Put it back for the next test.
60 rtc::SetRandomTestMode(false);
61 }
62 void SetLocalMtu(int mtu) {
63 local_.NotifyMTU(mtu);
64 local_mtu_ = mtu;
65 }
66 void SetRemoteMtu(int mtu) {
67 remote_.NotifyMTU(mtu);
68 remote_mtu_ = mtu;
69 }
70 void SetDelay(int delay) {
71 delay_ = delay;
72 }
73 void SetLoss(int percent) {
74 loss_ = percent;
75 }
76 void SetOptNagling(bool enable_nagles) {
77 local_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles);
78 remote_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles);
79 }
80 void SetOptAckDelay(int ack_delay) {
81 local_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay);
82 remote_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay);
83 }
84 void SetOptSndBuf(int size) {
85 local_.SetOption(PseudoTcp::OPT_SNDBUF, size);
86 remote_.SetOption(PseudoTcp::OPT_SNDBUF, size);
87 }
88 void SetRemoteOptRcvBuf(int size) {
89 remote_.SetOption(PseudoTcp::OPT_RCVBUF, size);
90 }
91 void SetLocalOptRcvBuf(int size) {
92 local_.SetOption(PseudoTcp::OPT_RCVBUF, size);
93 }
94 void DisableRemoteWindowScale() {
95 remote_.disableWindowScale();
96 }
97 void DisableLocalWindowScale() {
98 local_.disableWindowScale();
99 }
100
101 protected:
102 int Connect() {
103 int ret = local_.Connect();
104 if (ret == 0) {
105 UpdateLocalClock();
106 }
107 return ret;
108 }
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};
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)
Peter Boström0c4e06b2015-10-07 12:23:21 +0200129 virtual void OnTcpClosed(PseudoTcp* tcp, uint32_t error) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000130 // 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 }
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.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200143 if (rtc::CreateRandomId() % 100 < static_cast<uint32_t>(loss_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000144 LOG(LS_VERBOSE) << "Randomly dropping packet, size=" << len;
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000145 } else if (len > static_cast<size_t>(std::min(local_mtu_, remote_mtu_))) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000146 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
156 void UpdateLocalClock() { UpdateClock(&local_, MSG_LCLOCK); }
157 void UpdateRemoteClock() { UpdateClock(&remote_, MSG_RCLOCK); }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200158 void UpdateClock(PseudoTcp* tcp, uint32_t message) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000159 long interval = 0; // NOLINT
160 tcp->GetNextClock(PseudoTcp::Now(), interval);
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000161 interval = std::max<int>(interval, 0L); // sometimes interval is < 0
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000162 rtc::Thread::Current()->Clear(this, message);
163 rtc::Thread::Current()->PostDelayed(interval, this, message);
164 }
165
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
208class PseudoTcpTest : public PseudoTcpTestBase {
209 public:
210 void TestTransfer(int size) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200211 uint32_t start, elapsed;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000212 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
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 }
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
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 }
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
316class PseudoTcpTestPingPong : public PseudoTcpTestBase {
317 public:
318 PseudoTcpTestPingPong()
319 : iterations_remaining_(0),
320 sender_(NULL),
321 receiver_(NULL),
322 bytes_per_send_(0) {
323 }
324 void SetBytesPerSend(int bytes) {
325 bytes_per_send_ = bytes;
326 }
327 void TestPingPong(int size, int iterations) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200328 uint32_t start, elapsed;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000329 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
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 }
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
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 }
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.
439class 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.
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
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
Peter Boström0c4e06b2015-10-07 12:23:21 +0200491 uint32_t EstimateReceiveWindowSize() const {
492 return static_cast<uint32_t>(recv_position_[0]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000493 }
494
Peter Boström0c4e06b2015-10-07 12:23:21 +0200495 uint32_t EstimateSendWindowSize() const {
496 return static_cast<uint32_t>(send_position_[0] - recv_position_[0]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000497 }
498
499 private:
500 // IPseudoTcpNotify interface
501 virtual void OnTcpReadable(PseudoTcp* tcp) {
502 }
503
504 virtual void OnTcpWriteable(PseudoTcp* tcp) {
505 }
506
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
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.
591TEST_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.
599TEST_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.
608TEST_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.
617TEST_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.
627TEST_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.
637TEST_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.
646TEST_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.
655TEST_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.
664TEST_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.
674TEST_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.
683TEST_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.
692TEST_F(PseudoTcpTest, TestSendLargeInFlight) {
693 SetLocalMtu(1500);
694 SetRemoteMtu(1500);
695 SetRemoteOptRcvBuf(100000);
696 SetLocalOptRcvBuf(100000);
697 SetOptSndBuf(150000);
698 TestTransfer(1000000);
699}
700
701TEST_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.
710TEST_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.
719TEST_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.
730TEST_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.
737TEST_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.
745TEST_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.
753TEST_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.
762TEST_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.
771TEST_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.
781TEST_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.
791TEST_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.
800TEST_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.
809TEST_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.
820TEST_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.
835TEST_F(PseudoTcpTest, TestSendWithMismatchedMtus) {
836 SetLocalMtu(1500);
837 SetRemoteMtu(1280);
838 TestTransfer(1000000);
839}
840*/