Chromium Code Reviews| 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 |