Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(168)

Side by Side Diff: remoting/ios/bridge/client_instance.cc

Issue 278863003: Chromoting iOS client (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « remoting/ios/bridge/client_instance.h ('k') | remoting/ios/bridge/client_instance_unittest.mm » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 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/ios/bridge/client_instance.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/synchronization/waitable_event.h"
10 #include "net/socket/client_socket_factory.h"
11 #include "remoting/base/url_request_context.h"
12 #include "remoting/client/audio_player.h"
13 #include "remoting/client/plugin/delegating_signal_strategy.h"
14 #include "remoting/ios/bridge/client_proxy.h"
15 #include "remoting/jingle_glue/chromium_port_allocator.h"
16 #include "remoting/protocol/host_stub.h"
17 #include "remoting/protocol/libjingle_transport_factory.h"
18
19 namespace {
20 const char* const kXmppServer = "talk.google.com";
21 const int kXmppPort = 5222;
22 const bool kXmppUseTls = true;
23
24 void DoNothing() {}
25 } // namespace
26
27 namespace remoting {
28
29 ClientInstance::ClientInstance(const base::WeakPtr<ClientProxy>& proxy,
30 const std::string& username,
31 const std::string& auth_token,
32 const std::string& host_jid,
33 const std::string& host_id,
34 const std::string& host_pubkey,
35 const std::string& pairing_id,
36 const std::string& pairing_secret)
37 : proxyToClient_(proxy), host_id_(host_id), create_pairing_(false) {
38
39 if (!base::MessageLoop::current()) {
40 VLOG(1) << "Starting main message loop";
41 ui_loop_ = new base::MessageLoopForUI();
42 ui_loop_->Attach();
43 } else {
44 VLOG(1) << "Using existing main message loop";
45 ui_loop_ = base::MessageLoopForUI::current();
46 }
47
48 VLOG(1) << "Spawning additional threads";
49
50 // |ui_loop_| runs on the main thread, so |ui_task_runner_| will run on the
51 // main thread. We can not kill the main thread when the message loop becomes
52 // idle so the callback function does nothing (as opposed to the typical
53 // base::MessageLoop::QuitClosure())
54 ui_task_runner_ = new AutoThreadTaskRunner(ui_loop_->message_loop_proxy(),
55 base::Bind(&::DoNothing));
56
57 network_task_runner_ = AutoThread::CreateWithType(
58 "native_net", ui_task_runner_, base::MessageLoop::TYPE_IO);
59
60 url_requester_ = new URLRequestContextGetter(network_task_runner_);
61
62 client_context_.reset(new ClientContext(network_task_runner_));
63
64 DCHECK(ui_task_runner_->BelongsToCurrentThread());
65
66 // Initialize XMPP config.
67 xmpp_config_.host = kXmppServer;
68 xmpp_config_.port = kXmppPort;
69 xmpp_config_.use_tls = kXmppUseTls;
70 xmpp_config_.username = username;
71 xmpp_config_.auth_token = auth_token;
72 xmpp_config_.auth_service = "oauth2";
73
74 // Initialize ClientConfig.
75 client_config_.host_jid = host_jid;
76 client_config_.host_public_key = host_pubkey;
77 client_config_.authentication_tag = host_id_;
78 client_config_.client_pairing_id = pairing_id;
79 client_config_.client_paired_secret = pairing_secret;
80 client_config_.authentication_methods.push_back(
81 protocol::AuthenticationMethod::FromString("spake2_pair"));
82 client_config_.authentication_methods.push_back(
83 protocol::AuthenticationMethod::FromString("spake2_hmac"));
84 client_config_.authentication_methods.push_back(
85 protocol::AuthenticationMethod::FromString("spake2_plain"));
86 }
87
88 ClientInstance::~ClientInstance() {}
89
90 void ClientInstance::Start() {
91 DCHECK(ui_task_runner_->BelongsToCurrentThread());
92
93 // Creates a reference to |this|, so don't want to bind during constructor
94 client_config_.fetch_secret_callback =
95 base::Bind(&ClientInstance::FetchSecret, this);
96
97 view_.reset(new FrameConsumerBridge(
98 base::Bind(&ClientProxy::RedrawCanvas, proxyToClient_)));
99
100 // |consumer_proxy| must be created on the UI thread to proxy calls from the
101 // network or decode thread to the UI thread, but ownership will belong to a
102 // SoftwareVideoRenderer which runs on the network thread.
103 scoped_refptr<FrameConsumerProxy> consumer_proxy =
104 new FrameConsumerProxy(ui_task_runner_, view_->AsWeakPtr());
105
106 // Post a task to start connection
107 base::WaitableEvent done_event(true, false);
108 network_task_runner_->PostTask(
109 FROM_HERE,
110 base::Bind(&ClientInstance::ConnectToHostOnNetworkThread,
111 this,
112 consumer_proxy,
113 base::Bind(&base::WaitableEvent::Signal,
114 base::Unretained(&done_event))));
115 // Wait until initialization completes before continuing
116 done_event.Wait();
117 }
118
119 void ClientInstance::Cleanup() {
120 DCHECK(ui_task_runner_->BelongsToCurrentThread());
121
122 client_config_.fetch_secret_callback.Reset(); // Release ref to this
123 // |view_| must be destroyed on the UI thread before the producer is gone.
124 view_.reset();
125
126 base::WaitableEvent done_event(true, false);
127 network_task_runner_->PostTask(
128 FROM_HERE,
129 base::Bind(&ClientInstance::DisconnectFromHostOnNetworkThread,
130 this,
131 base::Bind(&base::WaitableEvent::Signal,
132 base::Unretained(&done_event))));
133 // Wait until we are fully disconnected before continuing
134 done_event.Wait();
135 }
136
137 // HOST attempts to continue automatically with previously supplied credentials,
138 // if it can't it requests the user's PIN.
139 void ClientInstance::FetchSecret(
140 bool pairable,
141 const protocol::SecretFetchedCallback& callback) {
142 if (!ui_task_runner_->BelongsToCurrentThread()) {
143 ui_task_runner_->PostTask(
144 FROM_HERE,
145 base::Bind(&ClientInstance::FetchSecret, this, pairable, callback));
146 return;
147 }
148
149 pin_callback_ = callback;
150
151 if (proxyToClient_) {
152 if (!client_config_.client_pairing_id.empty()) {
153 // We attempted to connect using an existing pairing that was rejected.
154 // Unless we forget about the stale credentials, we'll continue trying
155 // them.
156 VLOG(1) << "Deleting rejected pairing credentials";
157
158 proxyToClient_->CommitPairingCredentials(host_id_, "", "");
159 }
160 proxyToClient_->DisplayAuthenticationPrompt(pairable);
161 }
162 }
163
164 void ClientInstance::ProvideSecret(const std::string& pin,
165 bool create_pairing) {
166 DCHECK(ui_task_runner_->BelongsToCurrentThread());
167 create_pairing_ = create_pairing;
168
169 // Before this function can complete, FetchSecret must be called
170 DCHECK(!pin_callback_.is_null());
171 network_task_runner_->PostTask(FROM_HERE, base::Bind(pin_callback_, pin));
172 }
173
174 void ClientInstance::PerformMouseAction(
175 const webrtc::DesktopVector& position,
176 const webrtc::DesktopVector& wheel_delta,
177 int /* protocol::MouseEvent_MouseButton */ whichButton,
178 bool button_down) {
179 if (!network_task_runner_->BelongsToCurrentThread()) {
180 network_task_runner_->PostTask(
181 FROM_HERE,
182 base::Bind(&ClientInstance::PerformMouseAction,
183 this,
184 position,
185 wheel_delta,
186 whichButton,
187 button_down));
188 return;
189 }
190
191 protocol::MouseEvent_MouseButton mButton;
192
193 // Button must be within the bounds of the MouseEvent_MouseButton enum.
194 switch (whichButton) {
195 case protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_LEFT:
196 mButton =
197 protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_LEFT;
198 break;
199 case protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_MAX:
200 mButton =
201 protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_MAX;
202 break;
203 case protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_MIDDLE:
204 mButton = protocol::MouseEvent_MouseButton::
205 MouseEvent_MouseButton_BUTTON_MIDDLE;
206 break;
207 case protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_RIGHT:
208 mButton =
209 protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_RIGHT;
210 break;
211 case protocol::MouseEvent_MouseButton::
212 MouseEvent_MouseButton_BUTTON_UNDEFINED:
213 mButton = protocol::MouseEvent_MouseButton::
214 MouseEvent_MouseButton_BUTTON_UNDEFINED;
215 break;
216 default:
217 LOG(FATAL) << "Invalid constant for MouseEvent_MouseButton";
218 mButton = protocol::MouseEvent_MouseButton::
219 MouseEvent_MouseButton_BUTTON_UNDEFINED;
220 break;
221 }
222
223 protocol::MouseEvent action;
224 action.set_x(position.x());
225 action.set_y(position.y());
226 action.set_wheel_delta_x(wheel_delta.x());
227 action.set_wheel_delta_y(wheel_delta.y());
228 action.set_button(mButton);
229 if (mButton != protocol::MouseEvent::BUTTON_UNDEFINED)
230 action.set_button_down(button_down);
231
232 connection_->input_stub()->InjectMouseEvent(action);
233 }
234
235 void ClientInstance::PerformKeyboardAction(int key_code, bool key_down) {
236 if (!network_task_runner_->BelongsToCurrentThread()) {
237 network_task_runner_->PostTask(
238 FROM_HERE,
239 base::Bind(
240 &ClientInstance::PerformKeyboardAction, this, key_code, key_down));
241 return;
242 }
243
244 protocol::KeyEvent action;
245 action.set_usb_keycode(key_code);
246 action.set_pressed(key_down);
247 connection_->input_stub()->InjectKeyEvent(action);
248 }
249
250 void ClientInstance::OnConnectionState(protocol::ConnectionToHost::State state,
251 protocol::ErrorCode error) {
252 if (!ui_task_runner_->BelongsToCurrentThread()) {
253 ui_task_runner_->PostTask(
254 FROM_HERE,
255 base::Bind(&ClientInstance::OnConnectionState, this, state, error));
256 return;
257 }
258
259 // TODO (aboone) This functionality is not scheduled for QA yet.
260 // if (create_pairing_ && state == protocol::ConnectionToHost::CONNECTED) {
261 // VLOG(1) << "Attempting to pair with host";
262 // protocol::PairingRequest request;
263 // request.set_client_name("iOS");
264 // connection_->host_stub()->RequestPairing(request);
265 // }
266
267 if (proxyToClient_)
268 proxyToClient_->ReportConnectionStatus(state, error);
269 }
270
271 void ClientInstance::OnConnectionReady(bool ready) {
272 // We ignore this message, since OnConnectionState tells us the same thing.
273 }
274
275 void ClientInstance::OnRouteChanged(const std::string& channel_name,
276 const protocol::TransportRoute& route) {
277 VLOG(1) << "Using " << protocol::TransportRoute::GetTypeString(route.type)
278 << " connection for " << channel_name << " channel";
279 }
280
281 void ClientInstance::SetCapabilities(const std::string& capabilities) {
282 DCHECK(video_renderer_);
283 DCHECK(connection_);
284 DCHECK(connection_->state() == protocol::ConnectionToHost::CONNECTED);
285 video_renderer_->Initialize(connection_->config());
286 }
287
288 void ClientInstance::SetPairingResponse(
289 const protocol::PairingResponse& response) {
290 if (!ui_task_runner_->BelongsToCurrentThread()) {
291 ui_task_runner_->PostTask(
292 FROM_HERE,
293 base::Bind(&ClientInstance::SetPairingResponse, this, response));
294 return;
295 }
296
297 VLOG(1) << "Successfully established pairing with host";
298
299 if (proxyToClient_)
300 proxyToClient_->CommitPairingCredentials(
301 host_id_, response.client_id(), response.shared_secret());
302 }
303
304 void ClientInstance::DeliverHostMessage(
305 const protocol::ExtensionMessage& message) {
306 NOTIMPLEMENTED();
307 }
308
309 // Returning interface of protocol::ClipboardStub
310 protocol::ClipboardStub* ClientInstance::GetClipboardStub() { return this; }
311
312 // Returning interface of protocol::CursorShapeStub
313 protocol::CursorShapeStub* ClientInstance::GetCursorShapeStub() { return this; }
314
315 scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>
316 ClientInstance::GetTokenFetcher(const std::string& host_public_key) {
317 // Returns null when third-party authentication is unsupported.
318 return scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>();
319 }
320
321 void ClientInstance::InjectClipboardEvent(
322 const protocol::ClipboardEvent& event) {
323 NOTIMPLEMENTED();
324 }
325
326 void ClientInstance::SetCursorShape(const protocol::CursorShapeInfo& shape) {
327 if (!ui_task_runner_->BelongsToCurrentThread()) {
328 ui_task_runner_->PostTask(
329 FROM_HERE, base::Bind(&ClientInstance::SetCursorShape, this, shape));
330 return;
331 }
332 if (proxyToClient_)
333 proxyToClient_->UpdateCursorShape(shape);
334 }
335
336 void ClientInstance::ConnectToHostOnNetworkThread(
337 scoped_refptr<FrameConsumerProxy> consumer_proxy,
338 const base::Closure& done) {
339 DCHECK(network_task_runner_->BelongsToCurrentThread());
340
341 client_context_->Start();
342
343 video_renderer_.reset(
344 new SoftwareVideoRenderer(client_context_->main_task_runner(),
345 client_context_->decode_task_runner(),
346 consumer_proxy));
347
348 view_->Initialize(video_renderer_.get());
349
350 connection_.reset(new protocol::ConnectionToHost(true));
351
352 client_.reset(new ChromotingClient(client_config_,
353 client_context_.get(),
354 connection_.get(),
355 this,
356 video_renderer_.get(),
357 scoped_ptr<AudioPlayer>()));
358
359 signaling_.reset(
360 new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(),
361 url_requester_,
362 xmpp_config_));
363
364 NetworkSettings network_settings(NetworkSettings::NAT_TRAVERSAL_ENABLED);
365
366 scoped_ptr<ChromiumPortAllocator> port_allocator(
367 ChromiumPortAllocator::Create(url_requester_, network_settings));
368
369 scoped_ptr<protocol::TransportFactory> transport_factory(
370 new protocol::LibjingleTransportFactory(
371 signaling_.get(),
372 port_allocator.PassAs<cricket::HttpPortAllocatorBase>(),
373 network_settings));
374
375 client_->Start(signaling_.get(), transport_factory.Pass());
376
377 if (!done.is_null())
378 done.Run();
379 }
380
381 void ClientInstance::DisconnectFromHostOnNetworkThread(
382 const base::Closure& done) {
383 DCHECK(network_task_runner_->BelongsToCurrentThread());
384
385 host_id_.clear();
386
387 // |client_| must be torn down before |signaling_|.
388 connection_.reset();
389 client_.reset();
390 signaling_.reset();
391 video_renderer_.reset();
392 client_context_->Stop();
393 if (!done.is_null())
394 done.Run();
395 }
396
397 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/ios/bridge/client_instance.h ('k') | remoting/ios/bridge/client_instance_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698