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 |
34 } // namespace | 60 // RDC 6.1 (W2K8) supports resolution up to 4096x2048. |
Wez
2013/03/12 01:21:11
nit: resolution -> dimensions of
alexeypa (please no reviews)
2013/03/12 20:21:15
Done.
| |
35 | 61 const int kMaxRdpScreenWidth = 4096; |
36 namespace remoting { | 62 const int kMaxRdpScreenHeight = 2048; |
63 const int kMinRdpScreenWidth = 800; | |
64 const int kMinRdpScreenHeight = 600; | |
Wez
2013/03/12 01:21:11
nit: Comment on why we have a minimum.
alexeypa (please no reviews)
2013/03/12 20:21:15
Done.
| |
65 | |
66 const int kDefaultDpiX = 96; | |
67 const int kDefaultDpiY = 96; | |
Wez
2013/03/12 01:21:11
nit: Comment on what these are used for.
alexeypa (please no reviews)
2013/03/12 20:21:15
Done.
| |
68 | |
69 // The session attach notification should arrive within 30 seconds. | |
70 const int kSessionAttachTimeoutSeconds = 30; | |
71 | |
72 // Implements functionality shared by ConsoleSession and RdpSession classes. | |
73 class DesktopSessionWin | |
74 : public DesktopSession, | |
75 public WorkerProcessIpcDelegate, | |
76 public WtsTerminalObserver { | |
77 public: | |
78 // Passes the owning |daemon_process|, a unique identifier of the desktop | |
79 // session |id| and the interface for monitoring console session attach/detach | |
Wez
2013/03/12 01:21:11
nit: console session -> session
alexeypa (please no reviews)
2013/03/12 20:21:15
Done.
| |
80 // events. Both |daemon_process| and |monitor| must outlive |this|. | |
81 DesktopSessionWin( | |
82 scoped_refptr<AutoThreadTaskRunner> caller_task_runner, | |
83 scoped_refptr<AutoThreadTaskRunner> io_task_runner, | |
84 DaemonProcess* daemon_process, | |
85 int id, | |
Wez
2013/03/12 01:21:11
nit: |session_id|? or |desktop_session_id|?
alexeypa (please no reviews)
2013/03/12 20:21:15
I prefer |id| without any prefix because this is t
| |
86 WtsTerminalMonitor* monitor); | |
87 virtual ~DesktopSessionWin(); | |
88 | |
89 // WorkerProcessIpcDelegate implementation. | |
90 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE; | |
91 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; | |
92 virtual void OnPermanentError() OVERRIDE; | |
Wez
2013/03/12 01:21:11
nit: Both of these interfaces can move to private,
alexeypa (please no reviews)
2013/03/12 20:21:15
Done.
| |
93 | |
94 // WtsTerminalObserver implementation. | |
95 virtual void OnSessionAttached(uint32 session_id) OVERRIDE; | |
96 virtual void OnSessionDetached() OVERRIDE; | |
97 | |
98 protected: | |
99 const scoped_refptr<AutoThreadTaskRunner>& caller_task_runner() const { | |
100 return caller_task_runner_; | |
101 } | |
102 | |
103 // Called when |session_attach_timer_| expires. | |
104 void OnSessionAttachTimeout(); | |
105 | |
106 // Start monitoring session attach/detach notification for the given endpoint. | |
Wez
2013/03/12 01:21:11
nit: Start -> Starts
e.g. Starts monitoring for s
alexeypa (please no reviews)
2013/03/12 20:21:15
Done.
| |
107 void StartMonitoring(const net::IPEndPoint& client_endpoint); | |
108 | |
109 // Stop monitoring session attach/detach notifications. | |
110 void StopMonitoring(); | |
111 | |
112 // ChromotingDesktopDaemonMsg_InjectSas handler. | |
Wez
2013/03/12 01:21:11
nit: OnInjectSas() -> InjectSas() w/ comment "Inje
alexeypa (please no reviews)
2013/03/12 20:21:15
Done.
| |
113 virtual void OnInjectSas() = 0; | |
114 | |
115 private: | |
116 // ChromotingDesktopDaemonMsg_DesktopAttached handler. | |
117 void OnDesktopSessionAgentAttached(IPC::PlatformFileForTransit desktop_pipe); | |
118 | |
119 // Restarts the desktop process. | |
120 void RestartDesktopProcess(const tracked_objects::Location& location); | |
121 | |
122 // Task runner on which public methods of this class should be called. | |
123 scoped_refptr<AutoThreadTaskRunner> caller_task_runner_; | |
124 | |
125 // Message loop used by the IPC channel. | |
Wez
2013/03/12 01:21:11
nit: Does the IPC channel use it, or do we use it
alexeypa (please no reviews)
2013/03/12 20:21:15
It is used by the IPC channel.
| |
126 scoped_refptr<AutoThreadTaskRunner> io_task_runner_; | |
127 | |
128 // Handle of the desktop process. | |
Wez
2013/03/12 01:21:11
nit: Is the desktop process the DesktopSessionAgen
alexeypa (please no reviews)
2013/03/12 20:21:15
The desktop process is the process running in the
Wez
2013/03/13 22:30:27
What I'm really looking for is clarity as to what
| |
129 base::win::ScopedHandle desktop_process_; | |
130 | |
131 // Launches and monitors the desktop process. | |
132 scoped_ptr<WorkerProcessLauncher> launcher_; | |
133 | |
134 // Pointer used to unsubscribe from session attach and detach events. | |
135 WtsTerminalMonitor* monitor_; | |
136 | |
137 // True if |this| is subsribed to receive session attach/detach notifications. | |
138 bool monitoring_notifications_; | |
139 | |
140 // Used to report an error if the session attach notification does not arrives | |
141 // for too long. | |
142 base::OneShotTimer<DesktopSessionWin> session_attach_timer_; | |
143 | |
144 DISALLOW_COPY_AND_ASSIGN(DesktopSessionWin); | |
145 }; | |
146 | |
147 // DesktopSession implementation which attaches to the host's physical console. | |
148 // Receives IPC messages from the desktop process, running in the console | |
149 // session, via |WorkerProcessIpcDelegate|, and monitors console session | |
150 // attach/detach events via |WtsConsoleObserer|. | |
151 class ConsoleSession : public DesktopSessionWin { | |
152 public: | |
153 // Passes the owning |daemon_process|, a unique identifier of the desktop | |
154 // session |id| and the interface for monitoring console session attach/detach | |
155 // events. Both |daemon_process| and |monitor| must outlive |this|. | |
156 ConsoleSession( | |
157 scoped_refptr<AutoThreadTaskRunner> caller_task_runner, | |
158 scoped_refptr<AutoThreadTaskRunner> io_task_runner, | |
159 DaemonProcess* daemon_process, | |
160 int id, | |
161 WtsTerminalMonitor* monitor); | |
162 virtual ~ConsoleSession(); | |
163 | |
164 protected: | |
165 // DesktopSessionWin overrides. | |
166 virtual void OnInjectSas() OVERRIDE; | |
167 | |
168 private: | |
169 scoped_ptr<SasInjector> sas_injector_; | |
170 | |
171 DISALLOW_COPY_AND_ASSIGN(ConsoleSession); | |
172 }; | |
173 | |
174 // DesktopSession implementation which attaches to virtual RDP console. | |
175 // Receives IPC messages from the desktop process, running in the console | |
176 // session, via |WorkerProcessIpcDelegate|, and monitors console session | |
177 // attach/detach events via |WtsConsoleObserer|. | |
178 class RdpSession : public DesktopSessionWin { | |
179 public: | |
180 // Passes the owning |daemon_process|, a unique identifier of the desktop | |
181 // session |id| and the interface for monitoring console session attach/detach | |
182 // events. Both |daemon_process| and |monitor| must outlive |this|. | |
183 RdpSession( | |
184 scoped_refptr<AutoThreadTaskRunner> caller_task_runner, | |
185 scoped_refptr<AutoThreadTaskRunner> io_task_runner, | |
186 DaemonProcess* daemon_process, | |
187 int id, | |
188 WtsTerminalMonitor* monitor); | |
189 virtual ~RdpSession(); | |
190 | |
191 // Performs the part of initialization that can fail. | |
192 bool Initialize(const DesktopSessionParams& params); | |
193 | |
194 // Mirrors IRdpDesktopSessionEventHandler. | |
195 void OnRdpConnected(const net::IPEndPoint& client_endpoint); | |
196 void OnRdpClosed(); | |
197 | |
198 protected: | |
199 // DesktopSessionWin overrides. | |
200 virtual void OnInjectSas() OVERRIDE; | |
201 | |
202 private: | |
203 // An implementation of IRdpDesktopSessionEventHandler interface that forwards | |
204 // notifications to the owning desktop session. | |
205 class EventHandler : public IRdpDesktopSessionEventHandler { | |
206 public: | |
207 explicit EventHandler(base::WeakPtr<RdpSession> desktop_session); | |
208 virtual ~EventHandler(); | |
209 | |
210 // IUnknown interface. | |
211 STDMETHOD_(ULONG, AddRef)() OVERRIDE; | |
212 STDMETHOD_(ULONG, Release)() OVERRIDE; | |
213 STDMETHOD(QueryInterface)(REFIID riid, void** ppv) OVERRIDE; | |
214 | |
215 // IRdpDesktopSessionEventHandler interface. | |
216 STDMETHOD(OnRdpConnected)(byte* client_endpoint, long length) OVERRIDE; | |
217 STDMETHOD(OnRdpClosed)() OVERRIDE; | |
218 | |
219 private: | |
220 ULONG ref_count_; | |
221 | |
222 // Points to the desktop session object receiving OnRdpXxx() notifications. | |
223 base::WeakPtr<RdpSession> desktop_session_; | |
224 | |
225 // This class must be used on a single thread. | |
226 base::ThreadChecker thread_checker_; | |
227 | |
228 DISALLOW_COPY_AND_ASSIGN(EventHandler); | |
229 }; | |
230 | |
231 // Used to create an RDP desktop session. | |
232 base::win::ScopedComPtr<IRdpDesktopSession> rdp_desktop_session_; | |
233 | |
234 base::WeakPtrFactory<RdpSession> weak_factory_; | |
235 | |
236 DISALLOW_COPY_AND_ASSIGN(RdpSession); | |
237 }; | |
37 | 238 |
38 DesktopSessionWin::DesktopSessionWin( | 239 DesktopSessionWin::DesktopSessionWin( |
39 scoped_refptr<AutoThreadTaskRunner> main_task_runner, | 240 scoped_refptr<AutoThreadTaskRunner> caller_task_runner, |
40 scoped_refptr<AutoThreadTaskRunner> io_task_runner, | 241 scoped_refptr<AutoThreadTaskRunner> io_task_runner, |
41 DaemonProcess* daemon_process, | 242 DaemonProcess* daemon_process, |
42 int id, | 243 int id, |
43 const DesktopSessionParams& params, | |
44 bool virtual_terminal, | |
45 WtsTerminalMonitor* monitor) | 244 WtsTerminalMonitor* monitor) |
46 : DesktopSession(daemon_process, id), | 245 : DesktopSession(daemon_process, id), |
47 main_task_runner_(main_task_runner), | 246 caller_task_runner_(caller_task_runner), |
48 io_task_runner_(io_task_runner), | 247 io_task_runner_(io_task_runner), |
49 monitor_(monitor) { | 248 monitor_(monitor), |
50 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 249 monitoring_notifications_(false) { |
51 | 250 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
52 monitor_->AddWtsTerminalObserver(net::IPEndPoint(), this); | |
53 } | 251 } |
54 | 252 |
55 DesktopSessionWin::~DesktopSessionWin() { | 253 DesktopSessionWin::~DesktopSessionWin() { |
56 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 254 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
57 | 255 |
58 launcher_.reset(); | 256 StopMonitoring(); |
59 monitor_->RemoveWtsTerminalObserver(this); | |
60 } | 257 } |
61 | 258 |
62 void DesktopSessionWin::OnChannelConnected(int32 peer_pid) { | 259 void DesktopSessionWin::OnChannelConnected(int32 peer_pid) { |
63 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 260 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
64 | 261 |
65 // Obtain the handle of the desktop process. It will be passed to the network | 262 // 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 | 263 // process so it would be able to duplicate handles of shared memory objects |
67 // from the desktop process. | 264 // from the desktop process. |
68 desktop_process_.Set(OpenProcess(PROCESS_DUP_HANDLE, false, peer_pid)); | 265 desktop_process_.Set(OpenProcess(PROCESS_DUP_HANDLE, false, peer_pid)); |
69 if (!desktop_process_.IsValid()) { | 266 if (!desktop_process_.IsValid()) { |
70 RestartDesktopProcess(FROM_HERE); | 267 RestartDesktopProcess(FROM_HERE); |
71 return; | 268 return; |
72 } | 269 } |
73 | 270 |
74 VLOG(1) << "IPC: daemon <- desktop (" << peer_pid << ")"; | 271 VLOG(1) << "IPC: daemon <- desktop (" << peer_pid << ")"; |
75 } | 272 } |
76 | 273 |
77 bool DesktopSessionWin::OnMessageReceived(const IPC::Message& message) { | 274 bool DesktopSessionWin::OnMessageReceived(const IPC::Message& message) { |
78 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 275 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
79 | 276 |
80 bool handled = true; | 277 bool handled = true; |
81 IPC_BEGIN_MESSAGE_MAP(DesktopSessionWin, message) | 278 IPC_BEGIN_MESSAGE_MAP(DesktopSessionWin, message) |
82 IPC_MESSAGE_HANDLER(ChromotingDesktopDaemonMsg_DesktopAttached, | 279 IPC_MESSAGE_HANDLER(ChromotingDesktopDaemonMsg_DesktopAttached, |
83 OnDesktopSessionAgentAttached) | 280 OnDesktopSessionAgentAttached) |
84 IPC_MESSAGE_HANDLER(ChromotingDesktopDaemonMsg_InjectSas, | 281 IPC_MESSAGE_HANDLER(ChromotingDesktopDaemonMsg_InjectSas, |
85 OnInjectSas) | 282 OnInjectSas) |
86 IPC_MESSAGE_UNHANDLED(handled = false) | 283 IPC_MESSAGE_UNHANDLED(handled = false) |
87 IPC_END_MESSAGE_MAP() | 284 IPC_END_MESSAGE_MAP() |
88 | 285 |
89 if (!handled) { | 286 if (!handled) { |
90 LOG(ERROR) << "Received unexpected IPC type: " << message.type(); | 287 LOG(ERROR) << "Received unexpected IPC type: " << message.type(); |
91 RestartDesktopProcess(FROM_HERE); | 288 RestartDesktopProcess(FROM_HERE); |
92 } | 289 } |
93 | 290 |
94 return handled; | 291 return handled; |
95 } | 292 } |
96 | 293 |
97 void DesktopSessionWin::OnPermanentError() { | 294 void DesktopSessionWin::OnPermanentError() { |
98 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 295 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
99 | 296 |
100 launcher_.reset(); | 297 StopMonitoring(); |
101 | 298 |
102 // This call will delete |this| so it should be at the very end of the method. | 299 // This call will delete |this| so it should be at the very end of the method. |
103 daemon_process()->CloseDesktopSession(id()); | 300 daemon_process()->CloseDesktopSession(id()); |
104 } | 301 } |
105 | 302 |
106 void DesktopSessionWin::OnSessionAttached(uint32 session_id) { | 303 void DesktopSessionWin::OnSessionAttached(uint32 session_id) { |
107 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 304 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
108 DCHECK(launcher_.get() == NULL); | 305 DCHECK(!launcher_); |
306 DCHECK(monitoring_notifications_); | |
109 | 307 |
110 // Get the desktop binary name. | 308 // Get the desktop binary name. |
111 base::FilePath desktop_binary; | 309 base::FilePath desktop_binary; |
112 if (!GetInstalledBinaryPath(kDesktopBinaryName, &desktop_binary)) { | 310 if (!GetInstalledBinaryPath(kDesktopBinaryName, &desktop_binary)) { |
113 OnPermanentError(); | 311 OnPermanentError(); |
114 return; | 312 return; |
115 } | 313 } |
116 | 314 |
315 session_attach_timer_.Stop(); | |
316 | |
117 scoped_ptr<CommandLine> target(new CommandLine(desktop_binary)); | 317 scoped_ptr<CommandLine> target(new CommandLine(desktop_binary)); |
118 target->AppendSwitchASCII(kProcessTypeSwitchName, kProcessTypeDesktop); | 318 target->AppendSwitchASCII(kProcessTypeSwitchName, kProcessTypeDesktop); |
119 target->CopySwitchesFrom(*CommandLine::ForCurrentProcess(), | 319 target->CopySwitchesFrom(*CommandLine::ForCurrentProcess(), |
120 kCopiedSwitchNames, | 320 kCopiedSwitchNames, |
121 arraysize(kCopiedSwitchNames)); | 321 arraysize(kCopiedSwitchNames)); |
122 | 322 |
123 // Create a delegate to launch a process into the session. | 323 // Create a delegate to launch a process into the session. |
124 scoped_ptr<WtsSessionProcessDelegate> delegate( | 324 scoped_ptr<WtsSessionProcessDelegate> delegate( |
125 new WtsSessionProcessDelegate(main_task_runner_, io_task_runner_, | 325 new WtsSessionProcessDelegate( |
126 target.Pass(), session_id, | 326 caller_task_runner_, io_task_runner_, target.Pass(), session_id, true, |
127 true, kDaemonIpcSecurityDescriptor)); | 327 WideToUTF8(kDaemonIpcSecurityDescriptor))); |
128 | 328 |
129 // Create a launcher for the desktop process, using the per-session delegate. | 329 // Create a launcher for the desktop process, using the per-session delegate. |
130 launcher_.reset(new WorkerProcessLauncher( | 330 launcher_.reset(new WorkerProcessLauncher( |
131 main_task_runner_, delegate.Pass(), this)); | 331 caller_task_runner_, delegate.Pass(), this)); |
132 } | 332 } |
133 | 333 |
134 void DesktopSessionWin::OnSessionDetached() { | 334 void DesktopSessionWin::OnSessionDetached() { |
135 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 335 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
136 DCHECK(launcher_.get() != NULL); | |
137 | 336 |
138 launcher_.reset(); | 337 launcher_.reset(); |
338 | |
339 if (monitoring_notifications_) { | |
340 session_attach_timer_.Start( | |
341 FROM_HERE, base::TimeDelta::FromSeconds(kSessionAttachTimeoutSeconds), | |
342 this, &DesktopSessionWin::OnSessionAttachTimeout); | |
343 } | |
344 } | |
345 | |
346 void DesktopSessionWin::OnSessionAttachTimeout() { | |
347 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | |
348 | |
349 LOG(ERROR) << "Session attach notification hasn't arrived within " | |
350 << kSessionAttachTimeoutSeconds << " seconds."; | |
351 OnPermanentError(); | |
352 } | |
353 | |
354 void DesktopSessionWin::StartMonitoring( | |
355 const net::IPEndPoint& client_endpoint) { | |
356 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | |
357 DCHECK(!monitoring_notifications_); | |
358 DCHECK(!session_attach_timer_.IsRunning()); | |
359 | |
360 session_attach_timer_.Start( | |
361 FROM_HERE, base::TimeDelta::FromSeconds(kSessionAttachTimeoutSeconds), | |
362 this, &DesktopSessionWin::OnSessionAttachTimeout); | |
363 | |
364 monitoring_notifications_ = true; | |
365 monitor_->AddWtsTerminalObserver(client_endpoint, this); | |
366 } | |
367 | |
368 void DesktopSessionWin::StopMonitoring() { | |
369 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | |
370 | |
371 if (monitoring_notifications_) { | |
372 monitoring_notifications_ = false; | |
373 monitor_->RemoveWtsTerminalObserver(this); | |
374 } | |
375 | |
376 session_attach_timer_.Stop(); | |
377 OnSessionDetached(); | |
139 } | 378 } |
140 | 379 |
141 void DesktopSessionWin::OnDesktopSessionAgentAttached( | 380 void DesktopSessionWin::OnDesktopSessionAgentAttached( |
142 IPC::PlatformFileForTransit desktop_pipe) { | 381 IPC::PlatformFileForTransit desktop_pipe) { |
143 if (!daemon_process()->OnDesktopSessionAgentAttached(id(), | 382 if (!daemon_process()->OnDesktopSessionAgentAttached(id(), |
144 desktop_process_, | 383 desktop_process_, |
145 desktop_pipe)) { | 384 desktop_pipe)) { |
146 RestartDesktopProcess(FROM_HERE); | 385 RestartDesktopProcess(FROM_HERE); |
147 } | 386 } |
148 } | 387 } |
149 | 388 |
150 void DesktopSessionWin::OnInjectSas() { | 389 void DesktopSessionWin::RestartDesktopProcess( |
151 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 390 const tracked_objects::Location& location) { |
152 | 391 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
153 // Do not try to inject SAS if the desktop process is not running. This can | 392 |
154 // happen when the session has detached from the console for instance. | 393 launcher_->Send(new ChromotingDaemonDesktopMsg_Crash( |
155 if (!launcher_) | 394 location.function_name(), location.file_name(), location.line_number())); |
156 return; | 395 } |
157 | 396 |
397 ConsoleSession::ConsoleSession( | |
398 scoped_refptr<AutoThreadTaskRunner> caller_task_runner, | |
399 scoped_refptr<AutoThreadTaskRunner> io_task_runner, | |
400 DaemonProcess* daemon_process, | |
401 int id, | |
402 WtsTerminalMonitor* monitor) | |
403 : DesktopSessionWin(caller_task_runner, io_task_runner, daemon_process, id, | |
404 monitor) { | |
405 StartMonitoring(net::IPEndPoint()); | |
406 } | |
407 | |
408 ConsoleSession::~ConsoleSession() { | |
409 } | |
410 | |
411 void ConsoleSession::OnInjectSas() { | |
158 if (!sas_injector_) | 412 if (!sas_injector_) |
159 sas_injector_ = SasInjector::Create(); | 413 sas_injector_ = SasInjector::Create(); |
160 if (!sas_injector_->InjectSas()) | 414 if (!sas_injector_->InjectSas()) |
161 LOG(ERROR) << "Failed to inject Secure Attention Sequence."; | 415 LOG(ERROR) << "Failed to inject Secure Attention Sequence."; |
162 } | 416 } |
163 | 417 |
164 void DesktopSessionWin::RestartDesktopProcess( | 418 RdpSession::RdpSession( |
165 const tracked_objects::Location& location) { | 419 scoped_refptr<AutoThreadTaskRunner> caller_task_runner, |
166 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 420 scoped_refptr<AutoThreadTaskRunner> io_task_runner, |
167 | 421 DaemonProcess* daemon_process, |
168 launcher_->Send(new ChromotingDaemonDesktopMsg_Crash( | 422 int id, |
169 location.function_name(), location.file_name(), location.line_number())); | 423 WtsTerminalMonitor* monitor) |
424 : DesktopSessionWin(caller_task_runner, io_task_runner, daemon_process, id, | |
425 monitor), | |
426 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { | |
427 } | |
428 | |
429 RdpSession::~RdpSession() { | |
430 } | |
431 | |
432 bool RdpSession::Initialize(const DesktopSessionParams& params) { | |
433 DCHECK(caller_task_runner()->BelongsToCurrentThread()); | |
434 | |
435 // Create the RDP wrapper object. | |
436 HRESULT result = rdp_desktop_session_.CreateInstance( | |
437 __uuidof(RdpDesktopSession)); | |
438 if (FAILED(result)) { | |
439 LOG(ERROR) << "Failed to create RdpSession object, 0x" | |
440 << std::hex << result << std::dec << "."; | |
441 return false; | |
442 } | |
443 | |
444 // DaemonProcess::CreateDesktopSession() varifies that |client_dpi_| and | |
445 // |client_size_| are positive. | |
446 DCHECK(params.client_dpi_.x() >= 0 && params.client_dpi_.y() >= 0); | |
447 DCHECK(params.client_size_.width() >= 0 && params.client_size_.height() >= 0); | |
448 | |
449 // Handle the default DPI. | |
450 SkIPoint client_dpi = params.client_dpi_; | |
451 if (!client_dpi.x()) | |
452 client_dpi.setX(kDefaultDpiX); | |
453 if (!client_dpi.y()) | |
454 client_dpi.setY(kDefaultDpiY); | |
455 | |
456 // Make sure there will be no integer overflow while scaling the client | |
457 // resolution. | |
458 SkISize client_size = SkISize::Make( | |
459 std::min(params.client_size_.width(), | |
460 std::numeric_limits<int32_t>::max() / kDefaultDpiX), | |
461 std::min(params.client_size_.height(), | |
462 std::numeric_limits<int32_t>::max() / kDefaultDpiY)); | |
463 | |
464 // Scale the client resolution assiming RDP gives us the default 96 DPI. | |
465 SkISize host_size = SkISize::Make( | |
466 client_size.width() * kDefaultDpiX / client_dpi.x(), | |
467 client_size.height() * kDefaultDpiY / client_dpi.y()); | |
468 | |
469 // Make sure that the host resolution is within the limits supported by RDP. | |
470 host_size = SkISize::Make( | |
471 std::min(kMaxRdpScreenWidth, | |
472 std::max(kMinRdpScreenWidth, host_size.width())), | |
473 std::min(kMaxRdpScreenHeight, | |
474 std::max(kMinRdpScreenHeight, host_size.height()))); | |
475 | |
476 // Create an RDP session. | |
477 base::win::ScopedComPtr<IRdpDesktopSessionEventHandler> event_handler( | |
478 new EventHandler(weak_factory_.GetWeakPtr())); | |
479 result = rdp_desktop_session_->Connect(host_size.width(), | |
480 host_size.height(), | |
481 event_handler); | |
482 if (FAILED(result)) { | |
483 LOG(ERROR) << "RdpSession::Create() failed, 0x" | |
484 << std::hex << result << std::dec << "."; | |
485 return false; | |
486 } | |
487 | |
488 return true; | |
489 } | |
490 | |
491 void RdpSession::OnRdpConnected(const net::IPEndPoint& client_endpoint) { | |
492 DCHECK(caller_task_runner()->BelongsToCurrentThread()); | |
493 | |
494 StopMonitoring(); | |
495 StartMonitoring(client_endpoint); | |
496 } | |
497 | |
498 void RdpSession::OnRdpClosed() { | |
499 DCHECK(caller_task_runner()->BelongsToCurrentThread()); | |
500 | |
501 OnPermanentError(); | |
502 } | |
503 | |
504 void RdpSession::OnInjectSas() { | |
505 DCHECK(caller_task_runner()->BelongsToCurrentThread()); | |
506 | |
507 NOTIMPLEMENTED(); | |
508 } | |
509 | |
510 RdpSession::EventHandler::EventHandler( | |
511 base::WeakPtr<RdpSession> desktop_session) | |
512 : ref_count_(0), | |
513 desktop_session_(desktop_session) { | |
514 } | |
515 | |
516 RdpSession::EventHandler::~EventHandler() { | |
517 DCHECK(thread_checker_.CalledOnValidThread()); | |
518 | |
519 if (desktop_session_) | |
520 desktop_session_->OnRdpClosed(); | |
521 } | |
522 | |
523 ULONG STDMETHODCALLTYPE RdpSession::EventHandler::AddRef() { | |
524 DCHECK(thread_checker_.CalledOnValidThread()); | |
525 | |
526 return ++ref_count_; | |
527 } | |
528 | |
529 ULONG STDMETHODCALLTYPE RdpSession::EventHandler::Release() { | |
530 DCHECK(thread_checker_.CalledOnValidThread()); | |
531 | |
532 if (--ref_count_ == 0) { | |
533 delete this; | |
534 return 0; | |
535 } | |
536 | |
537 return ref_count_; | |
538 } | |
539 | |
540 STDMETHODIMP RdpSession::EventHandler::QueryInterface(REFIID riid, void** ppv) { | |
541 DCHECK(thread_checker_.CalledOnValidThread()); | |
542 | |
543 if (riid == IID_IUnknown || | |
544 riid == IID_IRdpDesktopSessionEventHandler) { | |
545 *ppv = static_cast<IRdpDesktopSessionEventHandler*>(this); | |
546 AddRef(); | |
547 return S_OK; | |
548 } | |
549 | |
550 *ppv = NULL; | |
551 return E_NOINTERFACE; | |
552 } | |
553 | |
554 STDMETHODIMP RdpSession::EventHandler::OnRdpConnected( | |
555 byte* client_endpoint, | |
556 long length) { | |
557 DCHECK(thread_checker_.CalledOnValidThread()); | |
558 | |
559 if (!desktop_session_) | |
560 return S_OK; | |
561 | |
562 net::IPEndPoint endpoint; | |
563 if (!endpoint.FromSockAddr(reinterpret_cast<sockaddr*>(client_endpoint), | |
564 length)) { | |
565 LOG(ERROR) << "Failed to parse the endpoint passed to OnRdpConnected()."; | |
566 OnRdpClosed(); | |
567 return S_OK; | |
568 } | |
569 | |
570 desktop_session_->OnRdpConnected(endpoint); | |
571 return S_OK; | |
572 } | |
573 | |
574 STDMETHODIMP RdpSession::EventHandler::OnRdpClosed() { | |
575 DCHECK(thread_checker_.CalledOnValidThread()); | |
576 | |
577 if (!desktop_session_) | |
578 return S_OK; | |
579 | |
580 base::WeakPtr<RdpSession> desktop_session = desktop_session_; | |
581 desktop_session_.reset(); | |
582 desktop_session->OnRdpClosed(); | |
583 return S_OK; | |
584 } | |
585 | |
586 } // namespace | |
587 | |
588 scoped_ptr<DesktopSession> CreateDesktopSessionWin( | |
589 scoped_refptr<AutoThreadTaskRunner> caller_task_runner, | |
590 scoped_refptr<AutoThreadTaskRunner> io_task_runner, | |
591 DaemonProcess* daemon_process, | |
592 int id, | |
593 const DesktopSessionParams& params, | |
594 bool virtual_terminal) { | |
595 if (virtual_terminal) { | |
596 scoped_ptr<RdpSession> session(new RdpSession( | |
597 caller_task_runner, io_task_runner, daemon_process, id, | |
598 HostService::GetInstance())); | |
599 | |
600 if (!session->Initialize(params)) | |
601 return scoped_ptr<DesktopSession>(); | |
602 | |
603 return session.PassAs<DesktopSession>(); | |
604 } else { | |
605 scoped_ptr<ConsoleSession> session(new ConsoleSession( | |
606 caller_task_runner, io_task_runner, daemon_process, id, | |
607 HostService::GetInstance())); | |
608 | |
609 return session.PassAs<DesktopSession>(); | |
610 } | |
170 } | 611 } |
171 | 612 |
172 } // namespace remoting | 613 } // namespace remoting |
OLD | NEW |