diff options
author | alexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-10 21:29:22 +0000 |
---|---|---|
committer | alexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-10 21:29:22 +0000 |
commit | de17e924a971f005ae8ddd5a884ab66b92b4136c (patch) | |
tree | 548134058c499f2c67d9d339ae7ea7f7fdc6fd73 /remoting | |
parent | 302b7c238f68ff98aafc3588e1a5d8e5714e376e (diff) | |
download | chromium_src-de17e924a971f005ae8ddd5a884ab66b92b4136c.zip chromium_src-de17e924a971f005ae8ddd5a884ab66b92b4136c.tar.gz chromium_src-de17e924a971f005ae8ddd5a884ab66b92b4136c.tar.bz2 |
The Chromoting service can now be started and stopped, running an empty message loop.
Review URL: http://codereview.chromium.org/9378009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@121537 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r-- | remoting/host/remoting_host_service_win.cc | 159 | ||||
-rw-r--r-- | remoting/host/remoting_host_service_win.h | 55 |
2 files changed, 197 insertions, 17 deletions
diff --git a/remoting/host/remoting_host_service_win.cc b/remoting/host/remoting_host_service_win.cc index 22b3d10..68d9e05 100644 --- a/remoting/host/remoting_host_service_win.cc +++ b/remoting/host/remoting_host_service_win.cc @@ -12,11 +12,12 @@ #include "base/at_exit.h" #include "base/base_paths.h" +#include "base/bind.h" #include "base/command_line.h" #include "base/file_path.h" #include "base/logging.h" +#include "base/message_loop.h" #include "base/path_service.h" -#include "base/string16.h" #include "base/stringprintf.h" #include "base/utf_string_conversions.h" @@ -79,12 +80,37 @@ void usage(const char* program_name) { namespace remoting { HostService::HostService() : - run_routine_(&HostService::RunAsService) { + run_routine_(&HostService::RunAsService), + service_name_(ASCIIToUTF16(kServiceName)), + service_status_handle_(0), + stopped_event_(true, false), + message_loop_(NULL) { } HostService::~HostService() { } +BOOL WINAPI HostService::ConsoleControlHandler(DWORD event) { + HostService* self = HostService::GetInstance(); + switch (event) { + case CTRL_C_EVENT: + case CTRL_BREAK_EVENT: + case CTRL_CLOSE_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + self->message_loop_->PostTask(FROM_HERE, MessageLoop::QuitClosure()); + self->stopped_event_.Wait(); + return TRUE; + + default: + return FALSE; + } +} + +HostService* HostService::GetInstance() { + return Singleton<HostService>::get(); +} + bool HostService::InitWithCommandLine(const CommandLine* command_line) { CommandLine::StringVector args = command_line->GetArgs(); @@ -135,7 +161,7 @@ int HostService::Install() { IDS_DISPLAY_SERVICE_NAME); ScopedScHandle service( CreateServiceW(scmanager, - ASCIIToUTF16(kServiceName).c_str(), + service_name_.c_str(), name.c_str(), SERVICE_QUERY_STATUS | SERVICE_CHANGE_CONFIG, SERVICE_WIN32_OWN_PROCESS, @@ -192,7 +218,7 @@ int HostService::Remove() { } ScopedScHandle service( - OpenServiceW(scmanager, ASCIIToUTF16(kServiceName).c_str(), + OpenServiceW(scmanager, service_name_.c_str(), DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS)); if (!service.IsValid()) { if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) { @@ -222,8 +248,8 @@ int HostService::Remove() { } // Ask SCM to stop the service and wait. - SERVICE_STATUS status; - if (ControlService(service, SERVICE_CONTROL_STOP, &status)) { + SERVICE_STATUS service_status; + if (ControlService(service, SERVICE_CONTROL_STOP, &service_status)) { printf("Stopping...\n"); } @@ -247,14 +273,121 @@ int HostService::Run() { return (this->*run_routine_)(); } +void HostService::RunMessageLoop() { + // Run the service. + message_loop_->Run(); + + // Release the control handler. + stopped_event_.Signal(); +} + int HostService::RunAsService() { - NOTIMPLEMENTED(); - return 0; + SERVICE_TABLE_ENTRYW dispatch_table[] = { + { const_cast<LPWSTR>(service_name_.c_str()), &HostService::ServiceMain }, + { NULL, NULL } + }; + + if (!StartServiceCtrlDispatcherW(dispatch_table)) { + LOG_GETLASTERROR(ERROR) + << "Failed to connect to the service control manager"; + return kErrorExitCode; + } + + return kSuccessExitCode; } int HostService::RunInConsole() { - NOTIMPLEMENTED(); - return 0; + MessageLoop message_loop; + + // Allow other threads to post to our message loop. + message_loop_ = &message_loop; + + // Subscribe to Ctrl-C and other console events. + if (!SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, TRUE)) { + LOG_GETLASTERROR(ERROR) + << "Failed to set console control handler"; + return kErrorExitCode; + } + + // Run the service. + RunMessageLoop(); + + // Unsubscribe from console events. Ignore the exit code. There is nothing + // we can do about it now and the program is about to exit anyway. Even if + // it crashes nothing is going to be broken because of it. + SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, FALSE); + + message_loop_ = NULL; + return kSuccessExitCode; +} + +DWORD WINAPI HostService::ServiceControlHandler(DWORD control, + DWORD event_type, + LPVOID event_data, + LPVOID context) { + HostService* self = reinterpret_cast<HostService*>(context); + switch (control) { + case SERVICE_CONTROL_INTERROGATE: + return NO_ERROR; + + case SERVICE_CONTROL_SHUTDOWN: + case SERVICE_CONTROL_STOP: + self->message_loop_->PostTask(FROM_HERE, MessageLoop::QuitClosure()); + self->stopped_event_.Wait(); + return NO_ERROR; + + default: + return ERROR_CALL_NOT_IMPLEMENTED; + } +} + +VOID WINAPI HostService::ServiceMain(DWORD argc, WCHAR* argv[]) { + MessageLoop message_loop; + + // Allow other threads to post to our message loop. + HostService* self = HostService::GetInstance(); + self->message_loop_ = &message_loop; + + // Register the service control handler. + self->service_status_handle_ = + RegisterServiceCtrlHandlerExW(self->service_name_.c_str(), + &HostService::ServiceControlHandler, + self); + if (self->service_status_handle_ == 0) { + LOG_GETLASTERROR(ERROR) + << "Failed to register the service control handler"; + return; + } + + // Report running status of the service. + SERVICE_STATUS service_status; + ZeroMemory(&service_status, sizeof(service_status)); + service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + service_status.dwCurrentState = SERVICE_RUNNING; + service_status.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | + SERVICE_ACCEPT_STOP; + service_status.dwWin32ExitCode = kSuccessExitCode; + + if (!SetServiceStatus(self->service_status_handle_, &service_status)) { + LOG_GETLASTERROR(ERROR) + << "Failed to report service status to the service control manager"; + return; + } + + // Run the service. + self->RunMessageLoop(); + + // Tell SCM that the service is stopped. + service_status.dwCurrentState = SERVICE_STOPPED; + service_status.dwControlsAccepted = 0; + + if (!SetServiceStatus(self->service_status_handle_, &service_status)) { + LOG_GETLASTERROR(ERROR) + << "Failed to report service status to the service control manager"; + return; + } + + self->message_loop_ = NULL; } } // namespace remoting @@ -274,11 +407,11 @@ int main(int argc, char** argv) { return kSuccessExitCode; } - remoting::HostService service; - if (!service.InitWithCommandLine(command_line)) { + remoting::HostService* service = remoting::HostService::GetInstance(); + if (!service->InitWithCommandLine(command_line)) { usage(argv[0]); return kUsageExitCode; } - return service.Run(); + return service->Run(); } diff --git a/remoting/host/remoting_host_service_win.h b/remoting/host/remoting_host_service_win.h index 6cfd55e..e1e59b2 100644 --- a/remoting/host/remoting_host_service_win.h +++ b/remoting/host/remoting_host_service_win.h @@ -7,14 +7,18 @@ #include <windows.h> +#include "base/memory/singleton.h" +#include "base/string16.h" +#include "base/synchronization/waitable_event.h" + class CommandLine; +class MessageLoop; namespace remoting { class HostService { public: - HostService(); - ~HostService(); + static HostService* GetInstance(); // This function parses the command line and selects the action routine. bool InitWithCommandLine(const CommandLine* command_line); @@ -23,18 +27,61 @@ class HostService { int Run(); private: + HostService(); + ~HostService(); + // This routine registers the service with the service control manager. int Install(); - static VOID CALLBACK OnServiceStopped(PVOID context); - // This routine uninstalls the service previously regerested by Install(). int Remove(); + // This is a common entry point to the main service loop called by both + // RunAsService() and RunInConsole(). + void RunMessageLoop(); + + // This function handshakes with the service control manager and starts + // the service. int RunAsService(); + + // This function starts the service in interactive mode (i.e. as a plain + // console application). int RunInConsole(); + static BOOL WINAPI ConsoleControlHandler(DWORD event); + static VOID CALLBACK OnServiceStopped(PVOID context); + + // The control handler of the service. + static DWORD WINAPI ServiceControlHandler(DWORD control, + DWORD event_type, + LPVOID event_data, + LPVOID context); + + // The main service entry point. + static VOID WINAPI ServiceMain(DWORD argc, WCHAR* argv[]); + + // The action routine to be executed. int (HostService::*run_routine_)(); + + // The service name. + string16 service_name_; + + // The service status structure. + SERVICE_STATUS service_status_; + + // The service status handle. + SERVICE_STATUS_HANDLE service_status_handle_; + + // Service message loop. + MessageLoop* message_loop_; + + // A waitable event that is used to wait until the service is stopped. + base::WaitableEvent stopped_event_; + + // Singleton. + friend struct DefaultSingletonTraits<HostService>; + + DISALLOW_COPY_AND_ASSIGN(HostService); }; } // namespace remoting |