blob: ce573f087d180ceb6b7fae34ab22752c013a06c6 [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
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "p2p/base/stun_request.h"
12
Steve Anton6c38cc72017-11-29 10:25:58 -080013#include <vector>
14
Steve Anton10542f22019-01-11 09:11:00 -080015#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "rtc_base/gunit.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080018#include "rtc_base/time_utils.h"
Yves Gerey3e707812018-11-28 16:47:49 +010019#include "test/gtest.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000020
Steve Anton6c38cc72017-11-29 10:25:58 -080021namespace cricket {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000022
Mirko Bonadei6a489f22019-04-09 15:11:12 +020023class StunRequestTest : public ::testing::Test, public sigslot::has_slots<> {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000024 public:
25 StunRequestTest()
26 : manager_(rtc::Thread::Current()),
Yves Gerey665174f2018-06-19 15:03:05 +020027 request_count_(0),
28 response_(NULL),
29 success_(false),
30 failure_(false),
31 timeout_(false) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000032 manager_.SignalSendPacket.connect(this, &StunRequestTest::OnSendPacket);
33 }
34
35 void OnSendPacket(const void* data, size_t size, StunRequest* req) {
36 request_count_++;
37 }
38
39 void OnResponse(StunMessage* res) {
40 response_ = res;
41 success_ = true;
42 }
43 void OnErrorResponse(StunMessage* res) {
44 response_ = res;
45 failure_ = true;
46 }
Yves Gerey665174f2018-06-19 15:03:05 +020047 void OnTimeout() { timeout_ = true; }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000048
49 protected:
50 static StunMessage* CreateStunMessage(StunMessageType type,
51 StunMessage* req) {
52 StunMessage* msg = new StunMessage();
53 msg->SetType(type);
54 if (req) {
55 msg->SetTransactionID(req->transaction_id());
56 }
57 return msg;
58 }
59 static int TotalDelay(int sends) {
pthatcher94a2f212017-02-08 14:42:22 -080060 std::vector<int> delays = {0, 250, 750, 1750, 3750,
61 7750, 15750, 23750, 31750, 39750};
62 return delays[sends];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000063 }
64
65 StunRequestManager manager_;
66 int request_count_;
67 StunMessage* response_;
68 bool success_;
69 bool failure_;
70 bool timeout_;
71};
72
73// Forwards results to the test class.
74class StunRequestThunker : public StunRequest {
75 public:
76 StunRequestThunker(StunMessage* msg, StunRequestTest* test)
77 : StunRequest(msg), test_(test) {}
78 explicit StunRequestThunker(StunRequestTest* test) : test_(test) {}
Yves Gerey665174f2018-06-19 15:03:05 +020079
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000080 private:
Yves Gerey665174f2018-06-19 15:03:05 +020081 virtual void OnResponse(StunMessage* res) { test_->OnResponse(res); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000082 virtual void OnErrorResponse(StunMessage* res) {
83 test_->OnErrorResponse(res);
84 }
Yves Gerey665174f2018-06-19 15:03:05 +020085 virtual void OnTimeout() { test_->OnTimeout(); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000086
87 virtual void Prepare(StunMessage* request) {
88 request->SetType(STUN_BINDING_REQUEST);
89 }
90
91 StunRequestTest* test_;
92};
93
94// Test handling of a normal binding response.
95TEST_F(StunRequestTest, TestSuccess) {
96 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
97
98 manager_.Send(new StunRequestThunker(req, this));
99 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req);
100 EXPECT_TRUE(manager_.CheckResponse(res));
101
102 EXPECT_TRUE(response_ == res);
103 EXPECT_TRUE(success_);
104 EXPECT_FALSE(failure_);
105 EXPECT_FALSE(timeout_);
106 delete res;
107}
108
109// Test handling of an error binding response.
110TEST_F(StunRequestTest, TestError) {
111 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
112
113 manager_.Send(new StunRequestThunker(req, this));
114 StunMessage* res = CreateStunMessage(STUN_BINDING_ERROR_RESPONSE, req);
115 EXPECT_TRUE(manager_.CheckResponse(res));
116
117 EXPECT_TRUE(response_ == res);
118 EXPECT_FALSE(success_);
119 EXPECT_TRUE(failure_);
120 EXPECT_FALSE(timeout_);
121 delete res;
122}
123
124// Test handling of a binding response with the wrong transaction id.
125TEST_F(StunRequestTest, TestUnexpected) {
126 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
127
128 manager_.Send(new StunRequestThunker(req, this));
129 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, NULL);
130 EXPECT_FALSE(manager_.CheckResponse(res));
131
132 EXPECT_TRUE(response_ == NULL);
133 EXPECT_FALSE(success_);
134 EXPECT_FALSE(failure_);
135 EXPECT_FALSE(timeout_);
136 delete res;
137}
138
pthatcher94a2f212017-02-08 14:42:22 -0800139// Test that requests are sent at the right times.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000140TEST_F(StunRequestTest, TestBackoff) {
skvladb9d8d102016-09-06 17:17:17 -0700141 rtc::ScopedFakeClock fake_clock;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000142 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
143
nisse1bffc1d2016-05-02 08:18:55 -0700144 int64_t start = rtc::TimeMillis();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000145 manager_.Send(new StunRequestThunker(req, this));
146 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req);
147 for (int i = 0; i < 9; ++i) {
pthatcher94a2f212017-02-08 14:42:22 -0800148 EXPECT_TRUE_SIMULATED_WAIT(request_count_ != i, STUN_TOTAL_TIMEOUT,
149 fake_clock);
nisse1bffc1d2016-05-02 08:18:55 -0700150 int64_t elapsed = rtc::TimeMillis() - start;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100151 RTC_LOG(LS_INFO) << "STUN request #" << (i + 1) << " sent at " << elapsed
152 << " ms";
skvladb9d8d102016-09-06 17:17:17 -0700153 EXPECT_EQ(TotalDelay(i), elapsed);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000154 }
155 EXPECT_TRUE(manager_.CheckResponse(res));
156
157 EXPECT_TRUE(response_ == res);
158 EXPECT_TRUE(success_);
159 EXPECT_FALSE(failure_);
160 EXPECT_FALSE(timeout_);
161 delete res;
162}
163
pthatcher94a2f212017-02-08 14:42:22 -0800164// Test that we timeout properly if no response is received.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000165TEST_F(StunRequestTest, TestTimeout) {
skvladb9d8d102016-09-06 17:17:17 -0700166 rtc::ScopedFakeClock fake_clock;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000167 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
168 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req);
169
170 manager_.Send(new StunRequestThunker(req, this));
pthatcher94a2f212017-02-08 14:42:22 -0800171 SIMULATED_WAIT(false, cricket::STUN_TOTAL_TIMEOUT, fake_clock);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000172
skvladb9d8d102016-09-06 17:17:17 -0700173 EXPECT_FALSE(manager_.CheckResponse(res));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000174 EXPECT_TRUE(response_ == NULL);
175 EXPECT_FALSE(success_);
176 EXPECT_FALSE(failure_);
177 EXPECT_TRUE(timeout_);
178 delete res;
179}
180
181// Regression test for specific crash where we receive a response with the
182// same id as a request that doesn't have an underlying StunMessage yet.
183TEST_F(StunRequestTest, TestNoEmptyRequest) {
184 StunRequestThunker* request = new StunRequestThunker(this);
185
186 manager_.SendDelayed(request, 100);
187
188 StunMessage dummy_req;
189 dummy_req.SetTransactionID(request->id());
190 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, &dummy_req);
191
192 EXPECT_TRUE(manager_.CheckResponse(res));
193
194 EXPECT_TRUE(response_ == res);
195 EXPECT_TRUE(success_);
196 EXPECT_FALSE(failure_);
197 EXPECT_FALSE(timeout_);
198 delete res;
199}
Steve Anton6c38cc72017-11-29 10:25:58 -0800200
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700201// If the response contains an attribute in the "comprehension required" range
202// which is not recognized, the transaction should be considered a failure and
203// the response should be ignored.
204TEST_F(StunRequestTest, TestUnrecognizedComprehensionRequiredAttribute) {
205 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
206
207 manager_.Send(new StunRequestThunker(req, this));
208 StunMessage* res = CreateStunMessage(STUN_BINDING_ERROR_RESPONSE, req);
209 res->AddAttribute(StunAttribute::CreateUInt32(0x7777));
210 EXPECT_FALSE(manager_.CheckResponse(res));
211
212 EXPECT_EQ(nullptr, response_);
213 EXPECT_FALSE(success_);
214 EXPECT_FALSE(failure_);
215 EXPECT_FALSE(timeout_);
216 delete res;
217}
218
Steve Anton6c38cc72017-11-29 10:25:58 -0800219} // namespace cricket