blob: 226cc95f466af2924218f1907c6f96874ab9b687 [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
Tommi86aa03e2022-04-12 09:17:57 +020013#include <utility>
Steve Anton6c38cc72017-11-29 10:25:58 -080014#include <vector>
15
Steve Anton10542f22019-01-11 09:11:00 -080016#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "rtc_base/gunit.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "rtc_base/time_utils.h"
Yves Gerey3e707812018-11-28 16:47:49 +010020#include "test/gtest.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000021
Steve Anton6c38cc72017-11-29 10:25:58 -080022namespace cricket {
Tommi86aa03e2022-04-12 09:17:57 +020023namespace {
24std::unique_ptr<StunMessage> CreateStunMessage(
25 StunMessageType type,
26 const StunMessage* req = nullptr) {
27 std::unique_ptr<StunMessage> msg = std::make_unique<StunMessage>();
28 msg->SetType(type);
29 if (req) {
30 msg->SetTransactionID(req->transaction_id());
31 }
32 return msg;
33}
34
35int TotalDelay(int sends) {
36 std::vector<int> delays = {0, 250, 750, 1750, 3750,
37 7750, 15750, 23750, 31750, 39750};
38 return delays[sends];
39}
40} // namespace
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000041
Mirko Bonadei6a489f22019-04-09 15:11:12 +020042class StunRequestTest : public ::testing::Test, public sigslot::has_slots<> {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000043 public:
44 StunRequestTest()
Tomas Gunnarssonf22dfdd2022-04-13 09:07:30 +000045 : manager_(rtc::Thread::Current(),
46 [this](const void* data, size_t size, StunRequest* request) {
47 OnSendPacket(data, size, request);
48 }),
Yves Gerey665174f2018-06-19 15:03:05 +020049 request_count_(0),
50 response_(NULL),
51 success_(false),
52 failure_(false),
Tomas Gunnarssonf22dfdd2022-04-13 09:07:30 +000053 timeout_(false) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000054
55 void OnSendPacket(const void* data, size_t size, StunRequest* req) {
56 request_count_++;
57 }
58
59 void OnResponse(StunMessage* res) {
60 response_ = res;
61 success_ = true;
62 }
63 void OnErrorResponse(StunMessage* res) {
64 response_ = res;
65 failure_ = true;
66 }
Yves Gerey665174f2018-06-19 15:03:05 +020067 void OnTimeout() { timeout_ = true; }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000068
69 protected:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000070 StunRequestManager manager_;
71 int request_count_;
72 StunMessage* response_;
73 bool success_;
74 bool failure_;
75 bool timeout_;
76};
77
78// Forwards results to the test class.
79class StunRequestThunker : public StunRequest {
80 public:
Tommi86aa03e2022-04-12 09:17:57 +020081 StunRequestThunker(StunRequestManager& manager,
82 StunMessageType message_type,
83 StunRequestTest* test)
84 : StunRequest(manager, CreateStunMessage(message_type)), test_(test) {
85 Construct(); // Triggers a call to `Prepare()` which sets the type.
86 }
87 StunRequestThunker(StunRequestManager& manager, StunRequestTest* test)
88 : StunRequest(manager), test_(test) {
89 Construct(); // Triggers a call to `Prepare()` which sets the type.
90 }
91
92 std::unique_ptr<StunMessage> CreateResponseMessage(StunMessageType type) {
93 return CreateStunMessage(type, msg());
94 }
Yves Gerey665174f2018-06-19 15:03:05 +020095
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000096 private:
Yves Gerey665174f2018-06-19 15:03:05 +020097 virtual void OnResponse(StunMessage* res) { test_->OnResponse(res); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000098 virtual void OnErrorResponse(StunMessage* res) {
99 test_->OnErrorResponse(res);
100 }
Yves Gerey665174f2018-06-19 15:03:05 +0200101 virtual void OnTimeout() { test_->OnTimeout(); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000102
Tommi278b19d2022-04-12 14:03:40 +0200103 virtual void Prepare(StunMessage* message) {
104 message->SetType(STUN_BINDING_REQUEST);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000105 }
106
107 StunRequestTest* test_;
108};
109
110// Test handling of a normal binding response.
111TEST_F(StunRequestTest, TestSuccess) {
Tommi86aa03e2022-04-12 09:17:57 +0200112 auto* request = new StunRequestThunker(manager_, STUN_BINDING_REQUEST, this);
113 std::unique_ptr<StunMessage> res =
114 request->CreateResponseMessage(STUN_BINDING_RESPONSE);
115 manager_.Send(request);
116 EXPECT_TRUE(manager_.CheckResponse(res.get()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000117
Tommi86aa03e2022-04-12 09:17:57 +0200118 EXPECT_TRUE(response_ == res.get());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000119 EXPECT_TRUE(success_);
120 EXPECT_FALSE(failure_);
121 EXPECT_FALSE(timeout_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000122}
123
124// Test handling of an error binding response.
125TEST_F(StunRequestTest, TestError) {
Tommi86aa03e2022-04-12 09:17:57 +0200126 auto* request = new StunRequestThunker(manager_, STUN_BINDING_REQUEST, this);
127 std::unique_ptr<StunMessage> res =
128 request->CreateResponseMessage(STUN_BINDING_ERROR_RESPONSE);
129 manager_.Send(request);
130 EXPECT_TRUE(manager_.CheckResponse(res.get()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000131
Tommi86aa03e2022-04-12 09:17:57 +0200132 EXPECT_TRUE(response_ == res.get());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000133 EXPECT_FALSE(success_);
134 EXPECT_TRUE(failure_);
135 EXPECT_FALSE(timeout_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000136}
137
138// Test handling of a binding response with the wrong transaction id.
139TEST_F(StunRequestTest, TestUnexpected) {
Tommi86aa03e2022-04-12 09:17:57 +0200140 auto* request = new StunRequestThunker(manager_, STUN_BINDING_REQUEST, this);
141 std::unique_ptr<StunMessage> res = CreateStunMessage(STUN_BINDING_RESPONSE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000142
Tommi86aa03e2022-04-12 09:17:57 +0200143 manager_.Send(request);
144 EXPECT_FALSE(manager_.CheckResponse(res.get()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000145
146 EXPECT_TRUE(response_ == NULL);
147 EXPECT_FALSE(success_);
148 EXPECT_FALSE(failure_);
149 EXPECT_FALSE(timeout_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000150}
151
pthatcher94a2f212017-02-08 14:42:22 -0800152// Test that requests are sent at the right times.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000153TEST_F(StunRequestTest, TestBackoff) {
skvladb9d8d102016-09-06 17:17:17 -0700154 rtc::ScopedFakeClock fake_clock;
Tommi86aa03e2022-04-12 09:17:57 +0200155 auto* request = new StunRequestThunker(manager_, STUN_BINDING_REQUEST, this);
156 std::unique_ptr<StunMessage> res =
157 request->CreateResponseMessage(STUN_BINDING_RESPONSE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000158
nisse1bffc1d2016-05-02 08:18:55 -0700159 int64_t start = rtc::TimeMillis();
Tommi86aa03e2022-04-12 09:17:57 +0200160 manager_.Send(request);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000161 for (int i = 0; i < 9; ++i) {
pthatcher94a2f212017-02-08 14:42:22 -0800162 EXPECT_TRUE_SIMULATED_WAIT(request_count_ != i, STUN_TOTAL_TIMEOUT,
163 fake_clock);
nisse1bffc1d2016-05-02 08:18:55 -0700164 int64_t elapsed = rtc::TimeMillis() - start;
Tommi86aa03e2022-04-12 09:17:57 +0200165 RTC_DLOG(LS_INFO) << "STUN request #" << (i + 1) << " sent at " << elapsed
166 << " ms";
skvladb9d8d102016-09-06 17:17:17 -0700167 EXPECT_EQ(TotalDelay(i), elapsed);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000168 }
Tommi86aa03e2022-04-12 09:17:57 +0200169 EXPECT_TRUE(manager_.CheckResponse(res.get()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000170
Tommi86aa03e2022-04-12 09:17:57 +0200171 EXPECT_TRUE(response_ == res.get());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000172 EXPECT_TRUE(success_);
173 EXPECT_FALSE(failure_);
174 EXPECT_FALSE(timeout_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000175}
176
pthatcher94a2f212017-02-08 14:42:22 -0800177// Test that we timeout properly if no response is received.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000178TEST_F(StunRequestTest, TestTimeout) {
skvladb9d8d102016-09-06 17:17:17 -0700179 rtc::ScopedFakeClock fake_clock;
Tommi86aa03e2022-04-12 09:17:57 +0200180 auto* request = new StunRequestThunker(manager_, STUN_BINDING_REQUEST, this);
181 std::unique_ptr<StunMessage> res =
182 request->CreateResponseMessage(STUN_BINDING_RESPONSE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000183
Tommi86aa03e2022-04-12 09:17:57 +0200184 manager_.Send(request);
pthatcher94a2f212017-02-08 14:42:22 -0800185 SIMULATED_WAIT(false, cricket::STUN_TOTAL_TIMEOUT, fake_clock);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000186
Tommi86aa03e2022-04-12 09:17:57 +0200187 EXPECT_FALSE(manager_.CheckResponse(res.get()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000188 EXPECT_TRUE(response_ == NULL);
189 EXPECT_FALSE(success_);
190 EXPECT_FALSE(failure_);
191 EXPECT_TRUE(timeout_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000192}
193
194// Regression test for specific crash where we receive a response with the
195// same id as a request that doesn't have an underlying StunMessage yet.
196TEST_F(StunRequestTest, TestNoEmptyRequest) {
Tommi86aa03e2022-04-12 09:17:57 +0200197 StunRequestThunker* request = new StunRequestThunker(manager_, this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000198
199 manager_.SendDelayed(request, 100);
200
201 StunMessage dummy_req;
202 dummy_req.SetTransactionID(request->id());
Tommi86aa03e2022-04-12 09:17:57 +0200203 std::unique_ptr<StunMessage> res =
204 CreateStunMessage(STUN_BINDING_RESPONSE, &dummy_req);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000205
Tommi86aa03e2022-04-12 09:17:57 +0200206 EXPECT_TRUE(manager_.CheckResponse(res.get()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000207
Tommi86aa03e2022-04-12 09:17:57 +0200208 EXPECT_TRUE(response_ == res.get());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000209 EXPECT_TRUE(success_);
210 EXPECT_FALSE(failure_);
211 EXPECT_FALSE(timeout_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000212}
Steve Anton6c38cc72017-11-29 10:25:58 -0800213
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700214// If the response contains an attribute in the "comprehension required" range
215// which is not recognized, the transaction should be considered a failure and
216// the response should be ignored.
217TEST_F(StunRequestTest, TestUnrecognizedComprehensionRequiredAttribute) {
Tommi86aa03e2022-04-12 09:17:57 +0200218 auto* request = new StunRequestThunker(manager_, STUN_BINDING_REQUEST, this);
219 std::unique_ptr<StunMessage> res =
220 request->CreateResponseMessage(STUN_BINDING_ERROR_RESPONSE);
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700221
Tommi86aa03e2022-04-12 09:17:57 +0200222 manager_.Send(request);
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700223 res->AddAttribute(StunAttribute::CreateUInt32(0x7777));
Tommi86aa03e2022-04-12 09:17:57 +0200224 EXPECT_FALSE(manager_.CheckResponse(res.get()));
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700225
226 EXPECT_EQ(nullptr, response_);
227 EXPECT_FALSE(success_);
228 EXPECT_FALSE(failure_);
229 EXPECT_FALSE(timeout_);
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700230}
231
Steve Anton6c38cc72017-11-29 10:25:58 -0800232} // namespace cricket