Home | History | Annotate | Download | only in base
      1 /*
      2  *  Copyright 2009 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 
     11 #include "webrtc/p2p/base/basicpacketsocketfactory.h"
     12 #include "webrtc/p2p/base/relayport.h"
     13 #include "webrtc/p2p/base/relayserver.h"
     14 #include "webrtc/base/gunit.h"
     15 #include "webrtc/base/helpers.h"
     16 #include "webrtc/base/logging.h"
     17 #include "webrtc/base/physicalsocketserver.h"
     18 #include "webrtc/base/scoped_ptr.h"
     19 #include "webrtc/base/socketadapters.h"
     20 #include "webrtc/base/socketaddress.h"
     21 #include "webrtc/base/ssladapter.h"
     22 #include "webrtc/base/thread.h"
     23 #include "webrtc/base/virtualsocketserver.h"
     24 
     25 using rtc::SocketAddress;
     26 
     27 static const SocketAddress kLocalAddress = SocketAddress("192.168.1.2", 0);
     28 static const SocketAddress kRelayUdpAddr = SocketAddress("99.99.99.1", 5000);
     29 static const SocketAddress kRelayTcpAddr = SocketAddress("99.99.99.2", 5001);
     30 static const SocketAddress kRelaySslAddr = SocketAddress("99.99.99.3", 443);
     31 static const SocketAddress kRelayExtAddr = SocketAddress("99.99.99.3", 5002);
     32 
     33 static const int kTimeoutMs = 1000;
     34 static const int kMaxTimeoutMs = 5000;
     35 
     36 // Tests connecting a RelayPort to a fake relay server
     37 // (cricket::RelayServer) using all currently available protocols. The
     38 // network layer is faked out by using a VirtualSocketServer for
     39 // creating sockets. The test will monitor the current state of the
     40 // RelayPort and created sockets by listening for signals such as,
     41 // SignalConnectFailure, SignalConnectTimeout, SignalSocketClosed and
     42 // SignalReadPacket.
     43 class RelayPortTest : public testing::Test,
     44                       public sigslot::has_slots<> {
     45  public:
     46   RelayPortTest()
     47       : main_(rtc::Thread::Current()),
     48         physical_socket_server_(new rtc::PhysicalSocketServer),
     49         virtual_socket_server_(new rtc::VirtualSocketServer(
     50             physical_socket_server_.get())),
     51         ss_scope_(virtual_socket_server_.get()),
     52         network_("unittest", "unittest", rtc::IPAddress(INADDR_ANY), 32),
     53         socket_factory_(rtc::Thread::Current()),
     54         username_(rtc::CreateRandomString(16)),
     55         password_(rtc::CreateRandomString(16)),
     56         relay_port_(cricket::RelayPort::Create(main_, &socket_factory_,
     57                                                &network_,
     58                                                kLocalAddress.ipaddr(),
     59                                                0, 0, username_, password_)),
     60         relay_server_(new cricket::RelayServer(main_)) {
     61   }
     62 
     63   void OnReadPacket(rtc::AsyncPacketSocket* socket,
     64                     const char* data, size_t size,
     65                     const rtc::SocketAddress& remote_addr,
     66                     const rtc::PacketTime& packet_time) {
     67     received_packet_count_[socket]++;
     68   }
     69 
     70   void OnConnectFailure(const cricket::ProtocolAddress* addr) {
     71     failed_connections_.push_back(*addr);
     72   }
     73 
     74   void OnSoftTimeout(const cricket::ProtocolAddress* addr) {
     75     soft_timedout_connections_.push_back(*addr);
     76   }
     77 
     78  protected:
     79   virtual void SetUp() {
     80     // The relay server needs an external socket to work properly.
     81     rtc::AsyncUDPSocket* ext_socket =
     82         CreateAsyncUdpSocket(kRelayExtAddr);
     83     relay_server_->AddExternalSocket(ext_socket);
     84 
     85     // Listen for failures.
     86     relay_port_->SignalConnectFailure.
     87         connect(this, &RelayPortTest::OnConnectFailure);
     88 
     89     // Listen for soft timeouts.
     90     relay_port_->SignalSoftTimeout.
     91         connect(this, &RelayPortTest::OnSoftTimeout);
     92   }
     93 
     94   // Udp has the highest 'goodness' value of the three different
     95   // protocols used for connecting to the relay server. As soon as
     96   // PrepareAddress is called, the RelayPort will start trying to
     97   // connect to the given UDP address. As soon as a response to the
     98   // sent STUN allocate request message has been received, the
     99   // RelayPort will consider the connection to be complete and will
    100   // abort any other connection attempts.
    101   void TestConnectUdp() {
    102     // Add a UDP socket to the relay server.
    103     rtc::AsyncUDPSocket* internal_udp_socket =
    104         CreateAsyncUdpSocket(kRelayUdpAddr);
    105     rtc::AsyncSocket* server_socket = CreateServerSocket(kRelayTcpAddr);
    106 
    107     relay_server_->AddInternalSocket(internal_udp_socket);
    108     relay_server_->AddInternalServerSocket(server_socket, cricket::PROTO_TCP);
    109 
    110     // Now add our relay addresses to the relay port and let it start.
    111     relay_port_->AddServerAddress(
    112         cricket::ProtocolAddress(kRelayUdpAddr, cricket::PROTO_UDP));
    113     relay_port_->AddServerAddress(
    114         cricket::ProtocolAddress(kRelayTcpAddr, cricket::PROTO_TCP));
    115     relay_port_->PrepareAddress();
    116 
    117     // Should be connected.
    118     EXPECT_TRUE_WAIT(relay_port_->IsReady(), kTimeoutMs);
    119 
    120     // Make sure that we are happy with UDP, ie. not continuing with
    121     // TCP, SSLTCP, etc.
    122     WAIT(relay_server_->HasConnection(kRelayTcpAddr), kTimeoutMs);
    123 
    124     // Should have only one connection.
    125     EXPECT_EQ(1, relay_server_->GetConnectionCount());
    126 
    127     // Should be the UDP address.
    128     EXPECT_TRUE(relay_server_->HasConnection(kRelayUdpAddr));
    129   }
    130 
    131   // TCP has the second best 'goodness' value, and as soon as UDP
    132   // connection has failed, the RelayPort will attempt to connect via
    133   // TCP. Here we add a fake UDP address together with a real TCP
    134   // address to simulate an UDP failure. As soon as UDP has failed the
    135   // RelayPort will try the TCP adress and succed.
    136   void TestConnectTcp() {
    137     // Create a fake UDP address for relay port to simulate a failure.
    138     cricket::ProtocolAddress fake_protocol_address =
    139         cricket::ProtocolAddress(kRelayUdpAddr, cricket::PROTO_UDP);
    140 
    141     // Create a server socket for the RelayServer.
    142     rtc::AsyncSocket* server_socket = CreateServerSocket(kRelayTcpAddr);
    143     relay_server_->AddInternalServerSocket(server_socket, cricket::PROTO_TCP);
    144 
    145     // Add server addresses to the relay port and let it start.
    146     relay_port_->AddServerAddress(
    147         cricket::ProtocolAddress(fake_protocol_address));
    148     relay_port_->AddServerAddress(
    149         cricket::ProtocolAddress(kRelayTcpAddr, cricket::PROTO_TCP));
    150     relay_port_->PrepareAddress();
    151 
    152     EXPECT_FALSE(relay_port_->IsReady());
    153 
    154     // Should have timed out in 200 + 200 + 400 + 800 + 1600 ms.
    155     EXPECT_TRUE_WAIT(HasFailed(&fake_protocol_address), 3600);
    156 
    157     // Wait until relayport is ready.
    158     EXPECT_TRUE_WAIT(relay_port_->IsReady(), kMaxTimeoutMs);
    159 
    160     // Should have only one connection.
    161     EXPECT_EQ(1, relay_server_->GetConnectionCount());
    162 
    163     // Should be the TCP address.
    164     EXPECT_TRUE(relay_server_->HasConnection(kRelayTcpAddr));
    165   }
    166 
    167   void TestConnectSslTcp() {
    168     // Create a fake TCP address for relay port to simulate a failure.
    169     // We skip UDP here since transition from UDP to TCP has been
    170     // tested above.
    171     cricket::ProtocolAddress fake_protocol_address =
    172         cricket::ProtocolAddress(kRelayTcpAddr, cricket::PROTO_TCP);
    173 
    174     // Create a ssl server socket for the RelayServer.
    175     rtc::AsyncSocket* ssl_server_socket =
    176         CreateServerSocket(kRelaySslAddr);
    177     relay_server_->AddInternalServerSocket(ssl_server_socket,
    178                                            cricket::PROTO_SSLTCP);
    179 
    180     // Create a tcp server socket that listens on the fake address so
    181     // the relay port can attempt to connect to it.
    182     rtc::scoped_ptr<rtc::AsyncSocket> tcp_server_socket(
    183         CreateServerSocket(kRelayTcpAddr));
    184 
    185     // Add server addresses to the relay port and let it start.
    186     relay_port_->AddServerAddress(fake_protocol_address);
    187     relay_port_->AddServerAddress(
    188         cricket::ProtocolAddress(kRelaySslAddr, cricket::PROTO_SSLTCP));
    189     relay_port_->PrepareAddress();
    190     EXPECT_FALSE(relay_port_->IsReady());
    191 
    192     // Should have timed out in 3000 ms(relayport.cc, kSoftConnectTimeoutMs).
    193     EXPECT_TRUE_WAIT_MARGIN(HasTimedOut(&fake_protocol_address), 3000, 100);
    194 
    195     // Wait until relayport is ready.
    196     EXPECT_TRUE_WAIT(relay_port_->IsReady(), kMaxTimeoutMs);
    197 
    198     // Should have only one connection.
    199     EXPECT_EQ(1, relay_server_->GetConnectionCount());
    200 
    201     // Should be the SSLTCP address.
    202     EXPECT_TRUE(relay_server_->HasConnection(kRelaySslAddr));
    203   }
    204 
    205  private:
    206   rtc::AsyncUDPSocket* CreateAsyncUdpSocket(const SocketAddress addr) {
    207     rtc::AsyncSocket* socket =
    208         virtual_socket_server_->CreateAsyncSocket(SOCK_DGRAM);
    209     rtc::AsyncUDPSocket* packet_socket =
    210         rtc::AsyncUDPSocket::Create(socket, addr);
    211     EXPECT_TRUE(packet_socket != NULL);
    212     packet_socket->SignalReadPacket.connect(this, &RelayPortTest::OnReadPacket);
    213     return packet_socket;
    214   }
    215 
    216   rtc::AsyncSocket* CreateServerSocket(const SocketAddress addr) {
    217     rtc::AsyncSocket* socket =
    218         virtual_socket_server_->CreateAsyncSocket(SOCK_STREAM);
    219     EXPECT_GE(socket->Bind(addr), 0);
    220     EXPECT_GE(socket->Listen(5), 0);
    221     return socket;
    222   }
    223 
    224   bool HasFailed(cricket::ProtocolAddress* addr) {
    225     for (size_t i = 0; i < failed_connections_.size(); i++) {
    226       if (failed_connections_[i].address == addr->address &&
    227           failed_connections_[i].proto == addr->proto) {
    228         return true;
    229       }
    230     }
    231     return false;
    232   }
    233 
    234   bool HasTimedOut(cricket::ProtocolAddress* addr) {
    235     for (size_t i = 0; i < soft_timedout_connections_.size(); i++) {
    236       if (soft_timedout_connections_[i].address == addr->address &&
    237           soft_timedout_connections_[i].proto == addr->proto) {
    238         return true;
    239       }
    240     }
    241     return false;
    242   }
    243 
    244   typedef std::map<rtc::AsyncPacketSocket*, int> PacketMap;
    245 
    246   rtc::Thread* main_;
    247   rtc::scoped_ptr<rtc::PhysicalSocketServer>
    248       physical_socket_server_;
    249   rtc::scoped_ptr<rtc::VirtualSocketServer> virtual_socket_server_;
    250   rtc::SocketServerScope ss_scope_;
    251   rtc::Network network_;
    252   rtc::BasicPacketSocketFactory socket_factory_;
    253   std::string username_;
    254   std::string password_;
    255   rtc::scoped_ptr<cricket::RelayPort> relay_port_;
    256   rtc::scoped_ptr<cricket::RelayServer> relay_server_;
    257   std::vector<cricket::ProtocolAddress> failed_connections_;
    258   std::vector<cricket::ProtocolAddress> soft_timedout_connections_;
    259   PacketMap received_packet_count_;
    260 };
    261 
    262 TEST_F(RelayPortTest, ConnectUdp) {
    263   TestConnectUdp();
    264 }
    265 
    266 TEST_F(RelayPortTest, ConnectTcp) {
    267   TestConnectTcp();
    268 }
    269 
    270 TEST_F(RelayPortTest, ConnectSslTcp) {
    271   TestConnectSslTcp();
    272 }
    273