Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / remoting / client / jni / chromoting_jni_instance.cc
index 96f0d35..1a69115 100644 (file)
@@ -8,16 +8,22 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
+#include "jingle/glue/thread_wrapper.h"
 #include "net/socket/client_socket_factory.h"
+#include "remoting/base/service_urls.h"
 #include "remoting/client/audio_player.h"
+#include "remoting/client/client_status_logger.h"
 #include "remoting/client/jni/android_keymap.h"
 #include "remoting/client/jni/chromoting_jni_runtime.h"
 #include "remoting/client/software_video_renderer.h"
-#include "remoting/jingle_glue/chromium_port_allocator.h"
-#include "remoting/jingle_glue/chromium_socket_factory.h"
-#include "remoting/jingle_glue/network_settings.h"
+#include "remoting/client/token_fetcher_proxy.h"
+#include "remoting/protocol/chromium_port_allocator.h"
+#include "remoting/protocol/chromium_socket_factory.h"
 #include "remoting/protocol/host_stub.h"
 #include "remoting/protocol/libjingle_transport_factory.h"
+#include "remoting/protocol/negotiating_client_authenticator.h"
+#include "remoting/protocol/network_settings.h"
+#include "remoting/signaling/server_log_entry.h"
 
 namespace remoting {
 
@@ -29,7 +35,7 @@ const int kXmppPort = 5222;
 const bool kXmppUseTls = true;
 
 // Interval at which to log performance statistics, if enabled.
-const int kPerfStatsIntervalMs = 10000;
+const int kPerfStatsIntervalMs = 60000;
 
 }
 
@@ -40,11 +46,15 @@ ChromotingJniInstance::ChromotingJniInstance(ChromotingJniRuntime* jni_runtime,
                                              const char* host_id,
                                              const char* host_pubkey,
                                              const char* pairing_id,
-                                             const char* pairing_secret)
+                                             const char* pairing_secret,
+                                             const char* capabilities)
     : jni_runtime_(jni_runtime),
       host_id_(host_id),
+      host_jid_(host_jid),
       create_pairing_(false),
