OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2011 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 <string> | |
12 | |
13 #include "webrtc/p2p/base/basicpacketsocketfactory.h" | |
14 #include "webrtc/p2p/base/relayport.h" | |
15 #include "webrtc/p2p/base/stunport.h" | |
16 #include "webrtc/p2p/client/connectivitychecker.h" | |
17 #include "webrtc/p2p/client/httpportallocator.h" | |
18 #include "webrtc/base/asynchttprequest.h" | |
19 #include "webrtc/base/fakenetwork.h" | |
20 #include "webrtc/base/gunit.h" | |
21 #include "webrtc/base/scoped_ptr.h" | |
22 #include "webrtc/base/socketaddress.h" | |
23 | |
24 namespace cricket { | |
25 | |
26 static const rtc::SocketAddress kClientAddr1("11.11.11.11", 0); | |
27 static const rtc::SocketAddress kClientAddr2("22.22.22.22", 0); | |
28 static const rtc::SocketAddress kExternalAddr("33.33.33.33", 3333); | |
29 static const rtc::SocketAddress kStunAddr("44.44.44.44", 4444); | |
30 static const rtc::SocketAddress kRelayAddr("55.55.55.55", 5555); | |
31 static const rtc::SocketAddress kProxyAddr("66.66.66.66", 6666); | |
32 static const rtc::ProxyType kProxyType = rtc::PROXY_HTTPS; | |
33 static const char kRelayHost[] = "relay.google.com"; | |
34 static const char kRelayToken[] = | |
35 "CAESFwoOb2phQGdvb2dsZS5jb20Q043h47MmGhBTB1rbfIXkhuarDCZe+xF6"; | |
36 static const char kBrowserAgent[] = "browser_test"; | |
37 static const char kJid[] = "a.b@c"; | |
38 static const char kUserName[] = "testuser"; | |
39 static const char kPassword[] = "testpassword"; | |
40 static const char kMagicCookie[] = "testcookie"; | |
41 static const char kRelayUdpPort[] = "4444"; | |
42 static const char kRelayTcpPort[] = "5555"; | |
43 static const char kRelaySsltcpPort[] = "6666"; | |
44 static const char kSessionId[] = "testsession"; | |
45 static const char kConnection[] = "testconnection"; | |
46 static const int kMinPort = 1000; | |
47 static const int kMaxPort = 2000; | |
48 | |
49 // Fake implementation to mock away real network usage. | |
50 class FakeRelayPort : public RelayPort { | |
51 public: | |
52 FakeRelayPort(rtc::Thread* thread, | |
53 rtc::PacketSocketFactory* factory, | |
54 rtc::Network* network, const rtc::IPAddress& ip, | |
55 int min_port, int max_port, | |
56 const std::string& username, const std::string& password) | |
57 : RelayPort(thread, factory, network, ip, min_port, max_port, | |
58 username, password) { | |
59 } | |
60 | |
61 // Just signal that we are done. | |
62 virtual void PrepareAddress() { | |
63 SignalPortComplete(this); | |
64 } | |
65 }; | |
66 | |
67 // Fake implementation to mock away real network usage. | |
68 class FakeStunPort : public StunPort { | |
69 public: | |
70 FakeStunPort(rtc::Thread* thread, | |
71 rtc::PacketSocketFactory* factory, | |
72 rtc::Network* network, | |
73 const rtc::IPAddress& ip, | |
74 int min_port, int max_port, | |
75 const std::string& username, const std::string& password, | |
76 const ServerAddresses& server_addr) | |
77 : StunPort(thread, factory, network, ip, min_port, max_port, | |
78 username, password, server_addr, std::string()) { | |
79 } | |
80 | |
81 // Just set external address and signal that we are done. | |
82 virtual void PrepareAddress() { | |
83 AddAddress(kExternalAddr, kExternalAddr, rtc::SocketAddress(), "udp", "", | |
84 "", STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_SRFLX, 0, true); | |
85 SignalPortComplete(this); | |
86 } | |
87 }; | |
88 | |
89 // Fake implementation to mock away real network usage by responding | |
90 // to http requests immediately. | |
91 class FakeHttpPortAllocatorSession : public TestHttpPortAllocatorSession { | |
92 public: | |
93 FakeHttpPortAllocatorSession( | |
94 HttpPortAllocator* allocator, | |
95 const std::string& content_name, | |
96 int component, | |
97 const std::string& ice_ufrag, const std::string& ice_pwd, | |
98 const std::vector<rtc::SocketAddress>& stun_hosts, | |
99 const std::vector<std::string>& relay_hosts, | |
100 const std::string& relay_token, | |
101 const std::string& agent) | |
102 : TestHttpPortAllocatorSession(allocator, | |
103 content_name, | |
104 component, | |
105 ice_ufrag, | |
106 ice_pwd, | |
107 stun_hosts, | |
108 relay_hosts, | |
109 relay_token, | |
110 agent) { | |
111 } | |
112 virtual void SendSessionRequest(const std::string& host, int port) { | |
113 FakeReceiveSessionResponse(host, port); | |
114 } | |
115 | |
116 // Pass results to the real implementation. | |
117 void FakeReceiveSessionResponse(const std::string& host, int port) { | |
118 rtc::AsyncHttpRequest* response = CreateAsyncHttpResponse(port); | |
119 TestHttpPortAllocatorSession::OnRequestDone(response); | |
120 response->Destroy(true); | |
121 } | |
122 | |
123 private: | |
124 // Helper method for creating a response to a relay session request. | |
125 rtc::AsyncHttpRequest* CreateAsyncHttpResponse(int port) { | |
126 rtc::AsyncHttpRequest* request = | |
127 new rtc::AsyncHttpRequest(kBrowserAgent); | |
128 std::stringstream ss; | |
129 ss << "username=" << kUserName << std::endl | |
130 << "password=" << kPassword << std::endl | |
131 << "magic_cookie=" << kMagicCookie << std::endl | |
132 << "relay.ip=" << kRelayAddr.ipaddr().ToString() << std::endl | |
133 << "relay.udp_port=" << kRelayUdpPort << std::endl | |
134 << "relay.tcp_port=" << kRelayTcpPort << std::endl | |
135 << "relay.ssltcp_port=" << kRelaySsltcpPort << std::endl; | |
136 request->response().document.reset( | |
137 new rtc::MemoryStream(ss.str().c_str())); | |
138 request->response().set_success(); | |
139 request->set_port(port); | |
140 request->set_secure(port == rtc::HTTP_SECURE_PORT); | |
141 return request; | |
142 } | |
143 }; | |
144 | |
145 // Fake implementation for creating fake http sessions. | |
146 class FakeHttpPortAllocator : public HttpPortAllocator { | |
147 public: | |
148 FakeHttpPortAllocator(rtc::NetworkManager* network_manager, | |
149 const std::string& user_agent) | |
150 : HttpPortAllocator(network_manager, user_agent) { | |
151 } | |
152 | |
153 virtual PortAllocatorSession* CreateSessionInternal( | |
154 const std::string& content_name, int component, | |
155 const std::string& ice_ufrag, const std::string& ice_pwd) { | |
156 std::vector<rtc::SocketAddress> stun_hosts; | |
157 stun_hosts.push_back(kStunAddr); | |
158 std::vector<std::string> relay_hosts; | |
159 relay_hosts.push_back(kRelayHost); | |
160 return new FakeHttpPortAllocatorSession(this, | |
161 content_name, | |
162 component, | |
163 ice_ufrag, | |
164 ice_pwd, | |
165 stun_hosts, | |
166 relay_hosts, | |
167 kRelayToken, | |
168 kBrowserAgent); | |
169 } | |
170 }; | |
171 | |
172 class ConnectivityCheckerForTest : public ConnectivityChecker { | |
173 public: | |
174 ConnectivityCheckerForTest(rtc::Thread* worker, | |
175 const std::string& jid, | |
176 const std::string& session_id, | |
177 const std::string& user_agent, | |
178 const std::string& relay_token, | |
179 const std::string& connection) | |
180 : ConnectivityChecker(worker, | |
181 jid, | |
182 session_id, | |
183 user_agent, | |
184 relay_token, | |
185 connection), | |
186 proxy_initiated_(false) { | |
187 } | |
188 | |
189 rtc::FakeNetworkManager* network_manager() const { | |
190 return network_manager_; | |
191 } | |
192 | |
193 FakeHttpPortAllocator* port_allocator() const { | |
194 return fake_port_allocator_; | |
195 } | |
196 | |
197 protected: | |
198 // Overridden methods for faking a real network. | |
199 virtual rtc::NetworkManager* CreateNetworkManager() { | |
200 network_manager_ = new rtc::FakeNetworkManager(); | |
201 return network_manager_; | |
202 } | |
203 virtual rtc::BasicPacketSocketFactory* CreateSocketFactory( | |
204 rtc::Thread* thread) { | |
205 // Create socket factory, for simplicity, let it run on the current thread. | |
206 socket_factory_ = | |
207 new rtc::BasicPacketSocketFactory(rtc::Thread::Current()); | |
208 return socket_factory_; | |
209 } | |
210 virtual HttpPortAllocator* CreatePortAllocator( | |
211 rtc::NetworkManager* network_manager, | |
212 const std::string& user_agent, | |
213 const std::string& relay_token) { | |
214 fake_port_allocator_ = | |
215 new FakeHttpPortAllocator(network_manager, user_agent); | |
216 return fake_port_allocator_; | |
217 } | |
218 virtual StunPort* CreateStunPort( | |
219 const std::string& username, const std::string& password, | |
220 const PortConfiguration* config, rtc::Network* network) { | |
221 return new FakeStunPort(worker(), | |
222 socket_factory_, | |
223 network, | |
224 network->GetBestIP(), | |
225 kMinPort, | |
226 kMaxPort, | |
227 username, | |
228 password, | |
229 config->stun_servers); | |
230 } | |
231 virtual RelayPort* CreateRelayPort( | |
232 const std::string& username, const std::string& password, | |
233 const PortConfiguration* config, rtc::Network* network) { | |
234 return new FakeRelayPort(worker(), | |
235 socket_factory_, | |
236 network, | |
237 network->GetBestIP(), | |
238 kMinPort, | |
239 kMaxPort, | |
240 username, | |
241 password); | |
242 } | |
243 virtual void InitiateProxyDetection() { | |
244 if (!proxy_initiated_) { | |
245 proxy_initiated_ = true; | |
246 proxy_info_.address = kProxyAddr; | |
247 proxy_info_.type = kProxyType; | |
248 SetProxyInfo(proxy_info_); | |
249 } | |
250 } | |
251 | |
252 virtual rtc::ProxyInfo GetProxyInfo() const { | |
253 return proxy_info_; | |
254 } | |
255 | |
256 private: | |
257 rtc::BasicPacketSocketFactory* socket_factory_; | |
258 FakeHttpPortAllocator* fake_port_allocator_; | |
259 rtc::FakeNetworkManager* network_manager_; | |
260 rtc::ProxyInfo proxy_info_; | |
261 bool proxy_initiated_; | |
262 }; | |
263 | |
264 class ConnectivityCheckerTest : public testing::Test { | |
265 protected: | |
266 void VerifyNic(const NicInfo& info, | |
267 const rtc::SocketAddress& local_address) { | |
268 // Verify that the external address has been set. | |
269 EXPECT_EQ(kExternalAddr, info.external_address); | |
270 | |
271 // Verify that the stun server address has been set. | |
272 EXPECT_EQ(1U, info.stun_server_addresses.size()); | |
273 EXPECT_EQ(kStunAddr, *(info.stun_server_addresses.begin())); | |
274 | |
275 // Verify that the media server address has been set. Don't care | |
276 // about port since it is different for different protocols. | |
277 EXPECT_EQ(kRelayAddr.ipaddr(), info.media_server_address.ipaddr()); | |
278 | |
279 // Verify that local ip matches. | |
280 EXPECT_EQ(local_address.ipaddr(), info.ip); | |
281 | |
282 // Verify that we have received responses for our | |
283 // pings. Unsuccessful ping has rtt value -1, successful >= 0. | |
284 EXPECT_GE(info.stun.rtt, 0); | |
285 EXPECT_GE(info.udp.rtt, 0); | |
286 EXPECT_GE(info.tcp.rtt, 0); | |
287 EXPECT_GE(info.ssltcp.rtt, 0); | |
288 | |
289 // If proxy has been set, verify address and type. | |
290 if (!info.proxy_info.address.IsNil()) { | |
291 EXPECT_EQ(kProxyAddr, info.proxy_info.address); | |
292 EXPECT_EQ(kProxyType, info.proxy_info.type); | |
293 } | |
294 } | |
295 }; | |
296 | |
297 // Tests a configuration with two network interfaces. Verifies that 4 | |
298 // combinations of ip/proxy are created and that all protocols are | |
299 // tested on each combination. | |
300 TEST_F(ConnectivityCheckerTest, TestStart) { | |
301 ConnectivityCheckerForTest connectivity_checker(rtc::Thread::Current(), | |
302 kJid, | |
303 kSessionId, | |
304 kBrowserAgent, | |
305 kRelayToken, | |
306 kConnection); | |
307 connectivity_checker.Initialize(); | |
308 connectivity_checker.set_stun_address(kStunAddr); | |
309 connectivity_checker.network_manager()->AddInterface(kClientAddr1); | |
310 connectivity_checker.network_manager()->AddInterface(kClientAddr2); | |
311 | |
312 connectivity_checker.Start(); | |
313 rtc::Thread::Current()->ProcessMessages(1000); | |
314 | |
315 NicMap nics = connectivity_checker.GetResults(); | |
316 | |
317 // There should be 4 nics in our map. 2 for each interface added, | |
318 // one with proxy set and one without. | |
319 EXPECT_EQ(4U, nics.size()); | |
320 | |
321 // First verify interfaces without proxy. | |
322 rtc::SocketAddress nilAddress; | |
323 | |
324 // First lookup the address of the first nic combined with no proxy. | |
325 NicMap::iterator i = nics.find(NicId(kClientAddr1.ipaddr(), nilAddress)); | |
326 ASSERT(i != nics.end()); | |
327 NicInfo info = i->second; | |
328 VerifyNic(info, kClientAddr1); | |
329 | |
330 // Then make sure the second device has been tested without proxy. | |
331 i = nics.find(NicId(kClientAddr2.ipaddr(), nilAddress)); | |
332 ASSERT(i != nics.end()); | |
333 info = i->second; | |
334 VerifyNic(info, kClientAddr2); | |
335 | |
336 // Now verify both interfaces with proxy. | |
337 i = nics.find(NicId(kClientAddr1.ipaddr(), kProxyAddr)); | |
338 ASSERT(i != nics.end()); | |
339 info = i->second; | |
340 VerifyNic(info, kClientAddr1); | |
341 | |
342 i = nics.find(NicId(kClientAddr2.ipaddr(), kProxyAddr)); | |
343 ASSERT(i != nics.end()); | |
344 info = i->second; | |
345 VerifyNic(info, kClientAddr2); | |
346 }; | |
347 | |
348 // Tests that nothing bad happens if thera are no network interfaces | |
349 // available to check. | |
350 TEST_F(ConnectivityCheckerTest, TestStartNoNetwork) { | |
351 ConnectivityCheckerForTest connectivity_checker(rtc::Thread::Current(), | |
352 kJid, | |
353 kSessionId, | |
354 kBrowserAgent, | |
355 kRelayToken, | |
356 kConnection); | |
357 connectivity_checker.Initialize(); | |
358 connectivity_checker.Start(); | |
359 rtc::Thread::Current()->ProcessMessages(1000); | |
360 | |
361 NicMap nics = connectivity_checker.GetResults(); | |
362 | |
363 // Verify that no nics where checked. | |
364 EXPECT_EQ(0U, nics.size()); | |
365 } | |
366 | |
367 } // namespace cricket | |
OLD | NEW |