Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / remoting / host / win / rdp_client.cc
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "remoting/host/win/rdp_client.h"
6
7 #include <windows.h>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/logging.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/win/registry.h"
14 #include "net/base/ip_endpoint.h"
15 #include "remoting/base/typed_buffer.h"
16 #include "remoting/host/win/rdp_client_window.h"
17 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
18
19 namespace remoting {
20
21 namespace {
22
23 // 127.0.0.1 is explicitly blocked by the RDP ActiveX control, so we use
24 // 127.0.0.2 instead.
25 const unsigned char kRdpLoopbackAddress[] = { 127, 0, 0, 2 };
26
27 const int kDefaultRdpPort = 3389;
28
29 // The port number used by RDP is stored in the registry.
30 const wchar_t kRdpPortKeyName[] = L"SYSTEM\\CurrentControlSet\\Control\\"
31     L"Terminal Server\\WinStations\\RDP-Tcp";
32 const wchar_t kRdpPortValueName[] = L"PortNumber";
33
34 }  // namespace
35
36 // The core of RdpClient is ref-counted since it services calls and notifies
37 // events on the caller task runner, but runs the ActiveX control on the UI
38 // task runner.
39 class RdpClient::Core
40     : public base::RefCountedThreadSafe<Core>,
41       public RdpClientWindow::EventHandler {
42  public:
43   Core(
44       scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
45       scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
46       RdpClient::EventHandler* event_handler);
47
48   // Initiates a loopback RDP connection.
49   void Connect(const webrtc::DesktopSize& screen_size,
50                const std::string& terminal_id);
51
52   // Initiates a graceful shutdown of the RDP connection.
53   void Disconnect();
54
55   // Sends Secure Attention Sequence to the session.
56   void InjectSas();
57
58   // RdpClientWindow::EventHandler interface.
59   virtual void OnConnected() override;
60   virtual void OnDisconnected() override;
61
62  private:
63   friend class base::RefCountedThreadSafe<Core>;
64   virtual ~Core();
65
66   // Helpers for the event handler's methods that make sure that OnRdpClosed()
67   // is the last notification delivered and is delevered only once.
68   void NotifyConnected();
69   void NotifyClosed();
70
71   // Task runner on which the caller expects |event_handler_| to be notified.
72   scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
73
74   // Task runner on which |rdp_client_window_| is running.
75   scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
76
77   // Event handler receiving notification about connection state. The pointer is
78   // cleared when Disconnect() methods is called, stopping any further updates.
79   RdpClient::EventHandler* event_handler_;
80
81   // Hosts the RDP ActiveX control.
82   scoped_ptr<RdpClientWindow> rdp_client_window_;
83
84   // A self-reference to keep the object alive during connection shutdown.
85   scoped_refptr<Core> self_;
86
87   DISALLOW_COPY_AND_ASSIGN(Core);
88 };
89
90 RdpClient::RdpClient(
91     scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
92     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
93     const webrtc::DesktopSize& screen_size,
94     const std::string& terminal_id,
95     EventHandler* event_handler) {
96   DCHECK(caller_task_runner->BelongsToCurrentThread());
97
98   core_ = new Core(caller_task_runner, ui_task_runner, event_handler);
99   core_->Connect(screen_size, terminal_id);
100 }
101
102 RdpClient::~RdpClient() {
103   DCHECK(CalledOnValidThread());
104
105   core_->Disconnect();
106 }
107
108 void RdpClient::InjectSas() {
109   DCHECK(CalledOnValidThread());
110
111   core_->InjectSas();
112 }
113
114 RdpClient::Core::Core(
115     scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
116     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
117     RdpClient::EventHandler* event_handler)
118     : caller_task_runner_(caller_task_runner),
119       ui_task_runner_(ui_task_runner),
120       event_handler_(event_handler) {
121 }
122
123 void RdpClient::Core::Connect(const webrtc::DesktopSize& screen_size,
124                               const std::string& terminal_id) {
125   if (!ui_task_runner_->BelongsToCurrentThread()) {
126     ui_task_runner_->PostTask(
127         FROM_HERE, base::Bind(&Core::Connect, this, screen_size, terminal_id));
128     return;
129   }
130
131   DCHECK(base::MessageLoopForUI::IsCurrent());
132   DCHECK(!rdp_client_window_);
133   DCHECK(!self_);
134
135   // Read the port number used by RDP.
136   DWORD server_port;
137   base::win::RegKey key(HKEY_LOCAL_MACHINE, kRdpPortKeyName, KEY_READ);
138   if (!key.Valid() ||
139       (key.ReadValueDW(kRdpPortValueName, &server_port) != ERROR_SUCCESS)) {
140     server_port = kDefaultRdpPort;
141   }
142
143   net::IPAddressNumber server_address(
144       kRdpLoopbackAddress,
145       kRdpLoopbackAddress + arraysize(kRdpLoopbackAddress));
146   net::IPEndPoint server_endpoint(server_address, server_port);
147
148   // Create the ActiveX control window.
149   rdp_client_window_.reset(new RdpClientWindow(server_endpoint, terminal_id,
150                                                this));
151   if (!rdp_client_window_->Connect(screen_size)) {
152     rdp_client_window_.reset();
153
154     // Notify the caller that connection attempt failed.
155     NotifyClosed();
156   }
157 }
158
159 void RdpClient::Core::Disconnect() {
160   if (!ui_task_runner_->BelongsToCurrentThread()) {
161     ui_task_runner_->PostTask(FROM_HERE, base::Bind(&Core::Disconnect, this));
162     return;
163   }
164
165   // The caller does not expect any notifications to be delivered after this
166   // point.
167   event_handler_ = NULL;
168
169   // Gracefully shutdown the RDP connection.
170   if (rdp_client_window_) {
171     self_ = this;
172     rdp_client_window_->Disconnect();
173   }
174 }
175
176 void RdpClient::Core::InjectSas() {
177   if (!ui_task_runner_->BelongsToCurrentThread()) {
178     ui_task_runner_->PostTask(FROM_HERE, base::Bind(&Core::InjectSas, this));
179     return;
180   }
181
182   if (rdp_client_window_)
183     rdp_client_window_->InjectSas();
184 }
185
186 void RdpClient::Core::OnConnected() {
187   DCHECK(ui_task_runner_->BelongsToCurrentThread());
188   DCHECK(rdp_client_window_);
189
190   NotifyConnected();
191 }
192
193 void RdpClient::Core::OnDisconnected() {
194   DCHECK(ui_task_runner_->BelongsToCurrentThread());
195   DCHECK(rdp_client_window_);
196
197   NotifyClosed();
198
199   // Delay window destruction until no ActiveX control's code is on the stack.
200   ui_task_runner_->DeleteSoon(FROM_HERE, rdp_client_window_.release());
201   self_ = NULL;
202 }
203
204 RdpClient::Core::~Core() {
205   DCHECK(!event_handler_);
206   DCHECK(!rdp_client_window_);
207 }
208
209 void RdpClient::Core::NotifyConnected() {
210   if (!caller_task_runner_->BelongsToCurrentThread()) {
211     caller_task_runner_->PostTask(
212         FROM_HERE, base::Bind(&Core::NotifyConnected, this));
213     return;
214   }
215
216   if (event_handler_)
217     event_handler_->OnRdpConnected();
218 }
219
220 void RdpClient::Core::NotifyClosed() {
221   if (!caller_task_runner_->BelongsToCurrentThread()) {
222     caller_task_runner_->PostTask(
223         FROM_HERE, base::Bind(&Core::NotifyClosed, this));
224     return;
225   }
226
227   if (event_handler_) {
228     RdpClient::EventHandler* event_handler = event_handler_;
229     event_handler_ = NULL;
230     event_handler->OnRdpClosed();
231   }
232 }
233
234 }  // namespace remoting