OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chromeos/components/tether/tether_disconnector.h" |
| 6 |
| 7 #include "base/values.h" |
| 8 #include "chromeos/components/tether/active_host.h" |
| 9 #include "chromeos/components/tether/device_id_tether_network_guid_map.h" |
| 10 #include "chromeos/components/tether/network_configuration_remover.h" |
| 11 #include "chromeos/components/tether/tether_connector.h" |
| 12 #include "chromeos/components/tether/tether_host_fetcher.h" |
| 13 #include "chromeos/network/network_connection_handler.h" |
| 14 #include "chromeos/network/network_state.h" |
| 15 #include "chromeos/network/network_state_handler.h" |
| 16 #include "components/proximity_auth/logging/logging.h" |
| 17 |
| 18 namespace chromeos { |
| 19 |
| 20 namespace tether { |
| 21 |
| 22 TetherDisconnector::DisconnectCallbacks::DisconnectCallbacks( |
| 23 const base::Closure& success_callback, |
| 24 const network_handler::StringResultCallback& error_callback) |
| 25 : success_callback(success_callback), error_callback(error_callback) {} |
| 26 |
| 27 TetherDisconnector::DisconnectCallbacks::~DisconnectCallbacks() {} |
| 28 |
| 29 TetherDisconnector::DisconnectCallbacks::DisconnectCallbacks( |
| 30 const DisconnectCallbacks& other) |
| 31 : success_callback(other.success_callback), |
| 32 error_callback(other.error_callback) {} |
| 33 |
| 34 TetherDisconnector::TetherDisconnector( |
| 35 NetworkConnectionHandler* network_connection_handler, |
| 36 NetworkStateHandler* network_state_handler, |
| 37 ActiveHost* active_host, |
| 38 BleConnectionManager* ble_connection_manager, |
| 39 NetworkConfigurationRemover* network_configuration_remover, |
| 40 TetherConnector* tether_connector, |
| 41 DeviceIdTetherNetworkGuidMap* device_id_tether_network_guid_map, |
| 42 TetherHostFetcher* tether_host_fetcher) |
| 43 : network_connection_handler_(network_connection_handler), |
| 44 network_state_handler_(network_state_handler), |
| 45 active_host_(active_host), |
| 46 ble_connection_manager_(ble_connection_manager), |
| 47 network_configuration_remover_(network_configuration_remover), |
| 48 tether_connector_(tether_connector), |
| 49 device_id_tether_network_guid_map_(device_id_tether_network_guid_map), |
| 50 tether_host_fetcher_(tether_host_fetcher), |
| 51 weak_ptr_factory_(this) {} |
| 52 |
| 53 TetherDisconnector::~TetherDisconnector() { |
| 54 for (auto& it : device_id_to_operations_map_) { |
| 55 it.second->RemoveObserver(this); |
| 56 } |
| 57 } |
| 58 |
| 59 void TetherDisconnector::DisconnectFromNetwork( |
| 60 const std::string& tether_network_guid, |
| 61 const base::Closure& success_callback, |
| 62 const network_handler::StringResultCallback& error_callback) { |
| 63 DCHECK(!tether_network_guid.empty()); |
| 64 |
| 65 ActiveHost::ActiveHostStatus status = active_host_->GetActiveHostStatus(); |
| 66 std::string active_tether_network_guid = active_host_->GetTetherNetworkGuid(); |
| 67 std::string active_wifi_network_guid = active_host_->GetWifiNetworkGuid(); |
| 68 |
| 69 if (status == ActiveHost::ActiveHostStatus::DISCONNECTED) { |
| 70 PA_LOG(ERROR) << "Disconnect requested for Tether network with GUID " |
| 71 << tether_network_guid << ", but no device is connected."; |
| 72 error_callback.Run(NetworkConnectionHandler::kErrorNotConnected); |
| 73 return; |
| 74 } |
| 75 |
| 76 if (tether_network_guid != active_tether_network_guid) { |
| 77 PA_LOG(ERROR) << "Disconnect requested for Tether network with GUID " |
| 78 << tether_network_guid << ", but that device is not the " |
| 79 << "active host."; |
| 80 error_callback.Run(NetworkConnectionHandler::kErrorNotConnected); |
| 81 return; |
| 82 } |
| 83 |
| 84 if (status == ActiveHost::ActiveHostStatus::CONNECTING) { |
| 85 // Note: CancelConnectionAttempt() internally sets the active host to be |
| 86 // disconnected. |
| 87 if (tether_connector_->CancelConnectionAttempt(tether_network_guid)) { |
| 88 PA_LOG(INFO) << "Disconnect requested for Tether network with GUID " |
| 89 << tether_network_guid << ", which had not yet connected. " |
| 90 << "Canceled in-progress connection attempt."; |
| 91 success_callback.Run(); |
| 92 return; |
| 93 } |
| 94 |
| 95 PA_LOG(ERROR) << "Disconnect requested for Tether network with GUID " |
| 96 << tether_network_guid << " (not yet connected), but " |
| 97 << "canceling connection attempt failed."; |
| 98 error_callback.Run(NetworkConnectionHandler::kErrorDisconnectFailed); |
| 99 return; |
| 100 } |
| 101 |
| 102 DCHECK(!active_wifi_network_guid.empty()); |
| 103 DisconnectActiveWifiConnection(tether_network_guid, active_wifi_network_guid, |
| 104 success_callback, error_callback); |
| 105 } |
| 106 |
| 107 void TetherDisconnector::DisconnectActiveWifiConnection( |
| 108 const std::string& tether_network_guid, |
| 109 const std::string& wifi_network_guid, |
| 110 const base::Closure& success_callback, |
| 111 const network_handler::StringResultCallback& error_callback) { |
| 112 // First, disconnect the active host so that the user gets visual indication |
| 113 // that the disconnection is in progress as quickly as possible. |
| 114 // TODO(hansberry): This will result in the Tether network becoming |
| 115 // disconnected, but the Wi-Fi network will still be connected until the |
| 116 // DisconnectNetwork() call below completes. This will result in a jarring UI |
| 117 // transition which needs to be fixed. |
| 118 active_host_->SetActiveHostDisconnected(); |
| 119 |
| 120 const NetworkState* wifi_network_state = |
| 121 network_state_handler_->GetNetworkStateFromGuid(wifi_network_guid); |
| 122 if (wifi_network_state) { |
| 123 // Cache the callbacks in |wifi_guid_to_callbacks_map_|. The disconnection |
| 124 // process is asynchronous, so these callbacks must be saved until the |
| 125 // disconnection is complete. |
| 126 wifi_guid_to_callbacks_map_.emplace( |
| 127 wifi_network_guid, |
| 128 DisconnectCallbacks(success_callback, error_callback)); |
| 129 network_connection_handler_->DisconnectNetwork( |
| 130 wifi_network_state->path(), |
| 131 base::Bind(&TetherDisconnector::OnSuccessfulWifiDisconnect, |
| 132 weak_ptr_factory_.GetWeakPtr(), wifi_network_guid), |
| 133 base::Bind(&TetherDisconnector::OnFailedWifiDisconnect, |
| 134 weak_ptr_factory_.GetWeakPtr(), wifi_network_guid)); |
| 135 } else { |
| 136 PA_LOG(ERROR) << "Wi-Fi NetworkState for GUID " << wifi_network_guid << " " |
| 137 << "was not registered. Cannot disconnect."; |
| 138 error_callback.Run(NetworkConnectionHandler::kErrorDisconnectFailed); |
| 139 } |
| 140 |
| 141 // In addition to disconnecting from the Wi-Fi network, this device must also |
| 142 // send a DisconnectTetheringRequest to the tether host so that it can shut |
| 143 // down its Wi-Fi hotspot if it is no longer in use. |
| 144 const std::string device_id = |
| 145 device_id_tether_network_guid_map_->GetDeviceIdForTetherNetworkGuid( |
| 146 tether_network_guid); |
| 147 tether_host_fetcher_->FetchTetherHost( |
| 148 device_id, base::Bind(&TetherDisconnector::OnTetherHostFetched, |
| 149 weak_ptr_factory_.GetWeakPtr(), device_id)); |
| 150 } |
| 151 |
| 152 void TetherDisconnector::OnOperationFinished(const std::string& device_id, |
| 153 bool success) { |
| 154 if (success) { |
| 155 PA_LOG(INFO) << "Successfully sent DisconnectTetheringRequest to device " |
| 156 << "with ID " |
| 157 << cryptauth::RemoteDevice::TruncateDeviceIdForLogs(device_id); |
| 158 } else { |
| 159 PA_LOG(ERROR) << "Failed to send DisconnectTetheringRequest to device " |
| 160 << "with ID " |
| 161 << cryptauth::RemoteDevice::TruncateDeviceIdForLogs( |
| 162 device_id); |
| 163 } |
| 164 |
| 165 // Regardless of success/failure, unregister as a listener and delete the |
| 166 // operation. |
| 167 auto it = device_id_to_operations_map_.find(device_id); |
| 168 DCHECK(it != device_id_to_operations_map_.end()); |
| 169 it->second->RemoveObserver(this); |
| 170 device_id_to_operations_map_.erase(it); |
| 171 } |
| 172 |
| 173 void TetherDisconnector::OnSuccessfulWifiDisconnect( |
| 174 const std::string& wifi_network_guid) { |
| 175 PA_LOG(INFO) << "Successfully disconnected from Wi-Fi network with GUID " |
| 176 << wifi_network_guid << "."; |
| 177 CleanUpAfterWifiDisconnection(true /* success */, wifi_network_guid); |
| 178 } |
| 179 |
| 180 void TetherDisconnector::OnFailedWifiDisconnect( |
| 181 const std::string& wifi_network_guid, |
| 182 const std::string& error_name, |
| 183 std::unique_ptr<base::DictionaryValue> error_data) { |
| 184 PA_LOG(ERROR) << "Failed to disconnect from Wi-Fi network with GUID " |
| 185 << wifi_network_guid << ". Error name: " << error_name; |
| 186 CleanUpAfterWifiDisconnection(false /* success */, wifi_network_guid); |
| 187 } |
| 188 |
| 189 void TetherDisconnector::CleanUpAfterWifiDisconnection( |
| 190 bool success, |
| 191 const std::string& wifi_network_guid) { |
| 192 auto it = wifi_guid_to_callbacks_map_.find(wifi_network_guid); |
| 193 DCHECK(it != wifi_guid_to_callbacks_map_.end()); |
| 194 |
| 195 if (success) |
| 196 it->second.success_callback.Run(); |
| 197 else { |
| 198 it->second.error_callback.Run( |
| 199 NetworkConnectionHandler::kErrorDisconnectFailed); |
| 200 } |
| 201 |
| 202 wifi_guid_to_callbacks_map_.erase(wifi_network_guid); |
| 203 network_configuration_remover_->RemoveNetworkConfiguration(wifi_network_guid); |
| 204 } |
| 205 |
| 206 void TetherDisconnector::OnTetherHostFetched( |
| 207 const std::string& device_id, |
| 208 std::unique_ptr<cryptauth::RemoteDevice> tether_host) { |
| 209 if (!tether_host) { |
| 210 PA_LOG(ERROR) << "Could not fetch device with ID " |
| 211 << cryptauth::RemoteDevice::TruncateDeviceIdForLogs(device_id) |
| 212 << ". Unable to send DisconnectTetheringRequest."; |
| 213 return; |
| 214 } |
| 215 |
| 216 std::unique_ptr<DisconnectTetheringOperation> operation = |
| 217 DisconnectTetheringOperation::Factory::NewInstance( |
| 218 *tether_host, ble_connection_manager_); |
| 219 // Start the operation; OnOperationFinished() will be called when finished. |
| 220 operation->AddObserver(this); |
| 221 operation->Initialize(); |
| 222 device_id_to_operations_map_.emplace(device_id, std::move(operation)); |
| 223 } |
| 224 |
| 225 } // namespace tether |
| 226 |
| 227 } // namespace chromeos |
OLD | NEW |