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