xref: /aosp_15_r20/external/webrtc/p2p/base/stun_request_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "p2p/base/stun_request.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <utility>
14*d9f75844SAndroid Build Coastguard Worker #include <vector>
15*d9f75844SAndroid Build Coastguard Worker 
16*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/fake_clock.h"
17*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/gunit.h"
18*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/helpers.h"
19*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
20*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/time_utils.h"
21*d9f75844SAndroid Build Coastguard Worker #include "test/gtest.h"
22*d9f75844SAndroid Build Coastguard Worker 
23*d9f75844SAndroid Build Coastguard Worker namespace cricket {
24*d9f75844SAndroid Build Coastguard Worker namespace {
CreateStunMessage(StunMessageType type,const StunMessage * req=nullptr)25*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<StunMessage> CreateStunMessage(
26*d9f75844SAndroid Build Coastguard Worker     StunMessageType type,
27*d9f75844SAndroid Build Coastguard Worker     const StunMessage* req = nullptr) {
28*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<StunMessage> msg = std::make_unique<StunMessage>(
29*d9f75844SAndroid Build Coastguard Worker       type, req ? req->transaction_id() : StunMessage::GenerateTransactionId());
30*d9f75844SAndroid Build Coastguard Worker   return msg;
31*d9f75844SAndroid Build Coastguard Worker }
32*d9f75844SAndroid Build Coastguard Worker 
TotalDelay(int sends)33*d9f75844SAndroid Build Coastguard Worker int TotalDelay(int sends) {
34*d9f75844SAndroid Build Coastguard Worker   std::vector<int> delays = {0,    250,   750,   1750,  3750,
35*d9f75844SAndroid Build Coastguard Worker                              7750, 15750, 23750, 31750, 39750};
36*d9f75844SAndroid Build Coastguard Worker   return delays[sends];
37*d9f75844SAndroid Build Coastguard Worker }
38*d9f75844SAndroid Build Coastguard Worker }  // namespace
39*d9f75844SAndroid Build Coastguard Worker 
40*d9f75844SAndroid Build Coastguard Worker class StunRequestTest : public ::testing::Test {
41*d9f75844SAndroid Build Coastguard Worker  public:
StunRequestTest()42*d9f75844SAndroid Build Coastguard Worker   StunRequestTest()
43*d9f75844SAndroid Build Coastguard Worker       : manager_(rtc::Thread::Current(),
44*d9f75844SAndroid Build Coastguard Worker                  [this](const void* data, size_t size, StunRequest* request) {
45*d9f75844SAndroid Build Coastguard Worker                    OnSendPacket(data, size, request);
46*d9f75844SAndroid Build Coastguard Worker                  }),
47*d9f75844SAndroid Build Coastguard Worker         request_count_(0),
48*d9f75844SAndroid Build Coastguard Worker         response_(NULL),
49*d9f75844SAndroid Build Coastguard Worker         success_(false),
50*d9f75844SAndroid Build Coastguard Worker         failure_(false),
51*d9f75844SAndroid Build Coastguard Worker         timeout_(false) {}
52*d9f75844SAndroid Build Coastguard Worker 
OnSendPacket(const void * data,size_t size,StunRequest * req)53*d9f75844SAndroid Build Coastguard Worker   void OnSendPacket(const void* data, size_t size, StunRequest* req) {
54*d9f75844SAndroid Build Coastguard Worker     request_count_++;
55*d9f75844SAndroid Build Coastguard Worker   }
56*d9f75844SAndroid Build Coastguard Worker 
OnResponse(StunMessage * res)57*d9f75844SAndroid Build Coastguard Worker   void OnResponse(StunMessage* res) {
58*d9f75844SAndroid Build Coastguard Worker     response_ = res;
59*d9f75844SAndroid Build Coastguard Worker     success_ = true;
60*d9f75844SAndroid Build Coastguard Worker   }
OnErrorResponse(StunMessage * res)61*d9f75844SAndroid Build Coastguard Worker   void OnErrorResponse(StunMessage* res) {
62*d9f75844SAndroid Build Coastguard Worker     response_ = res;
63*d9f75844SAndroid Build Coastguard Worker     failure_ = true;
64*d9f75844SAndroid Build Coastguard Worker   }
OnTimeout()65*d9f75844SAndroid Build Coastguard Worker   void OnTimeout() { timeout_ = true; }
66*d9f75844SAndroid Build Coastguard Worker 
67*d9f75844SAndroid Build Coastguard Worker  protected:
68*d9f75844SAndroid Build Coastguard Worker   rtc::AutoThread main_thread_;
69*d9f75844SAndroid Build Coastguard Worker   StunRequestManager manager_;
70*d9f75844SAndroid Build Coastguard Worker   int request_count_;
71*d9f75844SAndroid Build Coastguard Worker   StunMessage* response_;
72*d9f75844SAndroid Build Coastguard Worker   bool success_;
73*d9f75844SAndroid Build Coastguard Worker   bool failure_;
74*d9f75844SAndroid Build Coastguard Worker   bool timeout_;
75*d9f75844SAndroid Build Coastguard Worker };
76*d9f75844SAndroid Build Coastguard Worker 
77*d9f75844SAndroid Build Coastguard Worker // Forwards results to the test class.
78*d9f75844SAndroid Build Coastguard Worker class StunRequestThunker : public StunRequest {
79*d9f75844SAndroid Build Coastguard Worker  public:
StunRequestThunker(StunRequestManager & manager,StunRequestTest * test)80*d9f75844SAndroid Build Coastguard Worker   StunRequestThunker(StunRequestManager& manager, StunRequestTest* test)
81*d9f75844SAndroid Build Coastguard Worker       : StunRequest(manager, CreateStunMessage(STUN_BINDING_REQUEST)),
82*d9f75844SAndroid Build Coastguard Worker         test_(test) {}
83*d9f75844SAndroid Build Coastguard Worker 
CreateResponseMessage(StunMessageType type)84*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<StunMessage> CreateResponseMessage(StunMessageType type) {
85*d9f75844SAndroid Build Coastguard Worker     return CreateStunMessage(type, msg());
86*d9f75844SAndroid Build Coastguard Worker   }
87*d9f75844SAndroid Build Coastguard Worker 
88*d9f75844SAndroid Build Coastguard Worker  private:
OnResponse(StunMessage * res)89*d9f75844SAndroid Build Coastguard Worker   virtual void OnResponse(StunMessage* res) { test_->OnResponse(res); }
OnErrorResponse(StunMessage * res)90*d9f75844SAndroid Build Coastguard Worker   virtual void OnErrorResponse(StunMessage* res) {
91*d9f75844SAndroid Build Coastguard Worker     test_->OnErrorResponse(res);
92*d9f75844SAndroid Build Coastguard Worker   }
OnTimeout()93*d9f75844SAndroid Build Coastguard Worker   virtual void OnTimeout() { test_->OnTimeout(); }
94*d9f75844SAndroid Build Coastguard Worker 
95*d9f75844SAndroid Build Coastguard Worker   StunRequestTest* test_;
96*d9f75844SAndroid Build Coastguard Worker };
97*d9f75844SAndroid Build Coastguard Worker 
98*d9f75844SAndroid Build Coastguard Worker // Test handling of a normal binding response.
TEST_F(StunRequestTest,TestSuccess)99*d9f75844SAndroid Build Coastguard Worker TEST_F(StunRequestTest, TestSuccess) {
100*d9f75844SAndroid Build Coastguard Worker   auto* request = new StunRequestThunker(manager_, this);
101*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<StunMessage> res =
102*d9f75844SAndroid Build Coastguard Worker       request->CreateResponseMessage(STUN_BINDING_RESPONSE);
103*d9f75844SAndroid Build Coastguard Worker   manager_.Send(request);
104*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(manager_.CheckResponse(res.get()));
105*d9f75844SAndroid Build Coastguard Worker 
106*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(response_ == res.get());
107*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(success_);
108*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(failure_);
109*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(timeout_);
110*d9f75844SAndroid Build Coastguard Worker }
111*d9f75844SAndroid Build Coastguard Worker 
112*d9f75844SAndroid Build Coastguard Worker // Test handling of an error binding response.
TEST_F(StunRequestTest,TestError)113*d9f75844SAndroid Build Coastguard Worker TEST_F(StunRequestTest, TestError) {
114*d9f75844SAndroid Build Coastguard Worker   auto* request = new StunRequestThunker(manager_, this);
115*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<StunMessage> res =
116*d9f75844SAndroid Build Coastguard Worker       request->CreateResponseMessage(STUN_BINDING_ERROR_RESPONSE);
117*d9f75844SAndroid Build Coastguard Worker   manager_.Send(request);
118*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(manager_.CheckResponse(res.get()));
119*d9f75844SAndroid Build Coastguard Worker 
120*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(response_ == res.get());
121*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(success_);
122*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(failure_);
123*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(timeout_);
124*d9f75844SAndroid Build Coastguard Worker }
125*d9f75844SAndroid Build Coastguard Worker 
126*d9f75844SAndroid Build Coastguard Worker // Test handling of a binding response with the wrong transaction id.
TEST_F(StunRequestTest,TestUnexpected)127*d9f75844SAndroid Build Coastguard Worker TEST_F(StunRequestTest, TestUnexpected) {
128*d9f75844SAndroid Build Coastguard Worker   auto* request = new StunRequestThunker(manager_, this);
129*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<StunMessage> res = CreateStunMessage(STUN_BINDING_RESPONSE);
130*d9f75844SAndroid Build Coastguard Worker 
131*d9f75844SAndroid Build Coastguard Worker   manager_.Send(request);
132*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(manager_.CheckResponse(res.get()));
133*d9f75844SAndroid Build Coastguard Worker 
134*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(response_ == NULL);
135*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(success_);
136*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(failure_);
137*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(timeout_);
138*d9f75844SAndroid Build Coastguard Worker }
139*d9f75844SAndroid Build Coastguard Worker 
140*d9f75844SAndroid Build Coastguard Worker // Test that requests are sent at the right times.
TEST_F(StunRequestTest,TestBackoff)141*d9f75844SAndroid Build Coastguard Worker TEST_F(StunRequestTest, TestBackoff) {
142*d9f75844SAndroid Build Coastguard Worker   rtc::ScopedFakeClock fake_clock;
143*d9f75844SAndroid Build Coastguard Worker   auto* request = new StunRequestThunker(manager_, this);
144*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<StunMessage> res =
145*d9f75844SAndroid Build Coastguard Worker       request->CreateResponseMessage(STUN_BINDING_RESPONSE);
146*d9f75844SAndroid Build Coastguard Worker 
147*d9f75844SAndroid Build Coastguard Worker   int64_t start = rtc::TimeMillis();
148*d9f75844SAndroid Build Coastguard Worker   manager_.Send(request);
149*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < 9; ++i) {
150*d9f75844SAndroid Build Coastguard Worker     EXPECT_TRUE_SIMULATED_WAIT(request_count_ != i, STUN_TOTAL_TIMEOUT,
151*d9f75844SAndroid Build Coastguard Worker                                fake_clock);
152*d9f75844SAndroid Build Coastguard Worker     int64_t elapsed = rtc::TimeMillis() - start;
153*d9f75844SAndroid Build Coastguard Worker     RTC_DLOG(LS_INFO) << "STUN request #" << (i + 1) << " sent at " << elapsed
154*d9f75844SAndroid Build Coastguard Worker                       << " ms";
155*d9f75844SAndroid Build Coastguard Worker     EXPECT_EQ(TotalDelay(i), elapsed);
156*d9f75844SAndroid Build Coastguard Worker   }
157*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(manager_.CheckResponse(res.get()));
158*d9f75844SAndroid Build Coastguard Worker 
159*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(response_ == res.get());
160*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(success_);
161*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(failure_);
162*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(timeout_);
163*d9f75844SAndroid Build Coastguard Worker }
164*d9f75844SAndroid Build Coastguard Worker 
165*d9f75844SAndroid Build Coastguard Worker // Test that we timeout properly if no response is received.
TEST_F(StunRequestTest,TestTimeout)166*d9f75844SAndroid Build Coastguard Worker TEST_F(StunRequestTest, TestTimeout) {
167*d9f75844SAndroid Build Coastguard Worker   rtc::ScopedFakeClock fake_clock;
168*d9f75844SAndroid Build Coastguard Worker   auto* request = new StunRequestThunker(manager_, this);
169*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<StunMessage> res =
170*d9f75844SAndroid Build Coastguard Worker       request->CreateResponseMessage(STUN_BINDING_RESPONSE);
171*d9f75844SAndroid Build Coastguard Worker 
172*d9f75844SAndroid Build Coastguard Worker   manager_.Send(request);
173*d9f75844SAndroid Build Coastguard Worker   SIMULATED_WAIT(false, cricket::STUN_TOTAL_TIMEOUT, fake_clock);
174*d9f75844SAndroid Build Coastguard Worker 
175*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(manager_.CheckResponse(res.get()));
176*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(response_ == NULL);
177*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(success_);
178*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(failure_);
179*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(timeout_);
180*d9f75844SAndroid Build Coastguard Worker }
181*d9f75844SAndroid Build Coastguard Worker 
182*d9f75844SAndroid Build Coastguard Worker // Regression test for specific crash where we receive a response with the
183*d9f75844SAndroid Build Coastguard Worker // same id as a request that doesn't have an underlying StunMessage yet.
TEST_F(StunRequestTest,TestNoEmptyRequest)184*d9f75844SAndroid Build Coastguard Worker TEST_F(StunRequestTest, TestNoEmptyRequest) {
185*d9f75844SAndroid Build Coastguard Worker   StunRequestThunker* request = new StunRequestThunker(manager_, this);
186*d9f75844SAndroid Build Coastguard Worker 
187*d9f75844SAndroid Build Coastguard Worker   manager_.SendDelayed(request, 100);
188*d9f75844SAndroid Build Coastguard Worker 
189*d9f75844SAndroid Build Coastguard Worker   StunMessage dummy_req(0, request->id());
190*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<StunMessage> res =
191*d9f75844SAndroid Build Coastguard Worker       CreateStunMessage(STUN_BINDING_RESPONSE, &dummy_req);
192*d9f75844SAndroid Build Coastguard Worker 
193*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(manager_.CheckResponse(res.get()));
194*d9f75844SAndroid Build Coastguard Worker 
195*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(response_ == res.get());
196*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(success_);
197*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(failure_);
198*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(timeout_);
199*d9f75844SAndroid Build Coastguard Worker }
200*d9f75844SAndroid Build Coastguard Worker 
201*d9f75844SAndroid Build Coastguard Worker // If the response contains an attribute in the "comprehension required" range
202*d9f75844SAndroid Build Coastguard Worker // which is not recognized, the transaction should be considered a failure and
203*d9f75844SAndroid Build Coastguard Worker // the response should be ignored.
TEST_F(StunRequestTest,TestUnrecognizedComprehensionRequiredAttribute)204*d9f75844SAndroid Build Coastguard Worker TEST_F(StunRequestTest, TestUnrecognizedComprehensionRequiredAttribute) {
205*d9f75844SAndroid Build Coastguard Worker   auto* request = new StunRequestThunker(manager_, this);
206*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<StunMessage> res =
207*d9f75844SAndroid Build Coastguard Worker       request->CreateResponseMessage(STUN_BINDING_ERROR_RESPONSE);
208*d9f75844SAndroid Build Coastguard Worker 
209*d9f75844SAndroid Build Coastguard Worker   manager_.Send(request);
210*d9f75844SAndroid Build Coastguard Worker   res->AddAttribute(StunAttribute::CreateUInt32(0x7777));
211*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(manager_.CheckResponse(res.get()));
212*d9f75844SAndroid Build Coastguard Worker 
213*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(nullptr, response_);
214*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(success_);
215*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(failure_);
216*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(timeout_);
217*d9f75844SAndroid Build Coastguard Worker }
218*d9f75844SAndroid Build Coastguard Worker 
219*d9f75844SAndroid Build Coastguard Worker }  // namespace cricket
220