blob: 47d2d41c9189fa79bdb1f726da5ddb4077c511bf [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001/*
2 * Copyright 2004 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
Steve Anton6c38cc72017-11-29 10:25:58 -080011#include <vector>
12
Steve Anton10542f22019-01-11 09:11:00 -080013#include "p2p/base/stun_request.h"
14#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "rtc_base/gunit.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080017#include "rtc_base/time_utils.h"
Yves Gerey3e707812018-11-28 16:47:49 +010018#include "test/gtest.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000019
Steve Anton6c38cc72017-11-29 10:25:58 -080020namespace cricket {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000021
Mirko Bonadei6a489f22019-04-09 15:11:12 +020022class StunRequestTest : public ::testing::Test, public sigslot::has_slots<> {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000023 public:
24 StunRequestTest()
25 : manager_(rtc::Thread::Current()),
Yves Gerey665174f2018-06-19 15:03:05 +020026 request_count_(0),
27 response_(NULL),
28 success_(false),
29 failure_(false),
30 timeout_(false) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000031 manager_.SignalSendPacket.connect(this, &StunRequestTest::OnSendPacket);
32 }
33
34 void OnSendPacket(const void* data, size_t size, StunRequest* req) {
35 request_count_++;
36 }
37
38 void OnResponse(StunMessage* res) {
39 response_ = res;
40 success_ = true;
41 }
42 void OnErrorResponse(StunMessage* res) {
43 response_ = res;
44 failure_ = true;
45 }
Yves Gerey665174f2018-06-19 15:03:05 +020046 void OnTimeout() { timeout_ = true; }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000047
48 protected:
49 static StunMessage* CreateStunMessage(StunMessageType type,
50 StunMessage* req) {
51 StunMessage* msg = new StunMessage();
52 msg->SetType(type);
53 if (req) {
54 msg->SetTransactionID(req->transaction_id());
55 }
56 return msg;
57 }
58 static int TotalDelay(int sends) {
pthatcher94a2f212017-02-08 14:42:22 -080059 std::vector<int> delays = {0, 250, 750, 1750, 3750,
60 7750, 15750, 23750, 31750, 39750};
61 return delays[sends];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000062 }
63
64 StunRequestManager manager_;
65 int request_count_;
66 StunMessage* response_;
67 bool success_;
68 bool failure_;
69 bool timeout_;
70};
71
72// Forwards results to the test class.
73class StunRequestThunker : public StunRequest {
74 public:
75 StunRequestThunker(StunMessage* msg, StunRequestTest* test)
76 : StunRequest(msg), test_(test) {}
77 explicit StunRequestThunker(StunRequestTest* test) : test_(test) {}
Yves Gerey665174f2018-06-19 15:03:05 +020078
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000079 private:
Yves Gerey665174f2018-06-19 15:03:05 +020080 virtual void OnResponse(StunMessage* res) { test_->OnResponse(res); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000081 virtual void OnErrorResponse(StunMessage* res) {
82 test_->OnErrorResponse(res);
83 }
Yves Gerey665174f2018-06-19 15:03:05 +020084 virtual void OnTimeout() { test_->OnTimeout(); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000085
86 virtual void Prepare(StunMessage* request) {
87 request->SetType(STUN_BINDING_REQUEST);
88 }
89
90 StunRequestTest* test_;
91};
92
93// Test handling of a normal binding response.
94TEST_F(StunRequestTest, TestSuccess) {
95 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
96
97 manager_.Send(new StunRequestThunker(req, this));
98 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req);
99 EXPECT_TRUE(manager_.CheckResponse(res));
100
101 EXPECT_TRUE(response_ == res);
102 EXPECT_TRUE(success_);
103 EXPECT_FALSE(failure_);
104 EXPECT_FALSE(timeout_);
105 delete res;
106}
107
108// Test handling of an error binding response.
109TEST_F(StunRequestTest, TestError) {
110 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
111
112 manager_.Send(new StunRequestThunker(req, this));
113 StunMessage* res = CreateStunMessage(STUN_BINDING_ERROR_RESPONSE, req);
114 EXPECT_TRUE(manager_.CheckResponse(res));
115
116 EXPECT_TRUE(response_ == res);
117 EXPECT_FALSE(success_);
118 EXPECT_TRUE(failure_);
119 EXPECT_FALSE(timeout_);
120 delete res;
121}
122
123// Test handling of a binding response with the wrong transaction id.
124TEST_F(StunRequestTest, TestUnexpected) {
125 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
126
127 manager_.Send(new StunRequestThunker(req, this));
128 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, NULL);
129 EXPECT_FALSE(manager_.CheckResponse(res));
130
131 EXPECT_TRUE(response_ == NULL);
132 EXPECT_FALSE(success_);
133 EXPECT_FALSE(failure_);
134 EXPECT_FALSE(timeout_);
135 delete res;
136}
137
pthatcher94a2f212017-02-08 14:42:22 -0800138// Test that requests are sent at the right times.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000139TEST_F(StunRequestTest, TestBackoff) {
skvladb9d8d102016-09-06 17:17:17 -0700140 rtc::ScopedFakeClock fake_clock;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000141 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
142
nisse1bffc1d2016-05-02 08:18:55 -0700143 int64_t start = rtc::TimeMillis();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000144 manager_.Send(new StunRequestThunker(req, this));
145 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req);
146 for (int i = 0; i < 9; ++i) {
pthatcher94a2f212017-02-08 14:42:22 -0800147 EXPECT_TRUE_SIMULATED_WAIT(request_count_ != i, STUN_TOTAL_TIMEOUT,
148 fake_clock);
nisse1bffc1d2016-05-02 08:18:55 -0700149 int64_t elapsed = rtc::TimeMillis() - start;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100150 RTC_LOG(LS_INFO) << "STUN request #" << (i + 1) << " sent at " << elapsed
151 << " ms";
skvladb9d8d102016-09-06 17:17:17 -0700152 EXPECT_EQ(TotalDelay(i), elapsed);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000153 }
154 EXPECT_TRUE(manager_.CheckResponse(res));
155
156 EXPECT_TRUE(response_ == res);
157 EXPECT_TRUE(success_);
158 EXPECT_FALSE(failure_);
159 EXPECT_FALSE(timeout_);
160 delete res;
161}
162
pthatcher94a2f212017-02-08 14:42:22 -0800163// Test that we timeout properly if no response is received.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000164TEST_F(StunRequestTest, TestTimeout) {
skvladb9d8d102016-09-06 17:17:17 -0700165 rtc::ScopedFakeClock fake_clock;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000166 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
167 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req);
168
169 manager_.Send(new StunRequestThunker(req, this));
pthatcher94a2f212017-02-08 14:42:22 -0800170 SIMULATED_WAIT(false, cricket::STUN_TOTAL_TIMEOUT, fake_clock);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000171
skvladb9d8d102016-09-06 17:17:17 -0700172 EXPECT_FALSE(manager_.CheckResponse(res));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000173 EXPECT_TRUE(response_ == NULL);
174 EXPECT_FALSE(success_);
175 EXPECT_FALSE(failure_);
176 EXPECT_TRUE(timeout_);
177 delete res;
178}
179
180// Regression test for specific crash where we receive a response with the
181// same id as a request that doesn't have an underlying StunMessage yet.
182TEST_F(StunRequestTest, TestNoEmptyRequest) {
183 StunRequestThunker* request = new StunRequestThunker(this);
184
185 manager_.SendDelayed(request, 100);
186
187 StunMessage dummy_req;
188 dummy_req.SetTransactionID(request->id());
189 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, &dummy_req);
190
191 EXPECT_TRUE(manager_.CheckResponse(res));
192
193 EXPECT_TRUE(response_ == res);
194 EXPECT_TRUE(success_);
195 EXPECT_FALSE(failure_);
196 EXPECT_FALSE(timeout_);
197 delete res;
198}
Steve Anton6c38cc72017-11-29 10:25:58 -0800199
200} // namespace cricket