- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / geolocation / wifi_data_provider_mac.cc
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // For OSX 10.5 we use the system API function WirelessScanSplit. This function
6 // is not documented or included in the SDK, so we use a reverse-engineered
7 // header, osx_wifi_.h. This file is taken from the iStumbler project
8 // (http://www.istumbler.net).
9
10 #include "content/browser/geolocation/wifi_data_provider_mac.h"
11
12 #include <dlfcn.h>
13 #include <stdio.h>
14
15 #include "base/strings/utf_string_conversions.h"
16 #include "content/browser/geolocation/osx_wifi.h"
17 #include "content/browser/geolocation/wifi_data_provider_common.h"
18
19 namespace content {
20 namespace {
21 // The time periods, in milliseconds, between successive polls of the wifi data.
22 const int kDefaultPollingInterval = 120000;  // 2 mins
23 const int kNoChangePollingInterval = 300000;  // 5 mins
24 const int kTwoNoChangePollingInterval = 600000;  // 10 mins
25 const int kNoWifiPollingIntervalMilliseconds = 20 * 1000; // 20s
26
27 // Provides the wifi API binding for use when running on OSX 10.5 machines using
28 // the Apple80211 framework.
29 class Apple80211Api : public WifiDataProviderCommon::WlanApiInterface {
30  public:
31   Apple80211Api();
32   virtual ~Apple80211Api();
33
34   // Must be called before any other interface method. Will return false if the
35   // Apple80211 framework cannot be initialized (e.g. running on post-10.5 OSX),
36   // in which case no other method may be called.
37   bool Init();
38
39   // WlanApiInterface
40   virtual bool GetAccessPointData(WifiData::AccessPointDataSet* data) OVERRIDE;
41
42  private:
43   // Handle, context and function pointers for Apple80211 library.
44   void* apple_80211_library_;
45   WirelessContext* wifi_context_;
46   WirelessAttachFunction WirelessAttach_function_;
47   WirelessScanSplitFunction WirelessScanSplit_function_;
48   WirelessDetachFunction WirelessDetach_function_;
49
50   WifiData wifi_data_;
51
52   DISALLOW_COPY_AND_ASSIGN(Apple80211Api);
53 };
54
55 Apple80211Api::Apple80211Api()
56     : apple_80211_library_(NULL), wifi_context_(NULL),
57       WirelessAttach_function_(NULL), WirelessScanSplit_function_(NULL),
58       WirelessDetach_function_(NULL) {
59 }
60
61 Apple80211Api::~Apple80211Api() {
62   if (WirelessDetach_function_)
63     (*WirelessDetach_function_)(wifi_context_);
64   dlclose(apple_80211_library_);
65 }
66
67 bool Apple80211Api::Init() {
68   DVLOG(1) << "Apple80211Api::Init";
69   apple_80211_library_ = dlopen(
70       "/System/Library/PrivateFrameworks/Apple80211.framework/Apple80211",
71       RTLD_LAZY);
72   if (!apple_80211_library_) {
73     DLOG(WARNING) << "Could not open Apple80211 library";
74     return false;
75   }
76   WirelessAttach_function_ = reinterpret_cast<WirelessAttachFunction>(
77       dlsym(apple_80211_library_, "WirelessAttach"));
78   WirelessScanSplit_function_ = reinterpret_cast<WirelessScanSplitFunction>(
79       dlsym(apple_80211_library_, "WirelessScanSplit"));
80   WirelessDetach_function_ = reinterpret_cast<WirelessDetachFunction>(
81       dlsym(apple_80211_library_, "WirelessDetach"));
82   DCHECK(WirelessAttach_function_);
83   DCHECK(WirelessScanSplit_function_);
84   DCHECK(WirelessDetach_function_);
85
86   if (!WirelessAttach_function_ || !WirelessScanSplit_function_ ||
87       !WirelessDetach_function_) {
88     DLOG(WARNING) << "Symbol error. Attach: " << !!WirelessAttach_function_
89         << " Split: " << !!WirelessScanSplit_function_
90         << " Detach: " << !!WirelessDetach_function_;
91     return false;
92   }
93
94   WIErr err = (*WirelessAttach_function_)(&wifi_context_, 0);
95   if (err != noErr) {
96     DLOG(WARNING) << "Error attaching: " << err;
97     return false;
98   }
99   return true;
100 }
101
102 bool Apple80211Api::GetAccessPointData(WifiData::AccessPointDataSet* data) {
103   DVLOG(1) << "Apple80211Api::GetAccessPointData";
104   DCHECK(data);
105   DCHECK(WirelessScanSplit_function_);
106   CFArrayRef managed_access_points = NULL;
107   CFArrayRef adhoc_access_points = NULL;
108   // Arrays returned here are owned by the caller.
109   WIErr err = (*WirelessScanSplit_function_)(wifi_context_,
110                                              &managed_access_points,
111                                              &adhoc_access_points,
112                                              0);
113   if (err != noErr) {
114     DLOG(WARNING) << "Error spliting scan: " << err;
115     return false;
116   }
117
118   if (managed_access_points == NULL) {
119     DLOG(WARNING) << "managed_access_points == NULL";
120     return false;
121   }
122
123   int num_access_points = CFArrayGetCount(managed_access_points);
124   DVLOG(1) << "Found " << num_access_points << " managed access points";
125   for (int i = 0; i < num_access_points; ++i) {
126     const WirelessNetworkInfo* access_point_info =
127         reinterpret_cast<const WirelessNetworkInfo*>(
128         CFDataGetBytePtr(
129         reinterpret_cast<const CFDataRef>(
130         CFArrayGetValueAtIndex(managed_access_points, i))));
131
132     // Currently we get only MAC address, signal strength, channel
133     // signal-to-noise and SSID
134     AccessPointData access_point_data;
135     access_point_data.mac_address =
136         MacAddressAsString16(access_point_info->macAddress);
137     // WirelessNetworkInfo::signal appears to be signal strength in dBm.
138     access_point_data.radio_signal_strength = access_point_info->signal;
139     access_point_data.channel = access_point_info->channel;
140     // WirelessNetworkInfo::noise appears to be noise floor in dBm.
141     access_point_data.signal_to_noise = access_point_info->signal -
142                                         access_point_info->noise;
143     if (!UTF8ToUTF16(reinterpret_cast<const char*>(access_point_info->name),
144                      access_point_info->nameLen,
145                      &access_point_data.ssid)) {
146       access_point_data.ssid.clear();
147     }
148     data->insert(access_point_data);
149   }
150
151   if (managed_access_points)
152     CFRelease(managed_access_points);
153   if (adhoc_access_points)
154     CFRelease(adhoc_access_points);
155
156   return true;
157 }
158 }  // namespace
159
160 // static
161 WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() {
162   return new MacWifiDataProvider();
163 }
164
165 MacWifiDataProvider::MacWifiDataProvider() {
166 }
167
168 MacWifiDataProvider::~MacWifiDataProvider() {
169 }
170
171 MacWifiDataProvider::WlanApiInterface* MacWifiDataProvider::NewWlanApi() {
172   // Try and find a API binding that works: first try the officially supported
173   // CoreWLAN API, and if this fails (e.g. on OSX 10.5) fall back to the reverse
174   // engineered Apple80211 API.
175   MacWifiDataProvider::WlanApiInterface* core_wlan_api = NewCoreWlanApi();
176   if (core_wlan_api)
177     return core_wlan_api;
178
179   scoped_ptr<Apple80211Api> wlan_api(new Apple80211Api);
180   if (wlan_api->Init())
181     return wlan_api.release();
182
183   DVLOG(1) << "MacWifiDataProvider : failed to initialize any wlan api";
184   return NULL;
185 }
186
187 WifiPollingPolicy* MacWifiDataProvider::NewPollingPolicy() {
188   return new GenericWifiPollingPolicy<kDefaultPollingInterval,
189                                       kNoChangePollingInterval,
190                                       kTwoNoChangePollingInterval,
191                                       kNoWifiPollingIntervalMilliseconds>;
192 }
193
194 }  // namespace content