1/* 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/p2p/base/pseudotcp.h" 31#include "webrtc/base/gunit.h" 32#include "webrtc/base/helpers.h" 33#include "webrtc/base/messagehandler.h" 34#include "webrtc/base/stream.h" 35#include "webrtc/base/thread.h" 36#include "webrtc/base/timeutils.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 rtc::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 rtc::SetRandomTestMode(true); 74 } 75 ~PseudoTcpTestBase() { 76 // Put it back for the next test. 77 rtc::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 (rtc::CreateRandomId() % 100 < static_cast<uint32>(loss_)) { 161 LOG(LS_VERBOSE) << "Randomly dropping packet, size=" << len; 162 } else if (len > static_cast<size_t>( 163 rtc::_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 rtc::Thread::Current()->PostDelayed(delay_, this, id, 169 rtc::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 = 0; // NOLINT 178 tcp->GetNextClock(PseudoTcp::Now(), interval); 179 interval = rtc::_max<int>(interval, 0L); // sometimes interval is < 0 180 rtc::Thread::Current()->Clear(this, message); 181 rtc::Thread::Current()->PostDelayed(interval, this, message); 182 } 183 184 virtual void OnMessage(rtc::Message* message) { 185 switch (message->message_id) { 186 case MSG_LPACKET: { 187 const std::string& s( 188 rtc::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 rtc::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 rtc::MemoryStream send_stream_; 217 rtc::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 = rtc::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 = rtc::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 rtc::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 { 322 sent = static_cast<int>(tosend = 0); 323 } 324 } while (sent > 0); 325 *done = (tosend == 0); 326 } 327 328 private: 329 rtc::MemoryStream send_stream_; 330 rtc::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 = rtc::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 = rtc::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 rtc::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 { 442 sent = static_cast<int>(tosend = 0); 443 } 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 rtc::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(rtc::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 { 510 return static_cast<uint32>(recv_position_[0]); 511 } 512 513 uint32 EstimateSendWindowSize() const { 514 return static_cast<uint32>(send_position_[0] - recv_position_[0]); 515 } 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 rtc::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 { 569 sent = static_cast<int>(tosend = 0); 570 } 571 } while (sent > 0); 572 // At this point, we've filled up the available space in the send queue. 573 574 int message_queue_size = 575 static_cast<int>(rtc::Thread::Current()->size()); 576 // 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 rtc::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 rtc::MemoryStream send_stream_; 600 rtc::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*/ 859