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.
5 // This file implements a standalone host process for Me2Me.
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/service_urls.h"
40 #include "remoting/base/util.h"
41 #include "remoting/host/branding.h"
42 #include "remoting/host/chromoting_host.h"
43 #include "remoting/host/chromoting_host_context.h"
44 #include "remoting/host/chromoting_messages.h"
45 #include "remoting/host/config_file_watcher.h"
46 #include "remoting/host/config_watcher.h"
47 #include "remoting/host/desktop_environment.h"
48 #include "remoting/host/desktop_session_connector.h"
49 #include "remoting/host/dns_blackhole_checker.h"
50 #include "remoting/host/heartbeat_sender.h"
51 #include "remoting/host/host_change_notification_listener.h"
52 #include "remoting/host/host_config.h"
53 #include "remoting/host/host_event_logger.h"
54 #include "remoting/host/host_exit_codes.h"
55 #include "remoting/host/host_main.h"
56 #include "remoting/host/host_status_logger.h"
57 #include "remoting/host/host_status_sender.h"
58 #include "remoting/host/ipc_constants.h"
59 #include "remoting/host/ipc_desktop_environment.h"
60 #include "remoting/host/ipc_host_event_logger.h"
61 #include "remoting/host/json_host_config.h"
62 #include "remoting/host/logging.h"
63 #include "remoting/host/me2me_desktop_environment.h"
64 #include "remoting/host/pairing_registry_delegate.h"
65 #include "remoting/host/policy_hack/policy_watcher.h"
66 #include "remoting/host/session_manager_factory.h"
67 #include "remoting/host/signaling_connector.h"
68 #include "remoting/host/single_window_desktop_environment.h"
69 #include "remoting/host/token_validator_factory_impl.h"
70 #include "remoting/host/usage_stats_consent.h"
71 #include "remoting/host/username.h"
72 #include "remoting/host/video_frame_recorder_host_extension.h"
73 #include "remoting/protocol/me2me_host_authenticator_factory.h"
74 #include "remoting/protocol/network_settings.h"
75 #include "remoting/protocol/pairing_registry.h"
76 #include "remoting/protocol/token_validator.h"
77 #include "remoting/signaling/xmpp_signal_strategy.h"
81 #include <sys/types.h>
83 #include "base/file_descriptor_posix.h"
84 #include "remoting/host/pam_authorization_factory_posix.h"
85 #include "remoting/host/posix/signal_handler.h"
86 #endif // defined(OS_POSIX)
88 #if defined(OS_MACOSX)
89 #include "base/mac/scoped_cftyperef.h"
90 #endif // defined(OS_MACOSX)
95 #include "remoting/host/audio_capturer_linux.h"
96 #endif // defined(OS_LINUX)
100 #include "base/win/registry.h"
101 #include "base/win/scoped_handle.h"
102 #include "remoting/host/pairing_registry_delegate_win.h"
103 #include "remoting/host/win/session_desktop_environment.h"
104 #endif // defined(OS_WIN)
106 using remoting::protocol::PairingRegistry
;
107 using remoting::protocol::NetworkSettings
;
111 // This is used for tagging system event logs.
112 const char kApplicationName
[] = "chromoting";
114 #if defined(OS_LINUX)
115 // The command line switch used to pass name of the pipe to capture audio on
117 const char kAudioPipeSwitchName
[] = "audio-pipe-name";
119 // The command line switch used to pass name of the unix domain socket used to
120 // listen for gnubby requests.
121 const char kAuthSocknameSwitchName
[] = "ssh-auth-sockname";
122 #endif // defined(OS_LINUX)
124 // The command line switch used by the parent to request the host to signal it
125 // when it is successfully started.
126 const char kSignalParentSwitchName
[] = "signal-parent";
128 // Command line switch used to enable VP9 encoding.
129 const char kEnableVp9SwitchName
[] = "enable-vp9";
131 // Command line switch used to enable and configure the frame-recorder.
132 const char kFrameRecorderBufferKbName
[] = "frame-recorder-buffer-kb";
134 // Value used for --host-config option to indicate that the path must be read
136 const char kStdinConfigPath
[] = "-";
138 const char kWindowIdSwitchName
[] = "window-id";
145 : public ConfigWatcher::Delegate
,
146 public HeartbeatSender::Listener
,
147 public HostChangeNotificationListener::Listener
,
148 public IPC::Listener
,
149 public base::RefCountedThreadSafe
<HostProcess
> {
151 HostProcess(scoped_ptr
<ChromotingHostContext
> context
,
154 // ConfigWatcher::Delegate interface.
155 virtual void OnConfigUpdated(const std::string
& serialized_config
) OVERRIDE
;
156 virtual void OnConfigWatcherError() OVERRIDE
;
158 // IPC::Listener implementation.
159 virtual bool OnMessageReceived(const IPC::Message
& message
) OVERRIDE
;
160 virtual void OnChannelError() OVERRIDE
;
162 // HeartbeatSender::Listener overrides.
163 virtual void OnHeartbeatSuccessful() OVERRIDE
;
164 virtual void OnUnknownHostIdError() OVERRIDE
;
166 // HostChangeNotificationListener::Listener overrides.
167 virtual void OnHostDeleted() OVERRIDE
;
169 // Initializes the pairing registry on Windows.
170 void OnInitializePairingRegistry(
171 IPC::PlatformFileForTransit privileged_key
,
172 IPC::PlatformFileForTransit unprivileged_key
);
176 // Host process has just been started. Waiting for config and policies to be
177 // read from the disk.
180 // Host is started and running.
183 // Host is being stopped and will need to be started again.
184 HOST_STOPPING_TO_RESTART
,
186 // Host is being stopped.
189 // Host has been stopped.
192 // Allowed state transitions:
193 // INITIALIZING->STARTED
194 // INITIALIZING->STOPPED
195 // STARTED->STOPPING_TO_RESTART
197 // STOPPING_TO_RESTART->STARTED
198 // STOPPING_TO_RESTART->STOPPING
202 // |host_| must be NULL in INITIALIZING and STOPPED states and not-NULL in
206 friend class base::RefCountedThreadSafe
<HostProcess
>;
207 virtual ~HostProcess();
209 void StartOnNetworkThread();
211 #if defined(OS_POSIX)
212 // Callback passed to RegisterSignalHandler() to handle SIGTERM events.
213 void SigTermHandler(int signal_number
);
216 // Called to initialize resources on the UI thread.
217 void StartOnUiThread();
219 // Initializes IPC control channel and config file path from |cmd_line|.
220 // Called on the UI thread.
221 bool InitWithCommandLine(const base::CommandLine
* cmd_line
);
223 // Called on the UI thread to start monitoring the configuration file.
224 void StartWatchingConfigChanges();
226 // Called on the network thread to set the host's Authenticator factory.
227 void CreateAuthenticatorFactory();
229 // Tear down resources that run on the UI thread.
230 void ShutdownOnUiThread();
232 // Applies the host config, returning true if successful.
233 bool ApplyConfig(scoped_ptr
<JsonHostConfig
> config
);
235 // Handles policy updates, by calling On*PolicyUpdate methods.
236 void OnPolicyUpdate(scoped_ptr
<base::DictionaryValue
> policies
);
237 void ApplyHostDomainPolicy();
238 void ApplyUsernamePolicy();
239 bool OnHostDomainPolicyUpdate(base::DictionaryValue
* policies
);
240 bool OnUsernamePolicyUpdate(base::DictionaryValue
* policies
);
241 bool OnNatPolicyUpdate(base::DictionaryValue
* policies
);
242 bool OnRelayPolicyUpdate(base::DictionaryValue
* policies
);
243 bool OnUdpPortPolicyUpdate(base::DictionaryValue
* policies
);
244 bool OnCurtainPolicyUpdate(base::DictionaryValue
* policies
);
245 bool OnHostTalkGadgetPrefixPolicyUpdate(base::DictionaryValue
* policies
);
246 bool OnHostTokenUrlPolicyUpdate(base::DictionaryValue
* policies
);
247 bool OnPairingPolicyUpdate(base::DictionaryValue
* policies
);
248 bool OnGnubbyAuthPolicyUpdate(base::DictionaryValue
* policies
);
256 // Stops the host and shuts down the process with the specified |exit_code|.
257 void ShutdownHost(HostExitCodes exit_code
);
259 void ScheduleHostShutdown();
261 void ShutdownOnNetworkThread();
263 // Crashes the process in response to a daemon's request. The daemon passes
264 // the location of the code that detected the fatal error resulted in this
266 void OnCrash(const std::string
& function_name
,
267 const std::string
& file_name
,
268 const int& line_number
);
270 scoped_ptr
<ChromotingHostContext
> context_
;
272 // Created on the UI thread but used from the network thread.
273 scoped_ptr
<net::NetworkChangeNotifier
> network_change_notifier_
;
275 // Accessed on the UI thread.
276 scoped_ptr
<IPC::ChannelProxy
> daemon_channel_
;
278 // XMPP server/remoting bot configuration (initialized from the command line).
279 XmppSignalStrategy::XmppServerConfig xmpp_server_config_
;
280 std::string directory_bot_jid_
;
282 // Created on the UI thread but used from the network thread.
283 base::FilePath host_config_path_
;
284 std::string host_config_
;
285 scoped_ptr
<DesktopEnvironmentFactory
> desktop_environment_factory_
;
287 // Accessed on the network thread.
290 scoped_ptr
<ConfigWatcher
> config_watcher_
;
292 std::string host_id_
;
293 protocol::SharedSecretHash host_secret_hash_
;
294 scoped_refptr
<RsaKeyPair
> key_pair_
;
295 std::string oauth_refresh_token_
;
296 std::string serialized_config_
;
297 std::string host_owner_
;
298 bool use_service_account_
;
300 int64_t frame_recorder_buffer_size_
;
302 scoped_ptr
<policy_hack::PolicyWatcher
> policy_watcher_
;
303 std::string host_domain_
;
304 bool host_username_match_required_
;
305 bool allow_nat_traversal_
;
309 std::string talkgadget_prefix_
;
312 bool curtain_required_
;
313 ThirdPartyAuthConfig third_party_auth_config_
;
314 bool enable_gnubby_auth_
;
316 // Boolean to change flow, where ncessary, if we're
317 // capturing a window instead of the entire desktop.
318 bool enable_window_capture_
;
320 // Used to specify which window to stream, if enabled.
321 webrtc::WindowId window_id_
;
323 scoped_ptr
<OAuthTokenGetter
> oauth_token_getter_
;
324 scoped_ptr
<XmppSignalStrategy
> signal_strategy_
;
325 scoped_ptr
<SignalingConnector
> signaling_connector_
;
326 scoped_ptr
<HeartbeatSender
> heartbeat_sender_
;
327 scoped_ptr
<HostStatusSender
> host_status_sender_
;
328 scoped_ptr
<HostChangeNotificationListener
> host_change_notification_listener_
;
329 scoped_ptr
<HostStatusLogger
> host_status_logger_
;
330 scoped_ptr
<HostEventLogger
> host_event_logger_
;
332 scoped_ptr
<ChromotingHost
> host_
;
334 // Used to keep this HostProcess alive until it is shutdown.
335 scoped_refptr
<HostProcess
> self_
;
337 #if defined(REMOTING_MULTI_PROCESS)
338 DesktopSessionConnector
* desktop_session_connector_
;
339 #endif // defined(REMOTING_MULTI_PROCESS)
344 scoped_ptr
<PairingRegistry::Delegate
> pairing_registry_delegate_
;
347 HostProcess::HostProcess(scoped_ptr
<ChromotingHostContext
> context
,
349 : context_(context
.Pass()),
350 state_(HOST_INITIALIZING
),
351 use_service_account_(false),
353 frame_recorder_buffer_size_(0),
354 host_username_match_required_(false),
355 allow_nat_traversal_(true),
359 allow_pairing_(true),
360 curtain_required_(false),
361 enable_gnubby_auth_(false),
362 enable_window_capture_(false),
364 #if defined(REMOTING_MULTI_PROCESS)
365 desktop_session_connector_(NULL
),
366 #endif // defined(REMOTING_MULTI_PROCESS)
368 exit_code_out_(exit_code_out
),
369 signal_parent_(false) {
373 HostProcess::~HostProcess() {
374 // Verify that UI components have been torn down.
375 DCHECK(!config_watcher_
);
376 DCHECK(!daemon_channel_
);
377 DCHECK(!desktop_environment_factory_
);
379 // We might be getting deleted on one of the threads the |host_context| owns,
380 // so we need to post it back to the caller thread to safely join & delete the
381 // threads it contains. This will go away when we move to AutoThread.
382 // |context_release()| will null |context_| before the method is invoked, so
383 // we need to pull out the task-runner on which to call DeleteSoon first.
384 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
=
385 context_
->ui_task_runner();
386 task_runner
->DeleteSoon(FROM_HERE
, context_
.release());
389 bool HostProcess::InitWithCommandLine(const base::CommandLine
* cmd_line
) {
390 #if defined(REMOTING_MULTI_PROCESS)
391 // Parse the handle value and convert it to a handle/file descriptor.
392 std::string channel_name
=
393 cmd_line
->GetSwitchValueASCII(kDaemonPipeSwitchName
);
396 if (channel_name
.empty() ||
397 !base::StringToInt(channel_name
, &pipe_handle
)) {
398 LOG(ERROR
) << "Invalid '" << kDaemonPipeSwitchName
399 << "' value: " << channel_name
;
404 base::win::ScopedHandle
pipe(reinterpret_cast<HANDLE
>(pipe_handle
));
405 IPC::ChannelHandle
channel_handle(pipe
);
406 #elif defined(OS_POSIX)
407 base::FileDescriptor
pipe(pipe_handle
, true);
408 IPC::ChannelHandle
channel_handle(channel_name
, pipe
);
409 #endif // defined(OS_POSIX)
411 // Connect to the daemon process.
412 daemon_channel_
= IPC::ChannelProxy::Create(channel_handle
,
413 IPC::Channel::MODE_CLIENT
,
415 context_
->network_task_runner());
416 #else // !defined(REMOTING_MULTI_PROCESS)
417 // Connect to the daemon process.
418 std::string channel_name
=
419 cmd_line
->GetSwitchValueASCII(kDaemonPipeSwitchName
);
420 if (!channel_name
.empty()) {
422 IPC::ChannelProxy::Create(channel_name
,
423 IPC::Channel::MODE_CLIENT
,
425 context_
->network_task_runner().get());
428 if (cmd_line
->HasSwitch(kHostConfigSwitchName
)) {
429 host_config_path_
= cmd_line
->GetSwitchValuePath(kHostConfigSwitchName
);
431 // Read config from stdin if necessary.
432 if (host_config_path_
== base::FilePath(kStdinConfigPath
)) {
435 while ((len
= fread(buf
, 1, sizeof(buf
), stdin
)) > 0) {
436 host_config_
.append(buf
, len
);
440 base::FilePath default_config_dir
= remoting::GetConfigDir();
441 host_config_path_
= default_config_dir
.Append(kDefaultHostConfigFile
);
444 if (host_config_path_
!= base::FilePath(kStdinConfigPath
) &&
445 !base::PathExists(host_config_path_
)) {
446 LOG(ERROR
) << "Can't find host config at " << host_config_path_
.value();
449 #endif // !defined(REMOTING_MULTI_PROCESS)
451 // Ignore certificate requests - the host currently has no client certificate
452 // support, so ignoring certificate requests allows connecting to servers that
453 // request, but don't require, a certificate (optional client authentication).
454 net::URLFetcher::SetIgnoreCertificateRequests(true);
456 ServiceUrls
* service_urls
= ServiceUrls::GetInstance();
457 bool xmpp_server_valid
= net::ParseHostAndPort(
458 service_urls
->xmpp_server_address(),
459 &xmpp_server_config_
.host
, &xmpp_server_config_
.port
);
460 if (!xmpp_server_valid
) {
461 LOG(ERROR
) << "Invalid XMPP server: " <<
462 service_urls
->xmpp_server_address();
465 xmpp_server_config_
.use_tls
= service_urls
->xmpp_server_use_tls();
466 directory_bot_jid_
= service_urls
->directory_bot_jid();
468 signal_parent_
= cmd_line
->HasSwitch(kSignalParentSwitchName
);
470 enable_window_capture_
= cmd_line
->HasSwitch(kWindowIdSwitchName
);
471 if (enable_window_capture_
) {
473 #if defined(OS_LINUX) || defined(OS_WIN)
474 LOG(WARNING
) << "Window capturing is not fully supported on Linux or "
476 #endif // defined(OS_LINUX) || defined(OS_WIN)
478 // uint32_t is large enough to hold window IDs on all platforms.
480 if (base::StringToUint(
481 cmd_line
->GetSwitchValueASCII(kWindowIdSwitchName
),
483 window_id_
= static_cast<webrtc::WindowId
>(window_id
);
485 LOG(ERROR
) << "Window with window id: " << window_id_
486 << " not found. Shutting down host.";
493 void HostProcess::OnConfigUpdated(
494 const std::string
& serialized_config
) {
495 if (!context_
->network_task_runner()->BelongsToCurrentThread()) {
496 context_
->network_task_runner()->PostTask(FROM_HERE
,
497 base::Bind(&HostProcess::OnConfigUpdated
, this, serialized_config
));
501 // Filter out duplicates.
502 if (serialized_config_
== serialized_config
)
505 HOST_LOG
<< "Processing new host configuration.";
507 serialized_config_
= serialized_config
;
508 scoped_ptr
<JsonHostConfig
> config(new JsonHostConfig(base::FilePath()));
509 if (!config
->SetSerializedData(serialized_config
)) {
510 LOG(ERROR
) << "Invalid configuration.";
511 ShutdownHost(kInvalidHostConfigurationExitCode
);
515 if (!ApplyConfig(config
.Pass())) {
516 LOG(ERROR
) << "Failed to apply the configuration.";
517 ShutdownHost(kInvalidHostConfigurationExitCode
);
521 if (state_
== HOST_INITIALIZING
) {
522 // TODO(sergeyu): Currently OnPolicyUpdate() assumes that host config is
523 // already loaded so PolicyWatcher has to be started here. Separate policy
524 // loading from policy verifications and move |policy_watcher_|
525 // initialization to StartOnNetworkThread().
526 policy_watcher_
.reset(
527 policy_hack::PolicyWatcher::Create(context_
->file_task_runner()));
528 policy_watcher_
->StartWatching(
529 base::Bind(&HostProcess::OnPolicyUpdate
, base::Unretained(this)));
531 // Reapply policies that could be affected by a new config.
532 ApplyHostDomainPolicy();
533 ApplyUsernamePolicy();
535 if (state_
== HOST_STARTED
) {
536 // TODO(sergeyu): Here we assume that PIN is the only part of the config
537 // that may change while the service is running. Change ApplyConfig() to
538 // detect other changes in the config and restart host if necessary here.
539 CreateAuthenticatorFactory();
544 void HostProcess::OnConfigWatcherError() {
545 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
546 ShutdownHost(kInvalidHostConfigurationExitCode
);
549 void HostProcess::StartOnNetworkThread() {
550 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
552 #if !defined(REMOTING_MULTI_PROCESS)
553 if (host_config_path_
== base::FilePath(kStdinConfigPath
)) {
554 // Process config we've read from stdin.
555 OnConfigUpdated(host_config_
);
557 // Start watching the host configuration file.
558 config_watcher_
.reset(new ConfigFileWatcher(context_
->network_task_runner(),
559 context_
->file_task_runner(),
561 config_watcher_
->Watch(this);
563 #endif // !defined(REMOTING_MULTI_PROCESS)
565 #if defined(OS_POSIX)
566 remoting::RegisterSignalHandler(
568 base::Bind(&HostProcess::SigTermHandler
, base::Unretained(this)));
569 #endif // defined(OS_POSIX)
572 #if defined(OS_POSIX)
573 void HostProcess::SigTermHandler(int signal_number
) {
574 DCHECK(signal_number
== SIGTERM
);
575 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
576 HOST_LOG
<< "Caught SIGTERM: Shutting down...";
577 ShutdownHost(kSuccessExitCode
);
581 void HostProcess::CreateAuthenticatorFactory() {
582 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
584 if (state_
!= HOST_STARTED
)
587 std::string local_certificate
= key_pair_
->GenerateCertificate();
588 if (local_certificate
.empty()) {
589 LOG(ERROR
) << "Failed to generate host certificate.";
590 ShutdownHost(kInitializationFailed
);
594 scoped_refptr
<PairingRegistry
> pairing_registry
= NULL
;
595 if (allow_pairing_
) {
596 if (!pairing_registry_delegate_
)
597 pairing_registry_delegate_
= CreatePairingRegistryDelegate();
599 if (pairing_registry_delegate_
) {
600 pairing_registry
= new PairingRegistry(context_
->file_task_runner(),
601 pairing_registry_delegate_
.Pass());
605 scoped_ptr
<protocol::AuthenticatorFactory
> factory
;
607 if (third_party_auth_config_
.is_empty()) {
608 factory
= protocol::Me2MeHostAuthenticatorFactory::CreateWithSharedSecret(
609 use_service_account_
, host_owner_
, local_certificate
, key_pair_
,
610 host_secret_hash_
, pairing_registry
);
612 } else if (third_party_auth_config_
.is_valid()) {
613 scoped_ptr
<protocol::TokenValidatorFactory
> token_validator_factory(
614 new TokenValidatorFactoryImpl(
615 third_party_auth_config_
,
616 key_pair_
, context_
->url_request_context_getter()));
617 factory
= protocol::Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth(
618 use_service_account_
, host_owner_
, local_certificate
, key_pair_
,
619 token_validator_factory
.Pass());
622 // TODO(rmsousa): If the policy is bad the host should not go online. It
623 // should keep running, but not connected, until the policies are fixed.
624 // Having it show up as online and then reject all clients is misleading.
625 LOG(ERROR
) << "One of the third-party token URLs is empty or invalid. "
626 << "Host will reject all clients until policies are corrected. "
627 << "TokenUrl: " << third_party_auth_config_
.token_url
<< ", "
628 << "TokenValidationUrl: "
629 << third_party_auth_config_
.token_validation_url
;
630 factory
= protocol::Me2MeHostAuthenticatorFactory::CreateRejecting();
633 #if defined(OS_POSIX)
634 // On Linux and Mac, perform a PAM authorization step after authentication.
635 factory
.reset(new PamAuthorizationFactory(factory
.Pass()));
637 host_
->SetAuthenticatorFactory(factory
.Pass());
639 host_
->set_pairing_registry(pairing_registry
);
642 // IPC::Listener implementation.
643 bool HostProcess::OnMessageReceived(const IPC::Message
& message
) {
644 DCHECK(context_
->ui_task_runner()->BelongsToCurrentThread());
646 #if defined(REMOTING_MULTI_PROCESS)
648 IPC_BEGIN_MESSAGE_MAP(HostProcess
, message
)
649 IPC_MESSAGE_HANDLER(ChromotingDaemonMsg_Crash
, OnCrash
)
650 IPC_MESSAGE_HANDLER(ChromotingDaemonNetworkMsg_Configuration
,
652 IPC_MESSAGE_HANDLER(ChromotingDaemonNetworkMsg_InitializePairingRegistry
,
653 OnInitializePairingRegistry
)
655 ChromotingDaemonNetworkMsg_DesktopAttached
,
656 desktop_session_connector_
,
657 DesktopSessionConnector::OnDesktopSessionAgentAttached
)
658 IPC_MESSAGE_FORWARD(ChromotingDaemonNetworkMsg_TerminalDisconnected
,
659 desktop_session_connector_
,
660 DesktopSessionConnector::OnTerminalDisconnected
)
661 IPC_MESSAGE_UNHANDLED(handled
= false)
662 IPC_END_MESSAGE_MAP()
664 CHECK(handled
) << "Received unexpected IPC type: " << message
.type();
667 #else // !defined(REMOTING_MULTI_PROCESS)
669 #endif // !defined(REMOTING_MULTI_PROCESS)
672 void HostProcess::OnChannelError() {
673 DCHECK(context_
->ui_task_runner()->BelongsToCurrentThread());
675 // Shutdown the host if the daemon process disconnects the IPC channel.
676 context_
->network_task_runner()->PostTask(
678 base::Bind(&HostProcess::ShutdownHost
, this, kSuccessExitCode
));
681 void HostProcess::StartOnUiThread() {
682 DCHECK(context_
->ui_task_runner()->BelongsToCurrentThread());
684 if (!InitWithCommandLine(base::CommandLine::ForCurrentProcess())) {
685 // Shutdown the host if the command line is invalid.
686 context_
->network_task_runner()->PostTask(
687 FROM_HERE
, base::Bind(&HostProcess::ShutdownHost
, this,
692 #if defined(OS_LINUX)
693 // If an audio pipe is specific on the command-line then initialize
694 // AudioCapturerLinux to capture from it.
695 base::FilePath audio_pipe_name
= base::CommandLine::ForCurrentProcess()->
696 GetSwitchValuePath(kAudioPipeSwitchName
);
697 if (!audio_pipe_name
.empty()) {
698 remoting::AudioCapturerLinux::InitializePipeReader(
699 context_
->audio_task_runner(), audio_pipe_name
);
702 base::FilePath gnubby_socket_name
= base::CommandLine::ForCurrentProcess()->
703 GetSwitchValuePath(kAuthSocknameSwitchName
);
704 if (!gnubby_socket_name
.empty())
705 remoting::GnubbyAuthHandler::SetGnubbySocketName(gnubby_socket_name
);
706 #endif // defined(OS_LINUX)
708 // Create a desktop environment factory appropriate to the build type &
711 IpcDesktopEnvironmentFactory
* desktop_environment_factory
=
712 new IpcDesktopEnvironmentFactory(
713 context_
->audio_task_runner(),
714 context_
->network_task_runner(),
715 context_
->video_capture_task_runner(),
716 context_
->network_task_runner(),
717 daemon_channel_
.get());
718 desktop_session_connector_
= desktop_environment_factory
;
719 #else // !defined(OS_WIN)
720 DesktopEnvironmentFactory
* desktop_environment_factory
;
721 if (enable_window_capture_
) {
722 desktop_environment_factory
=
723 new SingleWindowDesktopEnvironmentFactory(
724 context_
->network_task_runner(),
725 context_
->input_task_runner(),
726 context_
->ui_task_runner(),
729 desktop_environment_factory
=
730 new Me2MeDesktopEnvironmentFactory(
731 context_
->network_task_runner(),
732 context_
->input_task_runner(),
733 context_
->ui_task_runner());
735 #endif // !defined(OS_WIN)
737 desktop_environment_factory_
.reset(desktop_environment_factory
);
738 desktop_environment_factory_
->SetEnableGnubbyAuth(enable_gnubby_auth_
);
740 context_
->network_task_runner()->PostTask(
742 base::Bind(&HostProcess::StartOnNetworkThread
, this));
745 void HostProcess::ShutdownOnUiThread() {
746 DCHECK(context_
->ui_task_runner()->BelongsToCurrentThread());
748 // Tear down resources that need to be torn down on the UI thread.
749 network_change_notifier_
.reset();
750 daemon_channel_
.reset();
751 desktop_environment_factory_
.reset();
753 // It is now safe for the HostProcess to be deleted.
756 #if defined(OS_LINUX)
757 // Cause the global AudioPipeReader to be freed, otherwise the audio
758 // thread will remain in-use and prevent the process from exiting.
759 // TODO(wez): DesktopEnvironmentFactory should own the pipe reader.
760 // See crbug.com/161373 and crbug.com/104544.
761 AudioCapturerLinux::InitializePipeReader(NULL
, base::FilePath());
765 // Overridden from HeartbeatSender::Listener
766 void HostProcess::OnUnknownHostIdError() {
767 LOG(ERROR
) << "Host ID not found.";
768 ShutdownHost(kInvalidHostIdExitCode
);
771 void HostProcess::OnHeartbeatSuccessful() {
772 HOST_LOG
<< "Host ready to receive connections.";
773 #if defined(OS_POSIX)
774 if (signal_parent_
) {
775 kill(getppid(), SIGUSR1
);
776 signal_parent_
= false;
781 void HostProcess::OnHostDeleted() {
782 LOG(ERROR
) << "Host was deleted from the directory.";
783 ShutdownHost(kInvalidHostIdExitCode
);
786 void HostProcess::OnInitializePairingRegistry(
787 IPC::PlatformFileForTransit privileged_key
,
788 IPC::PlatformFileForTransit unprivileged_key
) {
789 DCHECK(!pairing_registry_delegate_
);
792 // Initialize the pairing registry delegate.
793 scoped_ptr
<PairingRegistryDelegateWin
> delegate(
794 new PairingRegistryDelegateWin());
795 bool result
= delegate
->SetRootKeys(
796 reinterpret_cast<HKEY
>(
797 IPC::PlatformFileForTransitToPlatformFile(privileged_key
)),
798 reinterpret_cast<HKEY
>(
799 IPC::PlatformFileForTransitToPlatformFile(unprivileged_key
)));
803 pairing_registry_delegate_
= delegate
.PassAs
<PairingRegistry::Delegate
>();
804 #else // !defined(OS_WIN)
806 #endif // !defined(OS_WIN)
809 // Applies the host config, returning true if successful.
810 bool HostProcess::ApplyConfig(scoped_ptr
<JsonHostConfig
> config
) {
811 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
813 if (!config
->GetString(kHostIdConfigPath
, &host_id_
)) {
814 LOG(ERROR
) << "host_id is not defined in the config.";
818 std::string key_base64
;
819 if (!config
->GetString(kPrivateKeyConfigPath
, &key_base64
)) {
820 LOG(ERROR
) << "Private key couldn't be read from the config file.";
824 key_pair_
= RsaKeyPair::FromString(key_base64
);
825 if (!key_pair_
.get()) {
826 LOG(ERROR
) << "Invalid private key in the config file.";
830 std::string host_secret_hash_string
;
831 if (!config
->GetString(kHostSecretHashConfigPath
,
832 &host_secret_hash_string
)) {
833 host_secret_hash_string
= "plain:";
836 if (!host_secret_hash_
.Parse(host_secret_hash_string
)) {
837 LOG(ERROR
) << "Invalid host_secret_hash.";
841 // Use an XMPP connection to the Talk network for session signalling.
842 if (!config
->GetString(kXmppLoginConfigPath
, &xmpp_server_config_
.username
) ||
843 !(config
->GetString(kXmppAuthTokenConfigPath
,
844 &xmpp_server_config_
.auth_token
) ||
845 config
->GetString(kOAuthRefreshTokenConfigPath
,
846 &oauth_refresh_token_
))) {
847 LOG(ERROR
) << "XMPP credentials are not defined in the config.";
851 if (!oauth_refresh_token_
.empty()) {
852 // SignalingConnector is responsible for getting OAuth token.
853 xmpp_server_config_
.auth_token
= "";
854 xmpp_server_config_
.auth_service
= "oauth2";
855 } else if (!config
->GetString(kXmppAuthServiceConfigPath
,
856 &xmpp_server_config_
.auth_service
)) {
857 // For the me2me host, we default to ClientLogin token for chromiumsync
858 // because earlier versions of the host had no HTTP stack with which to
859 // request an OAuth2 access token.
860 xmpp_server_config_
.auth_service
= kChromotingTokenDefaultServiceName
;
863 if (config
->GetString(kHostOwnerConfigPath
, &host_owner_
)) {
864 // Service account configs have a host_owner, different from the xmpp_login.
865 use_service_account_
= true;
867 // User credential configs only have an xmpp_login, which is also the owner.
868 host_owner_
= xmpp_server_config_
.username
;
869 use_service_account_
= false;
872 // Allow offering of VP9 encoding to be overridden by the command-line.
873 if (CommandLine::ForCurrentProcess()->HasSwitch(kEnableVp9SwitchName
)) {
876 config
->GetBoolean(kEnableVp9ConfigPath
, &enable_vp9_
);
879 // Allow the command-line to override the size of the frame recorder buffer.
880 std::string frame_recorder_buffer_kb
;
881 if (CommandLine::ForCurrentProcess()->HasSwitch(
882 kFrameRecorderBufferKbName
)) {
883 frame_recorder_buffer_kb
=
884 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
885 kFrameRecorderBufferKbName
);
887 config
->GetString(kFrameRecorderBufferKbConfigPath
,
888 &frame_recorder_buffer_kb
);
890 if (!frame_recorder_buffer_kb
.empty()) {
892 if (base::StringToInt(frame_recorder_buffer_kb
, &buffer_kb
)) {
893 frame_recorder_buffer_size_
= 1024LL * buffer_kb
;
900 void HostProcess::OnPolicyUpdate(scoped_ptr
<base::DictionaryValue
> policies
) {
901 if (!context_
->network_task_runner()->BelongsToCurrentThread()) {
902 context_
->network_task_runner()->PostTask(FROM_HERE
, base::Bind(
903 &HostProcess::OnPolicyUpdate
, this, base::Passed(&policies
)));
907 bool restart_required
= false;
908 restart_required
|= OnHostDomainPolicyUpdate(policies
.get());
909 restart_required
|= OnCurtainPolicyUpdate(policies
.get());
910 // Note: UsernamePolicyUpdate must run after OnCurtainPolicyUpdate.
911 restart_required
|= OnUsernamePolicyUpdate(policies
.get());
912 restart_required
|= OnNatPolicyUpdate(policies
.get());
913 restart_required
|= OnRelayPolicyUpdate(policies
.get());
914 restart_required
|= OnUdpPortPolicyUpdate(policies
.get());
915 restart_required
|= OnHostTalkGadgetPrefixPolicyUpdate(policies
.get());
916 restart_required
|= OnHostTokenUrlPolicyUpdate(policies
.get());
917 restart_required
|= OnPairingPolicyUpdate(policies
.get());
918 restart_required
|= OnGnubbyAuthPolicyUpdate(policies
.get());
920 if (state_
== HOST_INITIALIZING
) {
922 } else if (state_
== HOST_STARTED
&& restart_required
) {
927 void HostProcess::ApplyHostDomainPolicy() {
928 HOST_LOG
<< "Policy sets host domain: " << host_domain_
;
929 if (!host_domain_
.empty() &&
930 !EndsWith(host_owner_
, std::string("@") + host_domain_
, false)) {
931 LOG(ERROR
) << "The host domain does not match the policy.";
932 ShutdownHost(kInvalidHostDomainExitCode
);
936 bool HostProcess::OnHostDomainPolicyUpdate(base::DictionaryValue
* policies
) {
937 // Returns true if the host has to be restarted after this policy update.
938 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
940 if (!policies
->GetString(policy_hack::PolicyWatcher::kHostDomainPolicyName
,
945 ApplyHostDomainPolicy();
949 void HostProcess::ApplyUsernamePolicy() {
950 if (host_username_match_required_
) {
951 HOST_LOG
<< "Policy requires host username match.";
952 std::string username
= GetUsername();
953 bool shutdown
= username
.empty() ||
954 !StartsWithASCII(host_owner_
, username
+ std::string("@"),
957 #if defined(OS_MACOSX)
958 // On Mac, we run as root at the login screen, so the username won't match.
959 // However, there's no need to enforce the policy at the login screen, as
960 // the client will have to reconnect if a login occurs.
961 if (shutdown
&& getuid() == 0) {
966 // Curtain-mode on Windows presents the standard OS login prompt to the user
967 // for each connection, removing the need for an explicit user-name matching
969 #if defined(OS_WIN) && defined(REMOTING_RDP_SESSION)
970 if (curtain_required_
)
972 #endif // defined(OS_WIN) && defined(REMOTING_RDP_SESSION)
974 // Shutdown the host if the username does not match.
976 LOG(ERROR
) << "The host username does not match.";
977 ShutdownHost(kUsernameMismatchExitCode
);
980 HOST_LOG
<< "Policy does not require host username match.";
984 bool HostProcess::OnUsernamePolicyUpdate(base::DictionaryValue
* policies
) {
985 // Returns false: never restart the host after this policy update.
986 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
988 if (!policies
->GetBoolean(
989 policy_hack::PolicyWatcher::kHostMatchUsernamePolicyName
,
990 &host_username_match_required_
)) {
994 ApplyUsernamePolicy();
998 bool HostProcess::OnNatPolicyUpdate(base::DictionaryValue
* policies
) {
999 // Returns true if the host has to be restarted after this policy update.
1000 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
1002 if (!policies
->GetBoolean(policy_hack::PolicyWatcher::kNatPolicyName
,
1003 &allow_nat_traversal_
)) {
1007 if (allow_nat_traversal_
) {
1008 HOST_LOG
<< "Policy enables NAT traversal.";
1010 HOST_LOG
<< "Policy disables NAT traversal.";
1015 bool HostProcess::OnRelayPolicyUpdate(base::DictionaryValue
* policies
) {
1016 // Returns true if the host has to be restarted after this policy update.
1017 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
1019 if (!policies
->GetBoolean(policy_hack::PolicyWatcher::kRelayPolicyName
,
1025 HOST_LOG
<< "Policy enables use of relay server.";
1027 HOST_LOG
<< "Policy disables use of relay server.";
1032 bool HostProcess::OnUdpPortPolicyUpdate(base::DictionaryValue
* policies
) {
1033 // Returns true if the host has to be restarted after this policy update.
1034 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
1036 std::string udp_port_range
;
1037 if (!policies
->GetString(policy_hack::PolicyWatcher::kUdpPortRangePolicyName
,
1042 // Use default values if policy setting is empty or invalid.
1043 int min_udp_port
= 0;
1044 int max_udp_port
= 0;
1045 if (!udp_port_range
.empty() &&
1046 !NetworkSettings::ParsePortRange(udp_port_range
, &min_udp_port
,
1048 LOG(WARNING
) << "Invalid port range policy: \"" << udp_port_range
1049 << "\". Using default values.";
1052 if (min_udp_port_
!= min_udp_port
|| max_udp_port_
!= max_udp_port
) {
1053 if (min_udp_port
!= 0 && max_udp_port
!= 0) {
1054 HOST_LOG
<< "Policy restricts UDP port range to [" << min_udp_port
1055 << ", " << max_udp_port
<< "]";
1057 HOST_LOG
<< "Policy does not restrict UDP port range.";
1059 min_udp_port_
= min_udp_port
;
1060 max_udp_port_
= max_udp_port
;
1066 bool HostProcess::OnCurtainPolicyUpdate(base::DictionaryValue
* policies
) {
1067 // Returns true if the host has to be restarted after this policy update.
1068 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
1070 if (!policies
->GetBoolean(
1071 policy_hack::PolicyWatcher::kHostRequireCurtainPolicyName
,
1072 &curtain_required_
)) {
1076 #if defined(OS_MACOSX)
1077 if (curtain_required_
) {
1078 // When curtain mode is in effect on Mac, the host process runs in the
1079 // user's switched-out session, but launchd will also run an instance at
1080 // the console login screen. Even if no user is currently logged-on, we
1081 // can't support remote-access to the login screen because the current host
1082 // process model disconnects the client during login, which would leave
1083 // the logged in session un-curtained on the console until they reconnect.
1085 // TODO(jamiewalch): Fix this once we have implemented the multi-process
1086 // daemon architecture (crbug.com/134894)
1087 if (getuid() == 0) {
1088 LOG(ERROR
) << "Running the host in the console login session is yet not "
1090 ShutdownHost(kLoginScreenNotSupportedExitCode
);
1096 if (curtain_required_
) {
1097 HOST_LOG
<< "Policy requires curtain-mode.";
1099 HOST_LOG
<< "Policy does not require curtain-mode.";
1103 host_
->SetEnableCurtaining(curtain_required_
);
1107 bool HostProcess::OnHostTalkGadgetPrefixPolicyUpdate(
1108 base::DictionaryValue
* policies
) {
1109 // Returns true if the host has to be restarted after this policy update.
1110 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
1112 if (!policies
->GetString(
1113 policy_hack::PolicyWatcher::kHostTalkGadgetPrefixPolicyName
,
1114 &talkgadget_prefix_
)) {
1118 HOST_LOG
<< "Policy sets talkgadget prefix: " << talkgadget_prefix_
;
1122 bool HostProcess::OnHostTokenUrlPolicyUpdate(base::DictionaryValue
* policies
) {
1123 // Returns true if the host has to be restarted after this policy update.
1124 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
1126 bool token_policy_changed
= false;
1127 std::string token_url_string
;
1128 if (policies
->GetString(
1129 policy_hack::PolicyWatcher::kHostTokenUrlPolicyName
,
1130 &token_url_string
)) {
1131 token_policy_changed
= true;
1132 third_party_auth_config_
.token_url
= GURL(token_url_string
);
1134 std::string token_validation_url_string
;
1135 if (policies
->GetString(
1136 policy_hack::PolicyWatcher::kHostTokenValidationUrlPolicyName
,
1137 &token_validation_url_string
)) {
1138 token_policy_changed
= true;
1139 third_party_auth_config_
.token_validation_url
=
1140 GURL(token_validation_url_string
);
1142 if (policies
->GetString(
1143 policy_hack::PolicyWatcher::kHostTokenValidationCertIssuerPolicyName
,
1144 &third_party_auth_config_
.token_validation_cert_issuer
)) {
1145 token_policy_changed
= true;
1148 if (token_policy_changed
) {
1149 HOST_LOG
<< "Policy sets third-party token URLs: "
1151 << third_party_auth_config_
.token_url
<< ", "
1152 << "TokenValidationUrl: "
1153 << third_party_auth_config_
.token_validation_url
<< ", "
1154 << "TokenValidationCertificateIssuer: "
1155 << third_party_auth_config_
.token_validation_cert_issuer
;
1157 return token_policy_changed
;
1160 bool HostProcess::OnPairingPolicyUpdate(base::DictionaryValue
* policies
) {
1161 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
1163 if (!policies
->GetBoolean(
1164 policy_hack::PolicyWatcher::kHostAllowClientPairing
,
1169 if (allow_pairing_
) {
1170 HOST_LOG
<< "Policy enables client pairing.";
1172 HOST_LOG
<< "Policy disables client pairing.";
1177 bool HostProcess::OnGnubbyAuthPolicyUpdate(base::DictionaryValue
* policies
) {
1178 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
1180 if (!policies
->GetBoolean(
1181 policy_hack::PolicyWatcher::kHostAllowGnubbyAuthPolicyName
,
1182 &enable_gnubby_auth_
)) {
1186 if (enable_gnubby_auth_
) {
1187 HOST_LOG
<< "Policy enables gnubby auth.";
1189 HOST_LOG
<< "Policy disables gnubby auth.";
1192 if (desktop_environment_factory_
)
1193 desktop_environment_factory_
->SetEnableGnubbyAuth(enable_gnubby_auth_
);
1198 void HostProcess::StartHost() {
1199 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
1201 DCHECK(!signal_strategy_
.get());
1202 DCHECK(state_
== HOST_INITIALIZING
|| state_
== HOST_STOPPING_TO_RESTART
||
1203 state_
== HOST_STOPPED
) << state_
;
1204 state_
= HOST_STARTED
;
1206 signal_strategy_
.reset(
1207 new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(),
1208 context_
->url_request_context_getter(),
1209 xmpp_server_config_
));
1211 scoped_ptr
<DnsBlackholeChecker
> dns_blackhole_checker(
1212 new DnsBlackholeChecker(context_
->url_request_context_getter(),
1213 talkgadget_prefix_
));
1215 // Create a NetworkChangeNotifier for use by the signaling connector.
1216 network_change_notifier_
.reset(net::NetworkChangeNotifier::Create());
1218 signaling_connector_
.reset(new SignalingConnector(
1219 signal_strategy_
.get(),
1220 dns_blackhole_checker
.Pass(),
1221 base::Bind(&HostProcess::OnAuthFailed
, this)));
1223 if (!oauth_refresh_token_
.empty()) {
1224 scoped_ptr
<OAuthTokenGetter::OAuthCredentials
> oauth_credentials
;
1225 oauth_credentials
.reset(
1226 new OAuthTokenGetter::OAuthCredentials(
1227 xmpp_server_config_
.username
, oauth_refresh_token_
,
1228 use_service_account_
));
1230 oauth_token_getter_
.reset(new OAuthTokenGetter(
1231 oauth_credentials
.Pass(), context_
->url_request_context_getter(),
1234 signaling_connector_
->EnableOAuth(oauth_token_getter_
.get());
1237 uint32 network_flags
= 0;
1238 if (allow_nat_traversal_
) {
1239 network_flags
= NetworkSettings::NAT_TRAVERSAL_STUN
|
1240 NetworkSettings::NAT_TRAVERSAL_OUTGOING
;
1242 network_flags
|= NetworkSettings::NAT_TRAVERSAL_RELAY
;
1245 NetworkSettings
network_settings(network_flags
);
1247 if (min_udp_port_
&& max_udp_port_
) {
1248 network_settings
.min_port
= min_udp_port_
;
1249 network_settings
.max_port
= max_udp_port_
;
1250 } else if (!allow_nat_traversal_
) {
1251 // For legacy reasons we have to restrict the port range to a set of default
1252 // values when nat traversal is disabled, even if the port range was not
1254 network_settings
.min_port
= NetworkSettings::kDefaultMinPort
;
1255 network_settings
.max_port
= NetworkSettings::kDefaultMaxPort
;
1258 host_
.reset(new ChromotingHost(
1259 signal_strategy_
.get(),
1260 desktop_environment_factory_
.get(),
1261 CreateHostSessionManager(signal_strategy_
.get(), network_settings
,
1262 context_
->url_request_context_getter()),
1263 context_
->audio_task_runner(),
1264 context_
->input_task_runner(),
1265 context_
->video_capture_task_runner(),
1266 context_
->video_encode_task_runner(),
1267 context_
->network_task_runner(),
1268 context_
->ui_task_runner()));
1271 scoped_ptr
<protocol::CandidateSessionConfig
> config
=
1272 host_
->protocol_config()->Clone();
1273 config
->EnableVideoCodec(protocol::ChannelConfig::CODEC_VP9
);
1274 host_
->set_protocol_config(config
.Pass());
1277 if (frame_recorder_buffer_size_
> 0) {
1278 scoped_ptr
<VideoFrameRecorderHostExtension
> frame_recorder_extension(
1279 new VideoFrameRecorderHostExtension());
1280 frame_recorder_extension
->SetMaxContentBytes(frame_recorder_buffer_size_
);
1281 host_
->AddExtension(frame_recorder_extension
.PassAs
<HostExtension
>());
1284 // TODO(simonmorris): Get the maximum session duration from a policy.
1285 #if defined(OS_LINUX)
1286 host_
->SetMaximumSessionDuration(base::TimeDelta::FromHours(20));
1289 heartbeat_sender_
.reset(new HeartbeatSender(
1290 this, host_id_
, signal_strategy_
.get(), key_pair_
,
1291 directory_bot_jid_
));
1293 host_status_sender_
.reset(new HostStatusSender(
1294 host_id_
, signal_strategy_
.get(), key_pair_
, directory_bot_jid_
));
1296 host_change_notification_listener_
.reset(new HostChangeNotificationListener(
1297 this, host_id_
, signal_strategy_
.get(), directory_bot_jid_
));
1299 host_status_logger_
.reset(
1300 new HostStatusLogger(host_
->AsWeakPtr(), ServerLogEntry::ME2ME
,
1301 signal_strategy_
.get(), directory_bot_jid_
));
1303 // Set up reporting the host status notifications.
1304 #if defined(REMOTING_MULTI_PROCESS)
1305 host_event_logger_
.reset(
1306 new IpcHostEventLogger(host_
->AsWeakPtr(), daemon_channel_
.get()));
1307 #else // !defined(REMOTING_MULTI_PROCESS)
1308 host_event_logger_
=
1309 HostEventLogger::Create(host_
->AsWeakPtr(), kApplicationName
);
1310 #endif // !defined(REMOTING_MULTI_PROCESS)
1312 host_
->SetEnableCurtaining(curtain_required_
);
1313 host_
->Start(host_owner_
);
1315 CreateAuthenticatorFactory();
1318 void HostProcess::OnAuthFailed() {
1319 ShutdownHost(kInvalidOauthCredentialsExitCode
);
1322 void HostProcess::RestartHost() {
1323 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
1324 DCHECK_EQ(state_
, HOST_STARTED
);
1326 state_
= HOST_STOPPING_TO_RESTART
;
1327 ShutdownOnNetworkThread();
1330 void HostProcess::ShutdownHost(HostExitCodes exit_code
) {
1331 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
1333 *exit_code_out_
= exit_code
;
1336 case HOST_INITIALIZING
:
1337 state_
= HOST_STOPPING
;
1338 ShutdownOnNetworkThread();
1342 state_
= HOST_STOPPING
;
1343 host_status_sender_
->SendOfflineStatus(exit_code
);
1344 ScheduleHostShutdown();
1347 case HOST_STOPPING_TO_RESTART
:
1348 state_
= HOST_STOPPING
;
1353 // Host is already stopped or being stopped. No action is required.
1358 // TODO(weitaosu): shut down the host once we get an ACK for the offline status
1360 void HostProcess::ScheduleHostShutdown() {
1361 // Delay the shutdown by 2 second to allow SendOfflineStatus to complete.
1362 context_
->network_task_runner()->PostDelayedTask(
1364 base::Bind(&HostProcess::ShutdownOnNetworkThread
, base::Unretained(this)),
1365 base::TimeDelta::FromSeconds(2));
1368 void HostProcess::ShutdownOnNetworkThread() {
1369 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
1372 host_event_logger_
.reset();
1373 host_status_logger_
.reset();
1374 heartbeat_sender_
.reset();
1375 host_status_sender_
.reset();
1376 host_change_notification_listener_
.reset();
1377 signaling_connector_
.reset();
1378 oauth_token_getter_
.reset();
1379 signal_strategy_
.reset();
1380 network_change_notifier_
.reset();
1382 if (state_
== HOST_STOPPING_TO_RESTART
) {
1384 } else if (state_
== HOST_STOPPING
) {
1385 state_
= HOST_STOPPED
;
1387 if (policy_watcher_
.get()) {
1388 base::WaitableEvent
done_event(true, false);
1389 policy_watcher_
->StopWatching(&done_event
);
1391 policy_watcher_
.reset();
1394 config_watcher_
.reset();
1396 // Complete the rest of shutdown on the main thread.
1397 context_
->ui_task_runner()->PostTask(
1399 base::Bind(&HostProcess::ShutdownOnUiThread
, this));
1401 // This method is only called in STOPPING_TO_RESTART and STOPPING states.
1406 void HostProcess::OnCrash(const std::string
& function_name
,
1407 const std::string
& file_name
,
1408 const int& line_number
) {
1410 base::snprintf(message
, sizeof(message
),
1411 "Requested by %s at %s, line %d.",
1412 function_name
.c_str(), file_name
.c_str(), line_number
);
1413 base::debug::Alias(message
);
1415 // The daemon requested us to crash the process.
1416 CHECK(false) << message
;
1419 int HostProcessMain() {
1420 #if defined(OS_LINUX)
1421 // Required in order for us to run multiple X11 threads.
1424 // Required for any calls into GTK functions, such as the Disconnect and
1425 // Continue windows, though these should not be used for the Me2Me case
1426 // (crbug.com/104377).
1427 gtk_init(NULL
, NULL
);
1430 // Enable support for SSL server sockets, which must be done while still
1432 net::EnableSSLServerSockets();
1434 // Ensures runtime specific CPU features are initialized.
1435 media::InitializeCPUSpecificMediaFeatures();
1437 // Create the main message loop and start helper threads.
1438 base::MessageLoopForUI message_loop
;
1439 scoped_ptr
<ChromotingHostContext
> context
=
1440 ChromotingHostContext::Create(new AutoThreadTaskRunner(
1441 message_loop
.message_loop_proxy(), base::MessageLoop::QuitClosure()));
1443 return kInitializationFailed
;
1445 // Create & start the HostProcess using these threads.
1446 // TODO(wez): The HostProcess holds a reference to itself until Shutdown().
1447 // Remove this hack as part of the multi-process refactoring.
1448 int exit_code
= kSuccessExitCode
;
1449 new HostProcess(context
.Pass(), &exit_code
);
1451 // Run the main (also UI) message loop until the host no longer needs it.
1457 } // namespace remoting