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