Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(152)

Side by Side Diff: webrtc/p2p/client/connectivitychecker.cc

Issue 1311353011: Remove AsyncHttpRequest, AutoPortAllocator, ConnectivityChecker, and HttpPortAllocator (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: undo chromium change Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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/client/connectivitychecker.h"
14
15 #include "webrtc/p2p/base/candidate.h"
16 #include "webrtc/p2p/base/common.h"
17 #include "webrtc/p2p/base/constants.h"
18 #include "webrtc/p2p/base/port.h"
19 #include "webrtc/p2p/base/relayport.h"
20 #include "webrtc/p2p/base/stunport.h"
21 #include "webrtc/base/asynchttprequest.h"
22 #include "webrtc/base/autodetectproxy.h"
23 #include "webrtc/base/helpers.h"
24 #include "webrtc/base/httpcommon-inl.h"
25 #include "webrtc/base/httpcommon.h"
26 #include "webrtc/base/logging.h"
27 #include "webrtc/base/proxydetect.h"
28 #include "webrtc/base/thread.h"
29
30 namespace cricket {
31
32 static const char kDefaultStunHostname[] = "stun.l.google.com";
33 static const int kDefaultStunPort = 19302;
34
35 // Default maximum time in milliseconds we will wait for connections.
36 static const uint32 kDefaultTimeoutMs = 3000;
37
38 enum {
39 MSG_START = 1,
40 MSG_STOP = 2,
41 MSG_TIMEOUT = 3,
42 MSG_SIGNAL_RESULTS = 4
43 };
44
45 class TestHttpPortAllocator : public HttpPortAllocator {
46 public:
47 TestHttpPortAllocator(rtc::NetworkManager* network_manager,
48 const std::string& user_agent,
49 const std::string& relay_token) :
50 HttpPortAllocator(network_manager, user_agent) {
51 SetRelayToken(relay_token);
52 }
53 PortAllocatorSession* CreateSessionInternal(
54 const std::string& content_name,
55 int component,
56 const std::string& ice_ufrag,
57 const std::string& ice_pwd) {
58 return new TestHttpPortAllocatorSession(this, content_name, component,
59 ice_ufrag, ice_pwd,
60 stun_hosts(), relay_hosts(),
61 relay_token(), user_agent());
62 }
63 };
64
65 void TestHttpPortAllocatorSession::ConfigReady(PortConfiguration* config) {
66 SignalConfigReady(username(), password(), config, proxy_);
67 delete config;
68 }
69
70 void TestHttpPortAllocatorSession::OnRequestDone(
71 rtc::SignalThread* data) {
72 rtc::AsyncHttpRequest* request =
73 static_cast<rtc::AsyncHttpRequest*>(data);
74
75 // Tell the checker that the request is complete.
76 SignalRequestDone(request);
77
78 // Pass on the response to super class.
79 HttpPortAllocatorSession::OnRequestDone(data);
80 }
81
82 ConnectivityChecker::ConnectivityChecker(
83 rtc::Thread* worker,
84 const std::string& jid,
85 const std::string& session_id,
86 const std::string& user_agent,
87 const std::string& relay_token,
88 const std::string& connection)
89 : worker_(worker),
90 jid_(jid),
91 session_id_(session_id),
92 user_agent_(user_agent),
93 relay_token_(relay_token),
94 connection_(connection),
95 proxy_detect_(NULL),
96 timeout_ms_(kDefaultTimeoutMs),
97 stun_address_(kDefaultStunHostname, kDefaultStunPort),
98 started_(false) {
99 }
100
101 ConnectivityChecker::~ConnectivityChecker() {
102 if (started_) {
103 // We try to clear the TIMEOUT below. But worker may still handle it and
104 // cause SignalCheckDone to happen on main-thread. So we finally clear any
105 // pending SIGNAL_RESULTS.
106 worker_->Clear(this, MSG_TIMEOUT);
107 worker_->Send(this, MSG_STOP);
108 nics_.clear();
109 main_->Clear(this, MSG_SIGNAL_RESULTS);
110 }
111 }
112
113 bool ConnectivityChecker::Initialize() {
114 network_manager_.reset(CreateNetworkManager());
115 socket_factory_.reset(CreateSocketFactory(worker_));
116 port_allocator_.reset(CreatePortAllocator(network_manager_.get(),
117 user_agent_, relay_token_));
118 return true;
119 }
120
121 void ConnectivityChecker::Start() {
122 main_ = rtc::Thread::Current();
123 worker_->Post(this, MSG_START);
124 started_ = true;
125 }
126
127 void ConnectivityChecker::CleanUp() {
128 ASSERT(worker_ == rtc::Thread::Current());
129 if (proxy_detect_) {
130 proxy_detect_->Release();
131 proxy_detect_ = NULL;
132 }
133
134 for (uint32 i = 0; i < sessions_.size(); ++i) {
135 delete sessions_[i];
136 }
137 sessions_.clear();
138 for (uint32 i = 0; i < ports_.size(); ++i) {
139 delete ports_[i];
140 }
141 ports_.clear();
142 }
143
144 bool ConnectivityChecker::AddNic(const rtc::IPAddress& ip,
145 const rtc::SocketAddress& proxy_addr) {
146 NicMap::iterator i = nics_.find(NicId(ip, proxy_addr));
147 if (i != nics_.end()) {
148 // Already have it.
149 return false;
150 }
151 uint32 now = rtc::Time();
152 NicInfo info;
153 info.ip = ip;
154 info.proxy_info = GetProxyInfo();
155 info.stun.start_time_ms = now;
156 nics_.insert(std::pair<NicId, NicInfo>(NicId(ip, proxy_addr), info));
157 return true;
158 }
159
160 void ConnectivityChecker::SetProxyInfo(const rtc::ProxyInfo& proxy_info) {
161 port_allocator_->set_proxy(user_agent_, proxy_info);
162 AllocatePorts();
163 }
164
165 rtc::ProxyInfo ConnectivityChecker::GetProxyInfo() const {
166 rtc::ProxyInfo proxy_info;
167 if (proxy_detect_) {
168 proxy_info = proxy_detect_->proxy();
169 }
170 return proxy_info;
171 }
172
173 void ConnectivityChecker::CheckNetworks() {
174 network_manager_->SignalNetworksChanged.connect(
175 this, &ConnectivityChecker::OnNetworksChanged);
176 network_manager_->StartUpdating();
177 }
178
179 void ConnectivityChecker::OnMessage(rtc::Message *msg) {
180 switch (msg->message_id) {
181 case MSG_START:
182 ASSERT(worker_ == rtc::Thread::Current());
183 worker_->PostDelayed(timeout_ms_, this, MSG_TIMEOUT);
184 CheckNetworks();
185 break;
186 case MSG_STOP:
187 // We're being stopped, free resources.
188 CleanUp();
189 break;
190 case MSG_TIMEOUT:
191 // We need to signal results on the main thread.
192 main_->Post(this, MSG_SIGNAL_RESULTS);
193 break;
194 case MSG_SIGNAL_RESULTS:
195 ASSERT(main_ == rtc::Thread::Current());
196 SignalCheckDone(this);
197 break;
198 default:
199 LOG(LS_ERROR) << "Unknown message: " << msg->message_id;
200 }
201 }
202
203 void ConnectivityChecker::OnProxyDetect(rtc::SignalThread* thread) {
204 ASSERT(worker_ == rtc::Thread::Current());
205 if (proxy_detect_->proxy().type != rtc::PROXY_NONE) {
206 SetProxyInfo(proxy_detect_->proxy());
207 }
208 }
209
210 void ConnectivityChecker::OnRequestDone(rtc::AsyncHttpRequest* request) {
211 ASSERT(worker_ == rtc::Thread::Current());
212 // Since we don't know what nic were actually used for the http request,
213 // for now, just use the first one.
214 std::vector<rtc::Network*> networks;
215 network_manager_->GetNetworks(&networks);
216 if (networks.empty()) {
217 LOG(LS_ERROR) << "No networks while registering http start.";
218 return;
219 }
220 rtc::ProxyInfo proxy_info = request->proxy();
221 NicMap::iterator i =
222 nics_.find(NicId(networks[0]->GetBestIP(), proxy_info.address));
223 if (i != nics_.end()) {
224 int port = request->port();
225 uint32 now = rtc::Time();
226 NicInfo* nic_info = &i->second;
227 if (port == rtc::HTTP_SECURE_PORT) {
228 nic_info->https.rtt = now - nic_info->https.start_time_ms;
229 } else {
230 LOG(LS_ERROR) << "Got response with unknown port: " << port;
231 }
232 } else {
233 LOG(LS_ERROR) << "No nic info found while receiving response.";
234 }
235 }
236
237 void ConnectivityChecker::OnConfigReady(
238 const std::string& username, const std::string& password,
239 const PortConfiguration* config, const rtc::ProxyInfo& proxy_info) {
240 ASSERT(worker_ == rtc::Thread::Current());
241
242 // Since we send requests on both HTTP and HTTPS we will get two
243 // configs per nic. Results from the second will overwrite the
244 // result from the first.
245 // TODO: Handle multiple pings on one nic.
246 CreateRelayPorts(username, password, config, proxy_info);
247 }
248
249 void ConnectivityChecker::OnRelayPortComplete(Port* port) {
250 ASSERT(worker_ == rtc::Thread::Current());
251 RelayPort* relay_port = reinterpret_cast<RelayPort*>(port);
252 const ProtocolAddress* address = relay_port->ServerAddress(0);
253 rtc::IPAddress ip = port->Network()->GetBestIP();
254 NicMap::iterator i = nics_.find(NicId(ip, port->proxy().address));
255 if (i != nics_.end()) {
256 // We have it already, add the new information.
257 NicInfo* nic_info = &i->second;
258 ConnectInfo* connect_info = NULL;
259 if (address) {
260 switch (address->proto) {
261 case PROTO_UDP:
262 connect_info = &nic_info->udp;
263 break;
264 case PROTO_TCP:
265 connect_info = &nic_info->tcp;
266 break;
267 case PROTO_SSLTCP:
268 connect_info = &nic_info->ssltcp;
269 break;
270 default:
271 LOG(LS_ERROR) << " relay address with bad protocol added";
272 }
273 if (connect_info) {
274 connect_info->rtt =
275 rtc::TimeSince(connect_info->start_time_ms);
276 }
277 }
278 } else {
279 LOG(LS_ERROR) << " got relay address for non-existing nic";
280 }
281 }
282
283 void ConnectivityChecker::OnStunPortComplete(Port* port) {
284 ASSERT(worker_ == rtc::Thread::Current());
285 const std::vector<Candidate> candidates = port->Candidates();
286 Candidate c = candidates[0];
287 rtc::IPAddress ip = port->Network()->GetBestIP();
288 NicMap::iterator i = nics_.find(NicId(ip, port->proxy().address));
289 if (i != nics_.end()) {
290 // We have it already, add the new information.
291 uint32 now = rtc::Time();
292 NicInfo* nic_info = &i->second;
293 nic_info->external_address = c.address();
294
295 nic_info->stun_server_addresses =
296 static_cast<StunPort*>(port)->server_addresses();
297 nic_info->stun.rtt = now - nic_info->stun.start_time_ms;
298 } else {
299 LOG(LS_ERROR) << "Got stun address for non-existing nic";
300 }
301 }
302
303 void ConnectivityChecker::OnStunPortError(Port* port) {
304 ASSERT(worker_ == rtc::Thread::Current());
305 LOG(LS_ERROR) << "Stun address error.";
306 rtc::IPAddress ip = port->Network()->GetBestIP();
307 NicMap::iterator i = nics_.find(NicId(ip, port->proxy().address));
308 if (i != nics_.end()) {
309 // We have it already, add the new information.
310 NicInfo* nic_info = &i->second;
311
312 nic_info->stun_server_addresses =
313 static_cast<StunPort*>(port)->server_addresses();
314 }
315 }
316
317 void ConnectivityChecker::OnRelayPortError(Port* port) {
318 ASSERT(worker_ == rtc::Thread::Current());
319 LOG(LS_ERROR) << "Relay address error.";
320 }
321
322 void ConnectivityChecker::OnNetworksChanged() {
323 ASSERT(worker_ == rtc::Thread::Current());
324 std::vector<rtc::Network*> networks;
325 network_manager_->GetNetworks(&networks);
326 if (networks.empty()) {
327 LOG(LS_ERROR) << "Machine has no networks; nothing to do";
328 return;
329 }
330 AllocatePorts();
331 }
332
333 HttpPortAllocator* ConnectivityChecker::CreatePortAllocator(
334 rtc::NetworkManager* network_manager,
335 const std::string& user_agent,
336 const std::string& relay_token) {
337 return new TestHttpPortAllocator(network_manager, user_agent, relay_token);
338 }
339
340 StunPort* ConnectivityChecker::CreateStunPort(
341 const std::string& username, const std::string& password,
342 const PortConfiguration* config, rtc::Network* network) {
343 return StunPort::Create(worker_,
344 socket_factory_.get(),
345 network,
346 network->GetBestIP(),
347 0,
348 0,
349 username,
350 password,
351 config->stun_servers,
352 std::string());
353 }
354
355 RelayPort* ConnectivityChecker::CreateRelayPort(
356 const std::string& username, const std::string& password,
357 const PortConfiguration* config, rtc::Network* network) {
358 return RelayPort::Create(worker_,
359 socket_factory_.get(),
360 network,
361 network->GetBestIP(),
362 port_allocator_->min_port(),
363 port_allocator_->max_port(),
364 username,
365 password);
366 }
367
368 void ConnectivityChecker::CreateRelayPorts(
369 const std::string& username, const std::string& password,
370 const PortConfiguration* config, const rtc::ProxyInfo& proxy_info) {
371 PortConfiguration::RelayList::const_iterator relay;
372 std::vector<rtc::Network*> networks;
373 network_manager_->GetNetworks(&networks);
374 if (networks.empty()) {
375 LOG(LS_ERROR) << "Machine has no networks; no relay ports created.";
376 return;
377 }
378 for (relay = config->relays.begin();
379 relay != config->relays.end(); ++relay) {
380 for (uint32 i = 0; i < networks.size(); ++i) {
381 NicMap::iterator iter =
382 nics_.find(NicId(networks[i]->GetBestIP(), proxy_info.address));
383 if (iter != nics_.end()) {
384 // TODO: Now setting the same start time for all protocols.
385 // This might affect accuracy, but since we are mainly looking for
386 // connect failures or number that stick out, this is good enough.
387 uint32 now = rtc::Time();
388 NicInfo* nic_info = &iter->second;
389 nic_info->udp.start_time_ms = now;
390 nic_info->tcp.start_time_ms = now;
391 nic_info->ssltcp.start_time_ms = now;
392
393 // Add the addresses of this protocol.
394 PortList::const_iterator relay_port;
395 for (relay_port = relay->ports.begin();
396 relay_port != relay->ports.end();
397 ++relay_port) {
398 RelayPort* port = CreateRelayPort(username, password,
399 config, networks[i]);
400 port->AddServerAddress(*relay_port);
401 port->AddExternalAddress(*relay_port);
402
403 nic_info->media_server_address = port->ServerAddress(0)->address;
404
405 // Listen to network events.
406 port->SignalPortComplete.connect(
407 this, &ConnectivityChecker::OnRelayPortComplete);
408 port->SignalPortError.connect(
409 this, &ConnectivityChecker::OnRelayPortError);
410
411 port->set_proxy(user_agent_, proxy_info);
412
413 // Start fetching an address for this port.
414 port->PrepareAddress();
415 ports_.push_back(port);
416 }
417 } else {
418 LOG(LS_ERROR) << "Failed to find nic info when creating relay ports.";
419 }
420 }
421 }
422 }
423
424 void ConnectivityChecker::AllocatePorts() {
425 const std::string username = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
426 const std::string password = rtc::CreateRandomString(ICE_PWD_LENGTH);
427 ServerAddresses stun_servers;
428 stun_servers.insert(stun_address_);
429 PortConfiguration config(stun_servers, username, password);
430 std::vector<rtc::Network*> networks;
431 network_manager_->GetNetworks(&networks);
432 if (networks.empty()) {
433 LOG(LS_ERROR) << "Machine has no networks; no ports will be allocated";
434 return;
435 }
436 rtc::ProxyInfo proxy_info = GetProxyInfo();
437 bool allocate_relay_ports = false;
438 for (uint32 i = 0; i < networks.size(); ++i) {
439 if (AddNic(networks[i]->GetBestIP(), proxy_info.address)) {
440 Port* port = CreateStunPort(username, password, &config, networks[i]);
441 if (port) {
442
443 // Listen to network events.
444 port->SignalPortComplete.connect(
445 this, &ConnectivityChecker::OnStunPortComplete);
446 port->SignalPortError.connect(
447 this, &ConnectivityChecker::OnStunPortError);
448
449 port->set_proxy(user_agent_, proxy_info);
450 port->PrepareAddress();
451 ports_.push_back(port);
452 allocate_relay_ports = true;
453 }
454 }
455 }
456
457 // If any new ip/proxy combinations were added, send a relay allocate.
458 if (allocate_relay_ports) {
459 AllocateRelayPorts();
460 }
461
462 // Initiate proxy detection.
463 InitiateProxyDetection();
464 }
465
466 void ConnectivityChecker::InitiateProxyDetection() {
467 // Only start if we haven't been started before.
468 if (!proxy_detect_) {
469 proxy_detect_ = new rtc::AutoDetectProxy(user_agent_);
470 rtc::Url<char> host_url("/", "relay.google.com",
471 rtc::HTTP_SECURE_PORT);
472 host_url.set_secure(true);
473 proxy_detect_->set_server_url(host_url.url());
474 proxy_detect_->SignalWorkDone.connect(
475 this, &ConnectivityChecker::OnProxyDetect);
476 proxy_detect_->Start();
477 }
478 }
479
480 void ConnectivityChecker::AllocateRelayPorts() {
481 // Currently we are using the 'default' nic for http(s) requests.
482 TestHttpPortAllocatorSession* allocator_session =
483 reinterpret_cast<TestHttpPortAllocatorSession*>(
484 port_allocator_->CreateSessionInternal(
485 "connectivity checker test content",
486 ICE_CANDIDATE_COMPONENT_RTP,
487 rtc::CreateRandomString(ICE_UFRAG_LENGTH),
488 rtc::CreateRandomString(ICE_PWD_LENGTH)));
489 allocator_session->set_proxy(port_allocator_->proxy());
490 allocator_session->SignalConfigReady.connect(
491 this, &ConnectivityChecker::OnConfigReady);
492 allocator_session->SignalRequestDone.connect(
493 this, &ConnectivityChecker::OnRequestDone);
494
495 // Try https only since using http would result in credentials being sent
496 // over the network unprotected.
497 RegisterHttpStart(rtc::HTTP_SECURE_PORT);
498 allocator_session->SendSessionRequest("relay.l.google.com",
499 rtc::HTTP_SECURE_PORT);
500
501 sessions_.push_back(allocator_session);
502 }
503
504 void ConnectivityChecker::RegisterHttpStart(int port) {
505 // Since we don't know what nic were actually used for the http request,
506 // for now, just use the first one.
507 std::vector<rtc::Network*> networks;
508 network_manager_->GetNetworks(&networks);
509 if (networks.empty()) {
510 LOG(LS_ERROR) << "No networks while registering http start.";
511 return;
512 }
513 rtc::ProxyInfo proxy_info = GetProxyInfo();
514 NicMap::iterator i =
515 nics_.find(NicId(networks[0]->GetBestIP(), proxy_info.address));
516 if (i != nics_.end()) {
517 uint32 now = rtc::Time();
518 NicInfo* nic_info = &i->second;
519 if (port == rtc::HTTP_SECURE_PORT) {
520 nic_info->https.start_time_ms = now;
521 } else {
522 LOG(LS_ERROR) << "Registering start time for unknown port: " << port;
523 }
524 } else {
525 LOG(LS_ERROR) << "Error, no nic info found while registering http start.";
526 }
527 }
528
529 } // namespace rtc
OLDNEW
« no previous file with comments | « webrtc/p2p/client/connectivitychecker.h ('k') | webrtc/p2p/client/connectivitychecker_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698