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