media/mtransport/test/turn_unittest.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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:
    10 /*
    11 Copyright (c) 2007, Adobe Systems, Incorporated
    12 All rights reserved.
    14 Redistribution and use in source and binary forms, with or without
    15 modification, are permitted provided that the following conditions are
    16 met:
    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.
    40 */
    42 #include <stdlib.h>
    43 #include <iostream>
    45 #include "sigslot.h"
    47 #include "logging.h"
    48 #include "nspr.h"
    49 #include "nss.h"
    50 #include "ssl.h"
    52 #include "mozilla/Scoped.h"
    53 #include "nsThreadUtils.h"
    54 #include "nsXPCOM.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"
    63 // nICEr includes
    64 extern "C" {
    65 #include "nr_api.h"
    66 #include "registry.h"
    67 #include "async_timer.h"
    68 #include "r_crc32.h"
    69 #include "ice_util.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"
    77 }
    79 #include "nricemediastream.h"
    80 #include "nricectx.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 {
    94  public:
    95   TurnClient()
    96       : turn_server_(g_turn_server),
    97         real_socket_(nullptr),
    98         net_socket_(nullptr),
    99         buffered_socket_(nullptr),
   100         net_fd_(nullptr),
   101         turn_ctx_(nullptr),
   102         allocated_(false),
   103         received_(0),
   104         protocol_(IPPROTO_UDP) {
   105   }
   107   ~TurnClient() {
   108   }
   110   void SetTcp() {
   111     protocol_ = IPPROTO_TCP;
   112   }
   114   void Init_s() {
   115     int r;
   116     nr_transport_addr addr;
   117     r = nr_ip4_port_to_transport_addr(0, 0, protocol_, &addr);
   118     ASSERT_EQ(0, r);
   120     r = nr_socket_local_create(&addr, &real_socket_);
   121     ASSERT_EQ(0, r);
   123     if (protocol_ == IPPROTO_TCP) {
   124       int r =
   125           nr_socket_buffered_stun_create(real_socket_, 100000,
   126                                          &buffered_socket_);
   127       ASSERT_EQ(0, r);
   128       net_socket_ = buffered_socket_;
   129     } else {
   130       net_socket_ = real_socket_;
   131     }
   133     r = nr_ip4_str_port_to_transport_addr(turn_server_.c_str(), 3478,
   134       protocol_, &addr);
   135     ASSERT_EQ(0, r);
   137     std::vector<unsigned char> password_vec(
   138         g_turn_password.begin(), g_turn_password.end());
   139     Data password;
   140     INIT_DATA(password, &password_vec[0], password_vec.size());
   141     r = nr_turn_client_ctx_create("test", net_socket_,
   142                                   g_turn_user.c_str(),
   143                                   &password,
   144                                   &addr, &turn_ctx_);
   145     ASSERT_EQ(0, r);
   147     r = nr_socket_getfd(net_socket_, &net_fd_);
   148     ASSERT_EQ(0, r);
   150     NR_ASYNC_WAIT(net_fd_, NR_ASYNC_WAIT_READ, socket_readable_cb,
   151         (void *)this);
   152   }
   154   void TearDown_s() {
   155     nr_turn_client_ctx_destroy(&turn_ctx_);
   156     if (net_fd_) {
   157       NR_ASYNC_CANCEL(net_fd_, NR_ASYNC_WAIT_READ);
   158     }
   160     nr_socket_destroy(&buffered_socket_);
   161   }
   163   void TearDown() {
   164     RUN_ON_THREAD(test_utils->sts_target(),
   165                   WrapRunnable(this, &TurnClient::TearDown_s),
   166                   NS_DISPATCH_SYNC);
   167   }
   169   void Allocate_s() {
   170     Init_s();
   171     ASSERT_TRUE(turn_ctx_);
   173     int r = nr_turn_client_allocate(turn_ctx_,
   174                                     allocate_success_cb,
   175                                     this);
   176     ASSERT_EQ(0, r);
   177   }
   179   void Allocate(bool expect_success=true) {
   180     RUN_ON_THREAD(test_utils->sts_target(),
   181                   WrapRunnable(this, &TurnClient::Allocate_s),
   182                   NS_DISPATCH_SYNC);
   184     if (expect_success) {
   185       ASSERT_TRUE_WAIT(allocated_, 5000);
   186     }
   187     else {
   188       PR_Sleep(10000);
   189       ASSERT_FALSE(allocated_);
   190     }
   191   }
   193   void Allocated() {
   194     if (turn_ctx_->state!=NR_TURN_CLIENT_STATE_ALLOCATED) {
   195       std::cerr << "Allocation failed" << std::endl;
   196       return;
   197     }
   198     allocated_ = true;
   200     int r;
   201     nr_transport_addr addr;
   203     r = nr_turn_client_get_relayed_address(turn_ctx_, &addr);
   204     ASSERT_EQ(0, r);
   206     relay_addr_ = addr.as_string;
   208     std::cerr << "Allocation succeeded with addr=" << relay_addr_ << std::endl;
   209   }
   211   void Readable(NR_SOCKET s, int how, void *arg) {
   212     // Re-arm
   213     std::cerr << "Socket is readable" << std::endl;
   214     NR_ASYNC_WAIT(s, how, socket_readable_cb, arg);
   216     UCHAR buf[8192];
   217     size_t len_s;
   218     nr_transport_addr addr;
   220     int r = nr_socket_recvfrom(net_socket_, buf, sizeof(buf), &len_s, 0, &addr);
   221     if (r) {
   222       std::cerr << "Error reading from socket" << std::endl;
   223       return;
   224     }
   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;
   235       }
   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];
   241       size_t datal;
   242       nr_transport_addr remote_addr;
   244       r = nr_turn_client_parse_data_indication(turn_ctx_, &addr,
   245                                                buf, len,
   246                                                data, &datal, sizeof(data),
   247                                                &remote_addr);
   248       ASSERT_EQ(0, r);
   249       std::cerr << "Received " << datal << " bytes from "
   250                 << remote_addr.as_string << std::endl;
   252       received_ += datal;
   254       for (size_t i=0; i < datal; i++) {
   255         ASSERT_EQ(i & 0xff, data[i]);
   256       }
   257     }
   258     else {
   259       if (nr_is_stun_message(buf, len)) {
   260         std::cerr << "STUN message of unexpected type" << std::endl;
   261       } else {
   262         std::cerr << "Not a STUN message" << std::endl;
   263       }
   264       return;
   265     }
   266   }
   268   void SendTo_s(const std::string& target) {
   269     nr_transport_addr addr;
   270     int r;
   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(),
   282                                           atoi(port.c_str()),
   283                                           IPPROTO_UDP,
   284                                           &addr);
   285     ASSERT_EQ(0, r);
   287     unsigned char test[100];
   288     for (size_t i=0; i<sizeof(test); i++) {
   289       test[i] = i & 0xff;
   290     }
   292     r = nr_turn_client_send_indication(turn_ctx_,
   293                                             test, sizeof(test), 0,
   294                                             &addr);
   295     ASSERT_EQ(0, r);
   296   }
   298   void SendTo(const std::string& target) {
   299     RUN_ON_THREAD(test_utils->sts_target(),
   300                   WrapRunnable(this, &TurnClient::SendTo_s, target),
   301                   NS_DISPATCH_SYNC);
   302   }
   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);
   308   }
   310   static void allocate_success_cb(NR_SOCKET s, int how, void *arg){
   311     static_cast<TurnClient *>(arg)->Allocated();
   312   }
   314  protected:
   315   std::string turn_server_;
   316   nr_socket *real_socket_;
   317   nr_socket *net_socket_;
   318   nr_socket *buffered_socket_;
   319   NR_SOCKET net_fd_;
   320   nr_turn_client_ctx *turn_ctx_;
   321   std::string relay_addr_;
   322   bool allocated_;
   323   int received_;
   324   int protocol_;
   325 };
   327 TEST_F(TurnClient, Allocate) {
   328   Allocate();
   329 }
   331 TEST_F(TurnClient, AllocateTcp) {
   332   SetTcp();
   333   Allocate();
   334 }
   336 TEST_F(TurnClient, AllocateAndHold) {
   337   Allocate();
   338   PR_Sleep(20000);
   339 }
   341 TEST_F(TurnClient, SendToSelf) {
   342   Allocate();
   343   SendTo(relay_addr_);
   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.
   347   SendTo(relay_addr_);
   348   ASSERT_TRUE_WAIT(received() == 200, 1000);
   349 }
   352 TEST_F(TurnClient, SendToSelfTcp) {
   353   SetTcp();
   354   Allocate();
   355   SendTo(relay_addr_);
   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.
   359   SendTo(relay_addr_);
   360   ASSERT_TRUE_WAIT(received() == 200, 1000);
   361 }
   363 TEST_F(TurnClient, AllocateDummyServer) {
   364   turn_server_ = kDummyTurnServer;
   365   Allocate(false);
   366 }
   368 static std::string get_environment(const char *name) {
   369   char *value = getenv(name);
   371   if (!value)
   372     return "";
   374   return value;
   375 }
   377 int main(int argc, char **argv)
   378 {
   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() ||
   384       g_turn_user.empty(),
   385       g_turn_password.empty()) {
   386     printf(
   387         "Set TURN_SERVER_ADDRESS, TURN_SERVER_USER, and TURN_SERVER_PASSWORD\n"
   388         "environment variables to run this test\n");
   389     return 0;
   390   }
   391   {
   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());
   397       return 0;
   398     }
   399   }
   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),
   410                 NS_DISPATCH_SYNC);
   412   // Start the tests
   413   ::testing::InitGoogleTest(&argc, argv);
   415   int rv = RUN_ALL_TESTS();
   416   delete test_utils;
   417   return rv;
   418 }

mercurial