diff options
author | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-29 01:11:24 +0000 |
---|---|---|
committer | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-29 01:11:24 +0000 |
commit | 77b10182480270e2737c58c5b3d6a73e901b3f6b (patch) | |
tree | 07e9ef5ba2b2f98b9bc42ab7c305759c589c2be8 /remoting | |
parent | 17e92030ad8eef809db6563d91a1328f96fbd24d (diff) | |
download | chromium_src-77b10182480270e2737c58c5b3d6a73e901b3f6b.zip chromium_src-77b10182480270e2737c58c5b3d6a73e901b3f6b.tar.gz chromium_src-77b10182480270e2737c58c5b3d6a73e901b3f6b.tar.bz2 |
Add methods needed for host registration in chromoting host plugin.
- Parsing config parameter for the SetConfigAndStart().
- Added getConfig().
- Added generateHostKeyPair().
Review URL: http://codereview.chromium.org/9874007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@129546 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r-- | remoting/host/host_key_pair.cc | 12 | ||||
-rw-r--r-- | remoting/host/host_key_pair.h | 3 | ||||
-rw-r--r-- | remoting/host/plugin/host_script_object.cc | 204 | ||||
-rw-r--r-- | remoting/host/plugin/host_script_object.h | 102 | ||||
-rw-r--r-- | remoting/webapp/host_plugin_proto.js | 14 |
5 files changed, 266 insertions, 69 deletions
diff --git a/remoting/host/host_key_pair.cc b/remoting/host/host_key_pair.cc index 7427471..7bf1e84 100644 --- a/remoting/host/host_key_pair.cc +++ b/remoting/host/host_key_pair.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -54,6 +54,10 @@ bool HostKeyPair::Load(HostConfig* host_config) { } void HostKeyPair::Save(MutableHostConfig* host_config) { + host_config->SetString(kPrivateKeyConfigPath, GetAsString()); +} + +std::string HostKeyPair::GetAsString() const { // Check that the key initialized. DCHECK(key_.get() != NULL); @@ -61,8 +65,10 @@ void HostKeyPair::Save(MutableHostConfig* host_config) { key_->ExportPrivateKey(&key_buf); std::string key_str(key_buf.begin(), key_buf.end()); std::string key_base64; - base::Base64Encode(key_str, &key_base64); - host_config->SetString(kPrivateKeyConfigPath, key_base64); + if (!base::Base64Encode(key_str, &key_base64)) { + LOG(FATAL) << "Base64Encode failed"; + } + return key_base64; } std::string HostKeyPair::GetPublicKey() const { diff --git a/remoting/host/host_key_pair.h b/remoting/host/host_key_pair.h index 6fd74f3..a2b9d5d 100644 --- a/remoting/host/host_key_pair.h +++ b/remoting/host/host_key_pair.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -31,6 +31,7 @@ class HostKeyPair { crypto::RSAPrivateKey* private_key() { return key_.get(); } + std::string GetAsString() const; std::string GetPublicKey() const; std::string GetSignature(const std::string& message) const; diff --git a/remoting/host/plugin/host_script_object.cc b/remoting/host/plugin/host_script_object.cc index 6c94143..fea43ea 100644 --- a/remoting/host/plugin/host_script_object.cc +++ b/remoting/host/plugin/host_script_object.cc @@ -6,10 +6,13 @@ #include "remoting/host/plugin/daemon_controller.h" #include "base/bind.h" +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" #include "base/message_loop.h" #include "base/message_loop_proxy.h" #include "base/sys_string_conversions.h" #include "base/threading/platform_thread.h" +#include "base/threading/sequenced_worker_pool.h" #include "base/utf_string_conversions.h" #include "remoting/jingle_glue/xmpp_signal_strategy.h" #include "remoting/base/auth_token_util.h" @@ -40,7 +43,9 @@ const char* kAttrNameOnStateChanged = "onStateChanged"; const char* kFuncNameConnect = "connect"; const char* kFuncNameDisconnect = "disconnect"; const char* kFuncNameLocalize = "localize"; +const char* kFuncNameGenerateKeyPair = "generateKeyPair"; const char* kFuncNameSetDaemonPin = "setDaemonPin"; +const char* kFuncNameGetDaemonConfig = "getDaemonConfig"; const char* kFuncNameStartDaemon = "startDaemon"; const char* kFuncNameStopDaemon = "stopDaemon"; @@ -55,6 +60,11 @@ const char* kAttrNameError = "ERROR"; const int kMaxLoginAttempts = 5; +// We may need to have more than one task running at the same time +// (e.g. key generation and status update), yet unlikely to ever need +// more than 2 threads. +const int kMaxWorkerPoolThreads = 2; + } // namespace HostNPScriptObject::HostNPScriptObject( @@ -63,16 +73,18 @@ HostNPScriptObject::HostNPScriptObject( PluginMessageLoopProxy::Delegate* plugin_thread_delegate) : plugin_(plugin), parent_(parent), + am_currently_logging_(false), state_(kDisconnected), np_thread_id_(base::PlatformThread::CurrentId()), plugin_message_loop_proxy_( new PluginMessageLoopProxy(plugin_thread_delegate)), failed_login_attempts_(0), - daemon_controller_(DaemonController::Create()), disconnected_event_(true, false), - am_currently_logging_(false), nat_traversal_enabled_(false), - policy_received_(false) { + policy_received_(false), + daemon_controller_(DaemonController::Create()), + worker_pool_(new base::SequencedWorkerPool(kMaxWorkerPoolThreads, + "RemotingHostPlugin")) { } HostNPScriptObject::~HostNPScriptObject() { @@ -108,6 +120,10 @@ HostNPScriptObject::~HostNPScriptObject() { // Stops all threads. host_context_.reset(); } + + // Must shutdown worker pool threads so that they don't try to + // access the host object. + worker_pool_->Shutdown(); } bool HostNPScriptObject::Init() { @@ -135,13 +151,15 @@ bool HostNPScriptObject::HasMethod(const std::string& method_name) { return (method_name == kFuncNameConnect || method_name == kFuncNameDisconnect || method_name == kFuncNameLocalize || + method_name == kFuncNameGenerateKeyPair || method_name == kFuncNameSetDaemonPin || + method_name == kFuncNameGetDaemonConfig || method_name == kFuncNameStartDaemon || method_name == kFuncNameStopDaemon); } bool HostNPScriptObject::InvokeDefault(const NPVariant* args, - uint32_t argCount, + uint32_t arg_count, NPVariant* result) { VLOG(2) << "InvokeDefault"; CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); @@ -151,22 +169,26 @@ bool HostNPScriptObject::InvokeDefault(const NPVariant* args, bool HostNPScriptObject::Invoke(const std::string& method_name, const NPVariant* args, - uint32_t argCount, + uint32_t arg_count, NPVariant* result) { VLOG(2) << "Invoke " << method_name; CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); if (method_name == kFuncNameConnect) { - return Connect(args, argCount, result); + return Connect(args, arg_count, result); } else if (method_name == kFuncNameDisconnect) { - return Disconnect(args, argCount, result); + return Disconnect(args, arg_count, result); } else if (method_name == kFuncNameLocalize) { - return Localize(args, argCount, result); + return Localize(args, arg_count, result); + } else if (method_name == kFuncNameGenerateKeyPair) { + return GenerateKeyPair(args, arg_count, result); } else if (method_name == kFuncNameSetDaemonPin) { - return SetDaemonPin(args, argCount, result); + return SetDaemonPin(args, arg_count, result); + } else if (method_name == kFuncNameGetDaemonConfig) { + return GetDaemonConfig(args, arg_count, result); } else if (method_name == kFuncNameStartDaemon) { - return StartDaemon(args, argCount, result); + return StartDaemon(args, arg_count, result); } else if (method_name == kFuncNameStopDaemon) { - return StopDaemon(args, argCount, result); + return StopDaemon(args, arg_count, result); } else { SetException("Invoke: unknown method " + method_name); return false; @@ -330,7 +352,9 @@ bool HostNPScriptObject::Enumerate(std::vector<std::string>* values) { kFuncNameConnect, kFuncNameDisconnect, kFuncNameLocalize, + kFuncNameGenerateKeyPair, kFuncNameSetDaemonPin, + kFuncNameGetDaemonConfig, kFuncNameStartDaemon, kFuncNameStopDaemon }; @@ -569,6 +593,28 @@ bool HostNPScriptObject::Localize(const NPVariant* args, } } +bool HostNPScriptObject::GenerateKeyPair(const NPVariant* args, + uint32_t arg_count, + NPVariant* result) { + if (arg_count != 1) { + SetException("generateKeyPair: bad number of arguments"); + return false; + } + + NPObject* callback_obj = ObjectFromNPVariant(args[0]); + if (!callback_obj) { + SetException("generateKeyPair: invalid callback parameter"); + return false; + } + + callback_obj = g_npnetscape_funcs->retainobject(callback_obj); + + worker_pool_->PostTask(FROM_HERE, + base::Bind(&HostNPScriptObject::DoGenerateKeyPair, + base::Unretained(this), callback_obj)); + return true; +} + bool HostNPScriptObject::SetDaemonPin(const NPVariant* args, uint32_t arg_count, NPVariant* result) { @@ -585,16 +631,51 @@ bool HostNPScriptObject::SetDaemonPin(const NPVariant* args, } } +bool HostNPScriptObject::GetDaemonConfig(const NPVariant* args, + uint32_t arg_count, + NPVariant* result) { + if (arg_count != 1) { + SetException("getDaemonConfig: bad number of arguments"); + return false; + } + + NPObject* callback_obj = ObjectFromNPVariant(args[0]); + if (!callback_obj) { + SetException("getDaemonConfig: invalid callback parameter"); + return false; + } + + callback_obj = g_npnetscape_funcs->retainobject(callback_obj); + + // We control lifetime of the |daemon_controller_| so it's safe to + // use base::Unretained() here. + daemon_controller_->GetConfig( + base::Bind(&HostNPScriptObject::InvokeGetDaemonConfigCallback, + base::Unretained(this), callback_obj)); + + return true; +} + bool HostNPScriptObject::StartDaemon(const NPVariant* args, uint32_t arg_count, NPVariant* result) { - if (arg_count != 0) { + if (arg_count != 1) { SetException("startDaemon: bad number of arguments"); return false; } - // TODO(sergeyu): Receive |config| parameters. - scoped_ptr<base::DictionaryValue> config(new base::DictionaryValue()); - daemon_controller_->SetConfigAndStart(config.Pass()); + + std::string config_str = StringFromNPVariant(args[0]); + base::Value* config = base::JSONReader::Read(config_str, true); + base::DictionaryValue* config_dict; + + if (config_str.empty() || !config || !config->GetAsDictionary(&config_dict)) { + delete config; + SetException("startDaemon: bad config parameter"); + return false; + } + + daemon_controller_->SetConfigAndStart( + scoped_ptr<base::DictionaryValue>(config_dict)); return true; } @@ -767,7 +848,6 @@ void HostNPScriptObject::NotifyStateChanged(State state) { LOG_IF(ERROR, !is_good) << "OnStateChanged failed"; } } - void HostNPScriptObject::PostLogDebugInfo(const std::string& message) { if (plugin_message_loop_proxy_->BelongsToCurrentThread()) { // Make sure we're not currently processing a log message. @@ -783,27 +863,6 @@ void HostNPScriptObject::PostLogDebugInfo(const std::string& message) { base::Unretained(this), message)); } -void HostNPScriptObject::LogDebugInfo(const std::string& message) { - DCHECK(plugin_message_loop_proxy_->BelongsToCurrentThread()); - if (log_debug_info_func_.get()) { - am_currently_logging_ = true; - NPVariant log_message; - STRINGZ_TO_NPVARIANT(message.c_str(), log_message); - bool is_good = InvokeAndIgnoreResult(log_debug_info_func_.get(), - &log_message, 1); - if (!is_good) { - LOG(ERROR) << "ERROR - LogDebugInfo failed\n"; - } - am_currently_logging_ = false; - } -} - -void HostNPScriptObject::SetException(const std::string& exception_string) { - DCHECK(plugin_message_loop_proxy_->BelongsToCurrentThread()); - g_npnetscape_funcs->setexception(parent_, exception_string.c_str()); - LOG(INFO) << exception_string; -} - void HostNPScriptObject::LocalizeStrings(NPObject* localize_func) { DCHECK(plugin_message_loop_proxy_->BelongsToCurrentThread()); @@ -874,15 +933,82 @@ void HostNPScriptObject::UpdateWebappNatPolicy(bool nat_traversal_enabled) { } } +void HostNPScriptObject::DoGenerateKeyPair(NPObject* callback) { + HostKeyPair key_pair; + key_pair.Generate(); + InvokeGenerateKeyPairCallback(callback, key_pair.GetAsString()); +} + +void HostNPScriptObject::InvokeGenerateKeyPairCallback( + NPObject* callback, + const std::string& result) { + if (!plugin_message_loop_proxy_->BelongsToCurrentThread()) { + plugin_message_loop_proxy_->PostTask( + FROM_HERE, base::Bind( + &HostNPScriptObject::InvokeGenerateKeyPairCallback, + base::Unretained(this), callback, result)); + return; + } + + NPVariant result_val = NPVariantFromString(result); + InvokeAndIgnoreResult(callback, &result_val, 1); + g_npnetscape_funcs->releasevariantvalue(&result_val); + g_npnetscape_funcs->releaseobject(callback); +} + +void HostNPScriptObject::InvokeGetDaemonConfigCallback( + NPObject* callback, + scoped_ptr<base::DictionaryValue> config) { + if (!plugin_message_loop_proxy_->BelongsToCurrentThread()) { + plugin_message_loop_proxy_->PostTask( + FROM_HERE, base::Bind( + &HostNPScriptObject::InvokeGetDaemonConfigCallback, + base::Unretained(this), callback, base::Passed(&config))); + return; + } + + // There is no easy way to create a dictionary from an NPAPI plugin + // so we have to serialize the dictionary to pass it to JavaScript. + std::string config_str; + base::JSONWriter::Write(config.get(), &config_str); + + NPVariant config_val = NPVariantFromString(config_str); + InvokeAndIgnoreResult(callback, &config_val, 1); + g_npnetscape_funcs->releasevariantvalue(&config_val); + g_npnetscape_funcs->releaseobject(callback); +} + +void HostNPScriptObject::LogDebugInfo(const std::string& message) { + DCHECK(plugin_message_loop_proxy_->BelongsToCurrentThread()); + if (log_debug_info_func_.get()) { + am_currently_logging_ = true; + NPVariant log_message; + STRINGZ_TO_NPVARIANT(message.c_str(), log_message); + bool is_good = InvokeAndIgnoreResult(log_debug_info_func_.get(), + &log_message, 1); + if (!is_good) { + LOG(ERROR) << "ERROR - LogDebugInfo failed\n"; + } + am_currently_logging_ = false; + } +} + bool HostNPScriptObject::InvokeAndIgnoreResult(NPObject* func, const NPVariant* args, - uint32_t argCount) { + uint32_t arg_count) { + DCHECK(plugin_message_loop_proxy_->BelongsToCurrentThread()); NPVariant np_result; bool is_good = g_npnetscape_funcs->invokeDefault(plugin_, func, args, - argCount, &np_result); + arg_count, &np_result); if (is_good) g_npnetscape_funcs->releasevariantvalue(&np_result); return is_good; } +void HostNPScriptObject::SetException(const std::string& exception_string) { + DCHECK(plugin_message_loop_proxy_->BelongsToCurrentThread()); + g_npnetscape_funcs->setexception(parent_, exception_string.c_str()); + LOG(INFO) << exception_string; +} + } // namespace remoting diff --git a/remoting/host/plugin/host_script_object.h b/remoting/host/plugin/host_script_object.h index e410292..f9d543f 100644 --- a/remoting/host/plugin/host_script_object.h +++ b/remoting/host/plugin/host_script_object.h @@ -28,6 +28,10 @@ #include "third_party/npapi/bindings/npfunctions.h" #include "third_party/npapi/bindings/npruntime.h" +namespace base { +class SequencedWorkerPool; +} // namespace base + namespace remoting { class ChromotingHost; @@ -57,11 +61,11 @@ class HostNPScriptObject : public HostStatusObserver { bool HasMethod(const std::string& method_name); bool InvokeDefault(const NPVariant* args, - uint32_t argCount, + uint32_t arg_count, NPVariant* result); bool Invoke(const std::string& method_name, const NPVariant* args, - uint32_t argCount, + uint32_t arg_count, NPVariant* result); bool HasProperty(const std::string& property_name); bool GetProperty(const std::string& property_name, NPVariant* result); @@ -93,34 +97,60 @@ class HostNPScriptObject : public HostStatusObserver { kError }; + ////////////////////////////////////////////////////////// + // Plugin methods for It2Me host. + // Start connection. args are: // string uid, string auth_token // No result. - bool Connect(const NPVariant* args, uint32_t argCount, NPVariant* result); + bool Connect(const NPVariant* args, uint32_t arg_count, NPVariant* result); // Disconnect. No arguments or result. - bool Disconnect(const NPVariant* args, uint32_t argCount, NPVariant* result); + bool Disconnect(const NPVariant* args, uint32_t arg_count, NPVariant* result); // Localize strings. args are: // localize_func - a callback function which returns a localized string for // a given tag name. // No result. - bool Localize(const NPVariant* args, uint32_t argCount, NPVariant* result); + bool Localize(const NPVariant* args, uint32_t arg_count, NPVariant* result); + + ////////////////////////////////////////////////////////// + // Plugin methods for Me2Me host. + + // Generates new key pair to use for the host. The specified + // callback is called when when the key is generated. The key is + // returned in format understood by the host (PublicKeyInfo + // structure encoded with ASN.1 DER, and then BASE64). Args are: + // function(string) callback The callback to be called when done. + bool GenerateKeyPair(const NPVariant* args, + uint32_t arg_count, + NPVariant* result); // Set the PIN for Me2Me. Args are: // string pin - // Returns true if the PIN was updated successfully. - bool SetDaemonPin(const NPVariant* args, uint32_t argCount, + bool SetDaemonPin(const NPVariant* args, + uint32_t arg_count, NPVariant* result); - // Start the daemon process or change the PIN if it is running. No args. - // Returns true if the download/start mechanism was initiated successfully - // (poll daemonState to wait for completion) or false if an error occurred. - bool StartDaemon(const NPVariant* args, uint32_t argCount, NPVariant* result); + // Loads daemon config config. The first argument specifies the + // callback to be called with the config is loaded. The config is + // returned as a JSON formatted string. Args are: + // function(string) callback + bool GetDaemonConfig(const NPVariant* args, + uint32_t arg_count, + NPVariant* result); - // Start the daemon process or change the PIN if it is running. No arguments. - // Returns true if the daemon was stopped successfully or false on error. - bool StopDaemon(const NPVariant* args, uint32_t argCount, NPVariant* result); + // Start the daemon process with the specified config. Args are: + // string config + bool StartDaemon(const NPVariant* args, + uint32_t arg_count, + NPVariant* result); + + // Stop the daemon process. No arguments. + bool StopDaemon(const NPVariant* args, uint32_t arg_count, NPVariant* result); + + ////////////////////////////////////////////////////////// + // Helper methods for It2Me host. // Updates state of the host. Can be called only on the main thread. void SetState(State state); @@ -128,10 +158,6 @@ class HostNPScriptObject : public HostStatusObserver { // Notifies OnStateChanged handler of a state change. void NotifyStateChanged(State state); - // Call LogDebugInfo handler if there is one. - // This must be called on the correct thread. - void LogDebugInfo(const std::string& message); - // Callbacks invoked during session setup. void OnReceivedSupportID(bool success, const std::string& support_id, @@ -169,18 +195,44 @@ class HostNPScriptObject : public HostStatusObserver { // NAT traversal policy, notify it. void UpdateWebappNatPolicy(bool nat_traversal_enabled); + ////////////////////////////////////////////////////////// + // Helper methods for Me2Me host. + + // Helpers for GenerateKeyPair(). + void DoGenerateKeyPair(NPObject* callback); + void InvokeGenerateKeyPairCallback(NPObject* callback, + const std::string& result); + + // Callback handler for DaemonController::GetConfig(). + void InvokeGetDaemonConfigCallback(NPObject* callback, + scoped_ptr<base::DictionaryValue> config); + + ////////////////////////////////////////////////////////// + // Basic helper methods used for both It2Me and Me2me. + + // Call LogDebugInfo handler if there is one. + // This must be called on the correct thread. + void LogDebugInfo(const std::string& message); + // Helper function for executing InvokeDefault on an NPObject, and ignoring // the return value. bool InvokeAndIgnoreResult(NPObject* func, const NPVariant* args, - uint32_t argCount); + uint32_t arg_count); // Set an exception for the current call. void SetException(const std::string& exception_string); + ////////////////////////////////////////////////////////// + // Plugin state variables shared between It2Me and Me2Me. + + // True if we're in the middle of handling a log message. NPP plugin_; NPObject* parent_; + bool am_currently_logging_; + ////////////////////////////////////////////////////////// + // It2Me host state. State state_; base::Lock access_code_lock_; @@ -208,13 +260,8 @@ class HostNPScriptObject : public HostStatusObserver { UiStrings ui_strings_; base::Lock ui_strings_lock_; - scoped_ptr<DaemonController> daemon_controller_; - base::WaitableEvent disconnected_event_; - // True if we're in the middle of handling a log message. - bool am_currently_logging_; - base::Lock nat_policy_lock_; scoped_ptr<policy_hack::NatPolicy> nat_policy_; @@ -232,6 +279,13 @@ class HostNPScriptObject : public HostStatusObserver { // it can be executed after at least one successful policy read. This // variable contains the thunk if it is necessary. base::Closure pending_connect_; + + ////////////////////////////////////////////////////////// + // Me2Me host state. + scoped_ptr<DaemonController> daemon_controller_; + scoped_refptr<base::SequencedWorkerPool> worker_pool_; + + DISALLOW_COPY_AND_ASSIGN(HostNPScriptObject); }; } // namespace remoting diff --git a/remoting/webapp/host_plugin_proto.js b/remoting/webapp/host_plugin_proto.js index 8adf49d..f555d10 100644 --- a/remoting/webapp/host_plugin_proto.js +++ b/remoting/webapp/host_plugin_proto.js @@ -29,12 +29,22 @@ remoting.HostPlugin.prototype.localize = function(callback) {}; * @return {void} Nothing. */ remoting.HostPlugin.prototype.setDaemonPin = function(pin) {}; -/** @return {void} Nothing. */ -remoting.HostPlugin.prototype.startDaemon = function() {}; +/** @param {string} callback Callback to be called for the config. + * @return {void} Nothing. */ +remoting.HostPlugin.prototype.getDaemonConfig = function(callback) {}; + +/** @param {string} config Host configuration. + * @return {void} Nothing. */ +remoting.HostPlugin.prototype.startDaemon = function(config) {}; /** @return {void} Nothing. */ remoting.HostPlugin.prototype.stopDaemon = function() {}; +/** @param {function(string):void} callback Callback to be called + * after new key is generated. + * @return {void} Nothing. */ +remoting.HostPlugin.prototype.generateKeyPair = function(callback) {}; + /** @type {number} */ remoting.HostPlugin.prototype.state; /** @type {number} */ remoting.HostPlugin.prototype.STARTING; |