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