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

Unified Diff: chrome/browser/geolocation/wifi_data_provider_linux.cc

Issue 556003: (Second attempt at http://codereview.chromium.org/553069/show)... (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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/geolocation/wifi_data_provider_linux.cc
===================================================================
--- chrome/browser/geolocation/wifi_data_provider_linux.cc (revision 0)
+++ chrome/browser/geolocation/wifi_data_provider_linux.cc (revision 0)
@@ -0,0 +1,279 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// 3. Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// WiFi card drivers for Linux implement the Wireless Extensions interface.
+// This interface is part of the Linux kernel.
+//
+// Various sets of tools are available to manipulate the Wireless Extensions,
+// of which Wireless Tools is the default implementation. Wireless Tools
+// provides a C++ library (libiw) as well as a set of command line tools
+// (iwconfig, iwlist etc). See
+// http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html for details.
+//
+// Ideally, we would use libiw to obtain WiFi data. However, Wireless Tools is
+// released under GPL, which is not compatible with Gears. Furthermore, little
+// documentation is available for Wireless Extensions, so replicating libiw
+// without copying it directly would be difficult.
+//
+// We therefore simply invoke iwlist (one of the Wireless Tools command line
+// tools) and parse the output. Sample output is shown below.
+//
+// lo Interface doesn't support scanning.
+//
+// ath0 Scan completed :
+// Cell 01 - Address: 00:24:86:11:4C:42
+// ESSID:"Test SSID"
+// Mode:Master
+// Frequency:2.427 GHz (Channel 4)
+// Quality=5/94 Signal level=-90 dBm Noise level=-95 dBm
+// Encryption key:off
+// Bit Rates:1 Mb/s; 2 Mb/s; 5 Mb/s; 6 Mb/s; 9 Mb/s
+// 11 Mb/s; 12 Mb/s; 18 Mb/s
+// Extra:bcn_int=100
+// Cell 02 - Address: 00:24:86:11:6F:E2
+// ESSID:"Test SSID"
+// Mode:Master
+// Frequency:2.447 GHz (Channel 8)
+// Quality=4/94 Signal level=-91 dBm Noise level=-95 dBm
+// Encryption key:off
+// Bit Rates:1 Mb/s; 2 Mb/s; 5 Mb/s; 6 Mb/s; 9 Mb/s
+// 11 Mb/s; 12 Mb/s; 18 Mb/s
+// Extra:bcn_int=100
+//
+// TODO(steveblock): Investigate the possibility of the author of Wireless Tools
+// releasing libiw under a Gears-compatible license.
+
+// TODO(cprince): remove platform-specific #ifdef guards when OS-specific
+// sources (e.g. WIN32_CPPSRCS) are implemented
+#if defined(LINUX) && !defined(OS_MACOSX)
+
+#include "gears/geolocation/wifi_data_provider_linux.h"
+
+#include <ctype.h> // For isxdigit()
+#include <stdio.h>
+#include "gears/base/common/string_utils.h"
+#include "gears/geolocation/wifi_data_provider_common.h"
+
+// The time periods, in milliseconds, between successive polls of the wifi data.
+extern const int kDefaultPollingInterval = 10000; // 10s
+extern const int kNoChangePollingInterval = 120000; // 2 mins
+extern const int kTwoNoChangePollingInterval = 600000; // 10 mins
+
+// Local function
+static bool GetAccessPointData(WifiData::AccessPointDataSet *access_points);
+
+// static
+template<>
+WifiDataProviderImplBase *WifiDataProvider::DefaultFactoryFunction() {
+ return new LinuxWifiDataProvider();
+}
+
+
+LinuxWifiDataProvider::LinuxWifiDataProvider()
+ : is_first_scan_complete_(false) {
+ Start();
+}
+
+LinuxWifiDataProvider::~LinuxWifiDataProvider() {
+ stop_event_.Signal();
+ Join();
+}
+
+bool LinuxWifiDataProvider::GetData(WifiData *data) {
+ assert(data);
+ MutexLock lock(&data_mutex_);
+ *data = wifi_data_;
+ // If we've successfully completed a scan, indicate that we have all of the
+ // data we can get.
+ return is_first_scan_complete_;
+}
+
+// Thread implementation
+void LinuxWifiDataProvider::Run() {
+ // Regularly get the access point data.
+ int polling_interval = kDefaultPollingInterval;
+ do {
+ WifiData new_data;
+ if (GetAccessPointData(&new_data.access_point_data)) {
+ bool update_available;
+ data_mutex_.Lock();
+ update_available = wifi_data_.DiffersSignificantly(new_data);
+ wifi_data_ = new_data;
+ data_mutex_.Unlock();
+ polling_interval =
+ UpdatePollingInterval(polling_interval, update_available);
+ if (update_available) {
+ is_first_scan_complete_ = true;
+ NotifyListeners();
+ }
+ }
+ } while (!stop_event_.WaitWithTimeout(polling_interval));
+}
+
+// Local functions
+
+static bool IsValidMacAddress(const char *mac_address) {
+ return isxdigit(mac_address[0]) &&
+ isxdigit(mac_address[1]) &&
+ mac_address[2] == ':' &&
+ isxdigit(mac_address[3]) &&
+ isxdigit(mac_address[4]) &&
+ mac_address[5] == ':' &&
+ isxdigit(mac_address[6]) &&
+ isxdigit(mac_address[7]) &&
+ mac_address[8] == ':' &&
+ isxdigit(mac_address[9]) &&
+ isxdigit(mac_address[10]) &&
+ mac_address[11] == ':' &&
+ isxdigit(mac_address[12]) &&
+ isxdigit(mac_address[13]) &&
+ mac_address[14] == ':' &&
+ isxdigit(mac_address[15]) &&
+ isxdigit(mac_address[16]);
+}
+
+static void ParseLine(const std::string &line,
+ const std::string &mac_address_string,
+ const std::string &ssid_string,
+ const std::string &signal_strength_string,
+ AccessPointData *access_point_data) {
+ // Currently we get only MAC address, SSID and signal strength.
+ // TODO(steveblock): Work out how to get age, channel and signal-to-noise.
+ std::string::size_type index;
+ if ((index = line.find(mac_address_string)) != std::string::npos) {
+ // MAC address
+ if (IsValidMacAddress(&line.at(index + mac_address_string.size()))) {
+ UTF8ToString16(&line.at(index + mac_address_string.size()),
+ 17, // XX:XX:XX:XX:XX:XX
+ &access_point_data->mac_address);
+ }
+ } else if ((index = line.find(ssid_string)) != std::string::npos) {
+ // SSID
+ // The string should be quoted.
+ std::string::size_type start = index + ssid_string.size() + 1;
+ std::string::size_type end = line.find('\"', start);
+ // If we can't find a trailing quote, something has gone wrong.
+ if (end != std::string::npos) {
+ UTF8ToString16(&line.at(start), end - start, &access_point_data->ssid);
+ }
+ } else if ((index = line.find(signal_strength_string)) != std::string::npos) {
+ // Signal strength
+ // iwlist will convert to dBm if it can. If it has failed to do so, we can't
+ // make use of the data.
+ if (line.find("dBm") != std::string::npos) {
+ // atoi will ignore trailing non-numeric characters
+ access_point_data->radio_signal_strength =
+ atoi(&line.at(index + signal_strength_string.size()));
+ }
+ }
+}
+
+static void ParseAccessPoint(const std::string &text,
+ const std::string &mac_address_string,
+ const std::string &ssid_string,
+ const std::string &signal_strength_string,
+ AccessPointData *access_point_data) {
+ // Split response into lines to aid parsing.
+ std::string::size_type start = 0;
+ std::string::size_type end;
+ do {
+ end = text.find('\n', start);
+ std::string::size_type length = (end == std::string::npos) ?
+ std::string::npos : end - start;
+ ParseLine(text.substr(start, length),
+ mac_address_string,
+ ssid_string,
+ signal_strength_string,
+ access_point_data);
+ start = end + 1;
+ } while (end != std::string::npos);
+}
+
+// Issues the specified command, and parses the response. Data for each access
+// point is separated by the given delimiter. Within each block of data, the
+// repsonse is split into lines and data is extracted by searching for the MAC
+// address, SSID and signal strength strings.
+bool IssueCommandAndParseResult(const char *command,
+ const char *delimiter,
+ const std::string &mac_address_string,
+ const std::string &ssid_string,
+ const std::string &signal_strength_string,
+ WifiData::AccessPointDataSet *access_points) {
+ // Open pipe in read mode.
+ FILE *result_pipe = popen(command, "r");
+ if (result_pipe == NULL) {
+ LOG(("IssueCommand(): Failed to open pipe.\n"));
+ return false;
+ }
+
+ // Read results of command.
+ static const int kBufferSize = 1024;
+ char buffer[kBufferSize];
+ size_t bytes_read;
+ std::string result;
+ do {
+ bytes_read = fread(buffer, 1, kBufferSize, result_pipe);
+ result.append(buffer, bytes_read);
+ } while (static_cast<int>(bytes_read) == kBufferSize);
+ pclose(result_pipe);
+
+
+ // Parse results.
+ assert(access_points);
+ access_points->clear();
+ std::string::size_type start = result.find(delimiter);
+ while (start != std::string::npos) {
+ std::string::size_type end = result.find(delimiter, start + 1);
+ std::string::size_type length = (end == std::string::npos) ?
+ std::string::npos : end - start;
+ AccessPointData access_point_data;
+ ParseAccessPoint(result.substr(start, length),
+ mac_address_string,
+ ssid_string,
+ signal_strength_string,
+ &access_point_data);
+ access_points->insert(access_point_data);
+ start = end;
+ }
+
+ return !access_points->empty();
+}
+
+static bool GetAccessPointData(WifiData::AccessPointDataSet *access_points) {
+ return IssueCommandAndParseResult("iwlist scan 2> /dev/null",
+ "Cell ",
+ "Address: ",
+ "ESSID:",
+ "Signal level=",
+ access_points) ||
+ IssueCommandAndParseResult("iwconfig 2> /dev/null",
+ "ESSID:\"",
+ "Access Point: ",
+ "ESSID:",
+ "Signal level=",
+ access_points);
+}
+
+#endif // LINUX && !OS_MACOSX
« 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