OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/host/it2me/it2me_host.h" | 5 #include "remoting/host/it2me/it2me_host.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
9 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" |
10 #include "base/threading/platform_thread.h" | 10 #include "base/threading/platform_thread.h" |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 policy_watcher_->StartWatching( | 75 policy_watcher_->StartWatching( |
76 base::Bind(&It2MeHost::OnPolicyUpdate, this), | 76 base::Bind(&It2MeHost::OnPolicyUpdate, this), |
77 base::Bind(&It2MeHost::OnPolicyError, this)); | 77 base::Bind(&It2MeHost::OnPolicyError, this)); |
78 | 78 |
79 // Switch to the network thread to start the actual connection. | 79 // Switch to the network thread to start the actual connection. |
80 host_context_->network_task_runner()->PostTask( | 80 host_context_->network_task_runner()->PostTask( |
81 FROM_HERE, base::Bind(&It2MeHost::ShowConfirmationPrompt, this)); | 81 FROM_HERE, base::Bind(&It2MeHost::ShowConfirmationPrompt, this)); |
82 } | 82 } |
83 | 83 |
84 void It2MeHost::Disconnect() { | 84 void It2MeHost::Disconnect() { |
85 if (!host_context_->network_task_runner()->BelongsToCurrentThread()) { | 85 DCHECK(task_runner_->BelongsToCurrentThread()); |
86 DCHECK(task_runner_->BelongsToCurrentThread()); | 86 host_context_->network_task_runner()->PostTask( |
87 host_context_->network_task_runner()->PostTask( | 87 FROM_HERE, base::Bind(&It2MeHost::Shutdown, this)); |
88 FROM_HERE, base::Bind(&It2MeHost::Disconnect, this)); | 88 } |
89 return; | 89 |
| 90 void It2MeHost::Shutdown() { |
| 91 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
| 92 |
| 93 confirmation_dialog_proxy_.reset(); |
| 94 |
| 95 host_event_logger_.reset(); |
| 96 if (host_) { |
| 97 host_->RemoveStatusObserver(this); |
| 98 host_.reset(); |
90 } | 99 } |
91 | 100 |
92 switch (state_) { | 101 register_request_.reset(); |
93 case kDisconnected: | 102 host_status_logger_.reset(); |
94 ShutdownOnNetworkThread(); | 103 signal_strategy_.reset(); |
95 return; | |
96 | 104 |
97 case kStarting: | 105 // Post tasks to delete UI objects on the UI thread. |
98 SetState(kDisconnecting, ""); | 106 host_context_->ui_task_runner()->DeleteSoon( |
99 SetState(kDisconnected, ""); | 107 FROM_HERE, desktop_environment_factory_.release()); |
100 ShutdownOnNetworkThread(); | 108 host_context_->ui_task_runner()->DeleteSoon(FROM_HERE, |
101 return; | 109 policy_watcher_.release()); |
102 | 110 |
103 case kDisconnecting: | 111 SetState(kDisconnected, ""); |
104 return; | |
105 | |
106 default: | |
107 SetState(kDisconnecting, ""); | |
108 | |
109 if (!host_) { | |
110 SetState(kDisconnected, ""); | |
111 ShutdownOnNetworkThread(); | |
112 return; | |
113 } | |
114 | |
115 // Deleting the host destroys SignalStrategy synchronously, but | |
116 // SignalStrategy::Listener handlers are not allowed to destroy | |
117 // SignalStrategy, so post task to destroy the host later. | |
118 host_context_->network_task_runner()->PostTask( | |
119 FROM_HERE, base::Bind(&It2MeHost::ShutdownOnNetworkThread, this)); | |
120 return; | |
121 } | |
122 } | 112 } |
123 | 113 |
124 void It2MeHost::RequestNatPolicy() { | 114 void It2MeHost::RequestNatPolicy() { |
125 if (!host_context_->network_task_runner()->BelongsToCurrentThread()) { | 115 if (!host_context_->network_task_runner()->BelongsToCurrentThread()) { |
126 DCHECK(task_runner_->BelongsToCurrentThread()); | 116 DCHECK(task_runner_->BelongsToCurrentThread()); |
127 host_context_->network_task_runner()->PostTask( | 117 host_context_->network_task_runner()->PostTask( |
128 FROM_HERE, base::Bind(&It2MeHost::RequestNatPolicy, this)); | 118 FROM_HERE, base::Bind(&It2MeHost::RequestNatPolicy, this)); |
129 return; | 119 return; |
130 } | 120 } |
131 | 121 |
(...skipping 23 matching lines...) Expand all Loading... |
155 base::Bind(&It2MeHost::OnConfirmationResult, base::Unretained(this))); | 145 base::Bind(&It2MeHost::OnConfirmationResult, base::Unretained(this))); |
156 } | 146 } |
157 | 147 |
158 void It2MeHost::OnConfirmationResult(It2MeConfirmationDialog::Result result) { | 148 void It2MeHost::OnConfirmationResult(It2MeConfirmationDialog::Result result) { |
159 switch (result) { | 149 switch (result) { |
160 case It2MeConfirmationDialog::Result::OK: | 150 case It2MeConfirmationDialog::Result::OK: |
161 ReadPolicyAndConnect(); | 151 ReadPolicyAndConnect(); |
162 break; | 152 break; |
163 | 153 |
164 case It2MeConfirmationDialog::Result::CANCEL: | 154 case It2MeConfirmationDialog::Result::CANCEL: |
165 Disconnect(); | 155 Shutdown(); |
166 break; | 156 break; |
167 | 157 |
168 default: | 158 default: |
169 NOTREACHED(); | 159 NOTREACHED(); |
170 return; | 160 return; |
171 } | 161 } |
172 } | 162 } |
173 | 163 |
174 void It2MeHost::ReadPolicyAndConnect() { | 164 void It2MeHost::ReadPolicyAndConnect() { |
175 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 165 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 HostEventLogger::Create(host_->AsWeakPtr(), kApplicationName); | 255 HostEventLogger::Create(host_->AsWeakPtr(), kApplicationName); |
266 | 256 |
267 // Connect signaling and start the host. | 257 // Connect signaling and start the host. |
268 signal_strategy_->Connect(); | 258 signal_strategy_->Connect(); |
269 host_->Start(xmpp_server_config_.username); | 259 host_->Start(xmpp_server_config_.username); |
270 | 260 |
271 SetState(kRequestedAccessCode, ""); | 261 SetState(kRequestedAccessCode, ""); |
272 return; | 262 return; |
273 } | 263 } |
274 | 264 |
275 void It2MeHost::ShutdownOnNetworkThread() { | |
276 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | |
277 DCHECK(state_ == kDisconnecting || state_ == kDisconnected); | |
278 | |
279 confirmation_dialog_proxy_.reset(); | |
280 | |
281 if (state_ == kDisconnecting) { | |
282 host_event_logger_.reset(); | |
283 host_->RemoveStatusObserver(this); | |
284 host_.reset(); | |
285 | |
286 register_request_.reset(); | |
287 host_status_logger_.reset(); | |
288 signal_strategy_.reset(); | |
289 SetState(kDisconnected, ""); | |
290 } | |
291 | |
292 host_context_->ui_task_runner()->PostTask( | |
293 FROM_HERE, base::Bind(&It2MeHost::ShutdownOnUiThread, this)); | |
294 } | |
295 | |
296 void It2MeHost::ShutdownOnUiThread() { | |
297 DCHECK(host_context_->ui_task_runner()->BelongsToCurrentThread()); | |
298 | |
299 // Destroy the DesktopEnvironmentFactory, to free thread references. | |
300 desktop_environment_factory_.reset(); | |
301 | |
302 // Stop listening for policy updates. | |
303 policy_watcher_.reset(); | |
304 } | |
305 | |
306 void It2MeHost::OnAccessDenied(const std::string& jid) { | 265 void It2MeHost::OnAccessDenied(const std::string& jid) { |
307 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 266 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
308 | 267 |
309 ++failed_login_attempts_; | 268 ++failed_login_attempts_; |
310 if (failed_login_attempts_ == kMaxLoginAttempts) { | 269 if (failed_login_attempts_ == kMaxLoginAttempts) { |
311 Disconnect(); | 270 Shutdown(); |
312 } | 271 } |
313 } | 272 } |
314 | 273 |
315 void It2MeHost::OnClientAuthenticated(const std::string& jid) { | 274 void It2MeHost::OnClientConnected(const std::string& jid) { |
316 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 275 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
317 | 276 |
318 if (state_ == kDisconnecting) { | 277 // ChromotingHost doesn't allow multiple concurrent connection and the |
319 // Ignore the new connection if we are disconnecting. | 278 // host is destroyed in OnClientDisconnected() after the first connection. |
320 return; | 279 CHECK_NE(state_, kConnected); |
321 } | |
322 if (state_ == kConnected) { | |
323 // If we already connected another client then one of the connections may be | |
324 // an attacker, so both are suspect and we have to reject the second | |
325 // connection and shutdown the host. | |
326 host_->RejectAuthenticatingClient(); | |
327 Disconnect(); | |
328 return; | |
329 } | |
330 | 280 |
331 std::string client_username = jid; | 281 std::string client_username = jid; |
332 size_t pos = client_username.find('/'); | 282 size_t pos = client_username.find('/'); |
333 if (pos != std::string::npos) | 283 if (pos != std::string::npos) |
334 client_username.replace(pos, std::string::npos, ""); | 284 client_username.replace(pos, std::string::npos, ""); |
335 | 285 |
336 HOST_LOG << "Client " << client_username << " connected."; | 286 HOST_LOG << "Client " << client_username << " connected."; |
337 | 287 |
338 // Pass the client user name to the script object before changing state. | 288 // Pass the client user name to the script object before changing state. |
339 task_runner_->PostTask( | 289 task_runner_->PostTask( |
340 FROM_HERE, base::Bind(&It2MeHost::Observer::OnClientAuthenticated, | 290 FROM_HERE, base::Bind(&It2MeHost::Observer::OnClientAuthenticated, |
341 observer_, client_username)); | 291 observer_, client_username)); |
342 | 292 |
343 SetState(kConnected, ""); | 293 SetState(kConnected, ""); |
344 } | 294 } |
345 | 295 |
346 void It2MeHost::OnClientDisconnected(const std::string& jid) { | 296 void It2MeHost::OnClientDisconnected(const std::string& jid) { |
347 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 297 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
348 | 298 |
349 Disconnect(); | 299 Shutdown(); |
350 } | 300 } |
351 | 301 |
352 void It2MeHost::OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies) { | 302 void It2MeHost::OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies) { |
353 // The policy watcher runs on the |ui_task_runner|. | 303 // The policy watcher runs on the |ui_task_runner|. |
354 if (!host_context_->network_task_runner()->BelongsToCurrentThread()) { | 304 if (!host_context_->network_task_runner()->BelongsToCurrentThread()) { |
355 host_context_->network_task_runner()->PostTask( | 305 host_context_->network_task_runner()->PostTask( |
356 FROM_HERE, | 306 FROM_HERE, |
357 base::Bind(&It2MeHost::OnPolicyUpdate, this, base::Passed(&policies))); | 307 base::Bind(&It2MeHost::OnPolicyUpdate, this, base::Passed(&policies))); |
358 return; | 308 return; |
359 } | 309 } |
(...skipping 21 matching lines...) Expand all Loading... |
381 } | 331 } |
382 | 332 |
383 void It2MeHost::UpdateNatPolicy(bool nat_traversal_enabled) { | 333 void It2MeHost::UpdateNatPolicy(bool nat_traversal_enabled) { |
384 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 334 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
385 | 335 |
386 VLOG(2) << "UpdateNatPolicy: " << nat_traversal_enabled; | 336 VLOG(2) << "UpdateNatPolicy: " << nat_traversal_enabled; |
387 | 337 |
388 // When transitioning from enabled to disabled, force disconnect any | 338 // When transitioning from enabled to disabled, force disconnect any |
389 // existing session. | 339 // existing session. |
390 if (nat_traversal_enabled_ && !nat_traversal_enabled && IsConnected()) { | 340 if (nat_traversal_enabled_ && !nat_traversal_enabled && IsConnected()) { |
391 Disconnect(); | 341 Shutdown(); |
392 } | 342 } |
393 | 343 |
394 nat_traversal_enabled_ = nat_traversal_enabled; | 344 nat_traversal_enabled_ = nat_traversal_enabled; |
395 | 345 |
396 // Notify the web-app of the policy setting. | 346 // Notify the web-app of the policy setting. |
397 task_runner_->PostTask( | 347 task_runner_->PostTask( |
398 FROM_HERE, base::Bind(&It2MeHost::Observer::OnNatPolicyChanged, | 348 FROM_HERE, base::Bind(&It2MeHost::Observer::OnNatPolicyChanged, |
399 observer_, nat_traversal_enabled_)); | 349 observer_, nat_traversal_enabled_)); |
400 } | 350 } |
401 | 351 |
402 void It2MeHost::UpdateHostDomainPolicy(const std::string& host_domain) { | 352 void It2MeHost::UpdateHostDomainPolicy(const std::string& host_domain) { |
403 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 353 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
404 | 354 |
405 VLOG(2) << "UpdateHostDomainPolicy: " << host_domain; | 355 VLOG(2) << "UpdateHostDomainPolicy: " << host_domain; |
406 | 356 |
407 // When setting a host domain policy, force disconnect any existing session. | 357 // When setting a host domain policy, force disconnect any existing session. |
408 if (!host_domain.empty() && IsConnected()) { | 358 if (!host_domain.empty() && IsConnected()) { |
409 Disconnect(); | 359 Shutdown(); |
410 } | 360 } |
411 | 361 |
412 required_host_domain_ = host_domain; | 362 required_host_domain_ = host_domain; |
413 } | 363 } |
414 | 364 |
415 It2MeHost::~It2MeHost() { | 365 It2MeHost::~It2MeHost() { |
416 // Check that resources that need to be torn down on the UI thread are gone. | 366 // Check that resources that need to be torn down on the UI thread are gone. |
417 DCHECK(!desktop_environment_factory_.get()); | 367 DCHECK(!desktop_environment_factory_.get()); |
418 DCHECK(!policy_watcher_.get()); | 368 DCHECK(!policy_watcher_.get()); |
419 } | 369 } |
420 | 370 |
421 void It2MeHost::SetState(It2MeHostState state, | 371 void It2MeHost::SetState(It2MeHostState state, |
422 const std::string& error_message) { | 372 const std::string& error_message) { |
423 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 373 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
424 | 374 |
425 switch (state_) { | 375 switch (state_) { |
426 case kDisconnected: | 376 case kDisconnected: |
427 DCHECK(state == kStarting || | 377 DCHECK(state == kStarting || |
428 state == kError) << state; | 378 state == kError) << state; |
429 break; | 379 break; |
430 case kStarting: | 380 case kStarting: |
431 DCHECK(state == kRequestedAccessCode || | 381 DCHECK(state == kRequestedAccessCode || |
432 state == kDisconnecting || | 382 state == kDisconnected || |
433 state == kError || | 383 state == kError || |
434 state == kInvalidDomainError) << state; | 384 state == kInvalidDomainError) << state; |
435 break; | 385 break; |
436 case kRequestedAccessCode: | 386 case kRequestedAccessCode: |
437 DCHECK(state == kReceivedAccessCode || | 387 DCHECK(state == kReceivedAccessCode || |
438 state == kDisconnecting || | 388 state == kDisconnected || |
439 state == kError) << state; | 389 state == kError) << state; |
440 break; | 390 break; |
441 case kReceivedAccessCode: | 391 case kReceivedAccessCode: |
442 DCHECK(state == kConnected || | 392 DCHECK(state == kConnected || |
443 state == kDisconnecting || | 393 state == kDisconnected || |
444 state == kError) << state; | 394 state == kError) << state; |
445 break; | 395 break; |
446 case kConnected: | 396 case kConnected: |
447 DCHECK(state == kDisconnecting || | 397 DCHECK(state == kDisconnected || |
448 state == kDisconnected || | |
449 state == kError) << state; | 398 state == kError) << state; |
450 break; | 399 break; |
451 case kDisconnecting: | 400 case kError: |
452 DCHECK(state == kDisconnected) << state; | 401 DCHECK(state == kDisconnected) << state; |
453 break; | 402 break; |
454 case kError: | |
455 DCHECK(state == kDisconnecting) << state; | |
456 break; | |
457 case kInvalidDomainError: | 403 case kInvalidDomainError: |
458 DCHECK(state == kDisconnecting) << state; | 404 DCHECK(state == kDisconnected) << state; |
459 break; | 405 break; |
460 }; | 406 }; |
461 | 407 |
462 state_ = state; | 408 state_ = state; |
463 | 409 |
464 // Post a state-change notification to the web-app. | 410 // Post a state-change notification to the web-app. |
465 task_runner_->PostTask( | 411 task_runner_->PostTask( |
466 FROM_HERE, base::Bind(&It2MeHost::Observer::OnStateChanged, | 412 FROM_HERE, base::Bind(&It2MeHost::Observer::OnStateChanged, |
467 observer_, state, error_message)); | 413 observer_, state, error_message)); |
468 } | 414 } |
469 | 415 |
470 bool It2MeHost::IsConnected() const { | 416 bool It2MeHost::IsConnected() const { |
471 return state_ == kRequestedAccessCode || state_ == kReceivedAccessCode || | 417 return state_ == kRequestedAccessCode || state_ == kReceivedAccessCode || |
472 state_ == kConnected; | 418 state_ == kConnected; |
473 } | 419 } |
474 | 420 |
475 void It2MeHost::OnReceivedSupportID( | 421 void It2MeHost::OnReceivedSupportID( |
476 const std::string& support_id, | 422 const std::string& support_id, |
477 const base::TimeDelta& lifetime, | 423 const base::TimeDelta& lifetime, |
478 const std::string& error_message) { | 424 const std::string& error_message) { |
479 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 425 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
480 | 426 |
481 if (!error_message.empty()) { | 427 if (!error_message.empty()) { |
482 SetState(kError, error_message); | 428 SetState(kError, error_message); |
483 Disconnect(); | 429 Shutdown(); |
484 return; | 430 return; |
485 } | 431 } |
486 | 432 |
487 std::string host_secret = GenerateSupportHostSecret(); | 433 std::string host_secret = GenerateSupportHostSecret(); |
488 std::string access_code = support_id + host_secret; | 434 std::string access_code = support_id + host_secret; |
489 | 435 |
490 std::string local_certificate = host_key_pair_->GenerateCertificate(); | 436 std::string local_certificate = host_key_pair_->GenerateCertificate(); |
491 if (local_certificate.empty()) { | 437 if (local_certificate.empty()) { |
492 std::string error_message = "Failed to generate host certificate."; | 438 std::string error_message = "Failed to generate host certificate."; |
493 LOG(ERROR) << error_message; | 439 LOG(ERROR) << error_message; |
494 SetState(kError, error_message); | 440 SetState(kError, error_message); |
495 Disconnect(); | 441 Shutdown(); |
496 return; | 442 return; |
497 } | 443 } |
498 | 444 |
499 scoped_ptr<protocol::AuthenticatorFactory> factory( | 445 scoped_ptr<protocol::AuthenticatorFactory> factory( |
500 new protocol::It2MeHostAuthenticatorFactory( | 446 new protocol::It2MeHostAuthenticatorFactory( |
501 local_certificate, host_key_pair_, access_code)); | 447 local_certificate, host_key_pair_, access_code)); |
502 host_->SetAuthenticatorFactory(factory.Pass()); | 448 host_->SetAuthenticatorFactory(factory.Pass()); |
503 | 449 |
504 // Pass the Access Code to the script object before changing state. | 450 // Pass the Access Code to the script object before changing state. |
505 task_runner_->PostTask( | 451 task_runner_->PostTask( |
(...skipping 25 matching lines...) Expand all Loading... |
531 scoped_ptr<It2MeConfirmationDialogFactory> confirmation_dialog_factory( | 477 scoped_ptr<It2MeConfirmationDialogFactory> confirmation_dialog_factory( |
532 new It2MeConfirmationDialogFactory()); | 478 new It2MeConfirmationDialogFactory()); |
533 scoped_ptr<PolicyWatcher> policy_watcher = | 479 scoped_ptr<PolicyWatcher> policy_watcher = |
534 PolicyWatcher::Create(policy_service_, context->file_task_runner()); | 480 PolicyWatcher::Create(policy_service_, context->file_task_runner()); |
535 return new It2MeHost(context.Pass(), policy_watcher.Pass(), | 481 return new It2MeHost(context.Pass(), policy_watcher.Pass(), |
536 confirmation_dialog_factory.Pass(), | 482 confirmation_dialog_factory.Pass(), |
537 observer, xmpp_server_config, directory_bot_jid); | 483 observer, xmpp_server_config, directory_bot_jid); |
538 } | 484 } |
539 | 485 |
540 } // namespace remoting | 486 } // namespace remoting |
OLD | NEW |