reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
WinCompat.cxx
Go to the documentation of this file.
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#include <Winsock2.h>
6#include <Iphlpapi.h>
7#include <tchar.h>
8#include <winternl.h>
9#pragma comment(lib, "ntdll.lib")
10
12#include "rutil/WinCompat.hxx"
13#include "rutil/DnsUtil.hxx"
14#include "rutil/Log.hxx"
15#include "rutil/Logger.hxx"
17
18#define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT
19
20
21static char* ConvertLPWSTRToLPSTR(LPWSTR lpwszStrIn)
22{
23 LPSTR pszOut = NULL;
24 if (lpwszStrIn != NULL)
25 {
26 int nInputStrLen = (int)wcslen(lpwszStrIn);
27
28 // Double NULL Termination
29 int nOutputStrLen = WideCharToMultiByte (CP_ACP, 0, lpwszStrIn, nInputStrLen, NULL, 0, 0, 0) + 2;
30 pszOut = new char [nOutputStrLen];
31
32 if (pszOut)
33 {
34 memset (pszOut, 0x00, nOutputStrLen);
35 WideCharToMultiByte(CP_ACP, 0, lpwszStrIn, nInputStrLen, pszOut, nOutputStrLen, 0, 0);
36 }
37 }
38 return pszOut;
39}
40
41using namespace resip;
42
44{
45public:
46 ~WinCompatInstanceCleaner() { WinCompat::destroyInstance(); }
48
49WinCompat::Exception::Exception(const Data& msg, const Data& file, const int line) :
50 BaseException(msg,file,line)
51{
52}
53
54extern "C" NTSTATUS NTAPI RtlGetVersion(PRTL_OSVERSIONINFOW lpVersionInformation);
55WinCompat::Version
56WinCompat::getVersion()
57{
58#ifdef UNDER_CE
59 return WinCompat::WindowsUnknown;
60#endif
61
62 // RtlGetVersion always returns the true OS version regardless of manifest,
63 // unlike GetVersionEx which lies on Windows 10+ without a compatibility manifest.
64 OSVERSIONINFOEXW osvi = { sizeof(osvi) };
65 if (RtlGetVersion((PRTL_OSVERSIONINFOW)&osvi) != 0)
66 {
67 return WinCompat::WindowsUnknown;
68 }
69
70 // Only Windows NT platform is relevant now (Win9x/ME are long dead)
71 if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT)
72 {
73 return WinCompat::WindowsUnknown;
74 }
75
76 const DWORD major = osvi.dwMajorVersion;
77 const DWORD minor = osvi.dwMinorVersion;
78 const WORD type = osvi.wProductType; // VER_NT_WORKSTATION or server
79
80 if (major == 10 && minor == 0)
81 {
82 if (osvi.dwBuildNumber >= 22000)
83 {
84 return (type == VER_NT_WORKSTATION) ? WinCompat::Windows11
85 : WinCompat::WindowsServer2022;
86 }
87 return (type == VER_NT_WORKSTATION) ? WinCompat::Windows10
88 : WinCompat::WindowsServer2016;
89 }
90 else if (major == 6 && minor == 3)
91 {
92 return (type == VER_NT_WORKSTATION) ? WinCompat::Windows81
93 : WinCompat::WindowsServer2012R2;
94 }
95 else if (major == 6 && minor == 2)
96 {
97 return (type == VER_NT_WORKSTATION) ? WinCompat::Windows8
98 : WinCompat::WindowsServer2012;
99 }
100 else if (major == 6 && minor == 1)
101 {
102 return (type == VER_NT_WORKSTATION) ? WinCompat::Windows7
103 : WinCompat::WindowsServer2008R2;
104 }
105 else if (major == 6 && minor == 0)
106 {
107 return (type == VER_NT_WORKSTATION) ? WinCompat::WindowsVista
108 : WinCompat::WindowsServer2008;
109 }
110 else if (major == 5 && minor == 2) { return WinCompat::Windows2003Server; }
111 else if (major == 5 && minor == 1) { return WinCompat::WindowsXP; }
112 else if (major == 5 && minor == 0) { return WinCompat::Windows2000; }
113 else if (major <= 4) { return WinCompat::WindowsNT; }
114
115 return WinCompat::WindowsUnknown;
116}
117
118
119WinCompat* WinCompat::mInstance = 0;
120
121
123WinCompat *
124WinCompat::instance()
125{
126 if (!mInstance)
127 {
129 if (!mInstance)
130 {
131 mInstance = new WinCompat();
132 }
133 }
134 return mInstance;
135}
136
137
138WinCompat::WinCompat() :
139 getBestInterfaceEx(0),
140 getAdaptersAddresses(0),
141 getAdaptersInfo(0),
142 loadLibraryWithIPv4Failed(false),
143 loadLibraryWithIPv6Failed(false),
144 hLib(0)
145{
146
147 // Note: IPHLPAPI has been known to conflict with some thirdparty DLL's.
148 // If you don't care about Win95/98/Me as your target system - then
149 // you can define NO_IPHLPAPI so that you are not required to link with this
150 // library. (SLG)
151#if !defined (NO_IPHLPAPI)
152 // check to see if the GetAdaptersAddresses() is in the IPHLPAPI library
153 HINSTANCE hLib = LoadLibrary(TEXT("iphlpapi.dll"));
154 if (hLib == NULL)
155 {
156 loadLibraryWithIPv6Failed = true;
157 loadLibraryWithIPv4Failed = true;
158 return;
159 }
160
161 getBestInterfaceEx = (GetBestInterfaceExProc) GetProcAddress(hLib, TEXT("GetBestInterfaceEx"));
162 getAdaptersAddresses = (GetAdaptersAddressesProc) GetProcAddress(hLib, TEXT("GetAdaptersAddresses"));
163 getAdaptersInfo = (GetAdaptersInfoProc) GetProcAddress(hLib, TEXT("GetAdaptersInfo"));
164 getBestRoute = (GetBestRouteProc) GetProcAddress(hLib, TEXT("GetBestRoute"));
165 getIpAddrTable = (GetIpAddrTableProc) GetProcAddress(hLib, TEXT("GetIpAddrTable"));
166 if (getAdaptersAddresses == NULL || getBestInterfaceEx == NULL)
167 {
168 loadLibraryWithIPv6Failed = true;
169 }
170 if (getAdaptersInfo == NULL || getBestRoute == NULL || getIpAddrTable == NULL)
171 {
172 loadLibraryWithIPv4Failed = true;
173 }
174#else
175 loadLibraryWithIPv6Failed = true;
176 loadLibraryWithIPv4Failed = true;
177#endif
178 DebugLog(<< "WinCompat constructor complete!");
179}
180
181void WinCompat::destroyInstance()
182{
183 delete mInstance;
184 mInstance = 0;
185}
186
187bool WinCompat::windowsEventLog(WORD type, WORD numStrings, LPCTSTR* strings)
188{
189 // type can be:
190 // EVENTLOG_SUCCESS (0x0000) Information event
191 // EVENTLOG_AUDIT_FAILURE (0x0010) Failure Audit event
192 // EVENTLOG_AUDIT_SUCCESS (0x0008) Success Audit event
193 // EVENTLOG_ERROR_TYPE (0x0001) Error event
194 // EVENTLOG_INFORMATION_TYPE (0x0004) Information event
195 // EVENTLOG_WARNING_TYPE (0x0002) Warning event
196
197 HKEY key;
198 long errorCode =
199 ::RegCreateKeyEx(HKEY_LOCAL_MACHINE, _T("System\\CurrentControlSet\\Services\\EventLog\\Application\\reSIProcate"),
200 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ, NULL, &key, NULL);
201 if (ERROR_SUCCESS == errorCode)
202 {
203 ::RegCloseKey(key);
204 HANDLE eventLogHandle = ::RegisterEventSource(NULL, _T("reSIProcate"));
205 if (eventLogHandle != NULL)
206 {
207 BOOL retVal = ::ReportEvent(eventLogHandle, type, 0, 0, NULL, numStrings, 0, strings, NULL);
208 ::DeregisterEventSource(eventLogHandle);
209 return (retVal != FALSE);
210 }
211 }
212 return false;
213}
214
215WinCompat::~WinCompat()
216{
217 if(hLib != NULL)
218 {
219 FreeLibrary(hLib);
220 }
221}
222
223
224#if !defined(NO_IPHLPAPI)
225// !slg! - This function is horribly slow (upto 200ms) and can cause serious performance issues for servers.
226// We should consider finding more efficient APIs, or caching some of the results.
228WinCompat::determineSourceInterfaceWithIPv6(const GenericIPAddress& destination)
229{
230 if (instance()->loadLibraryWithIPv6Failed)
231 {
232 throw Exception("Library iphlpapi.dll with IPv6 support not available", __FILE__,__LINE__);
233 }
234
235 // Obtain the size of the structure
236 IP_ADAPTER_ADDRESSES *pAdapterAddresses;
237 DWORD dwRet, dwSize;
238 DWORD flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
239 unsigned short family = destination.isVersion6() ? AF_INET6 : AF_INET;
240 dwRet = (instance()->getAdaptersAddresses)(family, flags, NULL, NULL, &dwSize);
241 if (dwRet != ERROR_BUFFER_OVERFLOW) // expected error
242 throw Exception("Unexpected return code", __FILE__, __LINE__);
243
244 {
245 // Allocate memory
246 pAdapterAddresses = (IP_ADAPTER_ADDRESSES *) LocalAlloc(LMEM_ZEROINIT,dwSize);
247 if (pAdapterAddresses == NULL)
248 {
249 throw Exception("Can't find source address for destination", __FILE__,__LINE__);
250 }
251
252 // Obtain network adapter information (IPv6)
253 dwRet = (instance()->getAdaptersAddresses)(family, flags, NULL, pAdapterAddresses, &dwSize);
254 if (dwRet != ERROR_SUCCESS)
255 {
256 LocalFree(pAdapterAddresses);
257 throw Exception("Can't find source address for destination", __FILE__,__LINE__);
258 }
259 }
260
261 // Check if this address is a local address - this also avoids returning
262 // the loopback address that can cause havoc if the registrar and user agent are on the same box
263 IP_ADAPTER_ADDRESSES *AI;
264 int i;
265 for (i = 0, AI = pAdapterAddresses; AI != NULL; AI = AI->Next, i++)
266 {
267 for (PIP_ADAPTER_UNICAST_ADDRESS unicast = AI->FirstUnicastAddress;
268 unicast; unicast = unicast->Next)
269 {
270 if (unicast->Address.lpSockaddr->sa_family != family)
271 continue;
272
273 if (family == AF_INET &&
274 reinterpret_cast<const struct sockaddr_in*>(unicast->Address.lpSockaddr)->sin_addr.S_un.S_addr ==
275 destination.v4Address.sin_addr.S_un.S_addr)
276 {
277 // Return default address for NIC. Note: We could also just return the destination,
278 // however returning the default address for NIC is beneficial in cases where the
279 // co-located registrar supports redundancy via a Virtual IP address.
280 for (PIP_ADAPTER_UNICAST_ADDRESS unicastRet = AI->FirstUnicastAddress;
281 unicastRet; unicastRet = unicastRet->Next)
282 {
283#if defined(AVOID_TRANSIENT_SOURCE_ADDRESSES)
284 if (unicastRet->Flags & IP_ADAPTER_ADDRESS_TRANSIENT)
285 continue;
286#endif
287
288 GenericIPAddress ipaddress(*unicastRet->Address.lpSockaddr);
289 LocalFree(pAdapterAddresses);
290 return(ipaddress);
291 }
292 }
293#ifdef USE_IPV6
294 else if (family == AF_INET6 &&
295 memcmp(&(reinterpret_cast<const struct sockaddr_in6*>(unicast->Address.lpSockaddr)->sin6_addr),
296 &(reinterpret_cast<const struct sockaddr_in6*>(&destination.address)->sin6_addr),
297 sizeof(IN6_ADDR)) == 0)
298 {
299 for (PIP_ADAPTER_UNICAST_ADDRESS unicastRet = AI->FirstUnicastAddress;
300 unicastRet; unicastRet = unicastRet->Next)
301 {
302#if defined(AVOID_TRANSIENT_SOURCE_ADDRESSES)
303 if (unicastRet->Flags & IP_ADAPTER_ADDRESS_TRANSIENT)
304 continue;
305#endif
306
307 // explicitly cast to sockaddr_in6, to use that version of GenericIPAddress' ctor. If we don't, then compiler
308 // defaults to ctor for sockaddr_in (at least under Win32), which will truncate the lower-bits of the IPv6 address.
309 const struct sockaddr_in6* psa = reinterpret_cast<const struct sockaddr_in6*>(unicastRet->Address.lpSockaddr);
310
311 // Return default address for NIC. Note: We could also just return the destination,
312 // however returning the default address for NIC is beneficial in cases where the
313 // co-located registrar supports redundancy via a Virtual IP address.
314 GenericIPAddress ipaddress(*psa);
315 LocalFree(pAdapterAddresses);
316 return(ipaddress);
317 }
318 }
319#endif
320 }
321 }
322
323 // Not a local address, get the best interface from the OS
324 DWORD dwBestIfIndex;
325 const sockaddr* saddr = &destination.address;
326 if ((instance()->getBestInterfaceEx)((sockaddr *)saddr, &dwBestIfIndex) != NO_ERROR)
327 {
328 LocalFree(pAdapterAddresses);
329 throw Exception("Can't find source address for destination", __FILE__,__LINE__);
330 }
331
332 for (i = 0, AI = pAdapterAddresses; AI != NULL; AI = AI->Next, i++)
333 {
334 for (PIP_ADAPTER_UNICAST_ADDRESS unicast = AI->FirstUnicastAddress;
335 unicast; unicast = unicast->Next)
336 {
337 if (unicast->Address.lpSockaddr->sa_family != saddr->sa_family)
338 continue;
339
340#if defined(AVOID_TRANSIENT_SOURCE_ADDRESSES)
341 if (unicast->Flags & IP_ADAPTER_ADDRESS_TRANSIENT)
342 continue;
343#endif
344
345 if (saddr->sa_family == AF_INET && AI->IfIndex == dwBestIfIndex)
346 {
347 GenericIPAddress ipaddress(*unicast->Address.lpSockaddr);
348 LocalFree(pAdapterAddresses);
349 return(ipaddress);
350 }
351#ifdef USE_IPV6
352 else if (saddr->sa_family == AF_INET6 && AI->Ipv6IfIndex == dwBestIfIndex)
353 {
354 // explicitly cast to sockaddr_in6, to use that version of GenericIPAddress' ctor. If we don't, then compiler
355 // defaults to ctor for sockaddr_in (at least under Win32), which will truncate the lower-bits of the IPv6 address.
356 const struct sockaddr_in6* psa = reinterpret_cast<const struct sockaddr_in6*>(unicast->Address.lpSockaddr);
357 GenericIPAddress ipaddress(*psa);
358 LocalFree(pAdapterAddresses);
359 return(ipaddress);
360 }
361#endif
362 }
363 }
364 LocalFree(pAdapterAddresses);
365 throw Exception("Can't find source address for destination", __FILE__,__LINE__);
366
367 return GenericIPAddress();
368}
369
370
372WinCompat::determineSourceInterfaceWithoutIPv6(const GenericIPAddress& destination)
373{
374 if (instance()->loadLibraryWithIPv4Failed)
375 {
376 throw Exception("Library iphlpapi.dll not available", __FILE__,__LINE__);
377 }
378
379 struct sockaddr_in sourceIP;
380 memset(&sourceIP, 0, sizeof(sockaddr_in));
381 sourceIP.sin_family = AF_INET;
382
383 // look through the local ip address - first we want to see if the address is local, if
384 // not then we want to look for the Best route
385 PMIB_IPADDRTABLE pIpAddrTable = NULL;
386 ULONG addrSize = 0;
387
388 // allocate the space
389 DWORD ret = instance()->getIpAddrTable(NULL, &addrSize, FALSE);
390 if(ERROR_INSUFFICIENT_BUFFER == ret)
391 {
392 pIpAddrTable = (PMIB_IPADDRTABLE) new char [addrSize];
393 if(pIpAddrTable == 0)
394 {
395 throw Exception("Can't find source address for destination - unable to new memory", __FILE__,__LINE__);
396 }
397 }
398 else
399 {
400 throw Exception("Can't find source address for destination (GetIpAddrTable to get buffer space failed), ret=" + Data((uint32_t)ret), __FILE__,__LINE__);
401 }
402
403 ret = instance()->getIpAddrTable(pIpAddrTable, &addrSize, FALSE);
404 if (NO_ERROR != ret)
405 {
406 delete [] (char *) pIpAddrTable;
407 throw Exception("Can't find source address for destination (GetIpAddrTable failed), addrSize=" + Data((uint32_t)addrSize) + ", ret=" + Data((uint32_t)ret), __FILE__,__LINE__);
408 }
409
410 // Check if address is local or not
411 DWORD i = 0;
412 for(i = 0; i <pIpAddrTable->dwNumEntries; i++)
413 {
414 if(pIpAddrTable->table[i].dwAddr ==
415 destination.v4Address.sin_addr.S_un.S_addr)
416 {
417 // Address is local - no need to find best route - this also avoids returning
418 // 127.0.0.1 that can cause havoc if the registrar and user agent are on the same box
419 // Return default address for NIC. Note: We could also just return the destination,
420 // however returning the default address for NIC is beneficial in cases where the
421 // co-located registrar supports redundancy via a Virtual IP address.
422 DWORD dwNicIndex = pIpAddrTable->table[i].dwIndex;
423 for(DWORD j = 0; j <pIpAddrTable->dwNumEntries; j++)
424 {
425#if defined(AVOID_TRANSIENT_SOURCE_ADDRESSES)
426 if (pIpAddrTable->table[j].wType & MIB_IPADDR_TRANSIENT)
427 continue;
428#endif
429
430 if(pIpAddrTable->table[j].dwIndex == dwNicIndex) // Default address is first address found for NIC
431 {
432 DebugLog(<< "Routing to a local address - returning default address for NIC");
433 sourceIP.sin_addr.s_addr = pIpAddrTable->table[j].dwAddr;
434 delete [] (char *) pIpAddrTable;
435 return GenericIPAddress(sourceIP);
436 }
437 }
438 }
439 }
440
441 // try to figure the best route to the destination
442 MIB_IPFORWARDROW bestRoute;
443 memset(&bestRoute, 0, sizeof(bestRoute));
444 const sockaddr_in& sin = (const sockaddr_in&)destination.address;
445 ret = instance()->getBestRoute(sin.sin_addr.s_addr, 0, &bestRoute);
446 if (NO_ERROR != ret)
447 {
448 delete [] (char *) pIpAddrTable;
449 throw Exception("Can't find source address for destination, ret=" + Data((uint32_t)ret), __FILE__,__LINE__);
450 }
451
452 // look through the local ip address to find one that match the best route.
453 enum ENICEntryPreference {ENICUnknown = 0, ENextHopNotWithinNICSubnet, ENICSubnetIsAll1s, ENICServicesNextHop};
454 ENICEntryPreference eCurrSelection = ENICUnknown;
455
456 // try to find a match
457 for (i=0; i<pIpAddrTable->dwNumEntries; i++)
458 {
459 MIB_IPADDRROW &entry = pIpAddrTable->table[i];
460
461 ULONG addr = pIpAddrTable->table[i].dwAddr;
462 ULONG gw = bestRoute.dwForwardNextHop;
463
464#if defined(AVOID_TRANSIENT_SOURCE_ADDRESSES)
465 if (entry.wType & MIB_IPADDR_TRANSIENT)
466 continue;
467#endif
468
469 if(entry.dwIndex == bestRoute.dwForwardIfIndex) // Note: there MAY be > 1 entry with the same index, see AddIPAddress.
470 {
471 if( (entry.dwAddr & entry.dwMask) == (bestRoute.dwForwardNextHop & entry.dwMask) )
472 {
473 sourceIP.sin_addr.s_addr = entry.dwAddr;
474 eCurrSelection = ENICServicesNextHop;
475 break;
476 }
477 else if (entry.dwMask == 0xffffffff && eCurrSelection < ENICSubnetIsAll1s)
478 {
479 sourceIP.sin_addr.s_addr = entry.dwAddr;
480 eCurrSelection = ENICSubnetIsAll1s; // Lucent/Avaya VPN has Subnet Mask of 255.255.255.255. Illegal perhaps but we should use
481 // if cannot find one that serves next hop.
482 }
483 else if (eCurrSelection < ENextHopNotWithinNICSubnet)
484 {
485 sourceIP.sin_addr.s_addr = entry.dwAddr;
486 eCurrSelection = ENextHopNotWithinNICSubnet; // should use if nothing else works since bestRoute told us to use this NIC.
487 }
488 }
489 }
490
491 if (eCurrSelection != ENICServicesNextHop)
492 {
493 // rarely happens but it does. We would fail before with the old code, let's see what the ip table looks like.
494 in_addr subnet, netMask, nextHop;
495 subnet.s_addr = bestRoute.dwForwardDest;
496 netMask.s_addr = bestRoute.dwForwardMask;
497 nextHop.s_addr = bestRoute.dwForwardNextHop;
498 // best-route
499 DebugLog(<< "Best Route - subnet=" <<DnsUtil::inet_ntop(subnet)
500 <<" net-mask=" <<DnsUtil::inet_ntop(netMask)
501 <<" next-hop=" <<DnsUtil::inet_ntop(nextHop)
502 <<" if-index=" <<bestRoute.dwForwardIfIndex );
503 // ip-table
504 for (i=0; i<pIpAddrTable->dwNumEntries; i++)
505 {
506 MIB_IPADDRROW & entry = pIpAddrTable->table[i];
507 in_addr nicIP, nicMask;
508 nicIP.s_addr = entry.dwAddr;
509 nicMask.s_addr = entry.dwMask;
510 DebugLog(<<"IP Table entry " <<i+1 <<'/' <<pIpAddrTable->dwNumEntries <<" if-index=" <<entry.dwIndex
511 <<" NIC IP=" <<DnsUtil::inet_ntop(nicIP)
512 << (entry.wType & MIB_IPADDR_TRANSIENT ? " (Transient)" : "")
513 <<" NIC Mask=" <<DnsUtil::inet_ntop(nicMask) );
514 }
515 }
516
517 delete [] (char *) pIpAddrTable;
518 if(sourceIP.sin_addr.s_addr == 0)
519 {
520 throw Exception("Can't find source address for destination", __FILE__,__LINE__);
521 }
522 return GenericIPAddress(sourceIP);
523}
524#endif // !defined(NO_IPHLPAPI)
525
527WinCompat::determineSourceInterface(const GenericIPAddress& destination)
528{
529// Note: IPHLPAPI has been known to conflict with some thirdparty DLL's.
530// If you don't care about Win95/98/Me as your target system - then
531// you can define NO_IPHLPAPI so that you are not required to link with this
532// library. (SLG)
533
534#if !defined(NO_IPHLPAPI)
535
536 if(destination.isVersion6())
537 {
538 return determineSourceInterfaceWithIPv6(destination);
539 }
540 else
541 {
542 return determineSourceInterfaceWithoutIPv6(destination);
543 }
544
545#else
546 resip_assert(0);
547#endif
548 return GenericIPAddress();
549}
550
551
552std::list<std::pair<Data,Data> >
553WinCompat::getInterfaces(const Data& matching)
554{
555 if (instance()->loadLibraryWithIPv6Failed)
556 {
557 if (instance()->loadLibraryWithIPv4Failed)
558 {
559 throw Exception("Library iphlpapi.dll not available", __FILE__,__LINE__);
560 }
561
562 // Do IPV4 only lookup - useful for Windows versions less than W2k3 and WinXp
563 // Note: This query does not include the Loopback Adapter
564 PIP_ADAPTER_INFO pAdaptersInfo=NULL;
565 std::list<std::pair<Data,Data> > results;
566 DWORD dwRet, dwSize=0;
567 dwRet = (instance()->getAdaptersInfo)(pAdaptersInfo, &dwSize);
568 if (dwRet == ERROR_BUFFER_OVERFLOW) // expected error
569 {
570 // Allocate memory
571 pAdaptersInfo = (PIP_ADAPTER_INFO) LocalAlloc(LMEM_ZEROINIT,dwSize);
572 if (pAdaptersInfo == NULL)
573 {
574 throw Exception("Can't query for adapters info - LocalAlloc error", __FILE__,__LINE__);
575 }
576 dwRet = (instance()->getAdaptersInfo)(pAdaptersInfo, &dwSize);
577 if (dwRet != ERROR_SUCCESS)
578 {
579 LocalFree(pAdaptersInfo);
580 throw Exception("Can't query for adapters info - GetAdaptersInfo", __FILE__,__LINE__);
581 }
582 else
583 {
584 IP_ADAPTER_INFO *AI;
585 int i;
586 for (i = 0, AI = pAdaptersInfo; AI != NULL; AI = AI->Next, i++)
587 {
588 //Data name(AI->AdapterName);
589 Data name(AI->Description);
590 if(matching == Data::Empty || name == matching)
591 {
592 for (const IP_ADDR_STRING *addr=&AI->IpAddressList; addr; addr = addr->Next)
593 {
594 results.push_back(std::make_pair(name, Data(addr->IpAddress.String)));
595 }
596 }
597 }
598 LocalFree(pAdaptersInfo);
599 }
600 }
601 return results;
602 }
603
604 // Use IPV6 compatible query
605 // Note: This query includes the Loopback Adapter
606 // Obtain the size of the structure
607 IP_ADAPTER_ADDRESSES *pAdapterAddresses;
608 std::list<std::pair<Data,Data> > results;
609 DWORD dwRet, dwSize=0;
610 DWORD flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
611 dwRet = (instance()->getAdaptersAddresses)(AF_UNSPEC, flags, NULL, NULL, &dwSize);
612 if (dwRet == ERROR_BUFFER_OVERFLOW) // expected error
613 {
614 // Allocate memory
615 pAdapterAddresses = (IP_ADAPTER_ADDRESSES *) LocalAlloc(LMEM_ZEROINIT,dwSize);
616 if (pAdapterAddresses == NULL)
617 {
618 throw Exception("Can't query for adapter addresses - LocalAlloc error", __FILE__,__LINE__);
619 }
620
621 // Obtain network adapter information (IPv6)
622 dwRet = (instance()->getAdaptersAddresses)(AF_UNSPEC, flags, NULL, pAdapterAddresses, &dwSize);
623 if (dwRet != ERROR_SUCCESS)
624 {
625 LocalFree(pAdapterAddresses);
626 throw Exception("Can't query for adapter addresses - GetAdapterAddresses", __FILE__,__LINE__);
627 }
628 else
629 {
630 IP_ADAPTER_ADDRESSES *AI;
631 int i;
632 for (i = 0, AI = pAdapterAddresses; AI != NULL; AI = AI->Next, i++)
633 {
634 if (AI->FirstUnicastAddress != NULL)
635 {
636 LPSTR pszSimpleCharStringFromLPWSTR = ConvertLPWSTRToLPSTR(AI->FriendlyName);
637 Data name(pszSimpleCharStringFromLPWSTR);
638 delete [] pszSimpleCharStringFromLPWSTR;
639
640 if(matching == Data::Empty || name == matching)
641 {
642 for (PIP_ADAPTER_UNICAST_ADDRESS unicast = AI->FirstUnicastAddress;
643 unicast; unicast = unicast->Next)
644 {
645#ifndef USE_IPV6
646 // otherwise we would get 0.0.0.0 for AF_INET6 addresses
647 if (unicast->Address.lpSockaddr->sa_family != AF_INET) continue;
648#endif
649 results.push_back(std::make_pair(name, DnsUtil::inet_ntop(*unicast->Address.lpSockaddr)));
650 }
651 }
652 }
653 }
654 LocalFree(pAdapterAddresses);
655 }
656 }
657 return results;
658}
659
660
661/* ====================================================================
662 * The Vovida Software License, Version 1.0
663 *
664 * Copyright (c) 2000-2005 Vovida Networks, Inc. All rights reserved.
665 *
666 * Redistribution and use in source and binary forms, with or without
667 * modification, are permitted provided that the following conditions
668 * are met:
669 *
670 * 1. Redistributions of source code must retain the above copyright
671 * notice, this list of conditions and the following disclaimer.
672 *
673 * 2. Redistributions in binary form must reproduce the above copyright
674 * notice, this list of conditions and the following disclaimer in
675 * the documentation and/or other materials provided with the
676 * distribution.
677 *
678 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
679 * and "Vovida Open Communication Application Library (VOCAL)" must
680 * not be used to endorse or promote products derived from this
681 * software without prior written permission. For written
682 * permission, please contact vocal@vovida.org.
683 *
684 * 4. Products derived from this software may not be called "VOCAL", nor
685 * may "VOCAL" appear in their name, without prior written
686 * permission of Vovida Networks, Inc.
687 *
688 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
689 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
690 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
691 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
692 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
693 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
694 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
695 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
696 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
697 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
698 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
699 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
700 * DAMAGE.
701 *
702 * ====================================================================
703 *
704 * This software consists of voluntary contributions made by Vovida
705 * Networks, Inc. and many individuals on behalf of Vovida Networks,
706 * Inc. For more information on Vovida Networks, Inc., please see
707 * <http://www.vovida.org/>.
708 *
709 */
#define DebugLog(args_)
Definition Logger.hxx:128
#define resip_assert(x)
This file needs to work for both C and C++ code.
static char * ConvertLPWSTRToLPSTR(LPWSTR lpwszStrIn)
Definition WinCompat.cxx:21
static Mutex WinComaptInstanceMutex
class WinCompatInstanceCleaner winCompatInstanceCleaner
NTSTATUS NTAPI RtlGetVersion(PRTL_OSVERSIONINFOW lpVersionInformation)
static const struct nv flags[]
Definition adig.c:62
The abstract base-class for all exceptions thrown by resip code.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
static const Data Empty
Constant that represents a zero-length data.
Definition Data.hxx:882
Provides a collection of utility functions for manipulating DNS names and IP addresses and discoverin...
Definition DnsUtil.hxx:29
static Data inet_ntop(const struct in_addr &addr)
Converts from the network format to presentation format.
Definition DnsUtil.cxx:240
dcm! – add UnusedChecking(_enum) below;
std::mutex Mutex
A semaphore that can be locked by only one thread at a time.
Definition Mutex.hxx:37
std::unique_lock< Mutex > Lock
A convenience class to lock a Lockable (such as a Mutex) on object creation, and unlock on destructio...
Definition Lock.hxx:28
unsigned int uint32_t
Definition stdint.h:85
Represents an IP-address and port (V4 or V6).