blob: 99847f8b7d537299ba36c64cbcad9216213e2dba [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"
Tommi408143d2022-06-01 15:29:31 +020018#include "rtc_base/helpers.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080020#include "rtc_base/time_utils.h"
Yves Gerey3e707812018-11-28 16:47:49 +010021#include "test/gtest.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000022
Steve Anton6c38cc72017-11-29 10:25:58 -080023namespace cricket {
Tommi86aa03e2022-04-12 09:17:57 +020024namespace {
25std::unique_ptr<StunMessage> CreateStunMessage(
26 StunMessageType type,
27 const StunMessage* req = nullptr) {
Tommi408143d2022-06-01 15:29:31 +020028 std::unique_ptr<StunMessage> msg = std::make_unique<StunMessage>(
29 type, req ? req->transaction_id() : StunMessage::GenerateTransactionId());
Tommi86aa03e2022-04-12 09:17:57 +020030 return msg;
31}
32
33int TotalDelay(int sends) {
34 std::vector<int> delays = {0, 250, 750, 1750, 3750,
35 7750, 15750, 23750, 31750, 39750};
36 return delays[sends];
37}
38} // namespace
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000039
Tommib44a7942022-04-28 12:31:47 +020040class StunRequestTest : public ::testing::Test {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000041 public:
42 StunRequestTest()
Tomas Gunnarssonf22dfdd2022-04-13 09:07:30 +000043 : manager_(rtc::Thread::Current(),
44 [this](const void* data, size_t size, StunRequest* request) {
45 OnSendPacket(data, size, request);
46 }),
Yves Gerey665174f2018-06-19 15:03:05 +020047 request_count_(0),
48 response_(NULL),
49 success_(false),
50 failure_(false),
Tomas Gunnarssonf22dfdd2022-04-13 09:07:30 +000051 timeout_(false) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000052
53 void OnSendPacket(const void* data, size_t size, StunRequest* req) {
54 request_count_++;
55 }
56
57 void OnResponse(StunMessage* res) {
58 response_ = res;
59 success_ = true;
60 }
61 void OnErrorResponse(StunMessage* res) {
62 response_ = res;
63 failure_ = true;
64 }
Yves Gerey665174f2018-06-19 15:03:05 +020065 void OnTimeout() { timeout_ = true; }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000066
67 protected:
Niels Möller83830f32022-05-20 09:12:57 +020068 rtc::AutoThread main_thread_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000069 StunRequestManager manager_;
70 int request_count_;
71 StunMessage* response_;
72 bool success_;
73 bool failure_;
74 bool timeout_;
75};
76
77// Forwards results to the test class.
78class StunRequestThunker : public StunRequest {
79 public:
Tommi86aa03e2022-04-12 09:17:57 +020080 StunRequestThunker(StunRequestManager& manager,
81 StunMessageType message_type,
82 StunRequestTest* test)
83 : StunRequest(manager, CreateStunMessage(message_type)), test_(test) {
84 Construct(); // Triggers a call to `Prepare()` which sets the type.
85 }
86 StunRequestThunker(StunRequestManager& manager, StunRequestTest* test)
87 : StunRequest(manager), test_(test) {
88 Construct(); // Triggers a call to `Prepare()` which sets the type.
89 }
90
91 std::unique_ptr<StunMessage> CreateResponseMessage(StunMessageType type) {
92 return CreateStunMessage(type, msg());
93 }
Yves Gerey665174f2018-06-19 15:03:05 +020094
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000095 private:
Yves Gerey665174f2018-06-19 15:03:05 +020096 virtual void OnResponse(StunMessage* res) { test_->OnResponse(res); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000097 virtual void OnErrorResponse(StunMessage* res) {
98 test_->OnErrorResponse(res);
99 }
Yves Gerey665174f2018-06-19 15:03:05 +0200100 virtual void OnTimeout() { test_->OnTimeout(); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000101
Tommi278b19d2022-04-12 14:03:40 +0200102 virtual void Prepare(StunMessage* message) {
103 message->SetType(STUN_BINDING_REQUEST);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000104 }
105
106 StunRequestTest* test_;
107};
108
109// Test handling of a normal binding response.
110TEST_F(StunRequestTest, TestSuccess) {
Tommi86aa03e2022-04-12 09:17:57 +0200111 auto* request = new StunRequestThunker(manager_, STUN_BINDING_REQUEST, this);
112 std::unique_ptr<StunMessage> res =
113 request->CreateResponseMessage(STUN_BINDING_RESPONSE);
114 manager_.Send(request);
115 EXPECT_TRUE(manager_.CheckResponse(res.get()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000116
Tommi86aa03e2022-04-12 09:17:57 +0200117 EXPECT_TRUE(response_ == res.get());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000118 EXPECT_TRUE(success_);
119 EXPECT_FALSE(failure_);
120 EXPECT_FALSE(timeout_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000121}
122
123// Test handling of an error binding response.
124TEST_F(StunRequestTest, TestError) {
Tommi86aa03e2022-04-12 09:17:57 +0200125 auto* request = new StunRequestThunker(manager_, STUN_BINDING_REQUEST, this);
126 std::unique_ptr<StunMessage> res =
127 request->CreateResponseMessage(STUN_BINDING_ERROR_RESPONSE);
128 manager_.Send(request);
129 EXPECT_TRUE(manager_.CheckResponse(res.get()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000130
Tommi86aa03e2022-04-12 09:17:57 +0200131 EXPECT_TRUE(response_ == res.get());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000132 EXPECT_FALSE(success_);
133 EXPECT_TRUE(failure_);
134 EXPECT_FALSE(timeout_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000135}
136
137// Test handling of a binding response with the wrong transaction id.
138TEST_F(StunRequestTest, TestUnexpected) {
Tommi86aa03e2022-04-12 09:17:57 +0200139 auto* request = new StunRequestThunker(manager_, STUN_BINDING_REQUEST, this);
140 std::unique_ptr<StunMessage> res = CreateStunMessage(STUN_BINDING_RESPONSE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000141
Tommi86aa03e2022-04-12 09:17:57 +0200142 manager_.Send(request);
143 EXPECT_FALSE(manager_.CheckResponse(res.get()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000144
145 EXPECT_TRUE(response_ == NULL);
146 EXPECT_FALSE(success_);
147 EXPECT_FALSE(failure_);
148 EXPECT_FALSE(timeout_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000149}
150
pthatcher94a2f212017-02-08 14:42:22 -0800151// Test that requests are sent at the right times.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000152TEST_F(StunRequestTest, TestBackoff) {
skvladb9d8d102016-09-06 17:17:17 -0700153 rtc::ScopedFakeClock fake_clock;
Tommi86aa03e2022-04-12 09:17:57 +0200154 auto* request = new StunRequestThunker(manager_, STUN_BINDING_REQUEST, this);
155 std::unique_ptr<StunMessage> res =
156 request->CreateResponseMessage(STUN_BINDING_RESPONSE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000157
nisse1bffc1d2016-05-02 08:18:55 -0700158 int64_t start = rtc::TimeMillis();
Tommi86aa03e2022-04-12 09:17:57 +0200159 manager_.Send(request);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000160 for (int i = 0; i < 9; ++i) {
pthatcher94a2f212017-02-08 14:42:22 -0800161 EXPECT_TRUE_SIMULATED_WAIT(request_count_ != i, STUN_TOTAL_TIMEOUT,
162 fake_clock);
nisse1bffc1d2016-05-02 08:18:55 -0700163 int64_t elapsed = rtc::TimeMillis() - start;
Tommi86aa03e2022-04-12 09:17:57 +0200164 RTC_DLOG(LS_INFO) << "STUN request #" << (i + 1) << " sent at " << elapsed
165 << " ms";
skvladb9d8d102016-09-06 17:17:17 -0700166 EXPECT_EQ(TotalDelay(i), elapsed);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000167 }
Tommi86aa03e2022-04-12 09:17:57 +0200168 EXPECT_TRUE(manager_.CheckResponse(res.get()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000169
Tommi86aa03e2022-04-12 09:17:57 +0200170 EXPECT_TRUE(response_ == res.get());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000171 EXPECT_TRUE(success_);
172 EXPECT_FALSE(failure_);
173 EXPECT_FALSE(timeout_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000174}
175
pthatcher94a2f212017-02-08 14:42:22 -0800176// Test that we timeout properly if no response is received.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000177TEST_F(StunRequestTest, TestTimeout) {
skvladb9d8d102016-09-06 17:17:17 -0700178 rtc::ScopedFakeClock fake_clock;
Tommi86aa03e2022-04-12 09:17:57 +0200179 auto* request = new StunRequestThunker(manager_, STUN_BINDING_REQUEST, this);
180 std::unique_ptr<StunMessage> res =
181 request->CreateResponseMessage(STUN_BINDING_RESPONSE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000182
Tommi86aa03e2022-04-12 09:17:57 +0200183 manager_.Send(request);
pthatcher94a2f212017-02-08 14:42:22 -0800184 SIMULATED_WAIT(false, cricket::STUN_TOTAL_TIMEOUT, fake_clock);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000185
Tommi86aa03e2022-04-12 09:17:57 +0200186 EXPECT_FALSE(manager_.CheckResponse(res.get()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000187 EXPECT_TRUE(response_ == NULL);
188 EXPECT_FALSE(success_);
189 EXPECT_FALSE(failure_);
190 EXPECT_TRUE(timeout_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000191}
192
193// Regression test for specific crash where we receive a response with the
194// same id as a request that doesn't have an underlying StunMessage yet.
195TEST_F(StunRequestTest, TestNoEmptyRequest) {
Tommi86aa03e2022-04-12 09:17:57 +0200196 StunRequestThunker* request = new StunRequestThunker(manager_, this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000197
198 manager_.SendDelayed(request, 100);
199
Tommi408143d2022-06-01 15:29:31 +0200200 StunMessage dummy_req(0, request->id());
Tommi86aa03e2022-04-12 09:17:57 +0200201 std::unique_ptr<StunMessage> res =
202 CreateStunMessage(STUN_BINDING_RESPONSE, &dummy_req);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000203
Tommi86aa03e2022-04-12 09:17:57 +0200204 EXPECT_TRUE(manager_.CheckResponse(res.get()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000205
Tommi86aa03e2022-04-12 09:17:57 +0200206 EXPECT_TRUE(response_ == res.get());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000207 EXPECT_TRUE(success_);
208 EXPECT_FALSE(failure_);
209 EXPECT_FALSE(timeout_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000210}
Steve Anton6c38cc72017-11-29 10:25:58 -0800211
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700212// If the response contains an attribute in the "comprehension required" range
213// which is not recognized, the transaction should be considered a failure and
214// the response should be ignored.
215TEST_F(StunRequestTest, TestUnrecognizedComprehensionRequiredAttribute) {
Tommi86aa03e2022-04-12 09:17:57 +0200216 auto* request = new StunRequestThunker(manager_, STUN_BINDING_REQUEST, this);
217 std::unique_ptr<StunMessage> res =
218 request->CreateResponseMessage(STUN_BINDING_ERROR_RESPONSE);
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700219
Tommi86aa03e2022-04-12 09:17:57 +0200220 manager_.Send(request);
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700221 res->AddAttribute(StunAttribute::CreateUInt32(0x7777));
Tommi86aa03e2022-04-12 09:17:57 +0200222 EXPECT_FALSE(manager_.CheckResponse(res.get()));
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700223
224 EXPECT_EQ(nullptr, response_);
225 EXPECT_FALSE(success_);
226 EXPECT_FALSE(failure_);
227 EXPECT_FALSE(timeout_);
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700228}
229
Steve Anton6c38cc72017-11-29 10:25:58 -0800230} // namespace cricket