diff --git a/platform/platform.pro b/platform/platform.pro index 7339bd2b1e..feed73c5dc 100644 --- a/platform/platform.pro +++ b/platform/platform.pro @@ -23,13 +23,13 @@ QT *= core network HEADERS += \ qt_download_manager.hpp \ qt_download.hpp \ + wifi_info.hpp } HEADERS += \ platform.hpp \ download_manager.hpp \ location.hpp \ - wifi_info.hpp macx|iphone* { OBJECTIVE_SOURCES += apple_location_service.mm diff --git a/platform/wifi_info.hpp b/platform/wifi_info.hpp index 7584031f1e..3873d51869 100644 --- a/platform/wifi_info.hpp +++ b/platform/wifi_info.hpp @@ -7,10 +7,9 @@ class WiFiInfo { - class Impl; - Impl * m_pImpl; - public: + class Impl; + struct AccessPoint { string m_bssid; //!< for example, "33-12-03-5b-44-9a" @@ -23,4 +22,9 @@ public: typedef boost::function const &)> WifiRequestCallbackT; void RequestWiFiBSSIDs(WifiRequestCallbackT callback); + /// Stops any active updates + void Stop(); + +private: + Impl * m_pImpl; }; diff --git a/platform/wifi_info_mac.mm b/platform/wifi_info_mac.mm index 625fe0223d..d8f69afc03 100644 --- a/platform/wifi_info_mac.mm +++ b/platform/wifi_info_mac.mm @@ -37,7 +37,7 @@ static string AppendZeroIfNeeded(string const & macAddrPart) - (void)dealloc { [super dealloc]; - NSLog(@"Mac OS WiFiInfo selfdestructed successfully"); +// NSLog(@"Mac OS WiFiInfo selfdestructed successfully"); } /// Executed on main thread @@ -99,4 +99,8 @@ void WiFiInfo::RequestWiFiBSSIDs(WifiRequestCallbackT callback) [[WiFiInfoMac alloc] InitWithCallback:callback]; } +void WiFiInfo::Stop() +{ +} + #endif 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 +#include + +bool GatewaysInfo(vector & out) +{ + vector 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 +#include +#include + +///////////////////////////////////////////////////////////////// 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(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(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 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(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 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(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(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 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 diff --git a/platform/wifi_location_service.cpp b/platform/wifi_location_service.cpp index 700d33d62d..eba5f5d6eb 100644 --- a/platform/wifi_location_service.cpp +++ b/platform/wifi_location_service.cpp @@ -20,6 +20,13 @@ namespace location void OnHttpPostFinished(HttpFinishedParams const & result) { + if (result.m_error != EHttpDownloadOk) + { + LOG(LWARNING, ("Location server is not available")); + return; + } + // stop requesting wifi updates if reply from server is received + m_wifiInfo.Stop(); // here we should receive json reply with coordinates and accuracy try { @@ -40,9 +47,10 @@ namespace location info.m_horizontalAccuracy = json_real_value(acc); // @TODO introduce flags to mark valid values info.m_status = EAccurateMode; - info.m_timestamp = time(NULL); + info.m_timestamp = static_cast(time(NULL)); info.m_source = location::EGoogle; NotifyGpsObserver(info); + return; } } } @@ -90,11 +98,14 @@ namespace location virtual void StopUpdate() { + m_wifiInfo.Stop(); } }; } location::LocationService * CreateWiFiLocationService() { + // small hack - create and initialize downloader in main thread + GetDownloadManager(); return new location::WiFiLocationService(); } diff --git a/qt/qt.pro b/qt/qt.pro index 57c4c51852..c75acd2752 100644 --- a/qt/qt.pro +++ b/qt/qt.pro @@ -11,9 +11,12 @@ TEMPLATE = app QT *= core gui opengl network win32 { - LIBS += -lopengl32 -lws2_32 -lshell32 + LIBS += -lopengl32 -lws2_32 -lshell32 -liphlpapi RC_FILE = res/windows.rc } +win32-msvc2008 { + LIBS += -lwlanapi +} macx { LIBS += -framework CoreLocation -framework Foundation -framework CoreWLAN