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

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

Issue 553069: Revert 37009 - Adding geolocation data provider infrastructure to Chrome.... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 10 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2008, Google Inc.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are met:
5 //
6 // 1. Redistributions of source code must retain the above copyright notice,
7 // this list of conditions and the following disclaimer.
8 // 2. Redistributions in binary form must reproduce the above copyright notice,
9 // this list of conditions and the following disclaimer in the documentation
10 // and/or other materials provided with the distribution.
11 // 3. Neither the name of Google Inc. nor the names of its contributors may be
12 // used to endorse or promote products derived from this software without
13 // specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 //
26 // Windows Vista uses the Native Wifi (WLAN) API for accessing WiFi cards. See
27 // http://msdn.microsoft.com/en-us/library/ms705945(VS.85).aspx. Windows XP
28 // Service Pack 3 (and Windows XP Service Pack 2, if upgraded with a hot fix)
29 // also support a limited version of the WLAN API. See
30 // http://msdn.microsoft.com/en-us/library/bb204766.aspx. The WLAN API uses
31 // wlanapi.h, which is not part of the SDK used by Gears, so is replicated
32 // locally using data from the MSDN.
33 //
34 // Windows XP from Service Pack 2 onwards supports the Wireless Zero
35 // Configuration (WZC) programming interface. See
36 // http://msdn.microsoft.com/en-us/library/ms706587(VS.85).aspx.
37 //
38 // The MSDN recommends that one use the WLAN API where available, and WZC
39 // otherwise.
40 //
41 // However, it seems that WZC fails for some wireless cards. Also, WLAN seems
42 // not to work on XP SP3. So we use WLAN on Vista, and use NDIS directly
43 // otherwise.
44
45 // TODO(cprince): remove platform-specific #ifdef guards when OS-specific
46 // sources (e.g. WIN32_CPPSRCS) are implemented
47 #if defined(WIN32) && !defined(OS_WINCE)
48
49 #include "gears/geolocation/wifi_data_provider_win32.h"
50
51 #include <windows.h>
52 #include <ntddndis.h> // For IOCTL_NDIS_QUERY_GLOBAL_STATS
53 #include "gears/base/common/string_utils.h"
54 #include "gears/base/common/vista_utils.h"
55 #include "gears/geolocation/wifi_data_provider_common.h"
56 #include "gears/geolocation/wifi_data_provider_windows_common.h"
57
58 // Taken from ndis.h for WinCE.
59 #define NDIS_STATUS_INVALID_LENGTH ((NDIS_STATUS)0xC0010014L)
60 #define NDIS_STATUS_BUFFER_TOO_SHORT ((NDIS_STATUS)0xC0010016L)
61
62 // The limits on the size of the buffer used for the OID query.
63 static const int kInitialBufferSize = 2 << 12; // Good for about 50 APs.
64 static const int kMaximumBufferSize = 2 << 20; // 2MB
65
66 // Length for generic string buffers passed to Win32 APIs.
67 static const int kStringLength = 512;
68
69 // The time periods, in milliseconds, between successive polls of the wifi data.
70 extern const int kDefaultPollingInterval = 10000; // 10s
71 extern const int kNoChangePollingInterval = 120000; // 2 mins
72 extern const int kTwoNoChangePollingInterval = 600000; // 10 mins
73
74 // Local functions
75
76 // Extracts data for an access point and converts to Gears format.
77 static bool GetNetworkData(const WLAN_BSS_ENTRY &bss_entry,
78 AccessPointData *access_point_data);
79 bool UndefineDosDevice(const std::string16 &device_name);
80 bool DefineDosDeviceIfNotExists(const std::string16 &device_name);
81 HANDLE GetFileHandle(const std::string16 &device_name);
82 // Makes the OID query and returns a Win32 error code.
83 int PerformQuery(HANDLE adapter_handle,
84 BYTE *buffer,
85 DWORD buffer_size,
86 DWORD *bytes_out);
87 bool ResizeBuffer(int requested_size, BYTE **buffer);
88 // Gets the system directory and appends a trailing slash if not already
89 // present.
90 bool GetSystemDirectory(std::string16 *path);
91
92 // static
93 template<>
94 WifiDataProviderImplBase *WifiDataProvider::DefaultFactoryFunction() {
95 return new Win32WifiDataProvider();
96 }
97
98
99 Win32WifiDataProvider::Win32WifiDataProvider()
100 : oid_buffer_size_(kInitialBufferSize),
101 is_first_scan_complete_(false) {
102 // Start the polling thread.
103 Start();
104 }
105
106 Win32WifiDataProvider::~Win32WifiDataProvider() {
107 stop_event_.Signal();
108 Join();
109 }
110
111 bool Win32WifiDataProvider::GetData(WifiData *data) {
112 assert(data);
113 MutexLock lock(&data_mutex_);
114 *data = wifi_data_;
115 // If we've successfully completed a scan, indicate that we have all of the
116 // data we can get.
117 return is_first_scan_complete_;
118 }
119
120 // Thread implementation
121 void Win32WifiDataProvider::Run() {
122 // We use an absolute path to load the DLL to avoid DLL preloading attacks.
123 HINSTANCE library = NULL;
124 std::string16 system_directory;
125 if (GetSystemDirectory(&system_directory)) {
126 assert(!system_directory.empty());
127 std::string16 dll_path = system_directory + L"wlanapi.dll";
128 library = LoadLibraryEx(dll_path.c_str(),
129 NULL,
130 LOAD_WITH_ALTERED_SEARCH_PATH);
131 }
132
133 // Use the WLAN interface if we're on Vista and if it's available. Otherwise,
134 // use NDIS.
135 typedef bool (Win32WifiDataProvider::*GetAccessPointDataFunction)(
136 WifiData::AccessPointDataSet *data);
137 GetAccessPointDataFunction get_access_point_data_function = NULL;
138 if (VistaUtils::IsRunningOnVista() && library) {
139 GetWLANFunctions(library);
140 get_access_point_data_function =
141 &Win32WifiDataProvider::GetAccessPointDataWLAN;
142 } else {
143 // We assume the list of interfaces doesn't change while Gears is running.
144 if (!GetInterfacesNDIS()) {
145 is_first_scan_complete_ = true;
146 return;
147 }
148 get_access_point_data_function =
149 &Win32WifiDataProvider::GetAccessPointDataNDIS;
150 }
151 assert(get_access_point_data_function);
152
153 int polling_interval = kDefaultPollingInterval;
154 // Regularly get the access point data.
155 do {
156 WifiData new_data;
157 if ((this->*get_access_point_data_function)(&new_data.access_point_data)) {
158 bool update_available;
159 data_mutex_.Lock();
160 update_available = wifi_data_.DiffersSignificantly(new_data);
161 wifi_data_ = new_data;
162 data_mutex_.Unlock();
163 polling_interval =
164 UpdatePollingInterval(polling_interval, update_available);
165 if (update_available) {
166 is_first_scan_complete_ = true;
167 NotifyListeners();
168 }
169 }
170 } while (!stop_event_.WaitWithTimeout(polling_interval));
171
172 FreeLibrary(library);
173 }
174
175 // WLAN functions
176
177 void Win32WifiDataProvider::GetWLANFunctions(HINSTANCE wlan_library) {
178 assert(wlan_library);
179 WlanOpenHandle_function_ = reinterpret_cast<WlanOpenHandleFunction>(
180 GetProcAddress(wlan_library, "WlanOpenHandle"));
181 WlanEnumInterfaces_function_ = reinterpret_cast<WlanEnumInterfacesFunction>(
182 GetProcAddress(wlan_library, "WlanEnumInterfaces"));
183 WlanGetNetworkBssList_function_ =
184 reinterpret_cast<WlanGetNetworkBssListFunction>(
185 GetProcAddress(wlan_library, "WlanGetNetworkBssList"));
186 WlanFreeMemory_function_ = reinterpret_cast<WlanFreeMemoryFunction>(
187 GetProcAddress(wlan_library, "WlanFreeMemory"));
188 WlanCloseHandle_function_ = reinterpret_cast<WlanCloseHandleFunction>(
189 GetProcAddress(wlan_library, "WlanCloseHandle"));
190 assert(WlanOpenHandle_function_ &&
191 WlanEnumInterfaces_function_ &&
192 WlanGetNetworkBssList_function_ &&
193 WlanFreeMemory_function_ &&
194 WlanCloseHandle_function_);
195 }
196
197 bool Win32WifiDataProvider::GetAccessPointDataWLAN(
198 WifiData::AccessPointDataSet *data) {
199 assert(data);
200
201 // Get the handle to the WLAN API.
202 DWORD negotiated_version;
203 HANDLE wlan_handle = NULL;
204 // We could be executing on either Windows XP or Windows Vista, so use the
205 // lower version of the client WLAN API. It seems that the negotiated version
206 // is the Vista version irrespective of what we pass!
207 static const int kXpWlanClientVersion = 1;
208 if ((*WlanOpenHandle_function_)(kXpWlanClientVersion,
209 NULL,
210 &negotiated_version,
211 &wlan_handle) != ERROR_SUCCESS) {
212 return false;
213 }
214 assert(wlan_handle);
215
216 // Get the list of interfaces. WlanEnumInterfaces allocates interface_list.
217 WLAN_INTERFACE_INFO_LIST *interface_list = NULL;
218 if ((*WlanEnumInterfaces_function_)(wlan_handle, NULL, &interface_list) !=
219 ERROR_SUCCESS) {
220 return false;
221 }
222 assert(interface_list);
223
224 // Go through the list of interfaces and get the data for each.
225 for (int i = 0; i < static_cast<int>(interface_list->dwNumberOfItems); ++i) {
226 GetInterfaceDataWLAN(wlan_handle,
227 interface_list->InterfaceInfo[i].InterfaceGuid,
228 data);
229 }
230
231 // Free interface_list.
232 (*WlanFreeMemory_function_)(interface_list);
233
234 // Close the handle.
235 if ((*WlanCloseHandle_function_)(wlan_handle, NULL) != ERROR_SUCCESS) {
236 return false;
237 }
238
239 return true;
240 }
241
242 // Appends the data for a single interface to the data vector. Returns the
243 // number of access points found, or -1 on error.
244 int Win32WifiDataProvider::GetInterfaceDataWLAN(
245 const HANDLE wlan_handle,
246 const GUID &interface_id,
247 WifiData::AccessPointDataSet *data) {
248 assert(data);
249 // WlanGetNetworkBssList allocates bss_list.
250 WLAN_BSS_LIST *bss_list;
251 if ((*WlanGetNetworkBssList_function_)(wlan_handle,
252 &interface_id,
253 NULL, // Use all SSIDs.
254 DOT11_BSS_TYPE_UNUSED,
255 false, // bSecurityEnabled - unused
256 NULL, // reserved
257 &bss_list) != ERROR_SUCCESS) {
258 return -1;
259 }
260
261 int found = 0;
262 for (int i = 0; i < static_cast<int>(bss_list->dwNumberOfItems); ++i) {
263 AccessPointData access_point_data;
264 if (GetNetworkData(bss_list->wlanBssEntries[i], &access_point_data)) {
265 ++found;
266 data->insert(access_point_data);
267 }
268 }
269
270 (*WlanFreeMemory_function_)(bss_list);
271
272 return found;
273 }
274
275 // NDIS functions
276
277 bool Win32WifiDataProvider::GetInterfacesNDIS() {
278 HKEY network_cards_key = NULL;
279 if (RegOpenKeyEx(
280 HKEY_LOCAL_MACHINE,
281 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards",
282 0,
283 KEY_READ,
284 &network_cards_key) != ERROR_SUCCESS) {
285 return false;
286 }
287 assert(network_cards_key);
288
289 for (int i = 0; ; ++i) {
290 TCHAR name[kStringLength];
291 DWORD name_size = kStringLength;
292 FILETIME time;
293 if (RegEnumKeyEx(network_cards_key,
294 i,
295 name,
296 &name_size,
297 NULL,
298 NULL,
299 NULL,
300 &time) != ERROR_SUCCESS) {
301 break;
302 }
303 HKEY hardware_key = NULL;
304 if (RegOpenKeyEx(network_cards_key, name, 0, KEY_READ, &hardware_key) !=
305 ERROR_SUCCESS) {
306 break;
307 }
308 assert(hardware_key);
309
310 TCHAR service_name[kStringLength];
311 DWORD service_name_size = kStringLength;
312 DWORD type = 0;
313 if (RegQueryValueEx(hardware_key,
314 L"ServiceName",
315 NULL,
316 &type,
317 reinterpret_cast<LPBYTE>(service_name),
318 &service_name_size) == ERROR_SUCCESS) {
319 interface_service_names_.push_back(service_name);
320 }
321 RegCloseKey(hardware_key);
322 }
323
324 RegCloseKey(network_cards_key);
325 return true;
326 }
327
328 bool Win32WifiDataProvider::GetAccessPointDataNDIS(
329 WifiData::AccessPointDataSet *data) {
330 assert(data);
331
332 for (int i = 0; i < static_cast<int>(interface_service_names_.size()); ++i) {
333 // First, check that we have a DOS device for this adapter.
334 if (!DefineDosDeviceIfNotExists(interface_service_names_[i])) {
335 continue;
336 }
337
338 // Get the handle to the device. This will fail if the named device is not
339 // valid.
340 HANDLE adapter_handle = GetFileHandle(interface_service_names_[i]);
341 if (adapter_handle == INVALID_HANDLE_VALUE) {
342 continue;
343 }
344
345 // Get the data.
346 GetInterfaceDataNDIS(adapter_handle, data);
347
348 // Clean up.
349 CloseHandle(adapter_handle);
350 UndefineDosDevice(interface_service_names_[i]);
351 }
352
353 return true;
354 }
355
356 bool Win32WifiDataProvider::GetInterfaceDataNDIS(
357 HANDLE adapter_handle,
358 WifiData::AccessPointDataSet *data) {
359 assert(data);
360
361 BYTE *buffer = reinterpret_cast<BYTE*>(malloc(oid_buffer_size_));
362 if (buffer == NULL) {
363 return false;
364 }
365
366 DWORD bytes_out;
367 int result;
368
369 while (true) {
370 bytes_out = 0;
371 result = PerformQuery(adapter_handle, buffer, oid_buffer_size_, &bytes_out);
372 if (result == ERROR_GEN_FAILURE || // Returned by some Intel cards.
373 result == ERROR_INSUFFICIENT_BUFFER ||
374 result == ERROR_MORE_DATA ||
375 result == NDIS_STATUS_INVALID_LENGTH ||
376 result == NDIS_STATUS_BUFFER_TOO_SHORT) {
377 // The buffer we supplied is too small, so increase it. bytes_out should
378 // provide the required buffer size, but this is not always the case.
379 if (bytes_out > static_cast<DWORD>(oid_buffer_size_)) {
380 oid_buffer_size_ = bytes_out;
381 } else {
382 oid_buffer_size_ *= 2;
383 }
384 if (!ResizeBuffer(oid_buffer_size_, &buffer)) {
385 oid_buffer_size_ = kInitialBufferSize; // Reset for next time.
386 return false;
387 }
388 } else {
389 // The buffer is not too small.
390 break;
391 }
392 }
393 assert(buffer);
394
395 if (result == ERROR_SUCCESS) {
396 NDIS_802_11_BSSID_LIST* bssid_list =
397 reinterpret_cast<NDIS_802_11_BSSID_LIST*>(buffer);
398 GetDataFromBssIdList(*bssid_list, oid_buffer_size_, data);
399 }
400
401 free(buffer);
402 return true;
403 }
404
405 // Local functions
406
407 static bool GetNetworkData(const WLAN_BSS_ENTRY &bss_entry,
408 AccessPointData *access_point_data) {
409 // Currently we get only MAC address, signal strength and SSID.
410 assert(access_point_data);
411 access_point_data->mac_address = MacAddressAsString16(bss_entry.dot11Bssid);
412 access_point_data->radio_signal_strength = bss_entry.lRssi;
413 // bss_entry.dot11Ssid.ucSSID is not null-terminated.
414 UTF8ToString16(reinterpret_cast<const char*>(bss_entry.dot11Ssid.ucSSID),
415 static_cast<ULONG>(bss_entry.dot11Ssid.uSSIDLength),
416 &access_point_data->ssid);
417 // TODO(steveblock): Is it possible to get the following?
418 //access_point_data->signal_to_noise
419 //access_point_data->age
420 //access_point_data->channel
421 return true;
422 }
423
424 bool UndefineDosDevice(const std::string16 &device_name) {
425 // We remove only the mapping we use, that is \Device\<device_name>.
426 std::string16 target_path = L"\\Device\\" + device_name;
427 return DefineDosDevice(
428 DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
429 device_name.c_str(),
430 target_path.c_str()) == TRUE;
431 }
432
433 bool DefineDosDeviceIfNotExists(const std::string16 &device_name) {
434 // We create a DOS device name for the device at \Device\<device_name>.
435 std::string16 target_path = L"\\Device\\" + device_name;
436
437 TCHAR target[kStringLength];
438 if (QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 &&
439 target_path.compare(target) == 0) {
440 // Device already exists.
441 return true;
442 }
443
444 if (GetLastError() != ERROR_FILE_NOT_FOUND) {
445 return false;
446 }
447
448 if (!DefineDosDevice(DDD_RAW_TARGET_PATH,
449 device_name.c_str(),
450 target_path.c_str())) {
451 return false;
452 }
453
454 // Check that the device is really there.
455 return QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 &&
456 target_path.compare(target) == 0;
457 }
458
459 HANDLE GetFileHandle(const std::string16 &device_name) {
460 // We access a device with DOS path \Device\<device_name> at
461 // \\.\<device_name>.
462 std::string16 formatted_device_name = L"\\\\.\\" + device_name;
463
464 return CreateFile(formatted_device_name.c_str(),
465 GENERIC_READ,
466 FILE_SHARE_READ | FILE_SHARE_WRITE, // share mode
467 0, // security attributes
468 OPEN_EXISTING,
469 0, // flags and attributes
470 INVALID_HANDLE_VALUE);
471 }
472
473 int PerformQuery(HANDLE adapter_handle,
474 BYTE *buffer,
475 DWORD buffer_size,
476 DWORD *bytes_out) {
477 DWORD oid = OID_802_11_BSSID_LIST;
478 if (!DeviceIoControl(adapter_handle,
479 IOCTL_NDIS_QUERY_GLOBAL_STATS,
480 &oid,
481 sizeof(oid),
482 buffer,
483 buffer_size,
484 bytes_out,
485 NULL)) {
486 return GetLastError();
487 }
488 return ERROR_SUCCESS;
489 }
490
491 bool ResizeBuffer(int requested_size, BYTE **buffer) {
492 if (requested_size > kMaximumBufferSize) {
493 free(*buffer);
494 *buffer = NULL;
495 return false;
496 }
497
498 BYTE *new_buffer = reinterpret_cast<BYTE*>(realloc(*buffer, requested_size));
499 if (new_buffer == NULL) {
500 free(*buffer);
501 *buffer = NULL;
502 return false;
503 }
504
505 *buffer = new_buffer;
506 return true;
507 }
508
509 bool GetSystemDirectory(std::string16 *path) {
510 assert(path);
511 // Return value includes terminating NULL.
512 int buffer_size = GetSystemDirectory(NULL, 0);
513 if (buffer_size == 0) {
514 return false;
515 }
516 char16 *buffer = new char16[buffer_size];
517
518 // Return value excludes terminating NULL.
519 int characters_written = GetSystemDirectory(buffer, buffer_size);
520 if (characters_written == 0) {
521 return false;
522 }
523 assert(characters_written == buffer_size - 1);
524
525 path->assign(buffer);
526 delete[] buffer;
527
528 if (path->at(path->length() - 1) != L'\\') {
529 path->append(L"\\");
530 }
531 return true;
532 }
533
534 #endif // WIN32 && !OS_WINCE
OLDNEW
« no previous file with comments | « chrome/browser/geolocation/wifi_data_provider_win.h ('k') | chrome/browser/geolocation/wifi_data_provider_windows_common.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698