Chromium Code Reviews| Index: chromeos/network/network_connection_handler.cc |
| diff --git a/chromeos/network/network_connection_handler.cc b/chromeos/network/network_connection_handler.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..80f7fd9e9645f1e70e3c0e8f7036049f5aa6fa6b |
| --- /dev/null |
| +++ b/chromeos/network/network_connection_handler.cc |
| @@ -0,0 +1,294 @@ |
| +// Copyright (c) 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 "chromeos/network/network_connection_handler.h" |
| + |
| +#include "base/bind.h" |
| +#include "base/json/json_reader.h" |
| +#include "chromeos/dbus/dbus_thread_manager.h" |
| +#include "chromeos/dbus/shill_manager_client.h" |
| +#include "chromeos/dbus/shill_service_client.h" |
| +#include "chromeos/network/cert_loader.h" |
| +#include "chromeos/network/certificate_pattern_matcher.h" |
| +#include "chromeos/network/managed_network_configuration_handler.h" |
| +#include "chromeos/network/network_event_log.h" |
| +#include "chromeos/network/network_handler_callbacks.h" |
| +#include "chromeos/network/network_state.h" |
| +#include "chromeos/network/network_state_handler.h" |
| +#include "chromeos/network/network_ui_data.h" |
| +#include "dbus/object_path.h" |
| +#include "net/cert/x509_certificate.h" |
| +#include "third_party/cros_system_api/dbus/service_constants.h" |
| + |
| +namespace chromeos { |
| + |
| +namespace { |
| + |
| +const char kLogModule[] = "NetworkConnectionHandler"; |
| + |
| +void InvokeErrorCallback( |
| + const std::string& service_path, |
| + const network_handler::ErrorCallback& error_callback, |
| + const std::string& error_name) { |
| + network_handler::ShillErrorCallbackFunction( |
| + kLogModule, service_path, error_callback, error_name, "Connect Error"); |
| +} |
| + |
| +bool NetworkMayNeedCredentials(const NetworkState* network) { |
| + if (network->type() == flimflam::kTypeWifi && |
| + (network->security() == flimflam::kSecurity8021x || |
| + network->security() == flimflam::kSecurityWep /* For dynamic WEP*/)) |
| + return true; |
| + if (network->type() == flimflam::kTypeVPN) |
| + return true; |
| + return false; |
| +} |
| + |
| +bool NetworkRequiresActivation(const NetworkState* network) { |
| + return (network->type() == flimflam::kTypeCellular && |
| + (network->activation_state() != flimflam::kActivationStateActivated || |
| + network->cellular_out_of_credits())); |
| +} |
| + |
| +} |
| + |
| +NetworkConnectionHandler* g_connection_handler_instance = NULL; |
|
pneubeck (no reviews)
2013/05/08 08:07:46
static
stevenjb
2013/05/08 18:48:00
Done.
|
| + |
| +const char NetworkConnectionHandler::kNetworkNotFound[] = "not-found"; |
| +const char NetworkConnectionHandler::kConnected[] = "connected"; |
| +const char NetworkConnectionHandler::kConnecting[] = "connecting"; |
| +const char NetworkConnectionHandler::kNotConnected[] = "not-connected"; |
| +const char NetworkConnectionHandler::kPassphraseRequired[] = |
| + "passphrase-required"; |
| +const char NetworkConnectionHandler::kActivationRequired[] = |
| + "activation-required"; |
| +const char NetworkConnectionHandler::kCertificateRequired[] = |
| + "certificate-required"; |
| +const char NetworkConnectionHandler::kConfigurationRequired[] = |
| + "configuration-required"; |
| +const char NetworkConnectionHandler::kShillError[] = "shill-error"; |
| + |
| +// static |
| +void NetworkConnectionHandler::Initialize() { |
| + CHECK(!g_connection_handler_instance); |
| + g_connection_handler_instance = new NetworkConnectionHandler; |
| +} |
| + |
| +// static |
| +void NetworkConnectionHandler::Shutdown() { |
| + CHECK(g_connection_handler_instance); |
| + delete g_connection_handler_instance; |
| + g_connection_handler_instance = NULL; |
| +} |
| + |
| +// static |
| +NetworkConnectionHandler* NetworkConnectionHandler::Get() { |
| + CHECK(g_connection_handler_instance) |
| + << "NetworkConnectionHandler::Get() called before Initialize()"; |
| + return g_connection_handler_instance; |
| +} |
| + |
| +NetworkConnectionHandler::NetworkConnectionHandler() { |
| +} |
| + |
| +NetworkConnectionHandler::~NetworkConnectionHandler() { |
| +} |
| + |
| +void NetworkConnectionHandler::ConnectToNetwork( |
| + const std::string& service_path, |
| + const base::Closure& success_callback, |
| + const network_handler::ErrorCallback& error_callback) { |
| + const NetworkState* network = |
| + NetworkStateHandler::Get()->GetNetworkState(service_path); |
| + if (!network) { |
| + InvokeErrorCallback(service_path, error_callback, kNetworkNotFound); |
| + return; |
| + } |
| + if (network->IsConnectedState()) { |
| + InvokeErrorCallback(service_path, error_callback, kConnected); |
| + return; |
| + } |
| + if (network->IsConnectingState() || |
| + pending_requests_.find(service_path) != pending_requests_.end()) { |
| + InvokeErrorCallback(service_path, error_callback, kConnecting); |
| + return; |
| + } |
| + if (network->passphrase_required()) { |
| + InvokeErrorCallback(service_path, error_callback, kPassphraseRequired); |
| + return; |
| + } |
| + if (NetworkRequiresActivation(network)) { |
| + InvokeErrorCallback(service_path, error_callback, kActivationRequired); |
| + return; |
| + } |
| + |
| + // All synchronous checks passed, add |service_path| to connecting list. |
| + pending_requests_.insert(service_path); |
| + |
| + if (!network->connectable() && NetworkMayNeedCredentials(network)) { |
| + // Request additional properties to check. |
| + ManagedNetworkConfigurationHandler::Get()->GetProperties( |
| + network->path(), |
| + base::Bind(&NetworkConnectionHandler::GetPropertiesCallback, |
| + AsWeakPtr(), success_callback, error_callback), |
| + base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure, |
| + AsWeakPtr(), network->path(), error_callback)); |
| + return; |
| + } |
| + // All checks passed, send connect request. |
| + CallShillConnect(service_path, success_callback, error_callback); |
| +} |
| + |
| +void NetworkConnectionHandler::DisconnectNetwork( |
| + const std::string& service_path, |
| + const base::Closure& success_callback, |
| + const network_handler::ErrorCallback& error_callback) { |
| + const NetworkState* network = |
| + NetworkStateHandler::Get()->GetNetworkState(service_path); |
| + if (!network) { |
| + InvokeErrorCallback(service_path, error_callback, kNetworkNotFound); |
| + return; |
| + } |
| + if (!network->IsConnectedState()) { |
| + InvokeErrorCallback(service_path, error_callback, kNotConnected); |
| + return; |
| + } |
| + CallShillDisconnect(service_path, success_callback, error_callback); |
| +} |
| + |
| +void NetworkConnectionHandler::CallShillConnect( |
| + const std::string& service_path, |
| + const base::Closure& success_callback, |
| + const network_handler::ErrorCallback& error_callback) { |
| + // TODO(stevenjb): Remove SetConnectingNetwork and use this class to maintain |
| + // the connecting network(s) once NetworkLibrary path is eliminated. |
| + NetworkStateHandler::Get()->SetConnectingNetwork(service_path); |
| + network_event_log::AddEntry(kLogModule, "Connect Request", service_path); |
| + DBusThreadManager::Get()->GetShillServiceClient()->Connect( |
| + dbus::ObjectPath(service_path), |
| + base::Bind(&NetworkConnectionHandler::HandleShillSuccess, |
| + AsWeakPtr(), service_path, success_callback), |
| + base::Bind(&NetworkConnectionHandler::HandleShillFailure, |
| + AsWeakPtr(), service_path, error_callback)); |
| +} |
| + |
| +void NetworkConnectionHandler::CallShillDisconnect( |
| + const std::string& service_path, |
| + const base::Closure& success_callback, |
| + const network_handler::ErrorCallback& error_callback) { |
| + network_event_log::AddEntry(kLogModule, "Disconnect Request", service_path); |
| + DBusThreadManager::Get()->GetShillServiceClient()->Disconnect( |
| + dbus::ObjectPath(service_path), |
| + base::Bind(&NetworkConnectionHandler::HandleShillSuccess, |
| + AsWeakPtr(), service_path, success_callback), |
| + base::Bind(&NetworkConnectionHandler::HandleShillFailure, |
| + AsWeakPtr(), service_path, error_callback)); |
| +} |
| + |
| +void NetworkConnectionHandler::GetPropertiesCallback( |
| + const base::Closure& success_callback, |
| + const network_handler::ErrorCallback& error_callback, |
| + const std::string& service_path, |
| + const base::DictionaryValue& properties) { |
| + const NetworkState* network = |
| + NetworkStateHandler::Get()->GetNetworkState(service_path); |
| + if (!network) { |
| + InvokeErrorCallback(service_path, error_callback, kNetworkNotFound); |
| + return; |
| + } |
| + |
| + std::string provider_type; // For VPN |
| + // Note: we use Value path expansion to extract Provider.Type. |
| + properties.GetString(flimflam::kProviderTypeProperty, &provider_type); |
| + |
| + // VPN requires a host and username to be set. |
| + if (network->type() == flimflam::kTypeVPN) { |
| + std::string hostname; |
| + properties.GetString(flimflam::kProviderHostProperty, &hostname); |
| + bool config_required; |
| + if (provider_type == flimflam::kProviderOpenVpn) { |
| + std::string username, client_cert_id; |
| + properties.GetStringWithoutPathExpansion( |
| + flimflam::kOpenVPNUserProperty, &username); |
| + properties.GetStringWithoutPathExpansion( |
| + flimflam::kOpenVPNClientCertIdProperty, &client_cert_id); |
| + config_required = |
| + hostname.empty() || username.empty() || client_cert_id.empty(); |
| + } else { |
| + bool passphrase_required = false; |
| + std::string passphrase; |
| + properties.GetBooleanWithoutPathExpansion( |
| + flimflam::kL2tpIpsecPskRequiredProperty, &passphrase_required); |
| + properties.GetStringWithoutPathExpansion( |
| + flimflam::kL2tpIpsecPskProperty, &passphrase); |
| + config_required = passphrase_required && passphrase.empty(); |
| + } |
| + if (config_required) { |
| + InvokeErrorCallback(service_path, error_callback, kConfigurationRequired); |
| + return; |
| + } |
| + } |
| + |
| + // Get certificate properties from kUIDataProperty. |
| + scoped_ptr<NetworkUIData> ui_data = |
| + ManagedNetworkConfigurationHandler::GetUIData(properties); |
| + |
| + // We skip certificate patterns for device policy ONC so that an unmanaged |
| + // user can't get to the place where a cert is presented for them |
| + // involuntarily. |
| + if (ui_data && |
| + ui_data->certificate_type() == CLIENT_CERT_TYPE_PATTERN && |
| + ui_data->onc_source() != onc::ONC_SOURCE_DEVICE_POLICY) { |
| + if (ui_data->certificate_pattern().Empty()) { |
| + InvokeErrorCallback(service_path, error_callback, kCertificateRequired); |
| + return; |
| + } |
| + |
| + // Find the matching certificate. |
| + scoped_refptr<net::X509Certificate> matching_cert = |
| + certificate_pattern::GetCertificateMatch( |
| + ui_data->certificate_pattern()); |
| + if (!matching_cert.get()) { |
| + InvokeErrorCallback(service_path, error_callback, kCertificateRequired); |
| + return; |
| + } |
| + } |
| + CallShillConnect(service_path, success_callback, error_callback); |
| +} |
| + |
| +void NetworkConnectionHandler::HandleConfigurationFailure( |
| + const std::string& service_path, |
| + const network_handler::ErrorCallback& error_callback, |
| + const std::string& error_name, |
| + scoped_ptr<base::DictionaryValue> error_data) { |
| + pending_requests_.erase(service_path); |
| + if (!error_callback.is_null()) |
| + error_callback.Run(error_name, error_data.Pass()); |
| +} |
| + |
| +void NetworkConnectionHandler::HandleShillSuccess( |
| + const std::string& service_path, |
| + const base::Closure& success_callback) { |
| + // TODO(stevenjb): Currently, this only indicates that the connect request |
| + // succeeded. It might be preferable to wait for the actually connect |
| + // attempt to succeed or fail here and only call |success_callback| at that |
| + // point (or maybe call it twice, once indicating in-progress, then success |
| + // or failure). |
| + pending_requests_.erase(service_path); |
| + network_event_log::AddEntry(kLogModule, "Connected", service_path); |
| + success_callback.Run(); |
| +} |
| + |
| +void NetworkConnectionHandler::HandleShillFailure( |
| + const std::string& service_path, |
| + const network_handler::ErrorCallback& error_callback, |
| + const std::string& error_name, |
| + const std::string& error_message) { |
| + pending_requests_.erase(service_path); |
| + std::string error = "Connect Failure: " + error_name + ": " + error_message; |
| + network_handler::ShillErrorCallbackFunction( |
| + kLogModule, service_path, error_callback, error_name, error_message); |
| +} |
| + |
| +} // namespace chromeos |