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