summaryrefslogtreecommitdiffstats
path: root/chrome/browser/geolocation
diff options
context:
space:
mode:
authorjoth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-26 17:59:34 +0000
committerjoth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-26 17:59:34 +0000
commit0e3c29f912080391a8126d319fdefc2836626d90 (patch)
treeaced47ae1749b68f59d149fcb0871d9073976c51 /chrome/browser/geolocation
parenta8846849618cc9a1ac1fef59657c7a818cdf3a9c (diff)
downloadchromium_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')
-rw-r--r--chrome/browser/geolocation/device_data_provider.h391
-rw-r--r--chrome/browser/geolocation/empty_device_data_provider.cc39
-rw-r--r--chrome/browser/geolocation/empty_device_data_provider.h51
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_common.cc95
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_common.h39
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_linux.cc279
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_linux.h59
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_osx.cc168
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_osx.h71
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_win.cc534
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_win.h87
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_windows_common.cc76
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_windows_common.h45
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__