summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-17 00:33:46 +0000
committerhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-17 00:33:46 +0000
commitc41b2ecfcdc90b29ffc7b45e77a8fc68d269030c (patch)
treea9b8ea900db3a3181f403b4ad27ecfa3d9ce8b6a /chrome
parent9808e2f0f1e5b8b9c1798912ab1ae9a239426c92 (diff)
downloadchromium_src-c41b2ecfcdc90b29ffc7b45e77a8fc68d269030c.zip
chromium_src-c41b2ecfcdc90b29ffc7b45e77a8fc68d269030c.tar.gz
chromium_src-c41b2ecfcdc90b29ffc7b45e77a8fc68d269030c.tar.bz2
Gaia authentication for access remoting directory and talk
We are now able to access remoting directory token and talk token through the chromoting setup dialog. These information are sent to the service process for enabling the chromoting host and perform the host registration. All the plumbing for starting the service process, enabling the chromoting host through through IPC commands are in place but host registration is stubbed out and will be completed in next patch. Review URL: http://codereview.chromium.org/3176014 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@56278 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/remoting/remoting_setup_flow.cc103
-rw-r--r--chrome/browser/remoting/remoting_setup_flow.h37
-rw-r--r--chrome/browser/service/service_process_control.cc9
-rw-r--r--chrome/browser/service/service_process_control.h6
-rw-r--r--chrome/chrome.gyp2
-rw-r--r--chrome/common/net/gaia/gaia_constants.cc2
-rw-r--r--chrome/common/net/gaia/gaia_constants.h1
-rw-r--r--chrome/common/service_messages_internal.h7
-rw-r--r--chrome/service/remoting/remoting_directory_service.cc31
-rw-r--r--chrome/service/remoting/remoting_directory_service.h58
-rw-r--r--chrome/service/service_ipc_server.cc12
-rw-r--r--chrome/service/service_ipc_server.h4
-rw-r--r--chrome/service/service_process.cc24
-rw-r--r--chrome/service/service_process.h16
14 files changed, 292 insertions, 20 deletions
diff --git a/chrome/browser/remoting/remoting_setup_flow.cc b/chrome/browser/remoting/remoting_setup_flow.cc
index c9aa2b3..ce5574e 100644
--- a/chrome/browser/remoting/remoting_setup_flow.cc
+++ b/chrome/browser/remoting/remoting_setup_flow.cc
@@ -20,7 +20,12 @@
#include "chrome/browser/profile.h"
#include "chrome/browser/remoting/remoting_resources_source.h"
#include "chrome/browser/remoting/remoting_setup_message_handler.h"
+#include "chrome/browser/service/service_process_control.h"
+#include "chrome/browser/service/service_process_control_manager.h"
+#include "chrome/common/net/gaia/gaia_authenticator2.h"
+#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/pref_names.h"
+#include "chrome/common/service_process_type.h"
#include "gfx/font.h"
#include "grit/locale_settings.h"
@@ -28,7 +33,8 @@
RemotingSetupFlow::RemotingSetupFlow(const std::string& args, Profile* profile)
: message_handler_(NULL),
dialog_start_args_(args),
- profile_(profile) {
+ profile_(profile),
+ process_control_(NULL) {
// TODO(hclam): We are currently leaking this objcet. Need to fix this!
message_handler_ = new RemotingSetupMessageHandler(this);
ChromeThread::PostTask(
@@ -56,6 +62,9 @@ void RemotingSetupFlow::GetDialogSize(gfx::Size* size) const {
// A callback to notify the delegate that the dialog closed.
void RemotingSetupFlow::OnDialogClosed(const std::string& json_retval) {
+ // If we are fetching the token then cancel the request.
+ if (authenticator_.get())
+ authenticator_->CancelRequest();
delete this;
}
@@ -81,21 +90,84 @@ void RemotingSetupFlow::Focus() {
void RemotingSetupFlow::OnUserSubmittedAuth(const std::string& user,
const std::string& password,
const std::string& captcha) {
- // TODO(hclam): Should do the following two things.
- // 1. Authenicate using the info.
- // 2. Register the host service.
+ // Save the login name only.
+ login_ = user;
+
+ // Start the authenticator.
+ authenticator_.reset(
+ new GaiaAuthenticator2(this, GaiaConstants::kChromeSource,
+ profile_->GetRequestContext()));
+ authenticator_->StartClientLogin(user, password,
+ GaiaConstants::kRemotingService,
+ "", captcha);
+}
+
+void RemotingSetupFlow::OnClientLoginFailure(
+ const GaiaAuthConsumer::GaiaAuthError& error) {
+ message_handler_->ShowGaiaFailed();
+ authenticator_.reset();
+}
+
+void RemotingSetupFlow::OnClientLoginSuccess(
+ const GaiaAuthConsumer::ClientLoginResult& credentials) {
+ // Save the token for remoting.
+ remoting_token_ = credentials.token;
+
+ // After login has succeeded try to fetch the token for sync.
+ // We need the token for sync to connect to the talk network.
+ authenticator_->StartIssueAuthToken(credentials.sid, credentials.lsid,
+ GaiaConstants::kSyncService);
+}
+
+void RemotingSetupFlow::OnIssueAuthTokenSuccess(const std::string& service,
+ const std::string& auth_token) {
+ // Show that Gaia login has succeeded.
message_handler_->ShowGaiaSuccessAndSettingUp();
- // TODO(hclam): This is very unsafe because |message_handler_| is not
- // refcounted. Destruction of the handler before the timeout will cause
- // memory error.
- // This services as a demo to show that we can do authenication asynchronously
- // and setting up stuff and then present the done page later.
- ChromeThread::PostDelayedTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(message_handler_,
- &RemotingSetupMessageHandler::ShowSetupDone),
- 2000);
+ // Save the sync token.
+ sync_token_ = auth_token;
+ authenticator_.reset();
+
+ // And then launch the service process if it has not started yet.
+ // If we have already connected to the service process then submit the tokens
+ // to it to register the host.
+ process_control_ =
+ ServiceProcessControlManager::instance()->GetProcessControl(
+ profile_,
+ kServiceProcessRemoting);
+
+ if (process_control_->is_connected()) {
+ OnProcessLaunched();
+ } else {
+ // TODO(hclam): This is really messed up because I totally ignore the
+ // lifetime of this object. I need a master cleanup on the lifetime of
+ // objects.
+ // TODO(hclam): This call only works on Windows. I need to make it work
+ // on other platforms.
+ process_control_->Launch(
+ NewRunnableMethod(this, &RemotingSetupFlow::OnProcessLaunched));
+ }
+}
+
+void RemotingSetupFlow::OnIssueAuthTokenFailure(const std::string& service,
+ const GaiaAuthError& error) {
+ // TODO(hclam): Do something to show the error.
+ authenticator_.reset();
+}
+
+void RemotingSetupFlow::OnProcessLaunched() {
+ if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ ChromeThread::PostTask(
+ ChromeThread::UI,
+ FROM_HERE,
+ NewRunnableMethod(this, &RemotingSetupFlow::OnProcessLaunched));
+ return;
+ }
+
+ DCHECK(process_control_->is_connected());
+ process_control_->EnableRemotingWithTokens(login_, remoting_token_,
+ sync_token_);
+ message_handler_->ShowSetupDone();
}
// static
@@ -122,4 +194,7 @@ void OpenRemotingSetupDialog(Profile* profile) {
RemotingSetupFlow::Run(profile->GetOriginalProfile());
}
+// TODO(hclam): Need to refcount RemotingSetupFlow. I need to lifetime of
+// objects are all correct.
+DISABLE_RUNNABLE_METHOD_REFCOUNT(RemotingSetupFlow);
DISABLE_RUNNABLE_METHOD_REFCOUNT(RemotingSetupMessageHandler);
diff --git a/chrome/browser/remoting/remoting_setup_flow.h b/chrome/browser/remoting/remoting_setup_flow.h
index 5d7ec15..91912e8 100644
--- a/chrome/browser/remoting/remoting_setup_flow.h
+++ b/chrome/browser/remoting/remoting_setup_flow.h
@@ -11,13 +11,18 @@
#include "app/l10n_util.h"
#include "base/time.h"
#include "chrome/browser/dom_ui/html_dialog_ui.h"
+#include "chrome/common/net/gaia/gaia_auth_consumer.h"
+#include "chrome/common/net/gaia/gaia_authenticator2.h"
#include "gfx/native_widget_types.h"
#include "grit/generated_resources.h"
+class GaiaAuthenticator2;
class RemotingSetupMessageHandler;
+class ServiceProcessControl;
// The state machine used by Remoting for setup wizard.
-class RemotingSetupFlow : public HtmlDialogUIDelegate {
+class RemotingSetupFlow : public HtmlDialogUIDelegate,
+ public GaiaAuthConsumer {
public:
virtual ~RemotingSetupFlow();
@@ -63,17 +68,43 @@ class RemotingSetupFlow : public HtmlDialogUIDelegate {
return true;
}
- void OnUserSubmittedAuth(const std::string& user, const std::string& password,
+ // GaiaAuthConsumer implementation.
+ virtual void OnClientLoginFailure(
+ const GaiaAuthConsumer::GaiaAuthError& error);
+ virtual void OnClientLoginSuccess(
+ const GaiaAuthConsumer::ClientLoginResult& credentials);
+ virtual void OnIssueAuthTokenSuccess(const std::string& service,
+ const std::string& auth_token);
+ virtual void OnIssueAuthTokenFailure(const std::string& service,
+ const GaiaAuthError& error);
+
+ // Called by RemotingSetupMessageHandler.
+ void OnUserSubmittedAuth(const std::string& user,
+ const std::string& password,
const std::string& captcha);
private:
// Use static Run method to get an instance.
RemotingSetupFlow(const std::string& args, Profile* profile);
+ // Event triggered when the service process was launched.
+ void OnProcessLaunched();
+
RemotingSetupMessageHandler* message_handler_;
- std::string dialog_start_args_; // The args to pass to the initial page.
+
+ // The args to pass to the initial page.
+ std::string dialog_start_args_;
Profile* profile_;
+ // Fetcher to obtain the Chromoting Directory token.
+ scoped_ptr<GaiaAuthenticator2> authenticator_;
+ std::string login_;
+ std::string remoting_token_;
+ std::string sync_token_;
+
+ // Handle to the ServiceProcessControl which talks to the service process.
+ ServiceProcessControl* process_control_;
+
DISALLOW_COPY_AND_ASSIGN(RemotingSetupFlow);
};
diff --git a/chrome/browser/service/service_process_control.cc b/chrome/browser/service/service_process_control.cc
index 6cf649b..9b76dc7 100644
--- a/chrome/browser/service/service_process_control.cc
+++ b/chrome/browser/service/service_process_control.cc
@@ -209,4 +209,13 @@ bool ServiceProcessControl::Shutdown() {
return ret;
}
+bool ServiceProcessControl::EnableRemotingWithTokens(
+ const std::string& user,
+ const std::string& remoting_token,
+ const std::string& talk_token) {
+ return Send(
+ new ServiceMsg_EnableRemotingWithTokens(user, remoting_token,
+ talk_token));
+}
+
DISABLE_RUNNABLE_METHOD_REFCOUNT(ServiceProcessControl);
diff --git a/chrome/browser/service/service_process_control.h b/chrome/browser/service/service_process_control.h
index 469b17d..2577ec6 100644
--- a/chrome/browser/service/service_process_control.h
+++ b/chrome/browser/service/service_process_control.h
@@ -81,6 +81,12 @@ class ServiceProcessControl : public IPC::Channel::Sender,
// Return true if the message was sent.
bool Shutdown();
+ // Send a message to enable the remoting service in the service process.
+ // Return true if the message was sent.
+ bool EnableRemotingWithTokens(const std::string& user,
+ const std::string& remoting_token,
+ const std::string& talk_token);
+
// Set the message handler for receiving messages from the service process.
// TODO(hclam): Allow more than 1 handler.
void SetMessageHandler(MessageHandler* message_handler) {
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index c2aeb1d..ec82bf3 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -1101,6 +1101,8 @@
'service/gaia/service_gaia_authenticator.h',
'service/net/service_url_request_context.cc',
'service/net/service_url_request_context.h',
+ 'service/remoting/remoting_directory_service.cc',
+ 'service/remoting/remoting_directory_service.h',
],
'include_dirs': [
'..',
diff --git a/chrome/common/net/gaia/gaia_constants.cc b/chrome/common/net/gaia/gaia_constants.cc
index dcd32aa..60f7fbb 100644
--- a/chrome/common/net/gaia/gaia_constants.cc
+++ b/chrome/common/net/gaia/gaia_constants.cc
@@ -18,5 +18,7 @@ const char kContactsService[] = "cp";
const char kSyncService[] = "chromiumsync";
// Service name for XMPP Google Talk.
const char kTalkService[] = "talk";
+// Service name for remoting.
+const char kRemotingService[] = "chromoting";
} // namespace GaiaConstants
diff --git a/chrome/common/net/gaia/gaia_constants.h b/chrome/common/net/gaia/gaia_constants.h
index 45ac3c8..3daf858 100644
--- a/chrome/common/net/gaia/gaia_constants.h
+++ b/chrome/common/net/gaia/gaia_constants.h
@@ -17,6 +17,7 @@ extern const char kChromeSource[];
extern const char kContactsService[];
extern const char kTalkService[];
extern const char kSyncService[];
+extern const char kRemotingService[];
} // namespace GaiaConstants
diff --git a/chrome/common/service_messages_internal.h b/chrome/common/service_messages_internal.h
index 99d1dd8..538cf73 100644
--- a/chrome/common/service_messages_internal.h
+++ b/chrome/common/service_messages_internal.h
@@ -32,6 +32,12 @@ IPC_BEGIN_MESSAGES(Service)
// This message is for testing purpose.
IPC_MESSAGE_CONTROL0(ServiceMsg_Hello)
+ // This message is for enabling the remoting process.
+ IPC_MESSAGE_CONTROL3(ServiceMsg_EnableRemotingWithTokens,
+ std::string, /* username */
+ std::string, /* Token for remoting */
+ std::string /* Token for Google Talk */)
+
// Tell the service process to shutdown.
IPC_MESSAGE_CONTROL0(ServiceMsg_Shutdown)
@@ -49,4 +55,3 @@ IPC_BEGIN_MESSAGES(ServiceHost)
IPC_MESSAGE_CONTROL0(ServiceHostMsg_GoodDay)
IPC_END_MESSAGES(ServiceHost)
-
diff --git a/chrome/service/remoting/remoting_directory_service.cc b/chrome/service/remoting/remoting_directory_service.cc
new file mode 100644
index 0000000..a213717
--- /dev/null
+++ b/chrome/service/remoting/remoting_directory_service.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/service/remoting/remoting_directory_service.h"
+
+RemotingDirectoryService::RemotingDirectoryService(Client* client)
+ : client_(client) {
+}
+
+RemotingDirectoryService::~RemotingDirectoryService() {
+ // TODO(hclam): Implement.
+}
+
+void RemotingDirectoryService::AddHost(const std::string& token) {
+ // TODO(hclam): Implement.
+}
+
+void RemotingDirectoryService::CancelRequest() {
+ // TODO(hclam): Implement.
+}
+
+void RemotingDirectoryService::OnURLFetchComplete(
+ const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data) {
+ // TODO(hclam): Implement.
+}
diff --git a/chrome/service/remoting/remoting_directory_service.h b/chrome/service/remoting/remoting_directory_service.h
new file mode 100644
index 0000000..3fcd865
--- /dev/null
+++ b/chrome/service/remoting/remoting_directory_service.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2010 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.
+
+#ifndef CHROME_SERVICE_REMOTING_REMOTING_DIRECTORY_SERVICE_H_
+#define CHROME_SERVICE_REMOTING_REMOTING_DIRECTORY_SERVICE_H_
+
+#include <string>
+
+#include "base/scoped_ptr.h"
+#include "chrome/common/net/url_fetcher.h"
+#include "googleurl/src/gurl.h"
+
+// A class to provide access to the remoting directory service.
+// TODO(hclam): Should implement this in Javascript.
+class RemotingDirectoryService : public URLFetcher::Delegate {
+ public:
+ // Client to receive events from the directory service.
+ class Client {
+ public:
+ virtual ~Client() {}
+
+ // Called when a remoting host was added.
+ virtual void OnRemotingHostAdded() {}
+
+ // Called when the last operation has failed.
+ virtual void OnRemotingDirectoryError() {}
+ };
+
+ RemotingDirectoryService(Client* client);
+ ~RemotingDirectoryService();
+
+ // Add this computer as host. Use the token for authentication.
+ // TODO(hclam): Need more information for this method call.
+ void AddHost(const std::string& token);
+
+ // Cancel the last requested operation.
+ void CancelRequest();
+
+ // URLFetcher::Delegate implementation.
+ virtual void OnURLFetchComplete(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
+
+ private:
+ Client* client_;
+ scoped_ptr<URLFetcher> fetcher_;
+
+ // True if a URL request has made and response is pending.
+ bool request_pending_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemotingDirectoryService);
+};
+
+#endif // CHROME_SERVICE_REMOTING_REMOTING_DIRECTORY_SERVICE_H_
diff --git a/chrome/service/service_ipc_server.cc b/chrome/service/service_ipc_server.cc
index 116374f..1a698b4 100644
--- a/chrome/service/service_ipc_server.cc
+++ b/chrome/service/service_ipc_server.cc
@@ -64,6 +64,8 @@ void ServiceIPCServer::OnMessageReceived(const IPC::Message& msg) {
OnEnableCloudPrintProxy)
IPC_MESSAGE_HANDLER(ServiceMsg_EnableCloudPrintProxyWithTokens,
OnEnableCloudPrintProxyWithTokens)
+ IPC_MESSAGE_HANDLER(ServiceMsg_EnableRemotingWithTokens,
+ OnEnableRemotingWithTokens)
IPC_MESSAGE_HANDLER(ServiceMsg_DisableCloudPrintProxy,
OnDisableCloudPrintProxy)
IPC_MESSAGE_HANDLER(ServiceMsg_Hello, OnHello);
@@ -81,6 +83,16 @@ void ServiceIPCServer::OnEnableCloudPrintProxyWithTokens(
NOTIMPLEMENTED();
}
+void ServiceIPCServer::OnEnableRemotingWithTokens(
+ const std::string& login,
+ const std::string& remoting_token,
+ const std::string& talk_token) {
+#if defined(ENABLE_REMOTING)
+ g_service_process->EnableChromotingHostWithTokens(login, remoting_token,
+ talk_token);
+#endif
+}
+
void ServiceIPCServer::OnDisableCloudPrintProxy() {
g_service_process->GetCloudPrintProxy()->DisableForUser();
}
diff --git a/chrome/service/service_ipc_server.h b/chrome/service/service_ipc_server.h
index 521830e..2e8d437 100644
--- a/chrome/service/service_ipc_server.h
+++ b/chrome/service/service_ipc_server.h
@@ -40,6 +40,9 @@ class ServiceIPCServer : public IPC::Channel::Listener,
void OnEnableCloudPrintProxy(const std::string& lsid);
void OnEnableCloudPrintProxyWithTokens(const std::string& cloud_print_token,
const std::string& talk_token);
+ void OnEnableRemotingWithTokens(const std::string& login,
+ const std::string& remoting_token,
+ const std::string& talk_token);
void OnDisableCloudPrintProxy();
void OnHello();
void OnShutdown();
@@ -55,4 +58,3 @@ class ServiceIPCServer : public IPC::Channel::Listener,
};
#endif // CHROME_SERVICE_SERVICE_IPC_SERVER_H_
-
diff --git a/chrome/service/service_process.cc b/chrome/service/service_process.cc
index 77e8cf0..9e5da1a 100644
--- a/chrome/service/service_process.cc
+++ b/chrome/service/service_process.cc
@@ -122,6 +122,17 @@ CloudPrintProxy* ServiceProcess::GetCloudPrintProxy() {
}
#if defined(ENABLE_REMOTING)
+bool ServiceProcess::EnableChromotingHostWithTokens(
+ const std::string& login,
+ const std::string& remoting_token,
+ const std::string& talk_token) {
+ remoting_directory_.reset(new RemotingDirectoryService(this));
+
+ // TODO(hclam): Complete the API calling to the remoting directory.
+ remoting_directory_->AddHost(remoting_token);
+ return true;
+}
+
bool ServiceProcess::StartChromotingHost() {
// We have already started.
if (chromoting_context_.get())
@@ -180,6 +191,19 @@ bool ServiceProcess::ShutdownChromotingHost() {
return true;
}
+void ServiceProcess::OnRemotingHostAdded() {
+ // TODO(hclam): Need to save the keys and configuration here.
+ // TODO(hclam): If we have a problem we need to send an IPC message back
+ // to the client that started this.
+ bool ret = StartChromotingHost();
+ DCHECK(ret);
+}
+
+void ServiceProcess::OnRemotingDirectoryError() {
+ // TODO(hclam): Implement.
+ NOTIMPLEMENTED() << "Remoting directory error";
+}
+
// A util function to update the login information to host config.
static void SaveChromotingConfigFunc(remoting::JsonHostConfig* config,
const std::string& login,
diff --git a/chrome/service/service_process.h b/chrome/service/service_process.h
index 55c7c19..2facdda 100644
--- a/chrome/service/service_process.h
+++ b/chrome/service/service_process.h
@@ -11,10 +11,12 @@
#include "base/scoped_ptr.h"
#include "base/thread.h"
#include "base/waitable_event.h"
+#include "chrome/service/remoting/remoting_directory_service.h"
class CloudPrintProxy;
class JsonPrefStore;
class ServiceIPCServer;
+
namespace net {
class NetworkChangeNotifier;
}
@@ -27,7 +29,7 @@ class JsonHostConfig;
// The ServiceProcess does not inherit from ChildProcess because this
// process can live independently of the browser process.
-class ServiceProcess {
+class ServiceProcess : public RemotingDirectoryService::Client {
public:
ServiceProcess();
~ServiceProcess();
@@ -74,6 +76,12 @@ class ServiceProcess {
// Return the reference to the chromoting host only if it has started.
remoting::ChromotingHost* GetChromotingHost() { return chromoting_host_; }
+ // Enable chromoting host with the tokens.
+ // Return true if successful.
+ bool EnableChromotingHostWithTokens(const std::string& login,
+ const std::string& remoting_token,
+ const std::string& talk_token);
+
// Start running the chromoting host asynchronously.
// Return true if chromoting host has started.
bool StartChromotingHost();
@@ -81,6 +89,10 @@ class ServiceProcess {
// Shutdown chromoting host. Return true if chromoting host was shutdown.
// The shutdown process will happen asynchronously.
bool ShutdownChromotingHost();
+
+ // RemotingDirectoryService::Client implementation.
+ virtual void OnRemotingHostAdded();
+ virtual void OnRemotingDirectoryError();
#endif
private:
@@ -115,7 +127,9 @@ class ServiceProcess {
scoped_refptr<remoting::JsonHostConfig> chromoting_config_;
scoped_ptr<remoting::ChromotingHostContext> chromoting_context_;
scoped_refptr<remoting::ChromotingHost> chromoting_host_;
+ scoped_ptr<RemotingDirectoryService> remoting_directory_;
#endif
+
// An event that will be signalled when we shutdown.
base::WaitableEvent shutdown_event_;