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 conv)30 PseudoTcpForTest(cricket::IPseudoTcpNotify* notify, uint32 conv)
31 : PseudoTcp(notify, conv) {
32 }
33
isReceiveBufferFull() const34 bool isReceiveBufferFull() const {
35 return PseudoTcp::isReceiveBufferFull();
36 }
37
disableWindowScale()38 void disableWindowScale() {
39 PseudoTcp::disableWindowScale();
40 }
41 };
42
43 class PseudoTcpTestBase : public testing::Test,
44 public rtc::MessageHandler,
45 public cricket::IPseudoTcpNotify {
46 public:
PseudoTcpTestBase()47 PseudoTcpTestBase()
48 : local_(this, 1),
49 remote_(this, 1),
50 have_connected_(false),
51 have_disconnected_(false),
52 local_mtu_(65535),
53 remote_mtu_(65535),
54 delay_(0),
55 loss_(0) {
56 // Set use of the test RNG to get predictable loss patterns.
57 rtc::SetRandomTestMode(true);
58 }
~PseudoTcpTestBase()59 ~PseudoTcpTestBase() {
60 // Put it back for the next test.
61 rtc::SetRandomTestMode(false);
62 }
SetLocalMtu(int mtu)63 void SetLocalMtu(int mtu) {
64 local_.NotifyMTU(mtu);
65 local_mtu_ = mtu;
66 }
SetRemoteMtu(int mtu)67 void SetRemoteMtu(int mtu) {
68 remote_.NotifyMTU(mtu);
69 remote_mtu_ = mtu;
70 }
SetDelay(int delay)71 void SetDelay(int delay) {
72 delay_ = delay;
73 }
SetLoss(int percent)74 void SetLoss(int percent) {
75 loss_ = percent;
76 }
SetOptNagling(bool enable_nagles)77 void SetOptNagling(bool enable_nagles) {
78 local_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles);
79 remote_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles);
80 }
SetOptAckDelay(int ack_delay)81 void SetOptAckDelay(int ack_delay) {
82 local_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay);
83 remote_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay);
84 }
SetOptSndBuf(int size)85 void SetOptSndBuf(int size) {
86 local_.SetOption(PseudoTcp::OPT_SNDBUF, size);
87 remote_.SetOption(PseudoTcp::OPT_SNDBUF, size);
88 }
SetRemoteOptRcvBuf(int size)89 void SetRemoteOptRcvBuf(int size) {
90 remote_.SetOption(PseudoTcp::OPT_RCVBUF, size);
91 }
SetLocalOptRcvBuf(int size)92 void SetLocalOptRcvBuf(int size) {
93 local_.SetOption(PseudoTcp::OPT_RCVBUF, size);
94 }
DisableRemoteWindowScale()95 void DisableRemoteWindowScale() {
96 remote_.disableWindowScale();
97 }
DisableLocalWindowScale()98 void DisableLocalWindowScale() {
99 local_.disableWindowScale();
100 }
101
102 protected:
Connect()103 int Connect() {
104 int ret = local_.Connect();
105 if (ret == 0) {
106 UpdateLocalClock();
107 }
108 return ret;
109 }
Close()110 void Close() {
111 local_.Close(false);
112 UpdateLocalClock();
113 }
114
115 enum { MSG_LPACKET, MSG_RPACKET, MSG_LCLOCK, MSG_RCLOCK, MSG_IOCOMPLETE,
116 MSG_WRITE};
OnTcpOpen(PseudoTcp * tcp)117 virtual void OnTcpOpen(PseudoTcp* tcp) {
118 // Consider ourselves connected when the local side gets OnTcpOpen.
119 // OnTcpWriteable isn't fired at open, so we trigger it now.
120 LOG(LS_VERBOSE) << "Opened";
121 if (tcp == &local_) {
122 have_connected_ = true;
123 OnTcpWriteable(tcp);
124 }
125 }
126 // Test derived from the base should override
127 // virtual void OnTcpReadable(PseudoTcp* tcp)
128 // and
129 // virtual void OnTcpWritable(PseudoTcp* tcp)
OnTcpClosed(PseudoTcp * tcp,uint32 error)130 virtual void OnTcpClosed(PseudoTcp* tcp, uint32 error) {
131 // Consider ourselves closed when the remote side gets OnTcpClosed.
132 // TODO: OnTcpClosed is only ever notified in case of error in
133 // the current implementation. Solicited close is not (yet) supported.
134 LOG(LS_VERBOSE) << "Closed";
135 EXPECT_EQ(0U, error);
136 if (tcp == &remote_) {
137 have_disconnected_ = true;
138 }
139 }
TcpWritePacket(PseudoTcp * tcp,const char * buffer,size_t len)140 virtual WriteResult TcpWritePacket(PseudoTcp* tcp,
141 const char* buffer, size_t len) {
142 // Randomly drop the desired percentage of packets.
143 // Also drop packets that are larger than the configured MTU.
144 if (rtc::CreateRandomId() % 100 < static_cast<uint32>(loss_)) {
145 LOG(LS_VERBOSE) << "Randomly dropping packet, size=" << len;
146 } else if (len > static_cast<size_t>(std::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
UpdateLocalClock()157 void UpdateLocalClock() { UpdateClock(&local_, MSG_LCLOCK); }
UpdateRemoteClock()158 void UpdateRemoteClock() { UpdateClock(&remote_, MSG_RCLOCK); }
UpdateClock(PseudoTcp * tcp,uint32 message)159 void UpdateClock(PseudoTcp* tcp, uint32 message) {
160 long interval = 0; // NOLINT
161 tcp->GetNextClock(PseudoTcp::Now(), interval);
162 interval = std::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
OnMessage(rtc::Message * message)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
209 class PseudoTcpTest : public PseudoTcpTestBase {
210 public:
TestTransfer(int size)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
OnTcpReadable(PseudoTcp * tcp)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 }
OnTcpWriteable(PseudoTcp * tcp)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
ReadData()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 }
WriteData(bool * done)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
317 class PseudoTcpTestPingPong : public PseudoTcpTestBase {
318 public:
PseudoTcpTestPingPong()319 PseudoTcpTestPingPong()
320 : iterations_remaining_(0),
321 sender_(NULL),
322 receiver_(NULL),
323 bytes_per_send_(0) {
324 }
SetBytesPerSend(int bytes)325 void SetBytesPerSend(int bytes) {
326 bytes_per_send_ = bytes;
327 }
TestPingPong(int size,int iterations)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
OnTcpReadable(PseudoTcp * tcp)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 }
OnTcpWriteable(PseudoTcp * tcp)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
ReadData()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 }
WriteData()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.
440 class 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.
TestTransfer(int size)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
OnMessage(rtc::Message * message)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
EstimateReceiveWindowSize() const492 uint32 EstimateReceiveWindowSize() const {
493 return static_cast<uint32>(recv_position_[0]);
494 }
495
EstimateSendWindowSize() const496 uint32 EstimateSendWindowSize() const {
497 return static_cast<uint32>(send_position_[0] - recv_position_[0]);
498 }
499
500 private:
501 // IPseudoTcpNotify interface
OnTcpReadable(PseudoTcp * tcp)502 virtual void OnTcpReadable(PseudoTcp* tcp) {
503 }
504
OnTcpWriteable(PseudoTcp * tcp)505 virtual void OnTcpWriteable(PseudoTcp* tcp) {
506 }
507
ReadUntilIOPending()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
WriteData()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.
TEST_F(PseudoTcpTest,TestSend)592 TEST_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.
TEST_F(PseudoTcpTest,TestSendWithDelay)600 TEST_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.
TEST_F(PseudoTcpTest,TestSendWithLoss)609 TEST_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.
TEST_F(PseudoTcpTest,TestSendWithDelayAndLoss)618 TEST_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.
TEST_F(PseudoTcpTest,TestSendWithLossAndOptNaglingOff)628 TEST_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.
TEST_F(PseudoTcpTest,TestSendWithLossAndOptAckDelayOff)638 TEST_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.
TEST_F(PseudoTcpTest,TestSendWithDelayAndOptNaglingOff)647 TEST_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.
TEST_F(PseudoTcpTest,TestSendWithDelayAndOptAckDelayOff)656 TEST_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.
TEST_F(PseudoTcpTest,TestSendRemoteNoWindowScale)665 TEST_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.
TEST_F(PseudoTcpTest,TestSendLocalNoWindowScale)675 TEST_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.
TEST_F(PseudoTcpTest,TestSendBothUseWindowScale)684 TEST_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.
TEST_F(PseudoTcpTest,TestSendLargeInFlight)693 TEST_F(PseudoTcpTest, TestSendLargeInFlight) {
694 SetLocalMtu(1500);
695 SetRemoteMtu(1500);
696 SetRemoteOptRcvBuf(100000);
697 SetLocalOptRcvBuf(100000);
698 SetOptSndBuf(150000);
699 TestTransfer(1000000);
700 }
701
TEST_F(PseudoTcpTest,TestSendBothUseLargeWindowScale)702 TEST_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.
TEST_F(PseudoTcpTest,TestSendSmallReceiveBuffer)711 TEST_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.
TEST_F(PseudoTcpTest,TestSendVerySmallReceiveBuffer)720 TEST_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.
TEST_F(PseudoTcpTestPingPong,TestPingPong1xMtu)731 TEST_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.
TEST_F(PseudoTcpTestPingPong,TestPingPong3xMtu)738 TEST_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.
TEST_F(PseudoTcpTestPingPong,TestPingPong2xMtu)746 TEST_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.
TEST_F(PseudoTcpTestPingPong,TestPingPong2xMtuWithAckDelayOff)754 TEST_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.
TEST_F(PseudoTcpTestPingPong,TestPingPong2xMtuWithNaglingOff)763 TEST_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.
TEST_F(PseudoTcpTestPingPong,TestPingPongShortSegments)772 TEST_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.
TEST_F(PseudoTcpTestPingPong,TestPingPongShortSegmentsWithNaglingOff)782 TEST_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.
TEST_F(PseudoTcpTestPingPong,TestPingPongShortSegmentsWithAckDelayOff)792 TEST_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.
TEST_F(PseudoTcpTestReceiveWindow,TestReceiveWindow)801 TEST_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.
TEST_F(PseudoTcpTestReceiveWindow,TestSetVerySmallSendWindowSize)810 TEST_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.
TEST_F(PseudoTcpTestReceiveWindow,TestSetReceiveWindowSize)821 TEST_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.
836 TEST_F(PseudoTcpTest, TestSendWithMismatchedMtus) {
837 SetLocalMtu(1500);
838 SetRemoteMtu(1280);
839 TestTransfer(1000000);
840 }
841 */
842