1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 // 5 // This file implements a standalone host process for Me2Me. 6 7 #include <string> 8 9 #include "base/at_exit.h" 10 #include "base/bind.h" 11 #include "base/callback.h" 12 #include "base/command_line.h" 13 #include "base/debug/alias.h" 14 #include "base/file_util.h" 15 #include "base/files/file_path.h" 16 #include "base/memory/scoped_ptr.h" 17 #include "base/message_loop/message_loop.h" 18 #include "base/single_thread_task_runner.h" 19 #include "base/strings/string_number_conversions.h" 20 #include "base/strings/string_util.h" 21 #include "base/strings/utf_string_conversions.h" 22 #include "base/synchronization/waitable_event.h" 23 #include "base/threading/thread.h" 24 #include "build/build_config.h" 25 #include "crypto/nss_util.h" 26 #include "ipc/ipc_channel.h" 27 #include "ipc/ipc_channel_proxy.h" 28 #include "ipc/ipc_listener.h" 29 #include "media/base/media.h" 30 #include "net/base/network_change_notifier.h" 31 #include "net/socket/client_socket_factory.h" 32 #include "net/socket/ssl_server_socket.h" 33 #include "net/url_request/url_fetcher.h" 34 #include "remoting/base/auto_thread_task_runner.h" 35 #include "remoting/base/breakpad.h" 36 #include "remoting/base/constants.h" 37 #include "remoting/base/logging.h" 38 #include "remoting/base/rsa_key_pair.h" 39 #include "remoting/base/util.h" 40 #include "remoting/host/branding.h" 41 #include "remoting/host/chromoting_host.h" 42 #include "remoting/host/chromoting_host_context.h" 43 #include "remoting/host/chromoting_messages.h" 44 #include "remoting/host/config_file_watcher.h" 45 #include "remoting/host/config_watcher.h" 46 #include "remoting/host/desktop_environment.h" 47 #include "remoting/host/desktop_session_connector.h" 48 #include "remoting/host/dns_blackhole_checker.h" 49 #include "remoting/host/heartbeat_sender.h" 50 #include "remoting/host/host_change_notification_listener.h" 51 #include "remoting/host/host_config.h" 52 #include "remoting/host/host_event_logger.h" 53 #include "remoting/host/host_exit_codes.h" 54 #include "remoting/host/host_main.h" 55 #include "remoting/host/host_status_sender.h" 56 #include "remoting/host/ipc_constants.h" 57 #include "remoting/host/ipc_desktop_environment.h" 58 #include "remoting/host/ipc_host_event_logger.h" 59 #include "remoting/host/json_host_config.h" 60 #include "remoting/host/log_to_server.h" 61 #include "remoting/host/logging.h" 62 #include "remoting/host/me2me_desktop_environment.h" 63 #include "remoting/host/pairing_registry_delegate.h" 64 #include "remoting/host/policy_hack/policy_watcher.h" 65 #include "remoting/host/service_urls.h" 66 #include "remoting/host/session_manager_factory.h" 67 #include "remoting/host/signaling_connector.h" 68 #include "remoting/host/token_validator_factory_impl.h" 69 #include "remoting/host/usage_stats_consent.h" 70 #include "remoting/host/username.h" 71 #include "remoting/jingle_glue/network_settings.h" 72 #include "remoting/jingle_glue/xmpp_signal_strategy.h" 73 #include "remoting/protocol/me2me_host_authenticator_factory.h" 74 #include "remoting/protocol/pairing_registry.h" 75 #include "remoting/protocol/token_validator.h" 76 77 #if defined(OS_POSIX) 78 #include <signal.h> 79 #include <sys/types.h> 80 #include <unistd.h> 81 #include "base/file_descriptor_posix.h" 82 #include "remoting/host/pam_authorization_factory_posix.h" 83 #include "remoting/host/posix/signal_handler.h" 84 #endif // defined(OS_POSIX) 85 86 #if defined(OS_MACOSX) 87 #include "base/mac/scoped_cftyperef.h" 88 #endif // defined(OS_MACOSX) 89 90 #if defined(OS_LINUX) 91 #include <gtk/gtk.h> 92 #include "remoting/host/audio_capturer_linux.h" 93 #endif // defined(OS_LINUX) 94 95 #if defined(OS_WIN) 96 #include <commctrl.h> 97 #include "base/win/registry.h" 98 #include "base/win/scoped_handle.h" 99 #include "remoting/host/pairing_registry_delegate_win.h" 100 #include "remoting/host/win/session_desktop_environment.h" 101 #endif // defined(OS_WIN) 102 using remoting::protocol::PairingRegistry; 103 104 namespace { 105 106 // This is used for tagging system event logs. 107 const char kApplicationName[] = "chromoting"; 108 109 #if defined(OS_LINUX) 110 // The command line switch used to pass name of the pipe to capture audio on 111 // linux. 112 const char kAudioPipeSwitchName[] = "audio-pipe-name"; 113 114 // The command line switch used to pass name of the unix domain socket used to 115 // listen for gnubby requests. 116 const char kAuthSocknameSwitchName[] = "ssh-auth-sockname"; 117 #endif // defined(OS_LINUX) 118 119 // The command line switch used by the parent to request the host to signal it 120 // when it is successfully started. 121 const char kSignalParentSwitchName[] = "signal-parent"; 122 123 // Command line switch used to enable VP9 encoding. 124 const char kEnableVp9SwitchName[] = "enable-vp9"; 125 126 // Value used for --host-config option to indicate that the path must be read 127 // from stdin. 128 const char kStdinConfigPath[] = "-"; 129 130 } // namespace 131 132 namespace remoting { 133 134 class HostProcess 135 : public ConfigWatcher::Delegate, 136 public HeartbeatSender::Listener, 137 public HostChangeNotificationListener::Listener, 138 public IPC::Listener, 139 public base::RefCountedThreadSafe<HostProcess> { 140 public: 141 HostProcess(scoped_ptr<ChromotingHostContext> context, 142 int* exit_code_out); 143 144 // ConfigWatcher::Delegate interface. 145 virtual void OnConfigUpdated(const std::string& serialized_config) OVERRIDE; 146 virtual void OnConfigWatcherError() OVERRIDE; 147 148 // IPC::Listener implementation. 149 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; 150 virtual void OnChannelError() OVERRIDE; 151 152 // HeartbeatSender::Listener overrides. 153 virtual void OnHeartbeatSuccessful() OVERRIDE; 154 virtual void OnUnknownHostIdError() OVERRIDE; 155 156 // HostChangeNotificationListener::Listener overrides. 157 virtual void OnHostDeleted() OVERRIDE; 158 159 // Initializes the pairing registry on Windows. 160 void OnInitializePairingRegistry( 161 IPC::PlatformFileForTransit privileged_key, 162 IPC::PlatformFileForTransit unprivileged_key); 163 164 private: 165 enum HostState { 166 // Host process has just been started. Waiting for config and policies to be 167 // read from the disk. 168 HOST_INITIALIZING, 169 170 // Host is started and running. 171 HOST_STARTED, 172 173 // Host is being stopped and will need to be started again. 174 HOST_STOPPING_TO_RESTART, 175 176 // Host is being stopped. 177 HOST_STOPPING, 178 179 // Host has been stopped. 180 HOST_STOPPED, 181 182 // Allowed state transitions: 183 // INITIALIZING->STARTED 184 // INITIALIZING->STOPPED 185 // STARTED->STOPPING_TO_RESTART 186 // STARTED->STOPPING 187 // STOPPING_TO_RESTART->STARTED 188 // STOPPING_TO_RESTART->STOPPING 189 // STOPPING->STOPPED 190 // STOPPED->STARTED 191 // 192 // |host_| must be NULL in INITIALIZING and STOPPED states and not-NULL in 193 // all other states. 194 }; 195 196 friend class base::RefCountedThreadSafe<HostProcess>; 197 virtual ~HostProcess(); 198 199 void StartOnNetworkThread(); 200 201 #if defined(OS_POSIX) 202 // Callback passed to RegisterSignalHandler() to handle SIGTERM events. 203 void SigTermHandler(int signal_number); 204 #endif 205 206 // Called to initialize resources on the UI thread. 207 void StartOnUiThread(); 208 209 // Initializes IPC control channel and config file path from |cmd_line|. 210 // Called on the UI thread. 211 bool InitWithCommandLine(const base::CommandLine* cmd_line); 212 213 // Called on the UI thread to start monitoring the configuration file. 214 void StartWatchingConfigChanges(); 215 216 // Called on the network thread to set the host's Authenticator factory. 217 void CreateAuthenticatorFactory(); 218 219 // Tear down resources that run on the UI thread. 220 void ShutdownOnUiThread(); 221 222 // Applies the host config, returning true if successful. 223 bool ApplyConfig(scoped_ptr<JsonHostConfig> config); 224 225 // Handles policy updates, by calling On*PolicyUpdate methods. 226 void OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies); 227 void ApplyHostDomainPolicy(); 228 void ApplyUsernamePolicy(); 229 bool OnHostDomainPolicyUpdate(base::DictionaryValue* policies); 230 bool OnUsernamePolicyUpdate(base::DictionaryValue* policies); 231 bool OnNatPolicyUpdate(base::DictionaryValue* policies); 232 bool OnRelayPolicyUpdate(base::DictionaryValue* policies); 233 bool OnUdpPortPolicyUpdate(base::DictionaryValue* policies); 234 bool OnCurtainPolicyUpdate(base::DictionaryValue* policies); 235 bool OnHostTalkGadgetPrefixPolicyUpdate(base::DictionaryValue* policies); 236 bool OnHostTokenUrlPolicyUpdate(base::DictionaryValue* policies); 237 bool OnPairingPolicyUpdate(base::DictionaryValue* policies); 238 bool OnGnubbyAuthPolicyUpdate(base::DictionaryValue* policies); 239 240 void StartHost(); 241 242 void OnAuthFailed(); 243 244 void RestartHost(); 245 246 // Stops the host and shuts down the process with the specified |exit_code|. 247 void ShutdownHost(HostExitCodes exit_code); 248 249 void ScheduleHostShutdown(); 250 251 void ShutdownOnNetworkThread(); 252 253 // Crashes the process in response to a daemon's request. The daemon passes 254 // the location of the code that detected the fatal error resulted in this 255 // request. 256 void OnCrash(const std::string& function_name, 257 const std::string& file_name, 258 const int& line_number); 259 260 scoped_ptr<ChromotingHostContext> context_; 261 262 // Created on the UI thread but used from the network thread. 263 scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_; 264 265 // Accessed on the UI thread. 266 scoped_ptr<IPC::ChannelProxy> daemon_channel_; 267 268 // XMPP server/remoting bot configuration (initialized from the command line). 269 XmppSignalStrategy::XmppServerConfig xmpp_server_config_; 270 std::string directory_bot_jid_; 271 272 // Created on the UI thread but used from the network thread. 273 base::FilePath host_config_path_; 274 std::string host_config_; 275 scoped_ptr<DesktopEnvironmentFactory> desktop_environment_factory_; 276 277 // Accessed on the network thread. 278 HostState state_; 279 280 scoped_ptr<ConfigWatcher> config_watcher_; 281 282 std::string host_id_; 283 protocol::SharedSecretHash host_secret_hash_; 284 scoped_refptr<RsaKeyPair> key_pair_; 285 std::string oauth_refresh_token_; 286 std::string serialized_config_; 287 std::string host_owner_; 288 bool use_service_account_; 289 bool enable_vp9_; 290 291 scoped_ptr<policy_hack::PolicyWatcher> policy_watcher_; 292 std::string host_domain_; 293 bool host_username_match_required_; 294 bool allow_nat_traversal_; 295 bool allow_relay_; 296 int min_udp_port_; 297 int max_udp_port_; 298 std::string talkgadget_prefix_; 299 bool allow_pairing_; 300 301 bool curtain_required_; 302 ThirdPartyAuthConfig third_party_auth_config_; 303 bool enable_gnubby_auth_; 304 305 scoped_ptr<OAuthTokenGetter> oauth_token_getter_; 306 scoped_ptr<XmppSignalStrategy> signal_strategy_; 307 scoped_ptr<SignalingConnector> signaling_connector_; 308 scoped_ptr<HeartbeatSender> heartbeat_sender_; 309 scoped_ptr<HostStatusSender> host_status_sender_; 310 scoped_ptr<HostChangeNotificationListener> host_change_notification_listener_; 311 scoped_ptr<LogToServer> log_to_server_; 312 scoped_ptr<HostEventLogger> host_event_logger_; 313 314 scoped_ptr<ChromotingHost> host_; 315 316 // Used to keep this HostProcess alive until it is shutdown. 317 scoped_refptr<HostProcess> self_; 318 319 #if defined(REMOTING_MULTI_PROCESS) 320 DesktopSessionConnector* desktop_session_connector_; 321 #endif // defined(REMOTING_MULTI_PROCESS) 322 323 int* exit_code_out_; 324 bool signal_parent_; 325 326 scoped_ptr<PairingRegistry::Delegate> pairing_registry_delegate_; 327 }; 328 329 HostProcess::HostProcess(scoped_ptr<ChromotingHostContext> context, 330 int* exit_code_out) 331 : context_(context.Pass()), 332 state_(HOST_INITIALIZING), 333 use_service_account_(false), 334 enable_vp9_(false), 335 host_username_match_required_(false), 336 allow_nat_traversal_(true), 337 allow_relay_(true), 338 min_udp_port_(0), 339 max_udp_port_(0), 340 allow_pairing_(true), 341 curtain_required_(false), 342 enable_gnubby_auth_(false), 343 #if defined(REMOTING_MULTI_PROCESS) 344 desktop_session_connector_(NULL), 345 #endif // defined(REMOTING_MULTI_PROCESS) 346 self_(this), 347 exit_code_out_(exit_code_out), 348 signal_parent_(false) { 349 StartOnUiThread(); 350 } 351 352 HostProcess::~HostProcess() { 353 // Verify that UI components have been torn down. 354 DCHECK(!config_watcher_); 355 DCHECK(!daemon_channel_); 356 DCHECK(!desktop_environment_factory_); 357 358 // We might be getting deleted on one of the threads the |host_context| owns, 359 // so we need to post it back to the caller thread to safely join & delete the 360 // threads it contains. This will go away when we move to AutoThread. 361 // |context_release()| will null |context_| before the method is invoked, so 362 // we need to pull out the task-runner on which to call DeleteSoon first. 363 scoped_refptr<base::SingleThreadTaskRunner> task_runner = 364 context_->ui_task_runner(); 365 task_runner->DeleteSoon(FROM_HERE, context_.release()); 366 } 367 368 bool HostProcess::InitWithCommandLine(const base::CommandLine* cmd_line) { 369 #if defined(REMOTING_MULTI_PROCESS) 370 // Parse the handle value and convert it to a handle/file descriptor. 371 std::string channel_name = 372 cmd_line->GetSwitchValueASCII(kDaemonPipeSwitchName); 373 374 int pipe_handle = 0; 375 if (channel_name.empty() || 376 !base::StringToInt(channel_name, &pipe_handle)) { 377 LOG(ERROR) << "Invalid '" << kDaemonPipeSwitchName 378 << "' value: " << channel_name; 379 return false; 380 } 381 382 #if defined(OS_WIN) 383 base::win::ScopedHandle pipe(reinterpret_cast<HANDLE>(pipe_handle)); 384 IPC::ChannelHandle channel_handle(pipe); 385 #elif defined(OS_POSIX) 386 base::FileDescriptor pipe(pipe_handle, true); 387 IPC::ChannelHandle channel_handle(channel_name, pipe); 388 #endif // defined(OS_POSIX) 389 390 // Connect to the daemon process. 391 daemon_channel_ = IPC::ChannelProxy::Create(channel_handle, 392 IPC::Channel::MODE_CLIENT, 393 this, 394 context_->network_task_runner()); 395 #else // !defined(REMOTING_MULTI_PROCESS) 396 // Connect to the daemon process. 397 std::string channel_name = 398 cmd_line->GetSwitchValueASCII(kDaemonPipeSwitchName); 399 if (!channel_name.empty()) { 400 daemon_channel_ = 401 IPC::ChannelProxy::Create(channel_name, 402 IPC::Channel::MODE_CLIENT, 403 this, 404 context_->network_task_runner().get()); 405 } 406 407 if (cmd_line->HasSwitch(kHostConfigSwitchName)) { 408 host_config_path_ = cmd_line->GetSwitchValuePath(kHostConfigSwitchName); 409 410 // Read config from stdin if necessary. 411 if (host_config_path_ == base::FilePath(kStdinConfigPath)) { 412 char buf[4096]; 413 size_t len; 414 while ((len = fread(buf, 1, sizeof(buf), stdin)) > 0) { 415 host_config_.append(buf, len); 416 } 417 } 418 } else { 419 base::FilePath default_config_dir = remoting::GetConfigDir(); 420 host_config_path_ = default_config_dir.Append(kDefaultHostConfigFile); 421 } 422 423 if (host_config_path_ != base::FilePath(kStdinConfigPath) && 424 !base::PathExists(host_config_path_)) { 425 LOG(ERROR) << "Can't find host config at " << host_config_path_.value(); 426 return false; 427 } 428 #endif // !defined(REMOTING_MULTI_PROCESS) 429 430 // Ignore certificate requests - the host currently has no client certificate 431 // support, so ignoring certificate requests allows connecting to servers that 432 // request, but don't require, a certificate (optional client authentication). 433 net::URLFetcher::SetIgnoreCertificateRequests(true); 434 435 ServiceUrls* service_urls = ServiceUrls::GetInstance(); 436 bool xmpp_server_valid = net::ParseHostAndPort( 437 service_urls->xmpp_server_address(), 438 &xmpp_server_config_.host, &xmpp_server_config_.port); 439 if (!xmpp_server_valid) { 440 LOG(ERROR) << "Invalid XMPP server: " << 441 service_urls->xmpp_server_address(); 442 return false; 443 } 444 xmpp_server_config_.use_tls = service_urls->xmpp_server_use_tls(); 445 directory_bot_jid_ = service_urls->directory_bot_jid(); 446 447 signal_parent_ = cmd_line->HasSwitch(kSignalParentSwitchName); 448 449 return true; 450 } 451 452 void HostProcess::OnConfigUpdated( 453 const std::string& serialized_config) { 454 if (!context_->network_task_runner()->BelongsToCurrentThread()) { 455 context_->network_task_runner()->PostTask(FROM_HERE, 456 base::Bind(&HostProcess::OnConfigUpdated, this, serialized_config)); 457 return; 458 } 459 460 // Filter out duplicates. 461 if (serialized_config_ == serialized_config) 462 return; 463 464 HOST_LOG << "Processing new host configuration."; 465 466 serialized_config_ = serialized_config; 467 scoped_ptr<JsonHostConfig> config(new JsonHostConfig(base::FilePath())); 468 if (!config->SetSerializedData(serialized_config)) { 469 LOG(ERROR) << "Invalid configuration."; 470 ShutdownHost(kInvalidHostConfigurationExitCode); 471 return; 472 } 473 474 if (!ApplyConfig(config.Pass())) { 475 LOG(ERROR) << "Failed to apply the configuration."; 476 ShutdownHost(kInvalidHostConfigurationExitCode); 477 return; 478 } 479 480 if (state_ == HOST_INITIALIZING) { 481 // TODO(sergeyu): Currently OnPolicyUpdate() assumes that host config is 482 // already loaded so PolicyWatcher has to be started here. Separate policy 483 // loading from policy verifications and move |policy_watcher_| 484 // initialization to StartOnNetworkThread(). 485 policy_watcher_.reset( 486 policy_hack::PolicyWatcher::Create(context_->file_task_runner())); 487 policy_watcher_->StartWatching( 488 base::Bind(&HostProcess::OnPolicyUpdate, base::Unretained(this))); 489 } else { 490 // Reapply policies that could be affected by a new config. 491 ApplyHostDomainPolicy(); 492 ApplyUsernamePolicy(); 493 494 if (state_ == HOST_STARTED) { 495 // TODO(sergeyu): Here we assume that PIN is the only part of the config 496 // that may change while the service is running. Change ApplyConfig() to 497 // detect other changes in the config and restart host if necessary here. 498 CreateAuthenticatorFactory(); 499 } 500 } 501 } 502 503 void HostProcess::OnConfigWatcherError() { 504 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 505 ShutdownHost(kInvalidHostConfigurationExitCode); 506 } 507 508 void HostProcess::StartOnNetworkThread() { 509 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 510 511 #if !defined(REMOTING_MULTI_PROCESS) 512 if (host_config_path_ == base::FilePath(kStdinConfigPath)) { 513 // Process config we've read from stdin. 514 OnConfigUpdated(host_config_); 515 } else { 516 // Start watching the host configuration file. 517 config_watcher_.reset(new ConfigFileWatcher(context_->network_task_runner(), 518 context_->file_task_runner(), 519 host_config_path_)); 520 config_watcher_->Watch(this); 521 } 522 #endif // !defined(REMOTING_MULTI_PROCESS) 523 524 #if defined(OS_POSIX) 525 remoting::RegisterSignalHandler( 526 SIGTERM, 527 base::Bind(&HostProcess::SigTermHandler, base::Unretained(this))); 528 #endif // defined(OS_POSIX) 529 } 530 531 #if defined(OS_POSIX) 532 void HostProcess::SigTermHandler(int signal_number) { 533 DCHECK(signal_number == SIGTERM); 534 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 535 HOST_LOG << "Caught SIGTERM: Shutting down..."; 536 ShutdownHost(kSuccessExitCode); 537 } 538 #endif // OS_POSIX 539 540 void HostProcess::CreateAuthenticatorFactory() { 541 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 542 543 if (state_ != HOST_STARTED) 544 return; 545 546 std::string local_certificate = key_pair_->GenerateCertificate(); 547 if (local_certificate.empty()) { 548 LOG(ERROR) << "Failed to generate host certificate."; 549 ShutdownHost(kInitializationFailed); 550 return; 551 } 552 553 scoped_refptr<PairingRegistry> pairing_registry = NULL; 554 if (allow_pairing_) { 555 if (!pairing_registry_delegate_) 556 pairing_registry_delegate_ = CreatePairingRegistryDelegate(); 557 558 if (pairing_registry_delegate_) { 559 pairing_registry = new PairingRegistry(context_->file_task_runner(), 560 pairing_registry_delegate_.Pass()); 561 } 562 } 563 564 scoped_ptr<protocol::AuthenticatorFactory> factory; 565 566 if (third_party_auth_config_.is_empty()) { 567 factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithSharedSecret( 568 use_service_account_, host_owner_, local_certificate, key_pair_, 569 host_secret_hash_, pairing_registry); 570 571 } else if (third_party_auth_config_.is_valid()) { 572 scoped_ptr<protocol::TokenValidatorFactory> token_validator_factory( 573 new TokenValidatorFactoryImpl( 574 third_party_auth_config_, 575 key_pair_, context_->url_request_context_getter())); 576 factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth( 577 use_service_account_, host_owner_, local_certificate, key_pair_, 578 token_validator_factory.Pass()); 579 580 } else { 581 // TODO(rmsousa): If the policy is bad the host should not go online. It 582 // should keep running, but not connected, until the policies are fixed. 583 // Having it show up as online and then reject all clients is misleading. 584 LOG(ERROR) << "One of the third-party token URLs is empty or invalid. " 585 << "Host will reject all clients until policies are corrected. " 586 << "TokenUrl: " << third_party_auth_config_.token_url << ", " 587 << "TokenValidationUrl: " 588 << third_party_auth_config_.token_validation_url; 589 factory = protocol::Me2MeHostAuthenticatorFactory::CreateRejecting(); 590 } 591 592 #if defined(OS_POSIX) 593 // On Linux and Mac, perform a PAM authorization step after authentication. 594 factory.reset(new PamAuthorizationFactory(factory.Pass())); 595 #endif 596 host_->SetAuthenticatorFactory(factory.Pass()); 597 598 host_->set_pairing_registry(pairing_registry); 599 } 600 601 // IPC::Listener implementation. 602 bool HostProcess::OnMessageReceived(const IPC::Message& message) { 603 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread()); 604 605 #if defined(REMOTING_MULTI_PROCESS) 606 bool handled = true; 607 IPC_BEGIN_MESSAGE_MAP(HostProcess, message) 608 IPC_MESSAGE_HANDLER(ChromotingDaemonMsg_Crash, OnCrash) 609 IPC_MESSAGE_HANDLER(ChromotingDaemonNetworkMsg_Configuration, 610 OnConfigUpdated) 611 IPC_MESSAGE_HANDLER(ChromotingDaemonNetworkMsg_InitializePairingRegistry, 612 OnInitializePairingRegistry) 613 IPC_MESSAGE_FORWARD( 614 ChromotingDaemonNetworkMsg_DesktopAttached, 615 desktop_session_connector_, 616 DesktopSessionConnector::OnDesktopSessionAgentAttached) 617 IPC_MESSAGE_FORWARD(ChromotingDaemonNetworkMsg_TerminalDisconnected, 618 desktop_session_connector_, 619 DesktopSessionConnector::OnTerminalDisconnected) 620 IPC_MESSAGE_UNHANDLED(handled = false) 621 IPC_END_MESSAGE_MAP() 622 623 CHECK(handled) << "Received unexpected IPC type: " << message.type(); 624 return handled; 625 626 #else // !defined(REMOTING_MULTI_PROCESS) 627 return false; 628 #endif // !defined(REMOTING_MULTI_PROCESS) 629 } 630 631 void HostProcess::OnChannelError() { 632 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread()); 633 634 // Shutdown the host if the daemon process disconnects the IPC channel. 635 context_->network_task_runner()->PostTask( 636 FROM_HERE, 637 base::Bind(&HostProcess::ShutdownHost, this, kSuccessExitCode)); 638 } 639 640 void HostProcess::StartOnUiThread() { 641 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread()); 642 643 if (!InitWithCommandLine(base::CommandLine::ForCurrentProcess())) { 644 // Shutdown the host if the command line is invalid. 645 context_->network_task_runner()->PostTask( 646 FROM_HERE, base::Bind(&HostProcess::ShutdownHost, this, 647 kUsageExitCode)); 648 return; 649 } 650 651 #if defined(OS_LINUX) 652 // If an audio pipe is specific on the command-line then initialize 653 // AudioCapturerLinux to capture from it. 654 base::FilePath audio_pipe_name = base::CommandLine::ForCurrentProcess()-> 655 GetSwitchValuePath(kAudioPipeSwitchName); 656 if (!audio_pipe_name.empty()) { 657 remoting::AudioCapturerLinux::InitializePipeReader( 658 context_->audio_task_runner(), audio_pipe_name); 659 } 660 661 base::FilePath gnubby_socket_name = base::CommandLine::ForCurrentProcess()-> 662 GetSwitchValuePath(kAuthSocknameSwitchName); 663 if (!gnubby_socket_name.empty()) 664 remoting::GnubbyAuthHandler::SetGnubbySocketName(gnubby_socket_name); 665 #endif // defined(OS_LINUX) 666 667 // Create a desktop environment factory appropriate to the build type & 668 // platform. 669 #if defined(OS_WIN) 670 IpcDesktopEnvironmentFactory* desktop_environment_factory = 671 new IpcDesktopEnvironmentFactory( 672 context_->audio_task_runner(), 673 context_->network_task_runner(), 674 context_->video_capture_task_runner(), 675 context_->network_task_runner(), 676 daemon_channel_.get()); 677 desktop_session_connector_ = desktop_environment_factory; 678 #else // !defined(OS_WIN) 679 DesktopEnvironmentFactory* desktop_environment_factory = 680 new Me2MeDesktopEnvironmentFactory( 681 context_->network_task_runner(), 682 context_->input_task_runner(), 683 context_->ui_task_runner()); 684 #endif // !defined(OS_WIN) 685 686 desktop_environment_factory_.reset(desktop_environment_factory); 687 desktop_environment_factory_->SetEnableGnubbyAuth(enable_gnubby_auth_); 688 689 context_->network_task_runner()->PostTask( 690 FROM_HERE, 691 base::Bind(&HostProcess::StartOnNetworkThread, this)); 692 } 693 694 void HostProcess::ShutdownOnUiThread() { 695 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread()); 696 697 // Tear down resources that need to be torn down on the UI thread. 698 network_change_notifier_.reset(); 699 daemon_channel_.reset(); 700 desktop_environment_factory_.reset(); 701 702 // It is now safe for the HostProcess to be deleted. 703 self_ = NULL; 704 705 #if defined(OS_LINUX) 706 // Cause the global AudioPipeReader to be freed, otherwise the audio 707 // thread will remain in-use and prevent the process from exiting. 708 // TODO(wez): DesktopEnvironmentFactory should own the pipe reader. 709 // See crbug.com/161373 and crbug.com/104544. 710 AudioCapturerLinux::InitializePipeReader(NULL, base::FilePath()); 711 #endif 712 } 713 714 // Overridden from HeartbeatSender::Listener 715 void HostProcess::OnUnknownHostIdError() { 716 LOG(ERROR) << "Host ID not found."; 717 ShutdownHost(kInvalidHostIdExitCode); 718 } 719 720 void HostProcess::OnHeartbeatSuccessful() { 721 HOST_LOG << "Host ready to receive connections."; 722 #if defined(OS_POSIX) 723 if (signal_parent_) { 724 kill(getppid(), SIGUSR1); 725 signal_parent_ = false; 726 } 727 #endif 728 } 729 730 void HostProcess::OnHostDeleted() { 731 LOG(ERROR) << "Host was deleted from the directory."; 732 ShutdownHost(kInvalidHostIdExitCode); 733 } 734 735 void HostProcess::OnInitializePairingRegistry( 736 IPC::PlatformFileForTransit privileged_key, 737 IPC::PlatformFileForTransit unprivileged_key) { 738 DCHECK(!pairing_registry_delegate_); 739 740 #if defined(OS_WIN) 741 // Initialize the pairing registry delegate. 742 scoped_ptr<PairingRegistryDelegateWin> delegate( 743 new PairingRegistryDelegateWin()); 744 bool result = delegate->SetRootKeys( 745 reinterpret_cast<HKEY>( 746 IPC::PlatformFileForTransitToPlatformFile(privileged_key)), 747 reinterpret_cast<HKEY>( 748 IPC::PlatformFileForTransitToPlatformFile(unprivileged_key))); 749 if (!result) 750 return; 751 752 pairing_registry_delegate_ = delegate.PassAs<PairingRegistry::Delegate>(); 753 #else // !defined(OS_WIN) 754 NOTREACHED(); 755 #endif // !defined(OS_WIN) 756 } 757 758 // Applies the host config, returning true if successful. 759 bool HostProcess::ApplyConfig(scoped_ptr<JsonHostConfig> config) { 760 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 761 762 if (!config->GetString(kHostIdConfigPath, &host_id_)) { 763 LOG(ERROR) << "host_id is not defined in the config."; 764 return false; 765 } 766 767 std::string key_base64; 768 if (!config->GetString(kPrivateKeyConfigPath, &key_base64)) { 769 LOG(ERROR) << "Private key couldn't be read from the config file."; 770 return false; 771 } 772 773 key_pair_ = RsaKeyPair::FromString(key_base64); 774 if (!key_pair_.get()) { 775 LOG(ERROR) << "Invalid private key in the config file."; 776 return false; 777 } 778 779 std::string host_secret_hash_string; 780 if (!config->GetString(kHostSecretHashConfigPath, 781 &host_secret_hash_string)) { 782 host_secret_hash_string = "plain:"; 783 } 784 785 if (!host_secret_hash_.Parse(host_secret_hash_string)) { 786 LOG(ERROR) << "Invalid host_secret_hash."; 787 return false; 788 } 789 790 // Use an XMPP connection to the Talk network for session signalling. 791 if (!config->GetString(kXmppLoginConfigPath, &xmpp_server_config_.username) || 792 !(config->GetString(kXmppAuthTokenConfigPath, 793 &xmpp_server_config_.auth_token) || 794 config->GetString(kOAuthRefreshTokenConfigPath, 795 &oauth_refresh_token_))) { 796 LOG(ERROR) << "XMPP credentials are not defined in the config."; 797 return false; 798 } 799 800 if (!oauth_refresh_token_.empty()) { 801 // SignalingConnector is responsible for getting OAuth token. 802 xmpp_server_config_.auth_token = ""; 803 xmpp_server_config_.auth_service = "oauth2"; 804 } else if (!config->GetString(kXmppAuthServiceConfigPath, 805 &xmpp_server_config_.auth_service)) { 806 // For the me2me host, we default to ClientLogin token for chromiumsync 807 // because earlier versions of the host had no HTTP stack with which to 808 // request an OAuth2 access token. 809 xmpp_server_config_.auth_service = kChromotingTokenDefaultServiceName; 810 } 811 812 if (config->GetString(kHostOwnerConfigPath, &host_owner_)) { 813 // Service account configs have a host_owner, different from the xmpp_login. 814 use_service_account_ = true; 815 } else { 816 // User credential configs only have an xmpp_login, which is also the owner. 817 host_owner_ = xmpp_server_config_.username; 818 use_service_account_ = false; 819 } 820 821 // Allow offering of VP9 encoding to be overridden by the command-line. 822 if (CommandLine::ForCurrentProcess()->HasSwitch(kEnableVp9SwitchName)) { 823 enable_vp9_ = true; 824 } else { 825 config->GetBoolean(kEnableVp9ConfigPath, &enable_vp9_); 826 } 827 828 return true; 829 } 830 831 void HostProcess::OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies) { 832 if (!context_->network_task_runner()->BelongsToCurrentThread()) { 833 context_->network_task_runner()->PostTask(FROM_HERE, base::Bind( 834 &HostProcess::OnPolicyUpdate, this, base::Passed(&policies))); 835 return; 836 } 837 838 bool restart_required = false; 839 restart_required |= OnHostDomainPolicyUpdate(policies.get()); 840 restart_required |= OnCurtainPolicyUpdate(policies.get()); 841 // Note: UsernamePolicyUpdate must run after OnCurtainPolicyUpdate. 842 restart_required |= OnUsernamePolicyUpdate(policies.get()); 843 restart_required |= OnNatPolicyUpdate(policies.get()); 844 restart_required |= OnRelayPolicyUpdate(policies.get()); 845 restart_required |= OnUdpPortPolicyUpdate(policies.get()); 846 restart_required |= OnHostTalkGadgetPrefixPolicyUpdate(policies.get()); 847 restart_required |= OnHostTokenUrlPolicyUpdate(policies.get()); 848 restart_required |= OnPairingPolicyUpdate(policies.get()); 849 restart_required |= OnGnubbyAuthPolicyUpdate(policies.get()); 850 851 if (state_ == HOST_INITIALIZING) { 852 StartHost(); 853 } else if (state_ == HOST_STARTED && restart_required) { 854 RestartHost(); 855 } 856 } 857 858 void HostProcess::ApplyHostDomainPolicy() { 859 HOST_LOG << "Policy sets host domain: " << host_domain_; 860 if (!host_domain_.empty() && 861 !EndsWith(host_owner_, std::string("@") + host_domain_, false)) { 862 LOG(ERROR) << "The host domain does not match the policy."; 863 ShutdownHost(kInvalidHostDomainExitCode); 864 } 865 } 866 867 bool HostProcess::OnHostDomainPolicyUpdate(base::DictionaryValue* policies) { 868 // Returns true if the host has to be restarted after this policy update. 869 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 870 871 if (!policies->GetString(policy_hack::PolicyWatcher::kHostDomainPolicyName, 872 &host_domain_)) { 873 return false; 874 } 875 876 ApplyHostDomainPolicy(); 877 return false; 878 } 879 880 void HostProcess::ApplyUsernamePolicy() { 881 if (host_username_match_required_) { 882 HOST_LOG << "Policy requires host username match."; 883 std::string username = GetUsername(); 884 bool shutdown = username.empty() || 885 !StartsWithASCII(host_owner_, username + std::string("@"), 886 false); 887 888 #if defined(OS_MACOSX) 889 // On Mac, we run as root at the login screen, so the username won't match. 890 // However, there's no need to enforce the policy at the login screen, as 891 // the client will have to reconnect if a login occurs. 892 if (shutdown && getuid() == 0) { 893 shutdown = false; 894 } 895 #endif 896 897 // Curtain-mode on Windows presents the standard OS login prompt to the user 898 // for each connection, removing the need for an explicit user-name matching 899 // check. 900 #if defined(OS_WIN) && defined(REMOTING_RDP_SESSION) 901 if (curtain_required_) 902 return; 903 #endif // defined(OS_WIN) && defined(REMOTING_RDP_SESSION) 904 905 // Shutdown the host if the username does not match. 906 if (shutdown) { 907 LOG(ERROR) << "The host username does not match."; 908 ShutdownHost(kUsernameMismatchExitCode); 909 } 910 } else { 911 HOST_LOG << "Policy does not require host username match."; 912 } 913 } 914 915 bool HostProcess::OnUsernamePolicyUpdate(base::DictionaryValue* policies) { 916 // Returns false: never restart the host after this policy update. 917 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 918 919 if (!policies->GetBoolean( 920 policy_hack::PolicyWatcher::kHostMatchUsernamePolicyName, 921 &host_username_match_required_)) { 922 return false; 923 } 924 925 ApplyUsernamePolicy(); 926 return false; 927 } 928 929 bool HostProcess::OnNatPolicyUpdate(base::DictionaryValue* policies) { 930 // Returns true if the host has to be restarted after this policy update. 931 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 932 933 if (!policies->GetBoolean(policy_hack::PolicyWatcher::kNatPolicyName, 934 &allow_nat_traversal_)) { 935 return false; 936 } 937 938 if (allow_nat_traversal_) { 939 HOST_LOG << "Policy enables NAT traversal."; 940 } else { 941 HOST_LOG << "Policy disables NAT traversal."; 942 } 943 return true; 944 } 945 946 bool HostProcess::OnRelayPolicyUpdate(base::DictionaryValue* policies) { 947 // Returns true if the host has to be restarted after this policy update. 948 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 949 950 if (!policies->GetBoolean(policy_hack::PolicyWatcher::kRelayPolicyName, 951 &allow_relay_)) { 952 return false; 953 } 954 955 if (allow_relay_) { 956 HOST_LOG << "Policy enables use of relay server."; 957 } else { 958 HOST_LOG << "Policy disables use of relay server."; 959 } 960 return true; 961 } 962 963 bool HostProcess::OnUdpPortPolicyUpdate(base::DictionaryValue* policies) { 964 // Returns true if the host has to be restarted after this policy update. 965 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 966 967 std::string udp_port_range; 968 if (!policies->GetString(policy_hack::PolicyWatcher::kUdpPortRangePolicyName, 969 &udp_port_range)) { 970 return false; 971 } 972 973 // Use default values if policy setting is empty or invalid. 974 int min_udp_port = 0; 975 int max_udp_port = 0; 976 if (!udp_port_range.empty() && 977 !NetworkSettings::ParsePortRange(udp_port_range, &min_udp_port, 978 &max_udp_port)) { 979 LOG(WARNING) << "Invalid port range policy: \"" << udp_port_range 980 << "\". Using default values."; 981 } 982 983 if (min_udp_port_ != min_udp_port || max_udp_port_ != max_udp_port) { 984 if (min_udp_port != 0 && max_udp_port != 0) { 985 HOST_LOG << "Policy restricts UDP port range to [" << min_udp_port 986 << ", " << max_udp_port << "]"; 987 } else { 988 HOST_LOG << "Policy does not restrict UDP port range."; 989 } 990 min_udp_port_ = min_udp_port; 991 max_udp_port_ = max_udp_port; 992 return true; 993 } 994 return false; 995 } 996 997 bool HostProcess::OnCurtainPolicyUpdate(base::DictionaryValue* policies) { 998 // Returns true if the host has to be restarted after this policy update. 999 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 1000 1001 if (!policies->GetBoolean( 1002 policy_hack::PolicyWatcher::kHostRequireCurtainPolicyName, 1003 &curtain_required_)) { 1004 return false; 1005 } 1006 1007 #if defined(OS_MACOSX) 1008 if (curtain_required_) { 1009 // When curtain mode is in effect on Mac, the host process runs in the 1010 // user's switched-out session, but launchd will also run an instance at 1011 // the console login screen. Even if no user is currently logged-on, we 1012 // can't support remote-access to the login screen because the current host 1013 // process model disconnects the client during login, which would leave 1014 // the logged in session un-curtained on the console until they reconnect. 1015 // 1016 // TODO(jamiewalch): Fix this once we have implemented the multi-process 1017 // daemon architecture (crbug.com/134894) 1018 if (getuid() == 0) { 1019 LOG(ERROR) << "Running the host in the console login session is yet not " 1020 "supported."; 1021 ShutdownHost(kLoginScreenNotSupportedExitCode); 1022 return false; 1023 } 1024 } 1025 #endif 1026 1027 if (curtain_required_) { 1028 HOST_LOG << "Policy requires curtain-mode."; 1029 } else { 1030 HOST_LOG << "Policy does not require curtain-mode."; 1031 } 1032 1033 if (host_) 1034 host_->SetEnableCurtaining(curtain_required_); 1035 return false; 1036 } 1037 1038 bool HostProcess::OnHostTalkGadgetPrefixPolicyUpdate( 1039 base::DictionaryValue* policies) { 1040 // Returns true if the host has to be restarted after this policy update. 1041 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 1042 1043 if (!policies->GetString( 1044 policy_hack::PolicyWatcher::kHostTalkGadgetPrefixPolicyName, 1045 &talkgadget_prefix_)) { 1046 return false; 1047 } 1048 1049 HOST_LOG << "Policy sets talkgadget prefix: " << talkgadget_prefix_; 1050 return true; 1051 } 1052 1053 bool HostProcess::OnHostTokenUrlPolicyUpdate(base::DictionaryValue* policies) { 1054 // Returns true if the host has to be restarted after this policy update. 1055 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 1056 1057 bool token_policy_changed = false; 1058 std::string token_url_string; 1059 if (policies->GetString( 1060 policy_hack::PolicyWatcher::kHostTokenUrlPolicyName, 1061 &token_url_string)) { 1062 token_policy_changed = true; 1063 third_party_auth_config_.token_url = GURL(token_url_string); 1064 } 1065 std::string token_validation_url_string; 1066 if (policies->GetString( 1067 policy_hack::PolicyWatcher::kHostTokenValidationUrlPolicyName, 1068 &token_validation_url_string)) { 1069 token_policy_changed = true; 1070 third_party_auth_config_.token_validation_url = 1071 GURL(token_validation_url_string); 1072 } 1073 if (policies->GetString( 1074 policy_hack::PolicyWatcher::kHostTokenValidationCertIssuerPolicyName, 1075 &third_party_auth_config_.token_validation_cert_issuer)) { 1076 token_policy_changed = true; 1077 } 1078 1079 if (token_policy_changed) { 1080 HOST_LOG << "Policy sets third-party token URLs: " 1081 << "TokenUrl: " 1082 << third_party_auth_config_.token_url << ", " 1083 << "TokenValidationUrl: " 1084 << third_party_auth_config_.token_validation_url << ", " 1085 << "TokenValidationCertificateIssuer: " 1086 << third_party_auth_config_.token_validation_cert_issuer; 1087 } 1088 return token_policy_changed; 1089 } 1090 1091 bool HostProcess::OnPairingPolicyUpdate(base::DictionaryValue* policies) { 1092 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 1093 1094 if (!policies->GetBoolean( 1095 policy_hack::PolicyWatcher::kHostAllowClientPairing, 1096 &allow_pairing_)) { 1097 return false; 1098 } 1099 1100 if (allow_pairing_) { 1101 HOST_LOG << "Policy enables client pairing."; 1102 } else { 1103 HOST_LOG << "Policy disables client pairing."; 1104 } 1105 return true; 1106 } 1107 1108 bool HostProcess::OnGnubbyAuthPolicyUpdate(base::DictionaryValue* policies) { 1109 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 1110 1111 if (!policies->GetBoolean( 1112 policy_hack::PolicyWatcher::kHostAllowGnubbyAuthPolicyName, 1113 &enable_gnubby_auth_)) { 1114 return false; 1115 } 1116 1117 if (enable_gnubby_auth_) { 1118 HOST_LOG << "Policy enables gnubby auth."; 1119 } else { 1120 HOST_LOG << "Policy disables gnubby auth."; 1121 } 1122 1123 if (desktop_environment_factory_) 1124 desktop_environment_factory_->SetEnableGnubbyAuth(enable_gnubby_auth_); 1125 1126 return true; 1127 } 1128 1129 void HostProcess::StartHost() { 1130 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 1131 DCHECK(!host_); 1132 DCHECK(!signal_strategy_.get()); 1133 DCHECK(state_ == HOST_INITIALIZING || state_ == HOST_STOPPING_TO_RESTART || 1134 state_ == HOST_STOPPED) << state_; 1135 state_ = HOST_STARTED; 1136 1137 signal_strategy_.reset( 1138 new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(), 1139 context_->url_request_context_getter(), 1140 xmpp_server_config_)); 1141 1142 scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker( 1143 new DnsBlackholeChecker(context_->url_request_context_getter(), 1144 talkgadget_prefix_)); 1145 1146 // Create a NetworkChangeNotifier for use by the signaling connector. 1147 network_change_notifier_.reset(net::NetworkChangeNotifier::Create()); 1148 1149 signaling_connector_.reset(new SignalingConnector( 1150 signal_strategy_.get(), 1151 dns_blackhole_checker.Pass(), 1152 base::Bind(&HostProcess::OnAuthFailed, this))); 1153 1154 if (!oauth_refresh_token_.empty()) { 1155 scoped_ptr<OAuthTokenGetter::OAuthCredentials> oauth_credentials; 1156 oauth_credentials.reset( 1157 new OAuthTokenGetter::OAuthCredentials( 1158 xmpp_server_config_.username, oauth_refresh_token_, 1159 use_service_account_)); 1160 1161 oauth_token_getter_.reset(new OAuthTokenGetter( 1162 oauth_credentials.Pass(), context_->url_request_context_getter(), 1163 false)); 1164 1165 signaling_connector_->EnableOAuth(oauth_token_getter_.get()); 1166 } 1167 1168 uint32 network_flags = 0; 1169 if (allow_nat_traversal_) { 1170 network_flags = NetworkSettings::NAT_TRAVERSAL_STUN | 1171 NetworkSettings::NAT_TRAVERSAL_OUTGOING; 1172 if (allow_relay_) 1173 network_flags |= NetworkSettings::NAT_TRAVERSAL_RELAY; 1174 } 1175 1176 NetworkSettings network_settings(network_flags); 1177 1178 if (min_udp_port_ && max_udp_port_) { 1179 network_settings.min_port = min_udp_port_; 1180 network_settings.max_port = max_udp_port_; 1181 } else if (!allow_nat_traversal_) { 1182 // For legacy reasons we have to restrict the port range to a set of default 1183 // values when nat traversal is disabled, even if the port range was not 1184 // set in policy. 1185 network_settings.min_port = NetworkSettings::kDefaultMinPort; 1186 network_settings.max_port = NetworkSettings::kDefaultMaxPort; 1187 } 1188 1189 host_.reset(new ChromotingHost( 1190 signal_strategy_.get(), 1191 desktop_environment_factory_.get(), 1192 CreateHostSessionManager(signal_strategy_.get(), network_settings, 1193 context_->url_request_context_getter()), 1194 context_->audio_task_runner(), 1195 context_->input_task_runner(), 1196 context_->video_capture_task_runner(), 1197 context_->video_encode_task_runner(), 1198 context_->network_task_runner(), 1199 context_->ui_task_runner())); 1200 1201 if (enable_vp9_) { 1202 scoped_ptr<protocol::CandidateSessionConfig> config = 1203 host_->protocol_config()->Clone(); 1204 config->EnableVideoCodec(protocol::ChannelConfig::CODEC_VP9); 1205 host_->set_protocol_config(config.Pass()); 1206 } 1207 1208 // TODO(simonmorris): Get the maximum session duration from a policy. 1209 #if defined(OS_LINUX) 1210 host_->SetMaximumSessionDuration(base::TimeDelta::FromHours(20)); 1211 #endif 1212 1213 heartbeat_sender_.reset(new HeartbeatSender( 1214 this, host_id_, signal_strategy_.get(), key_pair_, 1215 directory_bot_jid_)); 1216 1217 host_status_sender_.reset(new HostStatusSender( 1218 host_id_, signal_strategy_.get(), key_pair_, directory_bot_jid_)); 1219 1220 host_change_notification_listener_.reset(new HostChangeNotificationListener( 1221 this, host_id_, signal_strategy_.get(), directory_bot_jid_)); 1222 1223 log_to_server_.reset( 1224 new LogToServer(host_->AsWeakPtr(), ServerLogEntry::ME2ME, 1225 signal_strategy_.get(), directory_bot_jid_)); 1226 1227 // Set up repoting the host status notifications. 1228 #if defined(REMOTING_MULTI_PROCESS) 1229 host_event_logger_.reset( 1230 new IpcHostEventLogger(host_->AsWeakPtr(), daemon_channel_.get())); 1231 #else // !defined(REMOTING_MULTI_PROCESS) 1232 host_event_logger_ = 1233 HostEventLogger::Create(host_->AsWeakPtr(), kApplicationName); 1234 #endif // !defined(REMOTING_MULTI_PROCESS) 1235 1236 host_->SetEnableCurtaining(curtain_required_); 1237 host_->Start(host_owner_); 1238 1239 CreateAuthenticatorFactory(); 1240 } 1241 1242 void HostProcess::OnAuthFailed() { 1243 ShutdownHost(kInvalidOauthCredentialsExitCode); 1244 } 1245 1246 void HostProcess::RestartHost() { 1247 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 1248 DCHECK_EQ(state_, HOST_STARTED); 1249 1250 state_ = HOST_STOPPING_TO_RESTART; 1251 ShutdownOnNetworkThread(); 1252 } 1253 1254 void HostProcess::ShutdownHost(HostExitCodes exit_code) { 1255 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 1256 1257 *exit_code_out_ = exit_code; 1258 1259 switch (state_) { 1260 case HOST_INITIALIZING: 1261 state_ = HOST_STOPPING; 1262 ShutdownOnNetworkThread(); 1263 break; 1264 1265 case HOST_STARTED: 1266 state_ = HOST_STOPPING; 1267 host_status_sender_->SendOfflineStatus(exit_code); 1268 ScheduleHostShutdown(); 1269 break; 1270 1271 case HOST_STOPPING_TO_RESTART: 1272 state_ = HOST_STOPPING; 1273 break; 1274 1275 case HOST_STOPPING: 1276 case HOST_STOPPED: 1277 // Host is already stopped or being stopped. No action is required. 1278 break; 1279 } 1280 } 1281 1282 // TODO(weitaosu): shut down the host once we get an ACK for the offline status 1283 // XMPP message. 1284 void HostProcess::ScheduleHostShutdown() { 1285 // Delay the shutdown by 2 second to allow SendOfflineStatus to complete. 1286 context_->network_task_runner()->PostDelayedTask( 1287 FROM_HERE, 1288 base::Bind(&HostProcess::ShutdownOnNetworkThread, base::Unretained(this)), 1289 base::TimeDelta::FromSeconds(2)); 1290 } 1291 1292 void HostProcess::ShutdownOnNetworkThread() { 1293 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 1294 1295 host_.reset(); 1296 host_event_logger_.reset(); 1297 log_to_server_.reset(); 1298 heartbeat_sender_.reset(); 1299 host_status_sender_.reset(); 1300 host_change_notification_listener_.reset(); 1301 signaling_connector_.reset(); 1302 oauth_token_getter_.reset(); 1303 signal_strategy_.reset(); 1304 network_change_notifier_.reset(); 1305 1306 if (state_ == HOST_STOPPING_TO_RESTART) { 1307 StartHost(); 1308 } else if (state_ == HOST_STOPPING) { 1309 state_ = HOST_STOPPED; 1310 1311 if (policy_watcher_.get()) { 1312 base::WaitableEvent done_event(true, false); 1313 policy_watcher_->StopWatching(&done_event); 1314 done_event.Wait(); 1315 policy_watcher_.reset(); 1316 } 1317 1318 config_watcher_.reset(); 1319 1320 // Complete the rest of shutdown on the main thread. 1321 context_->ui_task_runner()->PostTask( 1322 FROM_HERE, 1323 base::Bind(&HostProcess::ShutdownOnUiThread, this)); 1324 } else { 1325 // This method is only called in STOPPING_TO_RESTART and STOPPING states. 1326 NOTREACHED(); 1327 } 1328 } 1329 1330 void HostProcess::OnCrash(const std::string& function_name, 1331 const std::string& file_name, 1332 const int& line_number) { 1333 char message[1024]; 1334 base::snprintf(message, sizeof(message), 1335 "Requested by %s at %s, line %d.", 1336 function_name.c_str(), file_name.c_str(), line_number); 1337 base::debug::Alias(message); 1338 1339 // The daemon requested us to crash the process. 1340 CHECK(false) << message; 1341 } 1342 1343 int HostProcessMain() { 1344 #if defined(OS_LINUX) 1345 // Required for any calls into GTK functions, such as the Disconnect and 1346 // Continue windows, though these should not be used for the Me2Me case 1347 // (crbug.com/104377). 1348 gtk_init(NULL, NULL); 1349 #endif 1350 1351 // Enable support for SSL server sockets, which must be done while still 1352 // single-threaded. 1353 net::EnableSSLServerSockets(); 1354 1355 // Ensures runtime specific CPU features are initialized. 1356 media::InitializeCPUSpecificMediaFeatures(); 1357 1358 // Create the main message loop and start helper threads. 1359 base::MessageLoopForUI message_loop; 1360 scoped_ptr<ChromotingHostContext> context = 1361 ChromotingHostContext::Create(new AutoThreadTaskRunner( 1362 message_loop.message_loop_proxy(), base::MessageLoop::QuitClosure())); 1363 if (!context) 1364 return kInitializationFailed; 1365 1366 // Create & start the HostProcess using these threads. 1367 // TODO(wez): The HostProcess holds a reference to itself until Shutdown(). 1368 // Remove this hack as part of the multi-process refactoring. 1369 int exit_code = kSuccessExitCode; 1370 new HostProcess(context.Pass(), &exit_code); 1371 1372 // Run the main (also UI) message loop until the host no longer needs it. 1373 message_loop.Run(); 1374 1375 return exit_code; 1376 } 1377 1378 } // namespace remoting 1379 1380 #if !defined(OS_WIN) 1381 int main(int argc, char** argv) { 1382 return remoting::HostMain(argc, argv); 1383 } 1384 #endif // !defined(OS_WIN) 1385