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