blob: ecafec9fb64673f4fee2487e3b68fe3fcf4236a9 [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
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "p2p/base/pseudo_tcp.h"
12
Yves Gerey3e707812018-11-28 16:47:49 +010013#include <string.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020014
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000015#include <algorithm>
Yves Gerey3e707812018-11-28 16:47:49 +010016#include <cstddef>
Steve Anton5c8231c2017-12-06 10:39:22 -080017#include <string>
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000018#include <vector>
19
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "rtc_base/gunit.h"
21#include "rtc_base/helpers.h"
Yves Gerey3e707812018-11-28 16:47:49 +010022#include "rtc_base/location.h"
23#include "rtc_base/logging.h"
Niels Möllere7547d52018-11-01 09:33:08 +010024#include "rtc_base/memory_stream.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "rtc_base/message_handler.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "rtc_base/thread.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "rtc_base/time_utils.h"
Yves Gerey3e707812018-11-28 16:47:49 +010028#include "test/gtest.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000029
30using cricket::PseudoTcp;
31
32static const int kConnectTimeoutMs = 10000; // ~3 * default RTO of 3000ms
33static const int kTransferTimeoutMs = 15000;
34static const int kBlockSize = 4096;
35
36class PseudoTcpForTest : public cricket::PseudoTcp {
37 public:
Peter Boström0c4e06b2015-10-07 12:23:21 +020038 PseudoTcpForTest(cricket::IPseudoTcpNotify* notify, uint32_t conv)
39 : PseudoTcp(notify, conv) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000040
Steve Antoncc65bd02017-11-29 10:19:58 -080041 bool isReceiveBufferFull() const { return PseudoTcp::isReceiveBufferFull(); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000042
Steve Antoncc65bd02017-11-29 10:19:58 -080043 void disableWindowScale() { PseudoTcp::disableWindowScale(); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000044};
45
Mirko Bonadei6a489f22019-04-09 15:11:12 +020046class PseudoTcpTestBase : public ::testing::Test,
Tomas Gunnarssonabdb4702020-09-05 18:43:36 +020047 public rtc::MessageHandlerAutoCleanup,
Steve Antoncc65bd02017-11-29 10:19:58 -080048 public cricket::IPseudoTcpNotify {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000049 public:
50 PseudoTcpTestBase()
51 : local_(this, 1),
52 remote_(this, 1),
53 have_connected_(false),
54 have_disconnected_(false),
55 local_mtu_(65535),
56 remote_mtu_(65535),
57 delay_(0),
58 loss_(0) {
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -070059 // Set use of the test RNG to get predictable loss patterns. Otherwise,
60 // this test would occasionally get really unlucky loss and time out.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000061 rtc::SetRandomTestMode(true);
62 }
63 ~PseudoTcpTestBase() {
64 // Put it back for the next test.
65 rtc::SetRandomTestMode(false);
66 }
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -070067 // If true, both endpoints will send the "connect" segment simultaneously,
68 // rather than |local_| sending it followed by a response from |remote_|.
69 // Note that this is what chromoting ends up doing.
70 void SetSimultaneousOpen(bool enabled) { simultaneous_open_ = enabled; }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000071 void SetLocalMtu(int mtu) {
72 local_.NotifyMTU(mtu);
73 local_mtu_ = mtu;
74 }
75 void SetRemoteMtu(int mtu) {
76 remote_.NotifyMTU(mtu);
77 remote_mtu_ = mtu;
78 }
Steve Antoncc65bd02017-11-29 10:19:58 -080079 void SetDelay(int delay) { delay_ = delay; }
80 void SetLoss(int percent) { loss_ = percent; }
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -070081 // Used to cause the initial "connect" segment to be lost, needed for a
82 // regression test.
83 void DropNextPacket() { drop_next_packet_ = true; }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000084 void SetOptNagling(bool enable_nagles) {
85 local_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles);
86 remote_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles);
87 }
88 void SetOptAckDelay(int ack_delay) {
89 local_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay);
90 remote_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay);
91 }
92 void SetOptSndBuf(int size) {
93 local_.SetOption(PseudoTcp::OPT_SNDBUF, size);
94 remote_.SetOption(PseudoTcp::OPT_SNDBUF, size);
95 }
96 void SetRemoteOptRcvBuf(int size) {
97 remote_.SetOption(PseudoTcp::OPT_RCVBUF, size);
98 }
99 void SetLocalOptRcvBuf(int size) {
100 local_.SetOption(PseudoTcp::OPT_RCVBUF, size);
101 }
Steve Antoncc65bd02017-11-29 10:19:58 -0800102 void DisableRemoteWindowScale() { remote_.disableWindowScale(); }
103 void DisableLocalWindowScale() { local_.disableWindowScale(); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000104
105 protected:
106 int Connect() {
107 int ret = local_.Connect();
108 if (ret == 0) {
109 UpdateLocalClock();
110 }
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -0700111 if (simultaneous_open_) {
112 ret = remote_.Connect();
113 if (ret == 0) {
114 UpdateRemoteClock();
115 }
116 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000117 return ret;
118 }
119 void Close() {
120 local_.Close(false);
121 UpdateLocalClock();
122 }
123
Steve Antoncc65bd02017-11-29 10:19:58 -0800124 enum {
125 MSG_LPACKET,
126 MSG_RPACKET,
127 MSG_LCLOCK,
128 MSG_RCLOCK,
129 MSG_IOCOMPLETE,
130 MSG_WRITE
131 };
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000132 virtual void OnTcpOpen(PseudoTcp* tcp) {
133 // Consider ourselves connected when the local side gets OnTcpOpen.
134 // OnTcpWriteable isn't fired at open, so we trigger it now.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100135 RTC_LOG(LS_VERBOSE) << "Opened";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000136 if (tcp == &local_) {
137 have_connected_ = true;
138 OnTcpWriteable(tcp);
139 }
140 }
141 // Test derived from the base should override
142 // virtual void OnTcpReadable(PseudoTcp* tcp)
143 // and
144 // virtual void OnTcpWritable(PseudoTcp* tcp)
Peter Boström0c4e06b2015-10-07 12:23:21 +0200145 virtual void OnTcpClosed(PseudoTcp* tcp, uint32_t error) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000146 // Consider ourselves closed when the remote side gets OnTcpClosed.
Steve Anton5c8231c2017-12-06 10:39:22 -0800147 // TODO(?): OnTcpClosed is only ever notified in case of error in
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000148 // the current implementation. Solicited close is not (yet) supported.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100149 RTC_LOG(LS_VERBOSE) << "Closed";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000150 EXPECT_EQ(0U, error);
151 if (tcp == &remote_) {
152 have_disconnected_ = true;
153 }
154 }
155 virtual WriteResult TcpWritePacket(PseudoTcp* tcp,
Steve Antoncc65bd02017-11-29 10:19:58 -0800156 const char* buffer,
157 size_t len) {
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -0700158 // Drop a packet if the test called DropNextPacket.
159 if (drop_next_packet_) {
160 drop_next_packet_ = false;
161 RTC_LOG(LS_VERBOSE) << "Dropping packet due to DropNextPacket, size="
162 << len;
163 return WR_SUCCESS;
164 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000165 // Randomly drop the desired percentage of packets.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200166 if (rtc::CreateRandomId() % 100 < static_cast<uint32_t>(loss_)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100167 RTC_LOG(LS_VERBOSE) << "Randomly dropping packet, size=" << len;
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -0700168 return WR_SUCCESS;
169 }
170 // Also drop packets that are larger than the configured MTU.
171 if (len > static_cast<size_t>(std::min(local_mtu_, remote_mtu_))) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100172 RTC_LOG(LS_VERBOSE) << "Dropping packet that exceeds path MTU, size="
173 << len;
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -0700174 return WR_SUCCESS;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000175 }
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -0700176 int id = (tcp == &local_) ? MSG_RPACKET : MSG_LPACKET;
177 std::string packet(buffer, len);
178 rtc::Thread::Current()->PostDelayed(RTC_FROM_HERE, delay_, this, id,
179 rtc::WrapMessageData(packet));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000180 return WR_SUCCESS;
181 }
182
183 void UpdateLocalClock() { UpdateClock(&local_, MSG_LCLOCK); }
184 void UpdateRemoteClock() { UpdateClock(&remote_, MSG_RCLOCK); }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200185 void UpdateClock(PseudoTcp* tcp, uint32_t message) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000186 long interval = 0; // NOLINT
187 tcp->GetNextClock(PseudoTcp::Now(), interval);
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000188 interval = std::max<int>(interval, 0L); // sometimes interval is < 0
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000189 rtc::Thread::Current()->Clear(this, message);
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700190 rtc::Thread::Current()->PostDelayed(RTC_FROM_HERE, interval, this, message);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000191 }
192
193 virtual void OnMessage(rtc::Message* message) {
194 switch (message->message_id) {
195 case MSG_LPACKET: {
Steve Antoncc65bd02017-11-29 10:19:58 -0800196 const std::string& s(rtc::UseMessageData<std::string>(message->pdata));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000197 local_.NotifyPacket(s.c_str(), s.size());
198 UpdateLocalClock();
199 break;
200 }
201 case MSG_RPACKET: {
Steve Antoncc65bd02017-11-29 10:19:58 -0800202 const std::string& s(rtc::UseMessageData<std::string>(message->pdata));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000203 remote_.NotifyPacket(s.c_str(), s.size());
204 UpdateRemoteClock();
205 break;
206 }
207 case MSG_LCLOCK:
208 local_.NotifyClock(PseudoTcp::Now());
209 UpdateLocalClock();
210 break;
211 case MSG_RCLOCK:
212 remote_.NotifyClock(PseudoTcp::Now());
213 UpdateRemoteClock();
214 break;
215 default:
216 break;
217 }
218 delete message->pdata;
219 }
220
221 PseudoTcpForTest local_;
222 PseudoTcpForTest remote_;
223 rtc::MemoryStream send_stream_;
224 rtc::MemoryStream recv_stream_;
225 bool have_connected_;
226 bool have_disconnected_;
227 int local_mtu_;
228 int remote_mtu_;
229 int delay_;
230 int loss_;
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -0700231 bool drop_next_packet_ = false;
232 bool simultaneous_open_ = false;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000233};
234
235class PseudoTcpTest : public PseudoTcpTestBase {
236 public:
237 void TestTransfer(int size) {
Honghai Zhang82d78622016-05-06 11:29:15 -0700238 uint32_t start;
239 int32_t elapsed;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000240 size_t received;
241 // Create some dummy data to send.
242 send_stream_.ReserveSize(size);
243 for (int i = 0; i < size; ++i) {
244 char ch = static_cast<char>(i);
245 send_stream_.Write(&ch, 1, NULL, NULL);
246 }
247 send_stream_.Rewind();
248 // Prepare the receive stream.
249 recv_stream_.ReserveSize(size);
250 // Connect and wait until connected.
Honghai Zhang82d78622016-05-06 11:29:15 -0700251 start = rtc::Time32();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000252 EXPECT_EQ(0, Connect());
253 EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs);
254 // Sending will start from OnTcpWriteable and complete when all data has
255 // been received.
256 EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs);
Honghai Zhang82d78622016-05-06 11:29:15 -0700257 elapsed = rtc::Time32() - start;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000258 recv_stream_.GetSize(&received);
259 // Ensure we closed down OK and we got the right data.
Steve Anton5c8231c2017-12-06 10:39:22 -0800260 // TODO(?): Ensure the errors are cleared properly.
Steve Antoncc65bd02017-11-29 10:19:58 -0800261 // EXPECT_EQ(0, local_.GetError());
262 // EXPECT_EQ(0, remote_.GetError());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000263 EXPECT_EQ(static_cast<size_t>(size), received);
Steve Antoncc65bd02017-11-29 10:19:58 -0800264 EXPECT_EQ(0,
265 memcmp(send_stream_.GetBuffer(), recv_stream_.GetBuffer(), size));
Mirko Bonadei675513b2017-11-09 11:09:25 +0100266 RTC_LOG(LS_INFO) << "Transferred " << received << " bytes in " << elapsed
267 << " ms (" << size * 8 / elapsed << " Kbps)";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000268 }
269
270 private:
271 // IPseudoTcpNotify interface
272
273 virtual void OnTcpReadable(PseudoTcp* tcp) {
274 // Stream bytes to the recv stream as they arrive.
275 if (tcp == &remote_) {
276 ReadData();
277
Steve Anton5c8231c2017-12-06 10:39:22 -0800278 // TODO(?): OnTcpClosed() is currently only notified on error -
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000279 // there is no on-the-wire equivalent of TCP FIN.
280 // So we fake the notification when all the data has been read.
281 size_t received, required;
282 recv_stream_.GetPosition(&received);
283 send_stream_.GetSize(&required);
284 if (received == required)
285 OnTcpClosed(&remote_, 0);
286 }
287 }
288 virtual void OnTcpWriteable(PseudoTcp* tcp) {
289 // Write bytes from the send stream when we can.
290 // Shut down when we've sent everything.
291 if (tcp == &local_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100292 RTC_LOG(LS_VERBOSE) << "Flow Control Lifted";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000293 bool done;
294 WriteData(&done);
295 if (done) {
296 Close();
297 }
298 }
299 }
300
301 void ReadData() {
302 char block[kBlockSize];
303 size_t position;
304 int rcvd;
305 do {
306 rcvd = remote_.Recv(block, sizeof(block));
307 if (rcvd != -1) {
308 recv_stream_.Write(block, rcvd, NULL, NULL);
309 recv_stream_.GetPosition(&position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100310 RTC_LOG(LS_VERBOSE) << "Received: " << position;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000311 }
312 } while (rcvd > 0);
313 }
314 void WriteData(bool* done) {
315 size_t position, tosend;
316 int sent;
317 char block[kBlockSize];
318 do {
319 send_stream_.GetPosition(&position);
320 if (send_stream_.Read(block, sizeof(block), &tosend, NULL) !=
321 rtc::SR_EOS) {
322 sent = local_.Send(block, tosend);
323 UpdateLocalClock();
324 if (sent != -1) {
325 send_stream_.SetPosition(position + sent);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100326 RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000327 } else {
328 send_stream_.SetPosition(position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100329 RTC_LOG(LS_VERBOSE) << "Flow Controlled";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000330 }
331 } else {
332 sent = static_cast<int>(tosend = 0);
333 }
334 } while (sent > 0);
335 *done = (tosend == 0);
336 }
337
338 private:
339 rtc::MemoryStream send_stream_;
340 rtc::MemoryStream recv_stream_;
341};
342
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000343class PseudoTcpTestPingPong : public PseudoTcpTestBase {
344 public:
345 PseudoTcpTestPingPong()
346 : iterations_remaining_(0),
Steve Antoncc65bd02017-11-29 10:19:58 -0800347 sender_(NULL),
348 receiver_(NULL),
349 bytes_per_send_(0) {}
350 void SetBytesPerSend(int bytes) { bytes_per_send_ = bytes; }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000351 void TestPingPong(int size, int iterations) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200352 uint32_t start, elapsed;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000353 iterations_remaining_ = iterations;
354 receiver_ = &remote_;
355 sender_ = &local_;
356 // Create some dummy data to send.
357 send_stream_.ReserveSize(size);
358 for (int i = 0; i < size; ++i) {
359 char ch = static_cast<char>(i);
360 send_stream_.Write(&ch, 1, NULL, NULL);
361 }
362 send_stream_.Rewind();
363 // Prepare the receive stream.
364 recv_stream_.ReserveSize(size);
365 // Connect and wait until connected.
Honghai Zhang82d78622016-05-06 11:29:15 -0700366 start = rtc::Time32();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000367 EXPECT_EQ(0, Connect());
368 EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs);
369 // Sending will start from OnTcpWriteable and stop when the required
370 // number of iterations have completed.
371 EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs);
372 elapsed = rtc::TimeSince(start);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100373 RTC_LOG(LS_INFO) << "Performed " << iterations << " pings in " << elapsed
374 << " ms";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000375 }
376
377 private:
378 // IPseudoTcpNotify interface
379
380 virtual void OnTcpReadable(PseudoTcp* tcp) {
381 if (tcp != receiver_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100382 RTC_LOG_F(LS_ERROR) << "unexpected OnTcpReadable";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000383 return;
384 }
385 // Stream bytes to the recv stream as they arrive.
386 ReadData();
387 // If we've received the desired amount of data, rewind things
388 // and send it back the other way!
389 size_t position, desired;
390 recv_stream_.GetPosition(&position);
391 send_stream_.GetSize(&desired);
392 if (position == desired) {
393 if (receiver_ == &local_ && --iterations_remaining_ == 0) {
394 Close();
Steve Anton5c8231c2017-12-06 10:39:22 -0800395 // TODO(?): Fake OnTcpClosed() on the receiver for now.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000396 OnTcpClosed(&remote_, 0);
397 return;
398 }
399 PseudoTcp* tmp = receiver_;
400 receiver_ = sender_;
401 sender_ = tmp;
402 recv_stream_.Rewind();
403 send_stream_.Rewind();
404 OnTcpWriteable(sender_);
405 }
406 }
407 virtual void OnTcpWriteable(PseudoTcp* tcp) {
408 if (tcp != sender_)
409 return;
410 // Write bytes from the send stream when we can.
411 // Shut down when we've sent everything.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100412 RTC_LOG(LS_VERBOSE) << "Flow Control Lifted";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000413 WriteData();
414 }
415
416 void ReadData() {
417 char block[kBlockSize];
418 size_t position;
419 int rcvd;
420 do {
421 rcvd = receiver_->Recv(block, sizeof(block));
422 if (rcvd != -1) {
423 recv_stream_.Write(block, rcvd, NULL, NULL);
424 recv_stream_.GetPosition(&position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100425 RTC_LOG(LS_VERBOSE) << "Received: " << position;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000426 }
427 } while (rcvd > 0);
428 }
429 void WriteData() {
430 size_t position, tosend;
431 int sent;
432 char block[kBlockSize];
433 do {
434 send_stream_.GetPosition(&position);
435 tosend = bytes_per_send_ ? bytes_per_send_ : sizeof(block);
Steve Antoncc65bd02017-11-29 10:19:58 -0800436 if (send_stream_.Read(block, tosend, &tosend, NULL) != rtc::SR_EOS) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000437 sent = sender_->Send(block, tosend);
438 UpdateLocalClock();
439 if (sent != -1) {
440 send_stream_.SetPosition(position + sent);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100441 RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000442 } else {
443 send_stream_.SetPosition(position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100444 RTC_LOG(LS_VERBOSE) << "Flow Controlled";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000445 }
446 } else {
447 sent = static_cast<int>(tosend = 0);
448 }
449 } while (sent > 0);
450 }
451
452 private:
453 int iterations_remaining_;
454 PseudoTcp* sender_;
455 PseudoTcp* receiver_;
456 int bytes_per_send_;
457};
458
459// Fill the receiver window until it is full, drain it and then
460// fill it with the same amount. This is to test that receiver window
461// contracts and enlarges correctly.
462class PseudoTcpTestReceiveWindow : public PseudoTcpTestBase {
463 public:
464 // Not all the data are transfered, |size| just need to be big enough
465 // to fill up the receiver window twice.
466 void TestTransfer(int size) {
467 // Create some dummy data to send.
468 send_stream_.ReserveSize(size);
469 for (int i = 0; i < size; ++i) {
470 char ch = static_cast<char>(i);
471 send_stream_.Write(&ch, 1, NULL, NULL);
472 }
473 send_stream_.Rewind();
474
475 // Prepare the receive stream.
476 recv_stream_.ReserveSize(size);
477
478 // Connect and wait until connected.
479 EXPECT_EQ(0, Connect());
480 EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs);
481
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700482 rtc::Thread::Current()->Post(RTC_FROM_HERE, this, MSG_WRITE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000483 EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs);
484
485 ASSERT_EQ(2u, send_position_.size());
486 ASSERT_EQ(2u, recv_position_.size());
487
488 const size_t estimated_recv_window = EstimateReceiveWindowSize();
489
490 // The difference in consecutive send positions should equal the
491 // receive window size or match very closely. This verifies that receive
492 // window is open after receiver drained all the data.
493 const size_t send_position_diff = send_position_[1] - send_position_[0];
494 EXPECT_GE(1024u, estimated_recv_window - send_position_diff);
495
496 // Receiver drained the receive window twice.
497 EXPECT_EQ(2 * estimated_recv_window, recv_position_[1]);
498 }
499
500 virtual void OnMessage(rtc::Message* message) {
501 int message_id = message->message_id;
502 PseudoTcpTestBase::OnMessage(message);
503
504 switch (message_id) {
505 case MSG_WRITE: {
506 WriteData();
507 break;
508 }
509 default:
510 break;
511 }
512 }
513
Peter Boström0c4e06b2015-10-07 12:23:21 +0200514 uint32_t EstimateReceiveWindowSize() const {
515 return static_cast<uint32_t>(recv_position_[0]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000516 }
517
Peter Boström0c4e06b2015-10-07 12:23:21 +0200518 uint32_t EstimateSendWindowSize() const {
519 return static_cast<uint32_t>(send_position_[0] - recv_position_[0]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000520 }
521
522 private:
523 // IPseudoTcpNotify interface
Steve Antoncc65bd02017-11-29 10:19:58 -0800524 virtual void OnTcpReadable(PseudoTcp* tcp) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000525
Steve Antoncc65bd02017-11-29 10:19:58 -0800526 virtual void OnTcpWriteable(PseudoTcp* tcp) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000527
528 void ReadUntilIOPending() {
529 char block[kBlockSize];
530 size_t position;
531 int rcvd;
532
533 do {
534 rcvd = remote_.Recv(block, sizeof(block));
535 if (rcvd != -1) {
536 recv_stream_.Write(block, rcvd, NULL, NULL);
537 recv_stream_.GetPosition(&position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100538 RTC_LOG(LS_VERBOSE) << "Received: " << position;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000539 }
540 } while (rcvd > 0);
541
542 recv_stream_.GetPosition(&position);
543 recv_position_.push_back(position);
544
545 // Disconnect if we have done two transfers.
546 if (recv_position_.size() == 2u) {
547 Close();
548 OnTcpClosed(&remote_, 0);
549 } else {
550 WriteData();
551 }
552 }
553
554 void WriteData() {
555 size_t position, tosend;
556 int sent;
557 char block[kBlockSize];
558 do {
559 send_stream_.GetPosition(&position);
560 if (send_stream_.Read(block, sizeof(block), &tosend, NULL) !=
561 rtc::SR_EOS) {
562 sent = local_.Send(block, tosend);
563 UpdateLocalClock();
564 if (sent != -1) {
565 send_stream_.SetPosition(position + sent);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100566 RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000567 } else {
568 send_stream_.SetPosition(position);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100569 RTC_LOG(LS_VERBOSE) << "Flow Controlled";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000570 }
571 } else {
572 sent = static_cast<int>(tosend = 0);
573 }
574 } while (sent > 0);
575 // At this point, we've filled up the available space in the send queue.
576
Steve Antoncc65bd02017-11-29 10:19:58 -0800577 int message_queue_size = static_cast<int>(rtc::Thread::Current()->size());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000578 // The message queue will always have at least 2 messages, an RCLOCK and
579 // an LCLOCK, since they are added back on the delay queue at the same time
580 // they are pulled off and therefore are never really removed.
581 if (message_queue_size > 2) {
582 // If there are non-clock messages remaining, attempt to continue sending
583 // after giving those messages time to process, which should free up the
584 // send buffer.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700585 rtc::Thread::Current()->PostDelayed(RTC_FROM_HERE, 10, this, MSG_WRITE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000586 } else {
587 if (!remote_.isReceiveBufferFull()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100588 RTC_LOG(LS_ERROR) << "This shouldn't happen - the send buffer is full, "
Jonas Olssond7d762d2018-03-28 09:47:51 +0200589 "the receive buffer is not, and there are no "
590 "remaining messages to process.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000591 }
592 send_stream_.GetPosition(&position);
593 send_position_.push_back(position);
594
595 // Drain the receiver buffer.
596 ReadUntilIOPending();
597 }
598 }
599
600 private:
601 rtc::MemoryStream send_stream_;
602 rtc::MemoryStream recv_stream_;
603
604 std::vector<size_t> send_position_;
605 std::vector<size_t> recv_position_;
606};
607
608// Basic end-to-end data transfer tests
609
610// Test the normal case of sending data from one side to the other.
611TEST_F(PseudoTcpTest, TestSend) {
612 SetLocalMtu(1500);
613 SetRemoteMtu(1500);
614 TestTransfer(1000000);
615}
616
617// Test sending data with a 50 ms RTT. Transmission should take longer due
618// to a slower ramp-up in send rate.
619TEST_F(PseudoTcpTest, TestSendWithDelay) {
620 SetLocalMtu(1500);
621 SetRemoteMtu(1500);
622 SetDelay(50);
623 TestTransfer(1000000);
624}
625
626// Test sending data with packet loss. Transmission should take much longer due
627// to send back-off when loss occurs.
628TEST_F(PseudoTcpTest, TestSendWithLoss) {
629 SetLocalMtu(1500);
630 SetRemoteMtu(1500);
631 SetLoss(10);
632 TestTransfer(100000); // less data so test runs faster
633}
634
635// Test sending data with a 50 ms RTT and 10% packet loss. Transmission should
636// take much longer due to send back-off and slower detection of loss.
637TEST_F(PseudoTcpTest, TestSendWithDelayAndLoss) {
638 SetLocalMtu(1500);
639 SetRemoteMtu(1500);
640 SetDelay(50);
641 SetLoss(10);
642 TestTransfer(100000); // less data so test runs faster
643}
644
645// Test sending data with 10% packet loss and Nagling disabled. Transmission
646// should take about the same time as with Nagling enabled.
647TEST_F(PseudoTcpTest, TestSendWithLossAndOptNaglingOff) {
648 SetLocalMtu(1500);
649 SetRemoteMtu(1500);
650 SetLoss(10);
651 SetOptNagling(false);
652 TestTransfer(100000); // less data so test runs faster
653}
654
Taylor Brandstetter20e8cfb2018-05-24 16:43:02 -0700655// Regression test for bugs.webrtc.org/9208.
656//
657// This bug resulted in corrupted data if a "connect" segment was received after
658// a data segment. This is only possible if:
659//
660// * The initial "connect" segment is lost, and retransmitted later.
661// * Both sides send "connect"s simultaneously, such that the local side thinks
662// a connection is established even before its "connect" has been
663// acknowledged.
664// * Nagle algorithm disabled, allowing a data segment to be sent before the
665// "connect" has been acknowledged.
666TEST_F(PseudoTcpTest,
667 TestSendWhenFirstPacketLostWithOptNaglingOffAndSimultaneousOpen) {
668 SetLocalMtu(1500);
669 SetRemoteMtu(1500);
670 DropNextPacket();
671 SetOptNagling(false);
672 SetSimultaneousOpen(true);
673 TestTransfer(10000);
674}
675
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000676// Test sending data with 10% packet loss and Delayed ACK disabled.
677// Transmission should be slightly faster than with it enabled.
678TEST_F(PseudoTcpTest, TestSendWithLossAndOptAckDelayOff) {
679 SetLocalMtu(1500);
680 SetRemoteMtu(1500);
681 SetLoss(10);
682 SetOptAckDelay(0);
683 TestTransfer(100000);
684}
685
686// Test sending data with 50ms delay and Nagling disabled.
687TEST_F(PseudoTcpTest, TestSendWithDelayAndOptNaglingOff) {
688 SetLocalMtu(1500);
689 SetRemoteMtu(1500);
690 SetDelay(50);
691 SetOptNagling(false);
692 TestTransfer(100000); // less data so test runs faster
693}
694
695// Test sending data with 50ms delay and Delayed ACK disabled.
696TEST_F(PseudoTcpTest, TestSendWithDelayAndOptAckDelayOff) {
697 SetLocalMtu(1500);
698 SetRemoteMtu(1500);
699 SetDelay(50);
700 SetOptAckDelay(0);
701 TestTransfer(100000); // less data so test runs faster
702}
703
704// Test a large receive buffer with a sender that doesn't support scaling.
705TEST_F(PseudoTcpTest, TestSendRemoteNoWindowScale) {
706 SetLocalMtu(1500);
707 SetRemoteMtu(1500);
708 SetLocalOptRcvBuf(100000);
709 DisableRemoteWindowScale();
710 TestTransfer(1000000);
711}
712
713// Test a large sender-side receive buffer with a receiver that doesn't support
714// scaling.
715TEST_F(PseudoTcpTest, TestSendLocalNoWindowScale) {
716 SetLocalMtu(1500);
717 SetRemoteMtu(1500);
718 SetRemoteOptRcvBuf(100000);
719 DisableLocalWindowScale();
720 TestTransfer(1000000);
721}
722
723// Test when both sides use window scaling.
724TEST_F(PseudoTcpTest, TestSendBothUseWindowScale) {
725 SetLocalMtu(1500);
726 SetRemoteMtu(1500);
727 SetRemoteOptRcvBuf(100000);
728 SetLocalOptRcvBuf(100000);
729 TestTransfer(1000000);
730}
731
732// Test using a large window scale value.
733TEST_F(PseudoTcpTest, TestSendLargeInFlight) {
734 SetLocalMtu(1500);
735 SetRemoteMtu(1500);
736 SetRemoteOptRcvBuf(100000);
737 SetLocalOptRcvBuf(100000);
738 SetOptSndBuf(150000);
739 TestTransfer(1000000);
740}
741
742TEST_F(PseudoTcpTest, TestSendBothUseLargeWindowScale) {
743 SetLocalMtu(1500);
744 SetRemoteMtu(1500);
745 SetRemoteOptRcvBuf(1000000);
746 SetLocalOptRcvBuf(1000000);
747 TestTransfer(10000000);
748}
749
750// Test using a small receive buffer.
751TEST_F(PseudoTcpTest, TestSendSmallReceiveBuffer) {
752 SetLocalMtu(1500);
753 SetRemoteMtu(1500);
754 SetRemoteOptRcvBuf(10000);
755 SetLocalOptRcvBuf(10000);
756 TestTransfer(1000000);
757}
758
759// Test using a very small receive buffer.
760TEST_F(PseudoTcpTest, TestSendVerySmallReceiveBuffer) {
761 SetLocalMtu(1500);
762 SetRemoteMtu(1500);
763 SetRemoteOptRcvBuf(100);
764 SetLocalOptRcvBuf(100);
765 TestTransfer(100000);
766}
767
768// Ping-pong (request/response) tests
769
770// Test sending <= 1x MTU of data in each ping/pong. Should take <10ms.
771TEST_F(PseudoTcpTestPingPong, TestPingPong1xMtu) {
772 SetLocalMtu(1500);
773 SetRemoteMtu(1500);
774 TestPingPong(100, 100);
775}
776
777// Test sending 2x-3x MTU of data in each ping/pong. Should take <10ms.
778TEST_F(PseudoTcpTestPingPong, TestPingPong3xMtu) {
779 SetLocalMtu(1500);
780 SetRemoteMtu(1500);
781 TestPingPong(400, 100);
782}
783
784// Test sending 1x-2x MTU of data in each ping/pong.
785// Should take ~1s, due to interaction between Nagling and Delayed ACK.
786TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtu) {
787 SetLocalMtu(1500);
788 SetRemoteMtu(1500);
789 TestPingPong(2000, 5);
790}
791
792// Test sending 1x-2x MTU of data in each ping/pong with Delayed ACK off.
793// Should take <10ms.
794TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtuWithAckDelayOff) {
795 SetLocalMtu(1500);
796 SetRemoteMtu(1500);
797 SetOptAckDelay(0);
798 TestPingPong(2000, 100);
799}
800
801// Test sending 1x-2x MTU of data in each ping/pong with Nagling off.
802// Should take <10ms.
803TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtuWithNaglingOff) {
804 SetLocalMtu(1500);
805 SetRemoteMtu(1500);
806 SetOptNagling(false);
807 TestPingPong(2000, 5);
808}
809
810// Test sending a ping as pair of short (non-full) segments.
811// Should take ~1s, due to Delayed ACK interaction with Nagling.
812TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegments) {
813 SetLocalMtu(1500);
814 SetRemoteMtu(1500);
815 SetOptAckDelay(5000);
Steve Antoncc65bd02017-11-29 10:19:58 -0800816 SetBytesPerSend(50); // i.e. two Send calls per payload
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000817 TestPingPong(100, 5);
818}
819
820// Test sending ping as a pair of short (non-full) segments, with Nagling off.
821// Should take <10ms.
822TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegmentsWithNaglingOff) {
823 SetLocalMtu(1500);
824 SetRemoteMtu(1500);
825 SetOptNagling(false);
Steve Antoncc65bd02017-11-29 10:19:58 -0800826 SetBytesPerSend(50); // i.e. two Send calls per payload
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000827 TestPingPong(100, 5);
828}
829
830// Test sending <= 1x MTU of data ping/pong, in two segments, no Delayed ACK.
831// Should take ~1s.
832TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegmentsWithAckDelayOff) {
833 SetLocalMtu(1500);
834 SetRemoteMtu(1500);
Steve Antoncc65bd02017-11-29 10:19:58 -0800835 SetBytesPerSend(50); // i.e. two Send calls per payload
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000836 SetOptAckDelay(0);
837 TestPingPong(100, 5);
838}
839
840// Test that receive window expands and contract correctly.
841TEST_F(PseudoTcpTestReceiveWindow, TestReceiveWindow) {
842 SetLocalMtu(1500);
843 SetRemoteMtu(1500);
844 SetOptNagling(false);
845 SetOptAckDelay(0);
846 TestTransfer(1024 * 1000);
847}
848
849// Test setting send window size to a very small value.
850TEST_F(PseudoTcpTestReceiveWindow, TestSetVerySmallSendWindowSize) {
851 SetLocalMtu(1500);
852 SetRemoteMtu(1500);
853 SetOptNagling(false);
854 SetOptAckDelay(0);
855 SetOptSndBuf(900);
856 TestTransfer(1024 * 1000);
857 EXPECT_EQ(900u, EstimateSendWindowSize());
858}
859
860// Test setting receive window size to a value other than default.
861TEST_F(PseudoTcpTestReceiveWindow, TestSetReceiveWindowSize) {
862 SetLocalMtu(1500);
863 SetRemoteMtu(1500);
864 SetOptNagling(false);
865 SetOptAckDelay(0);
866 SetRemoteOptRcvBuf(100000);
867 SetLocalOptRcvBuf(100000);
868 TestTransfer(1024 * 1000);
869 EXPECT_EQ(100000u, EstimateReceiveWindowSize());
870}
871
872/* Test sending data with mismatched MTUs. We should detect this and reduce
873// our packet size accordingly.
Steve Anton5c8231c2017-12-06 10:39:22 -0800874// TODO(?): This doesn't actually work right now. The current code
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000875// doesn't detect if the MTU is set too high on either side.
876TEST_F(PseudoTcpTest, TestSendWithMismatchedMtus) {
877 SetLocalMtu(1500);
878 SetRemoteMtu(1280);
879 TestTransfer(1000000);
880}
881*/