| 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_util.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/stringize_macros.h" |
| 22 #include "base/stringprintf.h" | 23 #include "base/stringprintf.h" |
| 23 #include "base/threading/thread.h" | 24 #include "base/threading/thread.h" |
| 24 #include "base/utf_string_conversions.h" | |
| 25 #include "base/win/wrapped_window_proc.h" | 25 #include "base/win/wrapped_window_proc.h" |
| 26 | 26 |
| 27 #include "remoting/base/scoped_sc_handle_win.h" | 27 #include "remoting/base/scoped_sc_handle_win.h" |
| 28 #include "remoting/host/branding.h" | 28 #include "remoting/host/branding.h" |
| 29 #include "remoting/host/host_service_resource.h" | 29 #include "remoting/host/host_service_resource.h" |
| 30 #include "remoting/host/wts_console_observer_win.h" | 30 #include "remoting/host/wts_console_observer_win.h" |
| 31 #include "remoting/host/wts_session_process_launcher_win.h" | 31 #include "remoting/host/wts_session_process_launcher_win.h" |
| 32 | 32 |
| 33 using base::StringPrintf; | 33 using base::StringPrintf; |
| 34 | 34 |
| 35 namespace { | 35 namespace { |
| 36 | 36 |
| 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 char16 kMuiStringFormat[] = TO_L_STRING("@%ls,-%d"); |
| 39 const char kServiceDependencies[] = ""; | 39 const char16 kServiceDependencies[] = TO_L_STRING(""); |
| 40 | 40 |
| 41 const char kServiceCommandLineFormat[] = "\"%ls\" --host-binary=\"%ls\""; | 41 const char16 kServiceCommandLineFormat[] = |
| 42 TO_L_STRING("\"%ls\" --host-binary=\"%ls\""); |
| 42 | 43 |
| 43 const DWORD kServiceStopTimeoutMs = 30 * 1000; | 44 const DWORD kServiceStopTimeoutMs = 30 * 1000; |
| 44 | 45 |
| 45 // Session id that does not represent any session. | 46 // Session id that does not represent any session. |
| 46 const uint32 kInvalidSession = 0xffffffff; | 47 const uint32 kInvalidSession = 0xffffffff; |
| 47 | 48 |
| 48 const char kIoThreadName[] = "I/O thread"; | 49 const char kIoThreadName[] = "I/O thread"; |
| 49 | 50 |
| 50 // A window class for the session change notifications window. | 51 // A window class for the session change notifications window. |
| 51 static const char kSessionNotificationWindowClass[] = | 52 const char16 kSessionNotificationWindowClass[] = |
| 52 "Chromoting_SessionNotificationWindow"; | 53 TO_L_STRING("Chromoting_SessionNotificationWindow"); |
| 53 | 54 |
| 54 // Command line actions and switches: | 55 // Command line actions and switches: |
| 55 // "run" sumply runs the service as usual. | 56 // "run" sumply runs the service as usual. |
| 56 const char kRunActionName[] = "run"; | 57 const char16 kRunActionName[] = TO_L_STRING("run"); |
| 57 | 58 |
| 58 // "install" requests the service to be installed. | 59 // "install" requests the service to be installed. |
| 59 const char kInstallActionName[] = "install"; | 60 const char16 kInstallActionName[] = TO_L_STRING("install"); |
| 60 | 61 |
| 61 // "remove" uninstalls the service. | 62 // "remove" uninstalls the service. |
| 62 const char kRemoveActionName[] = "remove"; | 63 const char16 kRemoveActionName[] = TO_L_STRING("remove"); |
| 63 | 64 |
| 64 // "--console" runs the service interactively for debugging purposes. | 65 // "--console" runs the service interactively for debugging purposes. |
| 65 const char kConsoleSwitchName[] = "console"; | 66 const char kConsoleSwitchName[] = "console"; |
| 66 | 67 |
| 67 // "--host-binary" specifies the host binary to run in console session. | 68 // "--host-binary" specifies the host binary to run in console session. |
| 68 const char kHostBinarySwitchName[] = "host-binary"; | 69 const char kHostBinarySwitchName[] = "host-binary"; |
| 69 | 70 |
| 70 // "--help" or "--?" prints the usage message. | 71 // "--help" or "--?" prints the usage message. |
| 71 const char kHelpSwitchName[] = "help"; | 72 const char kHelpSwitchName[] = "help"; |
| 72 const char kQuestionSwitchName[] = "?"; | 73 const char kQuestionSwitchName[] = "?"; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 95 } | 96 } |
| 96 | 97 |
| 97 } // namespace | 98 } // namespace |
| 98 | 99 |
| 99 namespace remoting { | 100 namespace remoting { |
| 100 | 101 |
| 101 HostService::HostService() : | 102 HostService::HostService() : |
| 102 console_session_id_(kInvalidSession), | 103 console_session_id_(kInvalidSession), |
| 103 message_loop_(NULL), | 104 message_loop_(NULL), |
| 104 run_routine_(&HostService::RunAsService), | 105 run_routine_(&HostService::RunAsService), |
| 105 service_name_(UTF8ToUTF16(kWindowsServiceName)), | 106 service_name_(kWindowsServiceName), |
| 106 service_status_handle_(0), | 107 service_status_handle_(0), |
| 107 shutting_down_(false), | 108 shutting_down_(false), |
| 108 stopped_event_(true, false) { | 109 stopped_event_(true, false) { |
| 109 } | 110 } |
| 110 | 111 |
| 111 HostService::~HostService() { | 112 HostService::~HostService() { |
| 112 } | 113 } |
| 113 | 114 |
| 114 void HostService::AddWtsConsoleObserver(WtsConsoleObserver* observer) { | 115 void HostService::AddWtsConsoleObserver(WtsConsoleObserver* observer) { |
| 115 DCHECK(message_loop_->message_loop_proxy()->BelongsToCurrentThread()); | 116 DCHECK(message_loop_->message_loop_proxy()->BelongsToCurrentThread()); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 179 bool HostService::InitWithCommandLine(const CommandLine* command_line) { | 180 bool HostService::InitWithCommandLine(const CommandLine* command_line) { |
| 180 CommandLine::StringVector args = command_line->GetArgs(); | 181 CommandLine::StringVector args = command_line->GetArgs(); |
| 181 | 182 |
| 182 // Choose the action to perform. | 183 // Choose the action to perform. |
| 183 bool host_binary_required = true; | 184 bool host_binary_required = true; |
| 184 if (!args.empty()) { | 185 if (!args.empty()) { |
| 185 if (args.size() > 1) { | 186 if (args.size() > 1) { |
| 186 LOG(ERROR) << "Invalid command line: more than one action requested."; | 187 LOG(ERROR) << "Invalid command line: more than one action requested."; |
| 187 return false; | 188 return false; |
| 188 } | 189 } |
| 189 if (args[0] == ASCIIToUTF16(kInstallActionName)) { | 190 if (args[0] == kInstallActionName) { |
| 190 run_routine_ = &HostService::Install; | 191 run_routine_ = &HostService::Install; |
| 191 } else if (args[0] == ASCIIToUTF16(kRemoveActionName)) { | 192 } else if (args[0] == kRemoveActionName) { |
| 192 run_routine_ = &HostService::Remove; | 193 run_routine_ = &HostService::Remove; |
| 193 host_binary_required = false; | 194 host_binary_required = false; |
| 194 } else if (args[0] != ASCIIToUTF16(kRunActionName)) { | 195 } else if (args[0] != kRunActionName) { |
| 195 LOG(ERROR) << "Invalid command line: invalid action specified: " | 196 LOG(ERROR) << "Invalid command line: invalid action specified: " |
| 196 << args[0]; | 197 << args[0]; |
| 197 return false; | 198 return false; |
| 198 } | 199 } |
| 199 } | 200 } |
| 200 | 201 |
| 201 if (host_binary_required) { | 202 if (host_binary_required) { |
| 202 if (command_line->HasSwitch(kHostBinarySwitchName)) { | 203 if (command_line->HasSwitch(kHostBinarySwitchName)) { |
| 203 host_binary_ = command_line->GetSwitchValuePath(kHostBinarySwitchName); | 204 host_binary_ = command_line->GetSwitchValuePath(kHostBinarySwitchName); |
| 204 } else { | 205 } else { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 226 << "Failed to connect to the service control manager"; | 227 << "Failed to connect to the service control manager"; |
| 227 return kErrorExitCode; | 228 return kErrorExitCode; |
| 228 } | 229 } |
| 229 | 230 |
| 230 FilePath exe; | 231 FilePath exe; |
| 231 if (!PathService::Get(base::FILE_EXE, &exe)) { | 232 if (!PathService::Get(base::FILE_EXE, &exe)) { |
| 232 LOG(ERROR) << "Unable to retrieve the service binary path."; | 233 LOG(ERROR) << "Unable to retrieve the service binary path."; |
| 233 return kErrorExitCode; | 234 return kErrorExitCode; |
| 234 } | 235 } |
| 235 | 236 |
| 236 string16 name = StringPrintf(ASCIIToUTF16(kMuiStringFormat).c_str(), | 237 string16 name = StringPrintf(kMuiStringFormat, |
| 237 exe.value().c_str(), | 238 exe.value().c_str(), |
| 238 IDS_DISPLAY_SERVICE_NAME); | 239 IDS_DISPLAY_SERVICE_NAME); |
| 239 | 240 |
| 240 if (!file_util::AbsolutePath(&host_binary_) || | 241 if (!file_util::AbsolutePath(&host_binary_) || |
| 241 !file_util::PathExists(host_binary_)) { | 242 !file_util::PathExists(host_binary_)) { |
| 242 LOG(ERROR) << "Invalid host binary name: " << host_binary_.value(); | 243 LOG(ERROR) << "Invalid host binary name: " << host_binary_.value(); |
| 243 return kErrorExitCode; | 244 return kErrorExitCode; |
| 244 } | 245 } |
| 245 | 246 |
| 246 string16 command_line = StringPrintf( | 247 string16 command_line = StringPrintf(kServiceCommandLineFormat, |
| 247 ASCIIToUTF16(kServiceCommandLineFormat).c_str(), | 248 exe.value().c_str(), |
| 248 exe.value().c_str(), | 249 host_binary_.value().c_str()); |
| 249 host_binary_.value().c_str()); | |
| 250 ScopedScHandle service( | 250 ScopedScHandle service( |
| 251 CreateServiceW(scmanager, | 251 CreateServiceW(scmanager, |
| 252 service_name_.c_str(), | 252 service_name_.c_str(), |
| 253 name.c_str(), | 253 name.c_str(), |
| 254 SERVICE_QUERY_STATUS | SERVICE_CHANGE_CONFIG, | 254 SERVICE_QUERY_STATUS | SERVICE_CHANGE_CONFIG, |
| 255 SERVICE_WIN32_OWN_PROCESS, | 255 SERVICE_WIN32_OWN_PROCESS, |
| 256 SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, | 256 SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, |
| 257 command_line.c_str(), | 257 command_line.c_str(), |
| 258 NULL, | 258 NULL, |
| 259 NULL, | 259 NULL, |
| 260 ASCIIToUTF16(kServiceDependencies).c_str(), | 260 kServiceDependencies, |
| 261 NULL, | 261 NULL, |
| 262 NULL)); | 262 NULL)); |
| 263 | 263 |
| 264 if (service.IsValid()) { | 264 if (service.IsValid()) { |
| 265 // Set the service description if the service is freshly installed. | 265 // Set the service description if the service is freshly installed. |
| 266 string16 description = StringPrintf( | 266 string16 description = StringPrintf(kMuiStringFormat, |
| 267 ASCIIToUTF16(kMuiStringFormat).c_str(), | 267 exe.value().c_str(), |
| 268 exe.value().c_str(), | 268 IDS_SERVICE_DESCRIPTION); |
| 269 IDS_SERVICE_DESCRIPTION); | |
| 270 | 269 |
| 271 SERVICE_DESCRIPTIONW info; | 270 SERVICE_DESCRIPTIONW info; |
| 272 info.lpDescription = const_cast<LPWSTR>(description.c_str()); | 271 info.lpDescription = const_cast<LPWSTR>(description.c_str()); |
| 273 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &info)) { | 272 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &info)) { |
| 274 LOG_GETLASTERROR(ERROR) << "Failed to set the service description"; | 273 LOG_GETLASTERROR(ERROR) << "Failed to set the service description"; |
| 275 return kErrorExitCode; | 274 return kErrorExitCode; |
| 276 } | 275 } |
| 277 | 276 |
| 278 printf("The service has been installed successfully.\n"); | 277 printf("The service has been installed successfully.\n"); |
| 279 return kSuccessExitCode; | 278 return kSuccessExitCode; |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 414 if (!SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, TRUE)) { | 413 if (!SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, TRUE)) { |
| 415 LOG_GETLASTERROR(ERROR) | 414 LOG_GETLASTERROR(ERROR) |
| 416 << "Failed to set console control handler"; | 415 << "Failed to set console control handler"; |
| 417 return result; | 416 return result; |
| 418 } | 417 } |
| 419 | 418 |
| 420 // Create a window for receiving session change notifications. | 419 // Create a window for receiving session change notifications. |
| 421 LPCWSTR atom = NULL; | 420 LPCWSTR atom = NULL; |
| 422 HWND window = NULL; | 421 HWND window = NULL; |
| 423 HINSTANCE instance = GetModuleHandle(NULL); | 422 HINSTANCE instance = GetModuleHandle(NULL); |
| 424 string16 window_class = ASCIIToUTF16(kSessionNotificationWindowClass); | |
| 425 | 423 |
| 426 WNDCLASSEX wc = {0}; | 424 WNDCLASSEX wc = {0}; |
| 427 wc.cbSize = sizeof(wc); | 425 wc.cbSize = sizeof(wc); |
| 428 wc.lpfnWndProc = base::win::WrappedWindowProc<SessionChangeNotificationProc>; | 426 wc.lpfnWndProc = base::win::WrappedWindowProc<SessionChangeNotificationProc>; |
| 429 wc.hInstance = instance; | 427 wc.hInstance = instance; |
| 430 wc.lpszClassName = window_class.c_str(); | 428 wc.lpszClassName = kSessionNotificationWindowClass; |
| 431 atom = reinterpret_cast<LPCWSTR>(RegisterClassExW(&wc)); | 429 atom = reinterpret_cast<LPCWSTR>(RegisterClassExW(&wc)); |
| 432 if (atom == NULL) { | 430 if (atom == NULL) { |
| 433 LOG_GETLASTERROR(ERROR) | 431 LOG_GETLASTERROR(ERROR) |
| 434 << "Failed to register the window class '" | 432 << "Failed to register the window class '" |
| 435 << kSessionNotificationWindowClass << "'"; | 433 << kSessionNotificationWindowClass << "'"; |
| 436 goto cleanup; | 434 goto cleanup; |
| 437 } | 435 } |
| 438 | 436 |
| 439 window = CreateWindowW(atom, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, instance, 0); | 437 window = CreateWindowW(atom, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, instance, 0); |
| 440 if (window == NULL) { | 438 if (window == NULL) { |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 599 } | 597 } |
| 600 | 598 |
| 601 remoting::HostService* service = remoting::HostService::GetInstance(); | 599 remoting::HostService* service = remoting::HostService::GetInstance(); |
| 602 if (!service->InitWithCommandLine(command_line)) { | 600 if (!service->InitWithCommandLine(command_line)) { |
| 603 usage(argv[0]); | 601 usage(argv[0]); |
| 604 return kUsageExitCode; | 602 return kUsageExitCode; |
| 605 } | 603 } |
| 606 | 604 |
| 607 return service->Run(); | 605 return service->Run(); |
| 608 } | 606 } |
| OLD | NEW |