summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authorwez@chromium.org <wez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-18 20:33:12 +0000
committerwez@chromium.org <wez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-18 20:33:12 +0000
commiteadaca8e6f40e19cd9111adaecfbcfb1b8b3ec9e (patch)
treef934864c759bddd78d09eb9bfc60e29634a9959a /remoting
parent24950cb67304ad09ee05e32c3ffa5e07f52f0b8c (diff)
downloadchromium_src-eadaca8e6f40e19cd9111adaecfbcfb1b8b3ec9e.zip
chromium_src-eadaca8e6f40e19cd9111adaecfbcfb1b8b3ec9e.tar.gz
chromium_src-eadaca8e6f40e19cd9111adaecfbcfb1b8b3ec9e.tar.bz2
Move IT2Me functions into their own implementation object.
The script object itself is now used exclusively on the plugin/UI thread. When the IT2Me host function is used, an internal ref-counted implementation object is created which runs (mostly) on the network thread. The IT2Me implementation is passed a weak pointer to the script object through which to post tasks to it, allowing it to safely out-live the script object, for instance if there are still pending tasks for it at the moment it is stopped. BUG=156257 TEST=PyAuto & manual testing of IT2Me host functions. Review URL: https://chromiumcodereview.appspot.com/11195031 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@162777 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r--remoting/host/plugin/host_plugin.cc4
-rw-r--r--remoting/host/plugin/host_script_object.cc1166
-rw-r--r--remoting/host/plugin/host_script_object.h141
3 files changed, 714 insertions, 597 deletions
diff --git a/remoting/host/plugin/host_plugin.cc b/remoting/host/plugin/host_plugin.cc
index 2638e79..62af607 100644
--- a/remoting/host/plugin/host_plugin.cc
+++ b/remoting/host/plugin/host_plugin.cc
@@ -207,10 +207,6 @@ class HostNPPlugin : public remoting::PluginThreadTaskRunner::Delegate {
object->_class = aClass;
object->referenceCount = 1;
object->scriptable_object = new HostNPScriptObject(npp, object, plugin);
- if (!object->scriptable_object->Init()) {
- Deallocate(object);
- object = NULL;
- }
return object;
}
diff --git a/remoting/host/plugin/host_script_object.cc b/remoting/host/plugin/host_script_object.cc
index c0969d0..cc6a708 100644
--- a/remoting/host/plugin/host_script_object.cc
+++ b/remoting/host/plugin/host_script_object.cc
@@ -24,6 +24,7 @@
#include "remoting/host/host_event_logger.h"
#include "remoting/host/host_key_pair.h"
#include "remoting/host/host_secret.h"
+#include "remoting/host/host_status_observer.h"
#include "remoting/host/it2me_host_user_interface.h"
#include "remoting/host/network_settings.h"
#include "remoting/host/pin_hash.h"
@@ -82,85 +83,614 @@ const int kMaxWorkerPoolThreads = 2;
} // namespace
+// Internal implementation of the plugin's It2Me host function.
+class HostNPScriptObject::It2MeImpl
+ : public base::RefCountedThreadSafe<It2MeImpl>,
+ public HostStatusObserver {
+ public:
+ It2MeImpl(
+ scoped_ptr<ChromotingHostContext> context,
+ scoped_refptr<base::SingleThreadTaskRunner> plugin_task_runner,
+ base::WeakPtr<HostNPScriptObject> script_object,
+ const UiStrings& ui_strings);
+
+ // Methods called by the script object, from the plugin thread.
+
+ // Creates It2Me host structures and starts the host.
+ void Connect(const std::string& uid,
+ const std::string& auth_token,
+ const std::string& auth_service);
+
+ // Disconnects the host, ready for tear-down.
+ // Also called internally, from the network thread.
+ void Disconnect();
+
+ // Request a NAT policy notification.
+ void RequestNatPolicy();
+
+ // remoting::HostStatusObserver implementation.
+ virtual void OnAccessDenied(const std::string& jid) OVERRIDE;
+ virtual void OnClientAuthenticated(const std::string& jid) OVERRIDE;
+ virtual void OnClientDisconnected(const std::string& jid) OVERRIDE;
+ virtual void OnShutdown() OVERRIDE;
+
+ private:
+ friend class base::RefCountedThreadSafe<It2MeImpl>;
+
+ virtual ~It2MeImpl();
+
+ // Used to delete and join the ChromotingHostContext on the UI thread.
+ static void DeleteHostContext(scoped_ptr<ChromotingHostContext> context) {}
+
+ // Updates state of the host. Can be called only on the network thread.
+ void SetState(State state);
+
+ // Called by Connect() to check for policies and start connection process.
+ void ReadPolicyAndConnect(const std::string& uid,
+ const std::string& auth_token,
+ const std::string& auth_service);
+
+ // Called by ReadPolicyAndConnect once policies have been read.
+ void FinishConnect(const std::string& uid,
+ const std::string& auth_token,
+ const std::string& auth_service);
+
+ // Called when the support host registration completes.
+ void OnReceivedSupportID(bool success,
+ const std::string& support_id,
+ const base::TimeDelta& lifetime);
+
+ // Called when ChromotingHost::Shutdown() has completed.
+ void OnShutdownFinished();
+
+ // Called when initial policies are read, and when they change.
+ void OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies);
+
+ // Handlers for NAT traversal and host domain policies.
+ void UpdateNatPolicy(bool nat_traversal_enabled);
+ void UpdateHostDomainPolicy(const std::string& host_domain);
+
+ scoped_ptr<ChromotingHostContext> host_context_;
+ scoped_refptr<base::SingleThreadTaskRunner> plugin_task_runner_;
+ base::WeakPtr<HostNPScriptObject> script_object_;
+ UiStrings ui_strings_;
+
+ State state_;
+
+ HostKeyPair host_key_pair_;
+ scoped_ptr<SignalStrategy> signal_strategy_;
+ scoped_ptr<RegisterSupportHostRequest> register_request_;
+ scoped_ptr<LogToServer> log_to_server_;
+ scoped_ptr<DesktopEnvironmentFactory> desktop_environment_factory_;
+ scoped_ptr<It2MeHostUserInterface> it2me_host_user_interface_;
+ scoped_ptr<HostEventLogger> host_event_logger_;
+
+ scoped_refptr<ChromotingHost> host_;
+ int failed_login_attempts_;
+
+ scoped_ptr<policy_hack::PolicyWatcher> policy_watcher_;
+
+ // Host the current nat traversal policy setting.
+ bool nat_traversal_enabled_;
+
+ // The host domain policy setting.
+ std::string required_host_domain_;
+
+ // Indicates whether or not a policy has ever been read. This is to ensure
+ // that on startup, we do not accidentally start a connection before we have
+ // queried our policy restrictions.
+ bool policy_received_;
+
+ // On startup, it is possible to have Connect() called before the policy read
+ // is completed. Rather than just failing, we thunk the connection call so
+ // it can be executed after at least one successful policy read. This
+ // variable contains the thunk if it is necessary.
+ base::Closure pending_connect_;
+
+ DISALLOW_COPY_AND_ASSIGN(It2MeImpl);
+};
+
+HostNPScriptObject::It2MeImpl::It2MeImpl(
+ scoped_ptr<ChromotingHostContext> host_context,
+ scoped_refptr<base::SingleThreadTaskRunner> plugin_task_runner,
+ base::WeakPtr<HostNPScriptObject> script_object,
+ const UiStrings& ui_strings)
+ : host_context_(host_context.Pass()),
+ plugin_task_runner_(plugin_task_runner),
+ script_object_(script_object),
+ ui_strings_(ui_strings),
+ state_(kDisconnected),
+ failed_login_attempts_(0),
+ nat_traversal_enabled_(false),
+ policy_received_(false) {
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
+}
+
+void HostNPScriptObject::It2MeImpl::Connect(
+ const std::string& uid,
+ const std::string& auth_token,
+ const std::string& auth_service) {
+ if (!host_context_->ui_task_runner()->BelongsToCurrentThread()) {
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
+ host_context_->ui_task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&It2MeImpl::Connect, this, uid, auth_token, auth_service));
+ return;
+ }
+
+ // Create the desktop environment factory.
+ desktop_environment_factory_.reset(new DesktopEnvironmentFactory(
+ host_context_->input_task_runner(), host_context_->ui_task_runner()));
+
+ // Start monitoring configured policies.
+ policy_watcher_.reset(
+ policy_hack::PolicyWatcher::Create(host_context_->network_task_runner()));
+ policy_watcher_->StartWatching(
+ base::Bind(&It2MeImpl::OnPolicyUpdate, this));
+
+ // The UserInterface object needs to be created on the UI thread.
+ it2me_host_user_interface_.reset(
+ new It2MeHostUserInterface(host_context_->network_task_runner(),
+ host_context_->ui_task_runner()));
+
+ // Switch to the network thread to start the actual connection.
+ host_context_->network_task_runner()->PostTask(
+ FROM_HERE, base::Bind(
+ &It2MeImpl::ReadPolicyAndConnect, this,
+ uid, auth_token, auth_service));
+}
+
+void HostNPScriptObject::It2MeImpl::Disconnect() {
+ if (!host_context_->network_task_runner()->BelongsToCurrentThread()) {
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
+ host_context_->network_task_runner()->PostTask(
+ FROM_HERE, base::Bind(&It2MeImpl::Disconnect, this));
+ return;
+ }
+
+ switch (state_) {
+ case kDisconnected:
+ OnShutdownFinished();
+ return;
+
+ case kStarting:
+ SetState(kDisconnecting);
+ SetState(kDisconnected);
+ OnShutdownFinished();
+ return;
+
+ case kDisconnecting:
+ return;
+
+ default:
+ SetState(kDisconnecting);
+
+ if (!host_) {
+ OnShutdownFinished();
+ return;
+ }
+
+ // ChromotingHost::Shutdown() may destroy SignalStrategy
+ // synchronously, but SignalStrategy::Listener handlers are not
+ // allowed to destroy SignalStrategy, so post task to call
+ // Shutdown() later.
+ host_context_->network_task_runner()->PostTask(
+ FROM_HERE, base::Bind(
+ &ChromotingHost::Shutdown, host_,
+ base::Bind(&It2MeImpl::OnShutdownFinished, this)));
+ return;
+ }
+}
+
+void HostNPScriptObject::It2MeImpl::RequestNatPolicy() {
+ if (!host_context_->network_task_runner()->BelongsToCurrentThread()) {
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
+ host_context_->network_task_runner()->PostTask(
+ FROM_HERE, base::Bind(&It2MeImpl::RequestNatPolicy, this));
+ return;
+ }
+
+ if (policy_received_)
+ UpdateNatPolicy(nat_traversal_enabled_);
+}
+
+void HostNPScriptObject::It2MeImpl::ReadPolicyAndConnect(
+ const std::string& uid,
+ const std::string& auth_token,
+ const std::string& auth_service) {
+ DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+ SetState(kStarting);
+
+ // Only proceed to FinishConnect() if at least one policy update has been
+ // received.
+ if (policy_received_) {
+ FinishConnect(uid, auth_token, auth_service);
+ } else {
+ // Otherwise, create the policy watcher, and thunk the connect.
+ pending_connect_ =
+ base::Bind(&It2MeImpl::FinishConnect, this,
+ uid, auth_token, auth_service);
+ }
+}
+
+void HostNPScriptObject::It2MeImpl::FinishConnect(
+ const std::string& uid,
+ const std::string& auth_token,
+ const std::string& auth_service) {
+ DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+ if (state_ != kStarting) {
+ // Host has been stopped while we were fetching policy.
+ return;
+ }
+
+ // Check the host domain policy.
+ if (!required_host_domain_.empty() &&
+ !EndsWith(uid, std::string("@") + required_host_domain_, false)) {
+ SetState(kInvalidDomainError);
+ return;
+ }
+
+ // Generate a key pair for the Host to use.
+ // TODO(wez): Move this to the worker thread.
+ host_key_pair_.Generate();
+
+ // Create XMPP connection.
+ scoped_ptr<SignalStrategy> signal_strategy(
+ new XmppSignalStrategy(host_context_->url_request_context_getter(),
+ uid, auth_token, auth_service));
+
+ // Request registration of the host for support.
+ scoped_ptr<RegisterSupportHostRequest> register_request(
+ new RegisterSupportHostRequest(
+ signal_strategy.get(), &host_key_pair_,
+ base::Bind(&It2MeImpl::OnReceivedSupportID,
+ base::Unretained(this))));
+
+ // Beyond this point nothing can fail, so save the config and request.
+ signal_strategy_ = signal_strategy.Pass();
+ register_request_ = register_request.Pass();
+
+ // If NAT traversal is off then limit port range to allow firewall pin-holing.
+ LOG(INFO) << "NAT state: " << nat_traversal_enabled_;
+ NetworkSettings network_settings(
+ nat_traversal_enabled_ ?
+ NetworkSettings::NAT_TRAVERSAL_ENABLED :
+ NetworkSettings::NAT_TRAVERSAL_DISABLED);
+ if (!nat_traversal_enabled_) {
+ network_settings.min_port = NetworkSettings::kDefaultMinPort;
+ network_settings.max_port = NetworkSettings::kDefaultMaxPort;
+ }
+
+ // Create the host.
+ host_ = new ChromotingHost(
+ signal_strategy_.get(),
+ desktop_environment_factory_.get(),
+ CreateHostSessionManager(network_settings,
+ host_context_->url_request_context_getter()),
+ host_context_->capture_task_runner(),
+ host_context_->encode_task_runner(),
+ host_context_->network_task_runner());
+ host_->AddStatusObserver(this);
+ log_to_server_.reset(
+ new LogToServer(host_, ServerLogEntry::IT2ME, signal_strategy_.get()));
+
+ // Disable audio by default.
+ // TODO(sergeyu): Add UI to enable it.
+ scoped_ptr<protocol::CandidateSessionConfig> protocol_config =
+ protocol::CandidateSessionConfig::CreateDefault();
+ protocol::CandidateSessionConfig::DisableAudioChannel(protocol_config.get());
+ host_->set_protocol_config(protocol_config.Pass());
+
+ // Provide localization strings to the host.
+ host_->SetUiStrings(ui_strings_);
+
+ // Create user interface.
+ it2me_host_user_interface_->Start(host_.get(),
+ base::Bind(&It2MeImpl::Disconnect, this));
+
+ // Create event logger.
+ host_event_logger_ = HostEventLogger::Create(host_, kApplicationName);
+
+ // Connect signaling and start the host.
+ signal_strategy_->Connect();
+ host_->Start(uid);
+
+ SetState(kRequestedAccessCode);
+ return;
+}
+
+void HostNPScriptObject::It2MeImpl::OnShutdownFinished() {
+ if (!host_context_->ui_task_runner()->BelongsToCurrentThread()) {
+ host_context_->ui_task_runner()->PostTask(
+ FROM_HERE, base::Bind(&It2MeImpl::OnShutdownFinished, this));
+ return;
+ }
+
+ // Note that OnShutdownFinished() may be called more than once.
+
+ // UI needs to be shut down on the UI thread before we destroy the
+ // host context (because it depends on the context object), but
+ // only after the host has been shut down (becase the UI object is
+ // registered as status observer for the host, and we can't
+ // unregister it from this thread).
+ it2me_host_user_interface_.reset();
+
+ // Destroy the DesktopEnvironmentFactory, to free thread references.
+ desktop_environment_factory_.reset();
+
+ // Stop listening for policy updates.
+ if (policy_watcher_.get()) {
+ base::WaitableEvent policy_watcher_stopped_(true, false);
+ policy_watcher_->StopWatching(&policy_watcher_stopped_);
+ policy_watcher_stopped_.Wait();
+ policy_watcher_.reset();
+ }
+}
+
+void HostNPScriptObject::It2MeImpl::OnAccessDenied(const std::string& jid) {
+ DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+ ++failed_login_attempts_;
+ if (failed_login_attempts_ == kMaxLoginAttempts) {
+ Disconnect();
+ }
+}
+
+void HostNPScriptObject::It2MeImpl::OnClientAuthenticated(
+ const std::string& jid) {
+ DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+ if (state_ == kDisconnecting) {
+ // Ignore the new connection if we are disconnecting.
+ return;
+ }
+
+ std::string client_username = jid;
+ size_t pos = client_username.find('/');
+ if (pos != std::string::npos)
+ client_username.replace(pos, std::string::npos, "");
+
+ LOG(INFO) << "Client " << client_username << " connected.";
+
+ // Pass the client user name to the script object before changing state.
+ plugin_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&HostNPScriptObject::StoreClientUsername,
+ script_object_, client_username));
+
+ SetState(kConnected);
+}
+
+void HostNPScriptObject::It2MeImpl::OnClientDisconnected(
+ const std::string& jid) {
+ DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+ // Pass the client user name to the script object before changing state.
+ plugin_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&HostNPScriptObject::StoreClientUsername,
+ script_object_, std::string()));
+
+ Disconnect();
+}
+
+void HostNPScriptObject::It2MeImpl::OnShutdown() {
+ DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+ register_request_.reset();
+ log_to_server_.reset();
+ signal_strategy_.reset();
+ host_event_logger_.reset();
+ host_->RemoveStatusObserver(this);
+ host_ = NULL;
+
+ if (state_ != kDisconnected) {
+ SetState(kDisconnected);
+ }
+}
+
+void HostNPScriptObject::It2MeImpl::OnPolicyUpdate(
+ scoped_ptr<base::DictionaryValue> policies) {
+ DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+ bool nat_policy;
+ if (policies->GetBoolean(policy_hack::PolicyWatcher::kNatPolicyName,
+ &nat_policy)) {
+ UpdateNatPolicy(nat_policy);
+ }
+ std::string host_domain;
+ if (policies->GetString(policy_hack::PolicyWatcher::kHostDomainPolicyName,
+ &host_domain)) {
+ UpdateHostDomainPolicy(host_domain);
+ }
+
+ policy_received_ = true;
+
+ if (!pending_connect_.is_null()) {
+ pending_connect_.Run();
+ pending_connect_.Reset();
+ }
+}
+
+void HostNPScriptObject::It2MeImpl::UpdateNatPolicy(
+ bool nat_traversal_enabled) {
+ DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+ VLOG(2) << "UpdateNatPolicy: " << nat_traversal_enabled;
+
+ // When transitioning from enabled to disabled, force disconnect any
+ // existing session.
+ if (nat_traversal_enabled_ && !nat_traversal_enabled) {
+ Disconnect();
+ }
+
+ nat_traversal_enabled_ = nat_traversal_enabled;
+
+ // Notify the web-app of the policy setting.
+ plugin_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&HostNPScriptObject::NotifyNatPolicyChanged,
+ script_object_, nat_traversal_enabled_));
+}
+
+void HostNPScriptObject::It2MeImpl::UpdateHostDomainPolicy(
+ const std::string& host_domain) {
+ DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+ VLOG(2) << "UpdateHostDomainPolicy: " << host_domain;
+
+ // When setting a host domain policy, force disconnect any existing session.
+ if (!host_domain.empty() && state_ != kStarting) {
+ Disconnect();
+ }
+
+ required_host_domain_ = host_domain;
+}
+
+HostNPScriptObject::It2MeImpl::~It2MeImpl() {
+ // Check that resources that need to be torn down on the UI thread are gone.
+ DCHECK(!it2me_host_user_interface_.get());
+ DCHECK(!desktop_environment_factory_.get());
+ DCHECK(!policy_watcher_.get());
+
+ // We might be getting deleted on one of the threads the |host_context| owns,
+ // so we need to post it back to the plugin thread to safely join & delete the
+ // threads it contains. This will go away when we move to AutoThread.
+ plugin_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&It2MeImpl::DeleteHostContext, base::Passed(&host_context_)));
+}
+
+void HostNPScriptObject::It2MeImpl::SetState(State state) {
+ DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+ switch (state_) {
+ case kDisconnected:
+ DCHECK(state == kStarting ||
+ state == kError) << state;
+ break;
+ case kStarting:
+ DCHECK(state == kRequestedAccessCode ||
+ state == kDisconnecting ||
+ state == kError ||
+ state == kInvalidDomainError) << state;
+ break;
+ case kRequestedAccessCode:
+ DCHECK(state == kReceivedAccessCode ||
+ state == kDisconnecting ||
+ state == kError) << state;
+ break;
+ case kReceivedAccessCode:
+ DCHECK(state == kConnected ||
+ state == kDisconnecting ||
+ state == kError) << state;
+ break;
+ case kConnected:
+ DCHECK(state == kDisconnecting ||
+ state == kDisconnected ||
+ state == kError) << state;
+ break;
+ case kDisconnecting:
+ DCHECK(state == kDisconnected) << state;
+ break;
+ case kError:
+ DCHECK(state == kDisconnecting) << state;
+ break;
+ case kInvalidDomainError:
+ DCHECK(state == kDisconnecting) << state;
+ break;
+ };
+
+ state_ = state;
+
+ // Post a state-change notification to the web-app.
+ plugin_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&HostNPScriptObject::NotifyStateChanged,
+ script_object_, state));
+}
+
+void HostNPScriptObject::It2MeImpl::OnReceivedSupportID(
+ bool success,
+ const std::string& support_id,
+ const base::TimeDelta& lifetime) {
+ DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+ if (!success) {
+ SetState(kError);
+ Disconnect();
+ return;
+ }
+
+ std::string host_secret = GenerateSupportHostSecret();
+ std::string access_code = support_id + host_secret;
+
+ std::string local_certificate = host_key_pair_.GenerateCertificate();
+ if (local_certificate.empty()) {
+ LOG(ERROR) << "Failed to generate host certificate.";
+ SetState(kError);
+ Disconnect();
+ return;
+ }
+
+ scoped_ptr<protocol::AuthenticatorFactory> factory(
+ new protocol::It2MeHostAuthenticatorFactory(
+ local_certificate, *host_key_pair_.private_key(), access_code));
+ host_->SetAuthenticatorFactory(factory.Pass());
+
+ // Pass the Access Code to the script object before changing state.
+ plugin_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&HostNPScriptObject::StoreAccessCode,
+ script_object_, access_code, lifetime));
+
+ SetState(kReceivedAccessCode);
+}
+
HostNPScriptObject::HostNPScriptObject(
NPP plugin,
NPObject* parent,
PluginThreadTaskRunner::Delegate* plugin_thread_delegate)
: plugin_(plugin),
parent_(parent),
- am_currently_logging_(false),
- state_(kDisconnected),
- np_thread_id_(base::PlatformThread::CurrentId()),
plugin_task_runner_(
new PluginThreadTaskRunner(plugin_thread_delegate)),
- failed_login_attempts_(0),
- nat_traversal_enabled_(false),
- policy_received_(false),
+ auto_plugin_task_runner_(
+ new AutoThreadTaskRunner(plugin_task_runner_,
+ base::Bind(&PluginThreadTaskRunner::Quit,
+ plugin_task_runner_))),
+ am_currently_logging_(false),
+ state_(kDisconnected),
daemon_controller_(DaemonController::Create()),
- worker_thread_("RemotingHostPlugin") {
+ worker_thread_("RemotingHostPlugin"),
+ ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
+ weak_ptr_(weak_factory_.GetWeakPtr()) {
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
+
worker_thread_.Start();
}
HostNPScriptObject::~HostNPScriptObject() {
- CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
HostLogHandler::UnregisterLoggingScriptObject(this);
- // Stop listening for policy updates.
- if (policy_watcher_.get()) {
- base::WaitableEvent policy_watcher_stopped_(true, false);
- policy_watcher_->StopWatching(&policy_watcher_stopped_);
- policy_watcher_stopped_.Wait();
- policy_watcher_.reset();
+ // Stop the It2Me host if the caller forgot to.
+ if (it2me_impl_.get()) {
+ it2me_impl_->Disconnect();
+ it2me_impl_ = NULL;
}
- if (host_context_.get()) {
- DisconnectInternal();
- } else {
- plugin_task_runner_->Quit();
- }
+ // Release the AutoThreadTaskRunner so the plugin thread can quit.
+ auto_plugin_task_runner_ = NULL;
// Stop the message loop and run the remaining tasks. The loop will exit
// once the wrapping AutoThreadTaskRunner is destroyed.
plugin_task_runner_->DetachAndRunShutdownLoop();
- // Stop all threads.
- host_context_.reset();
+ // Stop the worker thread.
worker_thread_.Stop();
}
-bool HostNPScriptObject::Init() {
- DCHECK(plugin_task_runner_->BelongsToCurrentThread());
- VLOG(2) << "Init";
-
- // Create threads for the Chromoting host & desktop environment to use.
- scoped_refptr<AutoThreadTaskRunner> auto_plugin_task_runner =
- new AutoThreadTaskRunner(plugin_task_runner_,
- base::Bind(&PluginThreadTaskRunner::Quit,
- plugin_task_runner_));
- host_context_.reset(new ChromotingHostContext(auto_plugin_task_runner));
- auto_plugin_task_runner = NULL;
- if (!host_context_->Start()) {
- host_context_.reset();
- return false;
- }
-
- // Create the desktop environment factory.
- desktop_environment_factory_.reset(new DesktopEnvironmentFactory(
- host_context_->input_task_runner(), host_context_->ui_task_runner()));
-
- // Start monitoring configured policies.
- policy_watcher_.reset(
- policy_hack::PolicyWatcher::Create(host_context_->network_task_runner()));
- policy_watcher_->StartWatching(
- base::Bind(&HostNPScriptObject::OnPolicyUpdate,
- base::Unretained(this)));
- return true;
-}
-
bool HostNPScriptObject::HasMethod(const std::string& method_name) {
VLOG(2) << "HasMethod " << method_name;
- CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
return (method_name == kFuncNameConnect ||
method_name == kFuncNameDisconnect ||
method_name == kFuncNameLocalize ||
@@ -179,7 +709,7 @@ bool HostNPScriptObject::InvokeDefault(const NPVariant* args,
uint32_t arg_count,
NPVariant* result) {
VLOG(2) << "InvokeDefault";
- CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
SetException("exception during default invocation");
return false;
}
@@ -189,7 +719,7 @@ bool HostNPScriptObject::Invoke(const std::string& method_name,
uint32_t arg_count,
NPVariant* result) {
VLOG(2) << "Invoke " << method_name;
- CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
if (method_name == kFuncNameConnect) {
return Connect(args, arg_count, result);
} else if (method_name == kFuncNameDisconnect) {
@@ -222,7 +752,7 @@ bool HostNPScriptObject::Invoke(const std::string& method_name,
bool HostNPScriptObject::HasProperty(const std::string& property_name) {
VLOG(2) << "HasProperty " << property_name;
- CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
return (property_name == kAttrNameAccessCode ||
property_name == kAttrNameAccessCodeLifetime ||
property_name == kAttrNameClient ||
@@ -243,7 +773,7 @@ bool HostNPScriptObject::HasProperty(const std::string& property_name) {
bool HostNPScriptObject::GetProperty(const std::string& property_name,
NPVariant* result) {
VLOG(2) << "GetProperty " << property_name;
- CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
if (!result) {
SetException("GetProperty: NULL result");
return false;
@@ -262,11 +792,9 @@ bool HostNPScriptObject::GetProperty(const std::string& property_name,
INT32_TO_NPVARIANT(state_, *result);
return true;
} else if (property_name == kAttrNameAccessCode) {
- base::AutoLock auto_lock(access_code_lock_);
*result = NPVariantFromString(access_code_);
return true;
} else if (property_name == kAttrNameAccessCodeLifetime) {
- base::AutoLock auto_lock(access_code_lock_);
INT32_TO_NPVARIANT(access_code_lifetime_.InSeconds(), *result);
return true;
} else if (property_name == kAttrNameClient) {
@@ -308,19 +836,14 @@ bool HostNPScriptObject::GetProperty(const std::string& property_name,
bool HostNPScriptObject::SetProperty(const std::string& property_name,
const NPVariant* value) {
VLOG(2) << "SetProperty " << property_name;
- CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
if (property_name == kAttrNameOnNatTraversalPolicyChanged) {
if (NPVARIANT_IS_OBJECT(*value)) {
on_nat_traversal_policy_changed_func_ = NPVARIANT_TO_OBJECT(*value);
- bool policy_received, nat_traversal_enabled;
- {
- base::AutoLock lock(nat_policy_lock_);
- policy_received = policy_received_;
- nat_traversal_enabled = nat_traversal_enabled_;
- }
- if (policy_received) {
- UpdateWebappNatPolicy(nat_traversal_enabled);
+ if (it2me_impl_) {
+ // Ask the It2Me implementation to notify the web-app of the policy.
+ it2me_impl_->RequestNatPolicy();
}
return true;
} else {
@@ -358,13 +881,13 @@ bool HostNPScriptObject::SetProperty(const std::string& property_name,
bool HostNPScriptObject::RemoveProperty(const std::string& property_name) {
VLOG(2) << "RemoveProperty " << property_name;
- CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
return false;
}
bool HostNPScriptObject::Enumerate(std::vector<std::string>* values) {
VLOG(2) << "Enumerate";
- CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
const char* entries[] = {
kAttrNameAccessCode,
kAttrNameState,
@@ -396,52 +919,6 @@ bool HostNPScriptObject::Enumerate(std::vector<std::string>* values) {
return true;
}
-void HostNPScriptObject::OnAccessDenied(const std::string& jid) {
- DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
-
- ++failed_login_attempts_;
- if (failed_login_attempts_ == kMaxLoginAttempts) {
- DisconnectInternal();
- }
-}
-
-void HostNPScriptObject::OnClientAuthenticated(const std::string& jid) {
- DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
-
- if (state_ == kDisconnecting) {
- // Ignore the new connection if we are disconnecting.
- return;
- }
-
- client_username_ = jid;
- size_t pos = client_username_.find('/');
- if (pos != std::string::npos)
- client_username_.replace(pos, std::string::npos, "");
- LOG(INFO) << "Client " << client_username_ << " connected.";
- SetState(kConnected);
-}
-
-void HostNPScriptObject::OnClientDisconnected(const std::string& jid) {
- DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
- client_username_.clear();
- DisconnectInternal();
-}
-
-void HostNPScriptObject::OnShutdown() {
- DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
-
- register_request_.reset();
- log_to_server_.reset();
- signal_strategy_.reset();
- host_event_logger_.reset();
- host_->RemoveStatusObserver(this);
- host_ = NULL;
-
- if (state_ != kDisconnected) {
- SetState(kDisconnected);
- }
-}
-
// string uid, string auth_token
bool HostNPScriptObject::Connect(const NPVariant* args,
uint32_t arg_count,
@@ -455,7 +932,7 @@ bool HostNPScriptObject::Connect(const NPVariant* args,
return false;
}
- if (state_ != kDisconnected) {
+ if (it2me_impl_) {
SetException("connect: can be called only when disconnected");
return false;
}
@@ -476,136 +953,20 @@ bool HostNPScriptObject::Connect(const NPVariant* args,
return false;
}
- // The UserInterface object needs to be created on the UI thread.
- it2me_host_user_interface_.reset(
- new It2MeHostUserInterface(host_context_->network_task_runner(),
- host_context_->ui_task_runner()));
-
- ReadPolicyAndConnect(uid, auth_token, auth_service);
-
- return true;
-}
-
-void HostNPScriptObject::ReadPolicyAndConnect(const std::string& uid,
- const std::string& auth_token,
- const std::string& auth_service) {
- if (!host_context_->network_task_runner()->BelongsToCurrentThread()) {
- host_context_->network_task_runner()->PostTask(
- FROM_HERE, base::Bind(
- &HostNPScriptObject::ReadPolicyAndConnect, base::Unretained(this),
- uid, auth_token, auth_service));
- return;
- }
-
- SetState(kStarting);
-
- // Only proceed to FinishConnect() if at least one policy update has been
- // received.
- if (policy_received_) {
- FinishConnect(uid, auth_token, auth_service);
- } else {
- // Otherwise, create the policy watcher, and thunk the connect.
- pending_connect_ =
- base::Bind(&HostNPScriptObject::FinishConnect,
- base::Unretained(this), uid, auth_token, auth_service);
- }
-}
-
-void HostNPScriptObject::FinishConnect(
- const std::string& uid,
- const std::string& auth_token,
- const std::string& auth_service) {
- if (!host_context_->network_task_runner()->BelongsToCurrentThread()) {
- host_context_->network_task_runner()->PostTask(FROM_HERE, base::Bind(
- &HostNPScriptObject::FinishConnect, base::Unretained(this),
- uid, auth_token, auth_service));
- return;
- }
-
- if (state_ != kStarting) {
- // Host has been stopped while we were fetching policy.
- return;
- }
-
- // Check the host domain policy.
- if (!required_host_domain_.empty() &&
- !EndsWith(uid, std::string("@") + required_host_domain_, false)) {
- SetState(kInvalidDomainError);
- return;
- }
-
- // Generate a key pair for the Host to use.
- // TODO(wez): Move this to the worker thread.
- host_key_pair_.Generate();
-
- // Create XMPP connection.
- scoped_ptr<SignalStrategy> signal_strategy(
- new XmppSignalStrategy(host_context_->url_request_context_getter(),
- uid, auth_token, auth_service));
-
- // Request registration of the host for support.
- scoped_ptr<RegisterSupportHostRequest> register_request(
- new RegisterSupportHostRequest(
- signal_strategy.get(), &host_key_pair_,
- base::Bind(&HostNPScriptObject::OnReceivedSupportID,
- base::Unretained(this))));
-
- // Beyond this point nothing can fail, so save the config and request.
- signal_strategy_.reset(signal_strategy.release());
- register_request_.reset(register_request.release());
-
- // If NAT traversal is off then limit port range to allow firewall pin-holing.
- LOG(INFO) << "NAT state: " << nat_traversal_enabled_;
- NetworkSettings network_settings(
- nat_traversal_enabled_ ?
- NetworkSettings::NAT_TRAVERSAL_ENABLED :
- NetworkSettings::NAT_TRAVERSAL_DISABLED);
- if (!nat_traversal_enabled_) {
- network_settings.min_port = NetworkSettings::kDefaultMinPort;
- network_settings.max_port = NetworkSettings::kDefaultMaxPort;
- }
-
- // Create the host.
- host_ = new ChromotingHost(
- signal_strategy_.get(),
- desktop_environment_factory_.get(),
- CreateHostSessionManager(network_settings,
- host_context_->url_request_context_getter()),
- host_context_->capture_task_runner(),
- host_context_->encode_task_runner(),
- host_context_->network_task_runner());
- host_->AddStatusObserver(this);
- log_to_server_.reset(
- new LogToServer(host_, ServerLogEntry::IT2ME, signal_strategy_.get()));
-
- // Disable audio by default.
- // TODO(sergeyu): Add UI to enable it.
- scoped_ptr<protocol::CandidateSessionConfig> protocol_config =
- protocol::CandidateSessionConfig::CreateDefault();
- protocol::CandidateSessionConfig::DisableAudioChannel(protocol_config.get());
- host_->set_protocol_config(protocol_config.Pass());
-
- // Provide localization strings to the host.
- {
- base::AutoLock auto_lock(ui_strings_lock_);
- host_->SetUiStrings(ui_strings_);
+ // Create threads for the Chromoting host & desktop environment to use.
+ scoped_ptr<ChromotingHostContext> host_context(
+ new ChromotingHostContext(auto_plugin_task_runner_));
+ if (!host_context->Start()) {
+ SetException("connect: failed to start threads");
+ return false;
}
- // Create user interface.
- base::Closure disconnect_callback = base::Bind(
- &ChromotingHost::Shutdown, base::Unretained(host_.get()),
- base::Closure());
- it2me_host_user_interface_->Start(host_.get(), disconnect_callback);
-
- // Create event logger.
- host_event_logger_ = HostEventLogger::Create(host_, kApplicationName);
-
- // Connect signaling and start the host.
- signal_strategy_->Connect();
- host_->Start(uid);
+ // Create the It2Me host implementation and start connecting.
+ it2me_impl_ = new It2MeImpl(
+ host_context.Pass(), auto_plugin_task_runner_, weak_ptr_, ui_strings_);
+ it2me_impl_->Connect(uid, auth_token, auth_service);
- SetState(kRequestedAccessCode);
- return;
+ return true;
}
bool HostNPScriptObject::Disconnect(const NPVariant* args,
@@ -617,7 +978,10 @@ bool HostNPScriptObject::Disconnect(const NPVariant* args,
return false;
}
- DisconnectInternal();
+ if (it2me_impl_) {
+ it2me_impl_->Disconnect();
+ it2me_impl_ = NULL;
+ }
return true;
}
@@ -692,6 +1056,9 @@ bool HostNPScriptObject::GenerateKeyPair(const NPVariant* args,
return false;
}
+ // TODO(wez): HostNPScriptObject needn't be touched on worker
+ // thread, so make DoGenerateKeyPair static and pass it a callback
+ // to run (crbug.com/156257).
worker_thread_.message_loop_proxy()->PostTask(
FROM_HERE, base::Bind(&HostNPScriptObject::DoGenerateKeyPair,
base::Unretained(this), callback_obj));
@@ -730,6 +1097,8 @@ bool HostNPScriptObject::UpdateDaemonConfig(const NPVariant* args,
return false;
}
+ // TODO(wez): Pass a static method here, that will post the result
+ // back to us on the right thread (crbug.com/156257).
daemon_controller_->UpdateConfig(
config_dict.Pass(),
base::Bind(&HostNPScriptObject::InvokeAsyncResultCallback,
@@ -751,8 +1120,8 @@ bool HostNPScriptObject::GetDaemonConfig(const NPVariant* args,
return false;
}
- // We control lifetime of the |daemon_controller_| so it's safe to
- // use base::Unretained() here.
+ // TODO(wez): Pass a static method here, that will post the result
+ // back to us on the right thread (crbug.com/156257).
daemon_controller_->GetConfig(
base::Bind(&HostNPScriptObject::InvokeGetDaemonConfigCallback,
base::Unretained(this), callback_obj));
@@ -774,8 +1143,8 @@ bool HostNPScriptObject::GetDaemonVersion(const NPVariant* args,
return false;
}
- // We control lifetime of the |daemon_controller_| so it's safe to
- // use base::Unretained() here.
+ // TODO(wez): Pass a static method here, that will post the result
+ // back to us on the right thread (crbug.com/156257).
daemon_controller_->GetVersion(
base::Bind(&HostNPScriptObject::InvokeGetDaemonVersionCallback,
base::Unretained(this), callback_obj));
@@ -797,8 +1166,8 @@ bool HostNPScriptObject::GetUsageStatsConsent(const NPVariant* args,
return false;
}
- // We control lifetime of the |daemon_controller_| so it's safe to
- // use base::Unretained() here.
+ // TODO(wez): Pass a static method here, that will post the result
+ // back to us on the right thread (crbug.com/156257).
daemon_controller_->GetUsageStatsConsent(
base::Bind(&HostNPScriptObject::InvokeGetUsageStatsConsentCallback,
base::Unretained(this), callback_obj));
@@ -808,6 +1177,8 @@ bool HostNPScriptObject::GetUsageStatsConsent(const NPVariant* args,
bool HostNPScriptObject::StartDaemon(const NPVariant* args,
uint32_t arg_count,
NPVariant* result) {
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
+
if (arg_count != 3) {
SetException("startDaemon: bad number of arguments");
return false;
@@ -835,6 +1206,8 @@ bool HostNPScriptObject::StartDaemon(const NPVariant* args,
return false;
}
+ // TODO(wez): Pass a static method here, that will post the result
+ // back to us on the right thread (crbug.com/156257).
daemon_controller_->SetConfigAndStart(
config_dict.Pass(),
NPVARIANT_TO_BOOLEAN(args[1]),
@@ -846,6 +1219,8 @@ bool HostNPScriptObject::StartDaemon(const NPVariant* args,
bool HostNPScriptObject::StopDaemon(const NPVariant* args,
uint32_t arg_count,
NPVariant* result) {
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
+
if (arg_count != 1) {
SetException("stopDaemon: bad number of arguments");
return false;
@@ -857,240 +1232,54 @@ bool HostNPScriptObject::StopDaemon(const NPVariant* args,
return false;
}
+ // TODO(wez): Pass a static method here, that will post the result
+ // back to us on the right thread (crbug.com/156257).
daemon_controller_->Stop(
base::Bind(&HostNPScriptObject::InvokeAsyncResultCallback,
base::Unretained(this), callback_obj));
return true;
}
-void HostNPScriptObject::DisconnectInternal() {
- if (!host_context_->network_task_runner())
- return;
-
- if (!host_context_->network_task_runner()->BelongsToCurrentThread()) {
- host_context_->network_task_runner()->PostTask(
- FROM_HERE, base::Bind(&HostNPScriptObject::DisconnectInternal,
- base::Unretained(this)));
- return;
- }
-
- switch (state_) {
- case kDisconnected:
- OnShutdownFinished();
- return;
-
- case kStarting:
- SetState(kDisconnecting);
- SetState(kDisconnected);
- OnShutdownFinished();
- return;
-
- case kDisconnecting:
- return;
-
- default:
- SetState(kDisconnecting);
-
- if (!host_) {
- OnShutdownFinished();
- return;
- }
- // ChromotingHost::Shutdown() may destroy SignalStrategy
- // synchronously, but SignalStrategy::Listener handlers are not
- // allowed to destroy SignalStrategy, so post task to call
- // Shutdown() later.
- host_context_->network_task_runner()->PostTask(
- FROM_HERE, base::Bind(
- &ChromotingHost::Shutdown, host_,
- base::Bind(&HostNPScriptObject::OnShutdownFinished,
- base::Unretained(this))));
- return;
- }
-}
-
-void HostNPScriptObject::OnShutdownFinished() {
- if (!host_context_->ui_task_runner()->BelongsToCurrentThread()) {
- host_context_->ui_task_runner()->PostTask(
- FROM_HERE, base::Bind(&HostNPScriptObject::OnShutdownFinished,
- base::Unretained(this)));
- return;
- }
-
- // UI needs to be shut down on the UI thread before we destroy the
- // host context (because it depends on the context object), but
- // only after the host has been shut down (becase the UI object is
- // registered as status observer for the host, and we can't
- // unregister it from this thread).
- it2me_host_user_interface_.reset();
-
- // Destroy the DesktopEnvironmentFactory, to free thread references.
- desktop_environment_factory_.reset();
-
- // Release the context's TaskRunner references for the threads, so they can
- // exit when no objects need them.
- host_context_->ReleaseTaskRunners();
-}
-
-void HostNPScriptObject::OnPolicyUpdate(
- scoped_ptr<base::DictionaryValue> policies) {
- if (!host_context_->network_task_runner()->BelongsToCurrentThread()) {
- host_context_->network_task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&HostNPScriptObject::OnPolicyUpdate,
- base::Unretained(this), base::Passed(&policies)));
- return;
- }
-
- bool nat_policy;
- if (policies->GetBoolean(policy_hack::PolicyWatcher::kNatPolicyName,
- &nat_policy)) {
- UpdateNatPolicy(nat_policy);
- }
- std::string host_domain;
- if (policies->GetString(policy_hack::PolicyWatcher::kHostDomainPolicyName,
- &host_domain)) {
- UpdateHostDomainPolicy(host_domain);
- }
+void HostNPScriptObject::NotifyStateChanged(State state) {
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
- {
- base::AutoLock lock(nat_policy_lock_);
- policy_received_ = true;
- }
+ state_ = state;
- if (!pending_connect_.is_null()) {
- pending_connect_.Run();
- pending_connect_.Reset();
+ if (on_state_changed_func_.get()) {
+ NPVariant state_var;
+ INT32_TO_NPVARIANT(state, state_var);
+ InvokeAndIgnoreResult(on_state_changed_func_.get(), &state_var, 1);
}
}
-void HostNPScriptObject::UpdateNatPolicy(bool nat_traversal_enabled) {
- DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
-
- VLOG(2) << "UpdateNatPolicy: " << nat_traversal_enabled;
-
- // When transitioning from enabled to disabled, force disconnect any
- // existing session.
- if (nat_traversal_enabled_ && !nat_traversal_enabled) {
- DisconnectInternal();
- }
+void HostNPScriptObject::NotifyNatPolicyChanged(bool nat_traversal_enabled) {
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
- {
- base::AutoLock lock(nat_policy_lock_);
- nat_traversal_enabled_ = nat_traversal_enabled;
+ if (on_nat_traversal_policy_changed_func_.get()) {
+ NPVariant policy;
+ BOOLEAN_TO_NPVARIANT(nat_traversal_enabled, policy);
+ InvokeAndIgnoreResult(on_nat_traversal_policy_changed_func_.get(),
+ &policy, 1);
}
-
- UpdateWebappNatPolicy(nat_traversal_enabled_);
}
-void HostNPScriptObject::UpdateHostDomainPolicy(
- const std::string& host_domain) {
- DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
-
- VLOG(2) << "UpdateHostDomainPolicy: " << host_domain;
-
- // When setting a host domain policy, force disconnect any existing session.
- if (!host_domain.empty() && state_ != kStarting) {
- DisconnectInternal();
- }
+// Stores the Access Code for the web-app to query.
+void HostNPScriptObject::StoreAccessCode(const std::string& access_code,
+ base::TimeDelta access_code_lifetime) {
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
- required_host_domain_ = host_domain;
+ access_code_ = access_code;
+ access_code_lifetime_ = access_code_lifetime;
}
-void HostNPScriptObject::OnReceivedSupportID(
- bool success,
- const std::string& support_id,
- const base::TimeDelta& lifetime) {
- DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
-
- if (!success) {
- SetState(kError);
- DisconnectInternal();
- return;
- }
-
- std::string host_secret = GenerateSupportHostSecret();
- std::string access_code = support_id + host_secret;
-
- std::string local_certificate = host_key_pair_.GenerateCertificate();
- if (local_certificate.empty()) {
- LOG(ERROR) << "Failed to generate host certificate.";
- SetState(kError);
- DisconnectInternal();
- return;
- }
-
- scoped_ptr<protocol::AuthenticatorFactory> factory(
- new protocol::It2MeHostAuthenticatorFactory(
- local_certificate, *host_key_pair_.private_key(), access_code));
- host_->SetAuthenticatorFactory(factory.Pass());
-
- {
- base::AutoLock lock(access_code_lock_);
- access_code_ = access_code;
- access_code_lifetime_ = lifetime;
- }
-
- SetState(kReceivedAccessCode);
-}
+// Stores the client user's name for the web-app to query.
+void HostNPScriptObject::StoreClientUsername(
+ const std::string& client_username) {
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
-void HostNPScriptObject::SetState(State state) {
- DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
- switch (state_) {
- case kDisconnected:
- DCHECK(state == kStarting ||
- state == kError) << state;
- break;
- case kStarting:
- DCHECK(state == kRequestedAccessCode ||
- state == kDisconnecting ||
- state == kError ||
- state == kInvalidDomainError) << state;
- break;
- case kRequestedAccessCode:
- DCHECK(state == kReceivedAccessCode ||
- state == kDisconnecting ||
- state == kError) << state;
- break;
- case kReceivedAccessCode:
- DCHECK(state == kConnected ||
- state == kDisconnecting ||
- state == kError) << state;
- break;
- case kConnected:
- DCHECK(state == kDisconnecting ||
- state == kDisconnected ||
- state == kError) << state;
- break;
- case kDisconnecting:
- DCHECK(state == kDisconnected) << state;
- break;
- case kError:
- DCHECK(state == kDisconnecting) << state;
- break;
- case kInvalidDomainError:
- DCHECK(state == kDisconnecting) << state;
- break;
- };
- state_ = state;
- NotifyStateChanged(state);
+ client_username_ = client_username;
}
-void HostNPScriptObject::NotifyStateChanged(State state) {
- if (!plugin_task_runner_->BelongsToCurrentThread()) {
- plugin_task_runner_->PostTask(
- FROM_HERE, base::Bind(&HostNPScriptObject::NotifyStateChanged,
- base::Unretained(this), state));
- return;
- }
- if (on_state_changed_func_.get()) {
- VLOG(2) << "Calling state changed " << state;
- NPVariant state_var;
- INT32_TO_NPVARIANT(state, state_var);
- bool is_good = InvokeAndIgnoreResult(on_state_changed_func_.get(),
- &state_var, 1);
- LOG_IF(ERROR, !is_good) << "OnStateChanged failed";
- }
-}
void HostNPScriptObject::PostLogDebugInfo(const std::string& message) {
if (plugin_task_runner_->BelongsToCurrentThread()) {
// Make sure we're not currently processing a log message.
@@ -1103,25 +1292,26 @@ void HostNPScriptObject::PostLogDebugInfo(const std::string& message) {
// log messages are shown in the correct order.
plugin_task_runner_->PostTask(
FROM_HERE, base::Bind(&HostNPScriptObject::LogDebugInfo,
- base::Unretained(this), message));
+ weak_ptr_, message));
}
void HostNPScriptObject::SetWindow(NPWindow* np_window) {
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread());
+
daemon_controller_->SetWindow(np_window->window);
}
void HostNPScriptObject::LocalizeStrings(NPObject* localize_func) {
DCHECK(plugin_task_runner_->BelongsToCurrentThread());
- UiStrings ui_strings;
string16 direction;
LocalizeString(localize_func, "@@bidi_dir", &direction);
- ui_strings.direction = UTF16ToUTF8(direction) == "rtl" ?
+ ui_strings_.direction = UTF16ToUTF8(direction) == "rtl" ?
remoting::UiStrings::RTL : remoting::UiStrings::LTR;
LocalizeString(localize_func, /*i18n-content*/"PRODUCT_NAME",
- &ui_strings.product_name);
+ &ui_strings_.product_name);
LocalizeString(localize_func, /*i18n-content*/"DISCONNECT_OTHER_BUTTON",
- &ui_strings.disconnect_button_text);
+ &ui_strings_.disconnect_button_text);
LocalizeString(localize_func,
#if defined(OS_WIN)
/*i18n-content*/"DISCONNECT_BUTTON_PLUS_SHORTCUT_WINDOWS",
@@ -1130,19 +1320,16 @@ void HostNPScriptObject::LocalizeStrings(NPObject* localize_func) {
#else
/*i18n-content*/"DISCONNECT_BUTTON_PLUS_SHORTCUT_LINUX",
#endif
- &ui_strings.disconnect_button_text_plus_shortcut);
+ &ui_strings_.disconnect_button_text_plus_shortcut);
LocalizeString(localize_func, /*i18n-content*/"CONTINUE_PROMPT",
- &ui_strings.continue_prompt);
+ &ui_strings_.continue_prompt);
LocalizeString(localize_func, /*i18n-content*/"CONTINUE_BUTTON",
- &ui_strings.continue_button_text);
+ &ui_strings_.continue_button_text);
LocalizeString(localize_func, /*i18n-content*/"STOP_SHARING_BUTTON",
- &ui_strings.stop_sharing_button_text);
+ &ui_strings_.stop_sharing_button_text);
LocalizeStringWithSubstitution(localize_func,
/*i18n-content*/"MESSAGE_SHARED", "$1",
- &ui_strings.disconnect_message);
-
- base::AutoLock auto_lock(ui_strings_lock_);
- ui_strings_ = ui_strings;
+ &ui_strings_.disconnect_message);
}
bool HostNPScriptObject::LocalizeString(NPObject* localize_func,
@@ -1178,21 +1365,6 @@ bool HostNPScriptObject::LocalizeStringWithSubstitution(
return true;
}
-void HostNPScriptObject::UpdateWebappNatPolicy(bool nat_traversal_enabled) {
- if (!plugin_task_runner_->BelongsToCurrentThread()) {
- plugin_task_runner_->PostTask(
- FROM_HERE, base::Bind(&HostNPScriptObject::UpdateWebappNatPolicy,
- base::Unretained(this), nat_traversal_enabled));
- return;
- }
- if (on_nat_traversal_policy_changed_func_.get()) {
- NPVariant policy;
- BOOLEAN_TO_NPVARIANT(nat_traversal_enabled, policy);
- InvokeAndIgnoreResult(on_nat_traversal_policy_changed_func_.get(),
- &policy, 1);
- }
-}
-
void HostNPScriptObject::DoGenerateKeyPair(const ScopedRefNPObject& callback) {
HostKeyPair key_pair;
key_pair.Generate();
@@ -1208,7 +1380,7 @@ void HostNPScriptObject::InvokeGenerateKeyPairCallback(
plugin_task_runner_->PostTask(
FROM_HERE, base::Bind(
&HostNPScriptObject::InvokeGenerateKeyPairCallback,
- base::Unretained(this), callback, private_key, public_key));
+ weak_ptr_, callback, private_key, public_key));
return;
}
@@ -1227,7 +1399,7 @@ void HostNPScriptObject::InvokeAsyncResultCallback(
plugin_task_runner_->PostTask(
FROM_HERE, base::Bind(
&HostNPScriptObject::InvokeAsyncResultCallback,
- base::Unretained(this), callback, result));
+ weak_ptr_, callback, result));
return;
}
@@ -1244,7 +1416,7 @@ void HostNPScriptObject::InvokeGetDaemonConfigCallback(
plugin_task_runner_->PostTask(
FROM_HERE, base::Bind(
&HostNPScriptObject::InvokeGetDaemonConfigCallback,
- base::Unretained(this), callback, base::Passed(&config)));
+ weak_ptr_, callback, base::Passed(&config)));
return;
}
@@ -1265,7 +1437,7 @@ void HostNPScriptObject::InvokeGetDaemonVersionCallback(
plugin_task_runner_->PostTask(
FROM_HERE, base::Bind(
&HostNPScriptObject::InvokeGetDaemonVersionCallback,
- base::Unretained(this), callback, version));
+ weak_ptr_, callback, version));
return;
}
@@ -1283,7 +1455,7 @@ void HostNPScriptObject::InvokeGetUsageStatsConsentCallback(
plugin_task_runner_->PostTask(
FROM_HERE, base::Bind(
&HostNPScriptObject::InvokeGetUsageStatsConsentCallback,
- base::Unretained(this), callback, supported, allowed,
+ weak_ptr_, callback, supported, allowed,
set_by_policy));
return;
}
@@ -1300,6 +1472,7 @@ void HostNPScriptObject::InvokeGetUsageStatsConsentCallback(
void HostNPScriptObject::LogDebugInfo(const std::string& message) {
DCHECK(plugin_task_runner_->BelongsToCurrentThread());
+
if (log_debug_info_func_.get()) {
am_currently_logging_ = true;
NPVariant log_message;
@@ -1317,16 +1490,19 @@ bool HostNPScriptObject::InvokeAndIgnoreResult(NPObject* func,
const NPVariant* args,
uint32_t arg_count) {
DCHECK(plugin_task_runner_->BelongsToCurrentThread());
+
NPVariant np_result;
bool is_good = g_npnetscape_funcs->invokeDefault(plugin_, func, args,
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_task_runner_->BelongsToCurrentThread());
+
g_npnetscape_funcs->setexception(parent_, exception_string.c_str());
LOG(INFO) << exception_string;
}
diff --git a/remoting/host/plugin/host_script_object.h b/remoting/host/plugin/host_script_object.h
index cfcb990..5634bab 100644
--- a/remoting/host/plugin/host_script_object.h
+++ b/remoting/host/plugin/host_script_object.h
@@ -11,6 +11,7 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "base/synchronization/cancellation_flag.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
@@ -21,7 +22,6 @@
#include "remoting/base/plugin_thread_task_runner.h"
#include "remoting/host/chromoting_host_context.h"
#include "remoting/host/host_key_pair.h"
-#include "remoting/host/host_status_observer.h"
#include "remoting/host/log_to_server.h"
#include "remoting/host/plugin/host_plugin_utils.h"
#include "remoting/host/setup/daemon_controller.h"
@@ -32,31 +32,17 @@
namespace remoting {
-class ChromotingHost;
-class DesktopEnvironmentFactory;
-class HostEventLogger;
-class It2MeHostUserInterface;
-class MutableHostConfig;
-class RegisterSupportHostRequest;
-class SignalStrategy;
-class SupportAccessVerifier;
-
-namespace policy_hack {
-class PolicyWatcher;
-} // namespace policy_hack
-
// NPAPI plugin implementation for remoting host script object.
// HostNPScriptObject creates threads that are required to run
// ChromotingHost and starts/stops the host on those threads. When
// destroyed it synchronously shuts down the host and all threads.
-class HostNPScriptObject : public HostStatusObserver {
+class HostNPScriptObject {
public:
HostNPScriptObject(NPP plugin, NPObject* parent,
PluginThreadTaskRunner::Delegate* plugin_thread_delegate);
virtual ~HostNPScriptObject();
- bool Init();
-
+ // Implementations used to implement the NPObject interface.
bool HasMethod(const std::string& method_name);
bool InvokeDefault(const NPVariant* args,
uint32_t arg_count,
@@ -71,12 +57,6 @@ class HostNPScriptObject : public HostStatusObserver {
bool RemoveProperty(const std::string& property_name);
bool Enumerate(std::vector<std::string>* values);
- // remoting::HostStatusObserver implementation.
- virtual void OnAccessDenied(const std::string& jid) OVERRIDE;
- virtual void OnClientAuthenticated(const std::string& jid) OVERRIDE;
- virtual void OnClientDisconnected(const std::string& jid) OVERRIDE;
- virtual void OnShutdown() OVERRIDE;
-
// Post LogDebugInfo to the correct proxy (and thus, on the correct thread).
// This should only be called by HostLogHandler. To log to the UI, use the
// standard LOG(INFO) and it will be sent to this method.
@@ -85,6 +65,11 @@ class HostNPScriptObject : public HostStatusObserver {
void SetWindow(NPWindow* np_window);
private:
+ //////////////////////////////////////////////////////////
+ // Definitions for It2Me host.
+
+ class It2MeImpl;
+
// These state values are duplicated in host_session.js. Remember to update
// both copies when making changes.
enum State {
@@ -181,42 +166,23 @@ class HostNPScriptObject : public HostStatusObserver {
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);
+ // Helper methods used by the It2Me host implementation.
// Notifies OnStateChanged handler of a state change.
void NotifyStateChanged(State state);
- // Callbacks invoked during session setup.
- void OnReceivedSupportID(bool success,
- const std::string& support_id,
- const base::TimeDelta& lifetime);
-
- // Helper functions that run on main thread. Can be called on any
- // other thread.
- void ReadPolicyAndConnect(const std::string& uid,
- const std::string& auth_token,
- const std::string& auth_service);
- void FinishConnect(const std::string& uid,
- const std::string& auth_token,
- const std::string& auth_service);
-
- void DisconnectInternal();
-
- // Callback for ChromotingHost::Shutdown().
- void OnShutdownFinished();
-
- // Called when a policy is updated.
- void OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies);
+ // If the web-app has registered a callback to be notified of changes to the
+ // NAT traversal policy, notify it.
+ void NotifyNatPolicyChanged(bool nat_traversal_enabled);
- // Called when the nat traversal policy is updated.
- void UpdateNatPolicy(bool nat_traversal_enabled);
+ // Stores the Access Code for the web-app to query.
+ void StoreAccessCode(const std::string& access_code,
+ base::TimeDelta access_code_lifetime);
- // Called when the host domain policy is updated.
- void UpdateHostDomainPolicy(const std::string& host_domain);
+ // Stores the client user's name for the web-app to query.
+ void StoreClientUsername(const std::string& client_username);
+ // Used to generate localized strings to pass to the It2Me host core.
void LocalizeStrings(NPObject* localize_func);
// Helper function for executing InvokeDefault on an NPObject that performs
@@ -235,10 +201,6 @@ class HostNPScriptObject : public HostStatusObserver {
const char* substitution,
string16* result);
- // If the web-app has registered a callback to be notified of changes to the
- // NAT traversal policy, notify it.
- void UpdateWebappNatPolicy(bool nat_traversal_enabled);
-
//////////////////////////////////////////////////////////
// Helper methods for Me2Me host.
@@ -287,64 +249,40 @@ class HostNPScriptObject : public HostStatusObserver {
//////////////////////////////////////////////////////////
// Plugin state variables shared between It2Me and Me2Me.
- // True if we're in the middle of handling a log message.
NPP plugin_;
NPObject* parent_;
+ scoped_refptr<PluginThreadTaskRunner> plugin_task_runner_;
+
+ scoped_refptr<AutoThreadTaskRunner> auto_plugin_task_runner_;
+
+ // True if we're in the middle of handling a log message.
bool am_currently_logging_;
+ ScopedRefNPObject log_debug_info_func_;
+
//////////////////////////////////////////////////////////
// It2Me host state.
- State state_;
- base::Lock access_code_lock_;
+ // Internal implementation of the It2Me host function.
+ scoped_refptr<It2MeImpl> it2me_impl_;
+
+ // Cached, read-only copies of |it2me_impl_| session state.
+ State state_;
std::string access_code_;
base::TimeDelta access_code_lifetime_;
-
std::string client_username_;
- ScopedRefNPObject log_debug_info_func_;
- ScopedRefNPObject on_nat_traversal_policy_changed_func_;
- ScopedRefNPObject on_state_changed_func_;
- base::PlatformThreadId np_thread_id_;
- scoped_refptr<PluginThreadTaskRunner> plugin_task_runner_;
-
- scoped_ptr<ChromotingHostContext> host_context_;
- HostKeyPair host_key_pair_;
- scoped_ptr<SignalStrategy> signal_strategy_;
- scoped_ptr<RegisterSupportHostRequest> register_request_;
- scoped_ptr<LogToServer> log_to_server_;
- scoped_ptr<DesktopEnvironmentFactory> desktop_environment_factory_;
- scoped_ptr<It2MeHostUserInterface> it2me_host_user_interface_;
- scoped_ptr<HostEventLogger> host_event_logger_;
-
- scoped_refptr<ChromotingHost> host_;
- int failed_login_attempts_;
+ // Localized strings for use by the |it2me_impl_| UI.
UiStrings ui_strings_;
- base::Lock ui_strings_lock_;
- base::Lock nat_policy_lock_;
-
- scoped_ptr<policy_hack::PolicyWatcher> policy_watcher_;
-
- // Host the current nat traversal policy setting.
- bool nat_traversal_enabled_;
-
- // The host domain policy setting.
- std::string required_host_domain_;
-
- // Indicates whether or not a policy has ever been read. This is to ensure
- // that on startup, we do not accidentally start a connection before we have
- // queried our policy restrictions.
- bool policy_received_;
-
- // On startup, it is possible to have Connect() called before the policy read
- // is completed. Rather than just failing, we thunk the connection call so
- // it can be executed after at least one successful policy read. This
- // variable contains the thunk if it is necessary.
- base::Closure pending_connect_;
+ // Callbacks to notify in response to |it2me_impl_| events.
+ ScopedRefNPObject on_nat_traversal_policy_changed_func_;
+ ScopedRefNPObject on_state_changed_func_;
//////////////////////////////////////////////////////////
// Me2Me host state.
+
+ // Platform-specific installation & configuration implementation.
scoped_ptr<DaemonController> daemon_controller_;
// TODO(sergeyu): Replace this thread with
@@ -352,6 +290,13 @@ class HostNPScriptObject : public HostStatusObserver {
// on MessageLoopProxy::current().
base::Thread worker_thread_;
+ //////////////////////////////////////////////////////////
+ // Plugin state used for both Ir2Me and Me2Me.
+
+ // Used to cancel pending tasks for this object when it is destroyed.
+ base::WeakPtrFactory<HostNPScriptObject> weak_factory_;
+ base::WeakPtr<HostNPScriptObject> weak_ptr_;
+
DISALLOW_COPY_AND_ASSIGN(HostNPScriptObject);
};