OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 // | 4 // |
5 // This file implements the Windows service controlling Me2Me host processes | 5 // This file implements the Windows service controlling Me2Me host processes |
6 // running within user sessions. | 6 // running within user sessions. |
7 | 7 |
8 #include "remoting/host/host_service_win.h" | 8 #include "remoting/host/host_service_win.h" |
9 | 9 |
10 #include <windows.h> | 10 #include <windows.h> |
11 #include <wtsapi32.h> | 11 #include <wtsapi32.h> |
12 #include <stdio.h> | 12 #include <stdio.h> |
13 | 13 |
14 #include "base/at_exit.h" | 14 #include "base/at_exit.h" |
15 #include "base/base_paths.h" | 15 #include "base/base_paths.h" |
16 #include "base/bind.h" | 16 #include "base/bind.h" |
17 #include "base/command_line.h" | 17 #include "base/command_line.h" |
18 #include "base/file_path.h" | 18 #include "base/file_util.h" |
19 #include "base/logging.h" | 19 #include "base/logging.h" |
20 #include "base/message_loop.h" | 20 #include "base/message_loop.h" |
21 #include "base/path_service.h" | 21 #include "base/path_service.h" |
22 #include "base/stringprintf.h" | 22 #include "base/stringprintf.h" |
23 #include "base/utf_string_conversions.h" | 23 #include "base/utf_string_conversions.h" |
24 #include "base/win/wrapped_window_proc.h" | 24 #include "base/win/wrapped_window_proc.h" |
25 | 25 |
26 #include "remoting/host/host_service_resource.h" | 26 #include "remoting/host/host_service_resource.h" |
27 #include "remoting/base/scoped_sc_handle_win.h" | 27 #include "remoting/base/scoped_sc_handle_win.h" |
28 #include "remoting/host/wts_console_observer_win.h" | 28 #include "remoting/host/wts_console_observer_win.h" |
29 #include "remoting/host/wts_session_process_launcher_win.h" | 29 #include "remoting/host/wts_session_process_launcher_win.h" |
30 | 30 |
31 using base::StringPrintf; | 31 using base::StringPrintf; |
32 | 32 |
33 namespace { | 33 namespace { |
34 | 34 |
35 // Service name. | 35 // Service name. |
36 const char kServiceName[] = "chromoting"; | 36 const char kServiceName[] = "chromoting"; |
37 // TODO(alexeypa): investigate and migrate this over to Chrome's i18n framework. | 37 // TODO(alexeypa): investigate and migrate this over to Chrome's i18n framework. |
38 const char kMuiStringFormat[] = "@%ls,-%d"; | 38 const char kMuiStringFormat[] = "@%ls,-%d"; |
39 const char kServiceDependencies[] = ""; | 39 const char kServiceDependencies[] = ""; |
40 | 40 |
41 const char kServiceCommandLineFormat[] = "\"%ls\" --host-binary=\"%ls\""; | |
42 | |
41 const DWORD kServiceStopTimeoutMs = 30 * 1000; | 43 const DWORD kServiceStopTimeoutMs = 30 * 1000; |
42 | 44 |
43 // Session id that does not represent any session. | 45 // Session id that does not represent any session. |
44 const uint32 kInvalidSession = 0xffffffff; | 46 const uint32 kInvalidSession = 0xffffffff; |
45 | 47 |
46 // A window class for the session change notifications window. | 48 // A window class for the session change notifications window. |
47 static const char kSessionNotificationWindowClass[] = | 49 static const char kSessionNotificationWindowClass[] = |
48 "Chromoting_SessionNotificationWindow"; | 50 "Chromoting_SessionNotificationWindow"; |
49 | 51 |
50 // Command line actions and switches: | 52 // Command line actions and switches: |
51 // "run" sumply runs the service as usual. | 53 // "run" sumply runs the service as usual. |
52 const char kRunActionName[] = "run"; | 54 const char kRunActionName[] = "run"; |
53 | 55 |
54 // "install" requests the service to be installed. | 56 // "install" requests the service to be installed. |
55 const char kInstallActionName[] = "install"; | 57 const char kInstallActionName[] = "install"; |
56 | 58 |
57 // "remove" uninstalls the service. | 59 // "remove" uninstalls the service. |
58 const char kRemoveActionName[] = "remove"; | 60 const char kRemoveActionName[] = "remove"; |
59 | 61 |
60 // "--console" runs the service interactively for debugging purposes. | 62 // "--console" runs the service interactively for debugging purposes. |
61 const char kConsoleSwitchName[] = "console"; | 63 const char kConsoleSwitchName[] = "console"; |
62 | 64 |
65 // "--host-binary" specifies the host bonary to run in console session. | |
Wez
2012/02/28 00:22:07
typo: binary
alexeypa (please no reviews)
2012/02/28 01:14:04
Done.
| |
66 const char kHostBinarySwitchName[] = "host-binary"; | |
67 | |
63 // "--help" or "--?" prints the usage message. | 68 // "--help" or "--?" prints the usage message. |
64 const char kHelpSwitchName[] = "help"; | 69 const char kHelpSwitchName[] = "help"; |
65 const char kQuestionSwitchName[] = "?"; | 70 const char kQuestionSwitchName[] = "?"; |
66 | 71 |
67 const char kUsageMessage[] = | 72 const char kUsageMessage[] = |
68 "\n" | 73 "\n" |
69 "Usage: %s [action] [options]\n" | 74 "Usage: %s [action] [options]\n" |
70 "\n" | 75 "\n" |
71 "Actions:\n" | 76 "Actions:\n" |
72 " run - Run the service. If no action specified 'run' is assumed.\n" | 77 " run - Run the service (default if no action was specified).\n" |
73 " install - Install the service.\n" | 78 " install - Install the service.\n" |
74 " remove - Uninstall the service.\n" | 79 " remove - Uninstall the service.\n" |
75 "\n" | 80 "\n" |
76 "Options:\n" | 81 "Options:\n" |
77 " --console - Run the service interactively for debugging purposes.\n" | 82 " --console - Run the service interactively for debugging purposes.\n" |
78 " --help, --? - Print this message.\n"; | 83 " --host-binary - Specifies the host binary to run in the console session.\n" |
84 " --help, --? - Print this message.\n"; | |
79 | 85 |
80 // Exit codes: | 86 // Exit codes: |
81 const int kSuccessExitCode = 0; | 87 const int kSuccessExitCode = 0; |
82 const int kUsageExitCode = 1; | 88 const int kUsageExitCode = 1; |
83 const int kErrorExitCode = 2; | 89 const int kErrorExitCode = 2; |
84 | 90 |
85 void usage(const char* program_name) { | 91 void usage(const char* program_name) { |
86 fprintf(stderr, kUsageMessage, program_name); | 92 fprintf(stderr, kUsageMessage, program_name); |
87 } | 93 } |
88 | 94 |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
156 } | 162 } |
157 | 163 |
158 HostService* HostService::GetInstance() { | 164 HostService* HostService::GetInstance() { |
159 return Singleton<HostService>::get(); | 165 return Singleton<HostService>::get(); |
160 } | 166 } |
161 | 167 |
162 bool HostService::InitWithCommandLine(const CommandLine* command_line) { | 168 bool HostService::InitWithCommandLine(const CommandLine* command_line) { |
163 CommandLine::StringVector args = command_line->GetArgs(); | 169 CommandLine::StringVector args = command_line->GetArgs(); |
164 | 170 |
165 // Choose the action to perform. | 171 // Choose the action to perform. |
172 bool host_binary_required = true; | |
166 if (!args.empty()) { | 173 if (!args.empty()) { |
167 if (args.size() > 1) { | 174 if (args.size() > 1) { |
168 LOG(ERROR) << "Invalid command line: more than one action requested."; | 175 LOG(ERROR) << "Invalid command line: more than one action requested."; |
169 return false; | 176 return false; |
170 } | 177 } |
171 if (args[0] == ASCIIToUTF16(kInstallActionName)) { | 178 if (args[0] == ASCIIToUTF16(kInstallActionName)) { |
172 run_routine_ = &HostService::Install; | 179 run_routine_ = &HostService::Install; |
173 } else if (args[0] == ASCIIToUTF16(kRemoveActionName)) { | 180 } else if (args[0] == ASCIIToUTF16(kRemoveActionName)) { |
174 run_routine_ = &HostService::Remove; | 181 run_routine_ = &HostService::Remove; |
182 host_binary_required = false; | |
175 } else if (args[0] != ASCIIToUTF16(kRunActionName)) { | 183 } else if (args[0] != ASCIIToUTF16(kRunActionName)) { |
176 LOG(ERROR) << "Invalid command line: invalid action specified: " | 184 LOG(ERROR) << "Invalid command line: invalid action specified: " |
177 << args[0]; | 185 << args[0]; |
178 return false; | 186 return false; |
179 } | 187 } |
180 } | 188 } |
181 | 189 |
190 if (command_line->HasSwitch(kHostBinarySwitchName)) { | |
191 host_binary_ = command_line->GetSwitchValuePath(kHostBinarySwitchName); | |
192 } else if (host_binary_required) { | |
Wez
2012/02/28 00:22:07
nit: I think this would be clearer as:
if (host_b
alexeypa (please no reviews)
2012/02/28 01:14:04
Done.
| |
193 LOG(ERROR) << "Invalid command line: --" << kHostBinarySwitchName | |
194 << " is required."; | |
Wez
2012/02/28 00:22:07
nit: Indentation.
alexeypa (please no reviews)
2012/02/28 01:14:04
This is how C++ style guide recommends to indent '
Wez
2012/02/28 22:55:36
Yes, but LOG() is mis-indented.
alexeypa (please no reviews)
2012/02/29 04:17:56
Oh, I see. My autopilot fixed it, apparently. :-)
| |
195 return false; | |
196 } | |
197 | |
182 // Run interactively if needed. | 198 // Run interactively if needed. |
183 if (run_routine_ == &HostService::RunAsService && | 199 if (run_routine_ == &HostService::RunAsService && |
184 command_line->HasSwitch(kConsoleSwitchName)) { | 200 command_line->HasSwitch(kConsoleSwitchName)) { |
185 run_routine_ = &HostService::RunInConsole; | 201 run_routine_ = &HostService::RunInConsole; |
186 } | 202 } |
187 | 203 |
188 return true; | 204 return true; |
189 } | 205 } |
190 | 206 |
191 int HostService::Install() { | 207 int HostService::Install() { |
192 ScopedScHandle scmanager( | 208 ScopedScHandle scmanager( |
193 OpenSCManagerW(NULL, NULL, | 209 OpenSCManagerW(NULL, NULL, |
194 SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE)); | 210 SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE)); |
195 if (!scmanager.IsValid()) { | 211 if (!scmanager.IsValid()) { |
196 LOG_GETLASTERROR(ERROR) | 212 LOG_GETLASTERROR(ERROR) |
197 << "Failed to connect to the service control manager"; | 213 << "Failed to connect to the service control manager"; |
198 return kErrorExitCode; | 214 return kErrorExitCode; |
199 } | 215 } |
200 | 216 |
201 FilePath exe; | 217 FilePath exe; |
202 if (!PathService::Get(base::FILE_EXE, &exe)) { | 218 if (!PathService::Get(base::FILE_EXE, &exe)) { |
203 LOG(ERROR) << "Unable to retrieve the service binary path."; | 219 LOG(ERROR) << "Unable to retrieve the service binary path."; |
204 return kErrorExitCode; | 220 return kErrorExitCode; |
205 } | 221 } |
206 | 222 |
207 string16 name = StringPrintf(ASCIIToUTF16(kMuiStringFormat).c_str(), | 223 string16 name = StringPrintf(ASCIIToUTF16(kMuiStringFormat).c_str(), |
208 exe.value().c_str(), | 224 exe.value().c_str(), |
209 IDS_DISPLAY_SERVICE_NAME); | 225 IDS_DISPLAY_SERVICE_NAME); |
226 | |
227 if (!file_util::AbsolutePath(&host_binary_) || | |
228 !file_util::PathExists(host_binary_)) { | |
229 LOG(ERROR) << "Invalid host binary name: " << host_binary_.value(); | |
230 return kErrorExitCode; | |
231 } | |
232 | |
233 string16 command_line = StringPrintf( | |
234 ASCIIToUTF16(kServiceCommandLineFormat).c_str(), | |
235 exe.value().c_str(), | |
236 host_binary_.value().c_str()); | |
210 ScopedScHandle service( | 237 ScopedScHandle service( |
211 CreateServiceW(scmanager, | 238 CreateServiceW(scmanager, |
212 service_name_.c_str(), | 239 service_name_.c_str(), |
213 name.c_str(), | 240 name.c_str(), |
214 SERVICE_QUERY_STATUS | SERVICE_CHANGE_CONFIG, | 241 SERVICE_QUERY_STATUS | SERVICE_CHANGE_CONFIG, |
215 SERVICE_WIN32_OWN_PROCESS, | 242 SERVICE_WIN32_OWN_PROCESS, |
216 SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, | 243 SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, |
217 exe.value().c_str(), | 244 command_line.c_str(), |
218 NULL, | 245 NULL, |
219 NULL, | 246 NULL, |
220 ASCIIToUTF16(kServiceDependencies).c_str(), | 247 ASCIIToUTF16(kServiceDependencies).c_str(), |
221 NULL, | 248 NULL, |
222 NULL)); | 249 NULL)); |
223 | 250 |
224 if (service.IsValid()) { | 251 if (service.IsValid()) { |
225 // Set the service description if the service is freshly installed. | 252 // Set the service description if the service is freshly installed. |
226 string16 description = StringPrintf( | 253 string16 description = StringPrintf( |
227 ASCIIToUTF16(kMuiStringFormat).c_str(), | 254 ASCIIToUTF16(kMuiStringFormat).c_str(), |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
315 | 342 |
316 printf("The service has been removed successfully.\n"); | 343 printf("The service has been removed successfully.\n"); |
317 return kSuccessExitCode; | 344 return kSuccessExitCode; |
318 } | 345 } |
319 | 346 |
320 int HostService::Run() { | 347 int HostService::Run() { |
321 return (this->*run_routine_)(); | 348 return (this->*run_routine_)(); |
322 } | 349 } |
323 | 350 |
324 void HostService::RunMessageLoop() { | 351 void HostService::RunMessageLoop() { |
325 WtsSessionProcessLauncher launcher(this); | 352 WtsSessionProcessLauncher launcher(this, host_binary_); |
326 | 353 |
327 // Run the service. | 354 // Run the service. |
328 message_loop_->Run(); | 355 message_loop_->Run(); |
329 | 356 |
330 // Clean up the observers by emulating detaching from the console. | 357 // Clean up the observers by emulating detaching from the console. |
331 shutting_down_ = true; | 358 shutting_down_ = true; |
332 OnSessionChange(); | 359 OnSessionChange(); |
333 | 360 |
334 // Release the control handler. | 361 // Release the control handler. |
335 stopped_event_.Signal(); | 362 stopped_event_.Signal(); |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
538 } | 565 } |
539 | 566 |
540 remoting::HostService* service = remoting::HostService::GetInstance(); | 567 remoting::HostService* service = remoting::HostService::GetInstance(); |
541 if (!service->InitWithCommandLine(command_line)) { | 568 if (!service->InitWithCommandLine(command_line)) { |
542 usage(argv[0]); | 569 usage(argv[0]); |
543 return kUsageExitCode; | 570 return kUsageExitCode; |
544 } | 571 } |
545 | 572 |
546 return service->Run(); | 573 return service->Run(); |
547 } | 574 } |
OLD | NEW |