1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 // Original author: ekr@rtfm.com
9 // Some code copied from nICEr. License is:
11 Copyright (c) 2007, Adobe Systems, Incorporated
14 Redistribution and use in source and binary forms, with or without
15 modification, are permitted provided that the following conditions are
18 * Redistributions of source code must retain the above copyright
19 notice, this list of conditions and the following disclaimer.
21 * Redistributions in binary form must reproduce the above copyright
22 notice, this list of conditions and the following disclaimer in the
23 documentation and/or other materials provided with the distribution.
25 * Neither the name of Adobe Systems, Network Resonance nor the names of its
26 contributors may be used to endorse or promote products derived from
27 this software without specific prior written permission.
29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 #include "mozilla/Scoped.h"
53 #include "nsThreadUtils.h"
56 #include "mtransport_test_utils.h"
57 #include "runnable_utils.h"
59 #define GTEST_HAS_RTTI 0
60 #include "gtest/gtest.h"
61 #include "gtest_utils.h"
67 #include "async_timer.h"
70 #include "transport_addr.h"
71 #include "nr_crypto.h"
72 #include "nr_socket.h"
73 #include "nr_socket_local.h"
74 #include "nr_socket_buffered_stun.h"
75 #include "stun_client_ctx.h"
76 #include "turn_client_ctx.h"
79 #include "nricemediastream.h"
83 MtransportTestUtils
*test_utils
;
85 using namespace mozilla
;
87 std::string g_turn_server
;
88 std::string g_turn_user
;
89 std::string g_turn_password
;
91 std::string
kDummyTurnServer("192.0.2.1"); // From RFC 5737
93 class TurnClient
: public ::testing::Test
{
96 : turn_server_(g_turn_server
),
97 real_socket_(nullptr),
99 buffered_socket_(nullptr),
104 protocol_(IPPROTO_UDP
) {
111 protocol_
= IPPROTO_TCP
;
116 nr_transport_addr addr
;
117 r
= nr_ip4_port_to_transport_addr(0, 0, protocol_
, &addr
);
120 r
= nr_socket_local_create(&addr
, &real_socket_
);
123 if (protocol_
== IPPROTO_TCP
) {
125 nr_socket_buffered_stun_create(real_socket_
, 100000,
128 net_socket_
= buffered_socket_
;
130 net_socket_
= real_socket_
;
133 r
= nr_ip4_str_port_to_transport_addr(turn_server_
.c_str(), 3478,
137 std::vector
<unsigned char> password_vec(
138 g_turn_password
.begin(), g_turn_password
.end());
140 INIT_DATA(password
, &password_vec
[0], password_vec
.size());
141 r
= nr_turn_client_ctx_create("test", net_socket_
,
147 r
= nr_socket_getfd(net_socket_
, &net_fd_
);
150 NR_ASYNC_WAIT(net_fd_
, NR_ASYNC_WAIT_READ
, socket_readable_cb
,
155 nr_turn_client_ctx_destroy(&turn_ctx_
);
157 NR_ASYNC_CANCEL(net_fd_
, NR_ASYNC_WAIT_READ
);
160 nr_socket_destroy(&buffered_socket_
);
164 RUN_ON_THREAD(test_utils
->sts_target(),
165 WrapRunnable(this, &TurnClient::TearDown_s
),
171 ASSERT_TRUE(turn_ctx_
);
173 int r
= nr_turn_client_allocate(turn_ctx_
,
179 void Allocate(bool expect_success
=true) {
180 RUN_ON_THREAD(test_utils
->sts_target(),
181 WrapRunnable(this, &TurnClient::Allocate_s
),
184 if (expect_success
) {
185 ASSERT_TRUE_WAIT(allocated_
, 5000);
189 ASSERT_FALSE(allocated_
);
194 if (turn_ctx_
->state
!=NR_TURN_CLIENT_STATE_ALLOCATED
) {
195 std::cerr
<< "Allocation failed" << std::endl
;
201 nr_transport_addr addr
;
203 r
= nr_turn_client_get_relayed_address(turn_ctx_
, &addr
);
206 relay_addr_
= addr
.as_string
;
208 std::cerr
<< "Allocation succeeded with addr=" << relay_addr_
<< std::endl
;
211 void Readable(NR_SOCKET s
, int how
, void *arg
) {
213 std::cerr
<< "Socket is readable" << std::endl
;
214 NR_ASYNC_WAIT(s
, how
, socket_readable_cb
, arg
);
218 nr_transport_addr addr
;
220 int r
= nr_socket_recvfrom(net_socket_
, buf
, sizeof(buf
), &len_s
, 0, &addr
);
222 std::cerr
<< "Error reading from socket" << std::endl
;
226 ASSERT_LT(len_s
, (size_t)INT_MAX
);
227 int len
= (int)len_s
;
229 if (nr_is_stun_response_message(buf
, len
)) {
230 std::cerr
<< "STUN response" << std::endl
;
231 r
= nr_turn_client_process_response(turn_ctx_
, buf
, len
, &addr
);
233 if (r
&& r
!= R_REJECTED
&& r
!= R_RETRY
) {
234 std::cerr
<< "Error processing STUN: " << r
<< std::endl
;
236 } else if (nr_is_stun_indication_message(buf
, len
)) {
237 std::cerr
<< "STUN indication" << std::endl
;
239 /* Process the indication */
240 unsigned char data
[NR_STUN_MAX_MESSAGE_SIZE
];
242 nr_transport_addr remote_addr
;
244 r
= nr_turn_client_parse_data_indication(turn_ctx_
, &addr
,
246 data
, &datal
, sizeof(data
),
249 std::cerr
<< "Received " << datal
<< " bytes from "
250 << remote_addr
.as_string
<< std::endl
;
254 for (size_t i
=0; i
< datal
; i
++) {
255 ASSERT_EQ(i
& 0xff, data
[i
]);
259 if (nr_is_stun_message(buf
, len
)) {
260 std::cerr
<< "STUN message of unexpected type" << std::endl
;
262 std::cerr
<< "Not a STUN message" << std::endl
;
268 void SendTo_s(const std::string
& target
) {
269 nr_transport_addr addr
;
272 // Expected pattern here is "IP4:127.0.0.1:3487"
273 ASSERT_EQ(0, target
.compare(0, 4, "IP4:"));
275 size_t offset
= target
.rfind(':');
276 ASSERT_NE(offset
, std::string::npos
);
278 std::string host
= target
.substr(4, offset
- 4);
279 std::string port
= target
.substr(offset
+ 1);
281 r
= nr_ip4_str_port_to_transport_addr(host
.c_str(),
287 unsigned char test
[100];
288 for (size_t i
=0; i
<sizeof(test
); i
++) {
292 r
= nr_turn_client_send_indication(turn_ctx_
,
293 test
, sizeof(test
), 0,
298 void SendTo(const std::string
& target
) {
299 RUN_ON_THREAD(test_utils
->sts_target(),
300 WrapRunnable(this, &TurnClient::SendTo_s
, target
),
304 int received() const { return received_
; }
306 static void socket_readable_cb(NR_SOCKET s
, int how
, void *arg
) {
307 static_cast<TurnClient
*>(arg
)->Readable(s
, how
, arg
);
310 static void allocate_success_cb(NR_SOCKET s
, int how
, void *arg
){
311 static_cast<TurnClient
*>(arg
)->Allocated();
315 std::string turn_server_
;
316 nr_socket
*real_socket_
;
317 nr_socket
*net_socket_
;
318 nr_socket
*buffered_socket_
;
320 nr_turn_client_ctx
*turn_ctx_
;
321 std::string relay_addr_
;
327 TEST_F(TurnClient
, Allocate
) {
331 TEST_F(TurnClient
, AllocateTcp
) {
336 TEST_F(TurnClient
, AllocateAndHold
) {
341 TEST_F(TurnClient
, SendToSelf
) {
344 ASSERT_TRUE_WAIT(received() == 100, 1000);
345 PR_Sleep(10000); // Wait 10 seconds to make sure the
346 // CreatePermission has time to complete/fail.
348 ASSERT_TRUE_WAIT(received() == 200, 1000);
352 TEST_F(TurnClient
, SendToSelfTcp
) {
356 ASSERT_TRUE_WAIT(received() == 100, 1000);
357 PR_Sleep(10000); // Wait 10 seconds to make sure the
358 // CreatePermission has time to complete/fail.
360 ASSERT_TRUE_WAIT(received() == 200, 1000);
363 TEST_F(TurnClient
, AllocateDummyServer
) {
364 turn_server_
= kDummyTurnServer
;
368 static std::string
get_environment(const char *name
) {
369 char *value
= getenv(name
);
377 int main(int argc
, char **argv
)
379 g_turn_server
= get_environment("TURN_SERVER_ADDRESS");
380 g_turn_user
= get_environment("TURN_SERVER_USER");
381 g_turn_password
= get_environment("TURN_SERVER_PASSWORD");
383 if (g_turn_server
.empty() ||
385 g_turn_password
.empty()) {
387 "Set TURN_SERVER_ADDRESS, TURN_SERVER_USER, and TURN_SERVER_PASSWORD\n"
388 "environment variables to run this test\n");
392 nr_transport_addr addr
;
393 if (nr_ip4_str_port_to_transport_addr(g_turn_server
.c_str(), 3478,
394 IPPROTO_UDP
, &addr
)) {
395 printf("Invalid TURN_SERVER_ADDRESS \"%s\". Only IP numbers supported.\n",
396 g_turn_server
.c_str());
400 test_utils
= new MtransportTestUtils();
401 NSS_NoDB_Init(nullptr);
402 NSS_SetDomesticPolicy();
404 // Set up the ICE registry, etc.
405 // TODO(ekr@rtfm.com): Clean up
406 std::string
dummy("dummy");
407 RUN_ON_THREAD(test_utils
->sts_target(),
408 WrapRunnableNM(&NrIceCtx::Create
,
409 dummy
, false, false, false),
413 ::testing::InitGoogleTest(&argc
, argv
);
415 int rv
= RUN_ALL_TESTS();