summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--remoting/host/remoting_host_service_win.cc148
-rw-r--r--remoting/host/remoting_host_service_win.h34
-rw-r--r--remoting/host/wts_console_monitor_win.h36
-rw-r--r--remoting/host/wts_console_observer_win.h34
-rw-r--r--remoting/host/wts_session_process_launcher_win.cc35
-rw-r--r--remoting/host/wts_session_process_launcher_win.h38
-rw-r--r--remoting/remoting.gyp11
7 files changed, 324 insertions, 12 deletions
diff --git a/remoting/host/remoting_host_service_win.cc b/remoting/host/remoting_host_service_win.cc
index 68d9e05..e0ac078 100644
--- a/remoting/host/remoting_host_service_win.cc
+++ b/remoting/host/remoting_host_service_win.cc
@@ -8,6 +8,7 @@
#include "remoting/host/remoting_host_service_win.h"
#include <windows.h>
+#include <wtsapi32.h>
#include <stdio.h>
#include "base/at_exit.h"
@@ -20,9 +21,12 @@
#include "base/path_service.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
+#include "base/win/wrapped_window_proc.h"
-#include "remoting/base/scoped_sc_handle_win.h"
#include "remoting/host/remoting_host_service_resource.h"
+#include "remoting/base/scoped_sc_handle_win.h"
+#include "remoting/host/wts_console_observer_win.h"
+#include "remoting/host/wts_session_process_launcher_win.h"
using base::StringPrintf;
@@ -36,6 +40,13 @@ const char kServiceDependencies[] = "";
const DWORD kServiceStopTimeoutMs = 30 * 1000;
+// Session id that does not represent any session.
+const uint32 kInvalidSession = 0xffffffff;
+
+// A window class for the session change notifications window.
+static const char kSessionNotificationWindowClass[] =
+ "Chromoting_SessionNotificationWindow";
+
// Command line actions and switches:
// "run" sumply runs the service as usual.
const char kRunActionName[] = "run";
@@ -80,16 +91,53 @@ void usage(const char* program_name) {
namespace remoting {
HostService::HostService() :
+ console_session_id_(kInvalidSession),
+ message_loop_(NULL),
run_routine_(&HostService::RunAsService),
service_name_(ASCIIToUTF16(kServiceName)),
service_status_handle_(0),
- stopped_event_(true, false),
- message_loop_(NULL) {
+ shutting_down_(false),
+ stopped_event_(true, false) {
}
HostService::~HostService() {
}
+void HostService::AddWtsConsoleObserver(WtsConsoleObserver* observer) {
+ console_observers_.AddObserver(observer);
+}
+
+void HostService::RemoveWtsConsoleObserver(WtsConsoleObserver* observer) {
+ console_observers_.RemoveObserver(observer);
+}
+
+void HostService::OnSessionChange() {
+ // WTSGetActiveConsoleSessionId is a very cheap API. It basically reads
+ // a single value from shared memory. Therefore it is better to check if
+ // the console session is still the same every time a session change
+ // notification event is posted. This also takes care of coalescing multiple
+ // events into one since we look at the latest state.
+ uint32 console_session_id = kInvalidSession;
+ if (!shutting_down_) {
+ console_session_id = WTSGetActiveConsoleSessionId();
+ }
+ if (console_session_id_ != console_session_id) {
+ if (console_session_id_ != kInvalidSession) {
+ FOR_EACH_OBSERVER(WtsConsoleObserver,
+ console_observers_,
+ OnSessionDetached());
+ }
+
+ console_session_id_ = console_session_id;
+
+ if (console_session_id_ != kInvalidSession) {
+ FOR_EACH_OBSERVER(WtsConsoleObserver,
+ console_observers_,
+ OnSessionAttached(console_session_id_));
+ }
+ }
+}
+
BOOL WINAPI HostService::ConsoleControlHandler(DWORD event) {
HostService* self = HostService::GetInstance();
switch (event) {
@@ -274,9 +322,15 @@ int HostService::Run() {
}
void HostService::RunMessageLoop() {
+ WtsSessionProcessLauncher launcher(this);
+
// Run the service.
message_loop_->Run();
+ // Clean up the observers by emulating detaching from the console.
+ shutting_down_ = true;
+ OnSessionChange();
+
// Release the control handler.
stopped_event_.Signal();
}
@@ -297,20 +351,69 @@ int HostService::RunAsService() {
}
int HostService::RunInConsole() {
- MessageLoop message_loop;
+ MessageLoop message_loop(MessageLoop::TYPE_UI);
// Allow other threads to post to our message loop.
message_loop_ = &message_loop;
+ int result = kErrorExitCode;
+
// Subscribe to Ctrl-C and other console events.
if (!SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, TRUE)) {
LOG_GETLASTERROR(ERROR)
<< "Failed to set console control handler";
- return kErrorExitCode;
+ return result;
}
- // Run the service.
- RunMessageLoop();
+ // Create a window for receiving session change notifications.
+ LPCWSTR atom = NULL;
+ HWND window = NULL;
+ HINSTANCE instance = GetModuleHandle(NULL);
+ string16 window_class = ASCIIToUTF16(kSessionNotificationWindowClass);
+
+ WNDCLASSEX wc = {0};
+ wc.cbSize = sizeof(wc);
+ wc.lpfnWndProc = base::win::WrappedWindowProc<SessionChangeNotificationProc>;
+ wc.hInstance = instance;
+ wc.lpszClassName = window_class.c_str();
+ atom = reinterpret_cast<LPCWSTR>(RegisterClassExW(&wc));
+ if (atom == NULL) {
+ LOG_GETLASTERROR(ERROR)
+ << "Failed to register the window class '"
+ << kSessionNotificationWindowClass << "'";
+ goto cleanup;
+ }
+
+ window = CreateWindowW(atom, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, instance, 0);
+ if (window == NULL) {
+ LOG_GETLASTERROR(ERROR)
+ << "Failed to creat the session notificationwindow";
+ goto cleanup;
+ }
+
+ // Post a dummy session change notification to peek up the current console
+ // session.
+ message_loop.PostTask(FROM_HERE, base::Bind(
+ &HostService::OnSessionChange, base::Unretained(this)));
+
+ // Subscribe to session change notifications.
+ if (WTSRegisterSessionNotification(window,
+ NOTIFY_FOR_ALL_SESSIONS) != FALSE) {
+ // Run the service.
+ RunMessageLoop();
+
+ WTSUnRegisterSessionNotification(window);
+ result = kSuccessExitCode;
+ }
+
+cleanup:
+ if (window != NULL) {
+ DestroyWindow(window);
+ }
+
+ if (atom != 0) {
+ UnregisterClass(atom, instance);
+ }
// 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
@@ -318,7 +421,7 @@ int HostService::RunInConsole() {
SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, FALSE);
message_loop_ = NULL;
- return kSuccessExitCode;
+ return result;
}
DWORD WINAPI HostService::ServiceControlHandler(DWORD control,
@@ -336,6 +439,11 @@ DWORD WINAPI HostService::ServiceControlHandler(DWORD control,
self->stopped_event_.Wait();
return NO_ERROR;
+ case SERVICE_CONTROL_SESSIONCHANGE:
+ self->message_loop_->PostTask(FROM_HERE, base::Bind(
+ &HostService::OnSessionChange, base::Unretained(self)));
+ return NO_ERROR;
+
default:
return ERROR_CALL_NOT_IMPLEMENTED;
}
@@ -365,7 +473,8 @@ VOID WINAPI HostService::ServiceMain(DWORD argc, WCHAR* argv[]) {
service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
service_status.dwCurrentState = SERVICE_RUNNING;
service_status.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN |
- SERVICE_ACCEPT_STOP;
+ SERVICE_ACCEPT_STOP |
+ SERVICE_ACCEPT_SESSIONCHANGE;
service_status.dwWin32ExitCode = kSuccessExitCode;
if (!SetServiceStatus(self->service_status_handle_, &service_status)) {
@@ -374,6 +483,11 @@ VOID WINAPI HostService::ServiceMain(DWORD argc, WCHAR* argv[]) {
return;
}
+ // Post a dummy session change notification to peek up the current console
+ // session.
+ message_loop.PostTask(FROM_HERE, base::Bind(
+ &HostService::OnSessionChange, base::Unretained(self)));
+
// Run the service.
self->RunMessageLoop();
@@ -390,6 +504,22 @@ VOID WINAPI HostService::ServiceMain(DWORD argc, WCHAR* argv[]) {
self->message_loop_ = NULL;
}
+LRESULT CALLBACK HostService::SessionChangeNotificationProc(HWND hwnd,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam) {
+ switch (message) {
+ case WM_WTSSESSION_CHANGE: {
+ HostService* self = HostService::GetInstance();
+ self->OnSessionChange();
+ return 0;
+ }
+
+ default:
+ return DefWindowProc(hwnd, message, wparam, lparam);
+ }
+}
+
} // namespace remoting
int main(int argc, char** argv) {
diff --git a/remoting/host/remoting_host_service_win.h b/remoting/host/remoting_host_service_win.h
index e1e59b2..0317f93 100644
--- a/remoting/host/remoting_host_service_win.h
+++ b/remoting/host/remoting_host_service_win.h
@@ -8,15 +8,20 @@
#include <windows.h>
#include "base/memory/singleton.h"
+#include "base/observer_list.h"
#include "base/string16.h"
#include "base/synchronization/waitable_event.h"
+#include "remoting/host/wts_console_monitor_win.h"
+
class CommandLine;
class MessageLoop;
namespace remoting {
-class HostService {
+class WtsConsoleObserver;
+
+class HostService : public WtsConsoleMonitor {
public:
static HostService* GetInstance();
@@ -26,10 +31,18 @@ class HostService {
// Invoke the choosen action routine.
int Run();
+ // WtsConsoleMonitor implementation
+ virtual void AddWtsConsoleObserver(WtsConsoleObserver* observer) OVERRIDE;
+ virtual void RemoveWtsConsoleObserver(
+ WtsConsoleObserver* observer) OVERRIDE;
+
private:
HostService();
~HostService();
+ // Notifies the service of changes in session state.
+ void OnSessionChange();
+
// This routine registers the service with the service control manager.
int Install();
@@ -60,6 +73,21 @@ class HostService {
// The main service entry point.
static VOID WINAPI ServiceMain(DWORD argc, WCHAR* argv[]);
+ static LRESULT CALLBACK SessionChangeNotificationProc(HWND hwnd,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam);
+
+ // Current physical console session id.
+ uint32 console_session_id_;
+
+ // The list of observers receiving notifications about any session attached
+ // to the physical console.
+ ObserverList<WtsConsoleObserver> console_observers_;
+
+ // Service message loop.
+ MessageLoop* message_loop_;
+
// The action routine to be executed.
int (HostService::*run_routine_)();
@@ -72,8 +100,8 @@ class HostService {
// The service status handle.
SERVICE_STATUS_HANDLE service_status_handle_;
- // Service message loop.
- MessageLoop* message_loop_;
+ // True if the service is being stopped.
+ bool shutting_down_;
// A waitable event that is used to wait until the service is stopped.
base::WaitableEvent stopped_event_;
diff --git a/remoting/host/wts_console_monitor_win.h b/remoting/host/wts_console_monitor_win.h
new file mode 100644
index 0000000..10a24da
--- /dev/null
+++ b/remoting/host/wts_console_monitor_win.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef REMOTING_HOST_WTS_CONSOLE_MONITOR_WIN_H_
+#define REMOTING_HOST_WTS_CONSOLE_MONITOR_WIN_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+
+namespace remoting {
+
+class WtsConsoleObserver;
+
+class WtsConsoleMonitor {
+ public:
+ virtual ~WtsConsoleMonitor() {}
+
+ // Registers an observer to receive notifications about a particular WTS
+ // console (i.e. the physical console or a remote console).
+ virtual void AddWtsConsoleObserver(WtsConsoleObserver* observer) = 0;
+
+ // Unregisters a previously registered observer.
+ virtual void RemoveWtsConsoleObserver(WtsConsoleObserver* observer) = 0;
+
+ protected:
+ WtsConsoleMonitor() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WtsConsoleMonitor);
+};
+
+} // namespace remoting
+
+#endif // REMOTING_HOST_WTS_CONSOLE_MONITOR_WIN_H_
diff --git a/remoting/host/wts_console_observer_win.h b/remoting/host/wts_console_observer_win.h
new file mode 100644
index 0000000..7f4d8475
--- /dev/null
+++ b/remoting/host/wts_console_observer_win.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef REMOTING_HOST_wts_console_observer_win_H_
+#define REMOTING_HOST_wts_console_observer_win_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+
+namespace remoting {
+
+// Provides callbacks for monitoring events on a WTS terminal.
+class WtsConsoleObserver {
+ public:
+ virtual ~WtsConsoleObserver() {}
+
+ // Called when |session_id| attaches to the console.
+ virtual void OnSessionAttached(uint32 session_id) = 0;
+
+ // Called when a session detaches from the console.
+ virtual void OnSessionDetached() = 0;
+
+ protected:
+ WtsConsoleObserver() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WtsConsoleObserver);
+};
+
+} // namespace remoting
+
+#endif // REMOTING_HOST_wts_console_observer_win_H_
diff --git a/remoting/host/wts_session_process_launcher_win.cc b/remoting/host/wts_session_process_launcher_win.cc
new file mode 100644
index 0000000..119b564
--- /dev/null
+++ b/remoting/host/wts_session_process_launcher_win.cc
@@ -0,0 +1,35 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This file implements the Windows service controlling Me2Me host processes
+// running within user sessions.
+
+#include "remoting/host/wts_session_process_launcher_win.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+
+#include "remoting/host/wts_console_monitor_win.h"
+
+namespace remoting {
+
+WtsSessionProcessLauncher::WtsSessionProcessLauncher(
+ WtsConsoleMonitor* monitor) : monitor_(monitor) {
+ monitor_->AddWtsConsoleObserver(this);
+}
+
+WtsSessionProcessLauncher::~WtsSessionProcessLauncher() {
+ monitor_->RemoveWtsConsoleObserver(this);
+}
+
+void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) {
+ // TODO(alexeypa): The code injecting the host process to a session goes here.
+}
+
+void WtsSessionProcessLauncher::OnSessionDetached() {
+ // TODO(alexeypa): The code terminating the host process goes here.
+}
+
+} // namespace remoting
diff --git a/remoting/host/wts_session_process_launcher_win.h b/remoting/host/wts_session_process_launcher_win.h
new file mode 100644
index 0000000..b1c9104
--- /dev/null
+++ b/remoting/host/wts_session_process_launcher_win.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef REMOTING_HOST_WTS_SESSION_PROCESS_LAUNCHER_WIN_H_
+#define REMOTING_HOST_WTS_SESSION_PROCESS_LAUNCHER_WIN_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+#include "remoting/host/wts_console_observer_win.h"
+
+namespace remoting {
+
+class WtsConsoleMonitor;
+
+class WtsSessionProcessLauncher : public WtsConsoleObserver {
+ public:
+ // Constructs a WtsSessionProcessLauncher object. |monitor| must outlive this
+ // class.
+ WtsSessionProcessLauncher(WtsConsoleMonitor* monitor);
+ virtual ~WtsSessionProcessLauncher();
+
+ // WtsConsoleObserver implementation
+ virtual void OnSessionAttached(uint32 session_id) OVERRIDE;
+ virtual void OnSessionDetached() OVERRIDE;
+
+ private:
+ WtsConsoleMonitor* monitor_;
+
+ DISALLOW_COPY_AND_ASSIGN(WtsSessionProcessLauncher);
+};
+
+} // namespace remoting
+
+#endif // REMOTING_HOST_WTS_SESSION_PROCESS_LAUNCHER_WIN_H_
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index 0ac2b50..6207cc7 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -236,7 +236,18 @@
'host/remoting_host_service_resource.h',
'host/remoting_host_service_win.cc',
'host/remoting_host_service_win.h',
+ 'host/wts_console_monitor_win.h',
+ 'host/wts_console_observer_win.h',
+ 'host/wts_session_process_launcher_win.cc',
+ 'host/wts_session_process_launcher_win.h',
],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'AdditionalDependencies': [
+ 'wtsapi32.lib',
+ ],
+ },
+ },
}, # end of target 'remoting_service'
],
}], # 'OS=="win"'