Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / remoting / host / remoting_me2me_host.cc
blob6ea5ce24164f621a8d1726b76656d4cc79e45b59
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/host_status_sender.h"
57 #include "remoting/host/ipc_constants.h"
58 #include "remoting/host/ipc_desktop_environment.h"
59 #include "remoting/host/ipc_host_event_logger.h"
60 #include "remoting/host/json_host_config.h"
61 #include "remoting/host/logging.h"
62 #include "remoting/host/me2me_desktop_environment.h"
63 #include "remoting/host/pairing_registry_delegate.h"
64 #include "remoting/host/policy_hack/policy_watcher.h"
65 #include "remoting/host/session_manager_factory.h"
66 #include "remoting/host/signaling_connector.h"
67 #include "remoting/host/single_window_desktop_environment.h"
68 #include "remoting/host/token_validator_factory_impl.h"
69 #include "remoting/host/usage_stats_consent.h"
70 #include "remoting/host/username.h"
71 #include "remoting/host/video_frame_recorder_host_extension.h"
72 #include "remoting/protocol/me2me_host_authenticator_factory.h"
73 #include "remoting/protocol/network_settings.h"
74 #include "remoting/protocol/pairing_registry.h"
75 #include "remoting/protocol/token_validator.h"
76 #include "remoting/signaling/xmpp_signal_strategy.h"
78 #if defined(OS_POSIX)
79 #include <signal.h>
80 #include <sys/types.h>
81 #include <unistd.h>
82 #include "base/file_descriptor_posix.h"
83 #include "remoting/host/pam_authorization_factory_posix.h"
84 #include "remoting/host/posix/signal_handler.h"
85 #endif // defined(OS_POSIX)
87 #if defined(OS_MACOSX)
88 #include "base/mac/scoped_cftyperef.h"
89 #endif // defined(OS_MACOSX)
91 #if defined(OS_LINUX)
92 #include <gtk/gtk.h>
93 #include <X11/Xlib.h>
94 #include "remoting/host/audio_capturer_linux.h"
95 #endif // defined(OS_LINUX)
97 #if defined(OS_WIN)
98 #include <commctrl.h>
99 #include "base/win/registry.h"
100 #include "base/win/scoped_handle.h"
101 #include "remoting/host/pairing_registry_delegate_win.h"
102 #include "remoting/host/win/session_desktop_environment.h"
103 #endif // defined(OS_WIN)
105 using remoting::protocol::PairingRegistry;
106 using remoting::protocol::NetworkSettings;
108 namespace {
110 // This is used for tagging system event logs.
111 const char kApplicationName[] = "chromoting";
113 #if defined(OS_LINUX)
114 // The command line switch used to pass name of the pipe to capture audio on
115 // linux.
116 const char kAudioPipeSwitchName[] = "audio-pipe-name";
118 // The command line switch used to pass name of the unix domain socket used to
119 // listen for gnubby requests.
120 const char kAuthSocknameSwitchName[] = "ssh-auth-sockname";
121 #endif // defined(OS_LINUX)
123 // The command line switch used by the parent to request the host to signal it
124 // when it is successfully started.
125 const char kSignalParentSwitchName[] = "signal-parent";
127 // Command line switch used to enable VP9 encoding.
128 const char kEnableVp9SwitchName[] = "enable-vp9";
130 // Command line switch used to enable and configure the frame-recorder.
131 const char kFrameRecorderBufferKbName[] = "frame-recorder-buffer-kb";
133 // Value used for --host-config option to indicate that the path must be read
134 // from stdin.
135 const char kStdinConfigPath[] = "-";
137 const char kWindowIdSwitchName[] = "window-id";
139 } // namespace
141 namespace remoting {
143 class HostProcess
144 : public ConfigWatcher::Delegate,
145 public HeartbeatSender::Listener,
146 public HostChangeNotificationListener::Listener,
147 public IPC::Listener,
148 public base::RefCountedThreadSafe<HostProcess> {
149 public:
150 HostProcess(scoped_ptr<ChromotingHostContext> context,
151 int* exit_code_out);
153 // ConfigWatcher::Delegate interface.
154 void OnConfigUpdated(const std::string& serialized_config) override;
155 void OnConfigWatcherError() override;
157 // IPC::Listener implementation.
158 bool OnMessageReceived(const IPC::Message& message) override;
159 void OnChannelError() override;
161 // HeartbeatSender::Listener overrides.
162 void OnHeartbeatSuccessful() override;
163 void OnUnknownHostIdError() override;
165 // HostChangeNotificationListener::Listener overrides.
166 void OnHostDeleted() override;
168 // Initializes the pairing registry on Windows.
169 void OnInitializePairingRegistry(
170 IPC::PlatformFileForTransit privileged_key,
171 IPC::PlatformFileForTransit unprivileged_key);
173 private:
174 enum HostState {
175 // Host process has just been started. Waiting for config and policies to be
176 // read from the disk.
177 HOST_INITIALIZING,
179 // Host is started and running.
180 HOST_STARTED,
182 // Host is being stopped and will need to be started again.
183 HOST_STOPPING_TO_RESTART,
185 // Host is being stopped.
186 HOST_STOPPING,
188 // Host has been stopped.
189 HOST_STOPPED,
191 // Allowed state transitions:
192 // INITIALIZING->STARTED
193 // INITIALIZING->STOPPED
194 // STARTED->STOPPING_TO_RESTART
195 // STARTED->STOPPING
196 // STOPPING_TO_RESTART->STARTED
197 // STOPPING_TO_RESTART->STOPPING
198 // STOPPING->STOPPED
199 // STOPPED->STARTED
201 // |host_| must be NULL in INITIALIZING and STOPPED states and not-NULL in
202 // all other states.
205 friend class base::RefCountedThreadSafe<HostProcess>;
206 ~HostProcess() override;
208 void StartOnNetworkThread();
210 #if defined(OS_POSIX)
211 // Callback passed to RegisterSignalHandler() to handle SIGTERM events.
212 void SigTermHandler(int signal_number);
213 #endif
215 // Called to initialize resources on the UI thread.
216 void StartOnUiThread();
218 // Initializes IPC control channel and config file path from |cmd_line|.
219 // Called on the UI thread.
220 bool InitWithCommandLine(const base::CommandLine* cmd_line);
222 // Called on the UI thread to start monitoring the configuration file.
223 void StartWatchingConfigChanges();
225 // Called on the network thread to set the host's Authenticator factory.
226 void CreateAuthenticatorFactory();
228 // Tear down resources that run on the UI thread.
229 void ShutdownOnUiThread();
231 // Applies the host config, returning true if successful.
232 bool ApplyConfig(scoped_ptr<JsonHostConfig> config);
234 // Handles policy updates, by calling On*PolicyUpdate methods.
235 void OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies);
236 void ApplyHostDomainPolicy();
237 void ApplyUsernamePolicy();
238 bool OnHostDomainPolicyUpdate(base::DictionaryValue* policies);
239 bool OnUsernamePolicyUpdate(base::DictionaryValue* policies);
240 bool OnNatPolicyUpdate(base::DictionaryValue* policies);
241 bool OnRelayPolicyUpdate(base::DictionaryValue* policies);
242 bool OnUdpPortPolicyUpdate(base::DictionaryValue* policies);
243 bool OnCurtainPolicyUpdate(base::DictionaryValue* policies);
244 bool OnHostTalkGadgetPrefixPolicyUpdate(base::DictionaryValue* policies);
245 bool OnHostTokenUrlPolicyUpdate(base::DictionaryValue* policies);
246 bool OnPairingPolicyUpdate(base::DictionaryValue* policies);
247 bool OnGnubbyAuthPolicyUpdate(base::DictionaryValue* policies);
249 void StartHost();
251 void OnAuthFailed();
253 void RestartHost();
255 // Stops the host and shuts down the process with the specified |exit_code|.
256 void ShutdownHost(HostExitCodes exit_code);
258 void ScheduleHostShutdown();
260 void ShutdownOnNetworkThread();
262 void OnPolicyWatcherShutdown();
264 // Crashes the process in response to a daemon's request. The daemon passes
265 // the location of the code that detected the fatal error resulted in this
266 // request.
267 void OnCrash(const std::string& function_name,
268 const std::string& file_name,
269 const int& line_number);
271 scoped_ptr<ChromotingHostContext> context_;
273 // Created on the UI thread but used from the network thread.
274 scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
276 // Accessed on the UI thread.
277 scoped_ptr<IPC::ChannelProxy> daemon_channel_;
279 // XMPP server/remoting bot configuration (initialized from the command line).
280 XmppSignalStrategy::XmppServerConfig xmpp_server_config_;
281 std::string directory_bot_jid_;
283 // Created on the UI thread but used from the network thread.
284 base::FilePath host_config_path_;
285 std::string host_config_;
286 scoped_ptr<DesktopEnvironmentFactory> desktop_environment_factory_;
288 // Accessed on the network thread.
289 HostState state_;
291 scoped_ptr<ConfigWatcher> config_watcher_;
293 std::string host_id_;
294 protocol::SharedSecretHash host_secret_hash_;
295 scoped_refptr<RsaKeyPair> key_pair_;
296 std::string oauth_refresh_token_;
297 std::string serialized_config_;
298 std::string host_owner_;
299 std::string host_owner_email_;
300 bool use_service_account_;
301 bool enable_vp9_;
302 int64_t frame_recorder_buffer_size_;
304 scoped_ptr<policy_hack::PolicyWatcher> policy_watcher_;
305 std::string host_domain_;
306 bool host_username_match_required_;
307 bool allow_nat_traversal_;
308 bool allow_relay_;
309 uint16 min_udp_port_;
310 uint16 max_udp_port_;
311 std::string talkgadget_prefix_;
312 bool allow_pairing_;
314 bool curtain_required_;
315 ThirdPartyAuthConfig third_party_auth_config_;
316 bool enable_gnubby_auth_;
318 // Boolean to change flow, where ncessary, if we're
319 // capturing a window instead of the entire desktop.
320 bool enable_window_capture_;
322 // Used to specify which window to stream, if enabled.
323 webrtc::WindowId window_id_;
325 scoped_ptr<OAuthTokenGetter> oauth_token_getter_;
326 scoped_ptr<XmppSignalStrategy> signal_strategy_;
327 scoped_ptr<SignalingConnector> signaling_connector_;
328 scoped_ptr<HeartbeatSender> heartbeat_sender_;
329 scoped_ptr<HostStatusSender> host_status_sender_;
330 scoped_ptr<HostChangeNotificationListener> host_change_notification_listener_;
331 scoped_ptr<HostStatusLogger> host_status_logger_;
332 scoped_ptr<HostEventLogger> host_event_logger_;
334 scoped_ptr<ChromotingHost> host_;
336 // Used to keep this HostProcess alive until it is shutdown.
337 scoped_refptr<HostProcess> self_;
339 #if defined(REMOTING_MULTI_PROCESS)
340 DesktopSessionConnector* desktop_session_connector_;
341 #endif // defined(REMOTING_MULTI_PROCESS)
343 int* exit_code_out_;
344 bool signal_parent_;
346 scoped_ptr<PairingRegistry::Delegate> pairing_registry_delegate_;
349 HostProcess::HostProcess(scoped_ptr<ChromotingHostContext> context,
350 int* exit_code_out)
351 : context_(context.Pass()),
352 state_(HOST_INITIALIZING),
353 use_service_account_(false),
354 enable_vp9_(false),
355 frame_recorder_buffer_size_(0),
356 host_username_match_required_(false),
357 allow_nat_traversal_(true),
358 allow_relay_(true),
359 min_udp_port_(0),
360 max_udp_port_(0),
361 allow_pairing_(true),
362 curtain_required_(false),
363 enable_gnubby_auth_(false),
364 enable_window_capture_(false),
365 window_id_(0),
366 #if defined(REMOTING_MULTI_PROCESS)
367 desktop_session_connector_(NULL),
368 #endif // defined(REMOTING_MULTI_PROCESS)
369 self_(this),
370 exit_code_out_(exit_code_out),
371 signal_parent_(false) {
372 StartOnUiThread();
375 HostProcess::~HostProcess() {
376 // Verify that UI components have been torn down.
377 DCHECK(!config_watcher_);
378 DCHECK(!daemon_channel_);
379 DCHECK(!desktop_environment_factory_);
381 // We might be getting deleted on one of the threads the |host_context| owns,
382 // so we need to post it back to the caller thread to safely join & delete the
383 // threads it contains. This will go away when we move to AutoThread.
384 // |context_release()| will null |context_| before the method is invoked, so
385 // we need to pull out the task-runner on which to call DeleteSoon first.
386 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
387 context_->ui_task_runner();
388 task_runner->DeleteSoon(FROM_HERE, context_.release());
391 bool HostProcess::InitWithCommandLine(const base::CommandLine* cmd_line) {
392 #if defined(REMOTING_MULTI_PROCESS)
393 // Parse the handle value and convert it to a handle/file descriptor.
394 std::string channel_name =
395 cmd_line->GetSwitchValueASCII(kDaemonPipeSwitchName);
397 int pipe_handle = 0;
398 if (channel_name.empty() ||
399 !base::StringToInt(channel_name, &pipe_handle)) {
400 LOG(ERROR) << "Invalid '" << kDaemonPipeSwitchName
401 << "' value: " << channel_name;
402 return false;
405 #if defined(OS_WIN)
406 base::win::ScopedHandle pipe(reinterpret_cast<HANDLE>(pipe_handle));
407 IPC::ChannelHandle channel_handle(pipe.Get());
408 #elif defined(OS_POSIX)
409 base::FileDescriptor pipe(pipe_handle, true);
410 IPC::ChannelHandle channel_handle(channel_name, pipe);
411 #endif // defined(OS_POSIX)
413 // Connect to the daemon process.
414 daemon_channel_ = IPC::ChannelProxy::Create(channel_handle,
415 IPC::Channel::MODE_CLIENT,
416 this,
417 context_->network_task_runner());
418 #else // !defined(REMOTING_MULTI_PROCESS)
419 // Connect to the daemon process.
420 std::string channel_name =
421 cmd_line->GetSwitchValueASCII(kDaemonPipeSwitchName);
422 if (!channel_name.empty()) {
423 daemon_channel_ =
424 IPC::ChannelProxy::Create(channel_name,
425 IPC::Channel::MODE_CLIENT,
426 this,
427 context_->network_task_runner().get());
430 if (cmd_line->HasSwitch(kHostConfigSwitchName)) {
431 host_config_path_ = cmd_line->GetSwitchValuePath(kHostConfigSwitchName);
433 // Read config from stdin if necessary.
434 if (host_config_path_ == base::FilePath(kStdinConfigPath)) {
435 char buf[4096];
436 size_t len;
437 while ((len = fread(buf, 1, sizeof(buf), stdin)) > 0) {
438 host_config_.append(buf, len);
441 } else {
442 base::FilePath default_config_dir = remoting::GetConfigDir();
443 host_config_path_ = default_config_dir.Append(kDefaultHostConfigFile);
446 if (host_config_path_ != base::FilePath(kStdinConfigPath) &&
447 !base::PathExists(host_config_path_)) {
448 LOG(ERROR) << "Can't find host config at " << host_config_path_.value();
449 return false;
451 #endif // !defined(REMOTING_MULTI_PROCESS)
453 // Ignore certificate requests - the host currently has no client certificate
454 // support, so ignoring certificate requests allows connecting to servers that
455 // request, but don't require, a certificate (optional client authentication).
456 net::URLFetcher::SetIgnoreCertificateRequests(true);
458 ServiceUrls* service_urls = ServiceUrls::GetInstance();
459 bool xmpp_server_valid = net::ParseHostAndPort(
460 service_urls->xmpp_server_address(),
461 &xmpp_server_config_.host, &xmpp_server_config_.port);
462 if (!xmpp_server_valid) {
463 LOG(ERROR) << "Invalid XMPP server: " <<
464 service_urls->xmpp_server_address();
465 return false;
467 xmpp_server_config_.use_tls = service_urls->xmpp_server_use_tls();
468 directory_bot_jid_ = service_urls->directory_bot_jid();
470 signal_parent_ = cmd_line->HasSwitch(kSignalParentSwitchName);
472 enable_window_capture_ = cmd_line->HasSwitch(kWindowIdSwitchName);
473 if (enable_window_capture_) {
475 #if defined(OS_LINUX) || defined(OS_WIN)
476 LOG(WARNING) << "Window capturing is not fully supported on Linux or "
477 "Windows.";
478 #endif // defined(OS_LINUX) || defined(OS_WIN)
480 // uint32_t is large enough to hold window IDs on all platforms.
481 uint32_t window_id;
482 if (base::StringToUint(
483 cmd_line->GetSwitchValueASCII(kWindowIdSwitchName),
484 &window_id)) {
485 window_id_ = static_cast<webrtc::WindowId>(window_id);
486 } else {
487 LOG(ERROR) << "Window with window id: " << window_id_
488 << " not found. Shutting down host.";
489 return false;
492 return true;
495 void HostProcess::OnConfigUpdated(
496 const std::string& serialized_config) {
497 if (!context_->network_task_runner()->BelongsToCurrentThread()) {
498 context_->network_task_runner()->PostTask(FROM_HERE,
499 base::Bind(&HostProcess::OnConfigUpdated, this, serialized_config));
500 return;
503 // Filter out duplicates.
504 if (serialized_config_ == serialized_config)
505 return;
507 HOST_LOG << "Processing new host configuration.";
509 serialized_config_ = serialized_config;
510 scoped_ptr<JsonHostConfig> config(new JsonHostConfig(base::FilePath()));
511 if (!config->SetSerializedData(serialized_config)) {
512 LOG(ERROR) << "Invalid configuration.";
513 ShutdownHost(kInvalidHostConfigurationExitCode);
514 return;
517 if (!ApplyConfig(config.Pass())) {
518 LOG(ERROR) << "Failed to apply the configuration.";
519 ShutdownHost(kInvalidHostConfigurationExitCode);
520 return;
523 if (state_ == HOST_INITIALIZING) {
524 // TODO(sergeyu): Currently OnPolicyUpdate() assumes that host config is
525 // already loaded so PolicyWatcher has to be started here. Separate policy
526 // loading from policy verifications and move |policy_watcher_|
527 // initialization to StartOnNetworkThread().
528 policy_watcher_ = policy_hack::PolicyWatcher::Create(
529 nullptr, context_->network_task_runner());
530 policy_watcher_->StartWatching(
531 base::Bind(&HostProcess::OnPolicyUpdate, base::Unretained(this)));
532 } else {
533 // Reapply policies that could be affected by a new config.
534 ApplyHostDomainPolicy();
535 ApplyUsernamePolicy();
537 if (state_ == HOST_STARTED) {
538 // TODO(sergeyu): Here we assume that PIN is the only part of the config
539 // that may change while the service is running. Change ApplyConfig() to
540 // detect other changes in the config and restart host if necessary here.
541 CreateAuthenticatorFactory();
546 void HostProcess::OnConfigWatcherError() {
547 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
548 ShutdownHost(kInvalidHostConfigurationExitCode);
551 void HostProcess::StartOnNetworkThread() {
552 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
554 #if !defined(REMOTING_MULTI_PROCESS)
555 if (host_config_path_ == base::FilePath(kStdinConfigPath)) {
556 // Process config we've read from stdin.
557 OnConfigUpdated(host_config_);
558 } else {
559 // Start watching the host configuration file.
560 config_watcher_.reset(new ConfigFileWatcher(context_->network_task_runner(),
561 context_->file_task_runner(),
562 host_config_path_));
563 config_watcher_->Watch(this);
565 #endif // !defined(REMOTING_MULTI_PROCESS)
567 #if defined(OS_POSIX)
568 remoting::RegisterSignalHandler(
569 SIGTERM,
570 base::Bind(&HostProcess::SigTermHandler, base::Unretained(this)));
571 #endif // defined(OS_POSIX)
574 #if defined(OS_POSIX)
575 void HostProcess::SigTermHandler(int signal_number) {
576 DCHECK(signal_number == SIGTERM);
577 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
578 HOST_LOG << "Caught SIGTERM: Shutting down...";
579 ShutdownHost(kSuccessExitCode);
581 #endif // OS_POSIX
583 void HostProcess::CreateAuthenticatorFactory() {
584 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
586 if (state_ != HOST_STARTED)
587 return;
589 std::string local_certificate = key_pair_->GenerateCertificate();
590 if (local_certificate.empty()) {
591 LOG(ERROR) << "Failed to generate host certificate.";
592 ShutdownHost(kInitializationFailed);
593 return;
596 scoped_refptr<PairingRegistry> pairing_registry = NULL;
597 if (allow_pairing_) {
598 if (!pairing_registry_delegate_)
599 pairing_registry_delegate_ = CreatePairingRegistryDelegate();
601 if (pairing_registry_delegate_) {
602 pairing_registry = new PairingRegistry(context_->file_task_runner(),
603 pairing_registry_delegate_.Pass());
607 scoped_ptr<protocol::AuthenticatorFactory> factory;
609 if (third_party_auth_config_.is_empty()) {
610 factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithSharedSecret(
611 use_service_account_, host_owner_, local_certificate, key_pair_,
612 host_secret_hash_, pairing_registry);
614 } else if (third_party_auth_config_.is_valid()) {
615 scoped_ptr<protocol::TokenValidatorFactory> token_validator_factory(
616 new TokenValidatorFactoryImpl(
617 third_party_auth_config_,
618 key_pair_, context_->url_request_context_getter()));
619 factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth(
620 use_service_account_, host_owner_, local_certificate, key_pair_,
621 token_validator_factory.Pass());
623 } else {
624 // TODO(rmsousa): If the policy is bad the host should not go online. It
625 // should keep running, but not connected, until the policies are fixed.
626 // Having it show up as online and then reject all clients is misleading.
627 LOG(ERROR) << "One of the third-party token URLs is empty or invalid. "
628 << "Host will reject all clients until policies are corrected. "
629 << "TokenUrl: " << third_party_auth_config_.token_url << ", "
630 << "TokenValidationUrl: "
631 << third_party_auth_config_.token_validation_url;
632 factory = protocol::Me2MeHostAuthenticatorFactory::CreateRejecting();
635 #if defined(OS_POSIX)
636 // On Linux and Mac, perform a PAM authorization step after authentication.
637 factory.reset(new PamAuthorizationFactory(factory.Pass()));
638 #endif
639 host_->SetAuthenticatorFactory(factory.Pass());
641 host_->set_pairing_registry(pairing_registry);
644 // IPC::Listener implementation.
645 bool HostProcess::OnMessageReceived(const IPC::Message& message) {
646 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
648 #if defined(REMOTING_MULTI_PROCESS)
649 bool handled = true;
650 IPC_BEGIN_MESSAGE_MAP(HostProcess, message)
651 IPC_MESSAGE_HANDLER(ChromotingDaemonMsg_Crash, OnCrash)
652 IPC_MESSAGE_HANDLER(ChromotingDaemonNetworkMsg_Configuration,
653 OnConfigUpdated)
654 IPC_MESSAGE_HANDLER(ChromotingDaemonNetworkMsg_InitializePairingRegistry,
655 OnInitializePairingRegistry)
656 IPC_MESSAGE_FORWARD(
657 ChromotingDaemonNetworkMsg_DesktopAttached,
658 desktop_session_connector_,
659 DesktopSessionConnector::OnDesktopSessionAgentAttached)
660 IPC_MESSAGE_FORWARD(ChromotingDaemonNetworkMsg_TerminalDisconnected,
661 desktop_session_connector_,
662 DesktopSessionConnector::OnTerminalDisconnected)
663 IPC_MESSAGE_UNHANDLED(handled = false)
664 IPC_END_MESSAGE_MAP()
666 CHECK(handled) << "Received unexpected IPC type: " << message.type();
667 return handled;
669 #else // !defined(REMOTING_MULTI_PROCESS)
670 return false;
671 #endif // !defined(REMOTING_MULTI_PROCESS)
674 void HostProcess::OnChannelError() {
675 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
677 // Shutdown the host if the daemon process disconnects the IPC channel.
678 context_->network_task_runner()->PostTask(
679 FROM_HERE,
680 base::Bind(&HostProcess::ShutdownHost, this, kSuccessExitCode));
683 void HostProcess::StartOnUiThread() {
684 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
686 if (!InitWithCommandLine(base::CommandLine::ForCurrentProcess())) {
687 // Shutdown the host if the command line is invalid.
688 context_->network_task_runner()->PostTask(
689 FROM_HERE, base::Bind(&HostProcess::ShutdownHost, this,
690 kUsageExitCode));
691 return;
694 #if defined(OS_LINUX)
695 // If an audio pipe is specific on the command-line then initialize
696 // AudioCapturerLinux to capture from it.
697 base::FilePath audio_pipe_name = base::CommandLine::ForCurrentProcess()->
698 GetSwitchValuePath(kAudioPipeSwitchName);
699 if (!audio_pipe_name.empty()) {
700 remoting::AudioCapturerLinux::InitializePipeReader(
701 context_->audio_task_runner(), audio_pipe_name);
704 base::FilePath gnubby_socket_name = base::CommandLine::ForCurrentProcess()->
705 GetSwitchValuePath(kAuthSocknameSwitchName);
706 if (!gnubby_socket_name.empty())
707 remoting::GnubbyAuthHandler::SetGnubbySocketName(gnubby_socket_name);
708 #endif // defined(OS_LINUX)
710 // Create a desktop environment factory appropriate to the build type &
711 // platform.
712 #if defined(OS_WIN)
713 IpcDesktopEnvironmentFactory* desktop_environment_factory =
714 new IpcDesktopEnvironmentFactory(
715 context_->audio_task_runner(),
716 context_->network_task_runner(),
717 context_->video_capture_task_runner(),
718 context_->network_task_runner(),
719 daemon_channel_.get());
720 desktop_session_connector_ = desktop_environment_factory;
721 #else // !defined(OS_WIN)
722 DesktopEnvironmentFactory* desktop_environment_factory;
723 if (enable_window_capture_) {
724 desktop_environment_factory =
725 new SingleWindowDesktopEnvironmentFactory(
726 context_->network_task_runner(),
727 context_->input_task_runner(),
728 context_->ui_task_runner(),
729 window_id_);
730 } else {
731 desktop_environment_factory =
732 new Me2MeDesktopEnvironmentFactory(
733 context_->network_task_runner(),
734 context_->input_task_runner(),
735 context_->ui_task_runner());
737 #endif // !defined(OS_WIN)
739 desktop_environment_factory_.reset(desktop_environment_factory);
740 desktop_environment_factory_->SetEnableGnubbyAuth(enable_gnubby_auth_);
742 context_->network_task_runner()->PostTask(
743 FROM_HERE,
744 base::Bind(&HostProcess::StartOnNetworkThread, this));
747 void HostProcess::ShutdownOnUiThread() {
748 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
750 // Tear down resources that need to be torn down on the UI thread.
751 network_change_notifier_.reset();
752 daemon_channel_.reset();
753 desktop_environment_factory_.reset();
755 // It is now safe for the HostProcess to be deleted.
756 self_ = NULL;
758 #if defined(OS_LINUX)
759 // Cause the global AudioPipeReader to be freed, otherwise the audio
760 // thread will remain in-use and prevent the process from exiting.
761 // TODO(wez): DesktopEnvironmentFactory should own the pipe reader.
762 // See crbug.com/161373 and crbug.com/104544.
763 AudioCapturerLinux::InitializePipeReader(NULL, base::FilePath());
764 #endif
767 // Overridden from HeartbeatSender::Listener
768 void HostProcess::OnUnknownHostIdError() {
769 LOG(ERROR) << "Host ID not found.";
770 ShutdownHost(kInvalidHostIdExitCode);
773 void HostProcess::OnHeartbeatSuccessful() {
774 HOST_LOG << "Host ready to receive connections.";
775 #if defined(OS_POSIX)
776 if (signal_parent_) {
777 kill(getppid(), SIGUSR1);
778 signal_parent_ = false;
780 #endif
783 void HostProcess::OnHostDeleted() {
784 LOG(ERROR) << "Host was deleted from the directory.";
785 ShutdownHost(kInvalidHostIdExitCode);
788 void HostProcess::OnInitializePairingRegistry(
789 IPC::PlatformFileForTransit privileged_key,
790 IPC::PlatformFileForTransit unprivileged_key) {
791 DCHECK(!pairing_registry_delegate_);
793 #if defined(OS_WIN)
794 // Initialize the pairing registry delegate.
795 scoped_ptr<PairingRegistryDelegateWin> delegate(
796 new PairingRegistryDelegateWin());
797 bool result = delegate->SetRootKeys(
798 reinterpret_cast<HKEY>(
799 IPC::PlatformFileForTransitToPlatformFile(privileged_key)),
800 reinterpret_cast<HKEY>(
801 IPC::PlatformFileForTransitToPlatformFile(unprivileged_key)));
802 if (!result)
803 return;
805 pairing_registry_delegate_ = delegate.Pass();
806 #else // !defined(OS_WIN)
807 NOTREACHED();
808 #endif // !defined(OS_WIN)
811 // Applies the host config, returning true if successful.
812 bool HostProcess::ApplyConfig(scoped_ptr<JsonHostConfig> config) {
813 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
815 if (!config->GetString(kHostIdConfigPath, &host_id_)) {
816 LOG(ERROR) << "host_id is not defined in the config.";
817 return false;
820 std::string key_base64;
821 if (!config->GetString(kPrivateKeyConfigPath, &key_base64)) {
822 LOG(ERROR) << "Private key couldn't be read from the config file.";
823 return false;
826 key_pair_ = RsaKeyPair::FromString(key_base64);
827 if (!key_pair_.get()) {
828 LOG(ERROR) << "Invalid private key in the config file.";
829 return false;
832 std::string host_secret_hash_string;
833 if (!config->GetString(kHostSecretHashConfigPath,
834 &host_secret_hash_string)) {
835 host_secret_hash_string = "plain:";
838 if (!host_secret_hash_.Parse(host_secret_hash_string)) {
839 LOG(ERROR) << "Invalid host_secret_hash.";
840 return false;
843 // Use an XMPP connection to the Talk network for session signalling.
844 if (!config->GetString(kXmppLoginConfigPath, &xmpp_server_config_.username) ||
845 !(config->GetString(kXmppAuthTokenConfigPath,
846 &xmpp_server_config_.auth_token) ||
847 config->GetString(kOAuthRefreshTokenConfigPath,
848 &oauth_refresh_token_))) {
849 LOG(ERROR) << "XMPP credentials are not defined in the config.";
850 return false;
853 if (!oauth_refresh_token_.empty()) {
854 // SignalingConnector is responsible for getting OAuth token.
855 xmpp_server_config_.auth_token = "";
856 xmpp_server_config_.auth_service = "oauth2";
857 } else if (!config->GetString(kXmppAuthServiceConfigPath,
858 &xmpp_server_config_.auth_service)) {
859 // For the me2me host, we default to ClientLogin token for chromiumsync
860 // because earlier versions of the host had no HTTP stack with which to
861 // request an OAuth2 access token.
862 xmpp_server_config_.auth_service = kChromotingTokenDefaultServiceName;
865 if (config->GetString(kHostOwnerConfigPath, &host_owner_)) {
866 // Service account configs have a host_owner, different from the xmpp_login.
867 use_service_account_ = true;
868 } else {
869 // User credential configs only have an xmpp_login, which is also the owner.
870 host_owner_ = xmpp_server_config_.username;
871 use_service_account_ = false;
874 // For non-Gmail Google accounts, the owner base JID differs from the email.
875 // host_owner_ contains the base JID (used for authenticating clients), while
876 // host_owner_email contains the account's email (used for UI and logs).
877 if (!config->GetString(kHostOwnerEmailConfigPath, &host_owner_email_)) {
878 host_owner_email_ = host_owner_;
881 // Allow offering of VP9 encoding to be overridden by the command-line.
882 if (CommandLine::ForCurrentProcess()->HasSwitch(kEnableVp9SwitchName)) {
883 enable_vp9_ = true;
884 } else {
885 config->GetBoolean(kEnableVp9ConfigPath, &enable_vp9_);
888 // Allow the command-line to override the size of the frame recorder buffer.
889 std::string frame_recorder_buffer_kb;
890 if (CommandLine::ForCurrentProcess()->HasSwitch(
891 kFrameRecorderBufferKbName)) {
892 frame_recorder_buffer_kb =
893 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
894 kFrameRecorderBufferKbName);
895 } else {
896 config->GetString(kFrameRecorderBufferKbConfigPath,
897 &frame_recorder_buffer_kb);
899 if (!frame_recorder_buffer_kb.empty()) {
900 int buffer_kb = 0;
901 if (base::StringToInt(frame_recorder_buffer_kb, &buffer_kb)) {
902 frame_recorder_buffer_size_ = 1024LL * buffer_kb;
906 return true;
909 void HostProcess::OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies) {
910 if (!context_->network_task_runner()->BelongsToCurrentThread()) {
911 context_->network_task_runner()->PostTask(FROM_HERE, base::Bind(
912 &HostProcess::OnPolicyUpdate, this, base::Passed(&policies)));
913 return;
916 bool restart_required = false;
917 restart_required |= OnHostDomainPolicyUpdate(policies.get());
918 restart_required |= OnCurtainPolicyUpdate(policies.get());
919 // Note: UsernamePolicyUpdate must run after OnCurtainPolicyUpdate.
920 restart_required |= OnUsernamePolicyUpdate(policies.get());
921 restart_required |= OnNatPolicyUpdate(policies.get());
922 restart_required |= OnRelayPolicyUpdate(policies.get());
923 restart_required |= OnUdpPortPolicyUpdate(policies.get());
924 restart_required |= OnHostTalkGadgetPrefixPolicyUpdate(policies.get());
925 restart_required |= OnHostTokenUrlPolicyUpdate(policies.get());
926 restart_required |= OnPairingPolicyUpdate(policies.get());
927 restart_required |= OnGnubbyAuthPolicyUpdate(policies.get());
929 if (state_ == HOST_INITIALIZING) {
930 StartHost();
931 } else if (state_ == HOST_STARTED && restart_required) {
932 RestartHost();
936 void HostProcess::ApplyHostDomainPolicy() {
937 HOST_LOG << "Policy sets host domain: " << host_domain_;
939 if (!host_domain_.empty()) {
940 // If the user does not have a Google email, their client JID will not be
941 // based on their email. In that case, the username/host domain policies
942 // would be meaningless, since there is no way to check that the JID
943 // trying to connect actually corresponds to the owner email in question.
944 if (host_owner_ != host_owner_email_) {
945 LOG(ERROR) << "The username and host domain policies cannot be enabled "
946 << "for accounts with a non-Google email.";
947 ShutdownHost(kInvalidHostDomainExitCode);
950 if (!EndsWith(host_owner_, std::string("@") + host_domain_, false)) {
951 LOG(ERROR) << "The host domain does not match the policy.";
952 ShutdownHost(kInvalidHostDomainExitCode);
957 bool HostProcess::OnHostDomainPolicyUpdate(base::DictionaryValue* policies) {
958 // Returns true if the host has to be restarted after this policy update.
959 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
961 if (!policies->GetString(policy_hack::PolicyWatcher::kHostDomainPolicyName,
962 &host_domain_)) {
963 return false;
966 ApplyHostDomainPolicy();
967 return false;
970 void HostProcess::ApplyUsernamePolicy() {
971 if (host_username_match_required_) {
972 HOST_LOG << "Policy requires host username match.";
974 // See comment in ApplyHostDomainPolicy.
975 if (host_owner_ != host_owner_email_) {
976 LOG(ERROR) << "The username and host domain policies cannot be enabled "
977 << "for accounts with a non-Google email.";
978 ShutdownHost(kUsernameMismatchExitCode);
981 std::string username = GetUsername();
982 bool shutdown = username.empty() ||
983 !StartsWithASCII(host_owner_, username + std::string("@"),
984 false);
986 #if defined(OS_MACOSX)
987 // On Mac, we run as root at the login screen, so the username won't match.
988 // However, there's no need to enforce the policy at the login screen, as
989 // the client will have to reconnect if a login occurs.
990 if (shutdown && getuid() == 0) {
991 shutdown = false;
993 #endif
995 // Curtain-mode on Windows presents the standard OS login prompt to the user
996 // for each connection, removing the need for an explicit user-name matching
997 // check.
998 #if defined(OS_WIN) && defined(REMOTING_RDP_SESSION)
999 if (curtain_required_)
1000 return;
1001 #endif // defined(OS_WIN) && defined(REMOTING_RDP_SESSION)
1003 // Shutdown the host if the username does not match.
1004 if (shutdown) {
1005 LOG(ERROR) << "The host username does not match.";
1006 ShutdownHost(kUsernameMismatchExitCode);
1008 } else {
1009 HOST_LOG << "Policy does not require host username match.";
1013 bool HostProcess::OnUsernamePolicyUpdate(base::DictionaryValue* policies) {
1014 // Returns false: never restart the host after this policy update.
1015 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1017 if (!policies->GetBoolean(
1018 policy_hack::PolicyWatcher::kHostMatchUsernamePolicyName,
1019 &host_username_match_required_)) {
1020 return false;
1023 ApplyUsernamePolicy();
1024 return false;
1027 bool HostProcess::OnNatPolicyUpdate(base::DictionaryValue* policies) {
1028 // Returns true if the host has to be restarted after this policy update.
1029 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1031 if (!policies->GetBoolean(policy_hack::PolicyWatcher::kNatPolicyName,
1032 &allow_nat_traversal_)) {
1033 return false;
1036 if (allow_nat_traversal_) {
1037 HOST_LOG << "Policy enables NAT traversal.";
1038 } else {
1039 HOST_LOG << "Policy disables NAT traversal.";
1041 return true;
1044 bool HostProcess::OnRelayPolicyUpdate(base::DictionaryValue* policies) {
1045 // Returns true if the host has to be restarted after this policy update.
1046 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1048 if (!policies->GetBoolean(policy_hack::PolicyWatcher::kRelayPolicyName,
1049 &allow_relay_)) {
1050 return false;
1053 if (allow_relay_) {
1054 HOST_LOG << "Policy enables use of relay server.";
1055 } else {
1056 HOST_LOG << "Policy disables use of relay server.";
1058 return true;
1061 bool HostProcess::OnUdpPortPolicyUpdate(base::DictionaryValue* policies) {
1062 // Returns true if the host has to be restarted after this policy update.
1063 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1065 std::string udp_port_range;
1066 if (!policies->GetString(policy_hack::PolicyWatcher::kUdpPortRangePolicyName,
1067 &udp_port_range)) {
1068 return false;
1071 // Use default values if policy setting is empty or invalid.
1072 uint16 min_udp_port = 0;
1073 uint16 max_udp_port = 0;
1074 if (!udp_port_range.empty() &&
1075 !NetworkSettings::ParsePortRange(udp_port_range, &min_udp_port,
1076 &max_udp_port)) {
1077 LOG(WARNING) << "Invalid port range policy: \"" << udp_port_range
1078 << "\". Using default values.";
1081 if (min_udp_port_ != min_udp_port || max_udp_port_ != max_udp_port) {
1082 if (min_udp_port != 0 && max_udp_port != 0) {
1083 HOST_LOG << "Policy restricts UDP port range to [" << min_udp_port
1084 << ", " << max_udp_port << "]";
1085 } else {
1086 HOST_LOG << "Policy does not restrict UDP port range.";
1088 min_udp_port_ = min_udp_port;
1089 max_udp_port_ = max_udp_port;
1090 return true;
1092 return false;
1095 bool HostProcess::OnCurtainPolicyUpdate(base::DictionaryValue* policies) {
1096 // Returns true if the host has to be restarted after this policy update.
1097 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1099 if (!policies->GetBoolean(
1100 policy_hack::PolicyWatcher::kHostRequireCurtainPolicyName,
1101 &curtain_required_)) {
1102 return false;
1105 #if defined(OS_MACOSX)
1106 if (curtain_required_) {
1107 // When curtain mode is in effect on Mac, the host process runs in the
1108 // user's switched-out session, but launchd will also run an instance at
1109 // the console login screen. Even if no user is currently logged-on, we
1110 // can't support remote-access to the login screen because the current host
1111 // process model disconnects the client during login, which would leave
1112 // the logged in session un-curtained on the console until they reconnect.
1114 // TODO(jamiewalch): Fix this once we have implemented the multi-process
1115 // daemon architecture (crbug.com/134894)
1116 if (getuid() == 0) {
1117 LOG(ERROR) << "Running the host in the console login session is yet not "
1118 "supported.";
1119 ShutdownHost(kLoginScreenNotSupportedExitCode);
1120 return false;
1123 #endif
1125 if (curtain_required_) {
1126 HOST_LOG << "Policy requires curtain-mode.";
1127 } else {
1128 HOST_LOG << "Policy does not require curtain-mode.";
1131 if (host_)
1132 host_->SetEnableCurtaining(curtain_required_);
1133 return false;
1136 bool HostProcess::OnHostTalkGadgetPrefixPolicyUpdate(
1137 base::DictionaryValue* policies) {
1138 // Returns true if the host has to be restarted after this policy update.
1139 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1141 if (!policies->GetString(
1142 policy_hack::PolicyWatcher::kHostTalkGadgetPrefixPolicyName,
1143 &talkgadget_prefix_)) {
1144 return false;
1147 HOST_LOG << "Policy sets talkgadget prefix: " << talkgadget_prefix_;
1148 return true;
1151 bool HostProcess::OnHostTokenUrlPolicyUpdate(base::DictionaryValue* policies) {
1152 // Returns true if the host has to be restarted after this policy update.
1153 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1155 bool token_policy_changed = false;
1156 std::string token_url_string;
1157 if (policies->GetString(
1158 policy_hack::PolicyWatcher::kHostTokenUrlPolicyName,
1159 &token_url_string)) {
1160 token_policy_changed = true;
1161 third_party_auth_config_.token_url = GURL(token_url_string);
1163 std::string token_validation_url_string;
1164 if (policies->GetString(
1165 policy_hack::PolicyWatcher::kHostTokenValidationUrlPolicyName,
1166 &token_validation_url_string)) {
1167 token_policy_changed = true;
1168 third_party_auth_config_.token_validation_url =
1169 GURL(token_validation_url_string);
1171 if (policies->GetString(
1172 policy_hack::PolicyWatcher::kHostTokenValidationCertIssuerPolicyName,
1173 &third_party_auth_config_.token_validation_cert_issuer)) {
1174 token_policy_changed = true;
1177 if (token_policy_changed) {
1178 HOST_LOG << "Policy sets third-party token URLs: "
1179 << "TokenUrl: "
1180 << third_party_auth_config_.token_url << ", "
1181 << "TokenValidationUrl: "
1182 << third_party_auth_config_.token_validation_url << ", "
1183 << "TokenValidationCertificateIssuer: "
1184 << third_party_auth_config_.token_validation_cert_issuer;
1186 return token_policy_changed;
1189 bool HostProcess::OnPairingPolicyUpdate(base::DictionaryValue* policies) {
1190 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1192 if (!policies->GetBoolean(
1193 policy_hack::PolicyWatcher::kHostAllowClientPairing,
1194 &allow_pairing_)) {
1195 return false;
1198 if (allow_pairing_) {
1199 HOST_LOG << "Policy enables client pairing.";
1200 } else {
1201 HOST_LOG << "Policy disables client pairing.";
1203 return true;
1206 bool HostProcess::OnGnubbyAuthPolicyUpdate(base::DictionaryValue* policies) {
1207 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1209 if (!policies->GetBoolean(
1210 policy_hack::PolicyWatcher::kHostAllowGnubbyAuthPolicyName,
1211 &enable_gnubby_auth_)) {
1212 return false;
1215 if (enable_gnubby_auth_) {
1216 HOST_LOG << "Policy enables gnubby auth.";
1217 } else {
1218 HOST_LOG << "Policy disables gnubby auth.";
1221 if (desktop_environment_factory_)
1222 desktop_environment_factory_->SetEnableGnubbyAuth(enable_gnubby_auth_);
1224 return true;
1227 void HostProcess::StartHost() {
1228 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1229 DCHECK(!host_);
1230 DCHECK(!signal_strategy_.get());
1231 DCHECK(state_ == HOST_INITIALIZING || state_ == HOST_STOPPING_TO_RESTART ||
1232 state_ == HOST_STOPPED) << state_;
1233 state_ = HOST_STARTED;
1235 signal_strategy_.reset(
1236 new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(),
1237 context_->url_request_context_getter(),
1238 xmpp_server_config_));
1240 scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker(
1241 new DnsBlackholeChecker(context_->url_request_context_getter(),
1242 talkgadget_prefix_));
1244 // Create a NetworkChangeNotifier for use by the signaling connector.
1245 network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
1247 signaling_connector_.reset(new SignalingConnector(
1248 signal_strategy_.get(),
1249 dns_blackhole_checker.Pass(),
1250 base::Bind(&HostProcess::OnAuthFailed, this)));
1252 if (!oauth_refresh_token_.empty()) {
1253 scoped_ptr<OAuthTokenGetter::OAuthCredentials> oauth_credentials;
1254 oauth_credentials.reset(
1255 new OAuthTokenGetter::OAuthCredentials(
1256 xmpp_server_config_.username, oauth_refresh_token_,
1257 use_service_account_));
1259 oauth_token_getter_.reset(new OAuthTokenGetter(
1260 oauth_credentials.Pass(), context_->url_request_context_getter(),
1261 false));
1263 signaling_connector_->EnableOAuth(oauth_token_getter_.get());
1266 uint32 network_flags = 0;
1267 if (allow_nat_traversal_) {
1268 network_flags = NetworkSettings::NAT_TRAVERSAL_STUN |
1269 NetworkSettings::NAT_TRAVERSAL_OUTGOING;
1270 if (allow_relay_)
1271 network_flags |= NetworkSettings::NAT_TRAVERSAL_RELAY;
1274 NetworkSettings network_settings(network_flags);
1276 if (min_udp_port_ && max_udp_port_) {
1277 network_settings.min_port = min_udp_port_;
1278 network_settings.max_port = max_udp_port_;
1279 } else if (!allow_nat_traversal_) {
1280 // For legacy reasons we have to restrict the port range to a set of default
1281 // values when nat traversal is disabled, even if the port range was not
1282 // set in policy.
1283 network_settings.min_port = NetworkSettings::kDefaultMinPort;
1284 network_settings.max_port = NetworkSettings::kDefaultMaxPort;
1287 host_.reset(new ChromotingHost(
1288 signal_strategy_.get(),
1289 desktop_environment_factory_.get(),
1290 CreateHostSessionManager(signal_strategy_.get(), network_settings,
1291 context_->url_request_context_getter()),
1292 context_->audio_task_runner(),
1293 context_->input_task_runner(),
1294 context_->video_capture_task_runner(),
1295 context_->video_encode_task_runner(),
1296 context_->network_task_runner(),
1297 context_->ui_task_runner()));
1299 if (enable_vp9_) {
1300 scoped_ptr<protocol::CandidateSessionConfig> config =
1301 host_->protocol_config()->Clone();
1302 config->EnableVideoCodec(protocol::ChannelConfig::CODEC_VP9);
1303 host_->set_protocol_config(config.Pass());
1306 if (frame_recorder_buffer_size_ > 0) {
1307 scoped_ptr<VideoFrameRecorderHostExtension> frame_recorder_extension(
1308 new VideoFrameRecorderHostExtension());
1309 frame_recorder_extension->SetMaxContentBytes(frame_recorder_buffer_size_);
1310 host_->AddExtension(frame_recorder_extension.Pass());
1313 // TODO(simonmorris): Get the maximum session duration from a policy.
1314 #if defined(OS_LINUX)
1315 host_->SetMaximumSessionDuration(base::TimeDelta::FromHours(20));
1316 #endif
1318 heartbeat_sender_.reset(new HeartbeatSender(
1319 this, host_id_, signal_strategy_.get(), key_pair_,
1320 directory_bot_jid_));
1322 host_status_sender_.reset(new HostStatusSender(
1323 host_id_, signal_strategy_.get(), key_pair_, directory_bot_jid_));
1325 host_change_notification_listener_.reset(new HostChangeNotificationListener(
1326 this, host_id_, signal_strategy_.get(), directory_bot_jid_));
1328 host_status_logger_.reset(
1329 new HostStatusLogger(host_->AsWeakPtr(), ServerLogEntry::ME2ME,
1330 signal_strategy_.get(), directory_bot_jid_));
1332 // Set up reporting the host status notifications.
1333 #if defined(REMOTING_MULTI_PROCESS)
1334 host_event_logger_.reset(
1335 new IpcHostEventLogger(host_->AsWeakPtr(), daemon_channel_.get()));
1336 #else // !defined(REMOTING_MULTI_PROCESS)
1337 host_event_logger_ =
1338 HostEventLogger::Create(host_->AsWeakPtr(), kApplicationName);
1339 #endif // !defined(REMOTING_MULTI_PROCESS)
1341 host_->SetEnableCurtaining(curtain_required_);
1342 host_->Start(host_owner_email_);
1344 CreateAuthenticatorFactory();
1347 void HostProcess::OnAuthFailed() {
1348 ShutdownHost(kInvalidOauthCredentialsExitCode);
1351 void HostProcess::RestartHost() {
1352 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1353 DCHECK_EQ(state_, HOST_STARTED);
1355 state_ = HOST_STOPPING_TO_RESTART;
1356 ShutdownOnNetworkThread();
1359 void HostProcess::ShutdownHost(HostExitCodes exit_code) {
1360 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1362 *exit_code_out_ = exit_code;
1364 switch (state_) {
1365 case HOST_INITIALIZING:
1366 state_ = HOST_STOPPING;
1367 ShutdownOnNetworkThread();
1368 break;
1370 case HOST_STARTED:
1371 state_ = HOST_STOPPING;
1372 host_status_sender_->SendOfflineStatus(exit_code);
1373 ScheduleHostShutdown();
1374 break;
1376 case HOST_STOPPING_TO_RESTART:
1377 state_ = HOST_STOPPING;
1378 break;
1380 case HOST_STOPPING:
1381 case HOST_STOPPED:
1382 // Host is already stopped or being stopped. No action is required.
1383 break;
1387 // TODO(weitaosu): shut down the host once we get an ACK for the offline status
1388 // XMPP message.
1389 void HostProcess::ScheduleHostShutdown() {
1390 // Delay the shutdown by 2 second to allow SendOfflineStatus to complete.
1391 context_->network_task_runner()->PostDelayedTask(
1392 FROM_HERE,
1393 base::Bind(&HostProcess::ShutdownOnNetworkThread, base::Unretained(this)),
1394 base::TimeDelta::FromSeconds(2));
1397 void HostProcess::ShutdownOnNetworkThread() {
1398 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1400 host_.reset();
1401 host_event_logger_.reset();
1402 host_status_logger_.reset();
1403 heartbeat_sender_.reset();
1404 host_status_sender_.reset();
1405 host_change_notification_listener_.reset();
1406 signaling_connector_.reset();
1407 oauth_token_getter_.reset();
1408 signal_strategy_.reset();
1409 network_change_notifier_.reset();
1411 if (state_ == HOST_STOPPING_TO_RESTART) {
1412 StartHost();
1413 } else if (state_ == HOST_STOPPING) {
1414 state_ = HOST_STOPPED;
1416 if (policy_watcher_.get()) {
1417 policy_watcher_->StopWatching(
1418 base::Bind(&HostProcess::OnPolicyWatcherShutdown, this));
1419 } else {
1420 OnPolicyWatcherShutdown();
1422 } else {
1423 // This method is only called in STOPPING_TO_RESTART and STOPPING states.
1424 NOTREACHED();
1428 void HostProcess::OnPolicyWatcherShutdown() {
1429 policy_watcher_.reset();
1431 // Complete the rest of shutdown on the main thread.
1432 context_->ui_task_runner()->PostTask(
1433 FROM_HERE, base::Bind(&HostProcess::ShutdownOnUiThread, this));
1436 void HostProcess::OnCrash(const std::string& function_name,
1437 const std::string& file_name,
1438 const int& line_number) {
1439 char message[1024];
1440 base::snprintf(message, sizeof(message),
1441 "Requested by %s at %s, line %d.",
1442 function_name.c_str(), file_name.c_str(), line_number);
1443 base::debug::Alias(message);
1445 // The daemon requested us to crash the process.
1446 CHECK(false) << message;
1449 int HostProcessMain() {
1450 #if defined(OS_LINUX)
1451 // Required in order for us to run multiple X11 threads.
1452 XInitThreads();
1454 // Required for any calls into GTK functions, such as the Disconnect and
1455 // Continue windows, though these should not be used for the Me2Me case
1456 // (crbug.com/104377).
1457 gtk_init(NULL, NULL);
1458 #endif
1460 // Enable support for SSL server sockets, which must be done while still
1461 // single-threaded.
1462 net::EnableSSLServerSockets();
1464 // Ensures runtime specific CPU features are initialized.
1465 media::InitializeCPUSpecificMediaFeatures();
1467 // Create the main message loop and start helper threads.
1468 base::MessageLoopForUI message_loop;
1469 scoped_ptr<ChromotingHostContext> context =
1470 ChromotingHostContext::Create(new AutoThreadTaskRunner(
1471 message_loop.message_loop_proxy(), base::MessageLoop::QuitClosure()));
1472 if (!context)
1473 return kInitializationFailed;
1475 // Create & start the HostProcess using these threads.
1476 // TODO(wez): The HostProcess holds a reference to itself until Shutdown().
1477 // Remove this hack as part of the multi-process refactoring.
1478 int exit_code = kSuccessExitCode;
1479 new HostProcess(context.Pass(), &exit_code);
1481 // Run the main (also UI) message loop until the host no longer needs it.
1482 message_loop.Run();
1484 return exit_code;
1487 } // namespace remoting