blob: 6304ce6789853e8fb559d7542f40a23a40df0cc7 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2012, 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/asynctcpsocket.h"
29#include "talk/base/buffer.h"
30#include "talk/base/firewallsocketserver.h"
31#include "talk/base/logging.h"
32#include "talk/base/gunit.h"
33#include "talk/base/helpers.h"
34#include "talk/base/physicalsocketserver.h"
35#include "talk/base/scoped_ptr.h"
36#include "talk/base/socketaddress.h"
37#include "talk/base/thread.h"
38#include "talk/base/virtualsocketserver.h"
39#include "talk/p2p/base/basicpacketsocketfactory.h"
40#include "talk/p2p/base/constants.h"
41#include "talk/p2p/base/tcpport.h"
42#include "talk/p2p/base/testturnserver.h"
43#include "talk/p2p/base/turnport.h"
44#include "talk/p2p/base/udpport.h"
45
46using talk_base::SocketAddress;
47using cricket::Connection;
48using cricket::Port;
49using cricket::PortInterface;
50using cricket::TurnPort;
51using cricket::UDPPort;
52
53static const SocketAddress kLocalAddr1("11.11.11.11", 0);
54static const SocketAddress kLocalAddr2("22.22.22.22", 0);
55static const SocketAddress kTurnUdpIntAddr("99.99.99.3",
56 cricket::TURN_SERVER_PORT);
57static const SocketAddress kTurnTcpIntAddr("99.99.99.4",
58 cricket::TURN_SERVER_PORT);
59static const SocketAddress kTurnUdpExtAddr("99.99.99.5", 0);
60
61static const char kIceUfrag1[] = "TESTICEUFRAG0001";
62static const char kIceUfrag2[] = "TESTICEUFRAG0002";
63static const char kIcePwd1[] = "TESTICEPWD00000000000001";
64static const char kIcePwd2[] = "TESTICEPWD00000000000002";
65static const char kTurnUsername[] = "test";
66static const char kTurnPassword[] = "test";
67static const int kTimeout = 1000;
68
wu@webrtc.org91053e72013-08-10 07:18:04 +000069static const cricket::ProtocolAddress kTurnUdpProtoAddr(
70 kTurnUdpIntAddr, cricket::PROTO_UDP);
71static const cricket::ProtocolAddress kTurnTcpProtoAddr(
72 kTurnTcpIntAddr, cricket::PROTO_TCP);
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073
74class TurnPortTest : public testing::Test,
75 public sigslot::has_slots<> {
76 public:
77 TurnPortTest()
78 : main_(talk_base::Thread::Current()),
79 pss_(new talk_base::PhysicalSocketServer),
80 ss_(new talk_base::VirtualSocketServer(pss_.get())),
81 ss_scope_(ss_.get()),
82 network_("unittest", "unittest", talk_base::IPAddress(INADDR_ANY), 32),
83 socket_factory_(talk_base::Thread::Current()),
84 turn_server_(main_, kTurnUdpIntAddr, kTurnUdpExtAddr),
85 turn_ready_(false),
86 turn_error_(false),
87 turn_unknown_address_(false),
88 turn_create_permission_success_(false),
89 udp_ready_(false) {
90 network_.AddIP(talk_base::IPAddress(INADDR_ANY));
91 }
92
93 void OnTurnPortComplete(Port* port) {
94 turn_ready_ = true;
95 }
96 void OnTurnPortError(Port* port) {
97 turn_error_ = true;
98 }
99 void OnTurnUnknownAddress(PortInterface* port, const SocketAddress& addr,
100 cricket::ProtocolType proto,
101 cricket::IceMessage* msg, const std::string& rf,
102 bool /*port_muxed*/) {
103 turn_unknown_address_ = true;
104 }
105 void OnTurnCreatePermissionResult(TurnPort* port, const SocketAddress& addr,
106 int code) {
107 // Ignoring the address.
108 if (code == 0) {
109 turn_create_permission_success_ = true;
110 }
111 }
112 void OnTurnReadPacket(Connection* conn, const char* data, size_t size) {
113 turn_packets_.push_back(talk_base::Buffer(data, size));
114 }
115 void OnUdpPortComplete(Port* port) {
116 udp_ready_ = true;
117 }
118 void OnUdpReadPacket(Connection* conn, const char* data, size_t size) {
119 udp_packets_.push_back(talk_base::Buffer(data, size));
120 }
121
122 talk_base::AsyncSocket* CreateServerSocket(const SocketAddress addr) {
123 talk_base::AsyncSocket* socket = ss_->CreateAsyncSocket(SOCK_STREAM);
124 EXPECT_GE(socket->Bind(addr), 0);
125 EXPECT_GE(socket->Listen(5), 0);
126 return socket;
127 }
128
129 void CreateTurnPort(const std::string& username,
130 const std::string& password,
131 const cricket::ProtocolAddress& server_address) {
132 cricket::RelayCredentials credentials(username, password);
133 turn_port_.reset(TurnPort::Create(main_, &socket_factory_, &network_,
134 kLocalAddr1.ipaddr(), 0, 0,
135 kIceUfrag1, kIcePwd1,
136 server_address, credentials));
137 turn_port_->SignalPortComplete.connect(this,
138 &TurnPortTest::OnTurnPortComplete);
139 turn_port_->SignalPortError.connect(this,
140 &TurnPortTest::OnTurnPortError);
141 turn_port_->SignalUnknownAddress.connect(this,
142 &TurnPortTest::OnTurnUnknownAddress);
143 turn_port_->SignalCreatePermissionResult.connect(this,
144 &TurnPortTest::OnTurnCreatePermissionResult);
145 }
146 void CreateUdpPort() {
147 udp_port_.reset(UDPPort::Create(main_, &socket_factory_, &network_,
148 kLocalAddr2.ipaddr(), 0, 0,
149 kIceUfrag2, kIcePwd2));
150 udp_port_->SignalPortComplete.connect(
151 this, &TurnPortTest::OnUdpPortComplete);
152 }
153
154 void TestTurnConnection() {
155 // Create ports and prepare addresses.
156 ASSERT_TRUE(turn_port_ != NULL);
157 turn_port_->PrepareAddress();
158 ASSERT_TRUE_WAIT(turn_ready_, kTimeout);
159 CreateUdpPort();
160 udp_port_->PrepareAddress();
161 ASSERT_TRUE_WAIT(udp_ready_, kTimeout);
162
163 // Send ping from UDP to TURN.
164 Connection* conn1 = udp_port_->CreateConnection(
165 turn_port_->Candidates()[0], Port::ORIGIN_MESSAGE);
166 ASSERT_TRUE(conn1 != NULL);
167 conn1->Ping(0);
168 WAIT(!turn_unknown_address_, kTimeout);
169 EXPECT_FALSE(turn_unknown_address_);
170 EXPECT_EQ(Connection::STATE_READ_INIT, conn1->read_state());
171 EXPECT_EQ(Connection::STATE_WRITE_INIT, conn1->write_state());
172
173 // Send ping from TURN to UDP.
174 Connection* conn2 = turn_port_->CreateConnection(
175 udp_port_->Candidates()[0], Port::ORIGIN_MESSAGE);
176 ASSERT_TRUE(conn2 != NULL);
177 ASSERT_TRUE_WAIT(turn_create_permission_success_, kTimeout);
178 conn2->Ping(0);
179
180 EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn2->write_state(), kTimeout);
181 EXPECT_EQ(Connection::STATE_READABLE, conn1->read_state());
182 EXPECT_EQ(Connection::STATE_READ_INIT, conn2->read_state());
183 EXPECT_EQ(Connection::STATE_WRITE_INIT, conn1->write_state());
184
185 // Send another ping from UDP to TURN.
186 conn1->Ping(0);
187 EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn1->write_state(), kTimeout);
188 EXPECT_EQ(Connection::STATE_READABLE, conn2->read_state());
189 }
190
191 void TestTurnSendData() {
192 turn_port_->PrepareAddress();
193 EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
194 CreateUdpPort();
195 udp_port_->PrepareAddress();
196 EXPECT_TRUE_WAIT(udp_ready_, kTimeout);
197 // Create connections and send pings.
198 Connection* conn1 = turn_port_->CreateConnection(
199 udp_port_->Candidates()[0], Port::ORIGIN_MESSAGE);
200 Connection* conn2 = udp_port_->CreateConnection(
201 turn_port_->Candidates()[0], Port::ORIGIN_MESSAGE);
202 ASSERT_TRUE(conn1 != NULL);
203 ASSERT_TRUE(conn2 != NULL);
204 conn1->SignalReadPacket.connect(static_cast<TurnPortTest*>(this),
205 &TurnPortTest::OnTurnReadPacket);
206 conn2->SignalReadPacket.connect(static_cast<TurnPortTest*>(this),
207 &TurnPortTest::OnUdpReadPacket);
208 conn1->Ping(0);
209 EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn1->write_state(), kTimeout);
210 conn2->Ping(0);
211 EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn2->write_state(), kTimeout);
212
213 // Send some data.
214 size_t num_packets = 256;
215 for (size_t i = 0; i < num_packets; ++i) {
216 char buf[256];
217 for (size_t j = 0; j < i + 1; ++j) {
218 buf[j] = 0xFF - j;
219 }
220 conn1->Send(buf, i + 1);
221 conn2->Send(buf, i + 1);
222 main_->ProcessMessages(0);
223 }
224
225 // Check the data.
226 ASSERT_EQ_WAIT(num_packets, turn_packets_.size(), kTimeout);
227 ASSERT_EQ_WAIT(num_packets, udp_packets_.size(), kTimeout);
228 for (size_t i = 0; i < num_packets; ++i) {
229 EXPECT_EQ(i + 1, turn_packets_[i].length());
230 EXPECT_EQ(i + 1, udp_packets_[i].length());
231 EXPECT_EQ(turn_packets_[i], udp_packets_[i]);
232 }
233 }
234
235 protected:
236 talk_base::Thread* main_;
237 talk_base::scoped_ptr<talk_base::PhysicalSocketServer> pss_;
238 talk_base::scoped_ptr<talk_base::VirtualSocketServer> ss_;
239 talk_base::SocketServerScope ss_scope_;
240 talk_base::Network network_;
241 talk_base::BasicPacketSocketFactory socket_factory_;
242 cricket::TestTurnServer turn_server_;
243 talk_base::scoped_ptr<TurnPort> turn_port_;
244 talk_base::scoped_ptr<UDPPort> udp_port_;
245 bool turn_ready_;
246 bool turn_error_;
247 bool turn_unknown_address_;
248 bool turn_create_permission_success_;
249 bool udp_ready_;
250 std::vector<talk_base::Buffer> turn_packets_;
251 std::vector<talk_base::Buffer> udp_packets_;
252};
253
254// Do a normal TURN allocation.
255TEST_F(TurnPortTest, TestTurnAllocate) {
256 CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
257 EXPECT_EQ(0, turn_port_->SetOption(talk_base::Socket::OPT_SNDBUF, 10*1024));
258 turn_port_->PrepareAddress();
259 EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
260 ASSERT_EQ(1U, turn_port_->Candidates().size());
261 EXPECT_EQ(kTurnUdpExtAddr.ipaddr(),
262 turn_port_->Candidates()[0].address().ipaddr());
263 EXPECT_NE(0, turn_port_->Candidates()[0].address().port());
264}
265
266TEST_F(TurnPortTest, TestTurnTcpAllocate) {
267 talk_base::AsyncSocket* tcp_server_socket =
268 CreateServerSocket(kTurnTcpIntAddr);
269 turn_server_.server()->AddInternalServerSocket(
270 tcp_server_socket, cricket::PROTO_TCP);
271 CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr);
272 EXPECT_EQ(0, turn_port_->SetOption(talk_base::Socket::OPT_SNDBUF, 10*1024));
273 turn_port_->PrepareAddress();
274 EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
275 ASSERT_EQ(1U, turn_port_->Candidates().size());
276 EXPECT_EQ(kTurnUdpExtAddr.ipaddr(),
277 turn_port_->Candidates()[0].address().ipaddr());
278 EXPECT_NE(0, turn_port_->Candidates()[0].address().port());
279}
280
281// Try to do a TURN allocation with an invalid password.
282TEST_F(TurnPortTest, TestTurnAllocateBadPassword) {
283 CreateTurnPort(kTurnUsername, "bad", kTurnUdpProtoAddr);
284 turn_port_->PrepareAddress();
285 EXPECT_TRUE_WAIT(turn_error_, kTimeout);
286 ASSERT_EQ(0U, turn_port_->Candidates().size());
287}
288
289// Do a TURN allocation and try to send a packet to it from the outside.
290// The packet should be dropped. Then, try to send a packet from TURN to the
291// outside. It should reach its destination. Finally, try again from the
292// outside. It should now work as well.
293TEST_F(TurnPortTest, TestTurnConnection) {
294 CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
295 TestTurnConnection();
296}
297
wu@webrtc.org91053e72013-08-10 07:18:04 +0000298// Test that we can establish a TCP connection with TURN server.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000299TEST_F(TurnPortTest, TestTurnTcpConnection) {
300 talk_base::AsyncSocket* tcp_server_socket =
301 CreateServerSocket(kTurnTcpIntAddr);
302 turn_server_.server()->AddInternalServerSocket(
303 tcp_server_socket, cricket::PROTO_TCP);
304 CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr);
305 TestTurnConnection();
306}
307
wu@webrtc.org91053e72013-08-10 07:18:04 +0000308// Test that we fail to create a connection when we want to use TLS over TCP.
309// This test should be removed once we have TLS support.
310TEST_F(TurnPortTest, TestTurnTlsTcpConnectionFails) {
311 cricket::ProtocolAddress secure_addr(kTurnTcpProtoAddr.address,
312 kTurnTcpProtoAddr.proto,
313 true);
314 CreateTurnPort(kTurnUsername, kTurnPassword, secure_addr);
315 turn_port_->PrepareAddress();
316 EXPECT_TRUE_WAIT(turn_error_, kTimeout);
317 ASSERT_EQ(0U, turn_port_->Candidates().size());
318}
319
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000320// Run TurnConnectionTest with one-time-use nonce feature.
321// Here server will send a 438 STALE_NONCE error message for
322// every TURN transaction.
323TEST_F(TurnPortTest, TestTurnConnectionUsingOTUNonce) {
324 turn_server_.set_enable_otu_nonce(true);
325 CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
326 TestTurnConnection();
327}
328
329// Do a TURN allocation, establish a connection, and send some data.
330TEST_F(TurnPortTest, TestTurnSendDataTurnUdpToUdp) {
331 // Create ports and prepare addresses.
332 CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
333 TestTurnSendData();
334}
335
336TEST_F(TurnPortTest, TestTurnSendDataTurnTcpToUdp) {
337 talk_base::AsyncSocket* tcp_server_socket =
338 CreateServerSocket(kTurnTcpIntAddr);
339 turn_server_.server()->AddInternalServerSocket(
340 tcp_server_socket, cricket::PROTO_TCP);
341 // Create ports and prepare addresses.
342 CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr);
343 TestTurnSendData();
344}