summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipc/ipc_message_utils.h1
-rw-r--r--remoting/host/chromoting_host_context.cc6
-rw-r--r--remoting/host/chromoting_host_context.h5
-rw-r--r--remoting/host/chromoting_host_context_unittest.cc3
-rw-r--r--remoting/host/chromoting_host_unittest.cc8
-rw-r--r--remoting/host/chromoting_messages.cc34
-rw-r--r--remoting/host/chromoting_messages.h17
-rw-r--r--remoting/host/desktop_environment.cc52
-rw-r--r--remoting/host/desktop_environment.h25
-rw-r--r--remoting/host/event_executor.h8
-rw-r--r--remoting/host/event_executor_linux.cc12
-rw-r--r--remoting/host/event_executor_mac.cc9
-rw-r--r--remoting/host/event_executor_win.cc9
-rw-r--r--remoting/host/host_mock_objects.cc2
-rw-r--r--remoting/host/host_mock_objects.h1
-rw-r--r--remoting/host/host_service_win.cc14
-rw-r--r--remoting/host/plugin/host_script_object.cc5
-rw-r--r--remoting/host/remoting_me2me_host.cc26
-rw-r--r--remoting/host/sas_injector.h28
-rw-r--r--remoting/host/sas_injector_win.cc186
-rw-r--r--remoting/host/session_event_executor_win.cc100
-rw-r--r--remoting/host/session_event_executor_win.h58
-rw-r--r--remoting/host/simple_host_process.cc15
-rw-r--r--remoting/host/wts_session_process_launcher_win.cc167
-rw-r--r--remoting/host/wts_session_process_launcher_win.h46
-rw-r--r--remoting/remoting.gyp31
26 files changed, 781 insertions, 87 deletions
diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h
index 912bc04..e8e3173 100644
--- a/ipc/ipc_message_utils.h
+++ b/ipc/ipc_message_utils.h
@@ -101,6 +101,7 @@ enum IPCMessageStart {
ShellMsgStart,
AccessibilityMsgStart,
PrerenderMsgStart,
+ ChromotingMsgStart,
LastIPCMsgStart // Must come last.
};
diff --git a/remoting/host/chromoting_host_context.cc b/remoting/host/chromoting_host_context.cc
index d66a4f2..783834f 100644
--- a/remoting/host/chromoting_host_context.cc
+++ b/remoting/host/chromoting_host_context.cc
@@ -13,10 +13,12 @@
namespace remoting {
ChromotingHostContext::ChromotingHostContext(
+ base::MessageLoopProxy* io_message_loop,
base::MessageLoopProxy* ui_message_loop)
: main_thread_("ChromotingMainThread"),
encode_thread_("ChromotingEncodeThread"),
desktop_thread_("ChromotingDesktopThread"),
+ io_message_loop_(io_message_loop),
ui_message_loop_(ui_message_loop) {
}
@@ -33,6 +35,10 @@ JingleThread* ChromotingHostContext::jingle_thread() {
return &jingle_thread_;
}
+base::MessageLoopProxy* ChromotingHostContext::io_message_loop() {
+ return io_message_loop_;
+}
+
base::MessageLoopProxy* ChromotingHostContext::ui_message_loop() {
return ui_message_loop_;
}
diff --git a/remoting/host/chromoting_host_context.h b/remoting/host/chromoting_host_context.h
index 92db811..d1b87ed 100644
--- a/remoting/host/chromoting_host_context.h
+++ b/remoting/host/chromoting_host_context.h
@@ -19,7 +19,8 @@ namespace remoting {
class ChromotingHostContext {
public:
// Create a context.
- explicit ChromotingHostContext(base::MessageLoopProxy* ui_message_loop);
+ ChromotingHostContext(base::MessageLoopProxy* io_message_loop,
+ base::MessageLoopProxy* ui_message_loop);
virtual ~ChromotingHostContext();
// TODO(ajwong): Move the Start method out of this class. Then
@@ -31,6 +32,7 @@ class ChromotingHostContext {
virtual JingleThread* jingle_thread();
+ virtual base::MessageLoopProxy* io_message_loop();
virtual base::MessageLoopProxy* ui_message_loop();
virtual MessageLoop* main_message_loop();
virtual MessageLoop* encode_message_loop();
@@ -53,6 +55,7 @@ class ChromotingHostContext {
// This is NOT a Chrome-style UI thread.
base::Thread desktop_thread_;
+ scoped_refptr<base::MessageLoopProxy> io_message_loop_;
scoped_refptr<base::MessageLoopProxy> ui_message_loop_;
DISALLOW_COPY_AND_ASSIGN(ChromotingHostContext);
diff --git a/remoting/host/chromoting_host_context_unittest.cc b/remoting/host/chromoting_host_context_unittest.cc
index 59a2ec5..2ada2ed 100644
--- a/remoting/host/chromoting_host_context_unittest.cc
+++ b/remoting/host/chromoting_host_context_unittest.cc
@@ -13,8 +13,7 @@ namespace remoting {
// operates properly and all threads and message loops are valid.
TEST(ChromotingHostContextTest, StartAndStop) {
MessageLoop message_loop;
- ChromotingHostContext context(
- base::MessageLoopProxy::current());
+ ChromotingHostContext context(NULL, base::MessageLoopProxy::current());
context.Start();
EXPECT_TRUE(context.jingle_thread());
diff --git a/remoting/host/chromoting_host_unittest.cc b/remoting/host/chromoting_host_unittest.cc
index 185be71..f04be7c 100644
--- a/remoting/host/chromoting_host_unittest.cc
+++ b/remoting/host/chromoting_host_unittest.cc
@@ -88,10 +88,12 @@ class ChromotingHostTest : public testing::Test {
EXPECT_CALL(context_, ui_message_loop())
.Times(AnyNumber());
- Capturer* capturer = new CapturerFake();
+ scoped_ptr<Capturer> capturer(new CapturerFake());
event_executor_ = new MockEventExecutor();
- desktop_environment_.reset(
- new DesktopEnvironment(&context_, capturer, event_executor_));
+ desktop_environment_ = DesktopEnvironment::CreateFake(
+ &context_,
+ capturer.Pass(),
+ scoped_ptr<protocol::InputStub>(event_executor_));
host_ = new ChromotingHost(
&context_, &signal_strategy_, desktop_environment_.get(),
diff --git a/remoting/host/chromoting_messages.cc b/remoting/host/chromoting_messages.cc
new file mode 100644
index 0000000..36c3cf4
--- /dev/null
+++ b/remoting/host/chromoting_messages.cc
@@ -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.
+
+// Get basic type definitions.
+#define IPC_MESSAGE_IMPL
+#include "remoting/host/chromoting_messages.h"
+
+// Generate constructors.
+#include "ipc/struct_constructor_macros.h"
+#include "remoting/host/chromoting_messages.h"
+
+// Generate destructors.
+#include "ipc/struct_destructor_macros.h"
+#include "remoting/host/chromoting_messages.h"
+
+// Generate param traits write methods.
+#include "ipc/param_traits_write_macros.h"
+namespace IPC {
+#include "remoting/host/chromoting_messages.h"
+} // namespace IPC
+
+// Generate param traits read methods.
+#include "ipc/param_traits_read_macros.h"
+namespace IPC {
+#include "remoting/host/chromoting_messages.h"
+} // namespace IPC
+
+// Generate param traits log methods.
+#include "ipc/param_traits_log_macros.h"
+namespace IPC {
+#include "remoting/host/chromoting_messages.h"
+} // namespace IPC
+
diff --git a/remoting/host/chromoting_messages.h b/remoting/host/chromoting_messages.h
new file mode 100644
index 0000000..0ec1339
--- /dev/null
+++ b/remoting/host/chromoting_messages.h
@@ -0,0 +1,17 @@
+// 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.
+
+// Defines IPC messages used by Chromoting components.
+
+// Multiply-included message file, no traditional include guard.
+#include "ipc/ipc_message_macros.h"
+
+#define IPC_MESSAGE_START ChromotingMsgStart
+
+//-----------------------------------------------------------------------------
+// The Chrmomoting session messages
+
+// Asks the service to send the Secure Attention Sequence (SAS) to the current
+// console session.
+IPC_MESSAGE_CONTROL0(ChromotingHostMsg_SendSasToConsole)
diff --git a/remoting/host/desktop_environment.cc b/remoting/host/desktop_environment.cc
index fbf4ffc..0007c8a 100644
--- a/remoting/host/desktop_environment.cc
+++ b/remoting/host/desktop_environment.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
@@ -11,31 +11,57 @@
#include "remoting/host/chromoting_host_context.h"
#include "remoting/host/event_executor.h"
+#if defined(OS_WIN)
+#include "remoting/host/session_event_executor_win.h"
+#endif
+
namespace remoting {
// static
-DesktopEnvironment* DesktopEnvironment::Create(ChromotingHostContext* context) {
+scoped_ptr<DesktopEnvironment> DesktopEnvironment::Create(
+ ChromotingHostContext* context) {
scoped_ptr<Capturer> capturer(Capturer::Create());
- scoped_ptr<EventExecutor> event_executor(
- EventExecutor::Create(context->desktop_message_loop(), capturer.get()));
+ scoped_ptr<protocol::InputStub> event_executor =
+ EventExecutor::Create(context->desktop_message_loop(),
+ capturer.get());
if (capturer.get() == NULL || event_executor.get() == NULL) {
LOG(ERROR) << "Unable to create DesktopEnvironment";
- return NULL;
+ return scoped_ptr<DesktopEnvironment>();
}
- return new DesktopEnvironment(context,
- capturer.release(),
- event_executor.release());
+#if defined(OS_WIN)
+ event_executor.reset(new SessionEventExecutorWin(
+ context->desktop_message_loop(),
+ context->io_message_loop(),
+ event_executor.Pass()));
+#endif
+
+ return scoped_ptr<DesktopEnvironment>(
+ new DesktopEnvironment(context,
+ capturer.Pass(),
+ event_executor.Pass()));
+}
+
+// static
+scoped_ptr<DesktopEnvironment> DesktopEnvironment::CreateFake(
+ ChromotingHostContext* context,
+ scoped_ptr<Capturer> capturer,
+ scoped_ptr<protocol::InputStub> event_executor) {
+ return scoped_ptr<DesktopEnvironment>(
+ new DesktopEnvironment(context,
+ capturer.Pass(),
+ event_executor.Pass()));
}
-DesktopEnvironment::DesktopEnvironment(ChromotingHostContext* context,
- Capturer* capturer,
- EventExecutor* event_executor)
+DesktopEnvironment::DesktopEnvironment(
+ ChromotingHostContext* context,
+ scoped_ptr<Capturer> capturer,
+ scoped_ptr<protocol::InputStub> event_executor)
: host_(NULL),
context_(context),
- capturer_(capturer),
- event_executor_(event_executor) {
+ capturer_(capturer.Pass()),
+ event_executor_(event_executor.Pass()) {
}
DesktopEnvironment::~DesktopEnvironment() {
diff --git a/remoting/host/desktop_environment.h b/remoting/host/desktop_environment.h
index f95089b..5573cfc 100644
--- a/remoting/host/desktop_environment.h
+++ b/remoting/host/desktop_environment.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
@@ -18,24 +18,31 @@ namespace remoting {
class Capturer;
class ChromotingHost;
class ChromotingHostContext;
-class EventExecutor;
+
+namespace protocol {
+class InputStub;
+};
class DesktopEnvironment {
public:
- static DesktopEnvironment* Create(ChromotingHostContext* context);
+ static scoped_ptr<DesktopEnvironment> Create(ChromotingHostContext* context);
+ static scoped_ptr<DesktopEnvironment> CreateFake(
+ ChromotingHostContext* context,
+ scoped_ptr<Capturer> capturer,
+ scoped_ptr<protocol::InputStub> event_executor);
- // DesktopEnvironment takes ownership of all the objects passed in.
- DesktopEnvironment(ChromotingHostContext* context,
- Capturer* capturer,
- EventExecutor* event_executor);
virtual ~DesktopEnvironment();
void set_host(ChromotingHost* host) { host_ = host; }
Capturer* capturer() const { return capturer_.get(); }
- EventExecutor* event_executor() const { return event_executor_.get(); }
+ protocol::InputStub* event_executor() const { return event_executor_.get(); }
private:
+ DesktopEnvironment(ChromotingHostContext* context,
+ scoped_ptr<Capturer> capturer,
+ scoped_ptr<protocol::InputStub> event_executor);
+
// The host that owns this DesktopEnvironment.
ChromotingHost* host_;
@@ -47,7 +54,7 @@ class DesktopEnvironment {
scoped_ptr<Capturer> capturer_;
// Executes input events received from the client.
- scoped_ptr<EventExecutor> event_executor_;
+ scoped_ptr<protocol::InputStub> event_executor_;
DISALLOW_COPY_AND_ASSIGN(DesktopEnvironment);
};
diff --git a/remoting/host/event_executor.h b/remoting/host/event_executor.h
index 6051b36..bcde0ba 100644
--- a/remoting/host/event_executor.h
+++ b/remoting/host/event_executor.h
@@ -1,10 +1,12 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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_EVENT_EXECUTOR_H_
#define REMOTING_HOST_EVENT_EXECUTOR_H_
+#include "base/memory/scoped_ptr.h"
+
#include "remoting/protocol/input_stub.h"
class MessageLoop;
@@ -17,8 +19,8 @@ class EventExecutor : public protocol::InputStub {
public:
// Creates default event executor for the current platform.
// Does not take ownership of |message_loop| or |capturer|.
- static EventExecutor* Create(MessageLoop* message_loop,
- Capturer* capturer);
+ static scoped_ptr<protocol::InputStub> Create(MessageLoop* message_loop,
+ Capturer* capturer);
};
} // namespace remoting
diff --git a/remoting/host/event_executor_linux.cc b/remoting/host/event_executor_linux.cc
index f2e68b8..7295c1a 100644
--- a/remoting/host/event_executor_linux.cc
+++ b/remoting/host/event_executor_linux.cc
@@ -426,14 +426,14 @@ void EventExecutorLinux::InjectMouseEvent(const MouseEvent& event) {
} // namespace
-EventExecutor* EventExecutor::Create(MessageLoop* message_loop,
- Capturer* capturer) {
- EventExecutorLinux* executor = new EventExecutorLinux(message_loop, capturer);
+scoped_ptr<protocol::InputStub> EventExecutor::Create(MessageLoop* message_loop,
+ Capturer* capturer) {
+ scoped_ptr<EventExecutorLinux> executor(
+ new EventExecutorLinux(message_loop, capturer));
if (!executor->Init()) {
- delete executor;
- executor = NULL;
+ executor.reset(NULL);
}
- return executor;
+ return executor.PassAs<protocol::InputStub>();
}
} // namespace remoting
diff --git a/remoting/host/event_executor_mac.cc b/remoting/host/event_executor_mac.cc
index cb65832..6ced472 100644
--- a/remoting/host/event_executor_mac.cc
+++ b/remoting/host/event_executor_mac.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
@@ -289,9 +289,10 @@ void EventExecutorMac::InjectMouseEvent(const MouseEvent& event) {
} // namespace
-EventExecutor* EventExecutor::Create(MessageLoop* message_loop,
- Capturer* capturer) {
- return new EventExecutorMac(message_loop, capturer);
+scoped_ptr<protocol::InputStub> EventExecutor::Create(MessageLoop* message_loop,
+ Capturer* capturer) {
+ return scoped_ptr<protocol::InputStub>(
+ new EventExecutorMac(message_loop, capturer));
}
} // namespace remoting
diff --git a/remoting/host/event_executor_win.cc b/remoting/host/event_executor_win.cc
index b1f5842..af66225 100644
--- a/remoting/host/event_executor_win.cc
+++ b/remoting/host/event_executor_win.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
@@ -167,9 +167,10 @@ void EventExecutorWin::HandleMouse(const MouseEvent& event) {
} // namespace
-EventExecutor* EventExecutor::Create(MessageLoop* message_loop,
- Capturer* capturer) {
- return new EventExecutorWin(message_loop, capturer);
+scoped_ptr<protocol::InputStub> EventExecutor::Create(MessageLoop* message_loop,
+ Capturer* capturer) {
+ return scoped_ptr<protocol::InputStub>(
+ new EventExecutorWin(message_loop, capturer));
}
} // namespace remoting
diff --git a/remoting/host/host_mock_objects.cc b/remoting/host/host_mock_objects.cc
index 2d34908..5144e7e 100644
--- a/remoting/host/host_mock_objects.cc
+++ b/remoting/host/host_mock_objects.cc
@@ -51,7 +51,7 @@ LocalInputMonitor* LocalInputMonitor::Create() {
}
MockChromotingHostContext::MockChromotingHostContext()
- : ChromotingHostContext(base::MessageLoopProxy::current()) {
+ : ChromotingHostContext(NULL, base::MessageLoopProxy::current()) {
}
MockChromotingHostContext::~MockChromotingHostContext() {}
diff --git a/remoting/host/host_mock_objects.h b/remoting/host/host_mock_objects.h
index 9136f3f..967613f 100644
--- a/remoting/host/host_mock_objects.h
+++ b/remoting/host/host_mock_objects.h
@@ -84,6 +84,7 @@ class MockChromotingHostContext : public ChromotingHostContext {
MOCK_METHOD0(Start, bool());
MOCK_METHOD0(Stop, void());
MOCK_METHOD0(jingle_thread, JingleThread*());
+ MOCK_METHOD0(io_message_loop, base::MessageLoopProxy*());
MOCK_METHOD0(ui_message_loop, base::MessageLoopProxy*());
MOCK_METHOD0(main_message_loop, MessageLoop*());
MOCK_METHOD0(encode_message_loop, MessageLoop*());
diff --git a/remoting/host/host_service_win.cc b/remoting/host/host_service_win.cc
index 66bfa09..a404e6e 100644
--- a/remoting/host/host_service_win.cc
+++ b/remoting/host/host_service_win.cc
@@ -20,6 +20,7 @@
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/stringprintf.h"
+#include "base/threading/thread.h"
#include "base/utf_string_conversions.h"
#include "base/win/wrapped_window_proc.h"
@@ -45,6 +46,8 @@ const DWORD kServiceStopTimeoutMs = 30 * 1000;
// Session id that does not represent any session.
const uint32 kInvalidSession = 0xffffffff;
+const char kIoThreadName[] = "I/O thread";
+
// A window class for the session change notifications window.
static const char kSessionNotificationWindowClass[] =
"Chromoting_SessionNotificationWindow";
@@ -351,7 +354,16 @@ int HostService::Run() {
}
void HostService::RunMessageLoop() {
- WtsSessionProcessLauncher launcher(this, host_binary_);
+ // Launch the I/O thread.
+ base::Thread io_thread(kIoThreadName);
+ base::Thread::Options io_thread_options(MessageLoop::TYPE_IO, 0);
+ if (!io_thread.StartWithOptions(io_thread_options)) {
+ shutting_down_ = true;
+ stopped_event_.Signal();
+ return;
+ }
+
+ WtsSessionProcessLauncher launcher(this, host_binary_, &io_thread);
// Run the service.
message_loop_->Run();
diff --git a/remoting/host/plugin/host_script_object.cc b/remoting/host/plugin/host_script_object.cc
index d25f89c..817e5a7 100644
--- a/remoting/host/plugin/host_script_object.cc
+++ b/remoting/host/plugin/host_script_object.cc
@@ -114,7 +114,8 @@ bool HostNPScriptObject::Init() {
DCHECK(plugin_message_loop_proxy_->BelongsToCurrentThread());
VLOG(2) << "Init";
- host_context_.reset(new ChromotingHostContext(plugin_message_loop_proxy_));
+ host_context_.reset(new ChromotingHostContext(NULL,
+ plugin_message_loop_proxy_));
if (!host_context_->Start()) {
host_context_.reset();
return false;
@@ -464,7 +465,7 @@ void HostNPScriptObject::FinishConnectMainThread(
// TODO(sergeyu): Fix DesktopEnvironment so that it can be created
// on either the UI or the network thread so that we can avoid
// jumping to the main thread here.
- desktop_environment_.reset(DesktopEnvironment::Create(host_context_.get()));
+ desktop_environment_ = DesktopEnvironment::Create(host_context_.get());
FinishConnectNetworkThread(uid, auth_token, auth_service);
}
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc
index d0479c7..0440303 100644
--- a/remoting/host/remoting_me2me_host.cc
+++ b/remoting/host/remoting_me2me_host.cc
@@ -18,6 +18,7 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/threading/thread.h"
@@ -85,12 +86,15 @@ class HostProcess {
HostProcess()
: message_loop_(MessageLoop::TYPE_UI),
file_io_thread_("FileIO"),
- context_(message_loop_.message_loop_proxy()),
allow_nat_traversal_(true),
restarting_(false) {
- context_.Start();
file_io_thread_.StartWithOptions(
base::Thread::Options(MessageLoop::TYPE_IO, 0));
+
+ context_.reset(new ChromotingHostContext(
+ file_io_thread_.message_loop_proxy(),
+ message_loop_.message_loop_proxy()));
+ context_->Start();
network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
}
@@ -187,8 +191,8 @@ class HostProcess {
}
void OnNatPolicyUpdate(bool nat_traversal_enabled) {
- if (!context_.network_message_loop()->BelongsToCurrentThread()) {
- context_.network_message_loop()->PostTask(FROM_HERE, base::Bind(
+ if (!context_->network_message_loop()->BelongsToCurrentThread()) {
+ context_->network_message_loop()->PostTask(FROM_HERE, base::Bind(
&HostProcess::OnNatPolicyUpdate, base::Unretained(this),
nat_traversal_enabled));
return;
@@ -209,19 +213,19 @@ class HostProcess {
}
void StartHost() {
- DCHECK(context_.network_message_loop()->BelongsToCurrentThread());
+ DCHECK(context_->network_message_loop()->BelongsToCurrentThread());
DCHECK(!host_);
if (!signal_strategy_.get()) {
signal_strategy_.reset(
- new XmppSignalStrategy(context_.jingle_thread(), xmpp_login_,
+ new XmppSignalStrategy(context_->jingle_thread(), xmpp_login_,
xmpp_auth_token_, xmpp_auth_service_));
signaling_connector_.reset(
new SignalingConnector(signal_strategy_.get()));
}
if (!desktop_environment_.get())
- desktop_environment_.reset(DesktopEnvironment::Create(&context_));
+ desktop_environment_ = DesktopEnvironment::Create(context_.get());
protocol::NetworkSettings network_settings(allow_nat_traversal_);
if (!allow_nat_traversal_) {
@@ -230,7 +234,7 @@ class HostProcess {
}
host_ = new ChromotingHost(
- &context_, signal_strategy_.get(), desktop_environment_.get(),
+ context_.get(), signal_strategy_.get(), desktop_environment_.get(),
network_settings);
heartbeat_sender_.reset(
@@ -251,7 +255,7 @@ class HostProcess {
}
void RestartHost() {
- DCHECK(context_.network_message_loop()->BelongsToCurrentThread());
+ DCHECK(context_->network_message_loop()->BelongsToCurrentThread());
if (restarting_)
return;
@@ -262,7 +266,7 @@ class HostProcess {
}
void RestartOnHostShutdown() {
- DCHECK(context_.network_message_loop()->BelongsToCurrentThread());
+ DCHECK(context_->network_message_loop()->BelongsToCurrentThread());
restarting_ = false;
@@ -276,7 +280,7 @@ class HostProcess {
MessageLoop message_loop_;
base::Thread file_io_thread_;
- ChromotingHostContext context_;
+ scoped_ptr<ChromotingHostContext> context_;
scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
FilePath auth_config_path_;
diff --git a/remoting/host/sas_injector.h b/remoting/host/sas_injector.h
new file mode 100644
index 0000000..2e3baaa
--- /dev/null
+++ b/remoting/host/sas_injector.h
@@ -0,0 +1,28 @@
+// 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_SAS_INJECTOR_H_
+#define REMOTING_HOST_SAS_INJECTOR_H_
+
+#include "base/memory/scoped_ptr.h"
+
+namespace remoting {
+
+// Provides a way to simulate a Secure Attention Sequence (SAS). The default
+// sequence is Ctrl+Alt+Delete.
+class SasInjector {
+ public:
+ virtual ~SasInjector() {}
+
+ // Sends the Secure Attention Sequence to the console session.
+ virtual bool InjectSas() = 0;
+
+ // Creates an instance of SasInjector if supported by the OS, otherwise
+ // returns NULL.
+ static scoped_ptr<SasInjector> Create();
+};
+
+} // namespace remoting
+
+#endif REMOTING_HOST_SAS_INJECTOR_H_
diff --git a/remoting/host/sas_injector_win.cc b/remoting/host/sas_injector_win.cc
new file mode 100644
index 0000000..3dd55f1
--- /dev/null
+++ b/remoting/host/sas_injector_win.cc
@@ -0,0 +1,186 @@
+// 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.
+
+#include "remoting/host/sas_injector.h"
+
+#include <windows.h>
+#include <string>
+
+#include "base/logging.h"
+#include "base/file_path.h"
+#include "base/native_library.h"
+#include "base/path_service.h"
+#include "base/utf_string_conversions.h"
+#include "base/win/registry.h"
+#include "base/win/windows_version.h"
+
+namespace remoting {
+
+namespace {
+
+// Names of the API and library implementing software SAS generation.
+const FilePath::CharType kSasDllFileName[] =
+ FILE_PATH_LITERAL("sas.dll");
+const char kSendSasName[] = "SendSAS";
+
+// The prototype of SendSAS().
+typedef VOID (WINAPI *SendSasFunc)(BOOL);
+
+// The registry key and value holding the policy controlling software SAS
+// generation.
+const char kSystemPolicyKeyName[] =
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System";
+const char kSoftwareSasValueName[] = "SoftwareSASGeneration";
+
+const DWORD kEnableSoftwareSasByServices = 1;
+
+// Toggles the default software SAS generation policy to enable SAS generation
+// by services. Non-default policy is not changed.
+class ScopedSoftwareSasPolicy {
+ public:
+ ScopedSoftwareSasPolicy();
+ ~ScopedSoftwareSasPolicy();
+
+ bool Apply();
+
+ private:
+ // The handle of the registry key were SoftwareSASGeneration policy is stored.
+ base::win::RegKey system_policy_;
+
+ // Name of the registry value holding the policy.
+ string16 value_name_;
+
+ // True if the policy needs to be restored.
+ bool restore_policy_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedSoftwareSasPolicy);
+};
+
+ScopedSoftwareSasPolicy::ScopedSoftwareSasPolicy()
+ : restore_policy_(false) {
+}
+
+ScopedSoftwareSasPolicy::~ScopedSoftwareSasPolicy() {
+ // Restore the default policy by deleting the value that we have set.
+ if (restore_policy_) {
+ LONG result = system_policy_.DeleteValue(value_name_.c_str());
+ if (result != ERROR_SUCCESS) {
+ SetLastError(result);
+ LOG_GETLASTERROR(ERROR)
+ << "Failed to restore the software SAS generation policy";
+ }
+ }
+}
+
+bool ScopedSoftwareSasPolicy::Apply() {
+ // Query the currently set SoftwareSASGeneration policy.
+ LONG result = system_policy_.Open(HKEY_LOCAL_MACHINE,
+ ASCIIToUTF16(kSystemPolicyKeyName).c_str(),
+ KEY_QUERY_VALUE | KEY_SET_VALUE |
+ KEY_WOW64_64KEY);
+ if (result != ERROR_SUCCESS) {
+ SetLastError(result);
+ LOG_GETLASTERROR(ERROR) << "Failed to open 'HKLM\\"
+ << kSystemPolicyKeyName << "'";
+ return false;
+ }
+
+ value_name_ = ASCIIToUTF16(kSoftwareSasValueName);
+ bool custom_policy = system_policy_.HasValue(value_name_.c_str());
+
+ // Override the default policy (i.e. there is no value in the registry) only.
+ if (!custom_policy) {
+ result = system_policy_.WriteValue(value_name_.c_str(),
+ kEnableSoftwareSasByServices);
+ if (result != ERROR_SUCCESS) {
+ SetLastError(result);
+ LOG_GETLASTERROR(ERROR)
+ << "Failed to enable software SAS generation by services";
+ return false;
+ } else {
+ restore_policy_ = true;
+ }
+ }
+
+ return true;
+}
+
+} // namespace
+
+// Sends the Secure Attention Sequence using the SendSAS() function from
+// sas.dll. This library is shipped starting from Win7/W2K8 R2 only. However
+// Win7 SDK includes a redistributable verion of the same library that works on
+// Vista/W2K8. We install the latter along with our binaries.
+class SasInjectorWin : public SasInjector {
+ public:
+ SasInjectorWin();
+ virtual ~SasInjectorWin();
+
+ // SasInjector implementation.
+ virtual bool InjectSas() OVERRIDE;
+
+ private:
+ base::NativeLibrary sas_dll_;
+ SendSasFunc send_sas_;
+};
+
+SasInjectorWin::SasInjectorWin() : sas_dll_(NULL), send_sas_(NULL) {
+}
+
+SasInjectorWin::~SasInjectorWin() {
+ if (sas_dll_ != NULL) {
+ base::UnloadNativeLibrary(sas_dll_);
+ }
+}
+
+bool SasInjectorWin::InjectSas() {
+ // Load sas.dll. The library is expected to be in the same folder as this
+ // binary.
+ if (sas_dll_ == NULL) {
+ FilePath exe_path;
+ if (!PathService::Get(base::FILE_EXE, &exe_path)) {
+ LOG(ERROR) << "Failed to get the executable file name.";
+ return false;
+ }
+
+ std::string error;
+ sas_dll_ = base::LoadNativeLibrary(
+ exe_path.DirName().Append(kSasDllFileName),
+ &error);
+ if (sas_dll_ == NULL) {
+ LOG(ERROR) << "Failed to load '" << kSasDllFileName << "'";
+ return false;
+ }
+ }
+
+ // Get the pointer to sas!SendSAS().
+ if (send_sas_ == NULL) {
+ send_sas_ = reinterpret_cast<SendSasFunc>(
+ base::GetFunctionPointerFromNativeLibrary(sas_dll_, kSendSasName));
+ if (send_sas_ == NULL) {
+ LOG(ERROR) << "Failed to retrieve the address of '" << kSendSasName
+ << "()'";
+ return false;
+ }
+ }
+
+ // Enable software SAS generation by services and send SAS. SAS can still fail
+ // if the policy does not allow services to generate software SAS.
+ ScopedSoftwareSasPolicy enable_sas;
+ if (!enable_sas.Apply())
+ return false;
+
+ (*send_sas_)(FALSE);
+ return true;
+}
+
+scoped_ptr<SasInjector> SasInjector::Create() {
+ if (base::win::OSInfo::GetInstance()->version() >= base::win::VERSION_VISTA) {
+ return scoped_ptr<SasInjector>(new SasInjectorWin());
+ }
+
+ return scoped_ptr<SasInjector>();
+}
+
+} // namespace remoting
diff --git a/remoting/host/session_event_executor_win.cc b/remoting/host/session_event_executor_win.cc
new file mode 100644
index 0000000..36e5056
--- /dev/null
+++ b/remoting/host/session_event_executor_win.cc
@@ -0,0 +1,100 @@
+// 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.
+
+#include "remoting/host/session_event_executor_win.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/message_loop.h"
+#include "ipc/ipc_channel.h"
+#include "ipc/ipc_channel_proxy.h"
+#include "remoting/proto/event.pb.h"
+#include "ui/base/keycodes/keyboard_codes.h"
+
+#include "remoting/host/chromoting_messages.h"
+
+namespace {
+
+// The command line switch specifying the name of the session IPC channel.
+const char kProcessChannelId[] = "channel";
+
+} // namespace
+
+namespace remoting {
+
+using protocol::MouseEvent;
+using protocol::KeyEvent;
+
+SessionEventExecutorWin::SessionEventExecutorWin(
+ MessageLoop* message_loop,
+ base::MessageLoopProxy* io_message_loop,
+ scoped_ptr<protocol::InputStub> nested_executor)
+ : nested_executor_(nested_executor.Pass()),
+ message_loop_(message_loop),
+ scroll_pressed_(false) {
+ std::string channel_name =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(kProcessChannelId);
+
+ // Connect to the Chromoting IPC channel if the name was passed in the command
+ // line.
+ if (!channel_name.empty()) {
+ chromoting_channel_.reset(new IPC::ChannelProxy(
+ channel_name,
+ IPC::Channel::MODE_CLIENT,
+ this,
+ io_message_loop));
+ }
+}
+
+SessionEventExecutorWin::~SessionEventExecutorWin() {
+}
+
+void SessionEventExecutorWin::InjectKeyEvent(const KeyEvent& event) {
+ if (MessageLoop::current() != message_loop_) {
+ message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&SessionEventExecutorWin::InjectKeyEvent,
+ base::Unretained(this), event));
+ return;
+ }
+
+ // Poor man's Ctrl+Alt+Delete emulation: a double Scroll Lock is converted to
+ // the Secure Attention Sequence.
+ // TODO(alexeypa): replace this with proper SAS handling.
+ if (chromoting_channel_.get() != NULL && event.keycode() == VK_SCROLL) {
+ if (event.pressed()) {
+ if (scroll_pressed_) {
+ chromoting_channel_->Send(new ChromotingHostMsg_SendSasToConsole());
+ scroll_pressed_ = false;
+ } else {
+ scroll_pressed_ = true;
+ }
+ }
+ } else {
+ scroll_pressed_ = false;
+ }
+
+ nested_executor_->InjectKeyEvent(event);
+}
+
+void SessionEventExecutorWin::InjectMouseEvent(const MouseEvent& event) {
+ if (MessageLoop::current() != message_loop_) {
+ message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&SessionEventExecutorWin::InjectMouseEvent,
+ base::Unretained(this), event));
+ return;
+ }
+
+ nested_executor_->InjectMouseEvent(event);
+}
+
+bool SessionEventExecutorWin::OnMessageReceived(const IPC::Message& message) {
+ return false;
+}
+
+} // namespace remoting
diff --git a/remoting/host/session_event_executor_win.h b/remoting/host/session_event_executor_win.h
new file mode 100644
index 0000000..3e33c44
--- /dev/null
+++ b/remoting/host/session_event_executor_win.h
@@ -0,0 +1,58 @@
+// 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_SESSION_EVENT_EXECUTOR_WIN_H_
+#define REMOTING_HOST_SESSION_EVENT_EXECUTOR_WIN_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "ipc/ipc_channel.h"
+
+#include "remoting/host/event_executor.h"
+#include "remoting/protocol/input_stub.h"
+
+class MessageLoop;
+
+namespace base {
+class MessageLoopProxy;
+} // namespace base
+
+namespace IPC {
+class ChannelProxy;
+} // namespace IPC
+
+namespace remoting {
+
+class SessionEventExecutorWin : public protocol::InputStub,
+ public IPC::Channel::Listener {
+ public:
+ SessionEventExecutorWin(MessageLoop* message_loop,
+ base::MessageLoopProxy* io_message_loop,
+ scoped_ptr<protocol::InputStub> nested_executor);
+ ~SessionEventExecutorWin();
+
+ // protocol::InputStub implementation.
+ virtual void InjectKeyEvent(const protocol::KeyEvent& event) OVERRIDE;
+ virtual void InjectMouseEvent(const protocol::MouseEvent& event) OVERRIDE;
+
+ // IPC::Channel::Listener implementation.
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+ private:
+ // Pointer to the next event executor.
+ scoped_ptr<protocol::InputStub> nested_executor_;
+
+ MessageLoop* message_loop_;
+
+ // The Chromoting IPC channel connecting the host with the service.
+ scoped_ptr<IPC::ChannelProxy> chromoting_channel_;
+
+ bool scroll_pressed_;
+
+ DISALLOW_COPY_AND_ASSIGN(SessionEventExecutorWin);
+};
+
+} // namespace remoting
+
+#endif // REMOTING_HOST_SESSION_EVENT_EXECUTOR_WIN_H_
diff --git a/remoting/host/simple_host_process.cc b/remoting/host/simple_host_process.cc
index ad454ae..16ed0a1 100644
--- a/remoting/host/simple_host_process.cc
+++ b/remoting/host/simple_host_process.cc
@@ -94,7 +94,7 @@ class SimpleHost {
SimpleHost()
: message_loop_(MessageLoop::TYPE_UI),
file_io_thread_("FileIO"),
- context_(message_loop_.message_loop_proxy()),
+ context_(NULL, message_loop_.message_loop_proxy()),
fake_(false),
is_it2me_(false) {
context_.Start();
@@ -215,13 +215,14 @@ class SimpleHost {
signaling_connector_.reset(new SignalingConnector(signal_strategy_.get()));
if (fake_) {
- Capturer* capturer = new CapturerFake();
- EventExecutor* event_executor =
- EventExecutor::Create(context_.desktop_message_loop(), capturer);
- desktop_environment_.reset(
- new DesktopEnvironment(&context_, capturer, event_executor));
+ scoped_ptr<Capturer> capturer(new CapturerFake());
+ scoped_ptr<protocol::InputStub> event_executor =
+ EventExecutor::Create(
+ context_.desktop_message_loop(), capturer.get());
+ desktop_environment_ = DesktopEnvironment::CreateFake(
+ &context_, capturer.Pass(), event_executor.Pass());
} else {
- desktop_environment_.reset(DesktopEnvironment::Create(&context_));
+ desktop_environment_ = DesktopEnvironment::Create(&context_);
}
host_ = new ChromotingHost(&context_, signal_strategy_.get(),
diff --git a/remoting/host/wts_session_process_launcher_win.cc b/remoting/host/wts_session_process_launcher_win.cc
index c5e42da..fa8b2b2 100644
--- a/remoting/host/wts_session_process_launcher_win.cc
+++ b/remoting/host/wts_session_process_launcher_win.cc
@@ -8,11 +8,23 @@
#include "remoting/host/wts_session_process_launcher_win.h"
#include <windows.h>
+#include <sddl.h>
+#include <limits>
#include "base/logging.h"
+#include "base/process_util.h"
+#include "base/rand_util.h"
+#include "base/string16.h"
+#include "base/stringprintf.h"
+#include "base/threading/thread.h"
#include "base/utf_string_conversions.h"
#include "base/win/scoped_handle.h"
+#include "ipc/ipc_channel_proxy.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_macros.h"
+#include "remoting/host/chromoting_messages.h"
+#include "remoting/host/sas_injector.h"
#include "remoting/host/wts_console_monitor_win.h"
using base::win::ScopedHandle;
@@ -28,6 +40,17 @@ const int kMinLaunchDelaySeconds = 1;
// Name of the default session desktop.
const char kDefaultDesktopName[] = "winsta0\\default";
+// Match the pipe name prefix used by Chrome IPC channels.
+const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome.";
+
+// Generates the command line of the host process.
+const char kHostProcessCommandLineFormat[] = "\"%ls\" --channel=%ls";
+
+// The security descriptor of the Chromoting IPC channel. It gives full access
+// to LocalSystem and denies access by anyone else.
+const char kChromotingChannelSecurityDescriptor[] =
+ "O:SY" "G:SY" "D:(A;;GA;;;SY)";
+
// Takes the process token and makes a copy of it. The returned handle will have
// |desired_access| rights.
bool CopyProcessToken(DWORD desired_access,
@@ -114,11 +137,74 @@ bool CreateSessionToken(uint32 session_id,
return true;
}
+// Generates random channel ID.
+// N.B. Stolen from src/content/common/child_process_host_impl.cc
+string16 GenerateRandomChannelId(void* instance) {
+ return base::StringPrintf(ASCIIToUTF16("%d.%p.%d").c_str(),
+ base::GetCurrentProcId(), instance,
+ base::RandInt(0, std::numeric_limits<int>::max()));
+}
+
+// Creates the server end of the Chromoting IPC channel.
+// N.B. This code is based on IPC::Channel's implementation.
+bool CreatePipeForIpcChannel(void* instance,
+ string16* channel_name_out,
+ ScopedHandle* pipe_out) {
+ // Create security descriptor for the channel.
+ SECURITY_ATTRIBUTES security_attributes;
+ security_attributes.nLength = sizeof(security_attributes);
+ security_attributes.bInheritHandle = FALSE;
+
+ ULONG security_descriptor_length = 0;
+ if (!ConvertStringSecurityDescriptorToSecurityDescriptorA(
+ kChromotingChannelSecurityDescriptor,
+ SDDL_REVISION_1,
+ reinterpret_cast<PSECURITY_DESCRIPTOR*>(
+ &security_attributes.lpSecurityDescriptor),
+ &security_descriptor_length)) {
+ LOG_GETLASTERROR(ERROR) <<
+ "Failed to create a security descriptor for the Chromoting IPC channel";
+ return false;
+ }
+
+ // Generate a random channel name.
+ string16 channel_name(GenerateRandomChannelId(instance));
+
+ // Convert it to the pipe name.
+ string16 pipe_name(ASCIIToUTF16(kChromePipeNamePrefix));
+ pipe_name.append(channel_name);
+
+ // Create the server end of the pipe. This code should match the code in
+ // IPC::Channel with exception of passing a non-default security descriptor.
+ HANDLE pipe = CreateNamedPipeW(pipe_name.c_str(),
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
+ FILE_FLAG_FIRST_PIPE_INSTANCE,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
+ 1,
+ IPC::Channel::kReadBufferSize,
+ IPC::Channel::kReadBufferSize,
+ 5000,
+ &security_attributes);
+ if (pipe == INVALID_HANDLE_VALUE) {
+ LOG_GETLASTERROR(ERROR) <<
+ "Failed to create the server end of the Chromoting IPC channel";
+ LocalFree(security_attributes.lpSecurityDescriptor);
+ return false;
+ }
+
+ LocalFree(security_attributes.lpSecurityDescriptor);
+
+ *channel_name_out = channel_name;
+ pipe_out->Set(pipe);
+ return true;
+}
+
// Launches |binary| in the security context of the supplied |user_token|.
bool LaunchProcessAsUser(const FilePath& binary,
+ const string16& command_line,
HANDLE user_token,
base::Process* process_out) {
- string16 command_line = binary.value();
+ string16 application_name = binary.value();
string16 desktop = ASCIIToUTF16(kDefaultDesktopName);
PROCESS_INFORMATION process_info;
@@ -129,7 +215,7 @@ bool LaunchProcessAsUser(const FilePath& binary,
startup_info.lpDesktop = const_cast<LPWSTR>(desktop.c_str());
if (!CreateProcessAsUserW(user_token,
- command_line.c_str(),
+ application_name.c_str(),
const_cast<LPWSTR>(command_line.c_str()),
NULL,
NULL,
@@ -155,8 +241,10 @@ namespace remoting {
WtsSessionProcessLauncher::WtsSessionProcessLauncher(
WtsConsoleMonitor* monitor,
- const FilePath& host_binary)
+ const FilePath& host_binary,
+ base::Thread* io_thread)
: host_binary_(host_binary),
+ io_thread_(io_thread),
monitor_(monitor),
state_(StateDetached) {
monitor_->AddWtsConsoleObserver(this);
@@ -167,6 +255,7 @@ WtsSessionProcessLauncher::~WtsSessionProcessLauncher() {
DCHECK(!timer_.IsRunning());
DCHECK(process_.handle() == NULL);
DCHECK(process_watcher_.GetWatchedObject() == NULL);
+ DCHECK(chromoting_channel_.get() == NULL);
monitor_->RemoveWtsConsoleObserver(this);
}
@@ -176,19 +265,40 @@ void WtsSessionProcessLauncher::LaunchProcess() {
DCHECK(!timer_.IsRunning());
DCHECK(process_.handle() == NULL);
DCHECK(process_watcher_.GetWatchedObject() == NULL);
+ DCHECK(chromoting_channel_.get() == NULL);
- // Try to launch the process and attach an object watcher to the returned
- // handle so that we get notified when the process terminates.
launch_time_ = base::Time::Now();
- if (LaunchProcessAsUser(host_binary_, session_token_, &process_)) {
- if (process_watcher_.StartWatching(process_.handle(), this)) {
- state_ = StateAttached;
- return;
- } else {
- LOG(ERROR) << "Failed to arm the process watcher.";
- process_.Terminate(0);
- process_.Close();
+
+ string16 channel_name;
+ ScopedHandle pipe;
+ if (CreatePipeForIpcChannel(this, &channel_name, &pipe)) {
+ // Wrap the pipe into an IPC channel.
+ chromoting_channel_.reset(new IPC::ChannelProxy(
+ IPC::ChannelHandle(pipe.Get()),
+ IPC::Channel::MODE_SERVER,
+ this,
+ io_thread_->message_loop_proxy().get()));
+
+ string16 command_line =
+ base::StringPrintf(ASCIIToUTF16(kHostProcessCommandLineFormat).c_str(),
+ host_binary_.value().c_str(),
+ channel_name.c_str());
+
+ // Try to launch the process and attach an object watcher to the returned
+ // handle so that we get notified when the process terminates.
+ if (LaunchProcessAsUser(host_binary_, command_line, session_token_,
+ &process_)) {
+ if (process_watcher_.StartWatching(process_.handle(), this)) {
+ state_ = StateAttached;
+ return;
+ } else {
+ LOG(ERROR) << "Failed to arm the process watcher.";
+ process_.Terminate(0);
+ process_.Close();
+ }
}
+
+ chromoting_channel_.reset();
}
// Something went wrong. Try to launch the host again later. The attempts rate
@@ -206,10 +316,12 @@ void WtsSessionProcessLauncher::OnObjectSignaled(HANDLE object) {
DCHECK(!timer_.IsRunning());
DCHECK(process_.handle() != NULL);
DCHECK(process_watcher_.GetWatchedObject() == NULL);
+ DCHECK(chromoting_channel_.get() != NULL);
// The host process has been terminated for some reason. The handle can now be
// closed.
process_.Close();
+ chromoting_channel_.reset();
// Expand the backoff interval if the process has died quickly or reset it if
// it was up longer than the maximum backoff delay.
@@ -230,11 +342,34 @@ void WtsSessionProcessLauncher::OnObjectSignaled(HANDLE object) {
this, &WtsSessionProcessLauncher::LaunchProcess);
}
+bool WtsSessionProcessLauncher::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(WtsSessionProcessLauncher, message)
+ IPC_MESSAGE_HANDLER(ChromotingHostMsg_SendSasToConsole,
+ OnSendSasToConsole)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void WtsSessionProcessLauncher::OnSendSasToConsole() {
+ if (state_ == StateAttached) {
+ if (sas_injector_.get() == NULL) {
+ sas_injector_ = SasInjector::Create();
+ }
+
+ if (sas_injector_.get() != NULL) {
+ sas_injector_->InjectSas();
+ }
+ }
+}
+
void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) {
DCHECK(state_ == StateDetached);
DCHECK(!timer_.IsRunning());
DCHECK(process_.handle() == NULL);
DCHECK(process_watcher_.GetWatchedObject() == NULL);
+ DCHECK(chromoting_channel_.get() == NULL);
// Temporarily enable the SE_TCB_NAME privilege. The privileged token is
// created as needed and kept for later reuse.
@@ -250,7 +385,7 @@ void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) {
return;
}
- // While the SE_TCB_NAME progolege is enabled, create a session token for
+ // While the SE_TCB_NAME privilege is enabled, create a session token for
// the launched process.
bool result = CreateSessionToken(session_id, &session_token_);
@@ -276,12 +411,14 @@ void WtsSessionProcessLauncher::OnSessionDetached() {
DCHECK(!timer_.IsRunning());
DCHECK(process_.handle() == NULL);
DCHECK(process_watcher_.GetWatchedObject() == NULL);
+ DCHECK(chromoting_channel_.get() == NULL);
break;
case StateStarting:
DCHECK(timer_.IsRunning());
DCHECK(process_.handle() == NULL);
DCHECK(process_watcher_.GetWatchedObject() == NULL);
+ DCHECK(chromoting_channel_.get() == NULL);
timer_.Stop();
launch_backoff_ = base::TimeDelta();
@@ -292,10 +429,12 @@ void WtsSessionProcessLauncher::OnSessionDetached() {
DCHECK(!timer_.IsRunning());
DCHECK(process_.handle() != NULL);
DCHECK(process_watcher_.GetWatchedObject() != NULL);
+ DCHECK(chromoting_channel_.get() != NULL);
process_watcher_.StopWatching();
process_.Terminate(0);
process_.Close();
+ chromoting_channel_.reset();
state_ = StateDetached;
break;
}
diff --git a/remoting/host/wts_session_process_launcher_win.h b/remoting/host/wts_session_process_launcher_win.h
index eaf9c67..efcb93a 100644
--- a/remoting/host/wts_session_process_launcher_win.h
+++ b/remoting/host/wts_session_process_launcher_win.h
@@ -15,29 +15,49 @@
#include "base/timer.h"
#include "base/win/scoped_handle.h"
#include "base/win/object_watcher.h"
+#include "ipc/ipc_channel.h"
#include "remoting/host/wts_console_observer_win.h"
+namespace base {
+
+class Thread;
+
+} // namespace base
+
+namespace IPC {
+
+class ChannelProxy;
+class Message;
+
+} // namespace IPC
+
namespace remoting {
+class SasInjector;
class WtsConsoleMonitor;
class WtsSessionProcessLauncher
: public base::win::ObjectWatcher::Delegate,
+ public IPC::Channel::Listener,
public WtsConsoleObserver {
public:
- // Constructs a WtsSessionProcessLauncher object. |monitor| must outlive this
- // class. |host_binary| is the name of the executable to be launched in
- // the console session.
+ // Constructs a WtsSessionProcessLauncher object. |monitor| and |io_thread|
+ // must outlive this object. |host_binary| is the name of the executable to
+ // be launched in the console session.
WtsSessionProcessLauncher(WtsConsoleMonitor* monitor,
- const FilePath& host_binary);
+ const FilePath& host_binary,
+ base::Thread* io_thread);
virtual ~WtsSessionProcessLauncher();
- // base::win::ObjectWatcher::Delegate implementation
+ // base::win::ObjectWatcher::Delegate implementation.
virtual void OnObjectSignaled(HANDLE object) OVERRIDE;
- // WtsConsoleObserver implementation
+ // IPC::Channel::Listener implementation.
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+ // WtsConsoleObserver implementation.
virtual void OnSessionAttached(uint32 session_id) OVERRIDE;
virtual void OnSessionDetached() OVERRIDE;
@@ -47,6 +67,10 @@ class WtsSessionProcessLauncher
// reason.
void LaunchProcess();
+ // Sends the Secure Attention Sequence to the session represented by
+ // |session_token_|.
+ void OnSendSasToConsole();
+
// Name of the host executable.
FilePath host_binary_;
@@ -59,6 +83,10 @@ class WtsSessionProcessLauncher
// Timer used to schedule the next attempt to launch the process.
base::OneShotTimer<WtsSessionProcessLauncher> timer_;
+ // The I/O thread hosts the Chromoting IPC channel and any other code
+ // requiring an I/O message loop.
+ base::Thread* io_thread_;
+
// This pointer is used to unsubscribe from session attach and detach events.
WtsConsoleMonitor* monitor_;
@@ -84,6 +112,12 @@ class WtsSessionProcessLauncher
// Current state of the process launcher.
State state_;
+ // The Chromoting IPC channel connecting the service to the per-session
+ // process.
+ scoped_ptr<IPC::ChannelProxy> chromoting_channel_;
+
+ scoped_ptr<SasInjector> sas_injector_;
+
DISALLOW_COPY_AND_ASSIGN(WtsSessionProcessLauncher);
};
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index 285ff03..14da577 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -234,6 +234,7 @@
'../base/base.gyp:base',
'../base/base.gyp:base_i18n',
'../media/media.gyp:media',
+ '../ipc/ipc.gyp:ipc',
],
'sources': [
'host/host_event_logger_win.cc',
@@ -279,13 +280,18 @@
'dependencies': [
'../base/base.gyp:base',
'../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ '../ipc/ipc.gyp:ipc',
],
'sources': [
'base/scoped_sc_handle_win.h',
+ 'host/chromoting_messages.cc',
+ 'host/chromoting_messages.h',
'host/host_service.rc',
'host/host_service_resource.h',
'host/host_service_win.cc',
'host/host_service_win.h',
+ 'host/sas_injector.h',
+ 'host/sas_injector_win.cc',
'host/wts_console_monitor_win.h',
'host/wts_console_observer_win.h',
'host/wts_session_process_launcher_win.cc',
@@ -404,6 +410,11 @@
}],
], # conditions
}], # OS=="mac"
+ [ 'OS=="win"', {
+ 'dependencies': [
+ '../ipc/ipc.gyp:ipc'
+ ],
+ }],
['OS!="win"', {
'sources!': [
'host/plugin/host_plugin.def',
@@ -641,6 +652,8 @@
'host/screen_recorder.h',
'host/server_log_entry.cc',
'host/server_log_entry.h',
+ 'host/session_event_executor_win.cc',
+ 'host/session_event_executor_win.h',
'host/signaling_connector.cc',
'host/signaling_connector.h',
'host/ui_strings.cc',
@@ -690,6 +703,12 @@
],
},
}],
+ ['OS=="win"', {
+ 'sources': [
+ 'host/chromoting_messages.cc',
+ 'host/chromoting_messages.h',
+ ],
+ }],
],
}, # end of target 'remoting_host'
@@ -750,6 +769,13 @@
'host/it2me_host_user_interface.h',
'host/simple_host_process.cc',
],
+ 'conditions': [
+ [ 'OS=="win"', {
+ 'dependencies': [
+ '../ipc/ipc.gyp:ipc'
+ ],
+ }],
+ ],
}, # end of target 'remoting_simple_host'
{
@@ -1021,6 +1047,11 @@
'run_all_unittests.cc',
],
'conditions': [
+ [ 'OS=="win"', {
+ 'dependencies': [
+ '../ipc/ipc.gyp:ipc'
+ ],
+ }],
['chromeos == 0', {
'dependencies': [
'remoting_host'