This source file includes following definitions.
- GetInstance
 
- InitWithCommandLine
 
- Run
 
- AddWtsTerminalObserver
 
- RemoveWtsTerminalObserver
 
- weak_factory_
 
- OnSessionChange
 
- CreateLauncher
 
- RunAsService
 
- RunAsServiceImpl
 
- RunInConsole
 
- StopDaemonProcess
 
- HandleMessage
 
- ConsoleControlHandler
 
- ServiceControlHandler
 
- ServiceMain
 
- DaemonProcessMain
 
#include "remoting/host/win/host_service.h"
#include <sddl.h>
#include <windows.h>
#include <wtsapi32.h>
#include "base/base_paths.h"
#include "base/base_switches.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread.h"
#include "base/win/message_window.h"
#include "base/win/scoped_com_initializer.h"
#include "remoting/base/auto_thread.h"
#include "remoting/base/scoped_sc_handle_win.h"
#include "remoting/host/branding.h"
#include "remoting/host/daemon_process.h"
#include "remoting/host/host_exit_codes.h"
#include "remoting/host/logging.h"
#include "remoting/host/win/com_security.h"
#include "remoting/host/win/core_resource.h"
#include "remoting/host/win/wts_terminal_observer.h"
namespace remoting {
namespace {
const char kIoThreadName[] = "I/O thread";
const char kConsoleSwitchName[] = "console";
const wchar_t kComProcessSd[] =
    SDDL_OWNER L":" SDDL_LOCAL_SYSTEM
    SDDL_GROUP L":" SDDL_LOCAL_SYSTEM
    SDDL_DACL L":"
    SDDL_ACE(SDDL_ACCESS_ALLOWED, SDDL_COM_EXECUTE_LOCAL, SDDL_LOCAL_SYSTEM)
    SDDL_ACE(SDDL_ACCESS_ALLOWED, SDDL_COM_EXECUTE_LOCAL, SDDL_LOCAL_SERVICE);
const wchar_t kComProcessMandatoryLabel[] =
    SDDL_SACL L":"
    SDDL_ACE(SDDL_MANDATORY_LABEL, SDDL_NO_EXECUTE_UP, SDDL_ML_MEDIUM);
}  
HostService* HostService::GetInstance() {
  return Singleton<HostService>::get();
}
bool HostService::InitWithCommandLine(const CommandLine* command_line) {
  CommandLine::StringVector args = command_line->GetArgs();
  if (!args.empty()) {
    LOG(ERROR) << "No positional parameters expected.";
    return false;
  }
  
  if (run_routine_ == &HostService::RunAsService &&
      command_line->HasSwitch(kConsoleSwitchName)) {
    run_routine_ = &HostService::RunInConsole;
  }
  return true;
}
int HostService::Run() {
  return (this->*run_routine_)();
}
bool HostService::AddWtsTerminalObserver(const std::string& terminal_id,
                                         WtsTerminalObserver* observer) {
  DCHECK(main_task_runner_->BelongsToCurrentThread());
  RegisteredObserver registered_observer;
  registered_observer.terminal_id = terminal_id;
  registered_observer.session_id = kInvalidSessionId;
  registered_observer.observer = observer;
  bool session_id_found = false;
  std::list<RegisteredObserver>::const_iterator i;
  for (i = observers_.begin(); i != observers_.end(); ++i) {
    
    
    if (i->terminal_id == terminal_id) {
      registered_observer.session_id = i->session_id;
      session_id_found = true;
    }
    
    if (i->observer == observer)
      return false;
  }
  
  
  if (!session_id_found)
    registered_observer.session_id = LookupSessionId(terminal_id);
  observers_.push_back(registered_observer);
  if (registered_observer.session_id != kInvalidSessionId) {
    observer->OnSessionAttached(registered_observer.session_id);
  }
  return true;
}
void HostService::RemoveWtsTerminalObserver(WtsTerminalObserver* observer) {
  DCHECK(main_task_runner_->BelongsToCurrentThread());
  std::list<RegisteredObserver>::const_iterator i;
  for (i = observers_.begin(); i != observers_.end(); ++i) {
    if (i->observer == observer) {
      observers_.erase(i);
      return;
    }
  }
}
HostService::HostService() :
  run_routine_(&HostService::RunAsService),
  service_status_handle_(0),
  stopped_event_(true, false),
  weak_factory_(this) {
}
HostService::~HostService() {
}
void HostService::OnSessionChange(uint32 event, uint32 session_id) {
  DCHECK(main_task_runner_->BelongsToCurrentThread());
  DCHECK_NE(session_id, kInvalidSessionId);
  
  if (event != WTS_CONSOLE_CONNECT && event != WTS_CONSOLE_DISCONNECT &&
      event != WTS_REMOTE_CONNECT && event != WTS_REMOTE_DISCONNECT) {
    return;
  }
  
  
  std::string terminal_id;
  bool attached = LookupTerminalId(session_id, &terminal_id);
  std::list<RegisteredObserver>::iterator i = observers_.begin();
  while (i != observers_.end()) {
    std::list<RegisteredObserver>::iterator next = i;
    ++next;
    
    
    if (i->session_id == session_id &&
        (!attached || !(i->terminal_id == terminal_id))) {
      i->session_id = kInvalidSessionId;
      i->observer->OnSessionDetached();
      i = next;
      continue;
    }
    
    
    if (attached && i->terminal_id == terminal_id &&
        i->session_id != session_id) {
      WtsTerminalObserver* observer = i->observer;
      if (i->session_id != kInvalidSessionId) {
        i->session_id = kInvalidSessionId;
        i->observer->OnSessionDetached();
      }
      
      
      std::list<RegisteredObserver>::iterator j = next;
      --j;
      if (j->observer == observer) {
        j->session_id = session_id;
        observer->OnSessionAttached(session_id);
      }
    }
    i = next;
  }
}
void HostService::CreateLauncher(
    scoped_refptr<AutoThreadTaskRunner> task_runner) {
  
  scoped_refptr<AutoThreadTaskRunner> io_task_runner =
      AutoThread::CreateWithType(
          kIoThreadName, task_runner, base::MessageLoop::TYPE_IO);
  if (!io_task_runner) {
    LOG(FATAL) << "Failed to start the I/O thread";
    return;
  }
  daemon_process_ = DaemonProcess::Create(
      task_runner,
      io_task_runner,
      base::Bind(&HostService::StopDaemonProcess, weak_ptr_));
}
int HostService::RunAsService() {
  SERVICE_TABLE_ENTRYW dispatch_table[] = {
    { const_cast<LPWSTR>(kWindowsServiceName), &HostService::ServiceMain },
    { NULL, NULL }
  };
  if (!StartServiceCtrlDispatcherW(dispatch_table)) {
    LOG_GETLASTERROR(ERROR)
        << "Failed to connect to the service control manager";
    return kInitializationFailed;
  }
  
  
  
  stopped_event_.Wait();
  return kSuccessExitCode;
}
void HostService::RunAsServiceImpl() {
  base::MessageLoopForUI message_loop;
  base::RunLoop run_loop;
  main_task_runner_ = message_loop.message_loop_proxy();
  weak_ptr_ = weak_factory_.GetWeakPtr();
  
  service_status_handle_ = RegisterServiceCtrlHandlerExW(
      kWindowsServiceName, &HostService::ServiceControlHandler, this);
  if (service_status_handle_ == 0) {
    LOG_GETLASTERROR(ERROR)
        << "Failed to register the service control handler";
    return;
  }
  
  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_ACCEPT_SESSIONCHANGE;
  service_status.dwWin32ExitCode = kSuccessExitCode;
  if (!SetServiceStatus(service_status_handle_, &service_status)) {
    LOG_GETLASTERROR(ERROR)
        << "Failed to report service status to the service control manager";
    return;
  }
  
  base::win::ScopedCOMInitializer com_initializer;
  if (!com_initializer.succeeded())
    return;
  if (!InitializeComSecurity(base::WideToUTF8(kComProcessSd),
                             base::WideToUTF8(kComProcessMandatoryLabel),
                             false)) {
    return;
  }
  CreateLauncher(scoped_refptr<AutoThreadTaskRunner>(
      new AutoThreadTaskRunner(main_task_runner_,
                               run_loop.QuitClosure())));
  
  run_loop.Run();
  weak_factory_.InvalidateWeakPtrs();
  
  service_status.dwCurrentState = SERVICE_STOPPED;
  service_status.dwControlsAccepted = 0;
  if (!SetServiceStatus(service_status_handle_, &service_status)) {
    LOG_GETLASTERROR(ERROR)
        << "Failed to report service status to the service control manager";
    return;
  }
}
int HostService::RunInConsole() {
  base::MessageLoopForUI message_loop;
  base::RunLoop run_loop;
  main_task_runner_ = message_loop.message_loop_proxy();
  weak_ptr_ = weak_factory_.GetWeakPtr();
  int result = kInitializationFailed;
  
  base::win::ScopedCOMInitializer com_initializer;
  if (!com_initializer.succeeded())
    return result;
  if (!InitializeComSecurity(base::WideToUTF8(kComProcessSd),
                             base::WideToUTF8(kComProcessMandatoryLabel),
                             false)) {
    return result;
  }
  
  if (!SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, TRUE)) {
    LOG_GETLASTERROR(ERROR)
        << "Failed to set console control handler";
    return result;
  }
  
