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