OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/host/desktop_session_win.h" | 5 #include "remoting/host/desktop_session_win.h" |
6 | 6 |
| 7 #include <limits> |
| 8 #include <sddl.h> |
| 9 |
7 #include "base/base_switches.h" | 10 #include "base/base_switches.h" |
8 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 12 #include "base/files/file_path.h" |
| 13 #include "base/memory/ref_counted.h" |
| 14 #include "base/memory/scoped_ptr.h" |
| 15 #include "base/memory/weak_ptr.h" |
9 #include "base/path_service.h" | 16 #include "base/path_service.h" |
| 17 #include "base/threading/thread_checker.h" |
| 18 #include "base/timer.h" |
| 19 #include "base/utf_string_conversions.h" |
| 20 #include "base/win/scoped_comptr.h" |
| 21 #include "base/win/scoped_handle.h" |
10 #include "ipc/ipc_message_macros.h" | 22 #include "ipc/ipc_message_macros.h" |
| 23 #include "ipc/ipc_platform_file.h" |
11 #include "net/base/ip_endpoint.h" | 24 #include "net/base/ip_endpoint.h" |
12 #include "remoting/base/auto_thread_task_runner.h" | 25 #include "remoting/base/auto_thread_task_runner.h" |
| 26 // MIDL-generated declarations and definitions. |
| 27 #include "remoting/host/chromoting_lib.h" |
13 #include "remoting/host/chromoting_messages.h" | 28 #include "remoting/host/chromoting_messages.h" |
14 #include "remoting/host/daemon_process.h" | 29 #include "remoting/host/daemon_process.h" |
| 30 #include "remoting/host/desktop_session.h" |
15 #include "remoting/host/host_main.h" | 31 #include "remoting/host/host_main.h" |
16 #include "remoting/host/ipc_constants.h" | 32 #include "remoting/host/ipc_constants.h" |
17 #include "remoting/host/sas_injector.h" | 33 #include "remoting/host/sas_injector.h" |
| 34 #include "remoting/host/win/host_service.h" |
18 #include "remoting/host/win/worker_process_launcher.h" | 35 #include "remoting/host/win/worker_process_launcher.h" |
19 #include "remoting/host/win/wts_session_process_delegate.h" | 36 #include "remoting/host/win/wts_session_process_delegate.h" |
20 #include "remoting/host/win/wts_terminal_monitor.h" | 37 #include "remoting/host/win/wts_terminal_monitor.h" |
| 38 #include "remoting/host/win/wts_terminal_observer.h" |
| 39 #include "remoting/host/worker_process_ipc_delegate.h" |
21 | 40 |
22 using base::win::ScopedHandle; | 41 using base::win::ScopedHandle; |
23 | 42 |
| 43 namespace remoting { |
| 44 |
24 namespace { | 45 namespace { |
25 | 46 |
26 // The security descriptor of the daemon IPC endpoint. It gives full access | 47 // The security descriptor of the daemon IPC endpoint. It gives full access |
27 // to SYSTEM and denies access by anyone else. | 48 // to SYSTEM and denies access by anyone else. |
28 const char kDaemonIpcSecurityDescriptor[] = "O:SYG:SYD:(A;;GA;;;SY)"; | 49 const wchar_t kDaemonIpcSecurityDescriptor[] = |
| 50 SDDL_OWNER L":" SDDL_LOCAL_SYSTEM |
| 51 SDDL_GROUP L":" SDDL_LOCAL_SYSTEM |
| 52 SDDL_DACL L":(" |
| 53 SDDL_ACCESS_ALLOWED L";;" SDDL_GENERIC_ALL L";;;" SDDL_LOCAL_SYSTEM |
| 54 L")"; |
29 | 55 |
30 // The command line parameters that should be copied from the service's command | 56 // The command line parameters that should be copied from the service's command |
31 // line to the host process. | 57 // line to the host process. |
32 const char* kCopiedSwitchNames[] = { switches::kV, switches::kVModule }; | 58 const char* kCopiedSwitchNames[] = { switches::kV, switches::kVModule }; |
33 | 59 |
| 60 // RDC 6.1 (W2K8) supports dimensions of up to 4096x2048. |
| 61 const int kMaxRdpScreenWidth = 4096; |
| 62 const int kMaxRdpScreenHeight = 2048; |
| 63 |
| 64 // The minimum effective screen dimensions supported by Windows are 800x600. |
| 65 const int kMinRdpScreenWidth = 800; |
| 66 const int kMinRdpScreenHeight = 600; |
| 67 |
| 68 // Default dots per inch is 96 DPI. |
| 69 const int kDefaultDpiX = 96; |
| 70 const int kDefaultDpiY = 96; |
| 71 |
| 72 // The session attach notification should arrive within 30 seconds. |
| 73 const int kSessionAttachTimeoutSeconds = 30; |
| 74 |
| 75 // DesktopSession implementation which attaches to the host's physical console. |
| 76 // Receives IPC messages from the desktop process, running in the console |
| 77 // session, via |WorkerProcessIpcDelegate|, and monitors console session |
| 78 // attach/detach events via |WtsConsoleObserer|. |
| 79 class ConsoleSession : public DesktopSessionWin { |
| 80 public: |
| 81 // Same as DesktopSessionWin(). |
| 82 ConsoleSession( |
| 83 scoped_refptr<AutoThreadTaskRunner> caller_task_runner, |
| 84 scoped_refptr<AutoThreadTaskRunner> io_task_runner, |
| 85 DaemonProcess* daemon_process, |
| 86 int id, |
| 87 WtsTerminalMonitor* monitor); |
| 88 virtual ~ConsoleSession(); |
| 89 |
| 90 protected: |
| 91 // DesktopSessionWin overrides. |
| 92 virtual void InjectSas() OVERRIDE; |
| 93 |
| 94 private: |
| 95 scoped_ptr<SasInjector> sas_injector_; |
| 96 |
| 97 DISALLOW_COPY_AND_ASSIGN(ConsoleSession); |
| 98 }; |
| 99 |
| 100 // DesktopSession implementation which attaches to virtual RDP console. |
| 101 // Receives IPC messages from the desktop process, running in the console |
| 102 // session, via |WorkerProcessIpcDelegate|, and monitors console session |
| 103 // attach/detach events via |WtsConsoleObserer|. |
| 104 class RdpSession : public DesktopSessionWin { |
| 105 public: |
| 106 // Same as DesktopSessionWin(). |
| 107 RdpSession( |
| 108 scoped_refptr<AutoThreadTaskRunner> caller_task_runner, |
| 109 scoped_refptr<AutoThreadTaskRunner> io_task_runner, |
| 110 DaemonProcess* daemon_process, |
| 111 int id, |
| 112 WtsTerminalMonitor* monitor); |
| 113 virtual ~RdpSession(); |
| 114 |
| 115 // Performs the part of initialization that can fail. |
| 116 bool Initialize(const DesktopSessionParams& params); |
| 117 |
| 118 // Mirrors IRdpDesktopSessionEventHandler. |
| 119 void OnRdpConnected(const net::IPEndPoint& client_endpoint); |
| 120 void OnRdpClosed(); |
| 121 |
| 122 protected: |
| 123 // DesktopSessionWin overrides. |
| 124 virtual void InjectSas() OVERRIDE; |
| 125 |
| 126 private: |
| 127 // An implementation of IRdpDesktopSessionEventHandler interface that forwards |
| 128 // notifications to the owning desktop session. |
| 129 class EventHandler : public IRdpDesktopSessionEventHandler { |
| 130 public: |
| 131 explicit EventHandler(base::WeakPtr<RdpSession> desktop_session); |
| 132 virtual ~EventHandler(); |
| 133 |
| 134 // IUnknown interface. |
| 135 STDMETHOD_(ULONG, AddRef)() OVERRIDE; |
| 136 STDMETHOD_(ULONG, Release)() OVERRIDE; |
| 137 STDMETHOD(QueryInterface)(REFIID riid, void** ppv) OVERRIDE; |
| 138 |
| 139 // IRdpDesktopSessionEventHandler interface. |
| 140 STDMETHOD(OnRdpConnected)(byte* client_endpoint, long length) OVERRIDE; |
| 141 STDMETHOD(OnRdpClosed)() OVERRIDE; |
| 142 |
| 143 private: |
| 144 ULONG ref_count_; |
| 145 |
| 146 // Points to the desktop session object receiving OnRdpXxx() notifications. |
| 147 base::WeakPtr<RdpSession> desktop_session_; |
| 148 |
| 149 // This class must be used on a single thread. |
| 150 base::ThreadChecker thread_checker_; |
| 151 |
| 152 DISALLOW_COPY_AND_ASSIGN(EventHandler); |
| 153 }; |
| 154 |
| 155 // Used to create an RDP desktop session. |
| 156 base::win::ScopedComPtr<IRdpDesktopSession> rdp_desktop_session_; |
| 157 |
| 158 base::WeakPtrFactory<RdpSession> weak_factory_; |
| 159 |
| 160 DISALLOW_COPY_AND_ASSIGN(RdpSession); |
| 161 }; |
| 162 |
| 163 ConsoleSession::ConsoleSession( |
| 164 scoped_refptr<AutoThreadTaskRunner> caller_task_runner, |
| 165 scoped_refptr<AutoThreadTaskRunner> io_task_runner, |
| 166 DaemonProcess* daemon_process, |
| 167 int id, |
| 168 WtsTerminalMonitor* monitor) |
| 169 : DesktopSessionWin(caller_task_runner, io_task_runner, daemon_process, id, |
| 170 monitor) { |
| 171 StartMonitoring(net::IPEndPoint()); |
| 172 } |
| 173 |
| 174 ConsoleSession::~ConsoleSession() { |
| 175 } |
| 176 |
| 177 void ConsoleSession::InjectSas() { |
| 178 if (!sas_injector_) |
| 179 sas_injector_ = SasInjector::Create(); |
| 180 if (!sas_injector_->InjectSas()) |
| 181 LOG(ERROR) << "Failed to inject Secure Attention Sequence."; |
| 182 } |
| 183 |
| 184 RdpSession::RdpSession( |
| 185 scoped_refptr<AutoThreadTaskRunner> caller_task_runner, |
| 186 scoped_refptr<AutoThreadTaskRunner> io_task_runner, |
| 187 DaemonProcess* daemon_process, |
| 188 int id, |
| 189 WtsTerminalMonitor* monitor) |
| 190 : DesktopSessionWin(caller_task_runner, io_task_runner, daemon_process, id, |
| 191 monitor), |
| 192 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { |
| 193 } |
| 194 |
| 195 RdpSession::~RdpSession() { |
| 196 } |
| 197 |
| 198 bool RdpSession::Initialize(const DesktopSessionParams& params) { |
| 199 DCHECK(caller_task_runner()->BelongsToCurrentThread()); |
| 200 |
| 201 // Create the RDP wrapper object. |
| 202 HRESULT result = rdp_desktop_session_.CreateInstance( |
| 203 __uuidof(RdpDesktopSession)); |
| 204 if (FAILED(result)) { |
| 205 LOG(ERROR) << "Failed to create RdpSession object, 0x" |
| 206 << std::hex << result << std::dec << "."; |
| 207 return false; |
| 208 } |
| 209 |
| 210 // DaemonProcess::CreateDesktopSession() varifies that |client_dpi_| and |
| 211 // |client_size_| are positive. |
| 212 DCHECK(params.client_dpi_.x() >= 0 && params.client_dpi_.y() >= 0); |
| 213 DCHECK(params.client_size_.width() >= 0 && params.client_size_.height() >= 0); |
| 214 |
| 215 // Handle the default DPI. |
| 216 SkIPoint client_dpi = params.client_dpi_; |
| 217 if (!client_dpi.x()) |
| 218 client_dpi.setX(kDefaultDpiX); |
| 219 if (!client_dpi.y()) |
| 220 client_dpi.setY(kDefaultDpiY); |
| 221 |
| 222 // Make sure there will be no integer overflow while scaling the client |
| 223 // resolution. |
| 224 SkISize client_size = SkISize::Make( |
| 225 std::min(params.client_size_.width(), |
| 226 std::numeric_limits<int32_t>::max() / kDefaultDpiX), |
| 227 std::min(params.client_size_.height(), |
| 228 std::numeric_limits<int32_t>::max() / kDefaultDpiY)); |
| 229 |
| 230 // Scale the client resolution assiming RDP gives us the default 96 DPI. |
| 231 SkISize host_size = SkISize::Make( |
| 232 client_size.width() * kDefaultDpiX / client_dpi.x(), |
| 233 client_size.height() * kDefaultDpiY / client_dpi.y()); |
| 234 |
| 235 // Make sure that the host resolution is within the limits supported by RDP. |
| 236 host_size = SkISize::Make( |
| 237 std::min(kMaxRdpScreenWidth, |
| 238 std::max(kMinRdpScreenWidth, host_size.width())), |
| 239 std::min(kMaxRdpScreenHeight, |
| 240 std::max(kMinRdpScreenHeight, host_size.height()))); |
| 241 |
| 242 // Create an RDP session. |
| 243 base::win::ScopedComPtr<IRdpDesktopSessionEventHandler> event_handler( |
| 244 new EventHandler(weak_factory_.GetWeakPtr())); |
| 245 result = rdp_desktop_session_->Connect(host_size.width(), |
| 246 host_size.height(), |
| 247 event_handler); |
| 248 if (FAILED(result)) { |
| 249 LOG(ERROR) << "RdpSession::Create() failed, 0x" |
| 250 << std::hex << result << std::dec << "."; |
| 251 return false; |
| 252 } |
| 253 |
| 254 return true; |
| 255 } |
| 256 |
| 257 void RdpSession::OnRdpConnected(const net::IPEndPoint& client_endpoint) { |
| 258 DCHECK(caller_task_runner()->BelongsToCurrentThread()); |
| 259 |
| 260 StopMonitoring(); |
| 261 StartMonitoring(client_endpoint); |
| 262 } |
| 263 |
| 264 void RdpSession::OnRdpClosed() { |
| 265 DCHECK(caller_task_runner()->BelongsToCurrentThread()); |
| 266 |
| 267 OnPermanentError(); |
| 268 } |
| 269 |
| 270 void RdpSession::InjectSas() { |
| 271 DCHECK(caller_task_runner()->BelongsToCurrentThread()); |
| 272 |
| 273 NOTIMPLEMENTED(); |
| 274 } |
| 275 |
| 276 RdpSession::EventHandler::EventHandler( |
| 277 base::WeakPtr<RdpSession> desktop_session) |
| 278 : ref_count_(0), |
| 279 desktop_session_(desktop_session) { |
| 280 } |
| 281 |
| 282 RdpSession::EventHandler::~EventHandler() { |
| 283 DCHECK(thread_checker_.CalledOnValidThread()); |
| 284 |
| 285 if (desktop_session_) |
| 286 desktop_session_->OnRdpClosed(); |
| 287 } |
| 288 |
| 289 ULONG STDMETHODCALLTYPE RdpSession::EventHandler::AddRef() { |
| 290 DCHECK(thread_checker_.CalledOnValidThread()); |
| 291 |
| 292 return ++ref_count_; |
| 293 } |
| 294 |
| 295 ULONG STDMETHODCALLTYPE RdpSession::EventHandler::Release() { |
| 296 DCHECK(thread_checker_.CalledOnValidThread()); |
| 297 |
| 298 if (--ref_count_ == 0) { |
| 299 delete this; |
| 300 return 0; |
| 301 } |
| 302 |
| 303 return ref_count_; |
| 304 } |
| 305 |
| 306 STDMETHODIMP RdpSession::EventHandler::QueryInterface(REFIID riid, void** ppv) { |
| 307 DCHECK(thread_checker_.CalledOnValidThread()); |
| 308 |
| 309 if (riid == IID_IUnknown || |
| 310 riid == IID_IRdpDesktopSessionEventHandler) { |
| 311 *ppv = static_cast<IRdpDesktopSessionEventHandler*>(this); |
| 312 AddRef(); |
| 313 return S_OK; |
| 314 } |
| 315 |
| 316 *ppv = NULL; |
| 317 return E_NOINTERFACE; |
| 318 } |
| 319 |
| 320 STDMETHODIMP RdpSession::EventHandler::OnRdpConnected( |
| 321 byte* client_endpoint, |
| 322 long length) { |
| 323 DCHECK(thread_checker_.CalledOnValidThread()); |
| 324 |
| 325 if (!desktop_session_) |
| 326 return S_OK; |
| 327 |
| 328 net::IPEndPoint endpoint; |
| 329 if (!endpoint.FromSockAddr(reinterpret_cast<sockaddr*>(client_endpoint), |
| 330 length)) { |
| 331 LOG(ERROR) << "Failed to parse the endpoint passed to OnRdpConnected()."; |
| 332 OnRdpClosed(); |
| 333 return S_OK; |
| 334 } |
| 335 |
| 336 desktop_session_->OnRdpConnected(endpoint); |
| 337 return S_OK; |
| 338 } |
| 339 |
| 340 STDMETHODIMP RdpSession::EventHandler::OnRdpClosed() { |
| 341 DCHECK(thread_checker_.CalledOnValidThread()); |
| 342 |
| 343 if (!desktop_session_) |
| 344 return S_OK; |
| 345 |
| 346 base::WeakPtr<RdpSession> desktop_session = desktop_session_; |
| 347 desktop_session_.reset(); |
| 348 desktop_session->OnRdpClosed(); |
| 349 return S_OK; |
| 350 } |
| 351 |
34 } // namespace | 352 } // namespace |
35 | 353 |
36 namespace remoting { | 354 // static |
| 355 scoped_ptr<DesktopSession> DesktopSessionWin::CreateForConsole( |
| 356 scoped_refptr<AutoThreadTaskRunner> caller_task_runner, |
| 357 scoped_refptr<AutoThreadTaskRunner> io_task_runner, |
| 358 DaemonProcess* daemon_process, |
| 359 int id, |
| 360 const DesktopSessionParams& params) { |
| 361 scoped_ptr<ConsoleSession> session(new ConsoleSession( |
| 362 caller_task_runner, io_task_runner, daemon_process, id, |
| 363 HostService::GetInstance())); |
| 364 |
| 365 return session.PassAs<DesktopSession>(); |
| 366 } |
| 367 |
| 368 // static |
| 369 scoped_ptr<DesktopSession> DesktopSessionWin::CreateForVirtualTerminal( |
| 370 scoped_refptr<AutoThreadTaskRunner> caller_task_runner, |
| 371 scoped_refptr<AutoThreadTaskRunner> io_task_runner, |
| 372 DaemonProcess* daemon_process, |
| 373 int id, |
| 374 const DesktopSessionParams& params) { |
| 375 scoped_ptr<RdpSession> session(new RdpSession( |
| 376 caller_task_runner, io_task_runner, daemon_process, id, |
| 377 HostService::GetInstance())); |
| 378 if (!session->Initialize(params)) |
| 379 return scoped_ptr<DesktopSession>(); |
| 380 |
| 381 return session.PassAs<DesktopSession>(); |
| 382 } |
37 | 383 |
38 DesktopSessionWin::DesktopSessionWin( | 384 DesktopSessionWin::DesktopSessionWin( |
39 scoped_refptr<AutoThreadTaskRunner> main_task_runner, | 385 scoped_refptr<AutoThreadTaskRunner> caller_task_runner, |
40 scoped_refptr<AutoThreadTaskRunner> io_task_runner, | 386 scoped_refptr<AutoThreadTaskRunner> io_task_runner, |
41 DaemonProcess* daemon_process, | 387 DaemonProcess* daemon_process, |
42 int id, | 388 int id, |
43 const DesktopSessionParams& params, | |
44 bool virtual_terminal, | |
45 WtsTerminalMonitor* monitor) | 389 WtsTerminalMonitor* monitor) |
46 : DesktopSession(daemon_process, id), | 390 : DesktopSession(daemon_process, id), |
47 main_task_runner_(main_task_runner), | 391 caller_task_runner_(caller_task_runner), |
48 io_task_runner_(io_task_runner), | 392 io_task_runner_(io_task_runner), |
49 monitor_(monitor) { | 393 monitor_(monitor), |
50 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 394 monitoring_notifications_(false) { |
51 | 395 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
52 monitor_->AddWtsTerminalObserver(net::IPEndPoint(), this); | |
53 } | 396 } |
54 | 397 |
55 DesktopSessionWin::~DesktopSessionWin() { | 398 DesktopSessionWin::~DesktopSessionWin() { |
56 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 399 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
57 | 400 |
58 launcher_.reset(); | 401 StopMonitoring(); |
59 monitor_->RemoveWtsTerminalObserver(this); | 402 } |
| 403 |
| 404 void DesktopSessionWin::OnSessionAttachTimeout() { |
| 405 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 406 |
| 407 LOG(ERROR) << "Session attach notification didn't arrived within " |
| 408 << kSessionAttachTimeoutSeconds << " seconds."; |
| 409 OnPermanentError(); |
| 410 } |
| 411 |
| 412 void DesktopSessionWin::StartMonitoring( |
| 413 const net::IPEndPoint& client_endpoint) { |
| 414 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 415 DCHECK(!monitoring_notifications_); |
| 416 DCHECK(!session_attach_timer_.IsRunning()); |
| 417 |
| 418 session_attach_timer_.Start( |
| 419 FROM_HERE, base::TimeDelta::FromSeconds(kSessionAttachTimeoutSeconds), |
| 420 this, &DesktopSessionWin::OnSessionAttachTimeout); |
| 421 |
| 422 monitoring_notifications_ = true; |
| 423 monitor_->AddWtsTerminalObserver(client_endpoint, this); |
| 424 } |
| 425 |
| 426 void DesktopSessionWin::StopMonitoring() { |
| 427 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 428 |
| 429 if (monitoring_notifications_) { |
| 430 monitoring_notifications_ = false; |
| 431 monitor_->RemoveWtsTerminalObserver(this); |
| 432 } |
| 433 |
| 434 session_attach_timer_.Stop(); |
| 435 OnSessionDetached(); |
60 } | 436 } |
61 | 437 |
62 void DesktopSessionWin::OnChannelConnected(int32 peer_pid) { | 438 void DesktopSessionWin::OnChannelConnected(int32 peer_pid) { |
63 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 439 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
64 | 440 |
65 // Obtain the handle of the desktop process. It will be passed to the network | 441 // Obtain the handle of the desktop process. It will be passed to the network |
66 // process so it would be able to duplicate handles of shared memory objects | 442 // process to use to duplicate handles of shared memory objects from |
67 // from the desktop process. | 443 // the desktop process. |
68 desktop_process_.Set(OpenProcess(PROCESS_DUP_HANDLE, false, peer_pid)); | 444 desktop_process_.Set(OpenProcess(PROCESS_DUP_HANDLE, false, peer_pid)); |
69 if (!desktop_process_.IsValid()) { | 445 if (!desktop_process_.IsValid()) { |
70 CrashDesktopProcess(FROM_HERE); | 446 CrashDesktopProcess(FROM_HERE); |
71 return; | 447 return; |
72 } | 448 } |
73 | 449 |
74 VLOG(1) << "IPC: daemon <- desktop (" << peer_pid << ")"; | 450 VLOG(1) << "IPC: daemon <- desktop (" << peer_pid << ")"; |
75 } | 451 } |
76 | 452 |
77 bool DesktopSessionWin::OnMessageReceived(const IPC::Message& message) { | 453 bool DesktopSessionWin::OnMessageReceived(const IPC::Message& message) { |
78 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 454 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
79 | 455 |
80 bool handled = true; | 456 bool handled = true; |
81 IPC_BEGIN_MESSAGE_MAP(DesktopSessionWin, message) | 457 IPC_BEGIN_MESSAGE_MAP(DesktopSessionWin, message) |
82 IPC_MESSAGE_HANDLER(ChromotingDesktopDaemonMsg_DesktopAttached, | 458 IPC_MESSAGE_HANDLER(ChromotingDesktopDaemonMsg_DesktopAttached, |
83 OnDesktopSessionAgentAttached) | 459 OnDesktopSessionAgentAttached) |
84 IPC_MESSAGE_HANDLER(ChromotingDesktopDaemonMsg_InjectSas, | 460 IPC_MESSAGE_HANDLER(ChromotingDesktopDaemonMsg_InjectSas, |
85 OnInjectSas) | 461 InjectSas) |
86 IPC_MESSAGE_UNHANDLED(handled = false) | 462 IPC_MESSAGE_UNHANDLED(handled = false) |
87 IPC_END_MESSAGE_MAP() | 463 IPC_END_MESSAGE_MAP() |
88 | 464 |
89 if (!handled) { | 465 if (!handled) { |
90 LOG(ERROR) << "Received unexpected IPC type: " << message.type(); | 466 LOG(ERROR) << "Received unexpected IPC type: " << message.type(); |
91 CrashDesktopProcess(FROM_HERE); | 467 CrashDesktopProcess(FROM_HERE); |
92 } | 468 } |
93 | 469 |
94 return handled; | 470 return handled; |
95 } | 471 } |
96 | 472 |
97 void DesktopSessionWin::OnPermanentError() { | 473 void DesktopSessionWin::OnPermanentError() { |
98 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 474 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
99 | 475 |
100 launcher_.reset(); | 476 StopMonitoring(); |
101 | 477 |
102 // This call will delete |this| so it should be at the very end of the method. | 478 // This call will delete |this| so it should be at the very end of the method. |
103 daemon_process()->CloseDesktopSession(id()); | 479 daemon_process()->CloseDesktopSession(id()); |
104 } | 480 } |
105 | 481 |
106 void DesktopSessionWin::OnSessionAttached(uint32 session_id) { | 482 void DesktopSessionWin::OnSessionAttached(uint32 session_id) { |
107 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 483 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
108 DCHECK(launcher_.get() == NULL); | 484 DCHECK(!launcher_); |
| 485 DCHECK(monitoring_notifications_); |
109 | 486 |
110 // Get the desktop binary name. | 487 // Get the name of the executable the desktop process will run. |
111 base::FilePath desktop_binary; | 488 base::FilePath desktop_binary; |
112 if (!GetInstalledBinaryPath(kDesktopBinaryName, &desktop_binary)) { | 489 if (!GetInstalledBinaryPath(kDesktopBinaryName, &desktop_binary)) { |
113 OnPermanentError(); | 490 OnPermanentError(); |
114 return; | 491 return; |
115 } | 492 } |
116 | 493 |
| 494 session_attach_timer_.Stop(); |
| 495 |
117 scoped_ptr<CommandLine> target(new CommandLine(desktop_binary)); | 496 scoped_ptr<CommandLine> target(new CommandLine(desktop_binary)); |
118 target->AppendSwitchASCII(kProcessTypeSwitchName, kProcessTypeDesktop); | 497 target->AppendSwitchASCII(kProcessTypeSwitchName, kProcessTypeDesktop); |
| 498 // Copy the command line switches enabling verbose logging. |
119 target->CopySwitchesFrom(*CommandLine::ForCurrentProcess(), | 499 target->CopySwitchesFrom(*CommandLine::ForCurrentProcess(), |
120 kCopiedSwitchNames, | 500 kCopiedSwitchNames, |
121 arraysize(kCopiedSwitchNames)); | 501 arraysize(kCopiedSwitchNames)); |
122 | 502 |
123 // Create a delegate to launch a process into the session. | 503 // Create a delegate capable of launching a process in a different session. |
124 scoped_ptr<WtsSessionProcessDelegate> delegate( | 504 scoped_ptr<WtsSessionProcessDelegate> delegate( |
125 new WtsSessionProcessDelegate(main_task_runner_, io_task_runner_, | 505 new WtsSessionProcessDelegate( |
126 target.Pass(), session_id, | 506 caller_task_runner_, io_task_runner_, target.Pass(), session_id, true, |
127 true, kDaemonIpcSecurityDescriptor)); | 507 WideToUTF8(kDaemonIpcSecurityDescriptor))); |
128 | 508 |
129 // Create a launcher for the desktop process, using the per-session delegate. | 509 // Create a launcher for the desktop process, using the per-session delegate. |
130 launcher_.reset(new WorkerProcessLauncher( | 510 launcher_.reset(new WorkerProcessLauncher( |
131 main_task_runner_, delegate.Pass(), this)); | 511 caller_task_runner_, delegate.Pass(), this)); |
132 } | 512 } |
133 | 513 |
134 void DesktopSessionWin::OnSessionDetached() { | 514 void DesktopSessionWin::OnSessionDetached() { |
135 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 515 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
136 DCHECK(launcher_.get() != NULL); | |
137 | 516 |
138 launcher_.reset(); | 517 launcher_.reset(); |
| 518 |
| 519 if (monitoring_notifications_) { |
| 520 session_attach_timer_.Start( |
| 521 FROM_HERE, base::TimeDelta::FromSeconds(kSessionAttachTimeoutSeconds), |
| 522 this, &DesktopSessionWin::OnSessionAttachTimeout); |
| 523 } |
139 } | 524 } |
140 | 525 |
141 void DesktopSessionWin::OnDesktopSessionAgentAttached( | 526 void DesktopSessionWin::OnDesktopSessionAgentAttached( |
142 IPC::PlatformFileForTransit desktop_pipe) { | 527 IPC::PlatformFileForTransit desktop_pipe) { |
143 if (!daemon_process()->OnDesktopSessionAgentAttached(id(), | 528 if (!daemon_process()->OnDesktopSessionAgentAttached(id(), |
144 desktop_process_, | 529 desktop_process_, |
145 desktop_pipe)) { | 530 desktop_pipe)) { |
146 CrashDesktopProcess(FROM_HERE); | 531 CrashDesktopProcess(FROM_HERE); |
147 } | 532 } |
148 } | 533 } |
149 | 534 |
150 void DesktopSessionWin::OnInjectSas() { | |
151 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
152 | |
153 // Do not try to inject SAS if the desktop process is not running. This can | |
154 // happen when the session has detached from the console for instance. | |
155 if (!launcher_) | |
156 return; | |
157 | |
158 if (!sas_injector_) | |
159 sas_injector_ = SasInjector::Create(); | |
160 if (!sas_injector_->InjectSas()) | |
161 LOG(ERROR) << "Failed to inject Secure Attention Sequence."; | |
162 } | |
163 | |
164 void DesktopSessionWin::CrashDesktopProcess( | 535 void DesktopSessionWin::CrashDesktopProcess( |
165 const tracked_objects::Location& location) { | 536 const tracked_objects::Location& location) { |
166 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 537 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
167 | 538 |
168 launcher_->Crash(location); | 539 launcher_->Crash(location); |
169 } | 540 } |
170 | 541 |
171 } // namespace remoting | 542 } // namespace remoting |
OLD | NEW |