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

Unified Diff: remoting/ios/bridge/client_instance.cc

Issue 186733007: iOS Chromoting Client (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 9 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 side-by-side diff with in-line comments
Download patch
Index: remoting/ios/bridge/client_instance.cc
diff --git a/remoting/ios/bridge/client_instance.cc b/remoting/ios/bridge/client_instance.cc
new file mode 100644
index 0000000000000000000000000000000000000000..423a01a72417bc71d54e850b6848f22dab9288fc
--- /dev/null
+++ b/remoting/ios/bridge/client_instance.cc
@@ -0,0 +1,326 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "remoting/ios/bridge/client_instance.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "net/socket/client_socket_factory.h"
+#include "remoting/client/audio_player.h"
+#include "remoting/client/software_video_renderer.h"
+#include "remoting/client/plugin/delegating_signal_strategy.h"
+#include "remoting/jingle_glue/chromium_port_allocator.h"
+#include "remoting/protocol/host_stub.h"
+#include "remoting/protocol/libjingle_transport_factory.h"
+
+#include "remoting/ios/bridge/client_bridge.h"
+
+namespace {
+const char* const kXmppServer = "talk.google.com";
+const int kXmppPort = 5222;
+const bool kXmppUseTls = true;
+} // namespace
+
+namespace remoting {
+
+ClientInstance::ClientInstance(ClientBridge* bridge,
+ const char* username,
+ const char* auth_token,
+ const char* host_jid,
+ const char* host_id,
+ const char* host_pubkey,
+ const char* pairing_id,
+ const char* pairing_secret)
+ : bridge_(bridge),
+ host_id_(host_id),
+ client_context_(bridge_->network_task_runner().get()),
+ create_pairing_(false) {
+ DCHECK(bridge_->ui_task_runner()->BelongsToCurrentThread());
+
+ // Intialize XMPP config.
+ xmpp_config_.host = kXmppServer;
+ xmpp_config_.port = kXmppPort;
+ xmpp_config_.use_tls = kXmppUseTls;
+ xmpp_config_.username = username;
+ xmpp_config_.auth_token = auth_token;
+ xmpp_config_.auth_service = "oauth2";
+
+ // Initialize ClientConfig.
+ client_config_.host_jid = host_jid;
+ client_config_.host_public_key = host_pubkey;
+
+ client_config_.fetch_secret_callback =
+ base::Bind(&ClientInstance::FetchSecret, this);
+ client_config_.authentication_tag = host_id_;
+
+ client_config_.client_pairing_id = pairing_id;
+ client_config_.client_paired_secret = pairing_secret;
+
+ client_config_.authentication_methods.push_back(
+ protocol::AuthenticationMethod::FromString("spake2_pair"));
+ client_config_.authentication_methods.push_back(
+ protocol::AuthenticationMethod::FromString("spake2_hmac"));
+ client_config_.authentication_methods.push_back(
+ protocol::AuthenticationMethod::FromString("spake2_plain"));
+
+ // Post a task to start connection
+ bridge_->network_task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ClientInstance::ConnectToHostOnNetworkThread, this));
+}
+
+ClientInstance::~ClientInstance() {}
+
+void ClientInstance::Cleanup() {
+ DCHECK(bridge_->ui_task_runner()->BelongsToCurrentThread());
+
+ bridge_->network_task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ClientInstance::DisconnectFromHostOnNetworkThread, this));
+}
+
+// CLIENT reporting user provided PIN
+void ClientInstance::ProvideSecret(const std::string& pin,
+ bool create_pairing) {
+ DCHECK(bridge_->ui_task_runner()->BelongsToCurrentThread());
+ DCHECK(!pin_callback_.is_null());
+
+ create_pairing_ = create_pairing;
+
+ bridge_->network_task_runner()->PostTask(FROM_HERE,
+ base::Bind(pin_callback_, pin));
+}
+
+// CLIENT invoked mouse input
+void ClientInstance::PerformMouseAction(
+ const webrtc::DesktopVector& position,
+ const webrtc::DesktopVector& wheel_delta,
+ int /* protocol::MouseEvent_MouseButton */ whichButton,
+ bool button_down) {
+ // Button must be within the bounds of the MouseEvent_MouseButton enum.
+ DCHECK(whichButton >= 0 && whichButton < 5);
+
+ protocol::MouseEvent_MouseButton mButton =
+ static_cast<remoting::protocol::MouseEvent_MouseButton>(whichButton);
+
+ 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.
+ bridge_->network_task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ClientInstance::PerformMouseAction,
+ this,
+ position,
+ wheel_delta,
+ mButton,
+ button_down));
+ return;
+ }
+
+ protocol::MouseEvent action;
+ action.set_x(position.x());
+ action.set_y(position.y());
+ action.set_wheel_delta_x(wheel_delta.x());
+ action.set_wheel_delta_y(wheel_delta.y());
+ action.set_button(mButton);
+ if (mButton != protocol::MouseEvent::BUTTON_UNDEFINED)
+ action.set_button_down(button_down);
+
+ connection_->input_stub()->InjectMouseEvent(action);
+}
+
+// CLIENT invoked keyboard input
+void ClientInstance::PerformKeyboardAction(int key_code, bool key_down) {
+ if (!bridge_->network_task_runner()->BelongsToCurrentThread()) {
+ bridge_->network_task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &ClientInstance::PerformKeyboardAction, this, key_code, key_down));
+ return;
+ }
+
+ protocol::KeyEvent action;
+ action.set_usb_keycode(key_code);
+ action.set_pressed(key_down);
+ connection_->input_stub()->InjectKeyEvent(action);
+}
+
+// HOST reporting Connections State and/or Error
+void ClientInstance::OnConnectionState(protocol::ConnectionToHost::State state,
+ protocol::ErrorCode error) {
+ if (!bridge_->ui_task_runner()->BelongsToCurrentThread()) {
+ bridge_->ui_task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ClientInstance::OnConnectionState, this, state, error));
+ return;
+ }
+
+ if (create_pairing_ && state == protocol::ConnectionToHost::CONNECTED) {
+ VLOG(1) << "Attempting to pair with host";
+ protocol::PairingRequest request;
+ request.set_client_name("iPad");
+ connection_->host_stub()->RequestPairing(request);
+ }
+
+ bridge_->ui_task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ClientBridge::ReportConnectionStatus,
+ 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.
+ state,
+ error));
+}
+
+void ClientInstance::OnConnectionReady(bool ready) {
+ // We ignore this message, since OnConnectoinState tells us the same thing.
+}
+
+void ClientInstance::OnRouteChanged(const std::string& channel_name,
+ const protocol::TransportRoute& route) {
+ VLOG(1) << "Using " << protocol::TransportRoute::GetTypeString(route.type)
+ << " connection for " << channel_name << " channel";
+}
+
+void ClientInstance::SetCapabilities(const std::string& capabilities) {
+ video_renderer_->Initialize(connection_->config());
+}
+
+// HOST accepted client creditials, and response
+void ClientInstance::SetPairingResponse(
+ const protocol::PairingResponse& response) {
+ VLOG(1) << "Successfully established pairing with host";
+
+ bridge_->ui_task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ClientBridge::CommitPairingCredentials,
+ base::Unretained(bridge_.get()),
dcaiafa 2014/03/19 01:14:15 Same as OnConnectionState().
aboone 2014/03/21 16:42:07 Done.
+ host_id_,
+ response.client_id(),
+ response.shared_secret()));
+}
+
+void ClientInstance::DeliverHostMessage(
+ const protocol::ExtensionMessage& message) {
+ NOTIMPLEMENTED();
+}
+
+// THIS inhereits protocol::ClipboardStub, returning a view of THIS as a
+// protocol::ClipboardStub
+protocol::ClipboardStub* ClientInstance::GetClipboardStub() { return this; }
+
+// THIS inhereits protocol::CursorShapeStub, returning a view of THIS as a
+// protocol::CursorShapeStub
+protocol::CursorShapeStub* ClientInstance::GetCursorShapeStub() { return this; }
+
+scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>
+ClientInstance::GetTokenFetcher(const std::string& host_public_key) {
+ // Return null to indicate that third-party authentication is unsupported.
+ return scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>();
+}
+
+void ClientInstance::InjectClipboardEvent(
+ const protocol::ClipboardEvent& event) {
+ NOTIMPLEMENTED();
+}
+
+// HOST delivering a Cursor (mouse) update
+void ClientInstance::SetCursorShape(const protocol::CursorShapeInfo& shape) {
+ if (!bridge_->ui_task_runner()->BelongsToCurrentThread()) {
+ bridge_->ui_task_runner()->PostTask(
+ FROM_HERE, base::Bind(&ClientInstance::SetCursorShape, this, shape));
+ return;
+ }
+
+ bridge_->UpdateCursorShape(shape);
+}
+
+// Create a thread to receive and package Canvas (desktop) updates
+void ClientInstance::ConnectToHostOnNetworkThread() {
+ DCHECK(bridge_->network_task_runner()->BelongsToCurrentThread());
+
+ view_.reset(
+ 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.
+ view_weak_factory_.reset(
dcaiafa 2014/03/19 01:14:15 Move the WeakPtrFactory into FrameConsumerBridge,
aboone 2014/03/21 16:42:07 Done.
+ new base::WeakPtrFactory<FrameConsumer>(view_.get()));
+
+ client_context_.Start();
+
+ scoped_refptr<FrameConsumerProxy> consumer_proxy = new FrameConsumerProxy(
+ bridge_->network_task_runner(), view_weak_factory_->GetWeakPtr());
+
+ SoftwareVideoRenderer* renderer =
+ new SoftwareVideoRenderer(client_context_.main_task_runner(),
+ client_context_.decode_task_runner(),
+ consumer_proxy);
+
+ view_->Initialize(renderer);
+ video_renderer_.reset(renderer);
+
+ connection_.reset(new protocol::ConnectionToHost(true));
+
+ client_.reset(new ChromotingClient(client_config_,
+ &client_context_,
+ connection_.get(),
+ this,
+ video_renderer_.get(),
+ scoped_ptr<AudioPlayer>()));
+
+ signaling_.reset(
+ new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(),
+ bridge_->url_requester(),
+ xmpp_config_));
+
+ NetworkSettings network_settings(NetworkSettings::NAT_TRAVERSAL_ENABLED);
+
+ scoped_ptr<ChromiumPortAllocator> port_allocator(
+ ChromiumPortAllocator::Create(bridge_->url_requester(),
+ network_settings));
+
+ scoped_ptr<protocol::TransportFactory> transport_factory(
+ new protocol::LibjingleTransportFactory(
+ signaling_.get(),
+ port_allocator.PassAs<cricket::HttpPortAllocatorBase>(),
+ network_settings));
+
+ client_->Start(signaling_.get(), transport_factory.Pass());
+}
+
+void ClientInstance::DisconnectFromHostOnNetworkThread() {
+ DCHECK(bridge_->network_task_runner()->BelongsToCurrentThread());
+
+ // This must be destroyed on the network thread before the producer is gone.
+ view_.reset();
+
+ // The weak pointers must be invalidated on the same thread they were used.
+ view_weak_factory_->InvalidateWeakPtrs();
+
+ host_id_.clear();
+
+ // |client_| must be torn down before |signaling_|.
+ connection_.reset();
+ client_.reset();
+ client_context_.Stop();
+}
+
+// HOST attempts to continue automatically with previously supplied credentials,
+// if it can't it requests the user's PIN.
+void ClientInstance::FetchSecret(
+ bool pairable,
+ const protocol::SecretFetchedCallback& callback) {
+ if (!bridge_->ui_task_runner()->BelongsToCurrentThread()) {
+ bridge_->ui_task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ClientInstance::FetchSecret, this, pairable, callback));
+ return;
+ }
+
+ if (!client_config_.client_pairing_id.empty()) {
+ // We attempted to connect using an existing pairing that was rejected.
+ // Unless we forget about the stale credentials, we'll continue trying them.
+ VLOG(1) << "Deleting rejected pairing credentials";
+ bridge_->CommitPairingCredentials(host_id_, "", "");
+ }
+
+ pin_callback_ = callback;
+ bridge_->DisplayAuthenticationPrompt(pairable);
+}
+
+} // namespace remoting

Powered by Google App Engine
This is Rietveld 408576698