Enable Enhanced Bookmark on Android Tablet
[chromium-blink-merge.git] / remoting / host / remoting_me2me_host.cc
blob2dffb93a8851e47b0edbd86b6989cd956e6b368c
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.
7 #include <string>
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/files/file_path.h"
15 #include "base/files/file_util.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/threading/thread.h"
23 #include "build/build_config.h"
24 #include "crypto/nss_util.h"
25 #include "ipc/ipc_channel.h"
26 #include "ipc/ipc_channel_proxy.h"
27 #include "ipc/ipc_listener.h"
28 #include "media/base/media.h"
29 #include "net/base/network_change_notifier.h"
30 #include "net/socket/client_socket_factory.h"
31 #include "net/socket/ssl_server_socket.h"
32 #include "net/url_request/url_fetcher.h"
33 #include "remoting/base/auto_thread_task_runner.h"
34 #include "remoting/base/breakpad.h"
35 #include "remoting/base/constants.h"
36 #include "remoting/base/logging.h"
37 #include "remoting/base/rsa_key_pair.h"
38 #include "remoting/base/service_urls.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_logger.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/logging.h"
60 #include "remoting/host/me2me_desktop_environment.h"
61 #include "remoting/host/pairing_registry_delegate.h"
62 #include "remoting/host/policy_hack/policy_watcher.h"
63 #include "remoting/host/session_manager_factory.h"
64 #include "remoting/host/shutdown_watchdog.h"
65 #include "remoting/host/signaling_connector.h"
66 #include "remoting/host/single_window_desktop_environment.h"
67 #include "remoting/host/token_validator_factory_impl.h"
68 #include "remoting/host/usage_stats_consent.h"
69 #include "remoting/host/username.h"
70 #include "remoting/host/video_frame_recorder_host_extension.h"
71 #include "remoting/protocol/me2me_host_authenticator_factory.h"
72 #include "remoting/protocol/network_settings.h"
73 #include "remoting/protocol/pairing_registry.h"
74 #include "remoting/protocol/token_validator.h"
75 #include "remoting/signaling/xmpp_signal_strategy.h"
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)
86 #if defined(OS_MACOSX)
87 #include "base/mac/scoped_cftyperef.h"
88 #endif // defined(OS_MACOSX)
90 #if defined(OS_LINUX)
91 #include <gtk/gtk.h>
92 #include <X11/Xlib.h>
93 #include "remoting/host/audio_capturer_linux.h"
94 #endif // defined(OS_LINUX)
96 #if defined(OS_WIN)
97 #include <commctrl.h>
98 #include "base/win/registry.h"
99 #include "base/win/scoped_handle.h"
100 #include "remoting/host/pairing_registry_delegate_win.h"
101 #include "remoting/host/win/session_desktop_environment.h"
102 #endif // defined(OS_WIN)
104 using remoting::protocol::PairingRegistry;
105 using remoting::protocol::NetworkSettings;
107 namespace {
109 // This is used for tagging system event logs.
110 const char kApplicationName[] = "chromoting";
112 #if defined(OS_LINUX)
113 // The command line switch used to pass name of the pipe to capture audio on
114 // linux.
115 const char kAudioPipeSwitchName[] = "audio-pipe-name";
117 // The command line switch used to pass name of the unix domain socket used to
118 // listen for gnubby requests.
119 const char kAuthSocknameSwitchName[] = "ssh-auth-sockname";
120 #endif // defined(OS_LINUX)
122 // The command line switch used by the parent to request the host to signal it
123 // when it is successfully started.
124 const char kSignalParentSwitchName[] = "signal-parent";
126 // Command line switch used to enable VP9 encoding.
127 const char kEnableVp9SwitchName[] = "enable-vp9";
129 // Command line switch used to enable and configure the frame-recorder.
130 const char kFrameRecorderBufferKbName[] = "frame-recorder-buffer-kb";
132 // Value used for --host-config option to indicate that the path must be read
133 // from stdin.
134 const char kStdinConfigPath[] = "-";
136 const char kWindowIdSwitchName[] = "window-id";
138 // Maximum time to wait for clean shutdown to occur, before forcing termination
139 // of the process.
140 const int kShutdownTimeoutSeconds = 15;
142 } // namespace
144 namespace remoting {
146 class HostProcess
147 : public ConfigWatcher::Delegate,
148 public HostChangeNotificationListener::Listener,
149 public IPC::Listener,
150 public base::RefCountedThreadSafe<HostProcess> {
151 public:
152 // |shutdown_watchdog| is armed when shutdown is started, and should be kept
153 // alive as long as possible until the process exits (since destroying the
154 // watchdog disarms it).
155 HostProcess(scoped_ptr<ChromotingHostContext> context,
156 int* exit_code_out,
157 ShutdownWatchdog* shutdown_watchdog);
159 // ConfigWatcher::Delegate interface.
160 void OnConfigUpdated(const std::string& serialized_config) override;
161 void OnConfigWatcherError() override;
163 // IPC::Listener implementation.
164 bool OnMessageReceived(const IPC::Message& message) override;
165 void OnChannelError() override;
167 // HostChangeNotificationListener::Listener overrides.
168 void OnHostDeleted() override;
170 // Initializes the pairing registry on Windows.
171 void OnInitializePairingRegistry(
172 IPC::PlatformFileForTransit privileged_key,
173 IPC::PlatformFileForTransit unprivileged_key);
175 private:
176 enum HostState {
177 // Host process has just been started. Waiting for config and policies to be
178 // read from the disk.
179 HOST_INITIALIZING,
181 // Host is started and running.
182 HOST_STARTED,
184 // Host is being stopped and will need to be started again.
185 HOST_STOPPING_TO_RESTART,
187 // Host is being stopped.
188 HOST_STOPPING,
190 // Host has been stopped.
191 HOST_STOPPED,
193 // Allowed state transitions:
194 // INITIALIZING->STARTED
195 // INITIALIZING->STOPPED
196 // STARTED->STOPPING_TO_RESTART
197 // STARTED->STOPPING
198 // STOPPING_TO_RESTART->STARTED
199 // STOPPING_TO_RESTART->STOPPING
200 // STOPPING->STOPPED
201 // STOPPED->STARTED
203 // |host_| must be NULL in INITIALIZING and STOPPED states and not-NULL in
204 // all other states.
207 friend class base::RefCountedThreadSafe<HostProcess>;
208 ~HostProcess() override;
210 void StartOnNetworkThread();
212 #if defined(OS_POSIX)
213 // Callback passed to RegisterSignalHandler() to handle SIGTERM events.
214 void SigTermHandler(int signal_number);
215 #endif
217 // Called to initialize resources on the UI thread.
218 void StartOnUiThread();
220 // Initializes IPC control channel and config file path from |cmd_line|.
221 // Called on the UI thread.
222 bool InitWithCommandLine(const base::CommandLine* cmd_line);
224 // Called on the UI thread to start monitoring the configuration file.
225 void StartWatchingConfigChanges();
227 // Called on the network thread to set the host's Authenticator factory.
228 void CreateAuthenticatorFactory();
230 // Tear down resources that run on the UI thread.
231 void ShutdownOnUiThread();
233 // Applies the host config, returning true if successful.
234 bool ApplyConfig(const base::DictionaryValue& config);
236 // Handles policy updates, by calling On*PolicyUpdate methods.
237 void OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies);
238 void OnPolicyError();
239 void ApplyHostDomainPolicy();
240 void ApplyUsernamePolicy();
241 bool OnHostDomainPolicyUpdate(base::DictionaryValue* policies);
242 bool OnUsernamePolicyUpdate(base::DictionaryValue* policies);
243 bool OnNatPolicyUpdate(base::DictionaryValue* policies);
244 bool OnRelayPolicyUpdate(base::DictionaryValue* policies);
245 bool OnUdpPortPolicyUpdate(base::DictionaryValue* policies);
246 bool OnCurtainPolicyUpdate(base::DictionaryValue* policies);
247 bool OnHostTalkGadgetPrefixPolicyUpdate(base::DictionaryValue* policies);
248 bool OnHostTokenUrlPolicyUpdate(base::DictionaryValue* policies);
249 bool OnPairingPolicyUpdate(base::DictionaryValue* policies);
250 bool OnGnubbyAuthPolicyUpdate(base::DictionaryValue* policies);
252 void StartHost();
254 void OnHeartbeatSuccessful();
255 void OnUnknownHostIdError();
257 void OnAuthFailed();
259 void RestartHost();
261 // Stops the host and shuts down the process with the specified |exit_code|.
262 void ShutdownHost(HostExitCodes exit_code);
264 void ScheduleHostShutdown();
266 void ShutdownOnNetworkThread();
268 void OnPolicyWatcherShutdown();
270 // Crashes the process in response to a daemon's request. The daemon passes
271 // the location of the code that detected the fatal error resulted in this
272 // request.
273 void OnCrash(const std::string& function_name,
274 const std::string& file_name,
275 const int& line_number);
277 scoped_ptr<ChromotingHostContext> context_;
279 // Created on the UI thread but used from the network thread.
280 scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
282 // Accessed on the UI thread.
283 scoped_ptr<IPC::ChannelProxy> daemon_channel_;
285 // XMPP server/remoting bot configuration (initialized from the command line).
286 XmppSignalStrategy::XmppServerConfig xmpp_server_config_;
287 std::string directory_bot_jid_;
289 // Created on the UI thread but used from the network thread.
290 base::FilePath host_config_path_;
291 std::string host_config_;
292 scoped_ptr<DesktopEnvironmentFactory> desktop_environment_factory_;
294 // Accessed on the network thread.
295 HostState state_;
297 scoped_ptr<ConfigWatcher> config_watcher_;
299 std::string host_id_;
300 protocol::SharedSecretHash host_secret_hash_;
301 scoped_refptr<RsaKeyPair> key_pair_;
302 std::string oauth_refresh_token_;
303 std::string serialized_config_;
304 std::string host_owner_;
305 std::string host_owner_email_;
306 bool use_service_account_;
307 bool enable_vp9_;
308 int64_t frame_recorder_buffer_size_;
310 scoped_ptr<policy_hack::PolicyWatcher> policy_watcher_;
311 std::string host_domain_;
312 bool host_username_match_required_;
313 bool allow_nat_traversal_;
314 bool allow_relay_;
315 uint16 min_udp_port_;
316 uint16 max_udp_port_;
317 std::string talkgadget_prefix_;
318 bool allow_pairing_;
320 bool curtain_required_;
321 ThirdPartyAuthConfig third_party_auth_config_;
322 bool enable_gnubby_auth_;
324 // Boolean to change flow, where ncessary, if we're
325 // capturing a window instead of the entire desktop.
326 bool enable_window_capture_;
328 // Used to specify which window to stream, if enabled.
329 webrtc::WindowId window_id_;
331 scoped_ptr<OAuthTokenGetter> oauth_token_getter_;
332 scoped_ptr<XmppSignalStrategy> signal_strategy_;
333 scoped_ptr<SignalingConnector> signaling_connector_;
334 scoped_ptr<HeartbeatSender> heartbeat_sender_;
335 scoped_ptr<HostChangeNotificationListener> host_change_notification_listener_;
336 scoped_ptr<HostStatusLogger> host_status_logger_;
337 scoped_ptr<HostEventLogger> host_event_logger_;
339 scoped_ptr<ChromotingHost> host_;
341 // Used to keep this HostProcess alive until it is shutdown.
342 scoped_refptr<HostProcess> self_;
344 #if defined(REMOTING_MULTI_PROCESS)
345 DesktopSessionConnector* desktop_session_connector_;
346 #endif // defined(REMOTING_MULTI_PROCESS)
348 int* exit_code_out_;
349 bool signal_parent_;
351 scoped_ptr<PairingRegistry::Delegate> pairing_registry_delegate_;
353 ShutdownWatchdog* shutdown_watchdog_;
356 HostProcess::HostProcess(scoped_ptr<ChromotingHostContext> context,
357 int* exit_code_out,
358 ShutdownWatchdog* shutdown_watchdog)
359 : context_(context.Pass()),
360 state_(HOST_INITIALIZING),
361 use_service_account_(false),
362 enable_vp9_(false),
363 frame_recorder_buffer_size_(0),
364 host_username_match_required_(false),
365 allow_nat_traversal_(true),
366 allow_relay_(true),
367 min_udp_port_(0),
368 max_udp_port_(0),
369 allow_pairing_(true),
370 curtain_required_(false),
371 enable_gnubby_auth_(false),
372 enable_window_capture_(false),
373 window_id_(0),
374 #if defined(REMOTING_MULTI_PROCESS)
375 desktop_session_connector_(NULL),
376 #endif // defined(REMOTING_MULTI_PROCESS)
377 self_(this),
378 exit_code_out_(exit_code_out),
379 signal_parent_(false),
380 shutdown_watchdog_(shutdown_watchdog) {
381 StartOnUiThread();
384 HostProcess::~HostProcess() {
385 // Verify that UI components have been torn down.
386 DCHECK(!config_watcher_);
387 DCHECK(!daemon_channel_);
388 DCHECK(!desktop_environment_factory_);
390 // We might be getting deleted on one of the threads the |host_context| owns,
391 // so we need to post it back to the caller thread to safely join & delete the
392 // threads it contains. This will go away when we move to AutoThread.
393 // |context_release()| will null |context_| before the method is invoked, so
394 // we need to pull out the task-runner on which to call DeleteSoon first.
395 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
396 context_->ui_task_runner();
397 task_runner->DeleteSoon(FROM_HERE, context_.release());
400 bool HostProcess::InitWithCommandLine(const base::CommandLine* cmd_line) {
401 #if defined(REMOTING_MULTI_PROCESS)
402 // Parse the handle value and convert it to a handle/file descriptor.
403 std::string channel_name =
404 cmd_line->GetSwitchValueASCII(kDaemonPipeSwitchName);
406 int pipe_handle = 0;
407 if (channel_name.empty() ||
408 !base::StringToInt(channel_name, &pipe_handle)) {
409 LOG(ERROR) << "Invalid '" << kDaemonPipeSwitchName
410 << "' value: " << channel_name;
411 return false;
414 #if defined(OS_WIN)
415 base::win::ScopedHandle pipe(reinterpret_cast<HANDLE>(pipe_handle));
416 IPC::ChannelHandle channel_handle(pipe.Get());
417 #elif defined(OS_POSIX)
418 base::FileDescriptor pipe(pipe_handle, true);
419 IPC::ChannelHandle channel_handle(channel_name, pipe);
420 #endif // defined(OS_POSIX)
422 // Connect to the daemon process.
423 daemon_channel_ = IPC::ChannelProxy::Create(channel_handle,
424 IPC::Channel::MODE_CLIENT,
425 this,
426 context_->network_task_runner());
427 #else // !defined(REMOTING_MULTI_PROCESS)
428 // Connect to the daemon process.
429 std::string channel_name =
430 cmd_line->GetSwitchValueASCII(kDaemonPipeSwitchName);
431 if (!channel_name.empty()) {
432 daemon_channel_ =
433 IPC::ChannelProxy::Create(channel_name,
434 IPC::Channel::MODE_CLIENT,
435 this,
436 context_->network_task_runner().get());
439 if (cmd_line->HasSwitch(kHostConfigSwitchName)) {
440 host_config_path_ = cmd_line->GetSwitchValuePath(kHostConfigSwitchName);
442 // Read config from stdin if necessary.
443 if (host_config_path_ == base::FilePath(kStdinConfigPath)) {
444 char buf[4096];
445 size_t len;
446 while ((len = fread(buf, 1, sizeof(buf), stdin)) > 0) {
447 host_config_.append(buf, len);
450 } else {
451 base::FilePath default_config_dir = remoting::GetConfigDir();
452 host_config_path_ = default_config_dir.Append(kDefaultHostConfigFile);
455 if (host_config_path_ != base::FilePath(kStdinConfigPath) &&
456 !base::PathExists(host_config_path_)) {
457 LOG(ERROR) << "Can't find host config at " << host_config_path_.value();
458 return false;
460 #endif // !defined(REMOTING_MULTI_PROCESS)
462 // Ignore certificate requests - the host currently has no client certificate
463 // support, so ignoring certificate requests allows connecting to servers that
464 // request, but don't require, a certificate (optional client authentication).
465 net::URLFetcher::SetIgnoreCertificateRequests(true);
467 ServiceUrls* service_urls = ServiceUrls::GetInstance();
468 bool xmpp_server_valid = net::ParseHostAndPort(
469 service_urls->xmpp_server_address(),
470 &xmpp_server_config_.host, &xmpp_server_config_.port);
471 if (!xmpp_server_valid) {
472 LOG(ERROR) << "Invalid XMPP server: " <<
473 service_urls->xmpp_server_address();
474 return false;
476 xmpp_server_config_.use_tls = service_urls->xmpp_server_use_tls();
477 directory_bot_jid_ = service_urls->directory_bot_jid();
479 signal_parent_ = cmd_line->HasSwitch(kSignalParentSwitchName);
481 enable_window_capture_ = cmd_line->HasSwitch(kWindowIdSwitchName);
482 if (enable_window_capture_) {
484 #if defined(OS_LINUX) || defined(OS_WIN)
485 LOG(WARNING) << "Window capturing is not fully supported on Linux or "
486 "Windows.";
487 #endif // defined(OS_LINUX) || defined(OS_WIN)
489 // uint32_t is large enough to hold window IDs on all platforms.
490 uint32_t window_id;
491 if (base::StringToUint(
492 cmd_line->GetSwitchValueASCII(kWindowIdSwitchName),
493 &window_id)) {
494 window_id_ = static_cast<webrtc::WindowId>(window_id);
495 } else {
496 LOG(ERROR) << "Window with window id: " << window_id_
497 << " not found. Shutting down host.";
498 return false;
501 return true;
504 void HostProcess::OnConfigUpdated(
505 const std::string& serialized_config) {
506 if (!context_->network_task_runner()->BelongsToCurrentThread()) {
507 context_->network_task_runner()->PostTask(FROM_HERE,
508 base::Bind(&HostProcess::OnConfigUpdated, this, serialized_config));
509 return;
512 // Filter out duplicates.
513 if (serialized_config_ == serialized_config)
514 return;
516 HOST_LOG << "Processing new host configuration.";
518 serialized_config_ = serialized_config;
519 scoped_ptr<base::DictionaryValue> config(
520 HostConfigFromJson(serialized_config));
521 if (!config) {
522 LOG(ERROR) << "Invalid configuration.";
523 ShutdownHost(kInvalidHostConfigurationExitCode);
524 return;
527 if (!ApplyConfig(*config)) {
528 LOG(ERROR) << "Failed to apply the configuration.";
529 ShutdownHost(kInvalidHostConfigurationExitCode);
530 return;
533 if (state_ == HOST_INITIALIZING) {
534 // TODO(sergeyu): Currently OnPolicyUpdate() assumes that host config is
535 // already loaded so PolicyWatcher has to be started here. Separate policy
536 // loading from policy verifications and move |policy_watcher_|
537 // initialization to StartOnNetworkThread().
538 policy_watcher_ = policy_hack::PolicyWatcher::Create(
539 nullptr, context_->network_task_runner());
540 policy_watcher_->StartWatching(
541 base::Bind(&HostProcess::OnPolicyUpdate, base::Unretained(this)),
542 base::Bind(&HostProcess::OnPolicyError, base::Unretained(this)));
543 } else {
544 // Reapply policies that could be affected by a new config.
545 ApplyHostDomainPolicy();
546 ApplyUsernamePolicy();
548 if (state_ == HOST_STARTED) {
549 // TODO(sergeyu): Here we assume that PIN is the only part of the config
550 // that may change while the service is running. Change ApplyConfig() to
551 // detect other changes in the config and restart host if necessary here.
552 CreateAuthenticatorFactory();
557 void HostProcess::OnConfigWatcherError() {
558 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
559 ShutdownHost(kInvalidHostConfigurationExitCode);
562 void HostProcess::StartOnNetworkThread() {
563 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
565 #if !defined(REMOTING_MULTI_PROCESS)
566 if (host_config_path_ == base::FilePath(kStdinConfigPath)) {
567 // Process config we've read from stdin.
568 OnConfigUpdated(host_config_);
569 } else {
570 // Start watching the host configuration file.
571 config_watcher_.reset(new ConfigFileWatcher(context_->network_task_runner(),
572 context_->file_task_runner(),
573 host_config_path_));
574 config_watcher_->Watch(this);
576 #endif // !defined(REMOTING_MULTI_PROCESS)
578 #if defined(OS_POSIX)
579 remoting::RegisterSignalHandler(
580 SIGTERM,
581 base::Bind(&HostProcess::SigTermHandler, base::Unretained(this)));
582 #endif // defined(OS_POSIX)
585 #if defined(OS_POSIX)
586 void HostProcess::SigTermHandler(int signal_number) {
587 DCHECK(signal_number == SIGTERM);
588 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
589 HOST_LOG << "Caught SIGTERM: Shutting down...";
590 ShutdownHost(kSuccessExitCode);
592 #endif // OS_POSIX
594 void HostProcess::CreateAuthenticatorFactory() {
595 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
597 if (state_ != HOST_STARTED)
598 return;
600 std::string local_certificate = key_pair_->GenerateCertificate();
601 if (local_certificate.empty()) {
602 LOG(ERROR) << "Failed to generate host certificate.";
603 ShutdownHost(kInitializationFailed);
604 return;
607 scoped_refptr<PairingRegistry> pairing_registry = NULL;
608 if (allow_pairing_) {
609 if (!pairing_registry_delegate_)
610 pairing_registry_delegate_ = CreatePairingRegistryDelegate();
612 if (pairing_registry_delegate_) {
613 pairing_registry = new PairingRegistry(context_->file_task_runner(),
614 pairing_registry_delegate_.Pass());
618 scoped_ptr<protocol::AuthenticatorFactory> factory;
620 if (third_party_auth_config_.is_empty()) {
621 factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithSharedSecret(
622 use_service_account_, host_owner_, local_certificate, key_pair_,
623 host_secret_hash_, pairing_registry);
625 } else if (third_party_auth_config_.is_valid()) {
626 scoped_ptr<protocol::TokenValidatorFactory> token_validator_factory(
627 new TokenValidatorFactoryImpl(
628 third_party_auth_config_,
629 key_pair_, context_->url_request_context_getter()));
630 factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth(
631 use_service_account_, host_owner_, local_certificate, key_pair_,
632 token_validator_factory.Pass());
634 } else {
635 // TODO(rmsousa): If the policy is bad the host should not go online. It
636 // should keep running, but not connected, until the policies are fixed.
637 // Having it show up as online and then reject all clients is misleading.
638 LOG(ERROR) << "One of the third-party token URLs is empty or invalid. "
639 << "Host will reject all clients until policies are corrected. "
640 << "TokenUrl: " << third_party_auth_config_.token_url << ", "
641 << "TokenValidationUrl: "
642 << third_party_auth_config_.token_validation_url;
643 factory = protocol::Me2MeHostAuthenticatorFactory::CreateRejecting();
646 #if defined(OS_POSIX)
647 // On Linux and Mac, perform a PAM authorization step after authentication.
648 factory.reset(new PamAuthorizationFactory(factory.Pass()));
649 #endif
650 host_->SetAuthenticatorFactory(factory.Pass());
652 host_->set_pairing_registry(pairing_registry);
655 // IPC::Listener implementation.
656 bool HostProcess::OnMessageReceived(const IPC::Message& message) {
657 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
659 #if defined(REMOTING_MULTI_PROCESS)
660 bool handled = true;
661 IPC_BEGIN_MESSAGE_MAP(HostProcess, message)
662 IPC_MESSAGE_HANDLER(ChromotingDaemonMsg_Crash, OnCrash)
663 IPC_MESSAGE_HANDLER(ChromotingDaemonNetworkMsg_Configuration,
664 OnConfigUpdated)
665 IPC_MESSAGE_HANDLER(ChromotingDaemonNetworkMsg_InitializePairingRegistry,
666 OnInitializePairingRegistry)
667 IPC_MESSAGE_FORWARD(
668 ChromotingDaemonNetworkMsg_DesktopAttached,
669 desktop_session_connector_,
670 DesktopSessionConnector::OnDesktopSessionAgentAttached)
671 IPC_MESSAGE_FORWARD(ChromotingDaemonNetworkMsg_TerminalDisconnected,
672 desktop_session_connector_,
673 DesktopSessionConnector::OnTerminalDisconnected)
674 IPC_MESSAGE_UNHANDLED(handled = false)
675 IPC_END_MESSAGE_MAP()
677 CHECK(handled) << "Received unexpected IPC type: " << message.type();
678 return handled;
680 #else // !defined(REMOTING_MULTI_PROCESS)
681 return false;
682 #endif // !defined(REMOTING_MULTI_PROCESS)
685 void HostProcess::OnChannelError() {
686 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
688 // Shutdown the host if the daemon process disconnects the IPC channel.
689 context_->network_task_runner()->PostTask(
690 FROM_HERE,
691 base::Bind(&HostProcess::ShutdownHost, this, kSuccessExitCode));
694 void HostProcess::StartOnUiThread() {
695 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
697 if (!InitWithCommandLine(base::CommandLine::ForCurrentProcess())) {
698 // Shutdown the host if the command line is invalid.
699 context_->network_task_runner()->PostTask(
700 FROM_HERE, base::Bind(&HostProcess::ShutdownHost, this,
701 kUsageExitCode));
702 return;
705 #if defined(OS_LINUX)
706 // If an audio pipe is specific on the command-line then initialize
707 // AudioCapturerLinux to capture from it.
708 base::FilePath audio_pipe_name = base::CommandLine::ForCurrentProcess()->
709 GetSwitchValuePath(kAudioPipeSwitchName);
710 if (!audio_pipe_name.empty()) {
711 remoting::AudioCapturerLinux::InitializePipeReader(
712 context_->audio_task_runner(), audio_pipe_name);
715 base::FilePath gnubby_socket_name = base::CommandLine::ForCurrentProcess()->
716 GetSwitchValuePath(kAuthSocknameSwitchName);
717 if (!gnubby_socket_name.empty())
718 remoting::GnubbyAuthHandler::SetGnubbySocketName(gnubby_socket_name);
719 #endif // defined(OS_LINUX)
721 // Create a desktop environment factory appropriate to the build type &
722 // platform.
723 #if defined(OS_WIN)
724 IpcDesktopEnvironmentFactory* desktop_environment_factory =
725 new IpcDesktopEnvironmentFactory(
726 context_->audio_task_runner(),
727 context_->network_task_runner(),
728 context_->video_capture_task_runner(),
729 context_->network_task_runner(),
730 daemon_channel_.get());
731 desktop_session_connector_ = desktop_environment_factory;
732 #else // !defined(OS_WIN)
733 DesktopEnvironmentFactory* desktop_environment_factory;
734 if (enable_window_capture_) {
735 desktop_environment_factory =
736 new SingleWindowDesktopEnvironmentFactory(
737 context_->network_task_runner(),
738 context_->input_task_runner(),
739 context_->ui_task_runner(),
740 window_id_);
741 } else {
742 desktop_environment_factory =
743 new Me2MeDesktopEnvironmentFactory(
744 context_->network_task_runner(),
745 context_->input_task_runner(),
746 context_->ui_task_runner());
748 #endif // !defined(OS_WIN)
750 desktop_environment_factory_.reset(desktop_environment_factory);
751 desktop_environment_factory_->SetEnableGnubbyAuth(enable_gnubby_auth_);
753 context_->network_task_runner()->PostTask(
754 FROM_HERE,
755 base::Bind(&HostProcess::StartOnNetworkThread, this));
758 void HostProcess::ShutdownOnUiThread() {
759 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
761 // Tear down resources that need to be torn down on the UI thread.
762 network_change_notifier_.reset();
763 daemon_channel_.reset();
764 desktop_environment_factory_.reset();
766 // It is now safe for the HostProcess to be deleted.
767 self_ = NULL;
769 #if defined(OS_LINUX)
770 // Cause the global AudioPipeReader to be freed, otherwise the audio
771 // thread will remain in-use and prevent the process from exiting.
772 // TODO(wez): DesktopEnvironmentFactory should own the pipe reader.
773 // See crbug.com/161373 and crbug.com/104544.
774 AudioCapturerLinux::InitializePipeReader(NULL, base::FilePath());
775 #endif
778 // Overridden from HeartbeatSender::Listener
779 void HostProcess::OnUnknownHostIdError() {
780 LOG(ERROR) << "Host ID not found.";
781 ShutdownHost(kInvalidHostIdExitCode);
784 void HostProcess::OnHeartbeatSuccessful() {
785 HOST_LOG << "Host ready to receive connections.";
786 #if defined(OS_POSIX)
787 if (signal_parent_) {
788 kill(getppid(), SIGUSR1);
789 signal_parent_ = false;
791 #endif
794 void HostProcess::OnHostDeleted() {
795 LOG(ERROR) << "Host was deleted from the directory.";
796 ShutdownHost(kInvalidHostIdExitCode);
799 void HostProcess::OnInitializePairingRegistry(
800 IPC::PlatformFileForTransit privileged_key,
801 IPC::PlatformFileForTransit unprivileged_key) {
802 DCHECK(!pairing_registry_delegate_);
804 #if defined(OS_WIN)
805 // Initialize the pairing registry delegate.
806 scoped_ptr<PairingRegistryDelegateWin> delegate(
807 new PairingRegistryDelegateWin());
808 bool result = delegate->SetRootKeys(
809 reinterpret_cast<HKEY>(
810 IPC::PlatformFileForTransitToPlatformFile(privileged_key)),
811 reinterpret_cast<HKEY>(
812 IPC::PlatformFileForTransitToPlatformFile(unprivileged_key)));
813 if (!result)
814 return;
816 pairing_registry_delegate_ = delegate.Pass();
817 #else // !defined(OS_WIN)
818 NOTREACHED();
819 #endif // !defined(OS_WIN)
822 // Applies the host config, returning true if successful.
823 bool HostProcess::ApplyConfig(const base::DictionaryValue& config) {
824 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
826 if (!config.GetString(kHostIdConfigPath, &host_id_)) {
827 LOG(ERROR) << "host_id is not defined in the config.";
828 return false;
831 std::string key_base64;
832 if (!config.GetString(kPrivateKeyConfigPath, &key_base64)) {
833 LOG(ERROR) << "Private key couldn't be read from the config file.";
834 return false;
837 key_pair_ = RsaKeyPair::FromString(key_base64);
838 if (!key_pair_.get()) {
839 LOG(ERROR) << "Invalid private key in the config file.";
840 return false;
843 std::string host_secret_hash_string;
844 if (!config.GetString(kHostSecretHashConfigPath,
845 &host_secret_hash_string)) {
846 host_secret_hash_string = "plain:";
849 if (!host_secret_hash_.Parse(host_secret_hash_string)) {
850 LOG(ERROR) << "Invalid host_secret_hash.";
851 return false;
854 // Use an XMPP connection to the Talk network for session signalling.
855 if (!config.GetString(kXmppLoginConfigPath, &xmpp_server_config_.username) ||
856 !(config.GetString(kXmppAuthTokenConfigPath,
857 &xmpp_server_config_.auth_token) ||
858 config.GetString(kOAuthRefreshTokenConfigPath,
859 &oauth_refresh_token_))) {
860 LOG(ERROR) << "XMPP credentials are not defined in the config.";
861 return false;
864 if (!oauth_refresh_token_.empty()) {
865 // SignalingConnector is responsible for getting OAuth token.
866 xmpp_server_config_.auth_token = "";
867 xmpp_server_config_.auth_service = "oauth2";
868 } else if (!config.GetString(kXmppAuthServiceConfigPath,
869 &xmpp_server_config_.auth_service)) {
870 // For the me2me host, we default to ClientLogin token for chromiumsync
871 // because earlier versions of the host had no HTTP stack with which to
872 // request an OAuth2 access token.
873 xmpp_server_config_.auth_service = kChromotingTokenDefaultServiceName;
876 if (config.GetString(kHostOwnerConfigPath, &host_owner_)) {
877 // Service account configs have a host_owner, different from the xmpp_login.
878 use_service_account_ = true;
879 } else {
880 // User credential configs only have an xmpp_login, which is also the owner.
881 host_owner_ = xmpp_server_config_.username;
882 use_service_account_ = false;
885 // For non-Gmail Google accounts, the owner base JID differs from the email.
886 // host_owner_ contains the base JID (used for authenticating clients), while
887 // host_owner_email contains the account's email (used for UI and logs).
888 if (!config.GetString(kHostOwnerEmailConfigPath, &host_owner_email_)) {
889 host_owner_email_ = host_owner_;
892 // Allow offering of VP9 encoding to be overridden by the command-line.
893 if (CommandLine::ForCurrentProcess()->HasSwitch(kEnableVp9SwitchName)) {
894 enable_vp9_ = true;
895 } else {
896 config.GetBoolean(kEnableVp9ConfigPath, &enable_vp9_);
899 // Allow the command-line to override the size of the frame recorder buffer.
900 int frame_recorder_buffer_kb = 0;
901 if (CommandLine::ForCurrentProcess()->HasSwitch(
902 kFrameRecorderBufferKbName)) {
903 std::string switch_value =
904 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
905 kFrameRecorderBufferKbName);
906 base::StringToInt(switch_value, &frame_recorder_buffer_kb);
907 } else {
908 config.GetInteger(kFrameRecorderBufferKbConfigPath,
909 &frame_recorder_buffer_kb);
911 if (frame_recorder_buffer_kb > 0) {
912 frame_recorder_buffer_size_ = 1024LL * frame_recorder_buffer_kb;
915 return true;
918 void HostProcess::OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies) {
919 if (!context_->network_task_runner()->BelongsToCurrentThread()) {
920 context_->network_task_runner()->PostTask(FROM_HERE, base::Bind(
921 &HostProcess::OnPolicyUpdate, this, base::Passed(&policies)));
922 return;
925 bool restart_required = false;
926 restart_required |= OnHostDomainPolicyUpdate(policies.get());
927 restart_required |= OnCurtainPolicyUpdate(policies.get());
928 // Note: UsernamePolicyUpdate must run after OnCurtainPolicyUpdate.
929 restart_required |= OnUsernamePolicyUpdate(policies.get());
930 restart_required |= OnNatPolicyUpdate(policies.get());
931 restart_required |= OnRelayPolicyUpdate(policies.get());
932 restart_required |= OnUdpPortPolicyUpdate(policies.get());
933 restart_required |= OnHostTalkGadgetPrefixPolicyUpdate(policies.get());
934 restart_required |= OnHostTokenUrlPolicyUpdate(policies.get());
935 restart_required |= OnPairingPolicyUpdate(policies.get());
936 restart_required |= OnGnubbyAuthPolicyUpdate(policies.get());
938 if (state_ == HOST_INITIALIZING) {
939 StartHost();
940 } else if (state_ == HOST_STARTED && restart_required) {
941 RestartHost();
945 void HostProcess::OnPolicyError() {
946 context_->network_task_runner()->PostTask(
947 FROM_HERE,
948 base::Bind(
949 &HostProcess::ShutdownHost,
950 this,
951 kInvalidHostConfigurationExitCode));
954 void HostProcess::ApplyHostDomainPolicy() {
955 HOST_LOG << "Policy sets host domain: " << host_domain_;
957 if (!host_domain_.empty()) {
958 // If the user does not have a Google email, their client JID will not be
959 // based on their email. In that case, the username/host domain policies
960 // would be meaningless, since there is no way to check that the JID
961 // trying to connect actually corresponds to the owner email in question.
962 if (host_owner_ != host_owner_email_) {
963 LOG(ERROR) << "The username and host domain policies cannot be enabled "
964 << "for accounts with a non-Google email.";
965 ShutdownHost(kInvalidHostDomainExitCode);
968 if (!EndsWith(host_owner_, std::string("@") + host_domain_, false)) {
969 LOG(ERROR) << "The host domain does not match the policy.";
970 ShutdownHost(kInvalidHostDomainExitCode);
975 bool HostProcess::OnHostDomainPolicyUpdate(base::DictionaryValue* policies) {
976 // Returns true if the host has to be restarted after this policy update.
977 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
979 if (!policies->GetString(policy_hack::PolicyWatcher::kHostDomainPolicyName,
980 &host_domain_)) {
981 return false;
984 ApplyHostDomainPolicy();
985 return false;
988 void HostProcess::ApplyUsernamePolicy() {
989 if (host_username_match_required_) {
990 HOST_LOG << "Policy requires host username match.";
992 // See comment in ApplyHostDomainPolicy.
993 if (host_owner_ != host_owner_email_) {
994 LOG(ERROR) << "The username and host domain policies cannot be enabled "
995 << "for accounts with a non-Google email.";
996 ShutdownHost(kUsernameMismatchExitCode);
999 std::string username = GetUsername();
1000 bool shutdown = username.empty() ||
1001 !StartsWithASCII(host_owner_, username + std::string("@"),
1002 false);
1004 #if defined(OS_MACOSX)
1005 // On Mac, we run as root at the login screen, so the username won't match.
1006 // However, there's no need to enforce the policy at the login screen, as
1007 // the client will have to reconnect if a login occurs.
1008 if (shutdown && getuid() == 0) {
1009 shutdown = false;
1011 #endif
1013 // Curtain-mode on Windows presents the standard OS login prompt to the user
1014 // for each connection, removing the need for an explicit user-name matching
1015 // check.
1016 #if defined(OS_WIN) && defined(REMOTING_RDP_SESSION)
1017 if (curtain_required_)
1018 return;
1019 #endif // defined(OS_WIN) && defined(REMOTING_RDP_SESSION)
1021 // Shutdown the host if the username does not match.
1022 if (shutdown) {
1023 LOG(ERROR) << "The host username does not match.";
1024 ShutdownHost(kUsernameMismatchExitCode);
1026 } else {
1027 HOST_LOG << "Policy does not require host username match.";
1031 bool HostProcess::OnUsernamePolicyUpdate(base::DictionaryValue* policies) {
1032 // Returns false: never restart the host after this policy update.
1033 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1035 if (!policies->GetBoolean(
1036 policy_hack::PolicyWatcher::kHostMatchUsernamePolicyName,
1037 &host_username_match_required_)) {
1038 return false;
1041 ApplyUsernamePolicy();
1042 return false;
1045 bool HostProcess::OnNatPolicyUpdate(base::DictionaryValue* policies) {
1046 // Returns true if the host has to be restarted after this policy update.
1047 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1049 if (!policies->GetBoolean(policy_hack::PolicyWatcher::kNatPolicyName,
1050 &allow_nat_traversal_)) {
1051 return false;
1054 if (allow_nat_traversal_) {
1055 HOST_LOG << "Policy enables NAT traversal.";
1056 } else {
1057 HOST_LOG << "Policy disables NAT traversal.";
1059 return true;
1062 bool HostProcess::OnRelayPolicyUpdate(base::DictionaryValue* policies) {
1063 // Returns true if the host has to be restarted after this policy update.
1064 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1066 if (!policies->GetBoolean(policy_hack::PolicyWatcher::kRelayPolicyName,
1067 &allow_relay_)) {
1068 return false;
1071 if (allow_relay_) {
1072 HOST_LOG << "Policy enables use of relay server.";
1073 } else {
1074 HOST_LOG << "Policy disables use of relay server.";
1076 return true;
1079 bool HostProcess::OnUdpPortPolicyUpdate(base::DictionaryValue* policies) {
1080 // Returns true if the host has to be restarted after this policy update.
1081 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1083 std::string udp_port_range;
1084 if (!policies->GetString(policy_hack::PolicyWatcher::kUdpPortRangePolicyName,
1085 &udp_port_range)) {
1086 return false;
1089 // Use default values if policy setting is empty or invalid.
1090 uint16 min_udp_port = 0;
1091 uint16 max_udp_port = 0;
1092 if (!udp_port_range.empty() &&
1093 !NetworkSettings::ParsePortRange(udp_port_range, &min_udp_port,
1094 &max_udp_port)) {
1095 LOG(WARNING) << "Invalid port range policy: \"" << udp_port_range
1096 << "\". Using default values.";
1099 if (min_udp_port_ != min_udp_port || max_udp_port_ != max_udp_port) {
1100 if (min_udp_port != 0 && max_udp_port != 0) {
1101 HOST_LOG << "Policy restricts UDP port range to [" << min_udp_port
1102 << ", " << max_udp_port << "]";
1103 } else {
1104 HOST_LOG << "Policy does not restrict UDP port range.";
1106 min_udp_port_ = min_udp_port;
1107 max_udp_port_ = max_udp_port;
1108 return true;
1110 return false;
1113 bool HostProcess::OnCurtainPolicyUpdate(base::DictionaryValue* policies) {
1114 // Returns true if the host has to be restarted after this policy update.
1115 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1117 if (!policies->GetBoolean(
1118 policy_hack::PolicyWatcher::kHostRequireCurtainPolicyName,
1119 &curtain_required_)) {
1120 return false;
1123 #if defined(OS_MACOSX)
1124 if (curtain_required_) {
1125 // When curtain mode is in effect on Mac, the host process runs in the
1126 // user's switched-out session, but launchd will also run an instance at
1127 // the console login screen. Even if no user is currently logged-on, we
1128 // can't support remote-access to the login screen because the current host
1129 // process model disconnects the client during login, which would leave
1130 // the logged in session un-curtained on the console until they reconnect.
1132 // TODO(jamiewalch): Fix this once we have implemented the multi-process
1133 // daemon architecture (crbug.com/134894)
1134 if (getuid() == 0) {
1135 LOG(ERROR) << "Running the host in the console login session is yet not "
1136 "supported.";
1137 ShutdownHost(kLoginScreenNotSupportedExitCode);
1138 return false;
1141 #endif
1143 if (curtain_required_) {
1144 HOST_LOG << "Policy requires curtain-mode.";
1145 } else {
1146 HOST_LOG << "Policy does not require curtain-mode.";
1149 if (host_)
1150 host_->SetEnableCurtaining(curtain_required_);
1151 return false;
1154 bool HostProcess::OnHostTalkGadgetPrefixPolicyUpdate(
1155 base::DictionaryValue* policies) {
1156 // Returns true if the host has to be restarted after this policy update.
1157 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1159 if (!policies->GetString(
1160 policy_hack::PolicyWatcher::kHostTalkGadgetPrefixPolicyName,
1161 &talkgadget_prefix_)) {
1162 return false;
1165 HOST_LOG << "Policy sets talkgadget prefix: " << talkgadget_prefix_;
1166 return true;
1169 bool HostProcess::OnHostTokenUrlPolicyUpdate(base::DictionaryValue* policies) {
1170 // Returns true if the host has to be restarted after this policy update.
1171 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1173 bool token_policy_changed = false;
1174 std::string token_url_string;
1175 if (policies->GetString(
1176 policy_hack::PolicyWatcher::kHostTokenUrlPolicyName,
1177 &token_url_string)) {
1178 token_policy_changed = true;
1179 third_party_auth_config_.token_url = GURL(token_url_string);
1181 std::string token_validation_url_string;
1182 if (policies->GetString(
1183 policy_hack::PolicyWatcher::kHostTokenValidationUrlPolicyName,
1184 &token_validation_url_string)) {
1185 token_policy_changed = true;
1186 third_party_auth_config_.token_validation_url =
1187 GURL(token_validation_url_string);
1189 if (policies->GetString(
1190 policy_hack::PolicyWatcher::kHostTokenValidationCertIssuerPolicyName,
1191 &third_party_auth_config_.token_validation_cert_issuer)) {
1192 token_policy_changed = true;
1195 if (token_policy_changed) {
1196 HOST_LOG << "Policy sets third-party token URLs: "
1197 << "TokenUrl: "
1198 << third_party_auth_config_.token_url << ", "
1199 << "TokenValidationUrl: "
1200 << third_party_auth_config_.token_validation_url << ", "
1201 << "TokenValidationCertificateIssuer: "
1202 << third_party_auth_config_.token_validation_cert_issuer;
1204 return token_policy_changed;
1207 bool HostProcess::OnPairingPolicyUpdate(base::DictionaryValue* policies) {
1208 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1210 if (!policies->GetBoolean(
1211 policy_hack::PolicyWatcher::kHostAllowClientPairing,
1212 &allow_pairing_)) {
1213 return false;
1216 if (allow_pairing_) {
1217 HOST_LOG << "Policy enables client pairing.";
1218 } else {
1219 HOST_LOG << "Policy disables client pairing.";
1221 return true;
1224 bool HostProcess::OnGnubbyAuthPolicyUpdate(base::DictionaryValue* policies) {
1225 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1227 if (!policies->GetBoolean(
1228 policy_hack::PolicyWatcher::kHostAllowGnubbyAuthPolicyName,
1229 &enable_gnubby_auth_)) {
1230 return false;
1233 if (enable_gnubby_auth_) {
1234 HOST_LOG << "Policy enables gnubby auth.";
1235 } else {
1236 HOST_LOG << "Policy disables gnubby auth.";
1239 if (desktop_environment_factory_)
1240 desktop_environment_factory_->SetEnableGnubbyAuth(enable_gnubby_auth_);
1242 return true;
1245 void HostProcess::StartHost() {
1246 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1247 DCHECK(!host_);
1248 DCHECK(!signal_strategy_.get());
1249 DCHECK(state_ == HOST_INITIALIZING || state_ == HOST_STOPPING_TO_RESTART ||
1250 state_ == HOST_STOPPED) << state_;
1251 state_ = HOST_STARTED;
1253 signal_strategy_.reset(
1254 new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(),
1255 context_->url_request_context_getter(),
1256 xmpp_server_config_));
1258 scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker(
1259 new DnsBlackholeChecker(context_->url_request_context_getter(),
1260 talkgadget_prefix_));
1262 // Create a NetworkChangeNotifier for use by the signaling connector.
1263 network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
1265 signaling_connector_.reset(new SignalingConnector(
1266 signal_strategy_.get(),
1267 dns_blackhole_checker.Pass(),
1268 base::Bind(&HostProcess::OnAuthFailed, this)));
1270 if (!oauth_refresh_token_.empty()) {
1271 scoped_ptr<OAuthTokenGetter::OAuthCredentials> oauth_credentials;
1272 oauth_credentials.reset(
1273 new OAuthTokenGetter::OAuthCredentials(
1274 xmpp_server_config_.username, oauth_refresh_token_,
1275 use_service_account_));
1277 oauth_token_getter_.reset(new OAuthTokenGetter(
1278 oauth_credentials.Pass(), context_->url_request_context_getter(),
1279 false));
1281 signaling_connector_->EnableOAuth(oauth_token_getter_.get());
1284 uint32 network_flags = 0;
1285 if (allow_nat_traversal_) {
1286 network_flags = NetworkSettings::NAT_TRAVERSAL_STUN |
1287 NetworkSettings::NAT_TRAVERSAL_OUTGOING;
1288 if (allow_relay_)
1289 network_flags |= NetworkSettings::NAT_TRAVERSAL_RELAY;
1292 NetworkSettings network_settings(network_flags);
1294 if (min_udp_port_ && max_udp_port_) {
1295 network_settings.min_port = min_udp_port_;
1296 network_settings.max_port = max_udp_port_;
1297 } else if (!allow_nat_traversal_) {
1298 // For legacy reasons we have to restrict the port range to a set of default
1299 // values when nat traversal is disabled, even if the port range was not
1300 // set in policy.
1301 network_settings.min_port = NetworkSettings::kDefaultMinPort;
1302 network_settings.max_port = NetworkSettings::kDefaultMaxPort;
1305 host_.reset(new ChromotingHost(
1306 signal_strategy_.get(),
1307 desktop_environment_factory_.get(),
1308 CreateHostSessionManager(signal_strategy_.get(), network_settings,
1309 context_->url_request_context_getter()),
1310 context_->audio_task_runner(),
1311 context_->input_task_runner(),
1312 context_->video_capture_task_runner(),
1313 context_->video_encode_task_runner(),
1314 context_->network_task_runner(),
1315 context_->ui_task_runner()));
1317 if (enable_vp9_) {
1318 scoped_ptr<protocol::CandidateSessionConfig> config =
1319 host_->protocol_config()->Clone();
1320 config->EnableVideoCodec(protocol::ChannelConfig::CODEC_VP9);
1321 host_->set_protocol_config(config.Pass());
1324 if (frame_recorder_buffer_size_ > 0) {
1325 scoped_ptr<VideoFrameRecorderHostExtension> frame_recorder_extension(
1326 new VideoFrameRecorderHostExtension());
1327 frame_recorder_extension->SetMaxContentBytes(frame_recorder_buffer_size_);
1328 host_->AddExtension(frame_recorder_extension.Pass());
1331 // TODO(simonmorris): Get the maximum session duration from a policy.
1332 #if defined(OS_LINUX)
1333 host_->SetMaximumSessionDuration(base::TimeDelta::FromHours(20));
1334 #endif
1336 heartbeat_sender_.reset(new HeartbeatSender(
1337 base::Bind(&HostProcess::OnHeartbeatSuccessful, base::Unretained(this)),
1338 base::Bind(&HostProcess::OnUnknownHostIdError, base::Unretained(this)),
1339 host_id_, signal_strategy_.get(), key_pair_, directory_bot_jid_));
1341 host_change_notification_listener_.reset(new HostChangeNotificationListener(
1342 this, host_id_, signal_strategy_.get(), directory_bot_jid_));
1344 host_status_logger_.reset(
1345 new HostStatusLogger(host_->AsWeakPtr(), ServerLogEntry::ME2ME,
1346 signal_strategy_.get(), directory_bot_jid_));
1348 // Set up reporting the host status notifications.
1349 #if defined(REMOTING_MULTI_PROCESS)
1350 host_event_logger_.reset(
1351 new IpcHostEventLogger(host_->AsWeakPtr(), daemon_channel_.get()));
1352 #else // !defined(REMOTING_MULTI_PROCESS)
1353 host_event_logger_ =
1354 HostEventLogger::Create(host_->AsWeakPtr(), kApplicationName);
1355 #endif // !defined(REMOTING_MULTI_PROCESS)
1357 host_->SetEnableCurtaining(curtain_required_);
1358 host_->Start(host_owner_email_);
1360 CreateAuthenticatorFactory();
1363 void HostProcess::OnAuthFailed() {
1364 ShutdownHost(kInvalidOauthCredentialsExitCode);
1367 void HostProcess::RestartHost() {
1368 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1369 DCHECK_EQ(state_, HOST_STARTED);
1371 state_ = HOST_STOPPING_TO_RESTART;
1372 ShutdownOnNetworkThread();
1375 void HostProcess::ShutdownHost(HostExitCodes exit_code) {
1376 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1378 *exit_code_out_ = exit_code;
1380 switch (state_) {
1381 case HOST_INITIALIZING:
1382 state_ = HOST_STOPPING;
1383 ShutdownOnNetworkThread();
1384 break;
1386 case HOST_STARTED:
1387 state_ = HOST_STOPPING;
1388 heartbeat_sender_->SetHostOfflineReason(
1389 ExitCodeToString(exit_code), base::Bind(base::DoNothing));
1390 ScheduleHostShutdown();
1391 break;
1393 case HOST_STOPPING_TO_RESTART:
1394 state_ = HOST_STOPPING;
1395 break;
1397 case HOST_STOPPING:
1398 case HOST_STOPPED:
1399 // Host is already stopped or being stopped. No action is required.
1400 break;
1404 // TODO(weitaosu): shut down the host once we get an ACK for the offline status
1405 // XMPP message.
1406 void HostProcess::ScheduleHostShutdown() {
1407 // Delay the shutdown by 2 second to allow SendOfflineStatus to complete.
1408 context_->network_task_runner()->PostDelayedTask(
1409 FROM_HERE,
1410 base::Bind(&HostProcess::ShutdownOnNetworkThread, base::Unretained(this)),
1411 base::TimeDelta::FromSeconds(2));
1414 void HostProcess::ShutdownOnNetworkThread() {
1415 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1417 host_.reset();
1418 host_event_logger_.reset();
1419 host_status_logger_.reset();
1420 heartbeat_sender_.reset();
1421 host_change_notification_listener_.reset();
1422 signaling_connector_.reset();
1423 oauth_token_getter_.reset();
1424 signal_strategy_.reset();
1425 network_change_notifier_.reset();
1427 if (state_ == HOST_STOPPING_TO_RESTART) {
1428 StartHost();
1429 } else if (state_ == HOST_STOPPING) {
1430 state_ = HOST_STOPPED;
1432 shutdown_watchdog_->SetExitCode(*exit_code_out_);
1433 shutdown_watchdog_->Arm();
1435 if (policy_watcher_.get()) {
1436 policy_watcher_->StopWatching(
1437 base::Bind(&HostProcess::OnPolicyWatcherShutdown, this));
1438 } else {
1439 OnPolicyWatcherShutdown();
1441 } else {
1442 // This method is only called in STOPPING_TO_RESTART and STOPPING states.
1443 NOTREACHED();
1447 void HostProcess::OnPolicyWatcherShutdown() {
1448 policy_watcher_.reset();
1450 // Complete the rest of shutdown on the main thread.
1451 context_->ui_task_runner()->PostTask(
1452 FROM_HERE, base::Bind(&HostProcess::ShutdownOnUiThread, this));
1455 void HostProcess::OnCrash(const std::string& function_name,
1456 const std::string& file_name,
1457 const int& line_number) {
1458 char message[1024];
1459 base::snprintf(message, sizeof(message),
1460 "Requested by %s at %s, line %d.",
1461 function_name.c_str(), file_name.c_str(), line_number);
1462 base::debug::Alias(message);
1464 // The daemon requested us to crash the process.
1465 CHECK(false) << message;
1468 int HostProcessMain() {
1469 #if defined(OS_LINUX)
1470 // Required in order for us to run multiple X11 threads.
1471 XInitThreads();
1473 // Required for any calls into GTK functions, such as the Disconnect and
1474 // Continue windows, though these should not be used for the Me2Me case
1475 // (crbug.com/104377).
1476 gtk_init(NULL, NULL);
1477 #endif
1479 // Enable support for SSL server sockets, which must be done while still
1480 // single-threaded.
1481 net::EnableSSLServerSockets();
1483 // Ensures runtime specific CPU features are initialized.
1484 media::InitializeCPUSpecificMediaFeatures();
1486 // Create the main message loop and start helper threads.
1487 base::MessageLoopForUI message_loop;
1488 scoped_ptr<ChromotingHostContext> context =
1489 ChromotingHostContext::Create(new AutoThreadTaskRunner(
1490 message_loop.message_loop_proxy(), base::MessageLoop::QuitClosure()));
1491 if (!context)
1492 return kInitializationFailed;
1494 // Create & start the HostProcess using these threads.
1495 // TODO(wez): The HostProcess holds a reference to itself until Shutdown().
1496 // Remove this hack as part of the multi-process refactoring.
1497 int exit_code = kSuccessExitCode;
1498 ShutdownWatchdog shutdown_watchdog(
1499 base::TimeDelta::FromSeconds(kShutdownTimeoutSeconds));
1500 new HostProcess(context.Pass(), &exit_code, &shutdown_watchdog);
1502 // Run the main (also UI) message loop until the host no longer needs it.
1503 message_loop.Run();
1505 return exit_code;
1508 } // namespace remoting