BookmarkManager: Fix 'new folder text field size changes on clicking it' issue.
[chromium-blink-merge.git] / remoting / host / win / rdp_client.cc
blob8f029ef599be8807d08deda3bb93a40a438f62e5
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.
5 #include "remoting/host/win/rdp_client.h"
7 #include <windows.h>
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"
19 namespace remoting {
21 namespace {
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 };
27 const int kDefaultRdpPort = 3389;
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";
34 } // namespace
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);
48 // Initiates a loopback RDP connection.
49 void Connect(const webrtc::DesktopSize& screen_size,
50 const std::string& terminal_id);
52 // Initiates a graceful shutdown of the RDP connection.
53 void Disconnect();
55 // Sends Secure Attention Sequence to the session.
56 void InjectSas();
58 // RdpClientWindow::EventHandler interface.
59 void OnConnected() override;
60 void OnDisconnected() override;
62 private:
63 friend class base::RefCountedThreadSafe<Core>;
64 ~Core() override;
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();
71 // Task runner on which the caller expects |event_handler_| to be notified.
72 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
74 // Task runner on which |rdp_client_window_| is running.
75 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
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_;
81 // Hosts the RDP ActiveX control.
82 scoped_ptr<RdpClientWindow> rdp_client_window_;
84 // A self-reference to keep the object alive during connection shutdown.
85 scoped_refptr<Core> self_;
87 DISALLOW_COPY_AND_ASSIGN(Core);
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());
98 core_ = new Core(caller_task_runner, ui_task_runner, event_handler);
99 core_->Connect(screen_size, terminal_id);
102 RdpClient::~RdpClient() {
103 DCHECK(CalledOnValidThread());
105 core_->Disconnect();
108 void RdpClient::InjectSas() {
109 DCHECK(CalledOnValidThread());
111 core_->InjectSas();
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) {
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;
131 DCHECK(base::MessageLoopForUI::IsCurrent());
132 DCHECK(!rdp_client_window_);
133 DCHECK(!self_.get());
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 > 65535) {
141 server_port = kDefaultRdpPort;
144 net::IPAddressNumber server_address(
145 kRdpLoopbackAddress,
146 kRdpLoopbackAddress + arraysize(kRdpLoopbackAddress));
147 net::IPEndPoint server_endpoint(server_address,
148 static_cast<uint16>(server_port));
150 // Create the ActiveX control window.
151 rdp_client_window_.reset(new RdpClientWindow(server_endpoint, terminal_id,
152 this));
153 if (!rdp_client_window_->Connect(screen_size)) {
154 rdp_client_window_.reset();
156 // Notify the caller that connection attempt failed.
157 NotifyClosed();
161 void RdpClient::Core::Disconnect() {
162 if (!ui_task_runner_->BelongsToCurrentThread()) {
163 ui_task_runner_->PostTask(FROM_HERE, base::Bind(&Core::Disconnect, this));
164 return;
167 // The caller does not expect any notifications to be delivered after this
168 // point.
169 event_handler_ = nullptr;
171 // Gracefully shutdown the RDP connection.
172 if (rdp_client_window_) {
173 self_ = this;
174 rdp_client_window_->Disconnect();
178 void RdpClient::Core::InjectSas() {
179 if (!ui_task_runner_->BelongsToCurrentThread()) {
180 ui_task_runner_->PostTask(FROM_HERE, base::Bind(&Core::InjectSas, this));
181 return;
184 if (rdp_client_window_)
185 rdp_client_window_->InjectSas();
188 void RdpClient::Core::OnConnected() {
189 DCHECK(ui_task_runner_->BelongsToCurrentThread());
190 DCHECK(rdp_client_window_);
192 NotifyConnected();
195 void RdpClient::Core::OnDisconnected() {
196 DCHECK(ui_task_runner_->BelongsToCurrentThread());
197 DCHECK(rdp_client_window_);
199 NotifyClosed();
201 // Delay window destruction until no ActiveX control's code is on the stack.
202 ui_task_runner_->DeleteSoon(FROM_HERE, rdp_client_window_.release());
203 self_ = nullptr;
206 RdpClient::Core::~Core() {
207 DCHECK(!event_handler_);
208 DCHECK(!rdp_client_window_);
211 void RdpClient::Core::NotifyConnected() {
212 if (!caller_task_runner_->BelongsToCurrentThread()) {
213 caller_task_runner_->PostTask(
214 FROM_HERE, base::Bind(&Core::NotifyConnected, this));
215 return;
218 if (event_handler_)
219 event_handler_->OnRdpConnected();
222 void RdpClient::Core::NotifyClosed() {
223 if (!caller_task_runner_->BelongsToCurrentThread()) {
224 caller_task_runner_->PostTask(
225 FROM_HERE, base::Bind(&Core::NotifyClosed, this));
226 return;
229 if (event_handler_) {
230 RdpClient::EventHandler* event_handler = event_handler_;
231 event_handler_ = nullptr;
232 event_handler->OnRdpClosed();
236 } // namespace remoting