diff options
author | Alex Zolotarev <deathbaba@gmail.com> | 2011-05-19 05:47:51 +0400 |
---|---|---|
committer | Alex Zolotarev <alex@maps.me> | 2015-09-23 01:17:42 +0300 |
commit | fb496023e71e47f5d957078396f70260fee521da (patch) | |
tree | 0547e1726a411dfe0a4dfec691de2baa72bc5f09 /platform/wifi_info_windows.cpp | |
parent | 942ab03f920b0fcaac28d21f1ab06d1da12fdc67 (diff) |
[win] My Position works using wifi or local router gateway
Diffstat (limited to 'platform/wifi_info_windows.cpp')
-rw-r--r-- | platform/wifi_info_windows.cpp | 263 |
1 files changed, 262 insertions, 1 deletions
diff --git a/platform/wifi_info_windows.cpp b/platform/wifi_info_windows.cpp index 742cf78890..2a226ec558 100644 --- a/platform/wifi_info_windows.cpp +++ b/platform/wifi_info_windows.cpp @@ -1,19 +1,275 @@ #include "../std/target_os.hpp" -#if defined(OMIM_OS_WINDOWS) +#ifdef OMIM_OS_WINDOWS #include "wifi_info.hpp" +#include "../base/logging.hpp" + +#include "../std/windows.hpp" +#include "../std/stdio.hpp" + +#include <winsock2.h> +#include <iphlpapi.h> + +bool GatewaysInfo(vector<WiFiInfo::AccessPoint> & out) +{ + vector<string> ips; + + ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO); + PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen); + if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) + { + free(pAdapterInfo); + pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen); + } + + if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == NO_ERROR) + { + PIP_ADAPTER_INFO pAdapter = pAdapterInfo; + while (pAdapter) + { + if (strcmp(pAdapter->GatewayList.IpAddress.String, "0.0.0.0")) + ips.push_back(pAdapter->GatewayList.IpAddress.String); + pAdapter = pAdapter->Next; + } + } + if (pAdapterInfo) + free(pAdapterInfo); + + if (!ips.empty()) + { + DWORD dwSize = 0; + GetIpNetTable(NULL, &dwSize, 0); + PMIB_IPNETTABLE pIpNetTable = (MIB_IPNETTABLE *)malloc(dwSize); + if (GetIpNetTable(pIpNetTable, &dwSize, 0) == NO_ERROR) + { + for (DWORD i = 0; i < pIpNetTable->dwNumEntries; ++i) + { + for (size_t j = 0; j < ips.size(); ++j) + { + if (ips[j] == inet_ntoa(*(struct in_addr *)&pIpNetTable->table[i].dwAddr) + && pIpNetTable->table[i].dwPhysAddrLen == 6) + { + char buff[20] = {}; + sprintf(buff, "%02X-%02X-%02X-%02X-%02X-%02X", + pIpNetTable->table[i].bPhysAddr[0], + pIpNetTable->table[i].bPhysAddr[1], + pIpNetTable->table[i].bPhysAddr[2], + pIpNetTable->table[i].bPhysAddr[3], + pIpNetTable->table[i].bPhysAddr[4], + pIpNetTable->table[i].bPhysAddr[5]); + WiFiInfo::AccessPoint apn; + apn.m_bssid = buff; + apn.m_signalStrength = "-34"; + apn.m_ssid = "dlink"; + out.push_back(apn); + } + } + } + } + free(pIpNetTable); + } + return !out.empty(); +} + +#if defined(OMIM_OS_WINDOWS_NATIVE) + +#include <wlanapi.h> +#include <objbase.h> +#include <wtypes.h> + +///////////////////////////////////////////////////////////////// class WiFiInfo::Impl { WiFiInfo::WifiRequestCallbackT m_callback; + HANDLE m_hClient; + bool m_isNotificationSupported; + + /// pointers to potential Vista-and-above functions + typedef DWORD (WINAPI *PWLANGETNETWORKBSSLIST)(HANDLE, const GUID *, const PDOT11_SSID, DOT11_BSS_TYPE, + BOOL, PVOID, PWLAN_BSS_LIST *); + PWLANGETNETWORKBSSLIST pWlanGetNetworkBssList; + + /// used only on XP + HANDLE m_timer; public: + Impl(); + ~Impl(); + HANDLE Handle() const { return m_hClient; } + void RequestWiFiBSSIDs(WifiRequestCallbackT callback); + void GetApnsAndNotifyClient(); + void StopNotifications(); +}; +///////////////////////////////////////////////////////////////// + +/// Called on Vista and above +VOID WINAPI OnWlanScanCompleted(PWLAN_NOTIFICATION_DATA data, PVOID context) +{ + switch (data->NotificationCode) + { + case wlan_notification_acm_scan_fail: + LOG(LDEBUG, ("WiFi scan failed with code", *((DWORD *)data->pData))); + // no break here! try to collect bssids anyway + case wlan_notification_acm_scan_complete: + { + WiFiInfo::Impl * impl = reinterpret_cast<WiFiInfo::Impl *>(context); + impl->GetApnsAndNotifyClient(); + } + break; + default: + LOG(LDEBUG, ("Unknown WiFi notification", data->NotificationCode)); + } +} + +/// Called only on XP by timer +VOID CALLBACK WaitOrTimerCallback(PVOID lpParameter, BOOLEAN) +{ + WiFiInfo::Impl * impl = reinterpret_cast<WiFiInfo::Impl *>(lpParameter); + impl->GetApnsAndNotifyClient(); +} + +WiFiInfo::Impl::Impl() : m_hClient(NULL), m_timer(NULL) +{ + DWORD dwMaxClient = 2; // 1 for WinXP, 2 for Vista and above + DWORD dwCurVersion = 0; + DWORD dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &m_hClient); + if (dwResult != ERROR_SUCCESS) + { + LOG(LWARNING, ("Error while opening WLAN handle", dwResult)); + } + m_isNotificationSupported = (dwCurVersion > 1); + pWlanGetNetworkBssList = (PWLANGETNETWORKBSSLIST)GetProcAddress(GetModuleHandleA("wlanapi.dll"), + "WlanGetNetworkBssList"); +} + +WiFiInfo::Impl::~Impl() +{ + WlanCloseHandle(m_hClient, NULL); +} + +void WiFiInfo::Impl::RequestWiFiBSSIDs(WifiRequestCallbackT callback) +{ + m_callback = callback; + // if it's XP without necessary api... use gateway instead + if (!pWlanGetNetworkBssList) + { + vector<WiFiInfo::AccessPoint> apns; + GatewaysInfo(apns); + callback(apns); + return; + } + + if (!m_isNotificationSupported) + { // request timer after 4 seconds, when scanning completes + CreateTimerQueueTimer(&m_timer, NULL, &WaitOrTimerCallback, this, + 4100, 0, WT_EXECUTEONLYONCE); + } + else + { // subscribe to notification when scanning is completed + WlanRegisterNotification(m_hClient, + WLAN_NOTIFICATION_SOURCE_ACM, + TRUE, + &OnWlanScanCompleted, + this, + NULL, + NULL); + } + // start scanning + PWLAN_INTERFACE_INFO_LIST pIfList = NULL; + DWORD dwResult = WlanEnumInterfaces(m_hClient, NULL, &pIfList); + if (dwResult == ERROR_SUCCESS) + { + for (int ifIndex = 0; ifIndex < static_cast<int>(pIfList->dwNumberOfItems); ++ifIndex) + { + PWLAN_INTERFACE_INFO pIfInfo = (PWLAN_INTERFACE_INFO)&pIfList->InterfaceInfo[ifIndex]; + WlanScan(m_hClient, &pIfInfo->InterfaceGuid, NULL, NULL, NULL); + } + WlanFreeMemory(pIfList); + } +} + +void WiFiInfo::Impl::GetApnsAndNotifyClient() +{ + vector<WiFiInfo::AccessPoint> apns; + PWLAN_INTERFACE_INFO_LIST pIfList = NULL; + DWORD dwResult = WlanEnumInterfaces(m_hClient, NULL, &pIfList); + if (dwResult == ERROR_SUCCESS) + { + for (int ifIndex = 0; ifIndex < static_cast<int>(pIfList->dwNumberOfItems); ++ifIndex) + { + PWLAN_INTERFACE_INFO pIfInfo = (PWLAN_INTERFACE_INFO)&pIfList->InterfaceInfo[ifIndex]; + PWLAN_BSS_LIST pWlanBssList = NULL; + if (pWlanGetNetworkBssList) + { // on WinXP we don't have this function :( + dwResult = pWlanGetNetworkBssList(m_hClient, + &pIfInfo->InterfaceGuid, + 0, + dot11_BSS_type_any, + FALSE, + NULL, + &pWlanBssList); + if (dwResult == ERROR_SUCCESS) + { + for (int wlanIndex = 0; wlanIndex < static_cast<int>(pWlanBssList->dwNumberOfItems); ++wlanIndex) + { + PWLAN_BSS_ENTRY pBssEntry = &pWlanBssList->wlanBssEntries[wlanIndex]; + WiFiInfo::AccessPoint apn; + apn.m_ssid.assign(&pBssEntry->dot11Ssid.ucSSID[0], + &pBssEntry->dot11Ssid.ucSSID[pBssEntry->dot11Ssid.uSSIDLength]); + char buff[20] = {}; + sprintf(buff, "%02X-%02X-%02X-%02X-%02X-%02X", + pBssEntry->dot11Bssid[0], pBssEntry->dot11Bssid[1], + pBssEntry->dot11Bssid[2], pBssEntry->dot11Bssid[3], + pBssEntry->dot11Bssid[4], pBssEntry->dot11Bssid[5]); + apn.m_bssid = buff; + sprintf(buff, "%ld", pBssEntry->lRssi); + apn.m_signalStrength = buff; + apns.push_back(apn); + } + WlanFreeMemory(pWlanBssList); + } + } + } + WlanFreeMemory(pIfList); + } + + m_callback(apns); + + // on WinXP, clean up timer if it was used + if (m_timer) + { + DeleteTimerQueueTimer(NULL, m_timer, NULL); + m_timer = NULL; + } +} + +void WiFiInfo::Impl::StopNotifications() +{ + WlanRegisterNotification(m_hClient, WLAN_NOTIFICATION_SOURCE_NONE, TRUE, NULL, NULL, NULL, NULL); +} +#else +/////////////////////////////////////////////////////////////////// +// MinGW doesn't support wlan api, so simply return mac address of the router + +class WiFiInfo::Impl +{ +public: + Impl() {} + ~Impl() {} void RequestWiFiBSSIDs(WifiRequestCallbackT callback) { + vector<WiFiInfo::AccessPoint> apns; + GatewaysInfo(apns); + callback(apns); } + void StopNotifications() {} }; +#endif +/////////////////////////////////////////////////////////////////// + WiFiInfo::WiFiInfo() : m_pImpl(new WiFiInfo::Impl) { @@ -29,4 +285,9 @@ void WiFiInfo::RequestWiFiBSSIDs(WifiRequestCallbackT callback) m_pImpl->RequestWiFiBSSIDs(callback); } +void WiFiInfo::Stop() +{ + m_pImpl->StopNotifications(); +} + #endif |