blob: 6831d9ffa24534486c0dfd70e23874a60812d2ff [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, StunRequestTest* test)
Tommi159f3132022-06-03 14:37:31 +020081 : StunRequest(manager, CreateStunMessage(STUN_BINDING_REQUEST)),
82 test_(test) {}
Tommi86aa03e2022-04-12 09:17:57 +020083
84 std::unique_ptr<StunMessage> CreateResponseMessage(StunMessageType type) {
85 return CreateStunMessage(type, msg());
86 }
Yves Gerey665174f2018-06-19 15:03:05 +020087
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000088 private:
Yves Gerey665174f2018-06-19 15:03:05 +020089 virtual void OnResponse(StunMessage* res) { test_->OnResponse(res); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000090 virtual void OnErrorResponse(StunMessage* res) {
91 test_->OnErrorResponse(res);
92 }
Yves Gerey665174f2018-06-19 15:03:05 +020093 virtual void OnTimeout() { test_->OnTimeout(); }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000094
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000095 StunRequestTest* test_;
96};
97
98// Test handling of a normal binding response.
99TEST_F(StunRequestTest, TestSuccess) {
Tommi159f3132022-06-03 14:37:31 +0200100 auto* request = new StunRequestThunker(manager_, this);
Tommi86aa03e2022-04-12 09:17:57 +0200101 std::unique_ptr<StunMessage> res =
102 request->CreateResponseMessage(STUN_BINDING_RESPONSE);
103 manager_.Send(request);
104 EXPECT_TRUE(manager_.CheckResponse(res.get()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000105
Tommi86aa03e2022-04-12 09:17:57 +0200106 EXPECT_TRUE(response_ == res.get());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000107 EXPECT_TRUE(success_);
108 EXPECT_FALSE(failure_);
109 EXPECT_FALSE(timeout_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000110}
111
112// Test handling of an error binding response.
113TEST_F(StunRequestTest, TestError) {
Tommi159f3132022-06-03 14:37:31 +0200114 auto* request = new StunRequestThunker(manager_, this);
Tommi86aa03e2022-04-12 09:17:57 +0200115 std::unique_ptr<StunMessage> res =
116 request->CreateResponseMessage(STUN_BINDING_ERROR_RESPONSE);
117 manager_.Send(request);
118 EXPECT_TRUE(manager_.CheckResponse(res.get()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000119
Tommi86aa03e2022-04-12 09:17:57 +0200120 EXPECT_TRUE(response_ == res.get());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000121 EXPECT_FALSE(success_);
122 EXPECT_TRUE(failure_);
123 EXPECT_FALSE(timeout_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000124}
125
126// Test handling of a binding response with the wrong transaction id.
127TEST_F(StunRequestTest, TestUnexpected) {
Tommi159f3132022-06-03 14:37:31 +0200128 auto* request = new StunRequestThunker(manager_, this);
Tommi86aa03e2022-04-12 09:17:57 +0200129 std::unique_ptr<StunMessage> res = CreateStunMessage(STUN_BINDING_RESPONSE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000130
Tommi86aa03e2022-04-12 09:17:57 +0200131 manager_.Send(request);
132 EXPECT_FALSE(manager_.CheckResponse(res.get()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000133
134 EXPECT_TRUE(response_ == NULL);
135 EXPECT_FALSE(success_);
136 EXPECT_FALSE(failure_);
137 EXPECT_FALSE(timeout_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000138}
139
pthatcher94a2f212017-02-08 14:42:22 -0800140// Test that requests are sent at the right times.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000141TEST_F(StunRequestTest, TestBackoff) {
skvladb9d8d102016-09-06 17:17:17 -0700142 rtc::ScopedFakeClock fake_clock;
Tommi159f3132022-06-03 14:37:31 +0200143 auto* request = new StunRequestThunker(manager_, this);
Tommi86aa03e2022-04-12 09:17:57 +0200144 std::unique_ptr<StunMessage> res =
145 request->CreateResponseMessage(STUN_BINDING_RESPONSE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000146
nisse1bffc1d2016-05-02 08:18:55 -0700147 int64_t start = rtc::TimeMillis();
Tommi86aa03e2022-04-12 09:17:57 +0200148 manager_.Send(request);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000149 for (int i = 0; i < 9; ++i) {
pthatcher94a2f212017-02-08 14:42:22 -0800150 EXPECT_TRUE_SIMULATED_WAIT(request_count_ != i, STUN_TOTAL_TIMEOUT,
151 fake_clock);
nisse1bffc1d2016-05-02 08:18:55 -0700152 int64_t elapsed = rtc::TimeMillis() - start;
Tommi86aa03e2022-04-12 09:17:57 +0200153 RTC_DLOG(LS_INFO) << "STUN request #" << (i + 1) << " sent at " << elapsed
154 << " ms";
skvladb9d8d102016-09-06 17:17:17 -0700155 EXPECT_EQ(TotalDelay(i), elapsed);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000156 }
Tommi86aa03e2022-04-12 09:17:57 +0200157 EXPECT_TRUE(manager_.CheckResponse(res.get()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000158
Tommi86aa03e2022-04-12 09:17:57 +0200159 EXPECT_TRUE(response_ == res.get());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000160 EXPECT_TRUE(success_);
161 EXPECT_FALSE(failure_);
162 EXPECT_FALSE(timeout_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000163}
164
pthatcher94a2f212017-02-08 14:42:22 -0800165// Test that we timeout properly if no response is received.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000166TEST_F(StunRequestTest, TestTimeout) {
skvladb9d8d102016-09-06 17:17:17 -0700167 rtc::ScopedFakeClock fake_clock;
Tommi159f3132022-06-03 14:37:31 +0200168 auto* request = new StunRequestThunker(manager_, this);
Tommi86aa03e2022-04-12 09:17:57 +0200169 std::unique_ptr<StunMessage> res =
170 request->CreateResponseMessage(STUN_BINDING_RESPONSE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000171
Tommi86aa03e2022-04-12 09:17:57 +0200172 manager_.Send(request);
pthatcher94a2f212017-02-08 14:42:22 -0800173 SIMULATED_WAIT(false, cricket::STUN_TOTAL_TIMEOUT, fake_clock);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000174
Tommi86aa03e2022-04-12 09:17:57 +0200175 EXPECT_FALSE(manager_.CheckResponse(res.get()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000176 EXPECT_TRUE(response_ == NULL);
177 EXPECT_FALSE(success_);
178 EXPECT_FALSE(failure_);
179 EXPECT_TRUE(timeout_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000180}
181
182// Regression test for specific crash where we receive a response with the
183// same id as a request that doesn't have an underlying StunMessage yet.
184TEST_F(StunRequestTest, TestNoEmptyRequest) {
Tommi86aa03e2022-04-12 09:17:57 +0200185 StunRequestThunker* request = new StunRequestThunker(manager_, this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000186
187 manager_.SendDelayed(request, 100);
188
Tommi408143d2022-06-01 15:29:31 +0200189 StunMessage dummy_req(0, request->id());
Tommi86aa03e2022-04-12 09:17:57 +0200190 std::unique_ptr<StunMessage> res =
191 CreateStunMessage(STUN_BINDING_RESPONSE, &dummy_req);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000192
Tommi86aa03e2022-04-12 09:17:57 +0200193 EXPECT_TRUE(manager_.CheckResponse(res.get()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000194
Tommi86aa03e2022-04-12 09:17:57 +0200195 EXPECT_TRUE(response_ == res.get());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000196 EXPECT_TRUE(success_);
197 EXPECT_FALSE(failure_);
198 EXPECT_FALSE(timeout_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000199}
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) {
Tommi159f3132022-06-03 14:37:31 +0200205 auto* request = new StunRequestThunker(manager_, this);
Tommi86aa03e2022-04-12 09:17:57 +0200206 std::unique_ptr<StunMessage> res =
207 request->CreateResponseMessage(STUN_BINDING_ERROR_RESPONSE);
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700208
Tommi86aa03e2022-04-12 09:17:57 +0200209 manager_.Send(request);
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700210 res->AddAttribute(StunAttribute::CreateUInt32(0x7777));
Tommi86aa03e2022-04-12 09:17:57 +0200211 EXPECT_FALSE(manager_.CheckResponse(res.get()));
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700212
213 EXPECT_EQ(nullptr, response_);
214 EXPECT_FALSE(success_);
215 EXPECT_FALSE(failure_);
216 EXPECT_FALSE(timeout_);
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700217}
218
Steve Anton6c38cc72017-11-29 10:25:58 -0800219} // namespace cricket