Stop using legacy GrContext member function aliases.
[chromium-blink-merge.git] / remoting / host / remoting_me2me_host.cc
blob6aa6b1e27eefdfead7a33b6ab89920cf4f6ba5cc
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/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"
79 #if defined(OS_POSIX)
80 #include <signal.h>
81 #include <sys/types.h>
82 #include <unistd.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)
92 #if defined(OS_LINUX)
93 #include <gtk/gtk.h>
94 #include <X11/Xlib.h>
95 #include "remoting/host/audio_capturer_linux.h"
96 #endif // defined(OS_LINUX)
98 #if defined(OS_WIN)
99 #include <commctrl.h>
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;
109 namespace {
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
116 // linux.
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
135 // from stdin.
136 const char kStdinConfigPath[] = "-";
138 const char kWindowIdSwitchName[] = "window-id";
140 } // namespace
142 namespace remoting {
144 class HostProcess
145 : public ConfigWatcher::Delegate,
146 public HeartbeatSender::Listener,
147 public HostChangeNotificationListener::Listener,
148 public IPC::Listener,
149 public base::RefCountedThreadSafe<HostProcess> {
150 public:
151 HostProcess(scoped_ptr<ChromotingHostContext> context,
152 int* exit_code_out);
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);
174 private:
175 enum HostState {
176 // Host process has just been started. Waiting for config and policies to be
177 // read from the disk.
178 HOST_INITIALIZING,
180 // Host is started and running.
181 HOST_STARTED,
183 // Host is being stopped and will need to be started again.
184 HOST_STOPPING_TO_RESTART,
186 // Host is being stopped.
187 HOST_STOPPING,
189 // Host has been stopped.
190 HOST_STOPPED,
192 // Allowed state transitions:
193 // INITIALIZING->STARTED
194 // INITIALIZING->STOPPED
195 // STARTED->STOPPING_TO_RESTART
196 // STARTED->STOPPING
197 // STOPPING_TO_RESTART->STARTED
198 // STOPPING_TO_RESTART->STOPPING
199 // STOPPING->STOPPED
200 // STOPPED->STARTED
202 // |host_| must be NULL in INITIALIZING and STOPPED states and not-NULL in
203 // all other states.
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);
214 #endif
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);
250 void StartHost();
252 void OnAuthFailed();
254 void RestartHost();
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
265 // request.
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.
288 HostState state_;
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 std::string host_owner_email_;
299 bool use_service_account_;
300 bool enable_vp9_;
301 int64_t frame_recorder_buffer_size_;
303 scoped_ptr<policy_hack::PolicyWatcher> policy_watcher_;
304 std::string host_domain_;
305 bool host_username_match_required_;
306 bool allow_nat_traversal_;
307 bool allow_relay_;
308 int min_udp_port_;
309 int max_udp_port_;
310 std::string talkgadget_prefix_;
311 bool allow_pairing_;
313 bool curtain_required_;
314 ThirdPartyAuthConfig third_party_auth_config_;
315 bool enable_gnubby_auth_;
317 // Boolean to change flow, where ncessary, if we're
318 // capturing a window instead of the entire desktop.
319 bool enable_window_capture_;
321 // Used to specify which window to stream, if enabled.
322 webrtc::WindowId window_id_;
324 scoped_ptr<OAuthTokenGetter> oauth_token_getter_;
325 scoped_ptr<XmppSignalStrategy> signal_strategy_;
326 scoped_ptr<SignalingConnector> signaling_connector_;
327 scoped_ptr<HeartbeatSender> heartbeat_sender_;
328 scoped_ptr<HostStatusSender> host_status_sender_;
329 scoped_ptr<HostChangeNotificationListener> host_change_notification_listener_;
330 scoped_ptr<HostStatusLogger> host_status_logger_;
331 scoped_ptr<HostEventLogger> host_event_logger_;
333 scoped_ptr<ChromotingHost> host_;
335 // Used to keep this HostProcess alive until it is shutdown.
336 scoped_refptr<HostProcess> self_;
338 #if defined(REMOTING_MULTI_PROCESS)
339 DesktopSessionConnector* desktop_session_connector_;
340 #endif // defined(REMOTING_MULTI_PROCESS)
342 int* exit_code_out_;
343 bool signal_parent_;
345 scoped_ptr<PairingRegistry::Delegate> pairing_registry_delegate_;
348 HostProcess::HostProcess(scoped_ptr<ChromotingHostContext> context,
349 int* exit_code_out)
350 : context_(context.Pass()),
351 state_(HOST_INITIALIZING),
352 use_service_account_(false),
353 enable_vp9_(false),
354 frame_recorder_buffer_size_(0),
355 host_username_match_required_(false),
356 allow_nat_traversal_(true),
357 allow_relay_(true),
358 min_udp_port_(0),
359 max_udp_port_(0),
360 allow_pairing_(true),
361 curtain_required_(false),
362 enable_gnubby_auth_(false),
363 enable_window_capture_(false),
364 window_id_(0),
365 #if defined(REMOTING_MULTI_PROCESS)
366 desktop_session_connector_(NULL),
367 #endif // defined(REMOTING_MULTI_PROCESS)
368 self_(this),
369 exit_code_out_(exit_code_out),
370 signal_parent_(false) {
371 StartOnUiThread();
374 HostProcess::~HostProcess() {
375 // Verify that UI components have been torn down.
376 DCHECK(!config_watcher_);
377 DCHECK(!daemon_channel_);
378 DCHECK(!desktop_environment_factory_);
380 // We might be getting deleted on one of the threads the |host_context| owns,
381 // so we need to post it back to the caller thread to safely join & delete the
382 // threads it contains. This will go away when we move to AutoThread.
383 // |context_release()| will null |context_| before the method is invoked, so
384 // we need to pull out the task-runner on which to call DeleteSoon first.
385 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
386 context_->ui_task_runner();
387 task_runner->DeleteSoon(FROM_HERE, context_.release());
390 bool HostProcess::InitWithCommandLine(const base::CommandLine* cmd_line) {
391 #if defined(REMOTING_MULTI_PROCESS)
392 // Parse the handle value and convert it to a handle/file descriptor.
393 std::string channel_name =
394 cmd_line->GetSwitchValueASCII(kDaemonPipeSwitchName);
396 int pipe_handle = 0;
397 if (channel_name.empty() ||
398 !base::StringToInt(channel_name, &pipe_handle)) {
399 LOG(ERROR) << "Invalid '" << kDaemonPipeSwitchName
400 << "' value: " << channel_name;
401 return false;
404 #if defined(OS_WIN)
405 base::win::ScopedHandle pipe(reinterpret_cast<HANDLE>(pipe_handle));
406 IPC::ChannelHandle channel_handle(pipe.Get());
407 #elif defined(OS_POSIX)
408 base::FileDescriptor pipe(pipe_handle, true);
409 IPC::ChannelHandle channel_handle(channel_name, pipe);
410 #endif // defined(OS_POSIX)
412 // Connect to the daemon process.
413 daemon_channel_ = IPC::ChannelProxy::Create(channel_handle,
414 IPC::Channel::MODE_CLIENT,
415 this,
416 context_->network_task_runner());
417 #else // !defined(REMOTING_MULTI_PROCESS)
418 // Connect to the daemon process.
419 std::string channel_name =
420 cmd_line->GetSwitchValueASCII(kDaemonPipeSwitchName);
421 if (!channel_name.empty()) {
422 daemon_channel_ =
423 IPC::ChannelProxy::Create(channel_name,
424 IPC::Channel::MODE_CLIENT,
425 this,
426 context_->network_task_runner().get());
429 if (cmd_line->HasSwitch(kHostConfigSwitchName)) {
430 host_config_path_ = cmd_line->GetSwitchValuePath(kHostConfigSwitchName);
432 // Read config from stdin if necessary.
433 if (host_config_path_ == base::FilePath(kStdinConfigPath)) {
434 char buf[4096];
435 size_t len;
436 while ((len = fread(buf, 1, sizeof(buf), stdin)) > 0) {
437 host_config_.append(buf, len);
440 } else {
441 base::FilePath default_config_dir = remoting::GetConfigDir();
442 host_config_path_ = default_config_dir.Append(kDefaultHostConfigFile);
445 if (host_config_path_ != base::FilePath(kStdinConfigPath) &&
446 !base::PathExists(host_config_path_)) {
447 LOG(ERROR) << "Can't find host config at " << host_config_path_.value();
448 return false;
450 #endif // !defined(REMOTING_MULTI_PROCESS)
452 // Ignore certificate requests - the host currently has no client certificate
453 // support, so ignoring certificate requests allows connecting to servers that
454 // request, but don't require, a certificate (optional client authentication).
455 net::URLFetcher::SetIgnoreCertificateRequests(true);
457 ServiceUrls* service_urls = ServiceUrls::GetInstance();
458 bool xmpp_server_valid = net::ParseHostAndPort(
459 service_urls->xmpp_server_address(),
460 &xmpp_server_config_.host, &xmpp_server_config_.port);
461 if (!xmpp_server_valid) {
462 LOG(ERROR) << "Invalid XMPP server: " <<
463 service_urls->xmpp_server_address();
464 return false;
466 xmpp_server_config_.use_tls = service_urls->xmpp_server_use_tls();
467 directory_bot_jid_ = service_urls->directory_bot_jid();
469 signal_parent_ = cmd_line->HasSwitch(kSignalParentSwitchName);
471 enable_window_capture_ = cmd_line->HasSwitch(kWindowIdSwitchName);
472 if (enable_window_capture_) {
474 #if defined(OS_LINUX) || defined(OS_WIN)
475 LOG(WARNING) << "Window capturing is not fully supported on Linux or "
476 "Windows.";
477 #endif // defined(OS_LINUX) || defined(OS_WIN)
479 // uint32_t is large enough to hold window IDs on all platforms.
480 uint32_t window_id;
481 if (base::StringToUint(
482 cmd_line->GetSwitchValueASCII(kWindowIdSwitchName),
483 &window_id)) {
484 window_id_ = static_cast<webrtc::WindowId>(window_id);
485 } else {
486 LOG(ERROR) << "Window with window id: " << window_id_
487 << " not found. Shutting down host.";
488 return false;
491 return true;
494 void HostProcess::OnConfigUpdated(
495 const std::string& serialized_config) {
496 if (!context_->network_task_runner()->BelongsToCurrentThread()) {
497 context_->network_task_runner()->PostTask(FROM_HERE,
498 base::Bind(&HostProcess::OnConfigUpdated, this, serialized_config));
499 return;
502 // Filter out duplicates.
503 if (serialized_config_ == serialized_config)
504 return;
506 HOST_LOG << "Processing new host configuration.";
508 serialized_config_ = serialized_config;
509 scoped_ptr<JsonHostConfig> config(new JsonHostConfig(base::FilePath()));
510 if (!config->SetSerializedData(serialized_config)) {
511 LOG(ERROR) << "Invalid configuration.";
512 ShutdownHost(kInvalidHostConfigurationExitCode);
513 return;
516 if (!ApplyConfig(config.Pass())) {
517 LOG(ERROR) << "Failed to apply the configuration.";
518 ShutdownHost(kInvalidHostConfigurationExitCode);
519 return;
522 if (state_ == HOST_INITIALIZING) {
523 // TODO(sergeyu): Currently OnPolicyUpdate() assumes that host config is
524 // already loaded so PolicyWatcher has to be started here. Separate policy
525 // loading from policy verifications and move |policy_watcher_|
526 // initialization to StartOnNetworkThread().
527 policy_watcher_.reset(
528 policy_hack::PolicyWatcher::Create(context_->file_task_runner()));
529 policy_watcher_->StartWatching(
530 base::Bind(&HostProcess::OnPolicyUpdate, base::Unretained(this)));
531 } else {
532 // Reapply policies that could be affected by a new config.
533 ApplyHostDomainPolicy();
534 ApplyUsernamePolicy();
536 if (state_ == HOST_STARTED) {
537 // TODO(sergeyu): Here we assume that PIN is the only part of the config
538 // that may change while the service is running. Change ApplyConfig() to
539 // detect other changes in the config and restart host if necessary here.
540 CreateAuthenticatorFactory();
545 void HostProcess::OnConfigWatcherError() {
546 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
547 ShutdownHost(kInvalidHostConfigurationExitCode);
550 void HostProcess::StartOnNetworkThread() {
551 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
553 #if !defined(REMOTING_MULTI_PROCESS)
554 if (host_config_path_ == base::FilePath(kStdinConfigPath)) {
555 // Process config we've read from stdin.
556 OnConfigUpdated(host_config_);
557 } else {
558 // Start watching the host configuration file.
559 config_watcher_.reset(new ConfigFileWatcher(context_->network_task_runner(),
560 context_->file_task_runner(),
561 host_config_path_));
562 config_watcher_->Watch(this);
564 #endif // !defined(REMOTING_MULTI_PROCESS)
566 #if defined(OS_POSIX)
567 remoting::RegisterSignalHandler(
568 SIGTERM,
569 base::Bind(&HostProcess::SigTermHandler, base::Unretained(this)));
570 #endif // defined(OS_POSIX)
573 #if defined(OS_POSIX)
574 void HostProcess::SigTermHandler(int signal_number) {
575 DCHECK(signal_number == SIGTERM);
576 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
577 HOST_LOG << "Caught SIGTERM: Shutting down...";
578 ShutdownHost(kSuccessExitCode);
580 #endif // OS_POSIX
582 void HostProcess::CreateAuthenticatorFactory() {
583 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
585 if (state_ != HOST_STARTED)
586 return;
588 std::string local_certificate = key_pair_->GenerateCertificate();
589 if (local_certificate.empty()) {
590 LOG(ERROR) << "Failed to generate host certificate.";
591 ShutdownHost(kInitializationFailed);
592 return;
595 scoped_refptr<PairingRegistry> pairing_registry = NULL;
596 if (allow_pairing_) {
597 if (!pairing_registry_delegate_)
598 pairing_registry_delegate_ = CreatePairingRegistryDelegate();
600 if (pairing_registry_delegate_) {
601 pairing_registry = new PairingRegistry(context_->file_task_runner(),
602 pairing_registry_delegate_.Pass());
606 scoped_ptr<protocol::AuthenticatorFactory> factory;
608 if (third_party_auth_config_.is_empty()) {
609 factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithSharedSecret(
610 use_service_account_, host_owner_, local_certificate, key_pair_,
611 host_secret_hash_, pairing_registry);
613 } else if (third_party_auth_config_.is_valid()) {
614 scoped_ptr<protocol::TokenValidatorFactory> token_validator_factory(
615 new TokenValidatorFactoryImpl(
616 third_party_auth_config_,
617 key_pair_, context_->url_request_context_getter()));
618 factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth(
619 use_service_account_, host_owner_, local_certificate, key_pair_,
620 token_validator_factory.Pass());
622 } else {
623 // TODO(rmsousa): If the policy is bad the host should not go online. It
624 // should keep running, but not connected, until the policies are fixed.
625 // Having it show up as online and then reject all clients is misleading.
626 LOG(ERROR) << "One of the third-party token URLs is empty or invalid. "
627 << "Host will reject all clients until policies are corrected. "
628 << "TokenUrl: " << third_party_auth_config_.token_url << ", "
629 << "TokenValidationUrl: "
630 << third_party_auth_config_.token_validation_url;
631 factory = protocol::Me2MeHostAuthenticatorFactory::CreateRejecting();
634 #if defined(OS_POSIX)
635 // On Linux and Mac, perform a PAM authorization step after authentication.
636 factory.reset(new PamAuthorizationFactory(factory.Pass()));
637 #endif
638 host_->SetAuthenticatorFactory(factory.Pass());
640 host_->set_pairing_registry(pairing_registry);
643 // IPC::Listener implementation.
644 bool HostProcess::OnMessageReceived(const IPC::Message& message) {
645 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
647 #if defined(REMOTING_MULTI_PROCESS)
648 bool handled = true;
649 IPC_BEGIN_MESSAGE_MAP(HostProcess, message)
650 IPC_MESSAGE_HANDLER(ChromotingDaemonMsg_Crash, OnCrash)
651 IPC_MESSAGE_HANDLER(ChromotingDaemonNetworkMsg_Configuration,
652 OnConfigUpdated)
653 IPC_MESSAGE_HANDLER(ChromotingDaemonNetworkMsg_InitializePairingRegistry,
654 OnInitializePairingRegistry)
655 IPC_MESSAGE_FORWARD(
656 ChromotingDaemonNetworkMsg_DesktopAttached,
657 desktop_session_connector_,
658 DesktopSessionConnector::OnDesktopSessionAgentAttached)
659 IPC_MESSAGE_FORWARD(ChromotingDaemonNetworkMsg_TerminalDisconnected,
660 desktop_session_connector_,
661 DesktopSessionConnector::OnTerminalDisconnected)
662 IPC_MESSAGE_UNHANDLED(handled = false)
663 IPC_END_MESSAGE_MAP()
665 CHECK(handled) << "Received unexpected IPC type: " << message.type();
666 return handled;
668 #else // !defined(REMOTING_MULTI_PROCESS)
669 return false;
670 #endif // !defined(REMOTING_MULTI_PROCESS)
673 void HostProcess::OnChannelError() {
674 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
676 // Shutdown the host if the daemon process disconnects the IPC channel.
677 context_->network_task_runner()->PostTask(
678 FROM_HERE,
679 base::Bind(&HostProcess::ShutdownHost, this, kSuccessExitCode));
682 void HostProcess::StartOnUiThread() {
683 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
685 if (!InitWithCommandLine(base::CommandLine::ForCurrentProcess())) {
686 // Shutdown the host if the command line is invalid.
687 context_->network_task_runner()->PostTask(
688 FROM_HERE, base::Bind(&HostProcess::ShutdownHost, this,
689 kUsageExitCode));
690 return;
693 #if defined(OS_LINUX)
694 // If an audio pipe is specific on the command-line then initialize
695 // AudioCapturerLinux to capture from it.
696 base::FilePath audio_pipe_name = base::CommandLine::ForCurrentProcess()->
697 GetSwitchValuePath(kAudioPipeSwitchName);
698 if (!audio_pipe_name.empty()) {
699 remoting::AudioCapturerLinux::InitializePipeReader(
700 context_->audio_task_runner(), audio_pipe_name);
703 base::FilePath gnubby_socket_name = base::CommandLine::ForCurrentProcess()->
704 GetSwitchValuePath(kAuthSocknameSwitchName);
705 if (!gnubby_socket_name.empty())
706 remoting::GnubbyAuthHandler::SetGnubbySocketName(gnubby_socket_name);
707 #endif // defined(OS_LINUX)
709 // Create a desktop environment factory appropriate to the build type &
710 // platform.
711 #if defined(OS_WIN)
712 IpcDesktopEnvironmentFactory* desktop_environment_factory =
713 new IpcDesktopEnvironmentFactory(
714 context_->audio_task_runner(),
715 context_->network_task_runner(),
716 context_->video_capture_task_runner(),
717 context_->network_task_runner(),
718 daemon_channel_.get());
719 desktop_session_connector_ = desktop_environment_factory;
720 #else // !defined(OS_WIN)
721 DesktopEnvironmentFactory* desktop_environment_factory;
722 if (enable_window_capture_) {
723 desktop_environment_factory =
724 new SingleWindowDesktopEnvironmentFactory(
725 context_->network_task_runner(),
726 context_->input_task_runner(),
727 context_->ui_task_runner(),
728 window_id_);
729 } else {
730 desktop_environment_factory =
731 new Me2MeDesktopEnvironmentFactory(
732 context_->network_task_runner(),
733 context_->input_task_runner(),
734 context_->ui_task_runner());
736 #endif // !defined(OS_WIN)
738 desktop_environment_factory_.reset(desktop_environment_factory);
739 desktop_environment_factory_->SetEnableGnubbyAuth(enable_gnubby_auth_);
741 context_->network_task_runner()->PostTask(
742 FROM_HERE,
743 base::Bind(&HostProcess::StartOnNetworkThread, this));
746 void HostProcess::ShutdownOnUiThread() {
747 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
749 // Tear down resources that need to be torn down on the UI thread.
750 network_change_notifier_.reset();
751 daemon_channel_.reset();
752 desktop_environment_factory_.reset();
754 // It is now safe for the HostProcess to be deleted.
755 self_ = NULL;
757 #if defined(OS_LINUX)
758 // Cause the global AudioPipeReader to be freed, otherwise the audio
759 // thread will remain in-use and prevent the process from exiting.
760 // TODO(wez): DesktopEnvironmentFactory should own the pipe reader.
761 // See crbug.com/161373 and crbug.com/104544.
762 AudioCapturerLinux::InitializePipeReader(NULL, base::FilePath());
763 #endif
766 // Overridden from HeartbeatSender::Listener
767 void HostProcess::OnUnknownHostIdError() {
768 LOG(ERROR) << "Host ID not found.";
769 ShutdownHost(kInvalidHostIdExitCode);
772 void HostProcess::OnHeartbeatSuccessful() {
773 HOST_LOG << "Host ready to receive connections.";
774 #if defined(OS_POSIX)
775 if (signal_parent_) {
776 kill(getppid(), SIGUSR1);
777 signal_parent_ = false;
779 #endif
782 void HostProcess::OnHostDeleted() {
783 LOG(ERROR) << "Host was deleted from the directory.";
784 ShutdownHost(kInvalidHostIdExitCode);
787 void HostProcess::OnInitializePairingRegistry(
788 IPC::PlatformFileForTransit privileged_key,
789 IPC::PlatformFileForTransit unprivileged_key) {
790 DCHECK(!pairing_registry_delegate_);
792 #if defined(OS_WIN)
793 // Initialize the pairing registry delegate.
794 scoped_ptr<PairingRegistryDelegateWin> delegate(
795 new PairingRegistryDelegateWin());
796 bool result = delegate->SetRootKeys(
797 reinterpret_cast<HKEY>(
798 IPC::PlatformFileForTransitToPlatformFile(privileged_key)),
799 reinterpret_cast<HKEY>(
800 IPC::PlatformFileForTransitToPlatformFile(unprivileged_key)));
801 if (!result)
802 return;
804 pairing_registry_delegate_ = delegate.Pass();
805 #else // !defined(OS_WIN)
806 NOTREACHED();
807 #endif // !defined(OS_WIN)
810 // Applies the host config, returning true if successful.
811 bool HostProcess::ApplyConfig(scoped_ptr<JsonHostConfig> config) {
812 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
814 if (!config->GetString(kHostIdConfigPath, &host_id_)) {
815 LOG(ERROR) << "host_id is not defined in the config.";
816 return false;
819 std::string key_base64;
820 if (!config->GetString(kPrivateKeyConfigPath, &key_base64)) {
821 LOG(ERROR) << "Private key couldn't be read from the config file.";
822 return false;
825 key_pair_ = RsaKeyPair::FromString(key_base64);
826 if (!key_pair_.get()) {
827 LOG(ERROR) << "Invalid private key in the config file.";
828 return false;
831 std::string host_secret_hash_string;
832 if (!config->GetString(kHostSecretHashConfigPath,
833 &host_secret_hash_string)) {
834 host_secret_hash_string = "plain:";
837 if (!host_secret_hash_.Parse(host_secret_hash_string)) {
838 LOG(ERROR) << "Invalid host_secret_hash.";
839 return false;
842 // Use an XMPP connection to the Talk network for session signalling.
843 if (!config->GetString(kXmppLoginConfigPath, &xmpp_server_config_.username) ||
844 !(config->GetString(kXmppAuthTokenConfigPath,
845 &xmpp_server_config_.auth_token) ||
846 config->GetString(kOAuthRefreshTokenConfigPath,
847 &oauth_refresh_token_))) {
848 LOG(ERROR) << "XMPP credentials are not defined in the config.";
849 return false;
852 if (!oauth_refresh_token_.empty()) {
853 // SignalingConnector is responsible for getting OAuth token.
854 xmpp_server_config_.auth_token = "";
855 xmpp_server_config_.auth_service = "oauth2";
856 } else if (!config->GetString(kXmppAuthServiceConfigPath,
857 &xmpp_server_config_.auth_service)) {
858 // For the me2me host, we default to ClientLogin token for chromiumsync
859 // because earlier versions of the host had no HTTP stack with which to
860 // request an OAuth2 access token.
861 xmpp_server_config_.auth_service = kChromotingTokenDefaultServiceName;
864 if (config->GetString(kHostOwnerConfigPath, &host_owner_)) {
865 // Service account configs have a host_owner, different from the xmpp_login.
866 use_service_account_ = true;
867 } else {
868 // User credential configs only have an xmpp_login, which is also the owner.
869 host_owner_ = xmpp_server_config_.username;
870 use_service_account_ = false;
873 // For non-Gmail Google accounts, the owner base JID differs from the email.
874 // host_owner_ contains the base JID (used for authenticating clients), while
875 // host_owner_email contains the account's email (used for UI and logs).
876 if (!config->GetString(kHostOwnerEmailConfigPath, &host_owner_email_)) {
877 host_owner_email_ = host_owner_;
880 // Allow offering of VP9 encoding to be overridden by the command-line.
881 if (CommandLine::ForCurrentProcess()->HasSwitch(kEnableVp9SwitchName)) {
882 enable_vp9_ = true;
883 } else {
884 config->GetBoolean(kEnableVp9ConfigPath, &enable_vp9_);
887 // Allow the command-line to override the size of the frame recorder buffer.
888 std::string frame_recorder_buffer_kb;
889 if (CommandLine::ForCurrentProcess()->HasSwitch(
890 kFrameRecorderBufferKbName)) {
891 frame_recorder_buffer_kb =
892 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
893 kFrameRecorderBufferKbName);
894 } else {
895 config->GetString(kFrameRecorderBufferKbConfigPath,
896 &frame_recorder_buffer_kb);
898 if (!frame_recorder_buffer_kb.empty()) {
899 int buffer_kb = 0;
900 if (base::StringToInt(frame_recorder_buffer_kb, &buffer_kb)) {
901 frame_recorder_buffer_size_ = 1024LL * buffer_kb;
905 return true;
908 void HostProcess::OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies) {
909 if (!context_->network_task_runner()->BelongsToCurrentThread()) {
910 context_->network_task_runner()->PostTask(FROM_HERE, base::Bind(
911 &HostProcess::OnPolicyUpdate, this, base::Passed(&policies)));
912 return;
915 bool restart_required = false;
916 restart_required |= OnHostDomainPolicyUpdate(policies.get());
917 restart_required |= OnCurtainPolicyUpdate(policies.get());
918 // Note: UsernamePolicyUpdate must run after OnCurtainPolicyUpdate.
919 restart_required |= OnUsernamePolicyUpdate(policies.get());
920 restart_required |= OnNatPolicyUpdate(policies.get());
921 restart_required |= OnRelayPolicyUpdate(policies.get());
922 restart_required |= OnUdpPortPolicyUpdate(policies.get());
923 restart_required |= OnHostTalkGadgetPrefixPolicyUpdate(policies.get());
924 restart_required |= OnHostTokenUrlPolicyUpdate(policies.get());
925 restart_required |= OnPairingPolicyUpdate(policies.get());
926 restart_required |= OnGnubbyAuthPolicyUpdate(policies.get());
928 if (state_ == HOST_INITIALIZING) {
929 StartHost();
930 } else if (state_ == HOST_STARTED && restart_required) {
931 RestartHost();
935 void HostProcess::ApplyHostDomainPolicy() {
936 HOST_LOG << "Policy sets host domain: " << host_domain_;
938 // If the user does not have a Google email, their client JID will not be
939 // based on their email. In that case, the username/host domain policies would
940 // be meaningless, since there is no way to check that the JID attempting to
941 // connect actually corresponds to the owner email in question.
942 if (host_owner_ != host_owner_email_) {
943 LOG(ERROR) << "The username and host domain policies cannot be enabled for "
944 << "accounts with a non-Google email.";
945 ShutdownHost(kInvalidHostDomainExitCode);
948 if (!host_domain_.empty() &&
949 !EndsWith(host_owner_, std::string("@") + host_domain_, false)) {
950 LOG(ERROR) << "The host domain does not match the policy.";
951 ShutdownHost(kInvalidHostDomainExitCode);
955 bool HostProcess::OnHostDomainPolicyUpdate(base::DictionaryValue* policies) {
956 // Returns true if the host has to be restarted after this policy update.
957 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
959 if (!policies->GetString(policy_hack::PolicyWatcher::kHostDomainPolicyName,
960 &host_domain_)) {
961 return false;
964 ApplyHostDomainPolicy();
965 return false;
968 void HostProcess::ApplyUsernamePolicy() {
969 // See comment in ApplyHostDomainPolicy.
970 if (host_owner_ != host_owner_email_) {
971 LOG(ERROR) << "The username and host domain policies cannot be enabled for "
972 << "accounts with a non-Google email.";
973 ShutdownHost(kUsernameMismatchExitCode);
976 if (host_username_match_required_) {
977 HOST_LOG << "Policy requires host username match.";
978 std::string username = GetUsername();
979 bool shutdown = username.empty() ||
980 !StartsWithASCII(host_owner_, username + std::string("@"),
981 false);
983 #if defined(OS_MACOSX)
984 // On Mac, we run as root at the login screen, so the username won't match.
985 // However, there's no need to enforce the policy at the login screen, as
986 // the client will have to reconnect if a login occurs.
987 if (shutdown && getuid() == 0) {
988 shutdown = false;
990 #endif
992 // Curtain-mode on Windows presents the standard OS login prompt to the user
993 // for each connection, removing the need for an explicit user-name matching
994 // check.
995 #if defined(OS_WIN) && defined(REMOTING_RDP_SESSION)
996 if (curtain_required_)
997 return;
998 #endif // defined(OS_WIN) && defined(REMOTING_RDP_SESSION)
1000 // Shutdown the host if the username does not match.
1001 if (shutdown) {
1002 LOG(ERROR) << "The host username does not match.";
1003 ShutdownHost(kUsernameMismatchExitCode);
1005 } else {
1006 HOST_LOG << "Policy does not require host username match.";
1010 bool HostProcess::OnUsernamePolicyUpdate(base::DictionaryValue* policies) {
1011 // Returns false: never restart the host after this policy update.
1012 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1014 if (!policies->GetBoolean(
1015 policy_hack::PolicyWatcher::kHostMatchUsernamePolicyName,
1016 &host_username_match_required_)) {
1017 return false;
1020 ApplyUsernamePolicy();
1021 return false;
1024 bool HostProcess::OnNatPolicyUpdate(base::DictionaryValue* policies) {
1025 // Returns true if the host has to be restarted after this policy update.
1026 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1028 if (!policies->GetBoolean(policy_hack::PolicyWatcher::kNatPolicyName,
1029 &allow_nat_traversal_)) {
1030 return false;
1033 if (allow_nat_traversal_) {
1034 HOST_LOG << "Policy enables NAT traversal.";
1035 } else {
1036 HOST_LOG << "Policy disables NAT traversal.";
1038 return true;
1041 bool HostProcess::OnRelayPolicyUpdate(base::DictionaryValue* policies) {
1042 // Returns true if the host has to be restarted after this policy update.
1043 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1045 if (!policies->GetBoolean(policy_hack::PolicyWatcher::kRelayPolicyName,
1046 &allow_relay_)) {
1047 return false;
1050 if (allow_relay_) {
1051 HOST_LOG << "Policy enables use of relay server.";
1052 } else {
1053 HOST_LOG << "Policy disables use of relay server.";
1055 return true;
1058 bool HostProcess::OnUdpPortPolicyUpdate(base::DictionaryValue* policies) {
1059 // Returns true if the host has to be restarted after this policy update.
1060 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1062 std::string udp_port_range;
1063 if (!policies->GetString(policy_hack::PolicyWatcher::kUdpPortRangePolicyName,
1064 &udp_port_range)) {
1065 return false;
1068 // Use default values if policy setting is empty or invalid.
1069 int min_udp_port = 0;
1070 int max_udp_port = 0;
1071 if (!udp_port_range.empty() &&
1072 !NetworkSettings::ParsePortRange(udp_port_range, &min_udp_port,
1073 &max_udp_port)) {
1074 LOG(WARNING) << "Invalid port range policy: \"" << udp_port_range
1075 << "\". Using default values.";
1078 if (min_udp_port_ != min_udp_port || max_udp_port_ != max_udp_port) {
1079 if (min_udp_port != 0 && max_udp_port != 0) {
1080 HOST_LOG << "Policy restricts UDP port range to [" << min_udp_port
1081 << ", " << max_udp_port << "]";
1082 } else {
1083 HOST_LOG << "Policy does not restrict UDP port range.";
1085 min_udp_port_ = min_udp_port;
1086 max_udp_port_ = max_udp_port;
1087 return true;
1089 return false;
1092 bool HostProcess::OnCurtainPolicyUpdate(base::DictionaryValue* policies) {
1093 // Returns true if the host has to be restarted after this policy update.
1094 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1096 if (!policies->GetBoolean(
1097 policy_hack::PolicyWatcher::kHostRequireCurtainPolicyName,
1098 &curtain_required_)) {
1099 return false;
1102 #if defined(OS_MACOSX)
1103 if (curtain_required_) {
1104 // When curtain mode is in effect on Mac, the host process runs in the
1105 // user's switched-out session, but launchd will also run an instance at
1106 // the console login screen. Even if no user is currently logged-on, we
1107 // can't support remote-access to the login screen because the current host
1108 // process model disconnects the client during login, which would leave
1109 // the logged in session un-curtained on the console until they reconnect.
1111 // TODO(jamiewalch): Fix this once we have implemented the multi-process
1112 // daemon architecture (crbug.com/134894)
1113 if (getuid() == 0) {
1114 LOG(ERROR) << "Running the host in the console login session is yet not "
1115 "supported.";
1116 ShutdownHost(kLoginScreenNotSupportedExitCode);
1117 return false;
1120 #endif
1122 if (curtain_required_) {
1123 HOST_LOG << "Policy requires curtain-mode.";
1124 } else {
1125 HOST_LOG << "Policy does not require curtain-mode.";
1128 if (host_)
1129 host_->SetEnableCurtaining(curtain_required_);
1130 return false;
1133 bool HostProcess::OnHostTalkGadgetPrefixPolicyUpdate(
1134 base::DictionaryValue* policies) {
1135 // Returns true if the host has to be restarted after this policy update.
1136 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1138 if (!policies->GetString(
1139 policy_hack::PolicyWatcher::kHostTalkGadgetPrefixPolicyName,
1140 &talkgadget_prefix_)) {
1141 return false;
1144 HOST_LOG << "Policy sets talkgadget prefix: " << talkgadget_prefix_;
1145 return true;
1148 bool HostProcess::OnHostTokenUrlPolicyUpdate(base::DictionaryValue* policies) {
1149 // Returns true if the host has to be restarted after this policy update.
1150 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1152 bool token_policy_changed = false;
1153 std::string token_url_string;
1154 if (policies->GetString(
1155 policy_hack::PolicyWatcher::kHostTokenUrlPolicyName,
1156 &token_url_string)) {
1157 token_policy_changed = true;
1158 third_party_auth_config_.token_url = GURL(token_url_string);
1160 std::string token_validation_url_string;
1161 if (policies->GetString(
1162 policy_hack::PolicyWatcher::kHostTokenValidationUrlPolicyName,
1163 &token_validation_url_string)) {
1164 token_policy_changed = true;
1165 third_party_auth_config_.token_validation_url =
1166 GURL(token_validation_url_string);
1168 if (policies->GetString(
1169 policy_hack::PolicyWatcher::kHostTokenValidationCertIssuerPolicyName,
1170 &third_party_auth_config_.token_validation_cert_issuer)) {
1171 token_policy_changed = true;
1174 if (token_policy_changed) {
1175 HOST_LOG << "Policy sets third-party token URLs: "
1176 << "TokenUrl: "
1177 << third_party_auth_config_.token_url << ", "
1178 << "TokenValidationUrl: "
1179 << third_party_auth_config_.token_validation_url << ", "
1180 << "TokenValidationCertificateIssuer: "
1181 << third_party_auth_config_.token_validation_cert_issuer;
1183 return token_policy_changed;
1186 bool HostProcess::OnPairingPolicyUpdate(base::DictionaryValue* policies) {
1187 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1189 if (!policies->GetBoolean(
1190 policy_hack::PolicyWatcher::kHostAllowClientPairing,
1191 &allow_pairing_)) {
1192 return false;
1195 if (allow_pairing_) {
1196 HOST_LOG << "Policy enables client pairing.";
1197 } else {
1198 HOST_LOG << "Policy disables client pairing.";
1200 return true;
1203 bool HostProcess::OnGnubbyAuthPolicyUpdate(base::DictionaryValue* policies) {
1204 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1206 if (!policies->GetBoolean(
1207 policy_hack::PolicyWatcher::kHostAllowGnubbyAuthPolicyName,
1208 &enable_gnubby_auth_)) {
1209 return false;
1212 if (enable_gnubby_auth_) {
1213 HOST_LOG << "Policy enables gnubby auth.";
1214 } else {
1215 HOST_LOG << "Policy disables gnubby auth.";
1218 if (desktop_environment_factory_)
1219 desktop_environment_factory_->SetEnableGnubbyAuth(enable_gnubby_auth_);
1221 return true;
1224 void HostProcess::StartHost() {
1225 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1226 DCHECK(!host_);
1227 DCHECK(!signal_strategy_.get());
1228 DCHECK(state_ == HOST_INITIALIZING || state_ == HOST_STOPPING_TO_RESTART ||
1229 state_ == HOST_STOPPED) << state_;
1230 state_ = HOST_STARTED;
1232 signal_strategy_.reset(
1233 new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(),
1234 context_->url_request_context_getter(),
1235 xmpp_server_config_));
1237 scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker(
1238 new DnsBlackholeChecker(context_->url_request_context_getter(),
1239 talkgadget_prefix_));
1241 // Create a NetworkChangeNotifier for use by the signaling connector.
1242 network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
1244 signaling_connector_.reset(new SignalingConnector(
1245 signal_strategy_.get(),
1246 dns_blackhole_checker.Pass(),
1247 base::Bind(&HostProcess::OnAuthFailed, this)));
1249 if (!oauth_refresh_token_.empty()) {
1250 scoped_ptr<OAuthTokenGetter::OAuthCredentials> oauth_credentials;
1251 oauth_credentials.reset(
1252 new OAuthTokenGetter::OAuthCredentials(
1253 xmpp_server_config_.username, oauth_refresh_token_,
1254 use_service_account_));
1256 oauth_token_getter_.reset(new OAuthTokenGetter(
1257 oauth_credentials.Pass(), context_->url_request_context_getter(),
1258 false));
1260 signaling_connector_->EnableOAuth(oauth_token_getter_.get());
1263 uint32 network_flags = 0;
1264 if (allow_nat_traversal_) {
1265 network_flags = NetworkSettings::NAT_TRAVERSAL_STUN |
1266 NetworkSettings::NAT_TRAVERSAL_OUTGOING;
1267 if (allow_relay_)
1268 network_flags |= NetworkSettings::NAT_TRAVERSAL_RELAY;
1271 NetworkSettings network_settings(network_flags);
1273 if (min_udp_port_ && max_udp_port_) {
1274 network_settings.min_port = min_udp_port_;
1275 network_settings.max_port = max_udp_port_;
1276 } else if (!allow_nat_traversal_) {
1277 // For legacy reasons we have to restrict the port range to a set of default
1278 // values when nat traversal is disabled, even if the port range was not
1279 // set in policy.
1280 network_settings.min_port = NetworkSettings::kDefaultMinPort;
1281 network_settings.max_port = NetworkSettings::kDefaultMaxPort;
1284 host_.reset(new ChromotingHost(
1285 signal_strategy_.get(),
1286 desktop_environment_factory_.get(),
1287 CreateHostSessionManager(signal_strategy_.get(), network_settings,
1288 context_->url_request_context_getter()),
1289 context_->audio_task_runner(),
1290 context_->input_task_runner(),
1291 context_->video_capture_task_runner(),
1292 context_->video_encode_task_runner(),
1293 context_->network_task_runner(),
1294 context_->ui_task_runner()));
1296 if (enable_vp9_) {
1297 scoped_ptr<protocol::CandidateSessionConfig> config =
1298 host_->protocol_config()->Clone();
1299 config->EnableVideoCodec(protocol::ChannelConfig::CODEC_VP9);
1300 host_->set_protocol_config(config.Pass());
1303 if (frame_recorder_buffer_size_ > 0) {
1304 scoped_ptr<VideoFrameRecorderHostExtension> frame_recorder_extension(
1305 new VideoFrameRecorderHostExtension());
1306 frame_recorder_extension->SetMaxContentBytes(frame_recorder_buffer_size_);
1307 host_->AddExtension(frame_recorder_extension.Pass());
1310 // TODO(simonmorris): Get the maximum session duration from a policy.
1311 #if defined(OS_LINUX)
1312 host_->SetMaximumSessionDuration(base::TimeDelta::FromHours(20));
1313 #endif
1315 heartbeat_sender_.reset(new HeartbeatSender(
1316 this, host_id_, signal_strategy_.get(), key_pair_,
1317 directory_bot_jid_));
1319 host_status_sender_.reset(new HostStatusSender(
1320 host_id_, signal_strategy_.get(), key_pair_, directory_bot_jid_));
1322 host_change_notification_listener_.reset(new HostChangeNotificationListener(
1323 this, host_id_, signal_strategy_.get(), directory_bot_jid_));
1325 host_status_logger_.reset(
1326 new HostStatusLogger(host_->AsWeakPtr(), ServerLogEntry::ME2ME,
1327 signal_strategy_.get(), directory_bot_jid_));
1329 // Set up reporting the host status notifications.
1330 #if defined(REMOTING_MULTI_PROCESS)
1331 host_event_logger_.reset(
1332 new IpcHostEventLogger(host_->AsWeakPtr(), daemon_channel_.get()));
1333 #else // !defined(REMOTING_MULTI_PROCESS)
1334 host_event_logger_ =
1335 HostEventLogger::Create(host_->AsWeakPtr(), kApplicationName);
1336 #endif // !defined(REMOTING_MULTI_PROCESS)
1338 host_->SetEnableCurtaining(curtain_required_);
1339 host_->Start(host_owner_email_);
1341 CreateAuthenticatorFactory();
1344 void HostProcess::OnAuthFailed() {
1345 ShutdownHost(kInvalidOauthCredentialsExitCode);
1348 void HostProcess::RestartHost() {
1349 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1350 DCHECK_EQ(state_, HOST_STARTED);
1352 state_ = HOST_STOPPING_TO_RESTART;
1353 ShutdownOnNetworkThread();
1356 void HostProcess::ShutdownHost(HostExitCodes exit_code) {
1357 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1359 *exit_code_out_ = exit_code;
1361 switch (state_) {
1362 case HOST_INITIALIZING:
1363 state_ = HOST_STOPPING;
1364 ShutdownOnNetworkThread();
1365 break;
1367 case HOST_STARTED:
1368 state_ = HOST_STOPPING;
1369 host_status_sender_->SendOfflineStatus(exit_code);
1370 ScheduleHostShutdown();
1371 break;
1373 case HOST_STOPPING_TO_RESTART:
1374 state_ = HOST_STOPPING;
1375 break;
1377 case HOST_STOPPING:
1378 case HOST_STOPPED:
1379 // Host is already stopped or being stopped. No action is required.
1380 break;
1384 // TODO(weitaosu): shut down the host once we get an ACK for the offline status
1385 // XMPP message.
1386 void HostProcess::ScheduleHostShutdown() {
1387 // Delay the shutdown by 2 second to allow SendOfflineStatus to complete.
1388 context_->network_task_runner()->PostDelayedTask(
1389 FROM_HERE,
1390 base::Bind(&HostProcess::ShutdownOnNetworkThread, base::Unretained(this)),
1391 base::TimeDelta::FromSeconds(2));
1394 void HostProcess::ShutdownOnNetworkThread() {
1395 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1397 host_.reset();
1398 host_event_logger_.reset();
1399 host_status_logger_.reset();
1400 heartbeat_sender_.reset();
1401 host_status_sender_.reset();
1402 host_change_notification_listener_.reset();
1403 signaling_connector_.reset();
1404 oauth_token_getter_.reset();
1405 signal_strategy_.reset();
1406 network_change_notifier_.reset();
1408 if (state_ == HOST_STOPPING_TO_RESTART) {
1409 StartHost();
1410 } else if (state_ == HOST_STOPPING) {
1411 state_ = HOST_STOPPED;
1413 if (policy_watcher_.get()) {
1414 base::WaitableEvent done_event(true, false);
1415 policy_watcher_->StopWatching(&done_event);
1416 done_event.Wait();
1417 policy_watcher_.reset();
1420 config_watcher_.reset();
1422 // Complete the rest of shutdown on the main thread.
1423 context_->ui_task_runner()->PostTask(
1424 FROM_HERE,
1425 base::Bind(&HostProcess::ShutdownOnUiThread, this));
1426 } else {
1427 // This method is only called in STOPPING_TO_RESTART and STOPPING states.
1428 NOTREACHED();
1432 void HostProcess::OnCrash(const std::string& function_name,
1433 const std::string& file_name,
1434 const int& line_number) {
1435 char message[1024];
1436 base::snprintf(message, sizeof(message),
1437 "Requested by %s at %s, line %d.",
1438 function_name.c_str(), file_name.c_str(), line_number);
1439 base::debug::Alias(message);
1441 // The daemon requested us to crash the process.
1442 CHECK(false) << message;
1445 int HostProcessMain() {
1446 #if defined(OS_LINUX)
1447 // Required in order for us to run multiple X11 threads.
1448 XInitThreads();
1450 // Required for any calls into GTK functions, such as the Disconnect and
1451 // Continue windows, though these should not be used for the Me2Me case
1452 // (crbug.com/104377).
1453 gtk_init(NULL, NULL);
1454 #endif
1456 // Enable support for SSL server sockets, which must be done while still
1457 // single-threaded.
1458 net::EnableSSLServerSockets();
1460 // Ensures runtime specific CPU features are initialized.
1461 media::InitializeCPUSpecificMediaFeatures();
1463 // Create the main message loop and start helper threads.
1464 base::MessageLoopForUI message_loop;
1465 scoped_ptr<ChromotingHostContext> context =
1466 ChromotingHostContext::Create(new AutoThreadTaskRunner(
1467 message_loop.message_loop_proxy(), base::MessageLoop::QuitClosure()));
1468 if (!context)
1469 return kInitializationFailed;
1471 // Create & start the HostProcess using these threads.
1472 // TODO(wez): The HostProcess holds a reference to itself until Shutdown().
1473 // Remove this hack as part of the multi-process refactoring.
1474 int exit_code = kSuccessExitCode;
1475 new HostProcess(context.Pass(), &exit_code);
1477 // Run the main (also UI) message loop until the host no longer needs it.
1478 message_loop.Run();
1480 return exit_code;
1483 } // namespace remoting