blob: d644d67c4f3d248cd9def2650a24ee9b691a224d [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001/*
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
25using rtc::SocketAddress;
26
27static const SocketAddress kLocalAddress = SocketAddress("192.168.1.2", 0);
28static const SocketAddress kRelayUdpAddr = SocketAddress("99.99.99.1", 5000);
29static const SocketAddress kRelayTcpAddr = SocketAddress("99.99.99.2", 5001);
30static const SocketAddress kRelaySslAddr = SocketAddress("99.99.99.3", 443);
31static const SocketAddress kRelayExtAddr = SocketAddress("99.99.99.3", 5002);
32
33static const int kTimeoutMs = 1000;
34static 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.
43class 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
262TEST_F(RelayPortTest, ConnectUdp) {
263 TestConnectUdp();
264}
265
266TEST_F(RelayPortTest, ConnectTcp) {
267 TestConnectTcp();
268}
269
270TEST_F(RelayPortTest, ConnectSslTcp) {
271 TestConnectSslTcp();
272}