15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file implements the Windows service controlling Me2Me host processes
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// running within user sessions.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/win/host_service.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sddl.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <wtsapi32.h>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base_paths.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base_switches.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
199ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/run_loop.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/single_thread_task_runner.h"
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/win/message_window.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/scoped_com_initializer.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "remoting/base/auto_thread.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/base/scoped_sc_handle_win.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/branding.h"
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "remoting/host/daemon_process.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/host_exit_codes.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/logging.h"
327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "remoting/host/win/com_security.h"
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "remoting/host/win/core_resource.h"
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "remoting/host/win/wts_terminal_observer.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace remoting {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kIoThreadName[] = "I/O thread";
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Command line switches:
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "--console" runs the service interactively for debugging purposes.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kConsoleSwitchName[] = "console";
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Security descriptor allowing local processes running under SYSTEM or
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// LocalService accounts to call COM methods exposed by the daemon.
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const wchar_t kComProcessSd[] =
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SDDL_OWNER L":" SDDL_LOCAL_SYSTEM
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SDDL_GROUP L":" SDDL_LOCAL_SYSTEM
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SDDL_DACL L":"
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SDDL_ACE(SDDL_ACCESS_ALLOWED, SDDL_COM_EXECUTE_LOCAL, SDDL_LOCAL_SYSTEM)
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SDDL_ACE(SDDL_ACCESS_ALLOWED, SDDL_COM_EXECUTE_LOCAL, SDDL_LOCAL_SERVICE);
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Appended to |kComProcessSd| to specify that only callers running at medium or
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// higher integrity level are allowed to call COM methods exposed by the daemon.
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const wchar_t kComProcessMandatoryLabel[] =
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SDDL_SACL L":"
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SDDL_ACE(SDDL_MANDATORY_LABEL, SDDL_NO_EXECUTE_UP, SDDL_ML_MEDIUM);
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HostService* HostService::GetInstance() {
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return Singleton<HostService>::get();
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool HostService::InitWithCommandLine(const base::CommandLine* command_line) {
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::CommandLine::StringVector args = command_line->GetArgs();
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!args.empty()) {
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "No positional parameters expected.";
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Run interactively if needed.
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (run_routine_ == &HostService::RunAsService &&
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      command_line->HasSwitch(kConsoleSwitchName)) {
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    run_routine_ = &HostService::RunInConsole;
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int HostService::Run() {
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return (this->*run_routine_)();
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool HostService::AddWtsTerminalObserver(const std::string& terminal_id,
89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                         WtsTerminalObserver* observer) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(main_task_runner_->BelongsToCurrentThread());
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RegisteredObserver registered_observer;
93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  registered_observer.terminal_id = terminal_id;
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registered_observer.session_id = kInvalidSessionId;
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registered_observer.observer = observer;
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool session_id_found = false;
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::list<RegisteredObserver>::const_iterator i;
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (i = observers_.begin(); i != observers_.end(); ++i) {
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Get the attached session ID from another observer watching the same WTS
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // console if any.
102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (i->terminal_id == terminal_id) {
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      registered_observer.session_id = i->session_id;
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      session_id_found = true;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Check that |observer| hasn't been registered already.
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (i->observer == observer)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // If |terminal_id| is new, enumerate all sessions to see if there is one
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // attached to |terminal_id|.
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!session_id_found)
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    registered_observer.session_id = LookupSessionId(terminal_id);
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  observers_.push_back(registered_observer);
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (registered_observer.session_id != kInvalidSessionId) {
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    observer->OnSessionAttached(registered_observer.session_id);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HostService::RemoveWtsTerminalObserver(WtsTerminalObserver* observer) {
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(main_task_runner_->BelongsToCurrentThread());
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::list<RegisteredObserver>::const_iterator i;
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (i = observers_.begin(); i != observers_.end(); ++i) {
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (i->observer == observer) {
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      observers_.erase(i);
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HostService::HostService() :
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  run_routine_(&HostService::RunAsService),
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  service_status_handle_(0),
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  stopped_event_(true, false),
142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  weak_factory_(this) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HostService::~HostService() {
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HostService::OnSessionChange(uint32 event, uint32 session_id) {
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(main_task_runner_->BelongsToCurrentThread());
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_NE(session_id, kInvalidSessionId);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Process only attach/detach notifications.
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (event != WTS_CONSOLE_CONNECT && event != WTS_CONSOLE_DISCONNECT &&
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      event != WTS_REMOTE_CONNECT && event != WTS_REMOTE_DISCONNECT) {
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Assuming that notification can arrive later query the current state of
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |session_id|.
160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string terminal_id;
161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool attached = LookupTerminalId(session_id, &terminal_id);
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::list<RegisteredObserver>::iterator i = observers_.begin();
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (i != observers_.end()) {
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::list<RegisteredObserver>::iterator next = i;
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ++next;
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Issue a detach notification if the session was detached from a client or
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // if it is now attached to a different client.
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (i->session_id == session_id &&
171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        (!attached || !(i->terminal_id == terminal_id))) {
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      i->session_id = kInvalidSessionId;
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      i->observer->OnSessionDetached();
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      i = next;
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The client currently attached to |session_id| was attached to a different
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // session before. Reconnect it to |session_id|.
180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (attached && i->terminal_id == terminal_id &&
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        i->session_id != session_id) {
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      WtsTerminalObserver* observer = i->observer;
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (i->session_id != kInvalidSessionId) {
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        i->session_id = kInvalidSessionId;
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        i->observer->OnSessionDetached();
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Verify that OnSessionDetached() above didn't remove |observer|
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // from the list.
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::list<RegisteredObserver>::iterator j = next;
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      --j;
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (j->observer == observer) {
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        j->session_id = session_id;
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        observer->OnSessionAttached(session_id);
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    i = next;
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HostService::CreateLauncher(
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<AutoThreadTaskRunner> task_runner) {
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Launch the I/O thread.
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<AutoThreadTaskRunner> io_task_runner =
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      AutoThread::CreateWithType(
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          kIoThreadName, task_runner, base::MessageLoop::TYPE_IO);
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!io_task_runner) {
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(FATAL) << "Failed to start the I/O thread";
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
214868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  daemon_process_ = DaemonProcess::Create(
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      task_runner,
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      io_task_runner,
217868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      base::Bind(&HostService::StopDaemonProcess, weak_ptr_));
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HostService::RunAsService() {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SERVICE_TABLE_ENTRYW dispatch_table[] = {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { const_cast<LPWSTR>(kWindowsServiceName), &HostService::ServiceMain },
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { NULL, NULL }
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!StartServiceCtrlDispatcherW(dispatch_table)) {
227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "Failed to connect to the service control manager";
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return kInitializationFailed;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Wait until the service thread completely exited to avoid concurrent
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // teardown of objects registered with base::AtExitManager and object
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // destoyed by the service thread.
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  stopped_event_.Wait();
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kSuccessExitCode;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HostService::RunAsServiceImpl() {
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::MessageLoopForUI message_loop;
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::RunLoop run_loop;
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  main_task_runner_ = message_loop.message_loop_proxy();
243868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  weak_ptr_ = weak_factory_.GetWeakPtr();
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Register the service control handler.
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  service_status_handle_ = RegisterServiceCtrlHandlerExW(
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      kWindowsServiceName, &HostService::ServiceControlHandler, this);
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (service_status_handle_ == 0) {
249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "Failed to register the service control handler";
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Report running status of the service.
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SERVICE_STATUS service_status;
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ZeroMemory(&service_status, sizeof(service_status));
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  service_status.dwCurrentState = SERVICE_RUNNING;
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  service_status.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN |
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      SERVICE_ACCEPT_STOP |
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      SERVICE_ACCEPT_SESSIONCHANGE;
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  service_status.dwWin32ExitCode = kSuccessExitCode;
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!SetServiceStatus(service_status_handle_, &service_status)) {
263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR)
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        << "Failed to report service status to the service control manager";
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Initialize COM.
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedCOMInitializer com_initializer;
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!com_initializer.succeeded())
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!InitializeComSecurity(base::WideToUTF8(kComProcessSd),
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             base::WideToUTF8(kComProcessMandatoryLabel),
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             false)) {
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CreateLauncher(scoped_refptr<AutoThreadTaskRunner>(
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new AutoThreadTaskRunner(main_task_runner_,
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               run_loop.QuitClosure())));
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Run the service.
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  run_loop.Run();
285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  weak_factory_.InvalidateWeakPtrs();
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Tell SCM that the service is stopped.
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  service_status.dwCurrentState = SERVICE_STOPPED;
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  service_status.dwControlsAccepted = 0;
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!SetServiceStatus(service_status_handle_, &service_status)) {
291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR)
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        << "Failed to report service status to the service control manager";
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int HostService::RunInConsole() {
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::MessageLoopForUI message_loop;
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::RunLoop run_loop;
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  main_task_runner_ = message_loop.message_loop_proxy();
301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  weak_ptr_ = weak_factory_.GetWeakPtr();
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = kInitializationFailed;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Initialize COM.
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedCOMInitializer com_initializer;
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!com_initializer.succeeded())
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return result;
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!InitializeComSecurity(base::WideToUTF8(kComProcessSd),
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             base::WideToUTF8(kComProcessMandatoryLabel),
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             false)) {
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return result;
3147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Subscribe to Ctrl-C and other console events.
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, TRUE)) {
318cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "Failed to set console control handler";
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a window for receiving session change notifications.
323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::win::MessageWindow window;
324eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!window.Create(base::Bind(&HostService::HandleMessage,
325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                base::Unretained(this)))) {
326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "Failed to create the session notification window";
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    goto cleanup;
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Subscribe to session change notifications.
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (WTSRegisterSessionNotification(window.hwnd(),
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     NOTIFY_FOR_ALL_SESSIONS) != FALSE) {
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CreateLauncher(scoped_refptr<AutoThreadTaskRunner>(
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        new AutoThreadTaskRunner(main_task_runner_,
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 run_loop.QuitClosure())));
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Run the service.
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    run_loop.Run();
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Release the control handler.
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stopped_event_.Signal();
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    WTSUnRegisterSessionNotification(window.hwnd());
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = kSuccessExitCode;
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cleanup:
348868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  weak_factory_.InvalidateWeakPtrs();
349868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Unsubscribe from console events. Ignore the exit code. There is nothing
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we can do about it now and the program is about to exit anyway. Even if
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it crashes nothing is going to be broken because of it.
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, FALSE);
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
358868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void HostService::StopDaemonProcess() {
359868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(main_task_runner_->BelongsToCurrentThread());
360868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
361868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  daemon_process_.reset();
362868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
363868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool HostService::HandleMessage(
365eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    UINT message, WPARAM wparam, LPARAM lparam, LRESULT* result) {
366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (message == WM_WTSSESSION_CHANGE) {
367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    OnSessionChange(wparam, lparam);
368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *result = 0;
369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return true;
370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return false;
373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)BOOL WINAPI HostService::ConsoleControlHandler(DWORD event) {
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HostService* self = HostService::GetInstance();
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (event) {
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case CTRL_C_EVENT:
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case CTRL_BREAK_EVENT:
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case CTRL_CLOSE_EVENT:
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case CTRL_LOGOFF_EVENT:
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case CTRL_SHUTDOWN_EVENT:
384868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      self->main_task_runner_->PostTask(
385868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          FROM_HERE, base::Bind(&HostService::StopDaemonProcess,
386868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                self->weak_ptr_));
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return TRUE;
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    default:
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return FALSE;
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DWORD WINAPI HostService::ServiceControlHandler(DWORD control,
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                DWORD event_type,
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                LPVOID event_data,
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                LPVOID context) {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HostService* self = reinterpret_cast<HostService*>(context);
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (control) {
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SERVICE_CONTROL_INTERROGATE:
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NO_ERROR;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SERVICE_CONTROL_SHUTDOWN:
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SERVICE_CONTROL_STOP:
406868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      self->main_task_runner_->PostTask(
407868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          FROM_HERE, base::Bind(&HostService::StopDaemonProcess,
408868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                self->weak_ptr_));
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NO_ERROR;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SERVICE_CONTROL_SESSIONCHANGE:
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self->main_task_runner_->PostTask(FROM_HERE, base::Bind(
413868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          &HostService::OnSessionChange, self->weak_ptr_, event_type,
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          reinterpret_cast<WTSSESSION_NOTIFICATION*>(event_data)->dwSessionId));
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NO_ERROR;
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERROR_CALL_NOT_IMPLEMENTED;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VOID WINAPI HostService::ServiceMain(DWORD argc, WCHAR* argv[]) {
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HostService* self = HostService::GetInstance();
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Run the service.
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  self->RunAsServiceImpl();
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Release the control handler and notify the main thread that it can exit
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // now.
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  self->stopped_event_.Signal();
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int DaemonProcessMain() {
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HostService* service = HostService::GetInstance();
436cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!service->InitWithCommandLine(base::CommandLine::ForCurrentProcess())) {
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return kUsageExitCode;
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return service->Run();
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
443cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace remoting
444