1// Copyright 2013 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#include "remoting/host/it2me/it2me_native_messaging_host_main.h"
6
7#include "base/at_exit.h"
8#include "base/command_line.h"
9#include "base/i18n/icu_util.h"
10#include "base/message_loop/message_loop.h"
11#include "base/run_loop.h"
12#include "media/base/media.h"
13#include "net/socket/ssl_server_socket.h"
14#include "remoting/base/breakpad.h"
15#include "remoting/base/resources.h"
16#include "remoting/host/host_exit_codes.h"
17#include "remoting/host/it2me/it2me_native_messaging_host.h"
18#include "remoting/host/logging.h"
19#include "remoting/host/native_messaging/pipe_messaging_channel.h"
20#include "remoting/host/usage_stats_consent.h"
21
22#if defined(OS_LINUX)
23#include <gtk/gtk.h>
24#include <X11/Xlib.h>
25#endif  // defined(OS_LINUX)
26
27#if defined(OS_MACOSX)
28#include "base/mac/scoped_nsautorelease_pool.h"
29#endif  // defined(OS_MACOSX)
30
31#if defined(OS_WIN)
32#include <commctrl.h>
33#endif  // defined(OS_WIN)
34
35namespace remoting {
36
37// Creates a It2MeNativeMessagingHost instance, attaches it to stdin/stdout and
38// runs the message loop until It2MeNativeMessagingHost signals shutdown.
39int StartIt2MeNativeMessagingHost() {
40#if defined(OS_MACOSX)
41  // Needed so we don't leak objects when threads are created.
42  base::mac::ScopedNSAutoreleasePool pool;
43#endif  // defined(OS_MACOSX)
44
45#if defined(REMOTING_ENABLE_BREAKPAD)
46  // Initialize Breakpad as early as possible. On Mac the command-line needs to
47  // be initialized first, so that the preference for crash-reporting can be
48  // looked up in the config file.
49  if (IsUsageStatsAllowed()) {
50    InitializeCrashReporting();
51  }
52#endif  // defined(REMOTING_ENABLE_BREAKPAD)
53
54#if defined(OS_WIN)
55  // Register and initialize common controls.
56  INITCOMMONCONTROLSEX info;
57  info.dwSize = sizeof(info);
58  info.dwICC = ICC_STANDARD_CLASSES;
59  InitCommonControlsEx(&info);
60#endif  // defined(OS_WIN)
61
62  // Required to find the ICU data file, used by some file_util routines.
63  base::i18n::InitializeICU();
64
65  remoting::LoadResources("");
66
67  // Cannot use TOOLKIT_GTK because it is not defined when aura is enabled.
68#if defined(OS_LINUX)
69  // Required in order for us to run multiple X11 threads.
70  XInitThreads();
71
72  // Required for any calls into GTK functions, such as the Disconnect and
73  // Continue windows. Calling with NULL arguments because we don't have
74  // any command line arguments for gtk to consume.
75  gtk_init(NULL, NULL);
76#endif  // OS_LINUX
77
78  // Enable support for SSL server sockets, which must be done while still
79  // single-threaded.
80  net::EnableSSLServerSockets();
81
82  // Ensures runtime specific CPU features are initialized.
83  media::InitializeCPUSpecificMediaFeatures();
84
85#if defined(OS_WIN)
86  // GetStdHandle() returns pseudo-handles for stdin and stdout even if
87  // the hosting executable specifies "Windows" subsystem. However the returned
88  // handles are invalid in that case unless standard input and output are
89  // redirected to a pipe or file.
90  base::File read_file(GetStdHandle(STD_INPUT_HANDLE));
91  base::File write_file(GetStdHandle(STD_OUTPUT_HANDLE));
92
93  // After the native messaging channel starts the native messaging reader
94  // will keep doing blocking read operations on the input named pipe.
95  // If any other thread tries to perform any operation on STDIN, it will also
96  // block because the input named pipe is synchronous (non-overlapped).
97  // It is pretty common for a DLL to query the device info (GetFileType) of
98  // the STD* handles at startup. So any LoadLibrary request can potentially
99  // be blocked. To prevent that from happening we close STDIN and STDOUT
100  // handles as soon as we retrieve the corresponding file handles.
101  SetStdHandle(STD_INPUT_HANDLE, NULL);
102  SetStdHandle(STD_OUTPUT_HANDLE, NULL);
103#elif defined(OS_POSIX)
104  // The files are automatically closed.
105  base::File read_file(STDIN_FILENO);
106  base::File write_file(STDOUT_FILENO);
107#else
108#error Not implemented.
109#endif
110
111  base::MessageLoopForUI message_loop;
112  base::RunLoop run_loop;
113
114  scoped_refptr<AutoThreadTaskRunner> task_runner =
115      new remoting::AutoThreadTaskRunner(message_loop.message_loop_proxy(),
116                                         run_loop.QuitClosure());
117
118  scoped_ptr<It2MeHostFactory> factory(new It2MeHostFactory());
119
120  // Set up the native messaging channel.
121  scoped_ptr<extensions::NativeMessagingChannel> channel(
122      new PipeMessagingChannel(read_file.Pass(), write_file.Pass()));
123
124  scoped_ptr<It2MeNativeMessagingHost> host(new It2MeNativeMessagingHost(
125      task_runner, channel.Pass(), factory.Pass()));
126  host->Start(run_loop.QuitClosure());
127
128  // Run the loop until channel is alive.
129  run_loop.Run();
130
131  return kSuccessExitCode;
132}
133
134int It2MeNativeMessagingHostMain(int argc, char** argv) {
135  // This object instance is required by Chrome code (such as MessageLoop).
136  base::AtExitManager exit_manager;
137
138  base::CommandLine::Init(argc, argv);
139  remoting::InitHostLogging();
140
141  return StartIt2MeNativeMessagingHost();
142}
143
144}  // namespace remoting
145