blob: 5850027ec8dc340195ca736d1dbf35b6a77d71ad [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2009 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "talk/base/gunit.h"
29#include "talk/base/helpers.h"
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +000030#include "talk/base/physicalsocketserver.h"
31#include "talk/base/scoped_ptr.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000032#include "talk/base/socketaddress.h"
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +000033#include "talk/base/virtualsocketserver.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000034#include "talk/p2p/base/basicpacketsocketfactory.h"
35#include "talk/p2p/base/stunport.h"
36#include "talk/p2p/base/teststunserver.h"
37
38using talk_base::SocketAddress;
39
40static const SocketAddress kLocalAddr("127.0.0.1", 0);
41static const SocketAddress kStunAddr("127.0.0.1", 5000);
42static const SocketAddress kBadAddr("0.0.0.1", 5000);
43static const SocketAddress kStunHostnameAddr("localhost", 5000);
44static const SocketAddress kBadHostnameAddr("not-a-real-hostname", 5000);
45static const int kTimeoutMs = 10000;
buildbot@webrtc.orgf875f152014-04-14 16:06:21 +000046// stun prio = 100 << 24 | 30 (IPV4) << 8 | 256 - 0
47static const uint32 kStunCandidatePriority = 1677729535;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000048
49// Tests connecting a StunPort to a fake STUN server (cricket::StunServer)
50// TODO: Use a VirtualSocketServer here. We have to use a
51// PhysicalSocketServer right now since DNS is not part of SocketServer yet.
52class StunPortTest : public testing::Test,
53 public sigslot::has_slots<> {
54 public:
55 StunPortTest()
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +000056 : pss_(new talk_base::PhysicalSocketServer),
57 ss_(new talk_base::VirtualSocketServer(pss_.get())),
58 ss_scope_(ss_.get()),
59 network_("unittest", "unittest", talk_base::IPAddress(INADDR_ANY), 32),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060 socket_factory_(talk_base::Thread::Current()),
61 stun_server_(new cricket::TestStunServer(
62 talk_base::Thread::Current(), kStunAddr)),
63 done_(false), error_(false), stun_keepalive_delay_(0) {
64 }
65
66 const cricket::Port* port() const { return stun_port_.get(); }
67 bool done() const { return done_; }
68 bool error() const { return error_; }
69
70 void CreateStunPort(const talk_base::SocketAddress& server_addr) {
71 stun_port_.reset(cricket::StunPort::Create(
72 talk_base::Thread::Current(), &socket_factory_, &network_,
73 kLocalAddr.ipaddr(), 0, 0, talk_base::CreateRandomString(16),
74 talk_base::CreateRandomString(22), server_addr));
75 stun_port_->set_stun_keepalive_delay(stun_keepalive_delay_);
76 stun_port_->SignalPortComplete.connect(this,
77 &StunPortTest::OnPortComplete);
78 stun_port_->SignalPortError.connect(this,
79 &StunPortTest::OnPortError);
80 }
81
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +000082 void CreateSharedStunPort(const talk_base::SocketAddress& server_addr) {
83 socket_.reset(socket_factory_.CreateUdpSocket(
84 talk_base::SocketAddress(kLocalAddr.ipaddr(), 0), 0, 0));
85 ASSERT_TRUE(socket_ != NULL);
86 socket_->SignalReadPacket.connect(this, &StunPortTest::OnReadPacket);
87 stun_port_.reset(cricket::UDPPort::Create(
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +000088 talk_base::Thread::Current(), &socket_factory_,
89 &network_, socket_.get(),
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +000090 talk_base::CreateRandomString(16), talk_base::CreateRandomString(22)));
91 ASSERT_TRUE(stun_port_ != NULL);
92 stun_port_->set_server_addr(server_addr);
93 stun_port_->SignalPortComplete.connect(this,
94 &StunPortTest::OnPortComplete);
95 stun_port_->SignalPortError.connect(this,
96 &StunPortTest::OnPortError);
97 }
98
henrike@webrtc.org28e20752013-07-10 00:45:36 +000099 void PrepareAddress() {
100 stun_port_->PrepareAddress();
101 }
102
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000103 void OnReadPacket(talk_base::AsyncPacketSocket* socket, const char* data,
wu@webrtc.orga9890802013-12-13 00:21:03 +0000104 size_t size, const talk_base::SocketAddress& remote_addr,
105 const talk_base::PacketTime& packet_time) {
106 stun_port_->HandleIncomingPacket(
107 socket, data, size, remote_addr, talk_base::PacketTime());
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000108 }
109
110 void SendData(const char* data, size_t len) {
111 stun_port_->HandleIncomingPacket(
wu@webrtc.orga9890802013-12-13 00:21:03 +0000112 socket_.get(), data, len, talk_base::SocketAddress("22.22.22.22", 0),
113 talk_base::PacketTime());
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000114 }
115
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000116 protected:
117 static void SetUpTestCase() {
118 // Ensure the RNG is inited.
119 talk_base::InitRandom(NULL, 0);
120 }
121
122 void OnPortComplete(cricket::Port* port) {
123 done_ = true;
124 error_ = false;
125 }
126 void OnPortError(cricket::Port* port) {
127 done_ = true;
128 error_ = true;
129 }
130 void SetKeepaliveDelay(int delay) {
131 stun_keepalive_delay_ = delay;
132 }
133
134 private:
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000135 talk_base::scoped_ptr<talk_base::PhysicalSocketServer> pss_;
136 talk_base::scoped_ptr<talk_base::VirtualSocketServer> ss_;
137 talk_base::SocketServerScope ss_scope_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000138 talk_base::Network network_;
139 talk_base::BasicPacketSocketFactory socket_factory_;
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000140 talk_base::scoped_ptr<cricket::UDPPort> stun_port_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000141 talk_base::scoped_ptr<cricket::TestStunServer> stun_server_;
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000142 talk_base::scoped_ptr<talk_base::AsyncPacketSocket> socket_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000143 bool done_;
144 bool error_;
145 int stun_keepalive_delay_;
146};
147
148// Test that we can create a STUN port
149TEST_F(StunPortTest, TestBasic) {
150 CreateStunPort(kStunAddr);
151 EXPECT_EQ("stun", port()->Type());
152 EXPECT_EQ(0U, port()->Candidates().size());
153}
154
155// Test that we can get an address from a STUN server.
156TEST_F(StunPortTest, TestPrepareAddress) {
157 CreateStunPort(kStunAddr);
158 PrepareAddress();
159 EXPECT_TRUE_WAIT(done(), kTimeoutMs);
160 ASSERT_EQ(1U, port()->Candidates().size());
161 EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address()));
162
163 // TODO: Add IPv6 tests here, once either physicalsocketserver supports
164 // IPv6, or this test is changed to use VirtualSocketServer.
165}
166
167// Test that we fail properly if we can't get an address.
168TEST_F(StunPortTest, TestPrepareAddressFail) {
169 CreateStunPort(kBadAddr);
170 PrepareAddress();
171 EXPECT_TRUE_WAIT(done(), kTimeoutMs);
172 EXPECT_TRUE(error());
173 EXPECT_EQ(0U, port()->Candidates().size());
174}
175
176// Test that we can get an address from a STUN server specified by a hostname.
177TEST_F(StunPortTest, TestPrepareAddressHostname) {
178 CreateStunPort(kStunHostnameAddr);
179 PrepareAddress();
180 EXPECT_TRUE_WAIT(done(), kTimeoutMs);
181 ASSERT_EQ(1U, port()->Candidates().size());
182 EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address()));
buildbot@webrtc.orgf875f152014-04-14 16:06:21 +0000183 EXPECT_EQ(kStunCandidatePriority, port()->Candidates()[0].priority());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000184}
185
186// Test that we handle hostname lookup failures properly.
187TEST_F(StunPortTest, TestPrepareAddressHostnameFail) {
188 CreateStunPort(kBadHostnameAddr);
189 PrepareAddress();
190 EXPECT_TRUE_WAIT(done(), kTimeoutMs);
191 EXPECT_TRUE(error());
192 EXPECT_EQ(0U, port()->Candidates().size());
193}
194
195// This test verifies keepalive response messages don't result in
196// additional candidate generation.
197TEST_F(StunPortTest, TestKeepAliveResponse) {
198 SetKeepaliveDelay(500); // 500ms of keepalive delay.
199 CreateStunPort(kStunHostnameAddr);
200 PrepareAddress();
201 EXPECT_TRUE_WAIT(done(), kTimeoutMs);
202 ASSERT_EQ(1U, port()->Candidates().size());
203 EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address()));
204 // Waiting for 1 seond, which will allow us to process
205 // response for keepalive binding request. 500 ms is the keepalive delay.
206 talk_base::Thread::Current()->ProcessMessages(1000);
207 ASSERT_EQ(1U, port()->Candidates().size());
208}
209
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000210// Test that a local candidate can be generated using a shared socket.
211TEST_F(StunPortTest, TestSharedSocketPrepareAddress) {
212 CreateSharedStunPort(kStunAddr);
213 PrepareAddress();
214 EXPECT_TRUE_WAIT(done(), kTimeoutMs);
215 ASSERT_EQ(1U, port()->Candidates().size());
216 EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address()));
217}
218
219// Test that we still a get a local candidate with invalid stun server hostname.
220// Also verifing that UDPPort can receive packets when stun address can't be
221// resolved.
222TEST_F(StunPortTest, TestSharedSocketPrepareAddressInvalidHostname) {
223 CreateSharedStunPort(kBadHostnameAddr);
224 PrepareAddress();
225 EXPECT_TRUE_WAIT(done(), kTimeoutMs);
226 ASSERT_EQ(1U, port()->Candidates().size());
227 EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address()));
228
229 // Send data to port after it's ready. This is to make sure, UDP port can
230 // handle data with unresolved stun server address.
231 std::string data = "some random data, sending to cricket::Port.";
232 SendData(data.c_str(), data.length());
233 // No crash is success.
234}