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