| 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 binary to run in console session. |
| 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 (host_binary_required) { |
| 191 if (command_line->HasSwitch(kHostBinarySwitchName)) { |
| 192 host_binary_ = command_line->GetSwitchValuePath(kHostBinarySwitchName); |
| 193 } else { |
| 194 LOG(ERROR) << "Invalid command line: --" << kHostBinarySwitchName |
| 195 << " is required."; |
| 196 return false; |
| 197 } |
| 198 } |
| 199 |
| 182 // Run interactively if needed. | 200 // Run interactively if needed. |
| 183 if (run_routine_ == &HostService::RunAsService && | 201 if (run_routine_ == &HostService::RunAsService && |
| 184 command_line->HasSwitch(kConsoleSwitchName)) { | 202 command_line->HasSwitch(kConsoleSwitchName)) { |
| 185 run_routine_ = &HostService::RunInConsole; | 203 run_routine_ = &HostService::RunInConsole; |
| 186 } | 204 } |
| 187 | 205 |
| 188 return true; | 206 return true; |
| 189 } | 207 } |
| 190 | 208 |
| 191 int HostService::Install() { | 209 int HostService::Install() { |
| 192 ScopedScHandle scmanager( | 210 ScopedScHandle scmanager( |
| 193 OpenSCManagerW(NULL, NULL, | 211 OpenSCManagerW(NULL, NULL, |
| 194 SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE)); | 212 SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE)); |
| 195 if (!scmanager.IsValid()) { | 213 if (!scmanager.IsValid()) { |
| 196 LOG_GETLASTERROR(ERROR) | 214 LOG_GETLASTERROR(ERROR) |
| 197 << "Failed to connect to the service control manager"; | 215 << "Failed to connect to the service control manager"; |
| 198 return kErrorExitCode; | 216 return kErrorExitCode; |
| 199 } | 217 } |
| 200 | 218 |
| 201 FilePath exe; | 219 FilePath exe; |
| 202 if (!PathService::Get(base::FILE_EXE, &exe)) { | 220 if (!PathService::Get(base::FILE_EXE, &exe)) { |
| 203 LOG(ERROR) << "Unable to retrieve the service binary path."; | 221 LOG(ERROR) << "Unable to retrieve the service binary path."; |
| 204 return kErrorExitCode; | 222 return kErrorExitCode; |
| 205 } | 223 } |
| 206 | 224 |
| 207 string16 name = StringPrintf(ASCIIToUTF16(kMuiStringFormat).c_str(), | 225 string16 name = StringPrintf(ASCIIToUTF16(kMuiStringFormat).c_str(), |
| 208 exe.value().c_str(), | 226 exe.value().c_str(), |
| 209 IDS_DISPLAY_SERVICE_NAME); | 227 IDS_DISPLAY_SERVICE_NAME); |
| 228 |
| 229 if (!file_util::AbsolutePath(&host_binary_) || |
| 230 !file_util::PathExists(host_binary_)) { |
| 231 LOG(ERROR) << "Invalid host binary name: " << host_binary_.value(); |
| 232 return kErrorExitCode; |
| 233 } |
| 234 |
| 235 string16 command_line = StringPrintf( |
| 236 ASCIIToUTF16(kServiceCommandLineFormat).c_str(), |
| 237 exe.value().c_str(), |
| 238 host_binary_.value().c_str()); |
| 210 ScopedScHandle service( | 239 ScopedScHandle service( |
| 211 CreateServiceW(scmanager, | 240 CreateServiceW(scmanager, |
| 212 service_name_.c_str(), | 241 service_name_.c_str(), |
| 213 name.c_str(), | 242 name.c_str(), |
| 214 SERVICE_QUERY_STATUS | SERVICE_CHANGE_CONFIG, | 243 SERVICE_QUERY_STATUS | SERVICE_CHANGE_CONFIG, |
| 215 SERVICE_WIN32_OWN_PROCESS, | 244 SERVICE_WIN32_OWN_PROCESS, |
| 216 SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, | 245 SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, |
| 217 exe.value().c_str(), | 246 command_line.c_str(), |
| 218 NULL, | 247 NULL, |
| 219 NULL, | 248 NULL, |
| 220 ASCIIToUTF16(kServiceDependencies).c_str(), | 249 ASCIIToUTF16(kServiceDependencies).c_str(), |
| 221 NULL, | 250 NULL, |
| 222 NULL)); | 251 NULL)); |
| 223 | 252 |
| 224 if (service.IsValid()) { | 253 if (service.IsValid()) { |
| 225 // Set the service description if the service is freshly installed. | 254 // Set the service description if the service is freshly installed. |
| 226 string16 description = StringPrintf( | 255 string16 description = StringPrintf( |
| 227 ASCIIToUTF16(kMuiStringFormat).c_str(), | 256 ASCIIToUTF16(kMuiStringFormat).c_str(), |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 | 344 |
| 316 printf("The service has been removed successfully.\n"); | 345 printf("The service has been removed successfully.\n"); |
| 317 return kSuccessExitCode; | 346 return kSuccessExitCode; |
| 318 } | 347 } |
| 319 | 348 |
| 320 int HostService::Run() { | 349 int HostService::Run() { |
| 321 return (this->*run_routine_)(); | 350 return (this->*run_routine_)(); |
| 322 } | 351 } |
| 323 | 352 |
| 324 void HostService::RunMessageLoop() { | 353 void HostService::RunMessageLoop() { |
| 325 WtsSessionProcessLauncher launcher(this); | 354 WtsSessionProcessLauncher launcher(this, host_binary_); |
| 326 | 355 |
| 327 // Run the service. | 356 // Run the service. |
| 328 message_loop_->Run(); | 357 message_loop_->Run(); |
| 329 | 358 |
| 330 // Clean up the observers by emulating detaching from the console. | 359 // Clean up the observers by emulating detaching from the console. |
| 331 shutting_down_ = true; | 360 shutting_down_ = true; |
| 332 OnSessionChange(); | 361 OnSessionChange(); |
| 333 | 362 |
| 334 // Release the control handler. | 363 // Release the control handler. |
| 335 stopped_event_.Signal(); | 364 stopped_event_.Signal(); |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 538 } | 567 } |
| 539 | 568 |
| 540 remoting::HostService* service = remoting::HostService::GetInstance(); | 569 remoting::HostService* service = remoting::HostService::GetInstance(); |
| 541 if (!service->InitWithCommandLine(command_line)) { | 570 if (!service->InitWithCommandLine(command_line)) { |
| 542 usage(argv[0]); | 571 usage(argv[0]); |
| 543 return kUsageExitCode; | 572 return kUsageExitCode; |
| 544 } | 573 } |
| 545 | 574 |
| 546 return service->Run(); | 575 return service->Run(); |
| 547 } | 576 } |
| OLD | NEW |