blob: 0b109b154484865e523d1ecfd81e9a3d0c7851d8 [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "p2p/base/stunrequest.h"
12#include "rtc_base/fakeclock.h"
13#include "rtc_base/gunit.h"
14#include "rtc_base/helpers.h"
15#include "rtc_base/logging.h"
16#include "rtc_base/ssladapter.h"
17#include "rtc_base/timeutils.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000018
19using namespace cricket;
20
21class StunRequestTest : public testing::Test,
22 public sigslot::has_slots<> {
23 public:
24 StunRequestTest()
25 : manager_(rtc::Thread::Current()),
26 request_count_(0), response_(NULL),
27 success_(false), failure_(false), timeout_(false) {
28 manager_.SignalSendPacket.connect(this, &StunRequestTest::OnSendPacket);
29 }
30
31 void OnSendPacket(const void* data, size_t size, StunRequest* req) {
32 request_count_++;
33 }
34
35 void OnResponse(StunMessage* res) {
36 response_ = res;
37 success_ = true;
38 }
39 void OnErrorResponse(StunMessage* res) {
40 response_ = res;
41 failure_ = true;
42 }
43 void OnTimeout() {
44 timeout_ = true;
45 }
46
47 protected:
48 static StunMessage* CreateStunMessage(StunMessageType type,
49 StunMessage* req) {
50 StunMessage* msg = new StunMessage();
51 msg->SetType(type);
52 if (req) {
53 msg->SetTransactionID(req->transaction_id());
54 }
55 return msg;
56 }
57 static int TotalDelay(int sends) {
pthatcher94a2f212017-02-08 14:42:22 -080058 std::vector<int> delays = {0, 250, 750, 1750, 3750,
59 7750, 15750, 23750, 31750, 39750};
60 return delays[sends];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000061 }
62
63 StunRequestManager manager_;
64 int request_count_;
65 StunMessage* response_;
66 bool success_;
67 bool failure_;
68 bool timeout_;
69};
70
71// Forwards results to the test class.
72class StunRequestThunker : public StunRequest {
73 public:
74 StunRequestThunker(StunMessage* msg, StunRequestTest* test)
75 : StunRequest(msg), test_(test) {}
76 explicit StunRequestThunker(StunRequestTest* test) : test_(test) {}
77 private:
78 virtual void OnResponse(StunMessage* res) {
79 test_->OnResponse(res);
80 }
81 virtual void OnErrorResponse(StunMessage* res) {
82 test_->OnErrorResponse(res);
83 }
84 virtual void OnTimeout() {
85 test_->OnTimeout();
86 }
87
88 virtual void Prepare(StunMessage* request) {
89 request->SetType(STUN_BINDING_REQUEST);
90 }
91
92 StunRequestTest* test_;
93};
94
95// Test handling of a normal binding response.
96TEST_F(StunRequestTest, TestSuccess) {
97 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
98
99 manager_.Send(new StunRequestThunker(req, this));
100 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req);
101 EXPECT_TRUE(manager_.CheckResponse(res));
102
103 EXPECT_TRUE(response_ == res);
104 EXPECT_TRUE(success_);
105 EXPECT_FALSE(failure_);
106 EXPECT_FALSE(timeout_);
107 delete res;
108}
109
110// Test handling of an error binding response.
111TEST_F(StunRequestTest, TestError) {
112 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
113
114 manager_.Send(new StunRequestThunker(req, this));
115 StunMessage* res = CreateStunMessage(STUN_BINDING_ERROR_RESPONSE, req);
116 EXPECT_TRUE(manager_.CheckResponse(res));
117
118 EXPECT_TRUE(response_ == res);
119 EXPECT_FALSE(success_);
120 EXPECT_TRUE(failure_);
121 EXPECT_FALSE(timeout_);
122 delete res;
123}
124
125// Test handling of a binding response with the wrong transaction id.
126TEST_F(StunRequestTest, TestUnexpected) {
127 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
128
129 manager_.Send(new StunRequestThunker(req, this));
130 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, NULL);
131 EXPECT_FALSE(manager_.CheckResponse(res));
132
133 EXPECT_TRUE(response_ == NULL);
134 EXPECT_FALSE(success_);
135 EXPECT_FALSE(failure_);
136 EXPECT_FALSE(timeout_);
137 delete res;
138}
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;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000143 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
144
nisse1bffc1d2016-05-02 08:18:55 -0700145 int64_t start = rtc::TimeMillis();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000146 manager_.Send(new StunRequestThunker(req, this));
147 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req);
148 for (int i = 0; i < 9; ++i) {
pthatcher94a2f212017-02-08 14:42:22 -0800149 EXPECT_TRUE_SIMULATED_WAIT(request_count_ != i, STUN_TOTAL_TIMEOUT,
150 fake_clock);
nisse1bffc1d2016-05-02 08:18:55 -0700151 int64_t elapsed = rtc::TimeMillis() - start;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000152 LOG(LS_INFO) << "STUN request #" << (i + 1)
153 << " sent at " << elapsed << " ms";
skvladb9d8d102016-09-06 17:17:17 -0700154 EXPECT_EQ(TotalDelay(i), elapsed);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000155 }
156 EXPECT_TRUE(manager_.CheckResponse(res));
157
158 EXPECT_TRUE(response_ == res);
159 EXPECT_TRUE(success_);
160 EXPECT_FALSE(failure_);
161 EXPECT_FALSE(timeout_);
162 delete res;
163}
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;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000168 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
169 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req);
170
171 manager_.Send(new StunRequestThunker(req, this));
pthatcher94a2f212017-02-08 14:42:22 -0800172 SIMULATED_WAIT(false, cricket::STUN_TOTAL_TIMEOUT, fake_clock);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000173
skvladb9d8d102016-09-06 17:17:17 -0700174 EXPECT_FALSE(manager_.CheckResponse(res));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000175 EXPECT_TRUE(response_ == NULL);
176 EXPECT_FALSE(success_);
177 EXPECT_FALSE(failure_);
178 EXPECT_TRUE(timeout_);
179 delete res;
180}
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) {
185 StunRequestThunker* request = new StunRequestThunker(this);
186
187 manager_.SendDelayed(request, 100);
188
189 StunMessage dummy_req;
190 dummy_req.SetTransactionID(request->id());
191 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, &dummy_req);
192
193 EXPECT_TRUE(manager_.CheckResponse(res));
194
195 EXPECT_TRUE(response_ == res);
196 EXPECT_TRUE(success_);
197 EXPECT_FALSE(failure_);
198 EXPECT_FALSE(timeout_);
199 delete res;
200}