1 // Copyright 2014 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/pairing/fake_controller_pairing_flow.h" 6 7 #include <map> 8 9 #include "base/bind.h" 10 #include "base/logging.h" 11 #include "base/message_loop/message_loop.h" 12 #include "base/rand_util.h" 13 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_split.h" 15 #include "base/strings/string_util.h" 16 17 namespace chromeos { 18 19 FakeControllerPairingFlow::FakeControllerPairingFlow(const std::string& config) 20 : current_stage_(STAGE_NONE), 21 should_fail_on_connecting_(false), 22 connection_lost_begin_(STAGE_NONE), 23 connection_lost_end_(STAGE_NONE), 24 enrollment_should_fail_(false) { 25 ApplyConfig(config); 26 AddObserver(this); 27 } 28 29 FakeControllerPairingFlow::~FakeControllerPairingFlow() { 30 RemoveObserver(this); 31 } 32 33 void FakeControllerPairingFlow::ApplyConfig(const std::string& config) { 34 typedef std::vector<std::string> Tokens; 35 36 base::StringPairs kv_pairs; 37 CHECK(base::SplitStringIntoKeyValuePairs(config, ':', ',', &kv_pairs)) 38 << "Wrong config format."; 39 std::map<std::string, std::string> dict(kv_pairs.begin(), kv_pairs.end()); 40 41 if (dict.count("async_duration")) { 42 int ms = 0; 43 CHECK(base::StringToInt(dict["async_duration"], &ms)) 44 << "Wrong 'async_duration' format."; 45 async_duration_ = base::TimeDelta::FromMilliseconds(ms); 46 } else { 47 async_duration_ = base::TimeDelta::FromMilliseconds(3000); 48 } 49 50 should_fail_on_connecting_ = 51 dict.count("fail_connecting") && (dict["fail_connecting"] == "1"); 52 53 enrollment_should_fail_ = 54 dict.count("fail_enrollment") && (dict["fail_enrollment"] == "1"); 55 56 if (dict.count("connection_lost")) { 57 Tokens lost_begin_end; 58 CHECK(Tokenize(dict["connection_lost"], "-", &lost_begin_end) == 2) 59 << "Wrong 'connection_lost' format."; 60 int begin = 0; 61 int end = 0; 62 CHECK(base::StringToInt(lost_begin_end[0], &begin) && 63 base::StringToInt(lost_begin_end[1], &end)) 64 << "Wrong 'connection_lost' format."; 65 CHECK((begin == 0 && end == 0) || 66 (STAGE_WAITING_FOR_CODE_CONFIRMATION <= begin && begin <= end && 67 end <= STAGE_HOST_ENROLLMENT_ERROR)) 68 << "Wrong 'connection_lost' interval."; 69 connection_lost_begin_ = static_cast<Stage>(begin); 70 connection_lost_end_ = static_cast<Stage>(end); 71 } else { 72 connection_lost_begin_ = connection_lost_end_ = STAGE_NONE; 73 } 74 75 if (!dict.count("discovery")) { 76 dict["discovery"] = 77 "F-Device_1~F-Device_5~F-Device_3~L-Device_3~L-Device_1~F-Device_1"; 78 } 79 base::StringPairs events; 80 CHECK( 81 base::SplitStringIntoKeyValuePairs(dict["discovery"], '-', '~', &events)) 82 << "Wrong 'discovery' format."; 83 DiscoveryScenario scenario; 84 for (base::StringPairs::const_iterator event = events.begin(); 85 event != events.end(); 86 ++event) { 87 std::string type = event->first; 88 std::string device_id = event->second; 89 CHECK(type == "F" || type == "L" || type == "N") 90 << "Wrong discovery event type."; 91 CHECK(!device_id.empty() || type == "N") << "Empty device ID."; 92 scenario.push_back(DiscoveryEvent( 93 type == "F" ? DEVICE_FOUND : type == "L" ? DEVICE_LOST : NOTHING_FOUND, 94 device_id)); 95 } 96 SetDiscoveryScenario(scenario); 97 98 preset_confirmation_code_ = dict["code"]; 99 CHECK(preset_confirmation_code_.empty() || 100 (preset_confirmation_code_.length() == 6 && 101 preset_confirmation_code_.find_first_not_of("0123456789") == 102 std::string::npos)) 103 << "Wrong 'code' format."; 104 } 105 106 void FakeControllerPairingFlow::SetShouldFailOnConnecting() { 107 should_fail_on_connecting_ = true; 108 } 109 110 void FakeControllerPairingFlow::SetShouldLoseConnection(Stage stage_begin, 111 Stage stage_end) { 112 connection_lost_begin_ = stage_begin; 113 connection_lost_end_ = stage_end; 114 } 115 116 void FakeControllerPairingFlow::SetEnrollmentShouldFail() { 117 enrollment_should_fail_ = true; 118 } 119 120 void FakeControllerPairingFlow::SetDiscoveryScenario( 121 const DiscoveryScenario& discovery_scenario) { 122 discovery_scenario_ = discovery_scenario; 123 // Check that scenario is valid. 124 std::set<std::string> devices; 125 for (DiscoveryScenario::const_iterator event = discovery_scenario_.begin(); 126 event != discovery_scenario_.end(); 127 ++event) { 128 switch (event->first) { 129 case DEVICE_FOUND: { 130 devices.insert(event->second); 131 break; 132 } 133 case DEVICE_LOST: { 134 CHECK(devices.count(event->second)); 135 devices.erase(event->second); 136 break; 137 } 138 case NOTHING_FOUND: { 139 CHECK(++event == discovery_scenario_.end()); 140 return; 141 } 142 } 143 } 144 } 145 146 void FakeControllerPairingFlow::AddObserver(Observer* observer) { 147 observers_.AddObserver(observer); 148 } 149 150 void FakeControllerPairingFlow::RemoveObserver(Observer* observer) { 151 observers_.RemoveObserver(observer); 152 } 153 154 ControllerPairingFlow::Stage FakeControllerPairingFlow::GetCurrentStage() { 155 return current_stage_; 156 } 157 158 void FakeControllerPairingFlow::StartFlow() { 159 CHECK(current_stage_ == STAGE_NONE); 160 ChangeStage(STAGE_DEVICES_DISCOVERY); 161 } 162 163 ControllerPairingFlow::DeviceIdList 164 FakeControllerPairingFlow::GetDiscoveredDevices() { 165 CHECK(current_stage_ == STAGE_DEVICES_DISCOVERY); 166 return DeviceIdList(discovered_devices_.begin(), discovered_devices_.end()); 167 } 168 169 void FakeControllerPairingFlow::ChooseDeviceForPairing( 170 const std::string& device_id) { 171 CHECK(current_stage_ == STAGE_DEVICES_DISCOVERY); 172 CHECK(discovered_devices_.count(device_id)); 173 choosen_device_ = device_id; 174 ChangeStage(STAGE_ESTABLISHING_CONNECTION); 175 } 176 177 void FakeControllerPairingFlow::RepeatDiscovery() { 178 CHECK(current_stage_ == STAGE_DEVICE_NOT_FOUND || 179 current_stage_ == STAGE_ESTABLISHING_CONNECTION_ERROR || 180 current_stage_ == STAGE_HOST_ENROLLMENT_ERROR); 181 ChangeStage(STAGE_DEVICES_DISCOVERY); 182 } 183 184 std::string FakeControllerPairingFlow::GetConfirmationCode() { 185 CHECK(current_stage_ == STAGE_WAITING_FOR_CODE_CONFIRMATION); 186 if (confirmation_code_.empty()) { 187 if (preset_confirmation_code_.empty()) { 188 for (int i = 0; i < 6; ++i) 189 confirmation_code_.push_back(base::RandInt('0', '9')); 190 } else { 191 confirmation_code_ = preset_confirmation_code_; 192 } 193 } 194 return confirmation_code_; 195 } 196 197 void FakeControllerPairingFlow::SetConfirmationCodeIsCorrect(bool correct) { 198 CHECK(current_stage_ == STAGE_WAITING_FOR_CODE_CONFIRMATION); 199 if (correct) 200 ChangeStage(STAGE_HOST_UPDATE_IN_PROGRESS); 201 else 202 ChangeStage(STAGE_DEVICES_DISCOVERY); 203 } 204 205 void FakeControllerPairingFlow::OnAuthenticationDone( 206 const chromeos::UserContext& user_context, 207 content::BrowserContext* browser_context) { 208 CHECK(current_stage_ == STAGE_WAITING_FOR_CREDENTIALS); 209 ChangeStage(STAGE_HOST_ENROLLMENT_IN_PROGRESS); 210 } 211 212 void FakeControllerPairingFlow::StartSession() { 213 CHECK(current_stage_ == STAGE_PAIRING_DONE); 214 ChangeStage(STAGE_FINISHED); 215 } 216 217 void FakeControllerPairingFlow::ChangeStage(Stage new_stage) { 218 if (current_stage_ == new_stage) 219 return; 220 current_stage_ = new_stage; 221 FOR_EACH_OBSERVER(Observer, observers_, PairingStageChanged(new_stage)); 222 } 223 224 void FakeControllerPairingFlow::ChangeStageLater(Stage new_stage) { 225 base::MessageLoop::current()->PostDelayedTask( 226 FROM_HERE, 227 base::Bind(&FakeControllerPairingFlow::ChangeStage, 228 base::Unretained(this), 229 new_stage), 230 async_duration_); 231 } 232 233 void FakeControllerPairingFlow::ExecuteDiscoveryEvent(size_t event_position) { 234 if (current_stage_ != STAGE_DEVICES_DISCOVERY) 235 return; 236 CHECK(event_position < discovery_scenario_.size()); 237 const DiscoveryEvent& event = discovery_scenario_[event_position]; 238 switch (event.first) { 239 case DEVICE_FOUND: { 240 DeviceFound(event.second); 241 break; 242 } 243 case DEVICE_LOST: { 244 DeviceLost(event.second); 245 break; 246 } 247 case NOTHING_FOUND: { 248 ChangeStage(STAGE_DEVICE_NOT_FOUND); 249 break; 250 } 251 } 252 if (++event_position == discovery_scenario_.size()) { 253 return; 254 } 255 base::MessageLoop::current()->PostDelayedTask( 256 FROM_HERE, 257 base::Bind(&FakeControllerPairingFlow::ExecuteDiscoveryEvent, 258 base::Unretained(this), 259 event_position), 260 async_duration_); 261 } 262 263 void FakeControllerPairingFlow::DeviceFound(const std::string& device_id) { 264 CHECK(current_stage_ == STAGE_DEVICES_DISCOVERY); 265 discovered_devices_.insert(device_id); 266 FOR_EACH_OBSERVER(Observer, observers_, DiscoveredDevicesListChanged()); 267 } 268 269 void FakeControllerPairingFlow::DeviceLost(const std::string& device_id) { 270 CHECK(current_stage_ == STAGE_DEVICES_DISCOVERY); 271 discovered_devices_.erase(device_id); 272 FOR_EACH_OBSERVER(Observer, observers_, DiscoveredDevicesListChanged()); 273 } 274 275 void FakeControllerPairingFlow::PairingStageChanged(Stage new_stage) { 276 Stage next_stage = STAGE_NONE; 277 switch (new_stage) { 278 case STAGE_DEVICES_DISCOVERY: { 279 discovered_devices_.clear(); 280 base::MessageLoop::current()->PostDelayedTask( 281 FROM_HERE, 282 base::Bind(&FakeControllerPairingFlow::ExecuteDiscoveryEvent, 283 base::Unretained(this), 284 0), 285 async_duration_); 286 break; 287 } 288 case STAGE_ESTABLISHING_CONNECTION: { 289 if (should_fail_on_connecting_) { 290 next_stage = STAGE_ESTABLISHING_CONNECTION_ERROR; 291 should_fail_on_connecting_ = false; 292 } else { 293 confirmation_code_.clear(); 294 next_stage = STAGE_WAITING_FOR_CODE_CONFIRMATION; 295 } 296 break; 297 } 298 case STAGE_HOST_UPDATE_IN_PROGRESS: { 299 next_stage = STAGE_WAITING_FOR_CREDENTIALS; 300 break; 301 } 302 case STAGE_HOST_ENROLLMENT_IN_PROGRESS: { 303 if (enrollment_should_fail_) { 304 enrollment_should_fail_ = false; 305 next_stage = STAGE_HOST_ENROLLMENT_ERROR; 306 } else { 307 next_stage = STAGE_PAIRING_DONE; 308 } 309 break; 310 } 311 case STAGE_HOST_CONNECTION_LOST: { 312 next_stage = connection_lost_end_; 313 connection_lost_end_ = STAGE_NONE; 314 break; 315 } 316 default: 317 break; 318 } 319 if (new_stage == connection_lost_begin_) { 320 connection_lost_begin_ = STAGE_NONE; 321 next_stage = STAGE_HOST_CONNECTION_LOST; 322 } 323 if (next_stage != STAGE_NONE) 324 ChangeStageLater(next_stage); 325 } 326 327 void FakeControllerPairingFlow::DiscoveredDevicesListChanged() { 328 } 329 330 } // namespace chromeos 331