OLD | NEW |
---|---|
(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 "net/socket/client_socket_factory.h" | |
10 #include "remoting/client/audio_player.h" | |
11 #include "remoting/client/software_video_renderer.h" | |
12 #include "remoting/client/plugin/delegating_signal_strategy.h" | |
13 #include "remoting/jingle_glue/chromium_port_allocator.h" | |
14 #include "remoting/protocol/host_stub.h" | |
15 #include "remoting/protocol/libjingle_transport_factory.h" | |
16 | |
17 #include "remoting/ios/bridge/client_bridge.h" | |
18 | |
19 namespace { | |
20 const char* const kXmppServer = "talk.google.com"; | |
21 const int kXmppPort = 5222; | |
22 const bool kXmppUseTls = true; | |
23 } // namespace | |
24 | |
25 namespace remoting { | |
26 | |
27 ClientInstance::ClientInstance(ClientBridge* bridge, | |
28 const char* username, | |
29 const char* auth_token, | |
30 const char* host_jid, | |
31 const char* host_id, | |
32 const char* host_pubkey, | |
33 const char* pairing_id, | |
34 const char* pairing_secret) | |
35 : bridge_(bridge), | |
36 host_id_(host_id), | |
37 client_context_(bridge_->network_task_runner().get()), | |
38 create_pairing_(false) { | |
39 DCHECK(bridge_->ui_task_runner()->BelongsToCurrentThread()); | |
40 | |
41 // Intialize XMPP config. | |
42 xmpp_config_.host = kXmppServer; | |
43 xmpp_config_.port = kXmppPort; | |
44 xmpp_config_.use_tls = kXmppUseTls; | |
45 xmpp_config_.username = username; | |
46 xmpp_config_.auth_token = auth_token; | |
47 xmpp_config_.auth_service = "oauth2"; | |
48 | |
49 // Initialize ClientConfig. | |
50 client_config_.host_jid = host_jid; | |
51 client_config_.host_public_key = host_pubkey; | |
52 | |
53 client_config_.fetch_secret_callback = | |
54 base::Bind(&ClientInstance::FetchSecret, this); | |
55 client_config_.authentication_tag = host_id_; | |
56 | |
57 client_config_.client_pairing_id = pairing_id; | |
58 client_config_.client_paired_secret = pairing_secret; | |
59 | |
60 client_config_.authentication_methods.push_back( | |
61 protocol::AuthenticationMethod::FromString("spake2_pair")); | |
62 client_config_.authentication_methods.push_back( | |
63 protocol::AuthenticationMethod::FromString("spake2_hmac")); | |
64 client_config_.authentication_methods.push_back( | |
65 protocol::AuthenticationMethod::FromString("spake2_plain")); | |
66 | |
67 // Post a task to start connection | |
68 bridge_->network_task_runner()->PostTask( | |
69 FROM_HERE, | |
70 base::Bind(&ClientInstance::ConnectToHostOnNetworkThread, this)); | |
71 } | |
72 | |
73 ClientInstance::~ClientInstance() {} | |
74 | |
75 void ClientInstance::Cleanup() { | |
76 DCHECK(bridge_->ui_task_runner()->BelongsToCurrentThread()); | |
77 | |
78 bridge_->network_task_runner()->PostTask( | |
79 FROM_HERE, | |
80 base::Bind(&ClientInstance::DisconnectFromHostOnNetworkThread, this)); | |
81 } | |
82 | |
83 // CLIENT reporting user provided PIN | |
84 void ClientInstance::ProvideSecret(const std::string& pin, | |
85 bool create_pairing) { | |
86 DCHECK(bridge_->ui_task_runner()->BelongsToCurrentThread()); | |
87 DCHECK(!pin_callback_.is_null()); | |
88 | |
89 create_pairing_ = create_pairing; | |
90 | |
91 bridge_->network_task_runner()->PostTask(FROM_HERE, | |
92 base::Bind(pin_callback_, pin)); | |
93 } | |
94 | |
95 // CLIENT invoked mouse input | |
96 void ClientInstance::PerformMouseAction( | |
97 const webrtc::DesktopVector& position, | |
98 const webrtc::DesktopVector& wheel_delta, | |
99 int /* protocol::MouseEvent_MouseButton */ whichButton, | |
100 bool button_down) { | |
101 // Button must be within the bounds of the MouseEvent_MouseButton enum. | |
102 DCHECK(whichButton >= 0 && whichButton < 5); | |
103 | |
104 protocol::MouseEvent_MouseButton mButton = | |
105 static_cast<remoting::protocol::MouseEvent_MouseButton>(whichButton); | |
106 | |
107 if (!bridge_->network_task_runner()->BelongsToCurrentThread()) { | |
dcaiafa
2014/03/19 01:14:15
Move this to the top of the function.
aboone
2014/03/21 16:42:07
Done.
| |
108 bridge_->network_task_runner()->PostTask( | |
109 FROM_HERE, | |
110 base::Bind(&ClientInstance::PerformMouseAction, | |
111 this, | |
112 position, | |
113 wheel_delta, | |
114 mButton, | |
115 button_down)); | |
116 return; | |
117 } | |
118 | |
119 protocol::MouseEvent action; | |
120 action.set_x(position.x()); | |
121 action.set_y(position.y()); | |
122 action.set_wheel_delta_x(wheel_delta.x()); | |
123 action.set_wheel_delta_y(wheel_delta.y()); | |
124 action.set_button(mButton); | |
125 if (mButton != protocol::MouseEvent::BUTTON_UNDEFINED) | |
126 action.set_button_down(button_down); | |
127 | |
128 connection_->input_stub()->InjectMouseEvent(action); | |
129 } | |
130 | |
131 // CLIENT invoked keyboard input | |
132 void ClientInstance::PerformKeyboardAction(int key_code, bool key_down) { | |
133 if (!bridge_->network_task_runner()->BelongsToCurrentThread()) { | |
134 bridge_->network_task_runner()->PostTask( | |
135 FROM_HERE, | |
136 base::Bind( | |
137 &ClientInstance::PerformKeyboardAction, this, key_code, key_down)); | |
138 return; | |
139 } | |
140 | |
141 protocol::KeyEvent action; | |
142 action.set_usb_keycode(key_code); | |
143 action.set_pressed(key_down); | |
144 connection_->input_stub()->InjectKeyEvent(action); | |
145 } | |
146 | |
147 // HOST reporting Connections State and/or Error | |
148 void ClientInstance::OnConnectionState(protocol::ConnectionToHost::State state, | |
149 protocol::ErrorCode error) { | |
150 if (!bridge_->ui_task_runner()->BelongsToCurrentThread()) { | |
151 bridge_->ui_task_runner()->PostTask( | |
152 FROM_HERE, | |
153 base::Bind(&ClientInstance::OnConnectionState, this, state, error)); | |
154 return; | |
155 } | |
156 | |
157 if (create_pairing_ && state == protocol::ConnectionToHost::CONNECTED) { | |
158 VLOG(1) << "Attempting to pair with host"; | |
159 protocol::PairingRequest request; | |
160 request.set_client_name("iPad"); | |
161 connection_->host_stub()->RequestPairing(request); | |
162 } | |
163 | |
164 bridge_->ui_task_runner()->PostTask( | |
165 FROM_HERE, | |
166 base::Bind(&ClientBridge::ReportConnectionStatus, | |
167 base::Unretained(bridge_.get()), | |
dcaiafa
2014/03/19 01:14:15
ClientBridge is currently RefCounted, so there sho
aboone
2014/03/21 16:42:07
Done.
| |
168 state, | |
169 error)); | |
170 } | |
171 | |
172 void ClientInstance::OnConnectionReady(bool ready) { | |
173 // We ignore this message, since OnConnectoinState tells us the same thing. | |
174 } | |
175 | |
176 void ClientInstance::OnRouteChanged(const std::string& channel_name, | |
177 const protocol::TransportRoute& route) { | |
178 VLOG(1) << "Using " << protocol::TransportRoute::GetTypeString(route.type) | |
179 << " connection for " << channel_name << " channel"; | |
180 } | |
181 | |
182 void ClientInstance::SetCapabilities(const std::string& capabilities) { | |
183 video_renderer_->Initialize(connection_->config()); | |
184 } | |
185 | |
186 // HOST accepted client creditials, and response | |
187 void ClientInstance::SetPairingResponse( | |
188 const protocol::PairingResponse& response) { | |
189 VLOG(1) << "Successfully established pairing with host"; | |
190 | |
191 bridge_->ui_task_runner()->PostTask( | |
192 FROM_HERE, | |
193 base::Bind(&ClientBridge::CommitPairingCredentials, | |
194 base::Unretained(bridge_.get()), | |
dcaiafa
2014/03/19 01:14:15
Same as OnConnectionState().
aboone
2014/03/21 16:42:07
Done.
| |
195 host_id_, | |
196 response.client_id(), | |
197 response.shared_secret())); | |
198 } | |
199 | |
200 void ClientInstance::DeliverHostMessage( | |
201 const protocol::ExtensionMessage& message) { | |
202 NOTIMPLEMENTED(); | |
203 } | |
204 | |
205 // THIS inhereits protocol::ClipboardStub, returning a view of THIS as a | |
206 // protocol::ClipboardStub | |
207 protocol::ClipboardStub* ClientInstance::GetClipboardStub() { return this; } | |
208 | |
209 // THIS inhereits protocol::CursorShapeStub, returning a view of THIS as a | |
210 // protocol::CursorShapeStub | |
211 protocol::CursorShapeStub* ClientInstance::GetCursorShapeStub() { return this; } | |
212 | |
213 scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher> | |
214 ClientInstance::GetTokenFetcher(const std::string& host_public_key) { | |
215 // Return null to indicate that third-party authentication is unsupported. | |
216 return scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>(); | |
217 } | |
218 | |
219 void ClientInstance::InjectClipboardEvent( | |
220 const protocol::ClipboardEvent& event) { | |
221 NOTIMPLEMENTED(); | |
222 } | |
223 | |
224 // HOST delivering a Cursor (mouse) update | |
225 void ClientInstance::SetCursorShape(const protocol::CursorShapeInfo& shape) { | |
226 if (!bridge_->ui_task_runner()->BelongsToCurrentThread()) { | |
227 bridge_->ui_task_runner()->PostTask( | |
228 FROM_HERE, base::Bind(&ClientInstance::SetCursorShape, this, shape)); | |
229 return; | |
230 } | |
231 | |
232 bridge_->UpdateCursorShape(shape); | |
233 } | |
234 | |
235 // Create a thread to receive and package Canvas (desktop) updates | |
236 void ClientInstance::ConnectToHostOnNetworkThread() { | |
237 DCHECK(bridge_->network_task_runner()->BelongsToCurrentThread()); | |
238 | |
239 view_.reset( | |
240 new FrameConsumerBridge(bridge_->BindToFrameConsumerBridgeCallback())); | |
dcaiafa
2014/03/19 01:14:15
Create the binding on site instead of using a help
aboone
2014/03/21 16:42:07
Done.
| |
241 view_weak_factory_.reset( | |
dcaiafa
2014/03/19 01:14:15
Move the WeakPtrFactory into FrameConsumerBridge,
aboone
2014/03/21 16:42:07
Done.
| |
242 new base::WeakPtrFactory<FrameConsumer>(view_.get())); | |
243 | |
244 client_context_.Start(); | |
245 | |
246 scoped_refptr<FrameConsumerProxy> consumer_proxy = new FrameConsumerProxy( | |
247 bridge_->network_task_runner(), view_weak_factory_->GetWeakPtr()); | |
248 | |
249 SoftwareVideoRenderer* renderer = | |
250 new SoftwareVideoRenderer(client_context_.main_task_runner(), | |
251 client_context_.decode_task_runner(), | |
252 consumer_proxy); | |
253 | |
254 view_->Initialize(renderer); | |
255 video_renderer_.reset(renderer); | |
256 | |
257 connection_.reset(new protocol::ConnectionToHost(true)); | |
258 | |
259 client_.reset(new ChromotingClient(client_config_, | |
260 &client_context_, | |
261 connection_.get(), | |
262 this, | |
263 video_renderer_.get(), | |
264 scoped_ptr<AudioPlayer>())); | |
265 | |
266 signaling_.reset( | |
267 new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(), | |
268 bridge_->url_requester(), | |
269 xmpp_config_)); | |
270 | |
271 NetworkSettings network_settings(NetworkSettings::NAT_TRAVERSAL_ENABLED); | |
272 | |
273 scoped_ptr<ChromiumPortAllocator> port_allocator( | |
274 ChromiumPortAllocator::Create(bridge_->url_requester(), | |
275 network_settings)); | |
276 | |
277 scoped_ptr<protocol::TransportFactory> transport_factory( | |
278 new protocol::LibjingleTransportFactory( | |
279 signaling_.get(), | |
280 port_allocator.PassAs<cricket::HttpPortAllocatorBase>(), | |
281 network_settings)); | |
282 | |
283 client_->Start(signaling_.get(), transport_factory.Pass()); | |
284 } | |
285 | |
286 void ClientInstance::DisconnectFromHostOnNetworkThread() { | |
287 DCHECK(bridge_->network_task_runner()->BelongsToCurrentThread()); | |
288 | |
289 // This must be destroyed on the network thread before the producer is gone. | |
290 view_.reset(); | |
291 | |
292 // The weak pointers must be invalidated on the same thread they were used. | |
293 view_weak_factory_->InvalidateWeakPtrs(); | |
294 | |
295 host_id_.clear(); | |
296 | |
297 // |client_| must be torn down before |signaling_|. | |
298 connection_.reset(); | |
299 client_.reset(); | |
300 client_context_.Stop(); | |
301 } | |
302 | |
303 // HOST attempts to continue automatically with previously supplied credentials, | |
304 // if it can't it requests the user's PIN. | |
305 void ClientInstance::FetchSecret( | |
306 bool pairable, | |
307 const protocol::SecretFetchedCallback& callback) { | |
308 if (!bridge_->ui_task_runner()->BelongsToCurrentThread()) { | |
309 bridge_->ui_task_runner()->PostTask( | |
310 FROM_HERE, | |
311 base::Bind(&ClientInstance::FetchSecret, this, pairable, callback)); | |
312 return; | |
313 } | |
314 | |
315 if (!client_config_.client_pairing_id.empty()) { | |
316 // We attempted to connect using an existing pairing that was rejected. | |
317 // Unless we forget about the stale credentials, we'll continue trying them. | |
318 VLOG(1) << "Deleting rejected pairing credentials"; | |
319 bridge_->CommitPairingCredentials(host_id_, "", ""); | |
320 } | |
321 | |
322 pin_callback_ = callback; | |
323 bridge_->DisplayAuthenticationPrompt(pairable); | |
324 } | |
325 | |
326 } // namespace remoting | |
OLD | NEW |