diff options
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' |