  base::win::MessageWindow window;
  if (!window.Create(base::Bind(&HostService::HandleMessage,
                                base::Unretained(this)))) {
    LOG_GETLASTERROR(ERROR)
        << "Failed to create the session notification window";
    goto cleanup;
  }
  
  if (WTSRegisterSessionNotification(window.hwnd(),
                                     NOTIFY_FOR_ALL_SESSIONS) != FALSE) {
    CreateLauncher(scoped_refptr<AutoThreadTaskRunner>(
        new AutoThreadTaskRunner(main_task_runner_,
                                 run_loop.QuitClosure())));
    
    run_loop.Run();
    
    stopped_event_.Signal();
    WTSUnRegisterSessionNotification(window.hwnd());
    result = kSuccessExitCode;
  }
cleanup:
  weak_factory_.InvalidateWeakPtrs();
  
  
  
  SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, FALSE);
  return result;
}
void HostService::StopDaemonProcess() {
  DCHECK(main_task_runner_->BelongsToCurrentThread());
  daemon_process_.reset();
}
bool HostService::HandleMessage(
    UINT message, WPARAM wparam, LPARAM lparam, LRESULT* result) {
  if (message == WM_WTSSESSION_CHANGE) {
    OnSessionChange(wparam, lparam);
    *result = 0;
    return true;
  }
  return false;
}
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->main_task_runner_->PostTask(
          FROM_HERE, base::Bind(&HostService::StopDaemonProcess,
                                self->weak_ptr_));
      return TRUE;
    default:
      return FALSE;
  }
}
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->main_task_runner_->PostTask(
          FROM_HERE, base::Bind(&HostService::StopDaemonProcess,
                                self->weak_ptr_));
      return NO_ERROR;
    case SERVICE_CONTROL_SESSIONCHANGE:
      self->main_task_runner_->PostTask(FROM_HERE, base::Bind(
          &HostService::OnSessionChange, self->weak_ptr_, event_type,
          reinterpret_cast<WTSSESSION_NOTIFICATION*>(event_data)->dwSessionId));
      return NO_ERROR;
    default:
      return ERROR_CALL_NOT_IMPLEMENTED;
  }
}
VOID WINAPI HostService::ServiceMain(DWORD argc, WCHAR* argv[]) {
  HostService* self = HostService::GetInstance();
  
  self->RunAsServiceImpl();
  
  
  self->stopped_event_.Signal();
}
int DaemonProcessMain() {
  HostService* service = HostService::GetInstance();
  if (!service->InitWithCommandLine(CommandLine::ForCurrentProcess())) {
    return kUsageExitCode;
  }
  return service->Run();
}
}