d642c095e73e073cd2951ab1550f12af145a2c10
[vuplus_xbmc] / xbmc / network / windows / NetworkWin32.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include <errno.h>
22 #include <iphlpapi.h>
23 #include <IcmpAPI.h>
24 #include "PlatformDefs.h"
25 #include "NetworkWin32.h"
26 #include "utils/log.h"
27 #include "threads/SingleLock.h"
28 #include "utils/CharsetConverter.h"
29
30 // undefine if you want to build without the wlan stuff
31 // might be needed for VS2003
32 #define HAS_WIN32_WLAN_API
33
34 #ifdef HAS_WIN32_WLAN_API
35 #include "Wlanapi.h"
36 #pragma comment (lib,"Wlanapi.lib")
37 #endif
38
39
40 using namespace std;
41
42 CNetworkInterfaceWin32::CNetworkInterfaceWin32(CNetworkWin32* network, IP_ADAPTER_INFO adapter)
43
44 {
45    m_network = network;
46    m_adapter = adapter;
47    m_adaptername = adapter.Description;
48 }
49
50 CNetworkInterfaceWin32::~CNetworkInterfaceWin32(void)
51 {
52 }
53
54 CStdString& CNetworkInterfaceWin32::GetName(void)
55 {
56   if (!g_charsetConverter.isValidUtf8(m_adaptername))
57     g_charsetConverter.unknownToUTF8(m_adaptername);
58   return m_adaptername;
59 }
60
61 bool CNetworkInterfaceWin32::IsWireless()
62 {
63   return (m_adapter.Type == IF_TYPE_IEEE80211);
64 }
65
66 bool CNetworkInterfaceWin32::IsEnabled()
67 {
68   return true;
69 }
70
71 bool CNetworkInterfaceWin32::IsConnected()
72 {
73   CStdString strIP = m_adapter.IpAddressList.IpAddress.String;
74   return (strIP != "0.0.0.0");
75 }
76
77 CStdString CNetworkInterfaceWin32::GetMacAddress()
78 {
79   CStdString result;
80   unsigned char* mAddr = m_adapter.Address;
81   result.Format("%02X:%02X:%02X:%02X:%02X:%02X", mAddr[0], mAddr[1], mAddr[2], mAddr[3], mAddr[4], mAddr[5]);
82   return result;
83 }
84
85 void CNetworkInterfaceWin32::GetMacAddressRaw(char rawMac[6])
86 {
87   memcpy(rawMac, m_adapter.Address, 6);
88 }
89
90 CStdString CNetworkInterfaceWin32::GetCurrentIPAddress(void)
91 {
92   return m_adapter.IpAddressList.IpAddress.String;
93 }
94
95 CStdString CNetworkInterfaceWin32::GetCurrentNetmask(void)
96 {
97   return m_adapter.IpAddressList.IpMask.String;
98 }
99
100 CStdString CNetworkInterfaceWin32::GetCurrentWirelessEssId(void)
101 {
102   CStdString result = "";
103
104 #ifdef HAS_WIN32_WLAN_API
105   if(IsWireless())
106   {
107     HANDLE hClientHdl = NULL;
108     DWORD dwVersion = 0;
109     DWORD dwret = 0;
110     PWLAN_CONNECTION_ATTRIBUTES pAttributes;
111     DWORD dwSize = 0;
112
113     if(WlanOpenHandle(1,NULL,&dwVersion, &hClientHdl) == ERROR_SUCCESS)
114     {
115       PWLAN_INTERFACE_INFO_LIST ppInterfaceList;
116       if(WlanEnumInterfaces(hClientHdl,NULL, &ppInterfaceList ) == ERROR_SUCCESS)
117       {
118         for(unsigned int i=0; i<ppInterfaceList->dwNumberOfItems;i++)
119         {
120           GUID guid = ppInterfaceList->InterfaceInfo[i].InterfaceGuid;
121           WCHAR wcguid[64];
122           StringFromGUID2(guid, (LPOLESTR)&wcguid, 64);
123           CStdStringW strGuid = wcguid;
124           CStdStringW strAdaptername = m_adapter.AdapterName;
125           if( strGuid == strAdaptername)
126           {
127             if(WlanQueryInterface(hClientHdl,&ppInterfaceList->InterfaceInfo[i].InterfaceGuid,wlan_intf_opcode_current_connection, NULL, &dwSize, (PVOID*)&pAttributes, NULL ) == ERROR_SUCCESS)
128             {
129               result = (char*)pAttributes->wlanAssociationAttributes.dot11Ssid.ucSSID;
130               WlanFreeMemory((PVOID*)&pAttributes);
131             }
132             else
133               OutputDebugString("Can't query wlan interface\n");
134           }
135         }
136       }
137       WlanCloseHandle(&hClientHdl, NULL);
138     }
139     else
140       OutputDebugString("Can't open wlan handle\n");
141   }
142 #endif
143   return result;
144 }
145
146 CStdString CNetworkInterfaceWin32::GetCurrentDefaultGateway(void)
147 {
148   return m_adapter.GatewayList.IpAddress.String;
149 }
150
151 CNetworkWin32::CNetworkWin32(void)
152 {
153   queryInterfaceList();
154 }
155
156 CNetworkWin32::~CNetworkWin32(void)
157 {
158   CleanInterfaceList();
159   m_netrefreshTimer.Stop();
160 }
161
162 void CNetworkWin32::CleanInterfaceList()
163 {
164   vector<CNetworkInterface*>::iterator it = m_interfaces.begin();
165   while(it != m_interfaces.end())
166   {
167     CNetworkInterface* nInt = *it;
168     delete nInt;
169     it = m_interfaces.erase(it);
170   }
171 }
172
173 std::vector<CNetworkInterface*>& CNetworkWin32::GetInterfaceList(void)
174 {
175   CSingleLock lock (m_critSection);
176   if(m_netrefreshTimer.GetElapsedSeconds() >= 5.0f)
177     queryInterfaceList();
178
179   return m_interfaces;
180 }
181
182 void CNetworkWin32::queryInterfaceList()
183 {
184   CleanInterfaceList();
185   m_netrefreshTimer.StartZero();
186
187   PIP_ADAPTER_INFO adapterInfo;
188   PIP_ADAPTER_INFO adapter = NULL;
189
190   ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO);
191
192   adapterInfo = (IP_ADAPTER_INFO *) malloc(sizeof (IP_ADAPTER_INFO));
193   if (adapterInfo == NULL)
194     return;
195
196   if (GetAdaptersInfo(adapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW)
197   {
198     free(adapterInfo);
199     adapterInfo = (IP_ADAPTER_INFO *) malloc(ulOutBufLen);
200     if (adapterInfo == NULL)
201     {
202       OutputDebugString("Error allocating memory needed to call GetAdaptersinfo\n");
203       return;
204     }
205   }
206
207   if ((GetAdaptersInfo(adapterInfo, &ulOutBufLen)) == NO_ERROR)
208   {
209     adapter = adapterInfo;
210     while (adapter)
211     {
212       m_interfaces.push_back(new CNetworkInterfaceWin32(this, *adapter));
213       adapter = adapter->Next;
214     }
215   }
216   free(adapterInfo);
217 }
218
219 std::vector<CStdString> CNetworkWin32::GetNameServers(void)
220 {
221   std::vector<CStdString> result;
222
223   FIXED_INFO *pFixedInfo;
224   ULONG ulOutBufLen;
225   IP_ADDR_STRING *pIPAddr;
226
227   pFixedInfo = (FIXED_INFO *) malloc(sizeof (FIXED_INFO));
228   if (pFixedInfo == NULL)
229   {
230     OutputDebugString("Error allocating memory needed to call GetNetworkParams\n");
231     return result;
232   }
233   ulOutBufLen = sizeof (FIXED_INFO);
234   if (GetNetworkParams(pFixedInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW)
235   {
236     free(pFixedInfo);
237     pFixedInfo = (FIXED_INFO *) malloc(ulOutBufLen);
238     if (pFixedInfo == NULL)
239     {
240       OutputDebugString("Error allocating memory needed to call GetNetworkParams\n");
241       return result;
242     }
243   }
244
245   if (GetNetworkParams(pFixedInfo, &ulOutBufLen) == NO_ERROR)
246   {
247     result.push_back(pFixedInfo->DnsServerList.IpAddress.String);
248     pIPAddr = pFixedInfo->DnsServerList.Next;
249     while(pIPAddr)
250     {
251       result.push_back(pIPAddr->IpAddress.String);
252       pIPAddr = pIPAddr->Next;
253     }
254
255   }
256   free(pFixedInfo);
257
258   return result;
259 }
260
261 void CNetworkWin32::SetNameServers(std::vector<CStdString> nameServers)
262 {
263   return;
264 }
265
266 bool CNetworkWin32::PingHost(unsigned long host, unsigned int timeout_ms /* = 2000 */)
267 {
268   char SendData[]    = "poke";
269   HANDLE hIcmpFile   = IcmpCreateFile();
270   BYTE ReplyBuffer [sizeof(ICMP_ECHO_REPLY) + sizeof(SendData)];
271
272   SetLastError(ERROR_SUCCESS);
273
274   DWORD dwRetVal = IcmpSendEcho(hIcmpFile, host, SendData, sizeof(SendData), 
275                                 NULL, ReplyBuffer, sizeof(ReplyBuffer), timeout_ms);
276
277   DWORD lastErr = GetLastError();
278   if (lastErr != ERROR_SUCCESS && lastErr != IP_REQ_TIMED_OUT)
279     CLog::Log(LOGERROR, "%s - IcmpSendEcho failed - %s", __FUNCTION__, WUSysMsg(lastErr).c_str());
280
281   IcmpCloseHandle (hIcmpFile);
282
283   if (dwRetVal != 0)
284   {
285     PICMP_ECHO_REPLY pEchoReply = (PICMP_ECHO_REPLY)ReplyBuffer;
286     return (pEchoReply->Status == IP_SUCCESS);
287   }
288   return false;
289 }
290
291 bool CNetworkInterfaceWin32::GetHostMacAddress(unsigned long host, CStdString& mac)
292 {
293   IPAddr src_ip = inet_addr(GetCurrentIPAddress().c_str());
294   BYTE bPhysAddr[6];      // for 6-byte hardware addresses
295   ULONG PhysAddrLen = 6;  // default to length of six bytes
296
297   memset(&bPhysAddr, 0xff, sizeof (bPhysAddr));
298
299   DWORD dwRetVal = SendARP(host, src_ip, &bPhysAddr, &PhysAddrLen);
300   if (dwRetVal == NO_ERROR)
301   {
302     if (PhysAddrLen == 6)
303     {
304       mac.Format("%02X:%02X:%02X:%02X:%02X:%02X", 
305         bPhysAddr[0], bPhysAddr[1], bPhysAddr[2], 
306         bPhysAddr[3], bPhysAddr[4], bPhysAddr[5]);
307       return true;
308     }
309     else
310       CLog::Log(LOGERROR, "%s - SendArp completed successfully, but mac address has length != 6 (%d)", __FUNCTION__, PhysAddrLen);
311   }
312   else
313     CLog::Log(LOGERROR, "%s - SendArp failed with error (%d)", __FUNCTION__, dwRetVal);
314
315   return false;
316 }
317
318 std::vector<NetworkAccessPoint> CNetworkInterfaceWin32::GetAccessPoints(void)
319 {
320    std::vector<NetworkAccessPoint> result;
321 #ifdef HAS_WIN32_WLAN_API
322   if (!IsWireless())
323     return result;
324
325   // According to Mozilla: "We could be executing on either Windows XP or Windows
326   // Vista, so use the lower version of the client WLAN API. It seems that the
327   // negotiated version is the Vista version irrespective of what we pass!"
328   // http://dxr.mozilla.org/mozilla-central/source/netwerk/wifi/nsWifiScannerWin.cpp#l51
329   static const int xpWlanClientVersion = 1;
330   DWORD negotiated_version;
331   DWORD dwResult;
332   HANDLE wlan_handle = NULL;
333
334   // Get the handle to the WLAN API
335   dwResult = WlanOpenHandle(xpWlanClientVersion, NULL, &negotiated_version, &wlan_handle);
336   if (dwResult != ERROR_SUCCESS || !wlan_handle)
337   {
338     CLog::Log(LOGERROR, "Could not load the client WLAN API");
339     return result;
340   }
341
342   // Get the list of interfaces (WlanEnumInterfaces allocates interface_list)
343   WLAN_INTERFACE_INFO_LIST *interface_list = NULL;
344   dwResult = WlanEnumInterfaces(wlan_handle, NULL, &interface_list);
345   if (dwResult != ERROR_SUCCESS || !interface_list)
346   {
347     WlanCloseHandle(wlan_handle, NULL);
348     CLog::Log(LOGERROR, "Failed to get the list of interfaces");
349     return result;
350   }
351
352   for (unsigned int i = 0; i < interface_list->dwNumberOfItems; ++i)
353   {
354     GUID guid = interface_list->InterfaceInfo[i].InterfaceGuid;
355     WCHAR wcguid[64];
356     StringFromGUID2(guid, (LPOLESTR)&wcguid, 64);
357     CStdStringW strGuid = wcguid;
358     CStdStringW strAdaptername = m_adapter.AdapterName;
359     if (strGuid == strAdaptername)
360     {
361       WLAN_BSS_LIST *bss_list;
362       HRESULT rv = WlanGetNetworkBssList(wlan_handle,
363                                          &interface_list->InterfaceInfo[i].InterfaceGuid,
364                                          NULL,               // Get all SSIDs
365                                          dot11_BSS_type_any, // unused
366                                          false,              // bSecurityEnabled - unused
367                                          NULL,               // reserved
368                                          &bss_list);
369       if (rv != ERROR_SUCCESS || !bss_list)
370         break;
371       for (unsigned int j = 0; j < bss_list->dwNumberOfItems; ++j)
372       {
373         const WLAN_BSS_ENTRY bss_entry = bss_list->wlanBssEntries[j];
374         // Add the access point info to the list of results
375         CStdString essId((char*)bss_entry.dot11Ssid.ucSSID, (unsigned int)bss_entry.dot11Ssid.uSSIDLength);
376         CStdString macAddress;
377         // macAddress is big-endian, write in byte chunks
378         macAddress.Format("%02x-%02x-%02x-%02x-%02x-%02x",
379           bss_entry.dot11Bssid[0], bss_entry.dot11Bssid[1], bss_entry.dot11Bssid[2],
380           bss_entry.dot11Bssid[3], bss_entry.dot11Bssid[4], bss_entry.dot11Bssid[5]);
381         int signalLevel = bss_entry.lRssi;
382         EncMode encryption = ENC_NONE; // TODO
383         int channel = NetworkAccessPoint::FreqToChannel((float)bss_entry.ulChCenterFrequency * 1000);
384         result.push_back(NetworkAccessPoint(essId, macAddress, signalLevel, encryption, channel));
385       }
386       WlanFreeMemory(bss_list);
387       break;
388     }
389   }
390
391   // Free the interface list
392   WlanFreeMemory(interface_list);
393
394   // Close the handle
395   WlanCloseHandle(wlan_handle, NULL);
396
397 #endif
398
399   return result;
400 }
401
402 void CNetworkInterfaceWin32::GetSettings(NetworkAssignment& assignment, CStdString& ipAddress, CStdString& networkMask, CStdString& defaultGateway, CStdString& essId, CStdString& key, EncMode& encryptionMode)
403 {
404   ipAddress = "0.0.0.0";
405   networkMask = "0.0.0.0";
406   defaultGateway = "0.0.0.0";
407   essId = "";
408   key = "";
409   encryptionMode = ENC_NONE;
410   assignment = NETWORK_DISABLED;
411
412
413   PIP_ADAPTER_INFO adapterInfo;
414   PIP_ADAPTER_INFO adapter = NULL;
415
416   ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO);
417
418   adapterInfo = (IP_ADAPTER_INFO *) malloc(sizeof (IP_ADAPTER_INFO));
419   if (adapterInfo == NULL)
420     return;
421
422   if (GetAdaptersInfo(adapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW)
423   {
424     free(adapterInfo);
425     adapterInfo = (IP_ADAPTER_INFO *) malloc(ulOutBufLen);
426     if (adapterInfo == NULL)
427     {
428       OutputDebugString("Error allocating memory needed to call GetAdaptersinfo\n");
429       return;
430     }
431   }
432
433   if ((GetAdaptersInfo(adapterInfo, &ulOutBufLen)) == NO_ERROR)
434   {
435     adapter = adapterInfo;
436     while (adapter)
437     {
438       if(m_adapter.Index == adapter->Index)
439       {
440         ipAddress = adapter->IpAddressList.IpAddress.String;
441         networkMask = adapter->IpAddressList.IpMask.String;
442         defaultGateway = adapter->GatewayList.IpAddress.String;
443         if (adapter->DhcpEnabled)
444           assignment = NETWORK_DHCP;
445         else
446           assignment = NETWORK_STATIC;
447
448       }
449       adapter = adapter->Next;
450     }
451   }
452   free(adapterInfo);
453
454 #ifdef HAS_WIN32_WLAN_API
455   if(IsWireless())
456   {
457     HANDLE hClientHdl = NULL;
458     DWORD dwVersion = 0;
459     DWORD dwret = 0;
460     PWLAN_CONNECTION_ATTRIBUTES pAttributes;
461     DWORD dwSize = 0;
462
463     if(WlanOpenHandle(1,NULL,&dwVersion, &hClientHdl) == ERROR_SUCCESS)
464     {
465       PWLAN_INTERFACE_INFO_LIST ppInterfaceList;
466       if(WlanEnumInterfaces(hClientHdl,NULL, &ppInterfaceList ) == ERROR_SUCCESS)
467       {
468         for(unsigned int i=0; i<ppInterfaceList->dwNumberOfItems;i++)
469         {
470           GUID guid = ppInterfaceList->InterfaceInfo[i].InterfaceGuid;
471           WCHAR wcguid[64];
472           StringFromGUID2(guid, (LPOLESTR)&wcguid, 64);
473           CStdStringW strGuid = wcguid;
474           CStdStringW strAdaptername = m_adapter.AdapterName;
475           if( strGuid == strAdaptername)
476           {
477             if(WlanQueryInterface(hClientHdl,&ppInterfaceList->InterfaceInfo[i].InterfaceGuid,wlan_intf_opcode_current_connection, NULL, &dwSize, (PVOID*)&pAttributes, NULL ) == ERROR_SUCCESS)
478             {
479               essId = (char*)pAttributes->wlanAssociationAttributes.dot11Ssid.ucSSID;
480               if(pAttributes->wlanSecurityAttributes.bSecurityEnabled)
481               {
482                 switch(pAttributes->wlanSecurityAttributes.dot11AuthAlgorithm)
483                 {
484                 case DOT11_AUTH_ALGO_80211_SHARED_KEY:
485                   encryptionMode = ENC_WEP;
486                   break;
487                 case DOT11_AUTH_ALGO_WPA:
488                 case DOT11_AUTH_ALGO_WPA_PSK:
489                   encryptionMode = ENC_WPA;
490                   break;
491                 case DOT11_AUTH_ALGO_RSNA:
492                 case DOT11_AUTH_ALGO_RSNA_PSK:
493                   encryptionMode = ENC_WPA2;
494                 }
495               }
496               WlanFreeMemory((PVOID*)&pAttributes);
497             }
498             else
499               OutputDebugString("Can't query wlan interface\n");
500           }
501         }
502       }
503       WlanCloseHandle(&hClientHdl, NULL);
504     }
505     else
506       OutputDebugString("Can't open wlan handle\n");
507   }
508   // Todo: get the key (WlanGetProfile, CryptUnprotectData?)
509 #endif
510 }
511
512 void CNetworkInterfaceWin32::SetSettings(NetworkAssignment& assignment, CStdString& ipAddress, CStdString& networkMask, CStdString& defaultGateway, CStdString& essId, CStdString& key, EncMode& encryptionMode)
513 {
514   return;
515 }
516
517 void CNetworkInterfaceWin32::WriteSettings(FILE* fw, NetworkAssignment assignment, CStdString& ipAddress, CStdString& networkMask, CStdString& defaultGateway, CStdString& essId, CStdString& key, EncMode& encryptionMode)
518 {
519   return;
520 }