blob: 2fc9900cbcca5b1fbf4960bc15ea1b8490a82a80 [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"
Niels Möllere7547d52018-11-01 09:33:08 +010018#include "rtc_base/memory_stream.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "rtc_base/messagehandler.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#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) {
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -070052 // Set use of the test RNG to get predictable loss patterns. Otherwise,
53 // this test would occasionally get really unlucky loss and time out.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000054 rtc::SetRandomTestMode(true);
55 }
56 ~PseudoTcpTestBase() {
57 // Put it back for the next test.
58 rtc::SetRandomTestMode(false);
59 }
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -070060 // If true, both endpoints will send the "connect" segment simultaneously,
61 // rather than |local_| sending it followed by a response from |remote_|.
62 // Note that this is what chromoting ends up doing.
63 void SetSimultaneousOpen(bool enabled) { simultaneous_open_ = enabled; }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000064 void SetLocalMtu(int mtu) {
65 local_.NotifyMTU(mtu);
66 local_mtu_ = mtu;
67 }
68 void SetRemoteMtu(int mtu) {
69 remote_.NotifyMTU(mtu);
70 remote_mtu_ = mtu;
71 }
Steve Antoncc65bd02017-11-29 10:19:58 -080072 void SetDelay(int delay) { delay_ = delay; }
73 void SetLoss(int percent) { loss_ = percent; }
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -070074 // Used to cause the initial "connect" segment to be lost, needed for a
75 // regression test.
76 void DropNextPacket() { drop_next_packet_ = true; }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000077 void SetOptNagling(bool enable_nagles) {
78 local_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles);
79 remote_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles);
80 }
81 void SetOptAckDelay(int ack_delay) {
82 local_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay);
83 remote_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay);
84 }
85 void SetOptSndBuf(int size) {
86 local_.SetOption(PseudoTcp::OPT_SNDBUF, size);
87 remote_.SetOption(PseudoTcp::OPT_SNDBUF, size);
88 }
89 void SetRemoteOptRcvBuf(int size) {
90 remote_.SetOption(PseudoTcp::OPT_RCVBUF, size);
91 }
92 void SetLocalOptRcvBuf(int size) {
93 local_.SetOption(PseudoTcp::OPT_RCVBUF, size);
94 }
Steve Antoncc65bd02017-11-29 10:19:58 -080095 void DisableRemoteWindowScale() { remote_.disableWindowScale(); }
96 void DisableLocalWindowScale() { local_.disableWindowScale(); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000097
98 protected:
99 int Connect() {
100 int ret = local_.Connect();
101 if (ret == 0) {
102 UpdateLocalClock();
103 }
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -0700104 if (simultaneous_open_) {
105 ret = remote_.Connect();
106 if (ret == 0) {
107 UpdateRemoteClock();
108 }
109 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000110 return ret;
111 }
112 void Close() {
113 local_.Close(false);
114 UpdateLocalClock();
115 }
116
Steve Antoncc65bd02017-11-29 10:19:58 -0800117 enum {
118 MSG_LPACKET,
119 MSG_RPACKET,
120 MSG_LCLOCK,
121 MSG_RCLOCK,
122 MSG_IOCOMPLETE,
123 MSG_WRITE
124 };
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000125 virtual void OnTcpOpen(PseudoTcp* tcp) {
126 // Consider ourselves connected when the local side gets OnTcpOpen.
127 // OnTcpWriteable isn't fired at open, so we trigger it now.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100128 RTC_LOG(LS_VERBOSE) << "Opened";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000129 if (tcp == &local_) {
130 have_connected_ = true;
131 OnTcpWriteable(tcp);
132 }
133 }
134 // Test derived from the base should override
135 // virtual void OnTcpReadable(PseudoTcp* tcp)
136 // and
137 // virtual void OnTcpWritable(PseudoTcp* tcp)
Peter Boström0c4e06b2015-10-07 12:23:21 +0200138 virtual void OnTcpClosed(PseudoTcp* tcp, uint32_t error) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000139 // Consider ourselves closed when the remote side gets OnTcpClosed.
Steve Anton5c8231c2017-12-06 10:39:22 -0800140 // TODO(?): OnTcpClosed is only ever notified in case of error in
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000141 // the current implementation. Solicited close is not (yet) supported.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100142 RTC_LOG(LS_VERBOSE) << "Closed";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000143 EXPECT_EQ(0U, error);
144 if (tcp == &remote_) {
145 have_disconnected_ = true;
146 }
147 }
148 virtual WriteResult TcpWritePacket(PseudoTcp* tcp,
Steve Antoncc65bd02017-11-29 10:19:58 -0800149 const char* buffer,
150 size_t len) {
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -0700151 // Drop a packet if the test called DropNextPacket.
152 if (drop_next_packet_) {
153 drop_next_packet_ = false;
154 RTC_LOG(LS_VERBOSE) << "Dropping packet due to DropNextPacket, size="
155 << len;
156 return WR_SUCCESS;
157 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000158 // Randomly drop the desired percentage of packets.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200159 if (rtc::CreateRandomId() % 100 < static_cast<uint32_t>(loss_)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100160 RTC_LOG(LS_VERBOSE) << "Randomly dropping packet, size=" << len;
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -0700161 return WR_SUCCESS;
162 }
163 // Also drop packets that are larger than the configured MTU.
164 if (len > static_cast<size_t>(std::min(local_mtu_, remote_mtu_))) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100165 RTC_LOG(LS_VERBOSE) << "Dropping packet that exceeds path MTU, size="
166 << len;
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -0700167 return WR_SUCCESS;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000168 }
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -0700169 int id = (tcp == &local_) ? MSG_RPACKET : MSG_LPACKET;
170 std::string packet(buffer, len);
171 rtc::Thread::Current()->PostDelayed(RTC_FROM_HERE, delay_, this, id,
172 rtc::WrapMessageData(packet));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000173 return WR_SUCCESS;
174 }
175
176 void UpdateLocalClock() { UpdateClock(&local_, MSG_LCLOCK); }
177 void UpdateRemoteClock() { UpdateClock(&remote_, MSG_RCLOCK); }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200178 void UpdateClock(PseudoTcp* tcp, uint32_t message) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000179 long interval = 0; // NOLINT
180 tcp->GetNextClock(PseudoTcp::Now(), interval);
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000181 interval = std::max<int>(interval, 0L); // sometimes interval is < 0
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000182 rtc::Thread::Current()->Clear(this, message);
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700183 rtc::Thread::Current()->PostDelayed(RTC_FROM_HERE, interval, this, message);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000184 }
185
186 virtual void OnMessage(rtc::Message* message) {
187 switch (message->message_id) {
188 case MSG_LPACKET: {
Steve Antoncc65bd02017-11-29 10:19:58 -0800189 const std::string& s(rtc::UseMessageData<std::string>(message->pdata));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000190 local_.NotifyPacket(s.c_str(), s.size());
191 UpdateLocalClock();
192 break;
193 }
194 case MSG_RPACKET: {
Steve Antoncc65bd02017-11-29 10:19:58 -0800195 const std::string& s(rtc::UseMessageData<std::string>(message->pdata));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000196 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_;
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -0700224 bool drop_next_packet_ = false;
225 bool simultaneous_open_ = false;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000226};
227
228class PseudoTcpTest : public PseudoTcpTestBase {
229 public:
230 void TestTransfer(int size) {
Honghai Zhang82d78622016-05-06 11:29:15 -0700231 uint32_t start;
232 int32_t elapsed;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000233 size_t received;
234 // Create some dummy data to send.
235 send_stream_.ReserveSize(size);
236 for (int i = 0; i < size; ++i) {
237 char ch = static_cast<char>(i);
238 send_stream_.Write(&ch, 1, NULL, NULL);
239 }
240 send_stream_.Rewind();
241 // Prepare the receive stream.
242 recv_stream_.ReserveSize(size);
243 // Connect and wait until connected.
Honghai Zhang82d78622016-05-06 11:29:15 -0700244 start = rtc::Time32();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000245 EXPECT_EQ(0, Connect());
246 EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs);
247 // Sending will start from OnTcpWriteable and complete when all data has
248 // been received.
249 EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs);
Honghai Zhang82d78622016-05-06 11:29:15 -0700250 elapsed = rtc::Time32() - start;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000251 recv_stream_.GetSize(&received);
252 // Ensure we closed down OK and we got the right data.
Steve Anton5c8231c2017-12-06 10:39:22 -0800253 // TODO(?): Ensure the errors are cleared properly.
Steve Antoncc65bd02017-11-29 10:19:58 -0800254 // EXPECT_EQ(0, local_.GetError());
255 // EXPECT_EQ(0, remote_.GetError());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000256 EXPECT_EQ(static_cast<size_t>(size), received);
Steve Antoncc65bd02017-11-29 10:19:58 -0800257 EXPECT_EQ(0,
258 memcmp(send_stream_.GetBuffer(), recv_stream_.GetBuffer(), size));
Mirko Bonadei675513b2017-11-09 11:09:25 +0100259 RTC_LOG(LS_INFO) << "Transferred " << received << " bytes in " << elapsed
260 << " ms (" << size * 8 / elapsed << " Kbps)";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000261 }
262
263 private:
264 // IPseudoTcpNotify interface
265
266 virtual void OnTcpReadable(PseudoTcp* tcp) {
267 // Stream bytes to the recv stream as they arrive.
268 if (tcp == &remote_) {
269 ReadData();
270
Steve Anton5c8231c2017-12-06 10:39:22 -0800271 // TODO(?): OnTcpClosed() is currently only notified on error -
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000272 // there is no on-the-wire equivalent of TCP FIN.
273 // So we fake the notification when all the data has been read.
274 size_t received, required;
275 recv_stream_.GetPosition(&received);
276 send_stream_.GetSize(&required);
277 if (received == required)
278 OnTcpClosed(&remote_, 0);
279 }
280 }
281 virtual void OnTcpWriteable(PseudoTcp* tcp) {
282 // Write bytes from the send stream when we can.
283 // Shut down when we've sent everything.
284 if (tcp == &local_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100285 RTC_LOG(LS_VERBOSE) << "Flow Control Lifted";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000286 bool done;
287 WriteData(&done);
288 if (done) {
289 Close();
290 }
291 }
292 }
293
294 void ReadData() {
295 char block[kBlockSize];
296 size_t position;
297 int rcvd;
298 do {
299 rcvd = remote_.Recv(block, sizeof(block));
300 if (rcvd != -1) {
301 recv_stream_.Write(block, rcvd, NULL, NULL);
302 recv_stream_.GetPosition(&position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100303 RTC_LOG(LS_VERBOSE) << "Received: " << position;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000304 }
305 } while (rcvd > 0);
306 }
307 void WriteData(bool* done) {
308 size_t position, tosend;
309 int sent;
310 char block[kBlockSize];
311 do {
312 send_stream_.GetPosition(&position);
313 if (send_stream_.Read(block, sizeof(block), &tosend, NULL) !=
314 rtc::SR_EOS) {
315 sent = local_.Send(block, tosend);
316 UpdateLocalClock();
317 if (sent != -1) {
318 send_stream_.SetPosition(position + sent);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100319 RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000320 } else {
321 send_stream_.SetPosition(position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100322 RTC_LOG(LS_VERBOSE) << "Flow Controlled";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000323 }
324 } else {
325 sent = static_cast<int>(tosend = 0);
326 }
327 } while (sent > 0);
328 *done = (tosend == 0);
329 }
330
331 private:
332 rtc::MemoryStream send_stream_;
333 rtc::MemoryStream recv_stream_;
334};
335
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000336class PseudoTcpTestPingPong : public PseudoTcpTestBase {
337 public:
338 PseudoTcpTestPingPong()
339 : iterations_remaining_(0),
Steve Antoncc65bd02017-11-29 10:19:58 -0800340 sender_(NULL),
341 receiver_(NULL),
342 bytes_per_send_(0) {}
343 void SetBytesPerSend(int bytes) { bytes_per_send_ = bytes; }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000344 void TestPingPong(int size, int iterations) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200345 uint32_t start, elapsed;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000346 iterations_remaining_ = iterations;
347 receiver_ = &remote_;
348 sender_ = &local_;
349 // Create some dummy data to send.
350 send_stream_.ReserveSize(size);
351 for (int i = 0; i < size; ++i) {
352 char ch = static_cast<char>(i);
353 send_stream_.Write(&ch, 1, NULL, NULL);
354 }
355 send_stream_.Rewind();
356 // Prepare the receive stream.
357 recv_stream_.ReserveSize(size);
358 // Connect and wait until connected.
Honghai Zhang82d78622016-05-06 11:29:15 -0700359 start = rtc::Time32();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000360 EXPECT_EQ(0, Connect());
361 EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs);
362 // Sending will start from OnTcpWriteable and stop when the required
363 // number of iterations have completed.
364 EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs);
365 elapsed = rtc::TimeSince(start);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100366 RTC_LOG(LS_INFO) << "Performed " << iterations << " pings in " << elapsed
367 << " ms";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000368 }
369
370 private:
371 // IPseudoTcpNotify interface
372
373 virtual void OnTcpReadable(PseudoTcp* tcp) {
374 if (tcp != receiver_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100375 RTC_LOG_F(LS_ERROR) << "unexpected OnTcpReadable";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000376 return;
377 }
378 // Stream bytes to the recv stream as they arrive.
379 ReadData();
380 // If we've received the desired amount of data, rewind things
381 // and send it back the other way!
382 size_t position, desired;
383 recv_stream_.GetPosition(&position);
384 send_stream_.GetSize(&desired);
385 if (position == desired) {
386 if (receiver_ == &local_ && --iterations_remaining_ == 0) {
387 Close();
Steve Anton5c8231c2017-12-06 10:39:22 -0800388 // TODO(?): Fake OnTcpClosed() on the receiver for now.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000389 OnTcpClosed(&remote_, 0);
390 return;
391 }
392 PseudoTcp* tmp = receiver_;
393 receiver_ = sender_;
394 sender_ = tmp;
395 recv_stream_.Rewind();
396 send_stream_.Rewind();
397 OnTcpWriteable(sender_);
398 }
399 }
400 virtual void OnTcpWriteable(PseudoTcp* tcp) {
401 if (tcp != sender_)
402 return;
403 // Write bytes from the send stream when we can.
404 // Shut down when we've sent everything.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100405 RTC_LOG(LS_VERBOSE) << "Flow Control Lifted";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000406 WriteData();
407 }
408
409 void ReadData() {
410 char block[kBlockSize];
411 size_t position;
412 int rcvd;
413 do {
414 rcvd = receiver_->Recv(block, sizeof(block));
415 if (rcvd != -1) {
416 recv_stream_.Write(block, rcvd, NULL, NULL);
417 recv_stream_.GetPosition(&position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100418 RTC_LOG(LS_VERBOSE) << "Received: " << position;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000419 }
420 } while (rcvd > 0);
421 }
422 void WriteData() {
423 size_t position, tosend;
424 int sent;
425 char block[kBlockSize];
426 do {
427 send_stream_.GetPosition(&position);
428 tosend = bytes_per_send_ ? bytes_per_send_ : sizeof(block);
Steve Antoncc65bd02017-11-29 10:19:58 -0800429 if (send_stream_.Read(block, tosend, &tosend, NULL) != rtc::SR_EOS) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000430 sent = sender_->Send(block, tosend);
431 UpdateLocalClock();
432 if (sent != -1) {
433 send_stream_.SetPosition(position + sent);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100434 RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000435 } else {
436 send_stream_.SetPosition(position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100437 RTC_LOG(LS_VERBOSE) << "Flow Controlled";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000438 }
439 } else {
440 sent = static_cast<int>(tosend = 0);
441 }
442 } while (sent > 0);
443 }
444
445 private:
446 int iterations_remaining_;
447 PseudoTcp* sender_;
448 PseudoTcp* receiver_;
449 int bytes_per_send_;
450};
451
452// Fill the receiver window until it is full, drain it and then
453// fill it with the same amount. This is to test that receiver window
454// contracts and enlarges correctly.
455class PseudoTcpTestReceiveWindow : public PseudoTcpTestBase {
456 public:
457 // Not all the data are transfered, |size| just need to be big enough
458 // to fill up the receiver window twice.
459 void TestTransfer(int size) {
460 // Create some dummy data to send.
461 send_stream_.ReserveSize(size);
462 for (int i = 0; i < size; ++i) {
463 char ch = static_cast<char>(i);
464 send_stream_.Write(&ch, 1, NULL, NULL);
465 }
466 send_stream_.Rewind();
467
468 // Prepare the receive stream.
469 recv_stream_.ReserveSize(size);
470
471 // Connect and wait until connected.
472 EXPECT_EQ(0, Connect());
473 EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs);
474
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700475 rtc::Thread::Current()->Post(RTC_FROM_HERE, this, MSG_WRITE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000476 EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs);
477
478 ASSERT_EQ(2u, send_position_.size());
479 ASSERT_EQ(2u, recv_position_.size());
480
481 const size_t estimated_recv_window = EstimateReceiveWindowSize();
482
483 // The difference in consecutive send positions should equal the
484 // receive window size or match very closely. This verifies that receive
485 // window is open after receiver drained all the data.
486 const size_t send_position_diff = send_position_[1] - send_position_[0];
487 EXPECT_GE(1024u, estimated_recv_window - send_position_diff);
488
489 // Receiver drained the receive window twice.
490 EXPECT_EQ(2 * estimated_recv_window, recv_position_[1]);
491 }
492
493 virtual void OnMessage(rtc::Message* message) {
494 int message_id = message->message_id;
495 PseudoTcpTestBase::OnMessage(message);
496
497 switch (message_id) {
498 case MSG_WRITE: {
499 WriteData();
500 break;
501 }
502 default:
503 break;
504 }
505 }
506
Peter Boström0c4e06b2015-10-07 12:23:21 +0200507 uint32_t EstimateReceiveWindowSize() const {
508 return static_cast<uint32_t>(recv_position_[0]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000509 }
510
Peter Boström0c4e06b2015-10-07 12:23:21 +0200511 uint32_t EstimateSendWindowSize() const {
512 return static_cast<uint32_t>(send_position_[0] - recv_position_[0]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000513 }
514
515 private:
516 // IPseudoTcpNotify interface
Steve Antoncc65bd02017-11-29 10:19:58 -0800517 virtual void OnTcpReadable(PseudoTcp* tcp) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000518
Steve Antoncc65bd02017-11-29 10:19:58 -0800519 virtual void OnTcpWriteable(PseudoTcp* tcp) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000520
521 void ReadUntilIOPending() {
522 char block[kBlockSize];
523 size_t position;
524 int rcvd;
525
526 do {
527 rcvd = remote_.Recv(block, sizeof(block));
528 if (rcvd != -1) {
529 recv_stream_.Write(block, rcvd, NULL, NULL);
530 recv_stream_.GetPosition(&position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100531 RTC_LOG(LS_VERBOSE) << "Received: " << position;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000532 }
533 } while (rcvd > 0);
534
535 recv_stream_.GetPosition(&position);
536 recv_position_.push_back(position);
537
538 // Disconnect if we have done two transfers.
539 if (recv_position_.size() == 2u) {
540 Close();
541 OnTcpClosed(&remote_, 0);
542 } else {
543 WriteData();
544 }
545 }
546
547 void WriteData() {
548 size_t position, tosend;
549 int sent;
550 char block[kBlockSize];
551 do {
552 send_stream_.GetPosition(&position);
553 if (send_stream_.Read(block, sizeof(block), &tosend, NULL) !=
554 rtc::SR_EOS) {
555 sent = local_.Send(block, tosend);
556 UpdateLocalClock();
557 if (sent != -1) {
558 send_stream_.SetPosition(position + sent);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100559 RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000560 } else {
561 send_stream_.SetPosition(position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100562 RTC_LOG(LS_VERBOSE) << "Flow Controlled";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000563 }
564 } else {
565 sent = static_cast<int>(tosend = 0);
566 }
567 } while (sent > 0);
568 // At this point, we've filled up the available space in the send queue.
569
Steve Antoncc65bd02017-11-29 10:19:58 -0800570 int message_queue_size = static_cast<int>(rtc::Thread::Current()->size());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000571 // The message queue will always have at least 2 messages, an RCLOCK and
572 // an LCLOCK, since they are added back on the delay queue at the same time
573 // they are pulled off and therefore are never really removed.
574 if (message_queue_size > 2) {
575 // If there are non-clock messages remaining, attempt to continue sending
576 // after giving those messages time to process, which should free up the
577 // send buffer.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700578 rtc::Thread::Current()->PostDelayed(RTC_FROM_HERE, 10, this, MSG_WRITE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000579 } else {
580 if (!remote_.isReceiveBufferFull()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100581 RTC_LOG(LS_ERROR) << "This shouldn't happen - the send buffer is full, "
Jonas Olssond7d762d2018-03-28 09:47:51 +0200582 "the receive buffer is not, and there are no "
583 "remaining messages to process.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000584 }
585 send_stream_.GetPosition(&position);
586 send_position_.push_back(position);
587
588 // Drain the receiver buffer.
589 ReadUntilIOPending();
590 }
591 }
592
593 private:
594 rtc::MemoryStream send_stream_;
595 rtc::MemoryStream recv_stream_;
596
597 std::vector<size_t> send_position_;
598 std::vector<size_t> recv_position_;
599};
600
601// Basic end-to-end data transfer tests
602
603// Test the normal case of sending data from one side to the other.
604TEST_F(PseudoTcpTest, TestSend) {
605 SetLocalMtu(1500);
606 SetRemoteMtu(1500);
607 TestTransfer(1000000);
608}
609
610// Test sending data with a 50 ms RTT. Transmission should take longer due
611// to a slower ramp-up in send rate.
612TEST_F(PseudoTcpTest, TestSendWithDelay) {
613 SetLocalMtu(1500);
614 SetRemoteMtu(1500);
615 SetDelay(50);
616 TestTransfer(1000000);
617}
618
619// Test sending data with packet loss. Transmission should take much longer due
620// to send back-off when loss occurs.
621TEST_F(PseudoTcpTest, TestSendWithLoss) {
622 SetLocalMtu(1500);
623 SetRemoteMtu(1500);
624 SetLoss(10);
625 TestTransfer(100000); // less data so test runs faster
626}
627
628// Test sending data with a 50 ms RTT and 10% packet loss. Transmission should
629// take much longer due to send back-off and slower detection of loss.
630TEST_F(PseudoTcpTest, TestSendWithDelayAndLoss) {
631 SetLocalMtu(1500);
632 SetRemoteMtu(1500);
633 SetDelay(50);
634 SetLoss(10);
635 TestTransfer(100000); // less data so test runs faster
636}
637
638// Test sending data with 10% packet loss and Nagling disabled. Transmission
639// should take about the same time as with Nagling enabled.
640TEST_F(PseudoTcpTest, TestSendWithLossAndOptNaglingOff) {
641 SetLocalMtu(1500);
642 SetRemoteMtu(1500);
643 SetLoss(10);
644 SetOptNagling(false);
645 TestTransfer(100000); // less data so test runs faster
646}
647
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -0700648// Regression test for bugs.webrtc.org/9208.
649//
650// This bug resulted in corrupted data if a "connect" segment was received after
651// a data segment. This is only possible if:
652//
653// * The initial "connect" segment is lost, and retransmitted later.
654// * Both sides send "connect"s simultaneously, such that the local side thinks
655// a connection is established even before its "connect" has been
656// acknowledged.
657// * Nagle algorithm disabled, allowing a data segment to be sent before the
658// "connect" has been acknowledged.
659TEST_F(PseudoTcpTest,
660 TestSendWhenFirstPacketLostWithOptNaglingOffAndSimultaneousOpen) {
661 SetLocalMtu(1500);
662 SetRemoteMtu(1500);
663 DropNextPacket();
664 SetOptNagling(false);
665 SetSimultaneousOpen(true);
666 TestTransfer(10000);
667}
668
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000669// Test sending data with 10% packet loss and Delayed ACK disabled.
670// Transmission should be slightly faster than with it enabled.
671TEST_F(PseudoTcpTest, TestSendWithLossAndOptAckDelayOff) {
672 SetLocalMtu(1500);
673 SetRemoteMtu(1500);
674 SetLoss(10);
675 SetOptAckDelay(0);
676 TestTransfer(100000);
677}
678
679// Test sending data with 50ms delay and Nagling disabled.
680TEST_F(PseudoTcpTest, TestSendWithDelayAndOptNaglingOff) {
681 SetLocalMtu(1500);
682 SetRemoteMtu(1500);
683 SetDelay(50);
684 SetOptNagling(false);
685 TestTransfer(100000); // less data so test runs faster
686}
687
688// Test sending data with 50ms delay and Delayed ACK disabled.
689TEST_F(PseudoTcpTest, TestSendWithDelayAndOptAckDelayOff) {
690 SetLocalMtu(1500);
691 SetRemoteMtu(1500);
692 SetDelay(50);
693 SetOptAckDelay(0);
694 TestTransfer(100000); // less data so test runs faster
695}
696
697// Test a large receive buffer with a sender that doesn't support scaling.
698TEST_F(PseudoTcpTest, TestSendRemoteNoWindowScale) {
699 SetLocalMtu(1500);
700 SetRemoteMtu(1500);
701 SetLocalOptRcvBuf(100000);
702 DisableRemoteWindowScale();
703 TestTransfer(1000000);
704}
705
706// Test a large sender-side receive buffer with a receiver that doesn't support
707// scaling.
708TEST_F(PseudoTcpTest, TestSendLocalNoWindowScale) {
709 SetLocalMtu(1500);
710 SetRemoteMtu(1500);
711 SetRemoteOptRcvBuf(100000);
712 DisableLocalWindowScale();
713 TestTransfer(1000000);
714}
715
716// Test when both sides use window scaling.
717TEST_F(PseudoTcpTest, TestSendBothUseWindowScale) {
718 SetLocalMtu(1500);
719 SetRemoteMtu(1500);
720 SetRemoteOptRcvBuf(100000);
721 SetLocalOptRcvBuf(100000);
722 TestTransfer(1000000);
723}
724
725// Test using a large window scale value.
726TEST_F(PseudoTcpTest, TestSendLargeInFlight) {
727 SetLocalMtu(1500);
728 SetRemoteMtu(1500);
729 SetRemoteOptRcvBuf(100000);
730 SetLocalOptRcvBuf(100000);
731 SetOptSndBuf(150000);
732 TestTransfer(1000000);
733}
734
735TEST_F(PseudoTcpTest, TestSendBothUseLargeWindowScale) {
736 SetLocalMtu(1500);
737 SetRemoteMtu(1500);
738 SetRemoteOptRcvBuf(1000000);
739 SetLocalOptRcvBuf(1000000);
740 TestTransfer(10000000);
741}
742
743// Test using a small receive buffer.
744TEST_F(PseudoTcpTest, TestSendSmallReceiveBuffer) {
745 SetLocalMtu(1500);
746 SetRemoteMtu(1500);
747 SetRemoteOptRcvBuf(10000);
748 SetLocalOptRcvBuf(10000);
749 TestTransfer(1000000);
750}
751
752// Test using a very small receive buffer.
753TEST_F(PseudoTcpTest, TestSendVerySmallReceiveBuffer) {
754 SetLocalMtu(1500);
755 SetRemoteMtu(1500);
756 SetRemoteOptRcvBuf(100);
757 SetLocalOptRcvBuf(100);
758 TestTransfer(100000);
759}
760
761// Ping-pong (request/response) tests
762
763// Test sending <= 1x MTU of data in each ping/pong. Should take <10ms.
764TEST_F(PseudoTcpTestPingPong, TestPingPong1xMtu) {
765 SetLocalMtu(1500);
766 SetRemoteMtu(1500);
767 TestPingPong(100, 100);
768}
769
770// Test sending 2x-3x MTU of data in each ping/pong. Should take <10ms.
771TEST_F(PseudoTcpTestPingPong, TestPingPong3xMtu) {
772 SetLocalMtu(1500);
773 SetRemoteMtu(1500);
774 TestPingPong(400, 100);
775}
776
777// Test sending 1x-2x MTU of data in each ping/pong.
778// Should take ~1s, due to interaction between Nagling and Delayed ACK.
779TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtu) {
780 SetLocalMtu(1500);
781 SetRemoteMtu(1500);
782 TestPingPong(2000, 5);
783}
784
785// Test sending 1x-2x MTU of data in each ping/pong with Delayed ACK off.
786// Should take <10ms.
787TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtuWithAckDelayOff) {
788 SetLocalMtu(1500);
789 SetRemoteMtu(1500);
790 SetOptAckDelay(0);
791 TestPingPong(2000, 100);
792}
793
794// Test sending 1x-2x MTU of data in each ping/pong with Nagling off.
795// Should take <10ms.
796TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtuWithNaglingOff) {
797 SetLocalMtu(1500);
798 SetRemoteMtu(1500);
799 SetOptNagling(false);
800 TestPingPong(2000, 5);
801}
802
803// Test sending a ping as pair of short (non-full) segments.
804// Should take ~1s, due to Delayed ACK interaction with Nagling.
805TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegments) {
806 SetLocalMtu(1500);
807 SetRemoteMtu(1500);
808 SetOptAckDelay(5000);
Steve Antoncc65bd02017-11-29 10:19:58 -0800809 SetBytesPerSend(50); // i.e. two Send calls per payload
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000810 TestPingPong(100, 5);
811}
812
813// Test sending ping as a pair of short (non-full) segments, with Nagling off.
814// Should take <10ms.
815TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegmentsWithNaglingOff) {
816 SetLocalMtu(1500);
817 SetRemoteMtu(1500);
818 SetOptNagling(false);
Steve Antoncc65bd02017-11-29 10:19:58 -0800819 SetBytesPerSend(50); // i.e. two Send calls per payload
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000820 TestPingPong(100, 5);
821}
822
823// Test sending <= 1x MTU of data ping/pong, in two segments, no Delayed ACK.
824// Should take ~1s.
825TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegmentsWithAckDelayOff) {
826 SetLocalMtu(1500);
827 SetRemoteMtu(1500);
Steve Antoncc65bd02017-11-29 10:19:58 -0800828 SetBytesPerSend(50); // i.e. two Send calls per payload
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000829 SetOptAckDelay(0);
830 TestPingPong(100, 5);
831}
832
833// Test that receive window expands and contract correctly.
834TEST_F(PseudoTcpTestReceiveWindow, TestReceiveWindow) {
835 SetLocalMtu(1500);
836 SetRemoteMtu(1500);
837 SetOptNagling(false);
838 SetOptAckDelay(0);
839 TestTransfer(1024 * 1000);
840}
841
842// Test setting send window size to a very small value.
843TEST_F(PseudoTcpTestReceiveWindow, TestSetVerySmallSendWindowSize) {
844 SetLocalMtu(1500);
845 SetRemoteMtu(1500);
846 SetOptNagling(false);
847 SetOptAckDelay(0);
848 SetOptSndBuf(900);
849 TestTransfer(1024 * 1000);
850 EXPECT_EQ(900u, EstimateSendWindowSize());
851}
852
853// Test setting receive window size to a value other than default.
854TEST_F(PseudoTcpTestReceiveWindow, TestSetReceiveWindowSize) {
855 SetLocalMtu(1500);
856 SetRemoteMtu(1500);
857 SetOptNagling(false);
858 SetOptAckDelay(0);
859 SetRemoteOptRcvBuf(100000);
860 SetLocalOptRcvBuf(100000);
861 TestTransfer(1024 * 1000);
862 EXPECT_EQ(100000u, EstimateReceiveWindowSize());
863}
864
865/* Test sending data with mismatched MTUs. We should detect this and reduce
866// our packet size accordingly.
Steve Anton5c8231c2017-12-06 10:39:22 -0800867// TODO(?): This doesn't actually work right now. The current code
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000868// doesn't detect if the MTU is set too high on either side.
869TEST_F(PseudoTcpTest, TestSendWithMismatchedMtus) {
870 SetLocalMtu(1500);
871 SetRemoteMtu(1280);
872 TestTransfer(1000000);
873}
874*/