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