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