diff options
author | joth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-26 17:59:34 +0000 |
---|---|---|
committer | joth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-26 17:59:34 +0000 |
commit | 0e3c29f912080391a8126d319fdefc2836626d90 (patch) | |
tree | aced47ae1749b68f59d149fcb0871d9073976c51 /chrome/browser/geolocation | |
parent | a8846849618cc9a1ac1fef59657c7a818cdf3a9c (diff) | |
download | chromium_src-0e3c29f912080391a8126d319fdefc2836626d90.zip chromium_src-0e3c29f912080391a8126d319fdefc2836626d90.tar.gz chromium_src-0e3c29f912080391a8126d319fdefc2836626d90.tar.bz2 |
(Second attempt at http://codereview.chromium.org/553069/show -- this time including DEPS exclusion)
These files are lifted from gears: http://code.google.com/p/gears/source/browse/trunk/gears/geolocation/
NOTE this is a direct copy of gears files; subsequent edits will be made to bring them into chrome style and add to gypi files and so on.
BUG=11246
TEST=None (just adding placeholder files; tests will follow in next change)
Review URL: http://codereview.chromium.org/556003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@37117 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/geolocation')
13 files changed, 1934 insertions, 0 deletions
diff --git a/chrome/browser/geolocation/device_data_provider.h b/chrome/browser/geolocation/device_data_provider.h new file mode 100644 index 0000000..6d5740e --- /dev/null +++ b/chrome/browser/geolocation/device_data_provider.h @@ -0,0 +1,391 @@ +// 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. +// +// A device data provider provides data from the device that is used by a +// NetworkLocationProvider to obtain a position fix. This data may be either +// cell radio data or wifi data. For a given type of data, we use a singleton +// instance of the device data provider, which is used by multiple +// NetworkLocationProvider objects. +// +// This file providers DeviceDataProvider, which provides static methods to +// access the singleton instance. The singleton instance uses a private +// implementation to abstract across platforms and also to allow mock providers +// to be used for testing. +// +// This file also provides DeviceDataProviderImplBase, a base class which +// provides commom functionality for the private implementations. +// +// This file also declares the data structures used to represent cell radio data +// and wifi data. + +#ifndef GEARS_GEOLOCATION_DEVICE_DATA_PROVIDER_H__ +#define GEARS_GEOLOCATION_DEVICE_DATA_PROVIDER_H__ + +#include <algorithm> +#include <set> +#include <vector> +#include "gears/base/common/basictypes.h" // For int64 +#include "gears/base/common/common.h" +#include "gears/base/common/mutex.h" +#include "gears/base/common/scoped_refptr.h" // For RefCount +#include "gears/base/common/string16.h" +#include "third_party/scoped_ptr/scoped_ptr.h" + +// The following data structures are used to store cell radio data and wifi +// data. See the Geolocation API design document at +// http://code.google.com/p/google-gears/wiki/LocationAPI for a more complete +// description. +// +// For all integer fields, we use kint32min to represent unknown values. + +// Cell radio data relating to a single cell tower. +struct CellData { + CellData() + : cell_id(kint32min), + location_area_code(kint32min), + mobile_network_code(kint32min), + mobile_country_code(kint32min), + age(kint32min), + radio_signal_strength(kint32min), + timing_advance(kint32min) {} + bool Matches(const CellData &other) const { + // Ignore age and radio_signal_strength when matching. + return cell_id == other.cell_id && + location_area_code == other.location_area_code && + mobile_network_code == other.mobile_network_code && + mobile_country_code == other.mobile_country_code && + timing_advance == other.timing_advance; + } + + int cell_id; // Unique identifier of the cell + int location_area_code; // For current location area + int mobile_network_code; // For current cell + int mobile_country_code; // For current cell + int age; // Milliseconds since this cell was primary + int radio_signal_strength; // Measured in dBm. + int timing_advance; // Timing advance representing the distance from + // the cell tower. Each unit is roughly 550 + // meters. +}; + +static bool CellDataMatches(const CellData &data1, const CellData &data2) { + return data1.Matches(data2); +} + +enum RadioType { + RADIO_TYPE_UNKNOWN, + RADIO_TYPE_GSM, + RADIO_TYPE_CDMA, + RADIO_TYPE_WCDMA, +}; + +// All data for the cell radio. +struct RadioData { + RadioData() + : home_mobile_network_code(kint32min), + home_mobile_country_code(kint32min), + radio_type(RADIO_TYPE_UNKNOWN) {} + bool Matches(const RadioData &other) const { + if (cell_data.size() != other.cell_data.size()) { + return false; + } + if (!std::equal(cell_data.begin(), cell_data.end(), other.cell_data.begin(), + CellDataMatches)) { + return false; + } + return device_id == other.device_id && + home_mobile_network_code == other.home_mobile_network_code && + home_mobile_country_code == other.home_mobile_country_code && + radio_type == other.radio_type && + carrier == other.carrier; + } + // Determines whether a new set of radio data differs significantly from this. + bool DiffersSignificantly(const RadioData &other) const { + // This is required by MockDeviceDataProviderImpl. + // TODO(steveblock): Implement properly. + return !Matches(other); + } + + std::string16 device_id; + std::vector<CellData> cell_data; + int home_mobile_network_code; // For the device's home network. + int home_mobile_country_code; // For the device's home network. + RadioType radio_type; // Mobile radio type. + std::string16 carrier; // Carrier name. +}; + +// Wifi data relating to a single access point. +struct AccessPointData { + AccessPointData() + : radio_signal_strength(kint32min), + age(kint32min), + channel(kint32min), + signal_to_noise(kint32min) {} + + std::string16 mac_address; + int radio_signal_strength; // Measured in dBm + int age; // Milliseconds since this access point was detected + int channel; + int signal_to_noise; // Ratio in dB + std::string16 ssid; // Network identifier +}; + +// This is to allow AccessPointData to be used in std::set. We order +// lexicographically by MAC address. +struct AccessPointDataLess : public std::less<AccessPointData> { + bool operator()(const AccessPointData &data1, + const AccessPointData &data2) const { + return data1.mac_address < data2.mac_address; + } +}; + +// All data for wifi. +struct WifiData { + // Determines whether a new set of WiFi data differs significantly from this. + bool DiffersSignificantly(const WifiData &other) const { + // At least 5 or 50% of access points added or removed is significant. + static const size_t kMinChangedAccessPoints = 5; + + // Compute size of interesction of old and new sets. + size_t num_common = 0; + for (AccessPointDataSet::const_iterator iter = access_point_data.begin(); + iter != access_point_data.end(); + iter++) { + if (other.access_point_data.find(*iter) != + other.access_point_data.end()) { + ++num_common; + } + } + assert(num_common <= access_point_data.size()); + assert(num_common <= other.access_point_data.size()); + + // Test how many have changed. + size_t added_or_removed = std::max( + other.access_point_data.size() - num_common, + access_point_data.size() - num_common); + return added_or_removed >= + std::min(kMinChangedAccessPoints, access_point_data.size() / 2); + } + + // Store access points as a set, sorted by MAC address. This allows quick + // comparison of sets for detecting changes and for caching. + typedef std::set<AccessPointData, AccessPointDataLess> AccessPointDataSet; + AccessPointDataSet access_point_data; +}; + +template<typename DataType> +class DeviceDataProvider; + +// DeviceDataProvider uses containment to hide platform-specific implementation +// details from common code. This class provides common functionality for these +// contained implementation classes. +template<typename DataType> +class DeviceDataProviderImplBase { + public: + DeviceDataProviderImplBase() : container_(NULL) {} + virtual ~DeviceDataProviderImplBase() {} + + virtual bool GetData(DataType *data) = 0; + + // Sets the container of this class, which is of type DeviceDataProvider. + // This is required to pass as a parameter when making the callback to + // listeners. + void SetContainer(DeviceDataProvider<DataType> *container) { + container_ = container; + } + + typedef typename DeviceDataProvider<DataType>::ListenerInterface + ListenerInterface; + void AddListener(ListenerInterface *listener) { + MutexLock mutex(&listeners_mutex_); + listeners_.insert(listener); + } + bool RemoveListener(ListenerInterface *listener) { + MutexLock mutex(&listeners_mutex_); + typename ListenersSet::iterator iter = find(listeners_.begin(), + listeners_.end(), + listener); + if (iter == listeners_.end()) { + return false; + } + listeners_.erase(iter); + return true; + } + + protected: + // Calls DeviceDataUpdateAvailable() on all registered listeners. + typedef std::set<ListenerInterface*> ListenersSet; + void NotifyListeners() { + MutexLock lock(&listeners_mutex_); + for (typename ListenersSet::const_iterator iter = listeners_.begin(); + iter != listeners_.end(); + ++iter) { + (*iter)->DeviceDataUpdateAvailable(container_); + } + } + + private: + DeviceDataProvider<DataType> *container_; + + // The listeners to this class and their mutex. + ListenersSet listeners_; + Mutex listeners_mutex_; + + DISALLOW_EVIL_CONSTRUCTORS(DeviceDataProviderImplBase); +}; + +typedef DeviceDataProviderImplBase<RadioData> RadioDataProviderImplBase; +typedef DeviceDataProviderImplBase<WifiData> WifiDataProviderImplBase; + +// A device data provider +// +// We use a singleton instance of this class which is shared by multiple network +// location providers. These location providers access the instance through the +// Register and Unregister methods. +template<typename DataType> +class DeviceDataProvider { + public: + // Interface to be implemented by listeners to a device data provider. + class ListenerInterface { + public: + virtual void DeviceDataUpdateAvailable( + DeviceDataProvider<DataType> *provider) = 0; + virtual ~ListenerInterface() {} + }; + + // Sets the factory function which will be used by Register to create the + // implementation used by the singleton instance. This factory approach is + // used to abastract accross both platform-specific implementation and to + // inject mock implementations for testing. + typedef DeviceDataProviderImplBase<DataType> *(*ImplFactoryFunction)(void); + static void SetFactory(ImplFactoryFunction factory_function_in) { + factory_function_ = factory_function_in; + } + + static void ResetFactory() { + factory_function_ = DefaultFactoryFunction; + } + + // Adds a listener, which will be called back with DeviceDataUpdateAvailable + // whenever new data is available. Returns the singleton instance. + static DeviceDataProvider *Register(ListenerInterface *listener) { + // We protect against Register and Unregister being called asynchronously + // from different threads. This is the case when a device data provider is + // used by a NetworkLocationProvider object. Register is always called from + // the JavaScript thread. Unregister is called when NetworkLocationProvider + // objects are destructed, which happens asynchronously once the + // NetworkLocationProvider HTTP request has completed. + MutexLock mutex(&instance_mutex_); + if (!instance_) { + instance_ = new DeviceDataProvider(); + } + assert(instance_); + instance_->Ref(); + instance_->AddListener(listener); + return instance_; + } + + // Removes a listener. If this is the last listener, deletes the singleton + // instance. Return value indicates success. + static bool Unregister(ListenerInterface *listener) { + MutexLock mutex(&instance_mutex_); + if (!instance_->RemoveListener(listener)) { + return false; + } + if (instance_->Unref()) { + delete instance_; + instance_ = NULL; + } + return true; + } + + // Provides whatever data the provider has, which may be nothing. Return + // value indicates whether this is all the data the provider could ever + // obtain. + bool GetData(DataType *data) { + return impl_->GetData(data); + } + + private: + // Private constructor and destructor, callers access singleton through + // Register and Unregister. + DeviceDataProvider() { + assert(factory_function_); + impl_.reset((*factory_function_)()); + impl_->SetContainer(this); + } + virtual ~DeviceDataProvider() {} + + void Ref() { + count_.Ref(); + } + // Returns true when the ref count transitions from 1 to 0. + bool Unref() { + return count_.Unref(); + } + + void AddListener(ListenerInterface *listener) { + impl_->AddListener(listener); + } + + bool RemoveListener(ListenerInterface *listener) { + return impl_->RemoveListener(listener); + } + + static DeviceDataProviderImplBase<DataType> *DefaultFactoryFunction(); + + // The singleton instance of this class and its mutex. + static DeviceDataProvider *instance_; + static Mutex instance_mutex_; + + // The factory function used to create the singleton instance. + static ImplFactoryFunction factory_function_; + + // The internal implementation. + scoped_ptr<DeviceDataProviderImplBase<DataType> > impl_; + + RefCount count_; + + DISALLOW_EVIL_CONSTRUCTORS(DeviceDataProvider); +}; + +// static +template<typename DataType> +Mutex DeviceDataProvider<DataType>::instance_mutex_; + +// static +template<typename DataType> +DeviceDataProvider<DataType> *DeviceDataProvider<DataType>::instance_ = + NULL; + +// static +template<typename DataType> +typename DeviceDataProvider<DataType>::ImplFactoryFunction + DeviceDataProvider<DataType>::factory_function_ = DefaultFactoryFunction; + +typedef DeviceDataProvider<RadioData> RadioDataProvider; +typedef DeviceDataProvider<WifiData> WifiDataProvider; + +#endif // GEARS_GEOLOCATION_DEVICE_DATA_PROVIDER_H__ diff --git a/chrome/browser/geolocation/empty_device_data_provider.cc b/chrome/browser/geolocation/empty_device_data_provider.cc new file mode 100644 index 0000000..9da8e831 --- /dev/null +++ b/chrome/browser/geolocation/empty_device_data_provider.cc @@ -0,0 +1,39 @@ +// 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. + +// Win32, Linux and OSX use the empty device data provider for radio data. +#if (defined(WIN32) && !defined(OS_WINCE)) || \ + defined(LINUX) || \ + defined(OS_MACOSX) + +#include "gears/geolocation/empty_device_data_provider.h" + +// static +template<> +RadioDataProviderImplBase *RadioDataProvider::DefaultFactoryFunction() { + return new EmptyDeviceDataProvider<RadioData>(); +} + +#endif // (WIN32 && !OS_WINCE) || LINUX || OS_MACOSX diff --git a/chrome/browser/geolocation/empty_device_data_provider.h b/chrome/browser/geolocation/empty_device_data_provider.h new file mode 100644 index 0000000..8c6097c --- /dev/null +++ b/chrome/browser/geolocation/empty_device_data_provider.h @@ -0,0 +1,51 @@ +// 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. + +#ifndef GEARS_GEOLOCATION_EMPTY_DEVICE_DATA_PROVIDER_H__ +#define GEARS_GEOLOCATION_EMPTY_DEVICE_DATA_PROVIDER_H__ + +#include "gears/geolocation/device_data_provider.h" + +// An implementation of DeviceDataProviderImplBase that does not provide any +// data. Used on platforms where a given data type is not available. + +template<typename DataType> +class EmptyDeviceDataProvider : public DeviceDataProviderImplBase<DataType> { + public: + EmptyDeviceDataProvider() {} + virtual ~EmptyDeviceDataProvider() {} + + // DeviceDataProviderImplBase implementation + virtual bool GetData(DataType *data) { + assert(data); + // This is all the data we can get - nothing. + return true; + } + + private: + DISALLOW_EVIL_CONSTRUCTORS(EmptyDeviceDataProvider); +}; + +#endif // GEARS_GEOLOCATION_EMPTY_DEVICE_DATA_PROVIDER_H__ diff --git a/chrome/browser/geolocation/wifi_data_provider_common.cc b/chrome/browser/geolocation/wifi_data_provider_common.cc new file mode 100644 index 0000000..7068bc4 --- /dev/null +++ b/chrome/browser/geolocation/wifi_data_provider_common.cc @@ -0,0 +1,95 @@ +// 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. + +#include "gears/geolocation/wifi_data_provider_common.h" + +#include <assert.h> + +#if defined(WIN32) || defined(OS_MACOSX) + +#if defined(WIN32) +#include <windows.h> +#elif defined(OS_MACOSX) +#include <CoreFoundation/CoreFoundation.h> +#include "gears/base/common/string_utils_osx.h" +#include "gears/base/safari/scoped_cf.h" +#include "third_party/scoped_ptr/scoped_ptr.h" // For scoped_array +#endif + +std::string16 MacAddressAsString16(const uint8 mac_as_int[6]) { + // mac_as_int is big-endian. Write in byte chunks. + // Format is XX-XX-XX-XX-XX-XX. + static const char16 *kMacFormatString = + STRING16(L"%02x-%02x-%02x-%02x-%02x-%02x"); +#ifdef OS_MACOSX + scoped_cftype<CFStringRef> format_string(CFStringCreateWithCharacters( + kCFAllocatorDefault, + kMacFormatString, + std::char_traits<char16>::length(kMacFormatString))); + scoped_cftype<CFStringRef> mac_string(CFStringCreateWithFormat( + kCFAllocatorDefault, + NULL, // not implemented + format_string.get(), + mac_as_int[0], mac_as_int[1], mac_as_int[2], + mac_as_int[3], mac_as_int[4], mac_as_int[5])); + std::string16 mac; + CFStringRefToString16(mac_string.get(), &mac); + return mac; +#else + char16 mac[18]; +#ifdef DEBUG + int num_characters = +#endif + wsprintf(mac, kMacFormatString, + mac_as_int[0], mac_as_int[1], mac_as_int[2], + mac_as_int[3], mac_as_int[4], mac_as_int[5]); + assert(num_characters == 17); + return mac; +#endif +} + +#endif // WIN32 || OS_MACOSX + +#if defined(WIN32) || defined(OS_MACOSX) || defined(LINUX) + +// These constants are defined for each platfrom in wifi_data_provider_xxx.cc. +extern const int kDefaultPollingInterval; +extern const int kNoChangePollingInterval; +extern const int kTwoNoChangePollingInterval; + +int UpdatePollingInterval(int polling_interval, bool scan_results_differ) { + if (scan_results_differ) { + return kDefaultPollingInterval; + } + if (polling_interval == kDefaultPollingInterval) { + return kNoChangePollingInterval; + } else { + assert(polling_interval == kNoChangePollingInterval || + polling_interval == kTwoNoChangePollingInterval); + return kTwoNoChangePollingInterval; + } +} + +#endif // WIN32 || OS_MACOSX || LINUX diff --git a/chrome/browser/geolocation/wifi_data_provider_common.h b/chrome/browser/geolocation/wifi_data_provider_common.h new file mode 100644 index 0000000..a8074b9 --- /dev/null +++ b/chrome/browser/geolocation/wifi_data_provider_common.h @@ -0,0 +1,39 @@ +// 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. + +#ifndef GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_COMMON_H__ +#define GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_COMMON_H__ + +#include "gears/base/common/string16.h" +#include "gears/base/common/basictypes.h" + +// Converts a MAC address stored as an array of uint8 to a string. +std::string16 MacAddressAsString16(const uint8 mac_as_int[6]); + +// Calculates the new polling interval for wiFi scans, given the previous +// interval and whether the last scan produced new results. +int UpdatePollingInterval(int polling_interval, bool scan_results_differ); + +#endif // GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_COMMON_H__ diff --git a/chrome/browser/geolocation/wifi_data_provider_linux.cc b/chrome/browser/geolocation/wifi_data_provider_linux.cc new file mode 100644 index 0000000..fd95a2c --- /dev/null +++ b/chrome/browser/geolocation/wifi_data_provider_linux.cc @@ -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 diff --git a/chrome/browser/geolocation/wifi_data_provider_linux.h b/chrome/browser/geolocation/wifi_data_provider_linux.h new file mode 100644 index 0000000..f635246 --- /dev/null +++ b/chrome/browser/geolocation/wifi_data_provider_linux.h @@ -0,0 +1,59 @@ +// 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. + +#ifndef GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_LINUX_H__ +#define GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_LINUX_H__ + +#include "gears/base/common/common.h" +#include "gears/base/common/event.h" +#include "gears/base/common/mutex.h" +#include "gears/base/common/thread.h" +#include "gears/geolocation/device_data_provider.h" + +class LinuxWifiDataProvider + : public WifiDataProviderImplBase, + public Thread { + public: + LinuxWifiDataProvider(); + virtual ~LinuxWifiDataProvider(); + + // WifiDataProviderImplBase implementation + virtual bool GetData(WifiData *data); + + private: + // Thread implementation. + virtual void Run(); + + WifiData wifi_data_; + Mutex data_mutex_; + // Event signalled to shut down the thread that polls for wifi data. + Event stop_event_; + // Whether we've successfully completed a scan for WiFi data. + bool is_first_scan_complete_; + + DISALLOW_EVIL_CONSTRUCTORS(LinuxWifiDataProvider); +}; + +#endif // GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_LINUX_H__ diff --git a/chrome/browser/geolocation/wifi_data_provider_osx.cc b/chrome/browser/geolocation/wifi_data_provider_osx.cc new file mode 100644 index 0000000..8dfa15d --- /dev/null +++ b/chrome/browser/geolocation/wifi_data_provider_osx.cc @@ -0,0 +1,168 @@ +// 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. +// +// We use the OSX system API function WirelessScanSplit. This function is not +// documented or included in the SDK, so we use a reverse-engineered header, +// osx_wifi_.h. This file is taken from the iStumbler project +// (http://www.istumbler.net). + +// TODO(cprince): remove platform-specific #ifdef guards when OS-specific +// sources (e.g. WIN32_CPPSRCS) are implemented +#ifdef OS_MACOSX + +#include "gears/geolocation/wifi_data_provider_osx.h" + +#include <dlfcn.h> +#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 = 120000; // 2 mins +extern const int kNoChangePollingInterval = 300000; // 5 mins +extern const int kTwoNoChangePollingInterval = 600000; // 10 mins + +// static +template<> +WifiDataProviderImplBase *WifiDataProvider::DefaultFactoryFunction() { + return new OsxWifiDataProvider(); +} + + +OsxWifiDataProvider::OsxWifiDataProvider() : is_first_scan_complete_(false) { + Start(); +} + +OsxWifiDataProvider::~OsxWifiDataProvider() { + stop_event_.Signal(); + Join(); +} + +bool OsxWifiDataProvider::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 OsxWifiDataProvider::Run() { + void *apple_80211_library = dlopen( + "/System/Library/PrivateFrameworks/Apple80211.framework/Apple80211", + RTLD_LAZY); + if (!apple_80211_library) { + is_first_scan_complete_ = true; + return; + } + + WirelessAttach_function_ = reinterpret_cast<WirelessAttachFunction>( + dlsym(apple_80211_library, "WirelessAttach")); + WirelessScanSplit_function_ = reinterpret_cast<WirelessScanSplitFunction>( + dlsym(apple_80211_library, "WirelessScanSplit")); + WirelessDetach_function_ = reinterpret_cast<WirelessDetachFunction>( + dlsym(apple_80211_library, "WirelessDetach")); + assert(WirelessAttach_function_ && + WirelessScanSplit_function_ && + WirelessDetach_function_); + + if ((*WirelessAttach_function_)(&wifi_context_, 0) != noErr) { + is_first_scan_complete_ = true; + return; + } + + // Regularly get the access point data. + int polling_interval = kDefaultPollingInterval; + do { + WifiData new_data; + 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)); + + (*WirelessDetach_function_)(wifi_context_); + + dlclose(apple_80211_library); +} + +void OsxWifiDataProvider::GetAccessPointData( + WifiData::AccessPointDataSet *access_points) { + assert(access_points); + assert(WirelessScanSplit_function_); + CFArrayRef managed_access_points = NULL; + CFArrayRef adhoc_access_points = NULL; + if ((*WirelessScanSplit_function_)(wifi_context_, + &managed_access_points, + &adhoc_access_points, + 0) != noErr) { + return; + } + + if (managed_access_points == NULL) { + return; + } + + int num_access_points = CFArrayGetCount(managed_access_points); + for (int i = 0; i < num_access_points; ++i) { + const WirelessNetworkInfo *access_point_info = + reinterpret_cast<const WirelessNetworkInfo*>( + CFDataGetBytePtr( + reinterpret_cast<const CFDataRef>( + CFArrayGetValueAtIndex(managed_access_points, i)))); + + // Currently we get only MAC address, signal strength, channel + // signal-to-noise and SSID + // TODO(steveblock): Work out how to get age. + AccessPointData access_point_data; + access_point_data.mac_address = + MacAddressAsString16(access_point_info->macAddress); + // WirelessNetworkInfo::signal appears to be signal strength in dBm. + access_point_data.radio_signal_strength = access_point_info->signal; + access_point_data.channel = access_point_info->channel; + // WirelessNetworkInfo::noise appears to be noise floor in dBm. + access_point_data.signal_to_noise = access_point_info->signal - + access_point_info->noise; + std::string16 ssid; + if (UTF8ToString16(reinterpret_cast<const char*>(access_point_info->name), + access_point_info->nameLen, + &ssid)) { + access_point_data.ssid = ssid; + } + + access_points->insert(access_point_data); + } +} + +#endif // OS_MACOSX diff --git a/chrome/browser/geolocation/wifi_data_provider_osx.h b/chrome/browser/geolocation/wifi_data_provider_osx.h new file mode 100644 index 0000000..69fc7828 --- /dev/null +++ b/chrome/browser/geolocation/wifi_data_provider_osx.h @@ -0,0 +1,71 @@ +// 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. + +#ifndef GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_OSX_H__ +#define GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_OSX_H__ + +#include "gears/base/common/common.h" +#include "gears/base/common/event.h" +#include "gears/base/common/mutex.h" +#include "gears/base/common/thread.h" +#include "gears/geolocation/device_data_provider.h" +#include "gears/geolocation/osx_wifi.h" + +class OsxWifiDataProvider + : public WifiDataProviderImplBase, + public Thread { + public: + OsxWifiDataProvider(); + virtual ~OsxWifiDataProvider(); + + // WifiDataProviderImplBase implementation. + virtual bool GetData(WifiData *data); + + private: + // Thread implementation. + virtual void Run(); + + void GetAccessPointData(WifiData::AccessPointDataSet *access_points); + + // Context and function pointers for Apple80211 library. + WirelessContextPtr wifi_context_; + WirelessAttachFunction WirelessAttach_function_; + WirelessScanSplitFunction WirelessScanSplit_function_; + WirelessDetachFunction WirelessDetach_function_; + + WifiData wifi_data_; + Mutex data_mutex_; + + // Event signalled to shut down the thread that polls for wifi data. + Event stop_event_; + + // Whether we've successfully completed a scan for WiFi data (or the polling + // thread has terminated early). + bool is_first_scan_complete_; + + DISALLOW_EVIL_CONSTRUCTORS(OsxWifiDataProvider); +}; + +#endif // GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_OSX_H__ diff --git a/chrome/browser/geolocation/wifi_data_provider_win.cc b/chrome/browser/geolocation/wifi_data_provider_win.cc new file mode 100644 index 0000000..1e42105 --- /dev/null +++ b/chrome/browser/geolocation/wifi_data_provider_win.cc @@ -0,0 +1,534 @@ +// 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. +// +// Windows Vista uses the Native Wifi (WLAN) API for accessing WiFi cards. See +// http://msdn.microsoft.com/en-us/library/ms705945(VS.85).aspx. Windows XP +// Service Pack 3 (and Windows XP Service Pack 2, if upgraded with a hot fix) +// also support a limited version of the WLAN API. See +// http://msdn.microsoft.com/en-us/library/bb204766.aspx. The WLAN API uses +// wlanapi.h, which is not part of the SDK used by Gears, so is replicated +// locally using data from the MSDN. +// +// Windows XP from Service Pack 2 onwards supports the Wireless Zero +// Configuration (WZC) programming interface. See +// http://msdn.microsoft.com/en-us/library/ms706587(VS.85).aspx. +// +// The MSDN recommends that one use the WLAN API where available, and WZC +// otherwise. +// +// However, it seems that WZC fails for some wireless cards. Also, WLAN seems +// not to work on XP SP3. So we use WLAN on Vista, and use NDIS directly +// otherwise. + +// TODO(cprince): remove platform-specific #ifdef guards when OS-specific +// sources (e.g. WIN32_CPPSRCS) are implemented +#if defined(WIN32) && !defined(OS_WINCE) + +#include "gears/geolocation/wifi_data_provider_win32.h" + +#include <windows.h> +#include <ntddndis.h> // For IOCTL_NDIS_QUERY_GLOBAL_STATS +#include "gears/base/common/string_utils.h" +#include "gears/base/common/vista_utils.h" +#include "gears/geolocation/wifi_data_provider_common.h" +#include "gears/geolocation/wifi_data_provider_windows_common.h" + +// Taken from ndis.h for WinCE. +#define NDIS_STATUS_INVALID_LENGTH ((NDIS_STATUS)0xC0010014L) +#define NDIS_STATUS_BUFFER_TOO_SHORT ((NDIS_STATUS)0xC0010016L) + +// The limits on the size of the buffer used for the OID query. +static const int kInitialBufferSize = 2 << 12; // Good for about 50 APs. +static const int kMaximumBufferSize = 2 << 20; // 2MB + +// Length for generic string buffers passed to Win32 APIs. +static const int kStringLength = 512; + +// 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 functions + +// Extracts data for an access point and converts to Gears format. +static bool GetNetworkData(const WLAN_BSS_ENTRY &bss_entry, + AccessPointData *access_point_data); +bool UndefineDosDevice(const std::string16 &device_name); +bool DefineDosDeviceIfNotExists(const std::string16 &device_name); +HANDLE GetFileHandle(const std::string16 &device_name); +// Makes the OID query and returns a Win32 error code. +int PerformQuery(HANDLE adapter_handle, + BYTE *buffer, + DWORD buffer_size, + DWORD *bytes_out); +bool ResizeBuffer(int requested_size, BYTE **buffer); +// Gets the system directory and appends a trailing slash if not already +// present. +bool GetSystemDirectory(std::string16 *path); + +// static +template<> +WifiDataProviderImplBase *WifiDataProvider::DefaultFactoryFunction() { + return new Win32WifiDataProvider(); +} + + +Win32WifiDataProvider::Win32WifiDataProvider() + : oid_buffer_size_(kInitialBufferSize), + is_first_scan_complete_(false) { + // Start the polling thread. + Start(); +} + +Win32WifiDataProvider::~Win32WifiDataProvider() { + stop_event_.Signal(); + Join(); +} + +bool Win32WifiDataProvider::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 Win32WifiDataProvider::Run() { + // We use an absolute path to load the DLL to avoid DLL preloading attacks. + HINSTANCE library = NULL; + std::string16 system_directory; + if (GetSystemDirectory(&system_directory)) { + assert(!system_directory.empty()); + std::string16 dll_path = system_directory + L"wlanapi.dll"; + library = LoadLibraryEx(dll_path.c_str(), + NULL, + LOAD_WITH_ALTERED_SEARCH_PATH); + } + + // Use the WLAN interface if we're on Vista and if it's available. Otherwise, + // use NDIS. + typedef bool (Win32WifiDataProvider::*GetAccessPointDataFunction)( + WifiData::AccessPointDataSet *data); + GetAccessPointDataFunction get_access_point_data_function = NULL; + if (VistaUtils::IsRunningOnVista() && library) { + GetWLANFunctions(library); + get_access_point_data_function = + &Win32WifiDataProvider::GetAccessPointDataWLAN; + } else { + // We assume the list of interfaces doesn't change while Gears is running. + if (!GetInterfacesNDIS()) { + is_first_scan_complete_ = true; + return; + } + get_access_point_data_function = + &Win32WifiDataProvider::GetAccessPointDataNDIS; + } + assert(get_access_point_data_function); + + int polling_interval = kDefaultPollingInterval; + // Regularly get the access point data. + do { + WifiData new_data; + if ((this->*get_access_point_data_function)(&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)); + + FreeLibrary(library); +} + +// WLAN functions + +void Win32WifiDataProvider::GetWLANFunctions(HINSTANCE wlan_library) { + assert(wlan_library); + WlanOpenHandle_function_ = reinterpret_cast<WlanOpenHandleFunction>( + GetProcAddress(wlan_library, "WlanOpenHandle")); + WlanEnumInterfaces_function_ = reinterpret_cast<WlanEnumInterfacesFunction>( + GetProcAddress(wlan_library, "WlanEnumInterfaces")); + WlanGetNetworkBssList_function_ = + reinterpret_cast<WlanGetNetworkBssListFunction>( + GetProcAddress(wlan_library, "WlanGetNetworkBssList")); + WlanFreeMemory_function_ = reinterpret_cast<WlanFreeMemoryFunction>( + GetProcAddress(wlan_library, "WlanFreeMemory")); + WlanCloseHandle_function_ = reinterpret_cast<WlanCloseHandleFunction>( + GetProcAddress(wlan_library, "WlanCloseHandle")); + assert(WlanOpenHandle_function_ && + WlanEnumInterfaces_function_ && + WlanGetNetworkBssList_function_ && + WlanFreeMemory_function_ && + WlanCloseHandle_function_); +} + +bool Win32WifiDataProvider::GetAccessPointDataWLAN( + WifiData::AccessPointDataSet *data) { + assert(data); + + // Get the handle to the WLAN API. + DWORD negotiated_version; + HANDLE wlan_handle = NULL; + // We could be executing on either Windows XP or Windows Vista, so use the + // lower version of the client WLAN API. It seems that the negotiated version + // is the Vista version irrespective of what we pass! + static const int kXpWlanClientVersion = 1; + if ((*WlanOpenHandle_function_)(kXpWlanClientVersion, + NULL, + &negotiated_version, + &wlan_handle) != ERROR_SUCCESS) { + return false; + } + assert(wlan_handle); + + // Get the list of interfaces. WlanEnumInterfaces allocates interface_list. + WLAN_INTERFACE_INFO_LIST *interface_list = NULL; + if ((*WlanEnumInterfaces_function_)(wlan_handle, NULL, &interface_list) != + ERROR_SUCCESS) { + return false; + } + assert(interface_list); + + // Go through the list of interfaces and get the data for each. + for (int i = 0; i < static_cast<int>(interface_list->dwNumberOfItems); ++i) { + GetInterfaceDataWLAN(wlan_handle, + interface_list->InterfaceInfo[i].InterfaceGuid, + data); + } + + // Free interface_list. + (*WlanFreeMemory_function_)(interface_list); + + // Close the handle. + if ((*WlanCloseHandle_function_)(wlan_handle, NULL) != ERROR_SUCCESS) { + return false; + } + + return true; +} + +// Appends the data for a single interface to the data vector. Returns the +// number of access points found, or -1 on error. +int Win32WifiDataProvider::GetInterfaceDataWLAN( + const HANDLE wlan_handle, + const GUID &interface_id, + WifiData::AccessPointDataSet *data) { + assert(data); + // WlanGetNetworkBssList allocates bss_list. + WLAN_BSS_LIST *bss_list; + if ((*WlanGetNetworkBssList_function_)(wlan_handle, + &interface_id, + NULL, // Use all SSIDs. + DOT11_BSS_TYPE_UNUSED, + false, // bSecurityEnabled - unused + NULL, // reserved + &bss_list) != ERROR_SUCCESS) { + return -1; + } + + int found = 0; + for (int i = 0; i < static_cast<int>(bss_list->dwNumberOfItems); ++i) { + AccessPointData access_point_data; + if (GetNetworkData(bss_list->wlanBssEntries[i], &access_point_data)) { + ++found; + data->insert(access_point_data); + } + } + + (*WlanFreeMemory_function_)(bss_list); + + return found; +} + +// NDIS functions + +bool Win32WifiDataProvider::GetInterfacesNDIS() { + HKEY network_cards_key = NULL; + if (RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + L"Software\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards", + 0, + KEY_READ, + &network_cards_key) != ERROR_SUCCESS) { + return false; + } + assert(network_cards_key); + + for (int i = 0; ; ++i) { + TCHAR name[kStringLength]; + DWORD name_size = kStringLength; + FILETIME time; + if (RegEnumKeyEx(network_cards_key, + i, + name, + &name_size, + NULL, + NULL, + NULL, + &time) != ERROR_SUCCESS) { + break; + } + HKEY hardware_key = NULL; + if (RegOpenKeyEx(network_cards_key, name, 0, KEY_READ, &hardware_key) != + ERROR_SUCCESS) { + break; + } + assert(hardware_key); + + TCHAR service_name[kStringLength]; + DWORD service_name_size = kStringLength; + DWORD type = 0; + if (RegQueryValueEx(hardware_key, + L"ServiceName", + NULL, + &type, + reinterpret_cast<LPBYTE>(service_name), + &service_name_size) == ERROR_SUCCESS) { + interface_service_names_.push_back(service_name); + } + RegCloseKey(hardware_key); + } + + RegCloseKey(network_cards_key); + return true; +} + +bool Win32WifiDataProvider::GetAccessPointDataNDIS( + WifiData::AccessPointDataSet *data) { + assert(data); + + for (int i = 0; i < static_cast<int>(interface_service_names_.size()); ++i) { + // First, check that we have a DOS device for this adapter. + if (!DefineDosDeviceIfNotExists(interface_service_names_[i])) { + continue; + } + + // Get the handle to the device. This will fail if the named device is not + // valid. + HANDLE adapter_handle = GetFileHandle(interface_service_names_[i]); + if (adapter_handle == INVALID_HANDLE_VALUE) { + continue; + } + + // Get the data. + GetInterfaceDataNDIS(adapter_handle, data); + + // Clean up. + CloseHandle(adapter_handle); + UndefineDosDevice(interface_service_names_[i]); + } + + return true; +} + +bool Win32WifiDataProvider::GetInterfaceDataNDIS( + HANDLE adapter_handle, + WifiData::AccessPointDataSet *data) { + assert(data); + + BYTE *buffer = reinterpret_cast<BYTE*>(malloc(oid_buffer_size_)); + if (buffer == NULL) { + return false; + } + + DWORD bytes_out; + int result; + + while (true) { + bytes_out = 0; + result = PerformQuery(adapter_handle, buffer, oid_buffer_size_, &bytes_out); + if (result == ERROR_GEN_FAILURE || // Returned by some Intel cards. + result == ERROR_INSUFFICIENT_BUFFER || + result == ERROR_MORE_DATA || + result == NDIS_STATUS_INVALID_LENGTH || + result == NDIS_STATUS_BUFFER_TOO_SHORT) { + // The buffer we supplied is too small, so increase it. bytes_out should + // provide the required buffer size, but this is not always the case. + if (bytes_out > static_cast<DWORD>(oid_buffer_size_)) { + oid_buffer_size_ = bytes_out; + } else { + oid_buffer_size_ *= 2; + } + if (!ResizeBuffer(oid_buffer_size_, &buffer)) { + oid_buffer_size_ = kInitialBufferSize; // Reset for next time. + return false; + } + } else { + // The buffer is not too small. + break; + } + } + assert(buffer); + + if (result == ERROR_SUCCESS) { + NDIS_802_11_BSSID_LIST* bssid_list = + reinterpret_cast<NDIS_802_11_BSSID_LIST*>(buffer); + GetDataFromBssIdList(*bssid_list, oid_buffer_size_, data); + } + + free(buffer); + return true; +} + +// Local functions + +static bool GetNetworkData(const WLAN_BSS_ENTRY &bss_entry, + AccessPointData *access_point_data) { + // Currently we get only MAC address, signal strength and SSID. + assert(access_point_data); + access_point_data->mac_address = MacAddressAsString16(bss_entry.dot11Bssid); + access_point_data->radio_signal_strength = bss_entry.lRssi; + // bss_entry.dot11Ssid.ucSSID is not null-terminated. + UTF8ToString16(reinterpret_cast<const char*>(bss_entry.dot11Ssid.ucSSID), + static_cast<ULONG>(bss_entry.dot11Ssid.uSSIDLength), + &access_point_data->ssid); + // TODO(steveblock): Is it possible to get the following? + //access_point_data->signal_to_noise + //access_point_data->age + //access_point_data->channel + return true; +} + +bool UndefineDosDevice(const std::string16 &device_name) { + // We remove only the mapping we use, that is \Device\<device_name>. + std::string16 target_path = L"\\Device\\" + device_name; + return DefineDosDevice( + DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE, + device_name.c_str(), + target_path.c_str()) == TRUE; +} + +bool DefineDosDeviceIfNotExists(const std::string16 &device_name) { + // We create a DOS device name for the device at \Device\<device_name>. + std::string16 target_path = L"\\Device\\" + device_name; + + TCHAR target[kStringLength]; + if (QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 && + target_path.compare(target) == 0) { + // Device already exists. + return true; + } + + if (GetLastError() != ERROR_FILE_NOT_FOUND) { + return false; + } + + if (!DefineDosDevice(DDD_RAW_TARGET_PATH, + device_name.c_str(), + target_path.c_str())) { + return false; + } + + // Check that the device is really there. + return QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 && + target_path.compare(target) == 0; +} + +HANDLE GetFileHandle(const std::string16 &device_name) { + // We access a device with DOS path \Device\<device_name> at + // \\.\<device_name>. + std::string16 formatted_device_name = L"\\\\.\\" + device_name; + + return CreateFile(formatted_device_name.c_str(), + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, // share mode + 0, // security attributes + OPEN_EXISTING, + 0, // flags and attributes + INVALID_HANDLE_VALUE); +} + +int PerformQuery(HANDLE adapter_handle, + BYTE *buffer, + DWORD buffer_size, + DWORD *bytes_out) { + DWORD oid = OID_802_11_BSSID_LIST; + if (!DeviceIoControl(adapter_handle, + IOCTL_NDIS_QUERY_GLOBAL_STATS, + &oid, + sizeof(oid), + buffer, + buffer_size, + bytes_out, + NULL)) { + return GetLastError(); + } + return ERROR_SUCCESS; +} + +bool ResizeBuffer(int requested_size, BYTE **buffer) { + if (requested_size > kMaximumBufferSize) { + free(*buffer); + *buffer = NULL; + return false; + } + + BYTE *new_buffer = reinterpret_cast<BYTE*>(realloc(*buffer, requested_size)); + if (new_buffer == NULL) { + free(*buffer); + *buffer = NULL; + return false; + } + + *buffer = new_buffer; + return true; +} + +bool GetSystemDirectory(std::string16 *path) { + assert(path); + // Return value includes terminating NULL. + int buffer_size = GetSystemDirectory(NULL, 0); + if (buffer_size == 0) { + return false; + } + char16 *buffer = new char16[buffer_size]; + + // Return value excludes terminating NULL. + int characters_written = GetSystemDirectory(buffer, buffer_size); + if (characters_written == 0) { + return false; + } + assert(characters_written == buffer_size - 1); + + path->assign(buffer); + delete[] buffer; + + if (path->at(path->length() - 1) != L'\\') { + path->append(L"\\"); + } + return true; +} + +#endif // WIN32 && !OS_WINCE diff --git a/chrome/browser/geolocation/wifi_data_provider_win.h b/chrome/browser/geolocation/wifi_data_provider_win.h new file mode 100644 index 0000000..81b2274 --- /dev/null +++ b/chrome/browser/geolocation/wifi_data_provider_win.h @@ -0,0 +1,87 @@ +// 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. + +#ifndef GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_WIN32_H__ +#define GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_WIN32_H__ + +#include <vector> +#include "gears/base/common/common.h" +#include "gears/base/common/thread.h" +#include "gears/geolocation/device_data_provider.h" +#include "gears/geolocation/wlanapi.h" + +class Win32WifiDataProvider + : public WifiDataProviderImplBase, + public Thread { + public: + Win32WifiDataProvider(); + virtual ~Win32WifiDataProvider(); + + // WifiDataProviderImplBase implementation + virtual bool GetData(WifiData *data); + + private: + // Thread implementation + virtual void Run(); + + // WLAN methods + // Loads the required functions from the DLL. + void GetWLANFunctions(HINSTANCE wlan_library); + // Gets wifi data for all visible access points. + bool GetAccessPointDataWLAN(WifiData::AccessPointDataSet *data); + int GetInterfaceDataWLAN(HANDLE wlan_handle, + const GUID &interface_id, + WifiData::AccessPointDataSet *data); + + // NDIS methods. + bool GetInterfacesNDIS(); + bool GetAccessPointDataNDIS(WifiData::AccessPointDataSet *data); + bool GetInterfaceDataNDIS(HANDLE adapter_handle, + WifiData::AccessPointDataSet *data); + + // Function pointers for WLAN + WlanOpenHandleFunction WlanOpenHandle_function_; + WlanEnumInterfacesFunction WlanEnumInterfaces_function_; + WlanGetNetworkBssListFunction WlanGetNetworkBssList_function_; + WlanFreeMemoryFunction WlanFreeMemory_function_; + WlanCloseHandleFunction WlanCloseHandle_function_; + + // NDIS variables. + std::vector<std::string16> interface_service_names_; + int oid_buffer_size_; + + WifiData wifi_data_; + Mutex data_mutex_; + // Events signalled to shut down the thread that polls for wifi data. + Event stop_event_; + + // Whether we've successfully completed a scan for WiFi data (or the polling + // thread has terminated early). + bool is_first_scan_complete_; + + DISALLOW_EVIL_CONSTRUCTORS(Win32WifiDataProvider); +}; + +#endif // GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_WIN32_H__ diff --git a/chrome/browser/geolocation/wifi_data_provider_windows_common.cc b/chrome/browser/geolocation/wifi_data_provider_windows_common.cc new file mode 100644 index 0000000..d367c90 --- /dev/null +++ b/chrome/browser/geolocation/wifi_data_provider_windows_common.cc @@ -0,0 +1,76 @@ +// 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. + +#if defined(WIN32) || defined(OS_WINCE) + +#include "gears/geolocation/wifi_data_provider_windows_common.h" + +#include <assert.h> +#include "gears/base/common/string_utils.h" +#include "gears/geolocation/device_data_provider.h" +#include "gears/geolocation/wifi_data_provider_common.h" + +bool ConvertToGearsFormat(const NDIS_WLAN_BSSID &data, + AccessPointData *access_point_data) { + // Currently we get only MAC address, signal strength and SSID. + // TODO(steveblock): Work out how to get age, channel and signal-to-noise. + assert(access_point_data); + access_point_data->mac_address = MacAddressAsString16(data.MacAddress); + access_point_data->radio_signal_strength = data.Rssi; + // Note that _NDIS_802_11_SSID::Ssid::Ssid is not null-terminated. + UTF8ToString16(reinterpret_cast<const char*>(data.Ssid.Ssid), + data.Ssid.SsidLength, + &access_point_data->ssid); + return true; +} + +int GetDataFromBssIdList(const NDIS_802_11_BSSID_LIST &bss_id_list, + int list_size, + WifiData::AccessPointDataSet *data) { + // Walk through the BSS IDs. + int found = 0; + const uint8 *iterator = reinterpret_cast<const uint8*>(&bss_id_list.Bssid[0]); + const uint8 *end_of_buffer = + reinterpret_cast<const uint8*>(&bss_id_list) + list_size; + for (int i = 0; i < static_cast<int>(bss_id_list.NumberOfItems); ++i) { + const NDIS_WLAN_BSSID *bss_id = + reinterpret_cast<const NDIS_WLAN_BSSID*>(iterator); + // Check that the length of this BSS ID is reasonable. + if (bss_id->Length < sizeof(NDIS_WLAN_BSSID) || + iterator + bss_id->Length > end_of_buffer) { + break; + } + AccessPointData access_point_data; + if (ConvertToGearsFormat(*bss_id, &access_point_data)) { + data->insert(access_point_data); + ++found; + } + // Move to the next BSS ID. + iterator += bss_id->Length; + } + return found; +} + +#endif // WIN32 || OS_WINCE diff --git a/chrome/browser/geolocation/wifi_data_provider_windows_common.h b/chrome/browser/geolocation/wifi_data_provider_windows_common.h new file mode 100644 index 0000000..e2e0873 --- /dev/null +++ b/chrome/browser/geolocation/wifi_data_provider_windows_common.h @@ -0,0 +1,45 @@ +// 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. +// +// This file contains functions which are common to both the WIN32 and WINCE +// implementations of the wifi data provider. + +#ifndef GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_WINDOWS_COMMON_H__ +#define GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_WINDOWS_COMMON_H__ + +#include <windows.h> +#include <ntddndis.h> +#include <vector> +#include "gears/geolocation/device_data_provider.h" + + +// Extracts access point data from the NDIS_802_11_BSSID_LIST structure and +// appends it to the data vector. Returns the number of access points for which +// data was extracted. +int GetDataFromBssIdList(const NDIS_802_11_BSSID_LIST &bss_id_list, + int list_size, + WifiData::AccessPointDataSet *data); + +#endif // GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_WINDOWS_COMMON_H__ |