blob: f777b85f85455933e7ccc6e53aa37a499876e295 [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
Steve Anton6c38cc72017-11-29 10:25:58 -080011#include <vector>
12
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "p2p/base/stunrequest.h"
14#include "rtc_base/fakeclock.h"
15#include "rtc_base/gunit.h"
16#include "rtc_base/helpers.h"
17#include "rtc_base/logging.h"
18#include "rtc_base/ssladapter.h"
19#include "rtc_base/timeutils.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000020
Steve Anton6c38cc72017-11-29 10:25:58 -080021namespace cricket {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000022
23class StunRequestTest : public testing::Test,
24 public sigslot::has_slots<> {
25 public:
26 StunRequestTest()
27 : manager_(rtc::Thread::Current()),
28 request_count_(0), response_(NULL),
29 success_(false), failure_(false), timeout_(false) {
30 manager_.SignalSendPacket.connect(this, &StunRequestTest::OnSendPacket);
31 }
32
33 void OnSendPacket(const void* data, size_t size, StunRequest* req) {
34 request_count_++;
35 }
36
37 void OnResponse(StunMessage* res) {
38 response_ = res;
39 success_ = true;
40 }
41 void OnErrorResponse(StunMessage* res) {
42 response_ = res;
43 failure_ = true;
44 }
45 void OnTimeout() {
46 timeout_ = true;
47 }
48
49 protected:
50 static StunMessage* CreateStunMessage(StunMessageType type,
51 StunMessage* req) {
52 StunMessage* msg = new StunMessage();
53 msg->SetType(type);
54 if (req) {
55 msg->SetTransactionID(req->transaction_id());
56 }
57 return msg;
58 }
59 static int TotalDelay(int sends) {
pthatcher94a2f212017-02-08 14:42:22 -080060 std::vector<int> delays = {0, 250, 750, 1750, 3750,
61 7750, 15750, 23750, 31750, 39750};
62 return delays[sends];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000063 }
64
65 StunRequestManager manager_;
66 int request_count_;
67 StunMessage* response_;
68 bool success_;
69 bool failure_;
70 bool timeout_;
71};
72
73// Forwards results to the test class.
74class StunRequestThunker : public StunRequest {
75 public:
76 StunRequestThunker(StunMessage* msg, StunRequestTest* test)
77 : StunRequest(msg), test_(test) {}
78 explicit StunRequestThunker(StunRequestTest* test) : test_(test) {}
79 private:
80 virtual void OnResponse(StunMessage* res) {
81 test_->OnResponse(res);
82 }
83 virtual void OnErrorResponse(StunMessage* res) {
84 test_->OnErrorResponse(res);
85 }
86 virtual void OnTimeout() {
87 test_->OnTimeout();
88 }
89
90 virtual void Prepare(StunMessage* request) {
91 request->SetType(STUN_BINDING_REQUEST);
92 }
93
94 StunRequestTest* test_;
95};
96
97// Test handling of a normal binding response.
98TEST_F(StunRequestTest, TestSuccess) {
99 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
100
101 manager_.Send(new StunRequestThunker(req, this));
102 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req);
103 EXPECT_TRUE(manager_.CheckResponse(res));
104
105 EXPECT_TRUE(response_ == res);
106 EXPECT_TRUE(success_);
107 EXPECT_FALSE(failure_);
108 EXPECT_FALSE(timeout_);
109 delete res;
110}
111
112// Test handling of an error binding response.
113TEST_F(StunRequestTest, TestError) {
114 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
115
116 manager_.Send(new StunRequestThunker(req, this));
117 StunMessage* res = CreateStunMessage(STUN_BINDING_ERROR_RESPONSE, req);
118 EXPECT_TRUE(manager_.CheckResponse(res));
119
120 EXPECT_TRUE(response_ == res);
121 EXPECT_FALSE(success_);
122 EXPECT_TRUE(failure_);
123 EXPECT_FALSE(timeout_);
124 delete res;
125}
126
127// Test handling of a binding response with the wrong transaction id.
128TEST_F(StunRequestTest, TestUnexpected) {
129 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
130
131 manager_.Send(new StunRequestThunker(req, this));
132 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, NULL);
133 EXPECT_FALSE(manager_.CheckResponse(res));
134
135 EXPECT_TRUE(response_ == NULL);
136 EXPECT_FALSE(success_);
137 EXPECT_FALSE(failure_);
138 EXPECT_FALSE(timeout_);
139 delete res;
140}
141
pthatcher94a2f212017-02-08 14:42:22 -0800142// Test that requests are sent at the right times.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000143TEST_F(StunRequestTest, TestBackoff) {
skvladb9d8d102016-09-06 17:17:17 -0700144 rtc::ScopedFakeClock fake_clock;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000145 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
146
nisse1bffc1d2016-05-02 08:18:55 -0700147 int64_t start = rtc::TimeMillis();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000148 manager_.Send(new StunRequestThunker(req, this));
149 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req);
150 for (int i = 0; i < 9; ++i) {
pthatcher94a2f212017-02-08 14:42:22 -0800151 EXPECT_TRUE_SIMULATED_WAIT(request_count_ != i, STUN_TOTAL_TIMEOUT,
152 fake_clock);
nisse1bffc1d2016-05-02 08:18:55 -0700153 int64_t elapsed = rtc::TimeMillis() - start;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100154 RTC_LOG(LS_INFO) << "STUN request #" << (i + 1) << " sent at " << elapsed
155 << " ms";
skvladb9d8d102016-09-06 17:17:17 -0700156 EXPECT_EQ(TotalDelay(i), elapsed);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000157 }
158 EXPECT_TRUE(manager_.CheckResponse(res));
159
160 EXPECT_TRUE(response_ == res);
161 EXPECT_TRUE(success_);
162 EXPECT_FALSE(failure_);
163 EXPECT_FALSE(timeout_);
164 delete res;
165}
166
pthatcher94a2f212017-02-08 14:42:22 -0800167// Test that we timeout properly if no response is received.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000168TEST_F(StunRequestTest, TestTimeout) {
skvladb9d8d102016-09-06 17:17:17 -0700169 rtc::ScopedFakeClock fake_clock;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000170 StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
171 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req);
172
173 manager_.Send(new StunRequestThunker(req, this));
pthatcher94a2f212017-02-08 14:42:22 -0800174 SIMULATED_WAIT(false, cricket::STUN_TOTAL_TIMEOUT, fake_clock);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000175
skvladb9d8d102016-09-06 17:17:17 -0700176 EXPECT_FALSE(manager_.CheckResponse(res));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000177 EXPECT_TRUE(response_ == NULL);
178 EXPECT_FALSE(success_);
179 EXPECT_FALSE(failure_);
180 EXPECT_TRUE(timeout_);
181 delete res;
182}
183
184// Regression test for specific crash where we receive a response with the
185// same id as a request that doesn't have an underlying StunMessage yet.
186TEST_F(StunRequestTest, TestNoEmptyRequest) {
187 StunRequestThunker* request = new StunRequestThunker(this);
188
189 manager_.SendDelayed(request, 100);
190
191 StunMessage dummy_req;
192 dummy_req.SetTransactionID(request->id());
193 StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, &dummy_req);
194
195 EXPECT_TRUE(manager_.CheckResponse(res));
196
197 EXPECT_TRUE(response_ == res);
198 EXPECT_TRUE(success_);
199 EXPECT_FALSE(failure_);
200 EXPECT_FALSE(timeout_);
201 delete res;
202}
Steve Anton6c38cc72017-11-29 10:25:58 -0800203
204} // namespace cricket