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