Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(270)

Side by Side Diff: chrome/browser/geolocation/wifi_data_provider_linux.cc

Issue 546116: Adding geolocation data provider infrastructure to Chrome.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2008, Google Inc.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are met:
5 //
6 // 1. Redistributions of source code must retain the above copyright notice,
7 // this list of conditions and the following disclaimer.
8 // 2. Redistributions in binary form must reproduce the above copyright notice,
9 // this list of conditions and the following disclaimer in the documentation
10 // and/or other materials provided with the distribution.
11 // 3. Neither the name of Google Inc. nor the names of its contributors may be
12 // used to endorse or promote products derived from this software without
13 // specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 //
26 // WiFi card drivers for Linux implement the Wireless Extensions interface.
27 // This interface is part of the Linux kernel.
28 //
29 // Various sets of tools are available to manipulate the Wireless Extensions,
30 // of which Wireless Tools is the default implementation. Wireless Tools
31 // provides a C++ library (libiw) as well as a set of command line tools
32 // (iwconfig, iwlist etc). See
33 // http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html for details.
34 //
35 // Ideally, we would use libiw to obtain WiFi data. However, Wireless Tools is
36 // released under GPL, which is not compatible with Gears. Furthermore, little
37 // documentation is available for Wireless Extensions, so replicating libiw
38 // without copying it directly would be difficult.
39 //
40 // We therefore simply invoke iwlist (one of the Wireless Tools command line
41 // tools) and parse the output. Sample output is shown below.
42 //
43 // lo Interface doesn't support scanning.
44 //
45 // ath0 Scan completed :
46 // Cell 01 - Address: 00:24:86:11:4C:42
47 // ESSID:"Test SSID"
48 // Mode:Master
49 // Frequency:2.427 GHz (Channel 4)
50 // Quality=5/94 Signal level=-90 dBm Noise level=-95 dBm
51 // Encryption key:off
52 // Bit Rates:1 Mb/s; 2 Mb/s; 5 Mb/s; 6 Mb/s; 9 Mb/s
53 // 11 Mb/s; 12 Mb/s; 18 Mb/s
54 // Extra:bcn_int=100
55 // Cell 02 - Address: 00:24:86:11:6F:E2
56 // ESSID:"Test SSID"
57 // Mode:Master
58 // Frequency:2.447 GHz (Channel 8)
59 // Quality=4/94 Signal level=-91 dBm Noise level=-95 dBm
60 // Encryption key:off
61 // Bit Rates:1 Mb/s; 2 Mb/s; 5 Mb/s; 6 Mb/s; 9 Mb/s
62 // 11 Mb/s; 12 Mb/s; 18 Mb/s
63 // Extra:bcn_int=100
64 //
65 // TODO(steveblock): Investigate the possibility of the author of Wireless Tools
66 // releasing libiw under a Gears-compatible license.
67
68 // TODO(cprince): remove platform-specific #ifdef guards when OS-specific
69 // sources (e.g. WIN32_CPPSRCS) are implemented
70 #if defined(LINUX) && !defined(OS_MACOSX)
71
72 #include "gears/geolocation/wifi_data_provider_linux.h"
73
74 #include <ctype.h> // For isxdigit()
75 #include <stdio.h>
76 #include "gears/base/common/string_utils.h"
77 #include "gears/geolocation/wifi_data_provider_common.h"
78
79 // The time periods, in milliseconds, between successive polls of the wifi data.
80 extern const int kDefaultPollingInterval = 10000; // 10s
81 extern const int kNoChangePollingInterval = 120000; // 2 mins
82 extern const int kTwoNoChangePollingInterval = 600000; // 10 mins
83
84 // Local function
85 static bool GetAccessPointData(WifiData::AccessPointDataSet *access_points);
86
87 // static
88 template<>
89 WifiDataProviderImplBase *WifiDataProvider::DefaultFactoryFunction() {
90 return new LinuxWifiDataProvider();
91 }
92
93
94 LinuxWifiDataProvider::LinuxWifiDataProvider()
95 : is_first_scan_complete_(false) {
96 Start();
97 }
98
99 LinuxWifiDataProvider::~LinuxWifiDataProvider() {
100 stop_event_.Signal();
101 Join();
102 }
103
104 bool LinuxWifiDataProvider::GetData(WifiData *data) {
105 assert(data);
106 MutexLock lock(&data_mutex_);
107 *data = wifi_data_;
108 // If we've successfully completed a scan, indicate that we have all of the
109 // data we can get.
110 return is_first_scan_complete_;
111 }
112
113 // Thread implementation
114 void LinuxWifiDataProvider::Run() {
115 // Regularly get the access point data.
116 int polling_interval = kDefaultPollingInterval;
117 do {
118 WifiData new_data;
119 if (GetAccessPointData(&new_data.access_point_data)) {
120 bool update_available;
121 data_mutex_.Lock();
122 update_available = wifi_data_.DiffersSignificantly(new_data);
123 wifi_data_ = new_data;
124 data_mutex_.Unlock();
125 polling_interval =
126 UpdatePollingInterval(polling_interval, update_available);
127 if (update_available) {
128 is_first_scan_complete_ = true;
129 NotifyListeners();
130 }
131 }
132 } while (!stop_event_.WaitWithTimeout(polling_interval));
133 }
134
135 // Local functions
136
137 static bool IsValidMacAddress(const char *mac_address) {
138 return isxdigit(mac_address[0]) &&
139 isxdigit(mac_address[1]) &&
140 mac_address[2] == ':' &&
141 isxdigit(mac_address[3]) &&
142 isxdigit(mac_address[4]) &&
143 mac_address[5] == ':' &&
144 isxdigit(mac_address[6]) &&
145 isxdigit(mac_address[7]) &&
146 mac_address[8] == ':' &&
147 isxdigit(mac_address[9]) &&
148 isxdigit(mac_address[10]) &&
149 mac_address[11] == ':' &&
150 isxdigit(mac_address[12]) &&
151 isxdigit(mac_address[13]) &&
152 mac_address[14] == ':' &&
153 isxdigit(mac_address[15]) &&
154 isxdigit(mac_address[16]);
155 }
156
157 static void ParseLine(const std::string &line,
158 const std::string &mac_address_string,
159 const std::string &ssid_string,
160 const std::string &signal_strength_string,
161 AccessPointData *access_point_data) {
162 // Currently we get only MAC address, SSID and signal strength.
163 // TODO(steveblock): Work out how to get age, channel and signal-to-noise.
164 std::string::size_type index;
165 if ((index = line.find(mac_address_string)) != std::string::npos) {
166 // MAC address
167 if (IsValidMacAddress(&line.at(index + mac_address_string.size()))) {
168 UTF8ToString16(&line.at(index + mac_address_string.size()),
169 17, // XX:XX:XX:XX:XX:XX
170 &access_point_data->mac_address);
171 }
172 } else if ((index = line.find(ssid_string)) != std::string::npos) {
173 // SSID
174 // The string should be quoted.
175 std::string::size_type start = index + ssid_string.size() + 1;
176 std::string::size_type end = line.find('\"', start);
177 // If we can't find a trailing quote, something has gone wrong.
178 if (end != std::string::npos) {
179 UTF8ToString16(&line.at(start), end - start, &access_point_data->ssid);
180 }
181 } else if ((index = line.find(signal_strength_string)) != std::string::npos) {
182 // Signal strength
183 // iwlist will convert to dBm if it can. If it has failed to do so, we can't
184 // make use of the data.
185 if (line.find("dBm") != std::string::npos) {
186 // atoi will ignore trailing non-numeric characters
187 access_point_data->radio_signal_strength =
188 atoi(&line.at(index + signal_strength_string.size()));
189 }
190 }
191 }
192
193 static void ParseAccessPoint(const std::string &text,
194 const std::string &mac_address_string,
195 const std::string &ssid_string,
196 const std::string &signal_strength_string,
197 AccessPointData *access_point_data) {
198 // Split response into lines to aid parsing.
199 std::string::size_type start = 0;
200 std::string::size_type end;
201 do {
202 end = text.find('\n', start);
203 std::string::size_type length = (end == std::string::npos) ?
204 std::string::npos : end - start;
205 ParseLine(text.substr(start, length),
206 mac_address_string,
207 ssid_string,
208 signal_strength_string,
209 access_point_data);
210 start = end + 1;
211 } while (end != std::string::npos);
212 }
213
214 // Issues the specified command, and parses the response. Data for each access
215 // point is separated by the given delimiter. Within each block of data, the
216 // repsonse is split into lines and data is extracted by searching for the MAC
217 // address, SSID and signal strength strings.
218 bool IssueCommandAndParseResult(const char *command,
219 const char *delimiter,
220 const std::string &mac_address_string,
221 const std::string &ssid_string,
222 const std::string &signal_strength_string,
223 WifiData::AccessPointDataSet *access_points) {
224 // Open pipe in read mode.
225 FILE *result_pipe = popen(command, "r");
226 if (result_pipe == NULL) {
227 LOG(("IssueCommand(): Failed to open pipe.\n"));
228 return false;
229 }
230
231 // Read results of command.
232 static const int kBufferSize = 1024;
233 char buffer[kBufferSize];
234 size_t bytes_read;
235 std::string result;
236 do {
237 bytes_read = fread(buffer, 1, kBufferSize, result_pipe);
238 result.append(buffer, bytes_read);
239 } while (static_cast<int>(bytes_read) == kBufferSize);
240 pclose(result_pipe);
241
242
243 // Parse results.
244 assert(access_points);
245 access_points->clear();
246 std::string::size_type start = result.find(delimiter);
247 while (start != std::string::npos) {
248 std::string::size_type end = result.find(delimiter, start + 1);
249 std::string::size_type length = (end == std::string::npos) ?
250 std::string::npos : end - start;
251 AccessPointData access_point_data;
252 ParseAccessPoint(result.substr(start, length),
253 mac_address_string,
254 ssid_string,
255 signal_strength_string,
256 &access_point_data);
257 access_points->insert(access_point_data);
258 start = end;
259 }
260
261 return !access_points->empty();
262 }
263
264 static bool GetAccessPointData(WifiData::AccessPointDataSet *access_points) {
265 return IssueCommandAndParseResult("iwlist scan 2> /dev/null",
266 "Cell ",
267 "Address: ",
268 "ESSID:",
269 "Signal level=",
270 access_points) ||
271 IssueCommandAndParseResult("iwconfig 2> /dev/null",
272 "ESSID:\"",
273 "Access Point: ",
274 "ESSID:",
275 "Signal level=",
276 access_points);
277 }
278
279 #endif // LINUX && !OS_MACOSX
OLDNEW
« no previous file with comments | « chrome/browser/geolocation/wifi_data_provider_linux.h ('k') | chrome/browser/geolocation/wifi_data_provider_osx.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698