-      stats_logging_enabled_(false) {
+      stats_logging_enabled_(false),
+      capabilities_(capabilities),
+      weak_factory_(this) {
   DCHECK(jni_runtime_->ui_task_runner()->BelongsToCurrentThread());
 
   // Intialize XMPP config.
@@ -55,23 +65,25 @@ ChromotingJniInstance::ChromotingJniInstance(ChromotingJniRuntime* jni_runtime,
   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(&ChromotingJniInstance::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"));
+  // Initialize |authenticator_|.
+  scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>
+      token_fetcher(new TokenFetcherProxy(
+          base::Bind(&ChromotingJniInstance::FetchThirdPartyToken,
+                     weak_factory_.GetWeakPtr()),
+          host_pubkey));
+
+  std::vector<protocol::AuthenticationMethod> auth_methods;
+  auth_methods.push_back(protocol::AuthenticationMethod::Spake2Pair());
+  auth_methods.push_back(protocol::AuthenticationMethod::Spake2(
+      protocol::AuthenticationMethod::HMAC_SHA256));
+  auth_methods.push_back(protocol::AuthenticationMethod::Spake2(
+      protocol::AuthenticationMethod::NONE));
+  auth_methods.push_back(protocol::AuthenticationMethod::ThirdParty());
+
+  authenticator_.reset(new protocol::NegotiatingClientAuthenticator(
+      pairing_id, pairing_secret, host_id_,
+      base::Bind(&ChromotingJniInstance::FetchSecret, this),
+      token_fetcher.Pass(), auth_methods));
 
   // Post a task to start connection
   jni_runtime_->display_task_runner()->PostTask(
@@ -80,13 +92,24 @@ ChromotingJniInstance::ChromotingJniInstance(ChromotingJniRuntime* jni_runtime,
                  this));
 }
 
-ChromotingJniInstance::~ChromotingJniInstance() {}
+ChromotingJniInstance::~ChromotingJniInstance() {
+  // This object is ref-counted, so this dtor can execute on any thread.
+  // Ensure that all these objects have been freed already, so they are not
+  // destroyed on some random thread.
+  DCHECK(!view_);
+  DCHECK(!client_context_);
+  DCHECK(!video_renderer_);
+  DCHECK(!authenticator_);
+  DCHECK(!client_);
+  DCHECK(!signaling_);
+  DCHECK(!client_status_logger_);
+}
 
-void ChromotingJniInstance::Cleanup() {
+void ChromotingJniInstance::Disconnect() {
   if (!jni_runtime_->display_task_runner()->BelongsToCurrentThread()) {
     jni_runtime_->display_task_runner()->PostTask(
         FROM_HERE,
-        base::Bind(&ChromotingJniInstance::Cleanup, this));
+        base::Bind(&ChromotingJniInstance::Disconnect, this));
     return;
   }
 
@@ -102,13 +125,58 @@ void ChromotingJniInstance::Cleanup() {
                  this));
 }
 
+void ChromotingJniInstance::FetchThirdPartyToken(
+    const GURL& token_url,
+    const std::string& client_id,
+    const std::string& scope,
+    base::WeakPtr<TokenFetcherProxy> token_fetcher_proxy) {
+  DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
+  DCHECK(!token_fetcher_proxy_.get());
+
+  __android_log_print(ANDROID_LOG_INFO,
+                      "ThirdPartyAuth",
+                      "Fetching Third Party Token from user.");
+
+  token_fetcher_proxy_ = token_fetcher_proxy;
+  jni_runtime_->ui_task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(&ChromotingJniRuntime::FetchThirdPartyToken,
+                 base::Unretained(jni_runtime_),
+                 token_url,
+                 client_id,
+                 scope));
+}
+
+void ChromotingJniInstance::HandleOnThirdPartyTokenFetched(
+    const std::string& token,
+    const std::string& shared_secret) {
+  DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
+
+  __android_log_print(
+      ANDROID_LOG_INFO, "ThirdPartyAuth", "Third Party Token Fetched.");
+
+  if (token_fetcher_proxy_.get()) {
+    token_fetcher_proxy_->OnTokenFetched(token, shared_secret);
+    token_fetcher_proxy_.reset();
+  } else {
+    __android_log_print(
+        ANDROID_LOG_WARN,
+        "ThirdPartyAuth",
+        "Ignored OnThirdPartyTokenFetched() without a pending fetch.");
+  }
+}
+
 void ChromotingJniInstance::ProvideSecret(const std::string& pin,
-                                          bool create_pairing) {
+                                          bool create_pairing,
+                                          const std::string& device_name) {
   DCHECK(jni_runtime_->ui_task_runner()->BelongsToCurrentThread());
   DCHECK(!pin_callback_.is_null());
 
   create_pairing_ = create_pairing;
 
+  if (create_pairing)
+    SetDeviceName(device_name);
+
   jni_runtime_->network_task_runner()->PostTask(FROM_HERE,
                                                 base::Bind(pin_callback_, pin));
 }
@@ -124,60 +192,80 @@ void ChromotingJniInstance::RedrawDesktop() {
   jni_runtime_->RedrawCanvas();
 }
 
-void ChromotingJniInstance::PerformMouseAction(
+void ChromotingJniInstance::SendMouseEvent(
     int x, int y,
     protocol::MouseEvent_MouseButton button,
     bool button_down) {
   if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
     jni_runtime_->network_task_runner()->PostTask(
-        FROM_HERE, base::Bind(&ChromotingJniInstance::PerformMouseAction,
+        FROM_HERE, base::Bind(&ChromotingJniInstance::SendMouseEvent,
                               this, x, y, button, button_down));
     return;
   }
 
-  protocol::MouseEvent action;
-  action.set_x(x);
-  action.set_y(y);
-  action.set_button(button);
+  protocol::MouseEvent event;
+  event.set_x(x);
+  event.set_y(y);
+  event.set_button(button);
   if (button != protocol::MouseEvent::BUTTON_UNDEFINED)
-    action.set_button_down(button_down);
+    event.set_button_down(button_down);
 
-  connection_->input_stub()->InjectMouseEvent(action);
+  client_->input_stub()->InjectMouseEvent(event);
 }
 
-void ChromotingJniInstance::PerformMouseWheelDeltaAction(int delta_x,
-                                                         int delta_y) {
+void ChromotingJniInstance::SendMouseWheelEvent(int delta_x, int delta_y) {
   if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
     jni_runtime_->network_task_runner()->PostTask(
         FROM_HERE,
-        base::Bind(&ChromotingJniInstance::PerformMouseWheelDeltaAction, this,
+        base::Bind(&ChromotingJniInstance::SendMouseWheelEvent, this,
                    delta_x, delta_y));
     return;
   }
 
-  protocol::MouseEvent action;
-  action.set_wheel_delta_x(delta_x);
-  action.set_wheel_delta_y(delta_y);
-  connection_->input_stub()->InjectMouseEvent(action);
+  protocol::MouseEvent event;
+  event.set_wheel_delta_x(delta_x);
+  event.set_wheel_delta_y(delta_y);
+  client_->input_stub()->InjectMouseEvent(event);
 }
 
-void ChromotingJniInstance::PerformKeyboardAction(int key_code, bool key_down) {
+bool ChromotingJniInstance::SendKeyEvent(int key_code, bool key_down) {
+  uint32 usb_key_code = AndroidKeycodeToUsbKeycode(key_code);
+  if (!usb_key_code) {
+    LOG(WARNING) << "Ignoring unknown keycode: " << key_code;
+    return false;
+  }
+
+  SendKeyEventInternal(usb_key_code, key_down);
+  return true;
+}
+
+void ChromotingJniInstance::SendTextEvent(const std::string& text) {
   if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
     jni_runtime_->network_task_runner()->PostTask(
-        FROM_HERE, base::Bind(&ChromotingJniInstance::PerformKeyboardAction,
-                              this, key_code, key_down));
+        FROM_HERE,
+        base::Bind(&ChromotingJniInstance::SendTextEvent, this, text));
     return;
   }
 
-  uint32 usb_code = AndroidKeycodeToUsbKeycode(key_code);
-  if (usb_code) {
-    protocol::KeyEvent action;
-    action.set_usb_keycode(usb_code);
-    action.set_pressed(key_down);
-    connection_->input_stub()->InjectKeyEvent(action);
-  } else {
-    LOG(WARNING) << "Ignoring unknown keycode: " << key_code;
+  protocol::TextEvent event;
+  event.set_text(text);
+  client_->input_stub()->InjectTextEvent(event);
+}
+
+void ChromotingJniInstance::SendClientMessage(const std::string& type,
+                                              const std::string& data) {
+  if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
+    jni_runtime_->network_task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(
+            &ChromotingJniInstance::SendClientMessage, this, type, data));
+    return;
   }
+
+  protocol::ExtensionMessage extension_message;
+  extension_message.set_type(type);
+  extension_message.set_data(data);
+  client_->host_stub()->DeliverClientMessage(extension_message);
 }
 
 void ChromotingJniInstance::RecordPaintTime(int64 paint_time_ms) {
@@ -199,15 +287,18 @@ void ChromotingJniInstance::OnConnectionState(
 
   EnableStatsLogging(state == protocol::ConnectionToHost::CONNECTED);
 
+  client_status_logger_->LogSessionStateChange(state, error);
+
   if (create_pairing_ && state == protocol::ConnectionToHost::CONNECTED) {
     protocol::PairingRequest request;
-    request.set_client_name("Android");
-    connection_->host_stub()->RequestPairing(request);
+    DCHECK(!device_name_.empty());
+    request.set_client_name(device_name_);
+    client_->host_stub()->RequestPairing(request);
   }
 
   jni_runtime_->ui_task_runner()->PostTask(
       FROM_HERE,
-      base::Bind(&ChromotingJniRuntime::ReportConnectionStatus,
+      base::Bind(&ChromotingJniRuntime::OnConnectionState,
                  base::Unretained(jni_runtime_),
                  state,
                  error));
@@ -226,7 +317,11 @@ void ChromotingJniInstance::OnRouteChanged(
 }
 
 void ChromotingJniInstance::SetCapabilities(const std::string& capabilities) {
-  NOTIMPLEMENTED();
+  jni_runtime_->ui_task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(&ChromotingJniRuntime::SetCapabilities,
+                 base::Unretained(jni_runtime_),
+                 capabilities));
 }
 
 void ChromotingJniInstance::SetPairingResponse(
@@ -241,7 +336,12 @@ void ChromotingJniInstance::SetPairingResponse(
 
 void ChromotingJniInstance::DeliverHostMessage(
     const protocol::ExtensionMessage& message) {
-  NOTIMPLEMENTED();
+  jni_runtime_->ui_task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(&ChromotingJniRuntime::HandleExtensionMessage,
+                 base::Unretained(jni_runtime_),
+                 message.type(),
+                 message.data()));
 }
 
 protocol::ClipboardStub* ChromotingJniInstance::GetClipboardStub() {
@@ -252,12 +352,6 @@ protocol::CursorShapeStub* ChromotingJniInstance::GetCursorShapeStub() {
   return this;
 }
 
-scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>
-    ChromotingJniInstance::GetTokenFetcher(const std::string& host_public_key) {
-  // Return null to indicate that third-party authentication is unsupported.
-  return scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>();
-}
-
 void ChromotingJniInstance::InjectClipboardEvent(
     const protocol::ClipboardEvent& event) {
   NOTIMPLEMENTED();
@@ -293,12 +387,12 @@ void ChromotingJniInstance::ConnectToHostOnDisplayThread() {
 void ChromotingJniInstance::ConnectToHostOnNetworkThread() {
   DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
 
+  jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
+
   client_context_.reset(new ClientContext(
       jni_runtime_->network_task_runner().get()));
   client_context_->Start();
 
-  connection_.reset(new protocol::ConnectionToHost(true));
-
   SoftwareVideoRenderer* renderer =
       new SoftwareVideoRenderer(client_context_->main_task_runner(),
                                 client_context_->decode_task_runner(),
@@ -307,28 +401,31 @@ void ChromotingJniInstance::ConnectToHostOnNetworkThread() {
   video_renderer_.reset(renderer);
 
   client_.reset(new ChromotingClient(
-      client_config_, client_context_.get(), connection_.get(),
-      this, video_renderer_.get(), scoped_ptr<AudioPlayer>()));
-
+      client_context_.get(), this, video_renderer_.get(), nullptr));
 
   signaling_.reset(new XmppSignalStrategy(
       net::ClientSocketFactory::GetDefaultFactory(),
       jni_runtime_->url_requester(), xmpp_config_));
 
-  NetworkSettings network_settings(NetworkSettings::NAT_TRAVERSAL_ENABLED);
+  client_status_logger_.reset(
+      new ClientStatusLogger(ServerLogEntry::ME2ME,
+                             signaling_.get(),
+                             ServiceUrls::GetInstance()->directory_bot_jid()));
+
+  protocol::NetworkSettings network_settings(
+      protocol::NetworkSettings::NAT_TRAVERSAL_FULL);
 
   // Use Chrome's network stack to allocate ports for peer-to-peer channels.
-  scoped_ptr<ChromiumPortAllocator> port_allocator(
-      ChromiumPortAllocator::Create(jni_runtime_->url_requester(),
-                                    network_settings));
+  scoped_ptr<protocol::ChromiumPortAllocator> port_allocator(
+      protocol::ChromiumPortAllocator::Create(jni_runtime_->url_requester(),
+                                              network_settings));
 
   scoped_ptr<protocol::TransportFactory> transport_factory(
       new protocol::LibjingleTransportFactory(
-          signaling_.get(),
-          port_allocator.PassAs<cricket::HttpPortAllocatorBase>(),
-          network_settings));
+          signaling_.get(), port_allocator.Pass(), network_settings));
 
-  client_->Start(signaling_.get(), transport_factory.Pass());
+  client_->Start(signaling_.get(), authenticator_.Pass(),
+                 transport_factory.Pass(), host_jid_, capabilities_);
 }
 
 void ChromotingJniInstance::DisconnectFromHostOnNetworkThread() {
@@ -339,8 +436,12 @@ void ChromotingJniInstance::DisconnectFromHostOnNetworkThread() {
   stats_logging_enabled_ = false;
 
   // |client_| must be torn down before |signaling_|.
-  connection_.reset();
   client_.reset();
+  client_status_logger_.reset();
+  client_context_.reset();
+  video_renderer_.reset();
+  authenticator_.reset();
+  signaling_.reset();
 }
 
 void ChromotingJniInstance::FetchSecret(
@@ -353,16 +454,40 @@ void ChromotingJniInstance::FetchSecret(
     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.
-    jni_runtime_->CommitPairingCredentials(host_id_, "", "");
-  }
+  // Delete pairing credentials if they exist.
+  jni_runtime_->CommitPairingCredentials(host_id_, "", "");
 
   pin_callback_ = callback;
   jni_runtime_->DisplayAuthenticationPrompt(pairable);
 }
 
+void ChromotingJniInstance::SetDeviceName(const std::string& device_name) {
+  if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
+    jni_runtime_->network_task_runner()->PostTask(
+        FROM_HERE, base::Bind(&ChromotingJniInstance::SetDeviceName, this,
+                              device_name));
+    return;
+  }
+
+  device_name_ = device_name;
+}
+
+void ChromotingJniInstance::SendKeyEventInternal(int usb_key_code,
+                                                 bool key_down) {
+  if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
+    jni_runtime_->network_task_runner()->PostTask(
+        FROM_HERE, base::Bind(&ChromotingJniInstance::SendKeyEventInternal,
+                              this, usb_key_code, key_down));
+    return;
+  }
+
+
+  protocol::KeyEvent event;
+  event.set_usb_keycode(usb_key_code);
+  event.set_pressed(key_down);
+  client_->input_stub()->InjectKeyEvent(event);
+}
+
 void ChromotingJniInstance::EnableStatsLogging(bool enabled) {
   DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
 
@@ -392,6 +517,8 @@ void ChromotingJniInstance::LogPerfStats() {
                       stats->video_paint_ms()->Average(),
                       stats->round_trip_ms()->Average());
 
+  client_status_logger_->LogStatistics(stats);
+
   jni_runtime_->network_task_runner()->PostDelayedTask(
       FROM_HERE, base::Bind(&ChromotingJniInstance::LogPerfStats, this),
       base::TimeDelta::FromMilliseconds(kPerfStatsIntervalMs));