bootstrapping_device_lister.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
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 "chrome/browser/local_discovery/wifi/bootstrapping_device_lister.h" 6 7#include <algorithm> 8#include <iterator> 9 10#include "base/bind.h" 11#include "base/location.h" 12#include "base/message_loop/message_loop_proxy.h" 13#include "base/strings/string_util.h" 14 15namespace local_discovery { 16 17namespace wifi { 18 19namespace { 20 21const char kPrivetSuffix[] = "prv"; 22// 3 for prv, 3 for type, one for connection status. 23const size_t kPrivetCharactersAfterSeparator = 7; 24 25const struct { 26 const char* const short_name; 27 const char* const long_name; 28} kPrivetShortNames[] = {{"cam", "camera"}, {"pri", "printer"}}; 29 30const struct { 31 char signifier; 32 BootstrappingDeviceDescription::ConnectionStatus status; 33} kPrivetConnectionStatuses[] = { 34 {'C', BootstrappingDeviceDescription::CONNECTING}, 35 {'F', BootstrappingDeviceDescription::OFFLINE}, 36 {'L', BootstrappingDeviceDescription::LOCAL_ONLY}, 37 {'N', BootstrappingDeviceDescription::NOT_CONFIGURED}, 38 {'O', BootstrappingDeviceDescription::ONLINE}, 39}; 40 41const char kPrivetDeviceLongName[] = "device"; 42 43std::string ExpandDeviceKind(const std::string& device_kind_short) { 44 for (size_t i = 0; i < arraysize(kPrivetShortNames); i++) { 45 if (device_kind_short == kPrivetShortNames[i].short_name) { 46 return kPrivetShortNames[i].long_name; 47 } 48 } 49 return kPrivetDeviceLongName; 50} 51 52BootstrappingDeviceDescription::ConnectionStatus GetConnectionStatus( 53 char signifier) { 54 for (size_t i = 0; i < arraysize(kPrivetConnectionStatuses); i++) { 55 if (signifier == kPrivetConnectionStatuses[i].signifier) { 56 return kPrivetConnectionStatuses[i].status; 57 } 58 } 59 60 LOG(WARNING) << "Unknown WiFi connection state signifier " << signifier; 61 return BootstrappingDeviceDescription::NOT_CONFIGURED; 62} 63 64// Return true if the SSID is a privet ssid and fills |description| with its 65// attributes. 66bool ParsePrivetSSID(const std::string& internal_id, 67 const std::string& ssid, 68 BootstrappingDeviceDescription* description) { 69 if (!EndsWith(ssid, kPrivetSuffix, true)) 70 return false; 71 72 size_t at_pos = ssid.length() - kPrivetCharactersAfterSeparator - 1; 73 74 if (ssid[at_pos] != '@' || ssid.find('@', at_pos + 1) != std::string::npos) 75 return false; 76 77 description->device_network_id = internal_id; 78 description->device_ssid = ssid; 79 80 description->device_name = ssid.substr(0, at_pos); 81 description->device_kind = ExpandDeviceKind(ssid.substr(at_pos + 1, 3)); 82 description->connection_status = GetConnectionStatus(ssid.at(at_pos + 4)); 83 84 return true; 85} 86 87} // namespace 88 89BootstrappingDeviceDescription::BootstrappingDeviceDescription() 90 : connection_status(NOT_CONFIGURED) { 91} 92 93BootstrappingDeviceDescription::~BootstrappingDeviceDescription() { 94} 95 96BootstrappingDeviceLister::BootstrappingDeviceLister( 97 WifiManager* wifi_manager, 98 const UpdateCallback& update_callback) 99 : wifi_manager_(wifi_manager), 100 update_callback_(update_callback), 101 started_(false), 102 weak_factory_(this) { 103} 104 105BootstrappingDeviceLister::~BootstrappingDeviceLister() { 106 if (started_) 107 wifi_manager_->RemoveNetworkListObserver(this); 108} 109 110void BootstrappingDeviceLister::Start() { 111 DCHECK(!started_); 112 113 started_ = true; 114 115 wifi_manager_->AddNetworkListObserver(this); 116 117 wifi_manager_->GetSSIDList( 118 base::Bind(&BootstrappingDeviceLister::OnNetworkListChanged, 119 weak_factory_.GetWeakPtr())); 120} 121 122void BootstrappingDeviceLister::OnNetworkListChanged( 123 const std::vector<NetworkProperties>& ssids) { 124 ActiveDeviceList new_devices; 125 126 for (size_t i = 0; i < ssids.size(); i++) { 127 new_devices.push_back(make_pair(ssids[i].ssid, ssids[i].guid)); 128 } 129 130 std::sort(new_devices.begin(), new_devices.end()); 131 132 base::WeakPtr<BootstrappingDeviceLister> weak_this = 133 weak_factory_.GetWeakPtr(); 134 // Find new or changed SSIDs 135 UpdateChangedSSIDs(true, new_devices, active_devices_); 136 if (!weak_this) 137 return; 138 139 // Find removed SSIDs 140 UpdateChangedSSIDs(false, active_devices_, new_devices); 141 if (!weak_this) 142 return; 143 144 active_devices_.swap(new_devices); 145} 146 147void BootstrappingDeviceLister::UpdateChangedSSIDs( 148 bool available, 149 const ActiveDeviceList& changed, 150 const ActiveDeviceList& original) { 151 base::WeakPtr<BootstrappingDeviceLister> weak_this = 152 weak_factory_.GetWeakPtr(); 153 154 ActiveDeviceList changed_devices; 155 std::set_difference(changed.begin(), 156 changed.end(), 157 original.begin(), 158 original.end(), 159 std::back_inserter(changed_devices)); 160 161 for (ActiveDeviceList::iterator i = changed_devices.begin(); 162 weak_this && i != changed_devices.end(); 163 i++) { 164 BootstrappingDeviceDescription description; 165 if (ParsePrivetSSID(i->second, i->first, &description)) { 166 update_callback_.Run(available, description); 167 } 168 } 169} 170 171} // namespace wifi 172 173} // namespace local_discovery 174