- add sources.
[platform/framework/web/crosswalk.git] / src / remoting / host / host_main.cc
1 // Copyright (c) 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 // This file implements the common entry point shared by all Chromoting Host
6 // processes.
7
8 #include "remoting/host/host_main.h"
9
10 #include <string>
11
12 #include "base/at_exit.h"
13 #include "base/command_line.h"
14 #include "base/files/file_path.h"
15 #include "base/logging.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringize_macros.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "remoting/base/breakpad.h"
21 #include "remoting/base/resources.h"
22 #include "remoting/host/host_exit_codes.h"
23 #include "remoting/host/logging.h"
24 #include "remoting/host/setup/me2me_native_messaging_host.h"
25 #include "remoting/host/usage_stats_consent.h"
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 #include <shellapi.h>
34 #endif  // defined(OS_WIN)
35
36 namespace remoting {
37
38 // Known entry points.
39 int DaemonProcessMain();
40 int DesktopProcessMain();
41 int ElevatedControllerMain();
42 int HostProcessMain();
43 int RdpDesktopSessionMain();
44
45 const char kElevateSwitchName[] = "elevate";
46 const char kProcessTypeSwitchName[] = "type";
47
48 const char kProcessTypeController[] = "controller";
49 const char kProcessTypeDaemon[] = "daemon";
50 const char kProcessTypeDesktop[] = "desktop";
51 const char kProcessTypeHost[] = "host";
52 const char kProcessTypeNativeMessagingHost[] = "native_messaging_host";
53 const char kProcessTypeRdpDesktopSession[] = "rdp_desktop_session";
54
55 const char kExtensionOriginPrefix[] = "chrome-extension://";
56
57 namespace {
58
59 typedef int (*MainRoutineFn)();
60
61 // "--help" or "--?" prints the usage message.
62 const char kHelpSwitchName[] = "help";
63 const char kQuestionSwitchName[] = "?";
64
65 // The command line switch used to get version of the daemon.
66 const char kVersionSwitchName[] = "version";
67
68 const char kUsageMessage[] =
69   "Usage: %s [options]\n"
70   "\n"
71   "Options:\n"
72   "  --audio-pipe-name=<pipe> - Sets the pipe name to capture audio on Linux.\n"
73   "  --console                - Runs the daemon interactively.\n"
74   "  --daemon-pipe=<pipe>     - Specifies the pipe to connect to the daemon.\n"
75   "  --elevate=<binary>       - Runs <binary> elevated.\n"
76   "  --host-config=<config>   - Specifies the host configuration.\n"
77   "  --help, -?               - Print this message.\n"
78   "  --type                   - Specifies process type.\n"
79   "  --version                - Prints the host version and exits.\n";
80
81 void Usage(const base::FilePath& program_name) {
82   printf(kUsageMessage, program_name.MaybeAsASCII().c_str());
83 }
84
85 #if defined(OS_WIN)
86
87 // Runs the binary specified by the command line, elevated.
88 int RunElevated() {
89   const CommandLine::SwitchMap& switches =
90       CommandLine::ForCurrentProcess()->GetSwitches();
91   CommandLine::StringVector args = CommandLine::ForCurrentProcess()->GetArgs();
92
93   // Create the child process command line by copying switches from the current
94   // command line.
95   CommandLine command_line(CommandLine::NO_PROGRAM);
96   for (CommandLine::SwitchMap::const_iterator i = switches.begin();
97        i != switches.end(); ++i) {
98     if (i->first != kElevateSwitchName)
99       command_line.AppendSwitchNative(i->first, i->second);
100   }
101   for (CommandLine::StringVector::const_iterator i = args.begin();
102        i != args.end(); ++i) {
103     command_line.AppendArgNative(*i);
104   }
105
106   // Get the name of the binary to launch.
107   base::FilePath binary =
108       CommandLine::ForCurrentProcess()->GetSwitchValuePath(kElevateSwitchName);
109   CommandLine::StringType parameters = command_line.GetCommandLineString();
110
111   // Launch the child process requesting elevation.
112   SHELLEXECUTEINFO info;
113   memset(&info, 0, sizeof(info));
114   info.cbSize = sizeof(info);
115   info.lpVerb = L"runas";
116   info.lpFile = binary.value().c_str();
117   info.lpParameters = parameters.c_str();
118   info.nShow = SW_SHOWNORMAL;
119
120   if (!ShellExecuteEx(&info)) {
121     DWORD exit_code = GetLastError();
122     LOG_GETLASTERROR(ERROR) << "Unable to launch '" << binary.value() << "'";
123     return exit_code;
124   }
125
126   return kSuccessExitCode;
127 }
128
129 #else  // !defined(OS_WIN)
130
131 // Fake entry points that exist only on Windows.
132 int DaemonProcessMain() {
133   NOTREACHED();
134   return kInitializationFailed;
135 }
136
137 int DesktopProcessMain() {
138   NOTREACHED();
139   return kInitializationFailed;
140 }
141
142 int ElevatedControllerMain() {
143   NOTREACHED();
144   return kInitializationFailed;
145 }
146
147 int RdpDesktopSessionMain() {
148   NOTREACHED();
149   return kInitializationFailed;
150 }
151
152 #endif  // !defined(OS_WIN)
153
154 // Select the entry point corresponding to the process type.
155 MainRoutineFn SelectMainRoutine(const std::string& process_type) {
156   MainRoutineFn main_routine = NULL;
157
158   if (process_type == kProcessTypeHost) {
159     main_routine = &HostProcessMain;
160 #if defined(OS_WIN)
161   } else if (process_type == kProcessTypeDaemon) {
162     main_routine = &DaemonProcessMain;
163   } else if (process_type == kProcessTypeDesktop) {
164     main_routine = &DesktopProcessMain;
165   } else if (process_type == kProcessTypeController) {
166     main_routine = &ElevatedControllerMain;
167   } else if (process_type == kProcessTypeRdpDesktopSession) {
168     main_routine = &RdpDesktopSessionMain;
169   } else if (process_type == kProcessTypeNativeMessagingHost) {
170     main_routine = &NativeMessagingHostMain;
171 #endif  // defined(OS_WIN)
172   }
173
174   return main_routine;
175 }
176
177 }  // namespace
178
179 int HostMain(int argc, char** argv) {
180 #if defined(OS_MACOSX)
181   // Needed so we don't leak objects when threads are created.
182   base::mac::ScopedNSAutoreleasePool pool;
183 #endif
184
185   CommandLine::Init(argc, argv);
186
187   // Initialize Breakpad as early as possible. On Mac the command-line needs to
188   // be initialized first, so that the preference for crash-reporting can be
189   // looked up in the config file.
190 #if defined(REMOTING_ENABLE_BREAKPAD)
191   if (IsUsageStatsAllowed()) {
192     InitializeCrashReporting();
193   }
194 #endif  // defined(REMOTING_ENABLE_BREAKPAD)
195
196   // This object instance is required by Chrome code (for example,
197   // LazyInstance, MessageLoop).
198   base::AtExitManager exit_manager;
199
200   // Enable debug logs.
201   InitHostLogging();
202
203   // Register and initialize common controls.
204 #if defined(OS_WIN)
205   INITCOMMONCONTROLSEX info;
206   info.dwSize = sizeof(info);
207   info.dwICC = ICC_STANDARD_CLASSES;
208   InitCommonControlsEx(&info);
209 #endif  // defined(OS_WIN)
210
211   // Parse the command line.
212   const CommandLine* command_line = CommandLine::ForCurrentProcess();
213   if (command_line->HasSwitch(kHelpSwitchName) ||
214       command_line->HasSwitch(kQuestionSwitchName)) {
215     Usage(command_line->GetProgram());
216     return kSuccessExitCode;
217   }
218
219   if (command_line->HasSwitch(kVersionSwitchName)) {
220     printf("%s\n", STRINGIZE(VERSION));
221     return kSuccessExitCode;
222   }
223
224 #if defined(OS_WIN)
225   if (command_line->HasSwitch(kElevateSwitchName)) {
226     return RunElevated();
227   }
228 #endif  // defined(OS_WIN)
229
230   // Assume the host process by default.
231   std::string process_type = kProcessTypeHost;
232   if (command_line->HasSwitch(kProcessTypeSwitchName)) {
233     process_type = command_line->GetSwitchValueASCII(kProcessTypeSwitchName);
234   } else {
235     // Assume that it is the native messaging host starting if "--type" is
236     // missing and the first argument looks like an origin that represents
237     // an extension.
238     CommandLine::StringVector args = command_line->GetArgs();
239     if (!args.empty()) {
240 #if defined(OS_WIN)
241       std::string origin = UTF16ToUTF8(args[0]);
242 #else
243       std::string origin = args[0];
244 #endif
245       if (StartsWithASCII(origin, kExtensionOriginPrefix, true)) {
246         process_type = kProcessTypeNativeMessagingHost;
247       }
248     }
249   }
250
251   MainRoutineFn main_routine = SelectMainRoutine(process_type);
252   if (!main_routine) {
253     fprintf(stderr, "Unknown process type '%s' specified.",
254             process_type.c_str());
255     Usage(command_line->GetProgram());
256     return kUsageExitCode;
257   }
258
259   remoting::LoadResources("");
260
261   // Invoke the entry point.
262   int exit_code = main_routine();
263   if (exit_code == kUsageExitCode) {
264     Usage(command_line->GetProgram());
265   }
266
267   remoting::UnloadResources();
268
269   return exit_code;
270 }
271
272 }  // namespace remoting