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.
5 // This file implements the common entry point shared by all Chromoting Host
8 #include "remoting/host/host_main.h"
12 #include "base/at_exit.h"
13 #include "base/command_line.h"
14 #include "base/files/file_path.h"
15 #include "base/i18n/icu_util.h"
16 #include "base/logging.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/stringize_macros.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "remoting/base/breakpad.h"
22 #include "remoting/base/resources.h"
23 #include "remoting/host/host_exit_codes.h"
24 #include "remoting/host/logging.h"
25 #include "remoting/host/setup/me2me_native_messaging_host.h"
26 #include "remoting/host/usage_stats_consent.h"
28 #if defined(OS_MACOSX)
29 #include "base/mac/scoped_nsautorelease_pool.h"
30 #endif // defined(OS_MACOSX)
35 #endif // defined(OS_WIN)
39 // Known entry points.
40 int HostProcessMain();
42 int DaemonProcessMain();
43 int DesktopProcessMain();
44 int ElevatedControllerMain();
45 int RdpDesktopSessionMain();
46 #endif // defined(OS_WIN)
48 const char kElevateSwitchName
[] = "elevate";
49 const char kProcessTypeSwitchName
[] = "type";
51 const char kProcessTypeController
[] = "controller";
52 const char kProcessTypeDaemon
[] = "daemon";
53 const char kProcessTypeDesktop
[] = "desktop";
54 const char kProcessTypeHost
[] = "host";
55 const char kProcessTypeRdpDesktopSession
[] = "rdp_desktop_session";
59 typedef int (*MainRoutineFn
)();
61 // "--help" or "--?" prints the usage message.
62 const char kHelpSwitchName
[] = "help";
63 const char kQuestionSwitchName
[] = "?";
65 // The command line switch used to get version of the daemon.
66 const char kVersionSwitchName
[] = "version";
68 const char kUsageMessage
[] =
69 "Usage: %s [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 " --window-id=<id> - Specifies a window to remote,"
81 " instead of the whole desktop.\n";
83 void Usage(const base::FilePath
& program_name
) {
84 printf(kUsageMessage
, program_name
.MaybeAsASCII().c_str());
89 // Runs the binary specified by the command line, elevated.
91 const base::CommandLine::SwitchMap
& switches
=
92 base::CommandLine::ForCurrentProcess()->GetSwitches();
93 base::CommandLine::StringVector args
=
94 base::CommandLine::ForCurrentProcess()->GetArgs();
96 // Create the child process command line by copying switches from the current
98 base::CommandLine
command_line(base::CommandLine::NO_PROGRAM
);
99 for (base::CommandLine::SwitchMap::const_iterator i
= switches
.begin();
100 i
!= switches
.end(); ++i
) {
101 if (i
->first
!= kElevateSwitchName
)
102 command_line
.AppendSwitchNative(i
->first
, i
->second
);
104 for (base::CommandLine::StringVector::const_iterator i
= args
.begin();
105 i
!= args
.end(); ++i
) {
106 command_line
.AppendArgNative(*i
);
109 // Get the name of the binary to launch.
110 base::FilePath binary
=
111 base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
113 base::CommandLine::StringType parameters
=
114 command_line
.GetCommandLineString();
116 // Launch the child process requesting elevation.
117 SHELLEXECUTEINFO info
;
118 memset(&info
, 0, sizeof(info
));
119 info
.cbSize
= sizeof(info
);
120 info
.lpVerb
= L
"runas";
121 info
.lpFile
= binary
.value().c_str();
122 info
.lpParameters
= parameters
.c_str();
123 info
.nShow
= SW_SHOWNORMAL
;
125 if (!ShellExecuteEx(&info
)) {
126 DWORD exit_code
= GetLastError();
127 PLOG(ERROR
) << "Unable to launch '" << binary
.value() << "'";
131 return kSuccessExitCode
;
134 #endif // !defined(OS_WIN)
136 // Select the entry point corresponding to the process type.
137 MainRoutineFn
SelectMainRoutine(const std::string
& process_type
) {
138 MainRoutineFn main_routine
= NULL
;
140 if (process_type
== kProcessTypeHost
) {
141 main_routine
= &HostProcessMain
;
143 } else if (process_type
== kProcessTypeDaemon
) {
144 main_routine
= &DaemonProcessMain
;
145 } else if (process_type
== kProcessTypeDesktop
) {
146 main_routine
= &DesktopProcessMain
;
147 } else if (process_type
== kProcessTypeController
) {
148 main_routine
= &ElevatedControllerMain
;
149 } else if (process_type
== kProcessTypeRdpDesktopSession
) {
150 main_routine
= &RdpDesktopSessionMain
;
151 #endif // defined(OS_WIN)
159 int HostMain(int argc
, char** argv
) {
160 #if defined(OS_MACOSX)
161 // Needed so we don't leak objects when threads are created.
162 base::mac::ScopedNSAutoreleasePool pool
;
165 base::CommandLine::Init(argc
, argv
);
167 // Initialize Breakpad as early as possible. On Mac the command-line needs to
168 // be initialized first, so that the preference for crash-reporting can be
169 // looked up in the config file.
170 #if defined(REMOTING_ENABLE_BREAKPAD)
171 if (IsUsageStatsAllowed()) {
172 InitializeCrashReporting();
174 #endif // defined(REMOTING_ENABLE_BREAKPAD)
176 // This object instance is required by Chrome code (for example,
177 // LazyInstance, MessageLoop).
178 base::AtExitManager exit_manager
;
180 // Enable debug logs.
183 // Register and initialize common controls.
185 INITCOMMONCONTROLSEX info
;
186 info
.dwSize
= sizeof(info
);
187 info
.dwICC
= ICC_STANDARD_CLASSES
;
188 InitCommonControlsEx(&info
);
189 #endif // defined(OS_WIN)
191 // Parse the command line.
192 const base::CommandLine
* command_line
=
193 base::CommandLine::ForCurrentProcess();
194 if (command_line
->HasSwitch(kHelpSwitchName
) ||
195 command_line
->HasSwitch(kQuestionSwitchName
)) {
196 Usage(command_line
->GetProgram());
197 return kSuccessExitCode
;
200 if (command_line
->HasSwitch(kVersionSwitchName
)) {
201 printf("%s\n", STRINGIZE(VERSION
));
202 return kSuccessExitCode
;
206 if (command_line
->HasSwitch(kElevateSwitchName
)) {
207 return RunElevated();
209 #endif // defined(OS_WIN)
211 // Assume the host process by default.
212 std::string process_type
= kProcessTypeHost
;
213 if (command_line
->HasSwitch(kProcessTypeSwitchName
)) {
214 process_type
= command_line
->GetSwitchValueASCII(kProcessTypeSwitchName
);
217 MainRoutineFn main_routine
= SelectMainRoutine(process_type
);
219 fprintf(stderr
, "Unknown process type '%s' specified.",
220 process_type
.c_str());
221 Usage(command_line
->GetProgram());
222 return kUsageExitCode
;
225 // Required to find the ICU data file, used by some file_util routines.
226 base::i18n::InitializeICU();
228 remoting::LoadResources("");
230 // Invoke the entry point.
231 int exit_code
= main_routine();
232 if (exit_code
== kUsageExitCode
) {
233 Usage(command_line
->GetProgram());
236 remoting::UnloadResources();
241 } // namespace remoting
244 int main(int argc
, char** argv
) {
245 return remoting::HostMain(argc
, argv
);
247 #endif // !defined(OS_WIN)