• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
15 namespace local_discovery {
16 
17 namespace wifi {
18 
19 namespace {
20 
21 const char kPrivetSuffix[] = "prv";
22 // 3 for prv, 3 for type, one for connection status.
23 const size_t kPrivetCharactersAfterSeparator = 7;
24 
25 const struct {
26   const char* const short_name;
27   const char* const long_name;
28 } kPrivetShortNames[] = {{"cam", "camera"}, {"pri", "printer"}};
29 
30 const 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 
41 const char kPrivetDeviceLongName[] = "device";
42 
ExpandDeviceKind(const std::string & device_kind_short)43 std::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 
GetConnectionStatus(char signifier)52 BootstrappingDeviceDescription::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.
ParsePrivetSSID(const std::string & internal_id,const std::string & ssid,BootstrappingDeviceDescription * description)66 bool 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 
BootstrappingDeviceDescription()89 BootstrappingDeviceDescription::BootstrappingDeviceDescription()
90     : connection_status(NOT_CONFIGURED) {
91 }
92 
~BootstrappingDeviceDescription()93 BootstrappingDeviceDescription::~BootstrappingDeviceDescription() {
94 }
95 
BootstrappingDeviceLister(WifiManager * wifi_manager,const UpdateCallback & update_callback)96 BootstrappingDeviceLister::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 
~BootstrappingDeviceLister()105 BootstrappingDeviceLister::~BootstrappingDeviceLister() {
106   if (started_)
107     wifi_manager_->RemoveNetworkListObserver(this);
108 }
109 
Start()110 void 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 
OnNetworkListChanged(const std::vector<NetworkProperties> & ssids)122 void 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 
UpdateChangedSSIDs(bool available,const ActiveDeviceList & changed,const ActiveDeviceList & original)147 void 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