blob: f6b46ccc6aaf2cd5ef6e092d4cdf710d613cc99a [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>
Steve Anton5c8231c2017-12-06 10:39:22 -080012#include <string>
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000013#include <vector>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "p2p/base/pseudotcp.h"
16#include "rtc_base/gunit.h"
17#include "rtc_base/helpers.h"
18#include "rtc_base/messagehandler.h"
19#include "rtc_base/stream.h"
20#include "rtc_base/thread.h"
21#include "rtc_base/timeutils.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000022
23using cricket::PseudoTcp;
24
25static const int kConnectTimeoutMs = 10000; // ~3 * default RTO of 3000ms
26static const int kTransferTimeoutMs = 15000;
27static const int kBlockSize = 4096;
28
29class PseudoTcpForTest : public cricket::PseudoTcp {
30 public:
Peter Boström0c4e06b2015-10-07 12:23:21 +020031 PseudoTcpForTest(cricket::IPseudoTcpNotify* notify, uint32_t conv)
32 : PseudoTcp(notify, conv) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000033
Steve Antoncc65bd02017-11-29 10:19:58 -080034 bool isReceiveBufferFull() const { return PseudoTcp::isReceiveBufferFull(); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000035
Steve Antoncc65bd02017-11-29 10:19:58 -080036 void disableWindowScale() { PseudoTcp::disableWindowScale(); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000037};
38
39class PseudoTcpTestBase : public testing::Test,
Steve Antoncc65bd02017-11-29 10:19:58 -080040 public rtc::MessageHandler,
41 public cricket::IPseudoTcpNotify {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000042 public:
43 PseudoTcpTestBase()
44 : local_(this, 1),
45 remote_(this, 1),
46 have_connected_(false),
47 have_disconnected_(false),
48 local_mtu_(65535),
49 remote_mtu_(65535),
50 delay_(0),
51 loss_(0) {
52 // Set use of the test RNG to get predictable loss patterns.
53 rtc::SetRandomTestMode(true);
54 }
55 ~PseudoTcpTestBase() {
56 // Put it back for the next test.
57 rtc::SetRandomTestMode(false);
58 }
59 void SetLocalMtu(int mtu) {
60 local_.NotifyMTU(mtu);
61 local_mtu_ = mtu;
62 }
63 void SetRemoteMtu(int mtu) {
64 remote_.NotifyMTU(mtu);
65 remote_mtu_ = mtu;
66 }
Steve Antoncc65bd02017-11-29 10:19:58 -080067 void SetDelay(int delay) { delay_ = delay; }
68 void SetLoss(int percent) { loss_ = percent; }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000069 void SetOptNagling(bool enable_nagles) {
70 local_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles);
71 remote_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles);
72 }
73 void SetOptAckDelay(int ack_delay) {
74 local_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay);
75 remote_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay);
76 }
77 void SetOptSndBuf(int size) {
78 local_.SetOption(PseudoTcp::OPT_SNDBUF, size);
79 remote_.SetOption(PseudoTcp::OPT_SNDBUF, size);
80 }
81 void SetRemoteOptRcvBuf(int size) {
82 remote_.SetOption(PseudoTcp::OPT_RCVBUF, size);
83 }
84 void SetLocalOptRcvBuf(int size) {
85 local_.SetOption(PseudoTcp::OPT_RCVBUF, size);
86 }
Steve Antoncc65bd02017-11-29 10:19:58 -080087 void DisableRemoteWindowScale() { remote_.disableWindowScale(); }
88 void DisableLocalWindowScale() { local_.disableWindowScale(); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000089
90 protected:
91 int Connect() {
92 int ret = local_.Connect();
93 if (ret == 0) {
94 UpdateLocalClock();
95 }
96 return ret;
97 }
98 void Close() {
99 local_.Close(false);
100 UpdateLocalClock();
101 }
102
Steve Antoncc65bd02017-11-29 10:19:58 -0800103 enum {
104 MSG_LPACKET,
105 MSG_RPACKET,
106 MSG_LCLOCK,
107 MSG_RCLOCK,
108 MSG_IOCOMPLETE,
109 MSG_WRITE
110 };
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000111 virtual void OnTcpOpen(PseudoTcp* tcp) {
112 // Consider ourselves connected when the local side gets OnTcpOpen.
113 // OnTcpWriteable isn't fired at open, so we trigger it now.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100114 RTC_LOG(LS_VERBOSE) << "Opened";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000115 if (tcp == &local_) {
116 have_connected_ = true;
117 OnTcpWriteable(tcp);
118 }
119 }
120 // Test derived from the base should override
121 // virtual void OnTcpReadable(PseudoTcp* tcp)
122 // and
123 // virtual void OnTcpWritable(PseudoTcp* tcp)
Peter Boström0c4e06b2015-10-07 12:23:21 +0200124 virtual void OnTcpClosed(PseudoTcp* tcp, uint32_t error) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000125 // Consider ourselves closed when the remote side gets OnTcpClosed.
Steve Anton5c8231c2017-12-06 10:39:22 -0800126 // TODO(?): OnTcpClosed is only ever notified in case of error in
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000127 // the current implementation. Solicited close is not (yet) supported.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100128 RTC_LOG(LS_VERBOSE) << "Closed";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000129 EXPECT_EQ(0U, error);
130 if (tcp == &remote_) {
131 have_disconnected_ = true;
132 }
133 }
134 virtual WriteResult TcpWritePacket(PseudoTcp* tcp,
Steve Antoncc65bd02017-11-29 10:19:58 -0800135 const char* buffer,
136 size_t len) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000137 // Randomly drop the desired percentage of packets.
138 // Also drop packets that are larger than the configured MTU.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200139 if (rtc::CreateRandomId() % 100 < static_cast<uint32_t>(loss_)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100140 RTC_LOG(LS_VERBOSE) << "Randomly dropping packet, size=" << len;
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000141 } else if (len > static_cast<size_t>(std::min(local_mtu_, remote_mtu_))) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100142 RTC_LOG(LS_VERBOSE) << "Dropping packet that exceeds path MTU, size="
143 << len;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000144 } else {
145 int id = (tcp == &local_) ? MSG_RPACKET : MSG_LPACKET;
146 std::string packet(buffer, len);
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700147 rtc::Thread::Current()->PostDelayed(RTC_FROM_HERE, delay_, this, id,
148 rtc::WrapMessageData(packet));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000149 }
150 return WR_SUCCESS;
151 }
152
153 void UpdateLocalClock() { UpdateClock(&local_, MSG_LCLOCK); }
154 void UpdateRemoteClock() { UpdateClock(&remote_, MSG_RCLOCK); }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200155 void UpdateClock(PseudoTcp* tcp, uint32_t message) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000156 long interval = 0; // NOLINT
157 tcp->GetNextClock(PseudoTcp::Now(), interval);
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000158 interval = std::max<int>(interval, 0L); // sometimes interval is < 0
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000159 rtc::Thread::Current()->Clear(this, message);
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700160 rtc::Thread::Current()->PostDelayed(RTC_FROM_HERE, interval, this, message);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000161 }
162
163 virtual void OnMessage(rtc::Message* message) {
164 switch (message->message_id) {
165 case MSG_LPACKET: {
Steve Antoncc65bd02017-11-29 10:19:58 -0800166 const std::string& s(rtc::UseMessageData<std::string>(message->pdata));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000167 local_.NotifyPacket(s.c_str(), s.size());
168 UpdateLocalClock();
169 break;
170 }
171 case MSG_RPACKET: {
Steve Antoncc65bd02017-11-29 10:19:58 -0800172 const std::string& s(rtc::UseMessageData<std::string>(message->pdata));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000173 remote_.NotifyPacket(s.c_str(), s.size());
174 UpdateRemoteClock();
175 break;
176 }
177 case MSG_LCLOCK:
178 local_.NotifyClock(PseudoTcp::Now());
179 UpdateLocalClock();
180 break;
181 case MSG_RCLOCK:
182 remote_.NotifyClock(PseudoTcp::Now());
183 UpdateRemoteClock();
184 break;
185 default:
186 break;
187 }
188 delete message->pdata;
189 }
190
191 PseudoTcpForTest local_;
192 PseudoTcpForTest remote_;
193 rtc::MemoryStream send_stream_;
194 rtc::MemoryStream recv_stream_;
195 bool have_connected_;
196 bool have_disconnected_;
197 int local_mtu_;
198 int remote_mtu_;
199 int delay_;
200 int loss_;
201};
202
203class PseudoTcpTest : public PseudoTcpTestBase {
204 public:
205 void TestTransfer(int size) {
Honghai Zhang82d78622016-05-06 11:29:15 -0700206 uint32_t start;
207 int32_t elapsed;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000208 size_t received;
209 // Create some dummy data to send.
210 send_stream_.ReserveSize(size);
211 for (int i = 0; i < size; ++i) {
212 char ch = static_cast<char>(i);
213 send_stream_.Write(&ch, 1, NULL, NULL);
214 }
215 send_stream_.Rewind();
216 // Prepare the receive stream.
217 recv_stream_.ReserveSize(size);
218 // Connect and wait until connected.
Honghai Zhang82d78622016-05-06 11:29:15 -0700219 start = rtc::Time32();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000220 EXPECT_EQ(0, Connect());
221 EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs);
222 // Sending will start from OnTcpWriteable and complete when all data has
223 // been received.
224 EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs);
Honghai Zhang82d78622016-05-06 11:29:15 -0700225 elapsed = rtc::Time32() - start;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000226 recv_stream_.GetSize(&received);
227 // Ensure we closed down OK and we got the right data.
Steve Anton5c8231c2017-12-06 10:39:22 -0800228 // TODO(?): Ensure the errors are cleared properly.
Steve Antoncc65bd02017-11-29 10:19:58 -0800229 // EXPECT_EQ(0, local_.GetError());
230 // EXPECT_EQ(0, remote_.GetError());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000231 EXPECT_EQ(static_cast<size_t>(size), received);
Steve Antoncc65bd02017-11-29 10:19:58 -0800232 EXPECT_EQ(0,
233 memcmp(send_stream_.GetBuffer(), recv_stream_.GetBuffer(), size));
Mirko Bonadei675513b2017-11-09 11:09:25 +0100234 RTC_LOG(LS_INFO) << "Transferred " << received << " bytes in " << elapsed
235 << " ms (" << size * 8 / elapsed << " Kbps)";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000236 }
237
238 private:
239 // IPseudoTcpNotify interface
240
241 virtual void OnTcpReadable(PseudoTcp* tcp) {
242 // Stream bytes to the recv stream as they arrive.
243 if (tcp == &remote_) {
244 ReadData();
245
Steve Anton5c8231c2017-12-06 10:39:22 -0800246 // TODO(?): OnTcpClosed() is currently only notified on error -
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000247 // there is no on-the-wire equivalent of TCP FIN.
248 // So we fake the notification when all the data has been read.
249 size_t received, required;
250 recv_stream_.GetPosition(&received);
251 send_stream_.GetSize(&required);
252 if (received == required)
253 OnTcpClosed(&remote_, 0);
254 }
255 }
256 virtual void OnTcpWriteable(PseudoTcp* tcp) {
257 // Write bytes from the send stream when we can.
258 // Shut down when we've sent everything.
259 if (tcp == &local_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100260 RTC_LOG(LS_VERBOSE) << "Flow Control Lifted";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000261 bool done;
262 WriteData(&done);
263 if (done) {
264 Close();
265 }
266 }
267 }
268
269 void ReadData() {
270 char block[kBlockSize];
271 size_t position;
272 int rcvd;
273 do {
274 rcvd = remote_.Recv(block, sizeof(block));
275 if (rcvd != -1) {
276 recv_stream_.Write(block, rcvd, NULL, NULL);
277 recv_stream_.GetPosition(&position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100278 RTC_LOG(LS_VERBOSE) << "Received: " << position;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000279 }
280 } while (rcvd > 0);
281 }
282 void WriteData(bool* done) {
283 size_t position, tosend;
284 int sent;
285 char block[kBlockSize];
286 do {
287 send_stream_.GetPosition(&position);
288 if (send_stream_.Read(block, sizeof(block), &tosend, NULL) !=
289 rtc::SR_EOS) {
290 sent = local_.Send(block, tosend);
291 UpdateLocalClock();
292 if (sent != -1) {
293 send_stream_.SetPosition(position + sent);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100294 RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000295 } else {
296 send_stream_.SetPosition(position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100297 RTC_LOG(LS_VERBOSE) << "Flow Controlled";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000298 }
299 } else {
300 sent = static_cast<int>(tosend = 0);
301 }
302 } while (sent > 0);
303 *done = (tosend == 0);
304 }
305
306 private:
307 rtc::MemoryStream send_stream_;
308 rtc::MemoryStream recv_stream_;
309};
310
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000311class PseudoTcpTestPingPong : public PseudoTcpTestBase {
312 public:
313 PseudoTcpTestPingPong()
314 : iterations_remaining_(0),
Steve Antoncc65bd02017-11-29 10:19:58 -0800315 sender_(NULL),
316 receiver_(NULL),
317 bytes_per_send_(0) {}
318 void SetBytesPerSend(int bytes) { bytes_per_send_ = bytes; }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000319 void TestPingPong(int size, int iterations) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200320 uint32_t start, elapsed;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000321 iterations_remaining_ = iterations;
322 receiver_ = &remote_;
323 sender_ = &local_;
324 // Create some dummy data to send.
325 send_stream_.ReserveSize(size);
326 for (int i = 0; i < size; ++i) {
327 char ch = static_cast<char>(i);
328 send_stream_.Write(&ch, 1, NULL, NULL);
329 }
330 send_stream_.Rewind();
331 // Prepare the receive stream.
332 recv_stream_.ReserveSize(size);
333 // Connect and wait until connected.
Honghai Zhang82d78622016-05-06 11:29:15 -0700334 start = rtc::Time32();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000335 EXPECT_EQ(0, Connect());
336 EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs);
337 // Sending will start from OnTcpWriteable and stop when the required
338 // number of iterations have completed.
339 EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs);
340 elapsed = rtc::TimeSince(start);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100341 RTC_LOG(LS_INFO) << "Performed " << iterations << " pings in " << elapsed
342 << " ms";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000343 }
344
345 private:
346 // IPseudoTcpNotify interface
347
348 virtual void OnTcpReadable(PseudoTcp* tcp) {
349 if (tcp != receiver_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100350 RTC_LOG_F(LS_ERROR) << "unexpected OnTcpReadable";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000351 return;
352 }
353 // Stream bytes to the recv stream as they arrive.
354 ReadData();
355 // If we've received the desired amount of data, rewind things
356 // and send it back the other way!
357 size_t position, desired;
358 recv_stream_.GetPosition(&position);
359 send_stream_.GetSize(&desired);
360 if (position == desired) {
361 if (receiver_ == &local_ && --iterations_remaining_ == 0) {
362 Close();
Steve Anton5c8231c2017-12-06 10:39:22 -0800363 // TODO(?): Fake OnTcpClosed() on the receiver for now.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000364 OnTcpClosed(&remote_, 0);
365 return;
366 }
367 PseudoTcp* tmp = receiver_;
368 receiver_ = sender_;
369 sender_ = tmp;
370 recv_stream_.Rewind();
371 send_stream_.Rewind();
372 OnTcpWriteable(sender_);
373 }
374 }
375 virtual void OnTcpWriteable(PseudoTcp* tcp) {
376 if (tcp != sender_)
377 return;
378 // Write bytes from the send stream when we can.
379 // Shut down when we've sent everything.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100380 RTC_LOG(LS_VERBOSE) << "Flow Control Lifted";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000381 WriteData();
382 }
383
384 void ReadData() {
385 char block[kBlockSize];
386 size_t position;
387 int rcvd;
388 do {
389 rcvd = receiver_->Recv(block, sizeof(block));
390 if (rcvd != -1) {
391 recv_stream_.Write(block, rcvd, NULL, NULL);
392 recv_stream_.GetPosition(&position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100393 RTC_LOG(LS_VERBOSE) << "Received: " << position;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000394 }
395 } while (rcvd > 0);
396 }
397 void WriteData() {
398 size_t position, tosend;
399 int sent;
400 char block[kBlockSize];
401 do {
402 send_stream_.GetPosition(&position);
403 tosend = bytes_per_send_ ? bytes_per_send_ : sizeof(block);
Steve Antoncc65bd02017-11-29 10:19:58 -0800404 if (send_stream_.Read(block, tosend, &tosend, NULL) != rtc::SR_EOS) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000405 sent = sender_->Send(block, tosend);
406 UpdateLocalClock();
407 if (sent != -1) {
408 send_stream_.SetPosition(position + sent);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100409 RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000410 } else {
411 send_stream_.SetPosition(position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100412 RTC_LOG(LS_VERBOSE) << "Flow Controlled";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000413 }
414 } else {
415 sent = static_cast<int>(tosend = 0);
416 }
417 } while (sent > 0);
418 }
419
420 private:
421 int iterations_remaining_;
422 PseudoTcp* sender_;
423 PseudoTcp* receiver_;
424 int bytes_per_send_;
425};
426
427// Fill the receiver window until it is full, drain it and then
428// fill it with the same amount. This is to test that receiver window
429// contracts and enlarges correctly.
430class PseudoTcpTestReceiveWindow : public PseudoTcpTestBase {
431 public:
432 // Not all the data are transfered, |size| just need to be big enough
433 // to fill up the receiver window twice.
434 void TestTransfer(int size) {
435 // Create some dummy data to send.
436 send_stream_.ReserveSize(size);
437 for (int i = 0; i < size; ++i) {
438 char ch = static_cast<char>(i);
439 send_stream_.Write(&ch, 1, NULL, NULL);
440 }
441 send_stream_.Rewind();
442
443 // Prepare the receive stream.
444 recv_stream_.ReserveSize(size);
445
446 // Connect and wait until connected.
447 EXPECT_EQ(0, Connect());
448 EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs);
449
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700450 rtc::Thread::Current()->Post(RTC_FROM_HERE, this, MSG_WRITE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000451 EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs);
452
453 ASSERT_EQ(2u, send_position_.size());
454 ASSERT_EQ(2u, recv_position_.size());
455
456 const size_t estimated_recv_window = EstimateReceiveWindowSize();
457
458 // The difference in consecutive send positions should equal the
459 // receive window size or match very closely. This verifies that receive
460 // window is open after receiver drained all the data.
461 const size_t send_position_diff = send_position_[1] - send_position_[0];
462 EXPECT_GE(1024u, estimated_recv_window - send_position_diff);
463
464 // Receiver drained the receive window twice.
465 EXPECT_EQ(2 * estimated_recv_window, recv_position_[1]);
466 }
467
468 virtual void OnMessage(rtc::Message* message) {
469 int message_id = message->message_id;
470 PseudoTcpTestBase::OnMessage(message);
471
472 switch (message_id) {
473 case MSG_WRITE: {
474 WriteData();
475 break;
476 }
477 default:
478 break;
479 }
480 }
481
Peter Boström0c4e06b2015-10-07 12:23:21 +0200482 uint32_t EstimateReceiveWindowSize() const {
483 return static_cast<uint32_t>(recv_position_[0]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000484 }
485
Peter Boström0c4e06b2015-10-07 12:23:21 +0200486 uint32_t EstimateSendWindowSize() const {
487 return static_cast<uint32_t>(send_position_[0] - recv_position_[0]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000488 }
489
490 private:
491 // IPseudoTcpNotify interface
Steve Antoncc65bd02017-11-29 10:19:58 -0800492 virtual void OnTcpReadable(PseudoTcp* tcp) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000493
Steve Antoncc65bd02017-11-29 10:19:58 -0800494 virtual void OnTcpWriteable(PseudoTcp* tcp) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000495
496 void ReadUntilIOPending() {
497 char block[kBlockSize];
498 size_t position;
499 int rcvd;
500
501 do {
502 rcvd = remote_.Recv(block, sizeof(block));
503 if (rcvd != -1) {
504 recv_stream_.Write(block, rcvd, NULL, NULL);
505 recv_stream_.GetPosition(&position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100506 RTC_LOG(LS_VERBOSE) << "Received: " << position;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000507 }
508 } while (rcvd > 0);
509
510 recv_stream_.GetPosition(&position);
511 recv_position_.push_back(position);
512
513 // Disconnect if we have done two transfers.
514 if (recv_position_.size() == 2u) {
515 Close();
516 OnTcpClosed(&remote_, 0);
517 } else {
518 WriteData();
519 }
520 }
521
522 void WriteData() {
523 size_t position, tosend;
524 int sent;
525 char block[kBlockSize];
526 do {
527 send_stream_.GetPosition(&position);
528 if (send_stream_.Read(block, sizeof(block), &tosend, NULL) !=
529 rtc::SR_EOS) {
530 sent = local_.Send(block, tosend);
531 UpdateLocalClock();
532 if (sent != -1) {
533 send_stream_.SetPosition(position + sent);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100534 RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000535 } else {
536 send_stream_.SetPosition(position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100537 RTC_LOG(LS_VERBOSE) << "Flow Controlled";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000538 }
539 } else {
540 sent = static_cast<int>(tosend = 0);
541 }
542 } while (sent > 0);
543 // At this point, we've filled up the available space in the send queue.
544
Steve Antoncc65bd02017-11-29 10:19:58 -0800545 int message_queue_size = static_cast<int>(rtc::Thread::Current()->size());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000546 // The message queue will always have at least 2 messages, an RCLOCK and
547 // an LCLOCK, since they are added back on the delay queue at the same time
548 // they are pulled off and therefore are never really removed.
549 if (message_queue_size > 2) {
550 // If there are non-clock messages remaining, attempt to continue sending
551 // after giving those messages time to process, which should free up the
552 // send buffer.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700553 rtc::Thread::Current()->PostDelayed(RTC_FROM_HERE, 10, this, MSG_WRITE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000554 } else {
555 if (!remote_.isReceiveBufferFull()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100556 RTC_LOG(LS_ERROR) << "This shouldn't happen - the send buffer is full, "
Jonas Olssond7d762d2018-03-28 09:47:51 +0200557 "the receive buffer is not, and there are no "
558 "remaining messages to process.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000559 }
560 send_stream_.GetPosition(&position);
561 send_position_.push_back(position);
562
563 // Drain the receiver buffer.
564 ReadUntilIOPending();
565 }
566 }
567
568 private:
569 rtc::MemoryStream send_stream_;
570 rtc::MemoryStream recv_stream_;
571
572 std::vector<size_t> send_position_;
573 std::vector<size_t> recv_position_;
574};
575
576// Basic end-to-end data transfer tests
577
578// Test the normal case of sending data from one side to the other.
579TEST_F(PseudoTcpTest, TestSend) {
580 SetLocalMtu(1500);
581 SetRemoteMtu(1500);
582 TestTransfer(1000000);
583}
584
585// Test sending data with a 50 ms RTT. Transmission should take longer due
586// to a slower ramp-up in send rate.
587TEST_F(PseudoTcpTest, TestSendWithDelay) {
588 SetLocalMtu(1500);
589 SetRemoteMtu(1500);
590 SetDelay(50);
591 TestTransfer(1000000);
592}
593
594// Test sending data with packet loss. Transmission should take much longer due
595// to send back-off when loss occurs.
596TEST_F(PseudoTcpTest, TestSendWithLoss) {
597 SetLocalMtu(1500);
598 SetRemoteMtu(1500);
599 SetLoss(10);
600 TestTransfer(100000); // less data so test runs faster
601}
602
603// Test sending data with a 50 ms RTT and 10% packet loss. Transmission should
604// take much longer due to send back-off and slower detection of loss.
605TEST_F(PseudoTcpTest, TestSendWithDelayAndLoss) {
606 SetLocalMtu(1500);
607 SetRemoteMtu(1500);
608 SetDelay(50);
609 SetLoss(10);
610 TestTransfer(100000); // less data so test runs faster
611}
612
613// Test sending data with 10% packet loss and Nagling disabled. Transmission
614// should take about the same time as with Nagling enabled.
615TEST_F(PseudoTcpTest, TestSendWithLossAndOptNaglingOff) {
616 SetLocalMtu(1500);
617 SetRemoteMtu(1500);
618 SetLoss(10);
619 SetOptNagling(false);
620 TestTransfer(100000); // less data so test runs faster
621}
622
623// Test sending data with 10% packet loss and Delayed ACK disabled.
624// Transmission should be slightly faster than with it enabled.
625TEST_F(PseudoTcpTest, TestSendWithLossAndOptAckDelayOff) {
626 SetLocalMtu(1500);
627 SetRemoteMtu(1500);
628 SetLoss(10);
629 SetOptAckDelay(0);
630 TestTransfer(100000);
631}
632
633// Test sending data with 50ms delay and Nagling disabled.
634TEST_F(PseudoTcpTest, TestSendWithDelayAndOptNaglingOff) {
635 SetLocalMtu(1500);
636 SetRemoteMtu(1500);
637 SetDelay(50);
638 SetOptNagling(false);
639 TestTransfer(100000); // less data so test runs faster
640}
641
642// Test sending data with 50ms delay and Delayed ACK disabled.
643TEST_F(PseudoTcpTest, TestSendWithDelayAndOptAckDelayOff) {
644 SetLocalMtu(1500);
645 SetRemoteMtu(1500);
646 SetDelay(50);
647 SetOptAckDelay(0);
648 TestTransfer(100000); // less data so test runs faster
649}
650
651// Test a large receive buffer with a sender that doesn't support scaling.
652TEST_F(PseudoTcpTest, TestSendRemoteNoWindowScale) {
653 SetLocalMtu(1500);
654 SetRemoteMtu(1500);
655 SetLocalOptRcvBuf(100000);
656 DisableRemoteWindowScale();
657 TestTransfer(1000000);
658}
659
660// Test a large sender-side receive buffer with a receiver that doesn't support
661// scaling.
662TEST_F(PseudoTcpTest, TestSendLocalNoWindowScale) {
663 SetLocalMtu(1500);
664 SetRemoteMtu(1500);
665 SetRemoteOptRcvBuf(100000);
666 DisableLocalWindowScale();
667 TestTransfer(1000000);
668}
669
670// Test when both sides use window scaling.
671TEST_F(PseudoTcpTest, TestSendBothUseWindowScale) {
672 SetLocalMtu(1500);
673 SetRemoteMtu(1500);
674 SetRemoteOptRcvBuf(100000);
675 SetLocalOptRcvBuf(100000);
676 TestTransfer(1000000);
677}
678
679// Test using a large window scale value.
680TEST_F(PseudoTcpTest, TestSendLargeInFlight) {
681 SetLocalMtu(1500);
682 SetRemoteMtu(1500);
683 SetRemoteOptRcvBuf(100000);
684 SetLocalOptRcvBuf(100000);
685 SetOptSndBuf(150000);
686 TestTransfer(1000000);
687}
688
689TEST_F(PseudoTcpTest, TestSendBothUseLargeWindowScale) {
690 SetLocalMtu(1500);
691 SetRemoteMtu(1500);
692 SetRemoteOptRcvBuf(1000000);
693 SetLocalOptRcvBuf(1000000);
694 TestTransfer(10000000);
695}
696
697// Test using a small receive buffer.
698TEST_F(PseudoTcpTest, TestSendSmallReceiveBuffer) {
699 SetLocalMtu(1500);
700 SetRemoteMtu(1500);
701 SetRemoteOptRcvBuf(10000);
702 SetLocalOptRcvBuf(10000);
703 TestTransfer(1000000);
704}
705
706// Test using a very small receive buffer.
707TEST_F(PseudoTcpTest, TestSendVerySmallReceiveBuffer) {
708 SetLocalMtu(1500);
709 SetRemoteMtu(1500);
710 SetRemoteOptRcvBuf(100);
711 SetLocalOptRcvBuf(100);
712 TestTransfer(100000);
713}
714
715// Ping-pong (request/response) tests
716
717// Test sending <= 1x MTU of data in each ping/pong. Should take <10ms.
718TEST_F(PseudoTcpTestPingPong, TestPingPong1xMtu) {
719 SetLocalMtu(1500);
720 SetRemoteMtu(1500);
721 TestPingPong(100, 100);
722}
723
724// Test sending 2x-3x MTU of data in each ping/pong. Should take <10ms.
725TEST_F(PseudoTcpTestPingPong, TestPingPong3xMtu) {
726 SetLocalMtu(1500);
727 SetRemoteMtu(1500);
728 TestPingPong(400, 100);
729}
730
731// Test sending 1x-2x MTU of data in each ping/pong.
732// Should take ~1s, due to interaction between Nagling and Delayed ACK.
733TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtu) {
734 SetLocalMtu(1500);
735 SetRemoteMtu(1500);
736 TestPingPong(2000, 5);
737}
738
739// Test sending 1x-2x MTU of data in each ping/pong with Delayed ACK off.
740// Should take <10ms.
741TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtuWithAckDelayOff) {
742 SetLocalMtu(1500);
743 SetRemoteMtu(1500);
744 SetOptAckDelay(0);
745 TestPingPong(2000, 100);
746}
747
748// Test sending 1x-2x MTU of data in each ping/pong with Nagling off.
749// Should take <10ms.
750TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtuWithNaglingOff) {
751 SetLocalMtu(1500);
752 SetRemoteMtu(1500);
753 SetOptNagling(false);
754 TestPingPong(2000, 5);
755}
756
757// Test sending a ping as pair of short (non-full) segments.
758// Should take ~1s, due to Delayed ACK interaction with Nagling.
759TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegments) {
760 SetLocalMtu(1500);
761 SetRemoteMtu(1500);
762 SetOptAckDelay(5000);
Steve Antoncc65bd02017-11-29 10:19:58 -0800763 SetBytesPerSend(50); // i.e. two Send calls per payload
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000764 TestPingPong(100, 5);
765}
766
767// Test sending ping as a pair of short (non-full) segments, with Nagling off.
768// Should take <10ms.
769TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegmentsWithNaglingOff) {
770 SetLocalMtu(1500);
771 SetRemoteMtu(1500);
772 SetOptNagling(false);
Steve Antoncc65bd02017-11-29 10:19:58 -0800773 SetBytesPerSend(50); // i.e. two Send calls per payload
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000774 TestPingPong(100, 5);
775}
776
777// Test sending <= 1x MTU of data ping/pong, in two segments, no Delayed ACK.
778// Should take ~1s.
779TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegmentsWithAckDelayOff) {
780 SetLocalMtu(1500);
781 SetRemoteMtu(1500);
Steve Antoncc65bd02017-11-29 10:19:58 -0800782 SetBytesPerSend(50); // i.e. two Send calls per payload
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000783 SetOptAckDelay(0);
784 TestPingPong(100, 5);
785}
786
787// Test that receive window expands and contract correctly.
788TEST_F(PseudoTcpTestReceiveWindow, TestReceiveWindow) {
789 SetLocalMtu(1500);
790 SetRemoteMtu(1500);
791 SetOptNagling(false);
792 SetOptAckDelay(0);
793 TestTransfer(1024 * 1000);
794}
795
796// Test setting send window size to a very small value.
797TEST_F(PseudoTcpTestReceiveWindow, TestSetVerySmallSendWindowSize) {
798 SetLocalMtu(1500);
799 SetRemoteMtu(1500);
800 SetOptNagling(false);
801 SetOptAckDelay(0);
802 SetOptSndBuf(900);
803 TestTransfer(1024 * 1000);
804 EXPECT_EQ(900u, EstimateSendWindowSize());
805}
806
807// Test setting receive window size to a value other than default.
808TEST_F(PseudoTcpTestReceiveWindow, TestSetReceiveWindowSize) {
809 SetLocalMtu(1500);
810 SetRemoteMtu(1500);
811 SetOptNagling(false);
812 SetOptAckDelay(0);
813 SetRemoteOptRcvBuf(100000);
814 SetLocalOptRcvBuf(100000);
815 TestTransfer(1024 * 1000);
816 EXPECT_EQ(100000u, EstimateReceiveWindowSize());
817}
818
819/* Test sending data with mismatched MTUs. We should detect this and reduce
820// our packet size accordingly.
Steve Anton5c8231c2017-12-06 10:39:22 -0800821// TODO(?): This doesn't actually work right now. The current code
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000822// doesn't detect if the MTU is set too high on either side.
823TEST_F(PseudoTcpTest, TestSendWithMismatchedMtus) {
824 SetLocalMtu(1500);
825 SetRemoteMtu(1280);
826 TestTransfer(1000000);
827}
828*/