| Index: chromeos/components/tether/tether_disconnector.cc
|
| diff --git a/chromeos/components/tether/tether_disconnector.cc b/chromeos/components/tether/tether_disconnector.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6e07201684442d5d9be229b04dd82d90eb69c7da
|
| --- /dev/null
|
| +++ b/chromeos/components/tether/tether_disconnector.cc
|
| @@ -0,0 +1,227 @@
|
| +// Copyright 2017 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/components/tether/tether_disconnector.h"
|
| +
|
| +#include "base/values.h"
|
| +#include "chromeos/components/tether/active_host.h"
|
| +#include "chromeos/components/tether/device_id_tether_network_guid_map.h"
|
| +#include "chromeos/components/tether/network_configuration_remover.h"
|
| +#include "chromeos/components/tether/tether_connector.h"
|
| +#include "chromeos/components/tether/tether_host_fetcher.h"
|
| +#include "chromeos/network/network_connection_handler.h"
|
| +#include "chromeos/network/network_state.h"
|
| +#include "chromeos/network/network_state_handler.h"
|
| +#include "components/proximity_auth/logging/logging.h"
|
| +
|
| +namespace chromeos {
|
| +
|
| +namespace tether {
|
| +
|
| +TetherDisconnector::DisconnectCallbacks::DisconnectCallbacks(
|
| + const base::Closure& success_callback,
|
| + const network_handler::StringResultCallback& error_callback)
|
| + : success_callback(success_callback), error_callback(error_callback) {}
|
| +
|
| +TetherDisconnector::DisconnectCallbacks::~DisconnectCallbacks() {}
|
| +
|
| +TetherDisconnector::DisconnectCallbacks::DisconnectCallbacks(
|
| + const DisconnectCallbacks& other)
|
| + : success_callback(other.success_callback),
|
| + error_callback(other.error_callback) {}
|
| +
|
| +TetherDisconnector::TetherDisconnector(
|
| + NetworkConnectionHandler* network_connection_handler,
|
| + NetworkStateHandler* network_state_handler,
|
| + ActiveHost* active_host,
|
| + BleConnectionManager* ble_connection_manager,
|
| + NetworkConfigurationRemover* network_configuration_remover,
|
| + TetherConnector* tether_connector,
|
| + DeviceIdTetherNetworkGuidMap* device_id_tether_network_guid_map,
|
| + TetherHostFetcher* tether_host_fetcher)
|
| + : network_connection_handler_(network_connection_handler),
|
| + network_state_handler_(network_state_handler),
|
| + active_host_(active_host),
|
| + ble_connection_manager_(ble_connection_manager),
|
| + network_configuration_remover_(network_configuration_remover),
|
| + tether_connector_(tether_connector),
|
| + device_id_tether_network_guid_map_(device_id_tether_network_guid_map),
|
| + tether_host_fetcher_(tether_host_fetcher),
|
| + weak_ptr_factory_(this) {}
|
| +
|
| +TetherDisconnector::~TetherDisconnector() {
|
| + for (auto& it : device_id_to_operations_map_) {
|
| + it.second->RemoveObserver(this);
|
| + }
|
| +}
|
| +
|
| +void TetherDisconnector::DisconnectFromNetwork(
|
| + const std::string& tether_network_guid,
|
| + const base::Closure& success_callback,
|
| + const network_handler::StringResultCallback& error_callback) {
|
| + DCHECK(!tether_network_guid.empty());
|
| +
|
| + ActiveHost::ActiveHostStatus status = active_host_->GetActiveHostStatus();
|
| + std::string active_tether_network_guid = active_host_->GetTetherNetworkGuid();
|
| + std::string active_wifi_network_guid = active_host_->GetWifiNetworkGuid();
|
| +
|
| + if (status == ActiveHost::ActiveHostStatus::DISCONNECTED) {
|
| + PA_LOG(ERROR) << "Disconnect requested for Tether network with GUID "
|
| + << tether_network_guid << ", but no device is connected.";
|
| + error_callback.Run(NetworkConnectionHandler::kErrorNotConnected);
|
| + return;
|
| + }
|
| +
|
| + if (tether_network_guid != active_tether_network_guid) {
|
| + PA_LOG(ERROR) << "Disconnect requested for Tether network with GUID "
|
| + << tether_network_guid << ", but that device is not the "
|
| + << "active host.";
|
| + error_callback.Run(NetworkConnectionHandler::kErrorNotConnected);
|
| + return;
|
| + }
|
| +
|
| + if (status == ActiveHost::ActiveHostStatus::CONNECTING) {
|
| + // Note: CancelConnectionAttempt() internally sets the active host to be
|
| + // disconnected.
|
| + if (tether_connector_->CancelConnectionAttempt(tether_network_guid)) {
|
| + PA_LOG(INFO) << "Disconnect requested for Tether network with GUID "
|
| + << tether_network_guid << ", which had not yet connected. "
|
| + << "Canceled in-progress connection attempt.";
|
| + success_callback.Run();
|
| + return;
|
| + }
|
| +
|
| + PA_LOG(ERROR) << "Disconnect requested for Tether network with GUID "
|
| + << tether_network_guid << " (not yet connected), but "
|
| + << "canceling connection attempt failed.";
|
| + error_callback.Run(NetworkConnectionHandler::kErrorDisconnectFailed);
|
| + return;
|
| + }
|
| +
|
| + DCHECK(!active_wifi_network_guid.empty());
|
| + DisconnectActiveWifiConnection(tether_network_guid, active_wifi_network_guid,
|
| + success_callback, error_callback);
|
| +}
|
| +
|
| +void TetherDisconnector::DisconnectActiveWifiConnection(
|
| + const std::string& tether_network_guid,
|
| + const std::string& wifi_network_guid,
|
| + const base::Closure& success_callback,
|
| + const network_handler::StringResultCallback& error_callback) {
|
| + // First, disconnect the active host so that the user gets visual indication
|
| + // that the disconnection is in progress as quickly as possible.
|
| + // TODO(hansberry): This will result in the Tether network becoming
|
| + // disconnected, but the Wi-Fi network will still be connected until the
|
| + // DisconnectNetwork() call below completes. This will result in a jarring UI
|
| + // transition which needs to be fixed.
|
| + active_host_->SetActiveHostDisconnected();
|
| +
|
| + const NetworkState* wifi_network_state =
|
| + network_state_handler_->GetNetworkStateFromGuid(wifi_network_guid);
|
| + if (wifi_network_state) {
|
| + // Cache the callbacks in |wifi_guid_to_callbacks_map_|. The disconnection
|
| + // process is asynchronous, so these callbacks must be saved until the
|
| + // disconnection is complete.
|
| + wifi_guid_to_callbacks_map_.emplace(
|
| + wifi_network_guid,
|
| + DisconnectCallbacks(success_callback, error_callback));
|
| + network_connection_handler_->DisconnectNetwork(
|
| + wifi_network_state->path(),
|
| + base::Bind(&TetherDisconnector::OnSuccessfulWifiDisconnect,
|
| + weak_ptr_factory_.GetWeakPtr(), wifi_network_guid),
|
| + base::Bind(&TetherDisconnector::OnFailedWifiDisconnect,
|
| + weak_ptr_factory_.GetWeakPtr(), wifi_network_guid));
|
| + } else {
|
| + PA_LOG(ERROR) << "Wi-Fi NetworkState for GUID " << wifi_network_guid << " "
|
| + << "was not registered. Cannot disconnect.";
|
| + error_callback.Run(NetworkConnectionHandler::kErrorDisconnectFailed);
|
| + }
|
| +
|
| + // In addition to disconnecting from the Wi-Fi network, this device must also
|
| + // send a DisconnectTetheringRequest to the tether host so that it can shut
|
| + // down its Wi-Fi hotspot if it is no longer in use.
|
| + const std::string device_id =
|
| + device_id_tether_network_guid_map_->GetDeviceIdForTetherNetworkGuid(
|
| + tether_network_guid);
|
| + tether_host_fetcher_->FetchTetherHost(
|
| + device_id, base::Bind(&TetherDisconnector::OnTetherHostFetched,
|
| + weak_ptr_factory_.GetWeakPtr(), device_id));
|
| +}
|
| +
|
| +void TetherDisconnector::OnOperationFinished(const std::string& device_id,
|
| + bool success) {
|
| + if (success) {
|
| + PA_LOG(INFO) << "Successfully sent DisconnectTetheringRequest to device "
|
| + << "with ID "
|
| + << cryptauth::RemoteDevice::TruncateDeviceIdForLogs(device_id);
|
| + } else {
|
| + PA_LOG(ERROR) << "Failed to send DisconnectTetheringRequest to device "
|
| + << "with ID "
|
| + << cryptauth::RemoteDevice::TruncateDeviceIdForLogs(
|
| + device_id);
|
| + }
|
| +
|
| + // Regardless of success/failure, unregister as a listener and delete the
|
| + // operation.
|
| + auto it = device_id_to_operations_map_.find(device_id);
|
| + DCHECK(it != device_id_to_operations_map_.end());
|
| + it->second->RemoveObserver(this);
|
| + device_id_to_operations_map_.erase(it);
|
| +}
|
| +
|
| +void TetherDisconnector::OnSuccessfulWifiDisconnect(
|
| + const std::string& wifi_network_guid) {
|
| + PA_LOG(INFO) << "Successfully disconnected from Wi-Fi network with GUID "
|
| + << wifi_network_guid << ".";
|
| + CleanUpAfterWifiDisconnection(true /* success */, wifi_network_guid);
|
| +}
|
| +
|
| +void TetherDisconnector::OnFailedWifiDisconnect(
|
| + const std::string& wifi_network_guid,
|
| + const std::string& error_name,
|
| + std::unique_ptr<base::DictionaryValue> error_data) {
|
| + PA_LOG(ERROR) << "Failed to disconnect from Wi-Fi network with GUID "
|
| + << wifi_network_guid << ". Error name: " << error_name;
|
| + CleanUpAfterWifiDisconnection(false /* success */, wifi_network_guid);
|
| +}
|
| +
|
| +void TetherDisconnector::CleanUpAfterWifiDisconnection(
|
| + bool success,
|
| + const std::string& wifi_network_guid) {
|
| + auto it = wifi_guid_to_callbacks_map_.find(wifi_network_guid);
|
| + DCHECK(it != wifi_guid_to_callbacks_map_.end());
|
| +
|
| + if (success)
|
| + it->second.success_callback.Run();
|
| + else {
|
| + it->second.error_callback.Run(
|
| + NetworkConnectionHandler::kErrorDisconnectFailed);
|
| + }
|
| +
|
| + wifi_guid_to_callbacks_map_.erase(wifi_network_guid);
|
| + network_configuration_remover_->RemoveNetworkConfiguration(wifi_network_guid);
|
| +}
|
| +
|
| +void TetherDisconnector::OnTetherHostFetched(
|
| + const std::string& device_id,
|
| + std::unique_ptr<cryptauth::RemoteDevice> tether_host) {
|
| + if (!tether_host) {
|
| + PA_LOG(ERROR) << "Could not fetch device with ID "
|
| + << cryptauth::RemoteDevice::TruncateDeviceIdForLogs(device_id)
|
| + << ". Unable to send DisconnectTetheringRequest.";
|
| + return;
|
| + }
|
| +
|
| + std::unique_ptr<DisconnectTetheringOperation> operation =
|
| + DisconnectTetheringOperation::Factory::NewInstance(
|
| + *tether_host, ble_connection_manager_);
|
| + // Start the operation; OnOperationFinished() will be called when finished.
|
| + operation->AddObserver(this);
|
| + operation->Initialize();
|
| + device_id_to_operations_map_.emplace(device_id, std::move(operation));
|
| +}
|
| +
|
| +} // namespace tether
|
| +
|
| +} // namespace chromeos
|
|
|