blob: 4dd4cd83d1236b0fe8b7b15dc4f432ec72c36ee1 [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
Steve Antoncc65bd02017-11-29 10:19:58 -080033 bool isReceiveBufferFull() const { return PseudoTcp::isReceiveBufferFull(); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000034
Steve Antoncc65bd02017-11-29 10:19:58 -080035 void disableWindowScale() { PseudoTcp::disableWindowScale(); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000036};
37
38class PseudoTcpTestBase : public testing::Test,
Steve Antoncc65bd02017-11-29 10:19:58 -080039 public rtc::MessageHandler,
40 public cricket::IPseudoTcpNotify {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000041 public:
42 PseudoTcpTestBase()
43 : local_(this, 1),
44 remote_(this, 1),
45 have_connected_(false),
46 have_disconnected_(false),
47 local_mtu_(65535),
48 remote_mtu_(65535),
49 delay_(0),
50 loss_(0) {
51 // Set use of the test RNG to get predictable loss patterns.
52 rtc::SetRandomTestMode(true);
53 }
54 ~PseudoTcpTestBase() {
55 // Put it back for the next test.
56 rtc::SetRandomTestMode(false);
57 }
58 void SetLocalMtu(int mtu) {
59 local_.NotifyMTU(mtu);
60 local_mtu_ = mtu;
61 }
62 void SetRemoteMtu(int mtu) {
63 remote_.NotifyMTU(mtu);
64 remote_mtu_ = mtu;
65 }
Steve Antoncc65bd02017-11-29 10:19:58 -080066 void SetDelay(int delay) { delay_ = delay; }
67 void SetLoss(int percent) { loss_ = percent; }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000068 void SetOptNagling(bool enable_nagles) {
69 local_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles);
70 remote_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles);
71 }
72 void SetOptAckDelay(int ack_delay) {
73 local_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay);
74 remote_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay);
75 }
76 void SetOptSndBuf(int size) {
77 local_.SetOption(PseudoTcp::OPT_SNDBUF, size);
78 remote_.SetOption(PseudoTcp::OPT_SNDBUF, size);
79 }
80 void SetRemoteOptRcvBuf(int size) {
81 remote_.SetOption(PseudoTcp::OPT_RCVBUF, size);
82 }
83 void SetLocalOptRcvBuf(int size) {
84 local_.SetOption(PseudoTcp::OPT_RCVBUF, size);
85 }
Steve Antoncc65bd02017-11-29 10:19:58 -080086 void DisableRemoteWindowScale() { remote_.disableWindowScale(); }
87 void DisableLocalWindowScale() { local_.disableWindowScale(); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000088
89 protected:
90 int Connect() {
91 int ret = local_.Connect();
92 if (ret == 0) {
93 UpdateLocalClock();
94 }
95 return ret;
96 }
97 void Close() {
98 local_.Close(false);
99 UpdateLocalClock();
100 }
101
Steve Antoncc65bd02017-11-29 10:19:58 -0800102 enum {
103 MSG_LPACKET,
104 MSG_RPACKET,
105 MSG_LCLOCK,
106 MSG_RCLOCK,
107 MSG_IOCOMPLETE,
108 MSG_WRITE
109 };
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000110 virtual void OnTcpOpen(PseudoTcp* tcp) {
111 // Consider ourselves connected when the local side gets OnTcpOpen.
112 // OnTcpWriteable isn't fired at open, so we trigger it now.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100113 RTC_LOG(LS_VERBOSE) << "Opened";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000114 if (tcp == &local_) {
115 have_connected_ = true;
116 OnTcpWriteable(tcp);
117 }
118 }
119 // Test derived from the base should override
120 // virtual void OnTcpReadable(PseudoTcp* tcp)
121 // and
122 // virtual void OnTcpWritable(PseudoTcp* tcp)
Peter Boström0c4e06b2015-10-07 12:23:21 +0200123 virtual void OnTcpClosed(PseudoTcp* tcp, uint32_t error) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000124 // Consider ourselves closed when the remote side gets OnTcpClosed.
125 // TODO: OnTcpClosed is only ever notified in case of error in
126 // the current implementation. Solicited close is not (yet) supported.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100127 RTC_LOG(LS_VERBOSE) << "Closed";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000128 EXPECT_EQ(0U, error);
129 if (tcp == &remote_) {
130 have_disconnected_ = true;
131 }
132 }
133 virtual WriteResult TcpWritePacket(PseudoTcp* tcp,
Steve Antoncc65bd02017-11-29 10:19:58 -0800134 const char* buffer,
135 size_t len) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000136 // Randomly drop the desired percentage of packets.
137 // Also drop packets that are larger than the configured MTU.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200138 if (rtc::CreateRandomId() % 100 < static_cast<uint32_t>(loss_)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100139 RTC_LOG(LS_VERBOSE) << "Randomly dropping packet, size=" << len;
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000140 } else if (len > static_cast<size_t>(std::min(local_mtu_, remote_mtu_))) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100141 RTC_LOG(LS_VERBOSE) << "Dropping packet that exceeds path MTU, size="
142 << len;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000143 } else {
144 int id = (tcp == &local_) ? MSG_RPACKET : MSG_LPACKET;
145 std::string packet(buffer, len);
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700146 rtc::Thread::Current()->PostDelayed(RTC_FROM_HERE, delay_, this, id,
147 rtc::WrapMessageData(packet));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000148 }
149 return WR_SUCCESS;
150 }
151
152 void UpdateLocalClock() { UpdateClock(&local_, MSG_LCLOCK); }
153 void UpdateRemoteClock() { UpdateClock(&remote_, MSG_RCLOCK); }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200154 void UpdateClock(PseudoTcp* tcp, uint32_t message) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000155 long interval = 0; // NOLINT
156 tcp->GetNextClock(PseudoTcp::Now(), interval);
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000157 interval = std::max<int>(interval, 0L); // sometimes interval is < 0
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000158 rtc::Thread::Current()->Clear(this, message);
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700159 rtc::Thread::Current()->PostDelayed(RTC_FROM_HERE, interval, this, message);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000160 }
161
162 virtual void OnMessage(rtc::Message* message) {
163 switch (message->message_id) {
164 case MSG_LPACKET: {
Steve Antoncc65bd02017-11-29 10:19:58 -0800165 const std::string& s(rtc::UseMessageData<std::string>(message->pdata));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000166 local_.NotifyPacket(s.c_str(), s.size());
167 UpdateLocalClock();
168 break;
169 }
170 case MSG_RPACKET: {
Steve Antoncc65bd02017-11-29 10:19:58 -0800171 const std::string& s(rtc::UseMessageData<std::string>(message->pdata));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000172 remote_.NotifyPacket(s.c_str(), s.size());
173 UpdateRemoteClock();
174 break;
175 }
176 case MSG_LCLOCK:
177 local_.NotifyClock(PseudoTcp::Now());
178 UpdateLocalClock();
179 break;
180 case MSG_RCLOCK:
181 remote_.NotifyClock(PseudoTcp::Now());
182 UpdateRemoteClock();
183 break;
184 default:
185 break;
186 }
187 delete message->pdata;
188 }
189
190 PseudoTcpForTest local_;
191 PseudoTcpForTest remote_;
192 rtc::MemoryStream send_stream_;
193 rtc::MemoryStream recv_stream_;
194 bool have_connected_;
195 bool have_disconnected_;
196 int local_mtu_;
197 int remote_mtu_;
198 int delay_;
199 int loss_;
200};
201
202class PseudoTcpTest : public PseudoTcpTestBase {
203 public:
204 void TestTransfer(int size) {
Honghai Zhang82d78622016-05-06 11:29:15 -0700205 uint32_t start;
206 int32_t elapsed;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000207 size_t received;
208 // Create some dummy data to send.
209 send_stream_.ReserveSize(size);
210 for (int i = 0; i < size; ++i) {
211 char ch = static_cast<char>(i);
212 send_stream_.Write(&ch, 1, NULL, NULL);
213 }
214 send_stream_.Rewind();
215 // Prepare the receive stream.
216 recv_stream_.ReserveSize(size);
217 // Connect and wait until connected.
Honghai Zhang82d78622016-05-06 11:29:15 -0700218 start = rtc::Time32();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000219 EXPECT_EQ(0, Connect());
220 EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs);
221 // Sending will start from OnTcpWriteable and complete when all data has
222 // been received.
223 EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs);
Honghai Zhang82d78622016-05-06 11:29:15 -0700224 elapsed = rtc::Time32() - start;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000225 recv_stream_.GetSize(&received);
226 // Ensure we closed down OK and we got the right data.
227 // TODO: Ensure the errors are cleared properly.
Steve Antoncc65bd02017-11-29 10:19:58 -0800228 // EXPECT_EQ(0, local_.GetError());
229 // EXPECT_EQ(0, remote_.GetError());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000230 EXPECT_EQ(static_cast<size_t>(size), received);
Steve Antoncc65bd02017-11-29 10:19:58 -0800231 EXPECT_EQ(0,
232 memcmp(send_stream_.GetBuffer(), recv_stream_.GetBuffer(), size));
Mirko Bonadei675513b2017-11-09 11:09:25 +0100233 RTC_LOG(LS_INFO) << "Transferred " << received << " bytes in " << elapsed
234 << " ms (" << size * 8 / elapsed << " Kbps)";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000235 }
236
237 private:
238 // IPseudoTcpNotify interface
239
240 virtual void OnTcpReadable(PseudoTcp* tcp) {
241 // Stream bytes to the recv stream as they arrive.
242 if (tcp == &remote_) {
243 ReadData();
244
245 // TODO: OnTcpClosed() is currently only notified on error -
246 // there is no on-the-wire equivalent of TCP FIN.
247 // So we fake the notification when all the data has been read.
248 size_t received, required;
249 recv_stream_.GetPosition(&received);
250 send_stream_.GetSize(&required);
251 if (received == required)
252 OnTcpClosed(&remote_, 0);
253 }
254 }
255 virtual void OnTcpWriteable(PseudoTcp* tcp) {
256 // Write bytes from the send stream when we can.
257 // Shut down when we've sent everything.
258 if (tcp == &local_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100259 RTC_LOG(LS_VERBOSE) << "Flow Control Lifted";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000260 bool done;
261 WriteData(&done);
262 if (done) {
263 Close();
264 }
265 }
266 }
267
268 void ReadData() {
269 char block[kBlockSize];
270 size_t position;
271 int rcvd;
272 do {
273 rcvd = remote_.Recv(block, sizeof(block));
274 if (rcvd != -1) {
275 recv_stream_.Write(block, rcvd, NULL, NULL);
276 recv_stream_.GetPosition(&position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100277 RTC_LOG(LS_VERBOSE) << "Received: " << position;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000278 }
279 } while (rcvd > 0);
280 }
281 void WriteData(bool* done) {
282 size_t position, tosend;
283 int sent;
284 char block[kBlockSize];
285 do {
286 send_stream_.GetPosition(&position);
287 if (send_stream_.Read(block, sizeof(block), &tosend, NULL) !=
288 rtc::SR_EOS) {
289 sent = local_.Send(block, tosend);
290 UpdateLocalClock();
291 if (sent != -1) {
292 send_stream_.SetPosition(position + sent);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100293 RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000294 } else {
295 send_stream_.SetPosition(position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100296 RTC_LOG(LS_VERBOSE) << "Flow Controlled";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000297 }
298 } else {
299 sent = static_cast<int>(tosend = 0);
300 }
301 } while (sent > 0);
302 *done = (tosend == 0);
303 }
304
305 private:
306 rtc::MemoryStream send_stream_;
307 rtc::MemoryStream recv_stream_;
308};
309
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000310class PseudoTcpTestPingPong : public PseudoTcpTestBase {
311 public:
312 PseudoTcpTestPingPong()
313 : iterations_remaining_(0),
Steve Antoncc65bd02017-11-29 10:19:58 -0800314 sender_(NULL),
315 receiver_(NULL),
316 bytes_per_send_(0) {}
317 void SetBytesPerSend(int bytes) { bytes_per_send_ = bytes; }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000318 void TestPingPong(int size, int iterations) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200319 uint32_t start, elapsed;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000320 iterations_remaining_ = iterations;
321 receiver_ = &remote_;
322 sender_ = &local_;
323 // Create some dummy data to send.
324 send_stream_.ReserveSize(size);
325 for (int i = 0; i < size; ++i) {
326 char ch = static_cast<char>(i);
327 send_stream_.Write(&ch, 1, NULL, NULL);
328 }
329 send_stream_.Rewind();
330 // Prepare the receive stream.
331 recv_stream_.ReserveSize(size);
332 // Connect and wait until connected.
Honghai Zhang82d78622016-05-06 11:29:15 -0700333 start = rtc::Time32();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000334 EXPECT_EQ(0, Connect());
335 EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs);
336 // Sending will start from OnTcpWriteable and stop when the required
337 // number of iterations have completed.
338 EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs);
339 elapsed = rtc::TimeSince(start);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100340 RTC_LOG(LS_INFO) << "Performed " << iterations << " pings in " << elapsed
341 << " ms";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000342 }
343
344 private:
345 // IPseudoTcpNotify interface
346
347 virtual void OnTcpReadable(PseudoTcp* tcp) {
348 if (tcp != receiver_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100349 RTC_LOG_F(LS_ERROR) << "unexpected OnTcpReadable";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000350 return;
351 }
352 // Stream bytes to the recv stream as they arrive.
353 ReadData();
354 // If we've received the desired amount of data, rewind things
355 // and send it back the other way!
356 size_t position, desired;
357 recv_stream_.GetPosition(&position);
358 send_stream_.GetSize(&desired);
359 if (position == desired) {
360 if (receiver_ == &local_ && --iterations_remaining_ == 0) {
361 Close();
362 // TODO: Fake OnTcpClosed() on the receiver for now.
363 OnTcpClosed(&remote_, 0);
364 return;
365 }
366 PseudoTcp* tmp = receiver_;
367 receiver_ = sender_;
368 sender_ = tmp;
369 recv_stream_.Rewind();
370 send_stream_.Rewind();
371 OnTcpWriteable(sender_);
372 }
373 }
374 virtual void OnTcpWriteable(PseudoTcp* tcp) {
375 if (tcp != sender_)
376 return;
377 // Write bytes from the send stream when we can.
378 // Shut down when we've sent everything.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100379 RTC_LOG(LS_VERBOSE) << "Flow Control Lifted";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000380 WriteData();
381 }
382
383 void ReadData() {
384 char block[kBlockSize];
385 size_t position;
386 int rcvd;
387 do {
388 rcvd = receiver_->Recv(block, sizeof(block));
389 if (rcvd != -1) {
390 recv_stream_.Write(block, rcvd, NULL, NULL);
391 recv_stream_.GetPosition(&position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100392 RTC_LOG(LS_VERBOSE) << "Received: " << position;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000393 }
394 } while (rcvd > 0);
395 }
396 void WriteData() {
397 size_t position, tosend;
398 int sent;
399 char block[kBlockSize];
400 do {
401 send_stream_.GetPosition(&position);
402 tosend = bytes_per_send_ ? bytes_per_send_ : sizeof(block);
Steve Antoncc65bd02017-11-29 10:19:58 -0800403 if (send_stream_.Read(block, tosend, &tosend, NULL) != rtc::SR_EOS) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000404 sent = sender_->Send(block, tosend);
405 UpdateLocalClock();
406 if (sent != -1) {
407 send_stream_.SetPosition(position + sent);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100408 RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000409 } else {
410 send_stream_.SetPosition(position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100411 RTC_LOG(LS_VERBOSE) << "Flow Controlled";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000412 }
413 } else {
414 sent = static_cast<int>(tosend = 0);
415 }
416 } while (sent > 0);
417 }
418
419 private:
420 int iterations_remaining_;
421 PseudoTcp* sender_;
422 PseudoTcp* receiver_;
423 int bytes_per_send_;
424};
425
426// Fill the receiver window until it is full, drain it and then
427// fill it with the same amount. This is to test that receiver window
428// contracts and enlarges correctly.
429class PseudoTcpTestReceiveWindow : public PseudoTcpTestBase {
430 public:
431 // Not all the data are transfered, |size| just need to be big enough
432 // to fill up the receiver window twice.
433 void TestTransfer(int size) {
434 // Create some dummy data to send.
435 send_stream_.ReserveSize(size);
436 for (int i = 0; i < size; ++i) {
437 char ch = static_cast<char>(i);
438 send_stream_.Write(&ch, 1, NULL, NULL);
439 }
440 send_stream_.Rewind();
441
442 // Prepare the receive stream.
443 recv_stream_.ReserveSize(size);
444
445 // Connect and wait until connected.
446 EXPECT_EQ(0, Connect());
447 EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs);
448
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700449 rtc::Thread::Current()->Post(RTC_FROM_HERE, this, MSG_WRITE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000450 EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs);
451
452 ASSERT_EQ(2u, send_position_.size());
453 ASSERT_EQ(2u, recv_position_.size());
454
455 const size_t estimated_recv_window = EstimateReceiveWindowSize();
456
457 // The difference in consecutive send positions should equal the
458 // receive window size or match very closely. This verifies that receive
459 // window is open after receiver drained all the data.
460 const size_t send_position_diff = send_position_[1] - send_position_[0];
461 EXPECT_GE(1024u, estimated_recv_window - send_position_diff);
462
463 // Receiver drained the receive window twice.
464 EXPECT_EQ(2 * estimated_recv_window, recv_position_[1]);
465 }
466
467 virtual void OnMessage(rtc::Message* message) {
468 int message_id = message->message_id;
469 PseudoTcpTestBase::OnMessage(message);
470
471 switch (message_id) {
472 case MSG_WRITE: {
473 WriteData();
474 break;
475 }
476 default:
477 break;
478 }
479 }
480
Peter Boström0c4e06b2015-10-07 12:23:21 +0200481 uint32_t EstimateReceiveWindowSize() const {
482 return static_cast<uint32_t>(recv_position_[0]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000483 }
484
Peter Boström0c4e06b2015-10-07 12:23:21 +0200485 uint32_t EstimateSendWindowSize() const {
486 return static_cast<uint32_t>(send_position_[0] - recv_position_[0]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000487 }
488
489 private:
490 // IPseudoTcpNotify interface
Steve Antoncc65bd02017-11-29 10:19:58 -0800491 virtual void OnTcpReadable(PseudoTcp* tcp) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000492
Steve Antoncc65bd02017-11-29 10:19:58 -0800493 virtual void OnTcpWriteable(PseudoTcp* tcp) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000494
495 void ReadUntilIOPending() {
496 char block[kBlockSize];
497 size_t position;
498 int rcvd;
499
500 do {
501 rcvd = remote_.Recv(block, sizeof(block));
502 if (rcvd != -1) {
503 recv_stream_.Write(block, rcvd, NULL, NULL);
504 recv_stream_.GetPosition(&position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100505 RTC_LOG(LS_VERBOSE) << "Received: " << position;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000506 }
507 } while (rcvd > 0);
508
509 recv_stream_.GetPosition(&position);
510 recv_position_.push_back(position);
511
512 // Disconnect if we have done two transfers.
513 if (recv_position_.size() == 2u) {
514 Close();
515 OnTcpClosed(&remote_, 0);
516 } else {
517 WriteData();
518 }
519 }
520
521 void WriteData() {
522 size_t position, tosend;
523 int sent;
524 char block[kBlockSize];
525 do {
526 send_stream_.GetPosition(&position);
527 if (send_stream_.Read(block, sizeof(block), &tosend, NULL) !=
528 rtc::SR_EOS) {
529 sent = local_.Send(block, tosend);
530 UpdateLocalClock();
531 if (sent != -1) {
532 send_stream_.SetPosition(position + sent);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100533 RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000534 } else {
535 send_stream_.SetPosition(position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100536 RTC_LOG(LS_VERBOSE) << "Flow Controlled";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000537 }
538 } else {
539 sent = static_cast<int>(tosend = 0);
540 }
541 } while (sent > 0);
542 // At this point, we've filled up the available space in the send queue.
543
Steve Antoncc65bd02017-11-29 10:19:58 -0800544 int message_queue_size = static_cast<int>(rtc::Thread::Current()->size());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000545 // The message queue will always have at least 2 messages, an RCLOCK and
546 // an LCLOCK, since they are added back on the delay queue at the same time
547 // they are pulled off and therefore are never really removed.
548 if (message_queue_size > 2) {
549 // If there are non-clock messages remaining, attempt to continue sending
550 // after giving those messages time to process, which should free up the
551 // send buffer.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700552 rtc::Thread::Current()->PostDelayed(RTC_FROM_HERE, 10, this, MSG_WRITE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000553 } else {
554 if (!remote_.isReceiveBufferFull()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100555 RTC_LOG(LS_ERROR) << "This shouldn't happen - the send buffer is full, "
556 << "the receive buffer is not, and there are no "
557 << "remaining messages to process.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000558 }
559 send_stream_.GetPosition(&position);
560 send_position_.push_back(position);
561
562 // Drain the receiver buffer.
563 ReadUntilIOPending();
564 }
565 }
566
567 private:
568 rtc::MemoryStream send_stream_;
569 rtc::MemoryStream recv_stream_;
570
571 std::vector<size_t> send_position_;
572 std::vector<size_t> recv_position_;
573};
574
575// Basic end-to-end data transfer tests
576
577// Test the normal case of sending data from one side to the other.
578TEST_F(PseudoTcpTest, TestSend) {
579 SetLocalMtu(1500);
580 SetRemoteMtu(1500);
581 TestTransfer(1000000);
582}
583
584// Test sending data with a 50 ms RTT. Transmission should take longer due
585// to a slower ramp-up in send rate.
586TEST_F(PseudoTcpTest, TestSendWithDelay) {
587 SetLocalMtu(1500);
588 SetRemoteMtu(1500);
589 SetDelay(50);
590 TestTransfer(1000000);
591}
592
593// Test sending data with packet loss. Transmission should take much longer due
594// to send back-off when loss occurs.
595TEST_F(PseudoTcpTest, TestSendWithLoss) {
596 SetLocalMtu(1500);
597 SetRemoteMtu(1500);
598 SetLoss(10);
599 TestTransfer(100000); // less data so test runs faster
600}
601
602// Test sending data with a 50 ms RTT and 10% packet loss. Transmission should
603// take much longer due to send back-off and slower detection of loss.
604TEST_F(PseudoTcpTest, TestSendWithDelayAndLoss) {
605 SetLocalMtu(1500);
606 SetRemoteMtu(1500);
607 SetDelay(50);
608 SetLoss(10);
609 TestTransfer(100000); // less data so test runs faster
610}
611
612// Test sending data with 10% packet loss and Nagling disabled. Transmission
613// should take about the same time as with Nagling enabled.
614TEST_F(PseudoTcpTest, TestSendWithLossAndOptNaglingOff) {
615 SetLocalMtu(1500);
616 SetRemoteMtu(1500);
617 SetLoss(10);
618 SetOptNagling(false);
619 TestTransfer(100000); // less data so test runs faster
620}
621
622// Test sending data with 10% packet loss and Delayed ACK disabled.
623// Transmission should be slightly faster than with it enabled.
624TEST_F(PseudoTcpTest, TestSendWithLossAndOptAckDelayOff) {
625 SetLocalMtu(1500);
626 SetRemoteMtu(1500);
627 SetLoss(10);
628 SetOptAckDelay(0);
629 TestTransfer(100000);
630}
631
632// Test sending data with 50ms delay and Nagling disabled.
633TEST_F(PseudoTcpTest, TestSendWithDelayAndOptNaglingOff) {
634 SetLocalMtu(1500);
635 SetRemoteMtu(1500);
636 SetDelay(50);
637 SetOptNagling(false);
638 TestTransfer(100000); // less data so test runs faster
639}
640
641// Test sending data with 50ms delay and Delayed ACK disabled.
642TEST_F(PseudoTcpTest, TestSendWithDelayAndOptAckDelayOff) {
643 SetLocalMtu(1500);
644 SetRemoteMtu(1500);
645 SetDelay(50);
646 SetOptAckDelay(0);
647 TestTransfer(100000); // less data so test runs faster
648}
649
650// Test a large receive buffer with a sender that doesn't support scaling.
651TEST_F(PseudoTcpTest, TestSendRemoteNoWindowScale) {
652 SetLocalMtu(1500);
653 SetRemoteMtu(1500);
654 SetLocalOptRcvBuf(100000);
655 DisableRemoteWindowScale();
656 TestTransfer(1000000);
657}
658
659// Test a large sender-side receive buffer with a receiver that doesn't support
660// scaling.
661TEST_F(PseudoTcpTest, TestSendLocalNoWindowScale) {
662 SetLocalMtu(1500);
663 SetRemoteMtu(1500);
664 SetRemoteOptRcvBuf(100000);
665 DisableLocalWindowScale();
666 TestTransfer(1000000);
667}
668
669// Test when both sides use window scaling.
670TEST_F(PseudoTcpTest, TestSendBothUseWindowScale) {
671 SetLocalMtu(1500);
672 SetRemoteMtu(1500);
673 SetRemoteOptRcvBuf(100000);
674 SetLocalOptRcvBuf(100000);
675 TestTransfer(1000000);
676}
677
678// Test using a large window scale value.
679TEST_F(PseudoTcpTest, TestSendLargeInFlight) {
680 SetLocalMtu(1500);
681 SetRemoteMtu(1500);
682 SetRemoteOptRcvBuf(100000);
683 SetLocalOptRcvBuf(100000);
684 SetOptSndBuf(150000);
685 TestTransfer(1000000);
686}
687
688TEST_F(PseudoTcpTest, TestSendBothUseLargeWindowScale) {
689 SetLocalMtu(1500);
690 SetRemoteMtu(1500);
691 SetRemoteOptRcvBuf(1000000);
692 SetLocalOptRcvBuf(1000000);
693 TestTransfer(10000000);
694}
695
696// Test using a small receive buffer.
697TEST_F(PseudoTcpTest, TestSendSmallReceiveBuffer) {
698 SetLocalMtu(1500);
699 SetRemoteMtu(1500);
700 SetRemoteOptRcvBuf(10000);
701 SetLocalOptRcvBuf(10000);
702 TestTransfer(1000000);
703}
704
705// Test using a very small receive buffer.
706TEST_F(PseudoTcpTest, TestSendVerySmallReceiveBuffer) {
707 SetLocalMtu(1500);
708 SetRemoteMtu(1500);
709 SetRemoteOptRcvBuf(100);
710 SetLocalOptRcvBuf(100);
711 TestTransfer(100000);
712}
713
714// Ping-pong (request/response) tests
715
716// Test sending <= 1x MTU of data in each ping/pong. Should take <10ms.
717TEST_F(PseudoTcpTestPingPong, TestPingPong1xMtu) {
718 SetLocalMtu(1500);
719 SetRemoteMtu(1500);
720 TestPingPong(100, 100);
721}
722
723// Test sending 2x-3x MTU of data in each ping/pong. Should take <10ms.
724TEST_F(PseudoTcpTestPingPong, TestPingPong3xMtu) {
725 SetLocalMtu(1500);
726 SetRemoteMtu(1500);
727 TestPingPong(400, 100);
728}
729
730// Test sending 1x-2x MTU of data in each ping/pong.
731// Should take ~1s, due to interaction between Nagling and Delayed ACK.
732TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtu) {
733 SetLocalMtu(1500);
734 SetRemoteMtu(1500);
735 TestPingPong(2000, 5);
736}
737
738// Test sending 1x-2x MTU of data in each ping/pong with Delayed ACK off.
739// Should take <10ms.
740TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtuWithAckDelayOff) {
741 SetLocalMtu(1500);
742 SetRemoteMtu(1500);
743 SetOptAckDelay(0);
744 TestPingPong(2000, 100);
745}
746
747// Test sending 1x-2x MTU of data in each ping/pong with Nagling off.
748// Should take <10ms.
749TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtuWithNaglingOff) {
750 SetLocalMtu(1500);
751 SetRemoteMtu(1500);
752 SetOptNagling(false);
753 TestPingPong(2000, 5);
754}
755
756// Test sending a ping as pair of short (non-full) segments.
757// Should take ~1s, due to Delayed ACK interaction with Nagling.
758TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegments) {
759 SetLocalMtu(1500);
760 SetRemoteMtu(1500);
761 SetOptAckDelay(5000);
Steve Antoncc65bd02017-11-29 10:19:58 -0800762 SetBytesPerSend(50); // i.e. two Send calls per payload
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000763 TestPingPong(100, 5);
764}
765
766// Test sending ping as a pair of short (non-full) segments, with Nagling off.
767// Should take <10ms.
768TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegmentsWithNaglingOff) {
769 SetLocalMtu(1500);
770 SetRemoteMtu(1500);
771 SetOptNagling(false);
Steve Antoncc65bd02017-11-29 10:19:58 -0800772 SetBytesPerSend(50); // i.e. two Send calls per payload
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000773 TestPingPong(100, 5);
774}
775
776// Test sending <= 1x MTU of data ping/pong, in two segments, no Delayed ACK.
777// Should take ~1s.
778TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegmentsWithAckDelayOff) {
779 SetLocalMtu(1500);
780 SetRemoteMtu(1500);
Steve Antoncc65bd02017-11-29 10:19:58 -0800781 SetBytesPerSend(50); // i.e. two Send calls per payload
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000782 SetOptAckDelay(0);
783 TestPingPong(100, 5);
784}
785
786// Test that receive window expands and contract correctly.
787TEST_F(PseudoTcpTestReceiveWindow, TestReceiveWindow) {
788 SetLocalMtu(1500);
789 SetRemoteMtu(1500);
790 SetOptNagling(false);
791 SetOptAckDelay(0);
792 TestTransfer(1024 * 1000);
793}
794
795// Test setting send window size to a very small value.
796TEST_F(PseudoTcpTestReceiveWindow, TestSetVerySmallSendWindowSize) {
797 SetLocalMtu(1500);
798 SetRemoteMtu(1500);
799 SetOptNagling(false);
800 SetOptAckDelay(0);
801 SetOptSndBuf(900);
802 TestTransfer(1024 * 1000);
803 EXPECT_EQ(900u, EstimateSendWindowSize());
804}
805
806// Test setting receive window size to a value other than default.
807TEST_F(PseudoTcpTestReceiveWindow, TestSetReceiveWindowSize) {
808 SetLocalMtu(1500);
809 SetRemoteMtu(1500);
810 SetOptNagling(false);
811 SetOptAckDelay(0);
812 SetRemoteOptRcvBuf(100000);
813 SetLocalOptRcvBuf(100000);
814 TestTransfer(1024 * 1000);
815 EXPECT_EQ(100000u, EstimateReceiveWindowSize());
816}
817
818/* Test sending data with mismatched MTUs. We should detect this and reduce
819// our packet size accordingly.
820// TODO: This doesn't actually work right now. The current code
821// doesn't detect if the MTU is set too high on either side.
822TEST_F(PseudoTcpTest, TestSendWithMismatchedMtus) {
823 SetLocalMtu(1500);
824 SetRemoteMtu(1280);
825 TestTransfer(1000000);
826}
827*/