Index: chrome/browser/extensions/api/networking_private/networking_private_process_client.cc |
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_process_client.cc b/chrome/browser/extensions/api/networking_private/networking_private_process_client.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6afe60de14657fe2a102c76b064b9511f4cd9250 |
--- /dev/null |
+++ b/chrome/browser/extensions/api/networking_private/networking_private_process_client.cc |
@@ -0,0 +1,458 @@ |
+// Copyright 2013 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/browser/extensions/api/networking_private/networking_private_process_client.h" |
+ |
+#include "base/base64.h" |
+#include "base/bind.h" |
+#include "base/strings/string_number_conversions.h" |
+#include "base/threading/worker_pool.h" |
+#include "chrome/browser/browser_process.h" |
+#include "chrome/browser/extensions/api/networking_private/networking_private_crypto.h" |
+#include "chrome/browser/profiles/profile.h" |
+#include "chrome/common/extensions/api/networking_private.h" |
+#include "chrome/common/networking_private_messages.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "content/public/browser/utility_process_host.h" |
+ |
+using content::BrowserThread; |
+using content::UtilityProcessHost; |
+using extensions::api::networking_private::VerificationProperties; |
+ |
+namespace extensions { |
+ |
+namespace { |
+// Implementation of Verify* methods using NetworkingPrivateCrypto. |
+// TODO(mef): Move this into NetworkingPrivateCrypto class. |
+class CryptoVerifyImpl : public NetworkingPrivateProcessClient::CryptoVerify { |
+ virtual bool VerifyDestination( |
+ const VerificationProperties& properties) OVERRIDE { |
+ std::vector<std::string> data_parts; |
+ data_parts.push_back(properties.device_ssid); |
+ data_parts.push_back(properties.device_serial); |
+ data_parts.push_back(properties.device_bssid); |
+ data_parts.push_back(properties.public_key); |
+ data_parts.push_back(properties.nonce); |
+ std::string unsigned_data = JoinString(data_parts, ","); |
+ std::string signed_data; |
+ if (!base::Base64Decode(properties.signed_data, &signed_data)) |
+ return false; |
+ NetworkingPrivateCrypto crypto; |
+ return crypto.VerifyCredentials(properties.certificate, |
+ signed_data, |
+ unsigned_data, |
+ properties.device_bssid); |
+ } |
+ |
+ virtual bool VerifyAndEncryptData(const VerificationProperties& properties, |
+ const std::string& plaintext, |
+ std::string* base64_ciphertext) OVERRIDE { |
+ if (!VerifyDestination(properties)) |
+ return false; |
+ |
+ std::string public_key; |
+ if (!base::Base64Decode(properties.public_key, &public_key)) |
+ return false; |
+ |
+ NetworkingPrivateCrypto crypto; |
+ std::string ciphertext; |
+ if (!crypto.EncryptByteString(public_key, plaintext, &ciphertext)) |
+ return false; |
+ |
+ return base::Base64Encode(ciphertext, base64_ciphertext); |
+ } |
+}; |
+ |
+const char kNetworkingPrivateProcessClient[] = "NetworkingPrivateProcessClient"; |
+ |
+} // namespace |
+ |
+scoped_refptr<NetworkingPrivateProcessClient> |
+NetworkingPrivateProcessClient::GetForProfile(Profile* profile) { |
+ profile = profile->GetOriginalProfile(); |
+ if (!profile->GetUserData(kNetworkingPrivateProcessClient)) { |
+ NetworkingPrivateProcessClient* client = |
+ new NetworkingPrivateProcessClient(profile); |
+ profile->SetUserData( |
+ kNetworkingPrivateProcessClient, |
+ new base::UserDataAdapter<NetworkingPrivateProcessClient>(client)); |
+ client->Start(); |
+ } |
+ |
+ return scoped_refptr<NetworkingPrivateProcessClient>( |
+ base::UserDataAdapter<NetworkingPrivateProcessClient>::Get( |
+ profile, kNetworkingPrivateProcessClient)); |
+} |
+ |
+NetworkingPrivateProcessClient::NetworkingPrivateProcessClient(Profile* profile) |
+ : profile_(profile), |
+ crypto_verify_(new CryptoVerifyImpl()) {} |
+ |
+NetworkingPrivateProcessClient::~NetworkingPrivateProcessClient() { |
+ // TODO(mef): |message_callbacks_| should be cleared on UI thread prior to |
+ // destruction, for example from NetworkingPrivateEventRouterImpl::Shutdown(). |
+} |
+ |
+NetworkingPrivateProcessClient::MessageCallbacks::MessageCallbacks() {} |
+ |
+NetworkingPrivateProcessClient::MessageCallbacks::~MessageCallbacks() {} |
+ |
+void NetworkingPrivateProcessClient::Start() { |
+ BrowserThread::ID thread_id; |
+ CHECK(BrowserThread::GetCurrentThreadIdentifier(&thread_id)); |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, |
+ FROM_HERE, |
+ base::Bind(&NetworkingPrivateProcessClient::StartProcessOnIOThread, |
+ this, |
+ thread_id)); |
+} |
+ |
+void NetworkingPrivateProcessClient::StartProcessOnIOThread( |
+ BrowserThread::ID thread_id) { |
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ utility_process_host_ = UtilityProcessHost::Create( |
+ this, BrowserThread::GetMessageLoopProxyForThread(thread_id).get()) |
+ ->AsWeakPtr(); |
+ utility_process_host_->DisableSandbox(); |
+ utility_process_host_->StartBatchMode(); |
+} |
+ |
+void NetworkingPrivateProcessClient::AddObserver(Observer* observer) { |
+ network_events_observers_.AddObserver(observer); |
+} |
+ |
+void NetworkingPrivateProcessClient::RemoveObserver(Observer* observer) { |
+ network_events_observers_.RemoveObserver(observer); |
+ // Shutdown will occur when all remaining calls are completed. |
+ ShutdownIfDone(); |
+} |
+ |
+void NetworkingPrivateProcessClient::ShutdownIfDone() { |
+ if (!network_events_observers_.might_have_observers() && |
+ callbacks_map_.IsEmpty()) { |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, |
+ FROM_HERE, |
+ base::Bind(&NetworkingPrivateProcessClient::ShutdownProcessOnIOThread, |
+ this)); |
+ // Remove current process client from profile, so new API calls would launch |
+ // new process. |
+ profile_->RemoveUserData(kNetworkingPrivateProcessClient); |
+ } |
+} |
+ |
+void NetworkingPrivateProcessClient::ShutdownProcessOnIOThread() { |
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ |
+ // The utility_process_host_ will take care of deleting itself. |
+ if (utility_process_host_.get()) { |
+ utility_process_host_->EndBatchMode(); |
+ utility_process_host_.reset(); |
+ } |
+} |
+ |
+void NetworkingPrivateProcessClient::Send(IPC::Message* message) { |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, |
+ FROM_HERE, |
+ base::Bind( |
+ &NetworkingPrivateProcessClient::SendOnIOThread, this, message)); |
+} |
+ |
+void NetworkingPrivateProcessClient::SendOnIOThread(IPC::Message* message) { |
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ if (utility_process_host_.get()) |
+ utility_process_host_->Send(message); |
+} |
+ |
+void NetworkingPrivateProcessClient::OnProcessCrashed(int exit_code) { |
+ std::string error_code("UtilityProcessCrashed"); |
+ // Report error for all pending callbacks |
+ for (IDMap<MessageCallbacks, IDMapOwnPointer>::iterator iter(&callbacks_map_); |
+ !iter.IsAtEnd(); |
+ iter.Advance()) { |
+ if (!iter.GetCurrentValue()->error_callback.is_null()) { |
+ scoped_ptr<DictionaryValue> error_data_ptr(new DictionaryValue()); |
+ iter.GetCurrentValue()->error_callback.Run(error_code, |
+ error_data_ptr.Pass()); |
+ } |
+ } |
+ callbacks_map_.Clear(); |
+ if (network_events_observers_.might_have_observers()) { |
+ // Restart the utility process. |
+ Start(); |
+ } else { |
+ ShutdownIfDone(); |
+ } |
+} |
+ |
+bool NetworkingPrivateProcessClient::OnMessageReceived( |
+ const IPC::Message& message) { |
+ bool handled = true; |
+ IPC_BEGIN_MESSAGE_MAP(NetworkingPrivateProcessClient, message) |
+ // Responses from NetworkingPrivateHandler. |
+ IPC_MESSAGE_HANDLER(NetworkingPrivateMsg_API_Error, OnApiError) |
+ IPC_MESSAGE_HANDLER(NetworkingPrivateMsg_GetProperties_Succeeded, |
+ OnGetPropertiesSucceeded) |
+ IPC_MESSAGE_HANDLER(NetworkingPrivateMsg_StartConnect_Succeeded, |
+ OnStartConnectSucceeded) |
+ IPC_MESSAGE_HANDLER(NetworkingPrivateMsg_StartDisconnect_Succeeded, |
+ OnStartDisconnectSucceeded) |
+ IPC_MESSAGE_HANDLER(NetworkingPrivateMsg_SetProperties_Succeeded, |
+ OnSetPropertiesSucceeded) |
+ IPC_MESSAGE_HANDLER(NetworkingPrivateMsg_GetVisibleNetworksSucceeded, |
+ OnGetVisibleNetworksSucceeded) |
+ IPC_MESSAGE_HANDLER(NetworkingPrivateMsg_NetworksChanged_Event, |
+ OnNetworksChangedEvent) |
+ IPC_MESSAGE_HANDLER(NetworkingPrivateMsg_NetworkListChanged_Event, |
+ OnNetworkListChangedEvent) |
+ IPC_MESSAGE_UNHANDLED(handled = false) |
+ IPC_END_MESSAGE_MAP() |
+ return handled; |
+} |
+ |
+void NetworkingPrivateProcessClient::GetProperties( |
+ const std::string& service_path, |
+ const DictionaryResultCallback& callback, |
+ const ErrorCallback& error_callback) { |
+ MessageCallbacks* message_callbacks = AddMessageCallbacks(); |
+ message_callbacks->error_callback = error_callback; |
+ message_callbacks->get_properties_callback = callback; |
+ |
+ Send(new NetworkingPrivateMsg_GetProperties(message_callbacks->id, |
+ service_path)); |
+} |
+ |
+void NetworkingPrivateProcessClient::GetVisibleNetworks( |
+ const ListResultCallback& callback) { |
+ MessageCallbacks* message_callbacks = AddMessageCallbacks(); |
+ message_callbacks->get_visible_networks_callback = callback; |
+ |
+ Send(new NetworkingPrivateMsg_GetVisibleNetworks(message_callbacks->id)); |
+} |
+ |
+// Requests network scan. Broadcasts NetworkListChangedEvent upon completion. |
+void NetworkingPrivateProcessClient::RequestNetworkScan() { |
+ Send(new NetworkingPrivateMsg_RequestNetworkScan()); |
+} |
+ |
+void NetworkingPrivateProcessClient::SetProperties( |
+ const std::string& service_path, |
+ const base::DictionaryValue& properties, |
+ const VoidResultCallback& callback, |
+ const ErrorCallback& error_callback) { |
+ MessageCallbacks* message_callbacks = AddMessageCallbacks(); |
+ message_callbacks->error_callback = error_callback; |
+ message_callbacks->set_properties_callback = callback; |
+ |
+ scoped_ptr<DictionaryValue> properties_ptr(properties.DeepCopy()); |
+ Send(new NetworkingPrivateMsg_SetProperties( |
+ message_callbacks->id, service_path, *properties_ptr)); |
+} |
+ |
+void NetworkingPrivateProcessClient::StartConnect( |
+ const std::string& service_path, |
+ const VoidResultCallback& callback, |
+ const ErrorCallback& error_callback) { |
+ MessageCallbacks* message_callbacks = AddMessageCallbacks(); |
+ message_callbacks->error_callback = error_callback; |
+ message_callbacks->start_connect_callback = callback; |
+ |
+ Send(new NetworkingPrivateMsg_StartConnect(message_callbacks->id, |
+ service_path)); |
+} |
+ |
+void NetworkingPrivateProcessClient::StartDisconnect( |
+ const std::string& service_path, |
+ const VoidResultCallback& callback, |
+ const ErrorCallback& error_callback) { |
+ MessageCallbacks* message_callbacks = AddMessageCallbacks(); |
+ message_callbacks->error_callback = error_callback; |
+ message_callbacks->start_disconnect_callback = callback; |
+ |
+ Send(new NetworkingPrivateMsg_StartDisconnect(message_callbacks->id, |
+ service_path)); |
+} |
+ |
+void NetworkingPrivateProcessClient::VerifyDestination( |
+ scoped_ptr<base::ListValue> args, |
+ const BoolResultCallback& callback, |
+ const CryptoErrorCallback& error_callback) { |
+ base::WorkerPool::PostTask( |
+ FROM_HERE, |
+ base::Bind( |
+ &NetworkingPrivateProcessClient::VerifyDestinationOnWorkerThread, |
+ this, |
+ Passed(&args), |
+ callback, |
+ error_callback), |
+ false); |
+} |
+ |
+void NetworkingPrivateProcessClient::VerifyDestinationOnWorkerThread( |
+ scoped_ptr<base::ListValue> args, |
+ const BoolResultCallback& callback, |
+ const CryptoErrorCallback& error_callback) { |
+ using extensions::api::networking_private::VerifyDestination::Params; |
+ scoped_ptr<Params> params = Params::Create(*args); |
+ bool result = crypto_verify_->VerifyDestination(params->properties); |
+ BrowserThread::PostTask(BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind(callback, result)); |
+} |
+ |
+void NetworkingPrivateProcessClient::VerifyAndEncryptData( |
+ scoped_ptr<base::ListValue> args, |
+ const StringResultCallback& callback, |
+ const CryptoErrorCallback& error_callback) { |
+ base::WorkerPool::PostTask( |
+ FROM_HERE, |
+ base::Bind( |
+ &NetworkingPrivateProcessClient::VerifyAndEncryptDataOnWorkerThread, |
+ this, |
+ Passed(&args), |
+ callback, |
+ error_callback), |
+ false); |
+} |
+ |
+ |
+void NetworkingPrivateProcessClient::VerifyAndEncryptDataOnWorkerThread( |
+ scoped_ptr<base::ListValue> args, |
+ const StringResultCallback& callback, |
+ const CryptoErrorCallback& error_callback) { |
+ using extensions::api::networking_private::VerifyAndEncryptData::Params; |
+ scoped_ptr<Params> params = Params::Create(*args); |
+ std::string encoded_data; |
+ bool verified = crypto_verify_->VerifyAndEncryptData( |
+ params->properties, params->data, &encoded_data); |
+ if (verified) { |
+ BrowserThread::PostTask(BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind(callback, encoded_data)); |
+ } else { |
+ BrowserThread::PostTask(BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind(error_callback, "VerifyError", "Error")); |
+ } |
+} |
+ |
+NetworkingPrivateProcessClient::MessageCallbacks* |
+NetworkingPrivateProcessClient::AddMessageCallbacks() { |
+ MessageCallbacks* message_callbacks = new MessageCallbacks(); |
+ message_callbacks->id = callbacks_map_.Add(message_callbacks); |
+ return message_callbacks; |
+} |
+ |
+void NetworkingPrivateProcessClient::RemoveMessageCallbacks( |
+ MessageCallbacksID message_id) { |
+ callbacks_map_.Remove(message_id); |
+ ShutdownIfDone(); |
+} |
+ |
+void NetworkingPrivateProcessClient::SetUpForTest( |
+ const base::DictionaryValue& parameters, |
+ CryptoVerify* crypto_verify_mock) { |
+ DCHECK(crypto_verify_mock); |
+ crypto_verify_.reset(crypto_verify_mock); |
+ // Prevent shutdown between calls. |
+ AddMessageCallbacks(); |
+ // Pass mock parameters to utility process itself. |
+ scoped_ptr<DictionaryValue> parameters_ptr(parameters.DeepCopy()); |
+ Send(new NetworkingPrivateMsg_SetUpForTest(*parameters_ptr)); |
+} |
+ |
+void NetworkingPrivateProcessClient::TearDownForTest() { |
+ // Remove extra callback added in SetUpForTest to prevent shutdown between |
+ // calls. |
+ callbacks_map_.Clear(); |
+ ShutdownIfDone(); |
+} |
+ |
+// Message handlers |
+void NetworkingPrivateProcessClient::OnApiError( |
+ MessageCallbacksID message_id, |
+ const std::string& error_code, |
+ const base::DictionaryValue& error_data) { |
+ MessageCallbacks* message_callbacks = callbacks_map_.Lookup(message_id); |
+ if (message_callbacks != NULL) { |
+ scoped_ptr<DictionaryValue> error_data_ptr(error_data.DeepCopy()); |
+ if (!message_callbacks->error_callback.is_null()) |
+ message_callbacks->error_callback.Run(error_code, error_data_ptr.Pass()); |
+ RemoveMessageCallbacks(message_id); |
+ } |
+} |
+ |
+void NetworkingPrivateProcessClient::OnGetPropertiesSucceeded( |
+ MessageCallbacksID message_id, |
+ const std::string& network_guid, |
+ const base::DictionaryValue& properties) { |
+ MessageCallbacks* message_callbacks = callbacks_map_.Lookup(message_id); |
+ if (message_callbacks != NULL) { |
+ if (!message_callbacks->get_properties_callback.is_null()) |
+ message_callbacks->get_properties_callback.Run(network_guid, properties); |
+ RemoveMessageCallbacks(message_id); |
+ } |
+} |
+ |
+void NetworkingPrivateProcessClient::OnGetVisibleNetworksSucceeded( |
+ MessageCallbacksID message_id, |
+ const base::ListValue& network_list) { |
+ MessageCallbacks* message_callbacks = callbacks_map_.Lookup(message_id); |
+ if (message_callbacks != NULL) { |
+ if (!message_callbacks->get_visible_networks_callback.is_null()) |
+ message_callbacks->get_visible_networks_callback.Run(network_list); |
+ RemoveMessageCallbacks(message_id); |
+ } |
+} |
+ |
+void NetworkingPrivateProcessClient::OnNetworksChangedEvent( |
+ const std::vector<std::string>& network_guids) { |
+ FOR_EACH_OBSERVER(Observer, |
+ network_events_observers_, |
+ OnNetworksChangedEvent(network_guids)); |
+} |
+ |
+void NetworkingPrivateProcessClient::OnNetworkListChangedEvent( |
+ const std::vector<std::string>& network_guids) { |
+ FOR_EACH_OBSERVER(Observer, |
+ network_events_observers_, |
+ OnNetworkListChangedEvent(network_guids)); |
+} |
+ |
+void NetworkingPrivateProcessClient::OnSetPropertiesSucceeded( |
+ MessageCallbacksID message_id, |
+ const std::string& network_guid) { |
+ MessageCallbacks* message_callbacks = callbacks_map_.Lookup(message_id); |
+ if (message_callbacks != NULL) { |
+ if (!message_callbacks->set_properties_callback.is_null()) |
+ message_callbacks->set_properties_callback.Run(); |
+ RemoveMessageCallbacks(message_id); |
+ } |
+} |
+ |
+void NetworkingPrivateProcessClient::OnStartConnectSucceeded( |
+ MessageCallbacksID message_id, |
+ const std::string& network_guid) { |
+ MessageCallbacks* message_callbacks = callbacks_map_.Lookup(message_id); |
+ if (message_callbacks != NULL) { |
+ if (!message_callbacks->start_connect_callback.is_null()) |
+ message_callbacks->start_connect_callback.Run(); |
+ RemoveMessageCallbacks(message_id); |
+ } |
+} |
+ |
+void NetworkingPrivateProcessClient::OnStartDisconnectSucceeded( |
+ MessageCallbacksID message_id, |
+ const std::string& network_guid) { |
+ MessageCallbacks* message_callbacks = callbacks_map_.Lookup(message_id); |
+ if (message_callbacks != NULL) { |
+ if (!message_callbacks->start_disconnect_callback.is_null()) |
+ message_callbacks->start_disconnect_callback.Run(); |
+ RemoveMessageCallbacks(message_id); |
+ } |
+} |
+ |
+} // namespace extensions |