reSIProcate/rutil  9694
WinCompat.cxx
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include "config.h"
00003 #endif
00004 
00005 #include <Winsock2.h>
00006 #include <Iphlpapi.h>
00007 
00008 #include "rutil/GenericIPAddress.hxx"
00009 #include "rutil/WinCompat.hxx"
00010 #include "rutil/DnsUtil.hxx"
00011 #include "rutil/Log.hxx"
00012 #include "rutil/Logger.hxx"
00013 #include "rutil/WinLeakCheck.hxx"
00014 
00015 #define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT
00016 
00017 
00018 static char* ConvertLPWSTRToLPSTR(LPWSTR lpwszStrIn)
00019 {
00020    LPSTR pszOut = NULL;
00021    if (lpwszStrIn != NULL)
00022    {
00023       int nInputStrLen = (int)wcslen(lpwszStrIn);
00024 
00025       // Double NULL Termination
00026       int nOutputStrLen = WideCharToMultiByte (CP_ACP, 0, lpwszStrIn, nInputStrLen, NULL, 0, 0, 0) + 2;
00027       pszOut = new char [nOutputStrLen];
00028 
00029       if (pszOut)
00030       {
00031          memset (pszOut, 0x00, nOutputStrLen);
00032          WideCharToMultiByte(CP_ACP, 0, lpwszStrIn, nInputStrLen, pszOut, nOutputStrLen, 0, 0);
00033       }
00034    }
00035    return pszOut;
00036 }
00037 
00038 using namespace resip;
00039 
00040 class WinCompatInstanceCleaner
00041 {
00042 public:
00043     ~WinCompatInstanceCleaner() { WinCompat::destroyInstance(); }
00044 } winCompatInstanceCleaner;
00045 
00046 WinCompat::Exception::Exception(const Data& msg, const Data& file, const int line) :
00047    BaseException(msg,file,line)
00048 {
00049 }
00050 
00051 
00052 WinCompat::Version
00053 WinCompat::getVersion()
00054 {
00055 #ifdef UNDER_CE
00056 #define OSVERSIONINFOEX OSVERSIONINFO
00057 #endif
00058    OSVERSIONINFOEX osvi;
00059    BOOL bOsVersionInfoEx;
00060 
00061    // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
00062    // If that fails, try using the OSVERSIONINFO structure.
00063 
00064    ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
00065    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
00066 
00067    if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
00068    {
00069       osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
00070       if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) )
00071       {
00072          return WindowsUnknown;
00073       }
00074    }
00075 
00076    switch (osvi.dwPlatformId)
00077    {
00078       // Test for the Windows NT product family.
00079       case VER_PLATFORM_WIN32_NT:
00080 
00081          // Test for the specific product family.
00082          if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
00083          {
00084             return WinCompat::Windows2003Server;
00085          }
00086          else if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 )
00087          {
00088             return WinCompat::WindowsXP;
00089          }
00090          else if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
00091          {
00092             return WinCompat::Windows2000;
00093          }
00094          else if ( osvi.dwMajorVersion <= 4 )
00095          {
00096             return WinCompat::WindowsNT;
00097          }
00098          break;
00099          
00100          // Test for the Windows 95 product family.
00101       case VER_PLATFORM_WIN32_WINDOWS:
00102          if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
00103          {
00104             return WinCompat::Windows95;
00105          } 
00106          else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
00107          {
00108             if ( osvi.szCSDVersion[1] == 'A' )
00109             {
00110                return WinCompat::Windows98SE;
00111             }
00112             else
00113             {
00114                return WinCompat::Windows98;
00115             }
00116          }
00117          else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
00118          {
00119             return WinCompat::WindowsME;
00120          } 
00121          break;
00122          
00123       default:
00124          return WinCompat::WindowsUnknown;
00125    }
00126 
00127    return WinCompat::WindowsUnknown;
00128 }
00129 
00130 
00131 WinCompat* WinCompat::mInstance = 0;
00132 
00133 
00134 WinCompat *
00135 WinCompat::instance()
00136 {
00137    static Mutex mutex;
00138    if (!mInstance)
00139    {
00140       Lock lock(mutex);
00141       if (!mInstance)
00142       {
00143          mInstance = new WinCompat();
00144       }
00145    }
00146    return mInstance;
00147 }
00148 
00149 
00150 WinCompat::WinCompat() :
00151    getBestInterfaceEx(0), 
00152    getAdaptersAddresses(0),
00153    getAdaptersInfo(0),
00154    loadLibraryWithIPv4Failed(false), 
00155    loadLibraryWithIPv6Failed(false),
00156    hLib(0)
00157 {
00158 
00159    // Note:  IPHLPAPI has been known to conflict with some thirdparty DLL's.
00160    //        If you don't care about Win95/98/Me as your target system - then
00161    //        you can define NO_IPHLPAPI so that you are not required to link with this 
00162    //        library. (SLG)
00163 #if !defined (NO_IPHLPAPI)
00164    // check to see if the GetAdaptersAddresses() is in the IPHLPAPI library
00165    HINSTANCE hLib = LoadLibrary(TEXT("iphlpapi.dll"));
00166    if (hLib == NULL)
00167    {
00168       loadLibraryWithIPv6Failed = true;
00169       loadLibraryWithIPv4Failed = true;
00170       return;
00171    }
00172 
00173    getBestInterfaceEx = (GetBestInterfaceExProc) GetProcAddress(hLib, TEXT("GetBestInterfaceEx"));
00174    getAdaptersAddresses = (GetAdaptersAddressesProc) GetProcAddress(hLib, TEXT("GetAdaptersAddresses"));
00175    getAdaptersInfo = (GetAdaptersInfoProc) GetProcAddress(hLib, TEXT("GetAdaptersInfo"));
00176    if (getAdaptersAddresses == NULL || getBestInterfaceEx == NULL)
00177    {   
00178       loadLibraryWithIPv6Failed = true;
00179    }
00180    if (getAdaptersInfo == NULL)
00181    {
00182       loadLibraryWithIPv4Failed = true;
00183    }
00184 #else
00185    loadLibraryWithIPv6Failed = true;
00186    loadLibraryWithIPv4Failed = true;
00187 #endif
00188 }
00189 
00190 void WinCompat::destroyInstance()
00191 {
00192     delete mInstance;
00193     mInstance = 0;
00194 }
00195 
00196 WinCompat::~WinCompat()
00197 {
00198    if(hLib != NULL)
00199    {
00200       FreeLibrary(hLib);
00201    }
00202 }
00203 
00204 
00205 #if !defined(NO_IPHLPAPI)
00206 // !slg! - This function is horribly slow (upto 200ms) and can cause serious performance issues for servers.
00207 //         We should consider finding more efficient APIs, or caching some of the results.
00208 GenericIPAddress
00209 WinCompat::determineSourceInterfaceWithIPv6(const GenericIPAddress& destination)
00210 {
00211    if (instance()->loadLibraryWithIPv6Failed)
00212    {
00213       throw Exception("Library iphlpapi.dll with IPv6 support not available", __FILE__,__LINE__);
00214    }
00215 
00216    // Obtain the size of the structure
00217    IP_ADAPTER_ADDRESSES *pAdapterAddresses;
00218    DWORD dwRet, dwSize;
00219    DWORD flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
00220    unsigned short family = destination.isVersion6() ? AF_INET6 : AF_INET;
00221    dwRet = (instance()->getAdaptersAddresses)(family, flags, NULL, NULL, &dwSize);
00222    if (dwRet == ERROR_BUFFER_OVERFLOW)  // expected error
00223    {
00224       // Allocate memory
00225       pAdapterAddresses = (IP_ADAPTER_ADDRESSES *) LocalAlloc(LMEM_ZEROINIT,dwSize);
00226       if (pAdapterAddresses == NULL) 
00227       {
00228          throw Exception("Can't find source address for destination", __FILE__,__LINE__);
00229       }
00230 
00231       // Obtain network adapter information (IPv6)
00232       dwRet = (instance()->getAdaptersAddresses)(family, flags, NULL, pAdapterAddresses, &dwSize);
00233       if (dwRet != ERROR_SUCCESS) 
00234       {
00235          LocalFree(pAdapterAddresses);
00236          throw Exception("Can't find source address for destination", __FILE__,__LINE__);
00237       } 
00238    }
00239 
00240    // Check if this address is a local address - this also avoids returning 
00241    // the loopback address that can cause havoc if the registrar and user agent are on the same box
00242    IP_ADAPTER_ADDRESSES *AI;
00243    int i;
00244    for (i = 0, AI = pAdapterAddresses; AI != NULL; AI = AI->Next, i++) 
00245    {
00246       PIP_ADAPTER_UNICAST_ADDRESS defaultAdaptorAddress = 0;
00247       for (PIP_ADAPTER_UNICAST_ADDRESS unicast = AI->FirstUnicastAddress;
00248            unicast; unicast = unicast->Next)
00249       {
00250          if (unicast->Address.lpSockaddr->sa_family != family)
00251             continue;
00252 
00253          // Store first address of matching family as the Adaptors default address
00254          if(!defaultAdaptorAddress) defaultAdaptorAddress = unicast;
00255 
00256          if (family == AF_INET && 
00257              reinterpret_cast<const struct sockaddr_in*>(unicast->Address.lpSockaddr)->sin_addr.S_un.S_addr == 
00258                                                          destination.v4Address.sin_addr.S_un.S_addr)
00259          {
00260             // Return default address for NIC.  Note:  We could also just return the destination, 
00261             // however returning the default address for NIC is beneficial in cases where the
00262             // co-located registrar supports redundancy via a Virtual IP address.
00263             GenericIPAddress ipaddress(*defaultAdaptorAddress->Address.lpSockaddr);
00264             LocalFree(pAdapterAddresses);
00265             return(ipaddress);
00266          }
00267 #ifdef USE_IPV6
00268          else if (family == AF_INET6 && 
00269                   memcmp(&(reinterpret_cast<const struct sockaddr_in6*>(unicast->Address.lpSockaddr)->sin6_addr), 
00270                          &(reinterpret_cast<const struct sockaddr_in6*>(&destination.address)->sin6_addr), 
00271                          sizeof(IN6_ADDR)) == 0)
00272          {
00273             // explicitly cast to sockaddr_in6, to use that version of GenericIPAddress' ctor. If we don't, then compiler
00274             // defaults to ctor for sockaddr_in (at least under Win32), which will truncate the lower-bits of the IPv6 address.
00275             const struct sockaddr_in6* psa = reinterpret_cast<const struct sockaddr_in6*>(defaultAdaptorAddress->Address.lpSockaddr);
00276 
00277             // Return default address for NIC.  Note:  We could also just return the destination, 
00278             // however returning the default address for NIC is beneficial in cases where the
00279             // co-located registrar supports redundancy via a Virtual IP address.
00280             GenericIPAddress ipaddress(*psa);
00281             LocalFree(pAdapterAddresses);
00282             return(ipaddress);
00283          }
00284 #endif
00285       } 
00286    }
00287 
00288    // Not a local address, get the best interface from the OS
00289    DWORD dwBestIfIndex;
00290    const sockaddr* saddr = &destination.address;
00291    if ((instance()->getBestInterfaceEx)((sockaddr *)saddr, &dwBestIfIndex) != NO_ERROR)
00292    {
00293       LocalFree(pAdapterAddresses);
00294       throw Exception("Can't find source address for destination", __FILE__,__LINE__);
00295    }
00296 
00297    for (i = 0, AI = pAdapterAddresses; AI != NULL; AI = AI->Next, i++) 
00298    {
00299        for (PIP_ADAPTER_UNICAST_ADDRESS unicast = AI->FirstUnicastAddress;
00300             unicast; unicast = unicast->Next)
00301        {
00302           if (unicast->Address.lpSockaddr->sa_family != saddr->sa_family)
00303              continue;
00304           if (saddr->sa_family == AF_INET && AI->IfIndex == dwBestIfIndex)
00305           {
00306              GenericIPAddress ipaddress(*unicast->Address.lpSockaddr);
00307              LocalFree(pAdapterAddresses);
00308              return(ipaddress);
00309           }
00310 #ifdef USE_IPV6
00311           else if (saddr->sa_family == AF_INET6 && AI->Ipv6IfIndex == dwBestIfIndex)
00312           {
00313              // explicitly cast to sockaddr_in6, to use that version of GenericIPAddress' ctor. If we don't, then compiler
00314              // defaults to ctor for sockaddr_in (at least under Win32), which will truncate the lower-bits of the IPv6 address.
00315              const struct sockaddr_in6* psa = reinterpret_cast<const struct sockaddr_in6*>(unicast->Address.lpSockaddr);
00316              GenericIPAddress ipaddress(*psa);
00317              LocalFree(pAdapterAddresses);
00318              return(ipaddress);
00319           }
00320 #endif
00321       } 
00322    }
00323    LocalFree(pAdapterAddresses);
00324    throw Exception("Can't find source address for destination", __FILE__,__LINE__);
00325 
00326    return GenericIPAddress();
00327 }
00328 
00329 
00330 GenericIPAddress
00331 WinCompat::determineSourceInterfaceWithoutIPv6(const GenericIPAddress& destination)
00332 {
00333    if (instance()->loadLibraryWithIPv4Failed)
00334    {
00335       throw Exception("Library iphlpapi.dll not available", __FILE__,__LINE__);
00336    }
00337 
00338    struct sockaddr_in sourceIP;
00339    memset(&sourceIP, 0, sizeof(sockaddr_in));
00340    sourceIP.sin_family = AF_INET;
00341 
00342    // look throught the local ip address - first we want to see if the address is local, if 
00343    // not then we want to look for the Best route
00344    PMIB_IPADDRTABLE  pIpAddrTable = NULL;
00345    ULONG addrSize = 0;
00346          
00347    // allocate the space
00348    if (ERROR_INSUFFICIENT_BUFFER == GetIpAddrTable(NULL, &addrSize, FALSE))
00349    {
00350       pIpAddrTable = (PMIB_IPADDRTABLE) new char [addrSize];
00351    } 
00352    else 
00353    {
00354       throw Exception("Can't find source address for destination", __FILE__,__LINE__);
00355    }
00356               
00357    if (NO_ERROR != GetIpAddrTable(pIpAddrTable, &addrSize, FALSE)) 
00358    {
00359        delete [] (char *) pIpAddrTable;
00360        return GenericIPAddress(sourceIP);
00361    }
00362 
00363    // Check if address is local or not
00364    DWORD i = 0;
00365    for(i = 0; i <pIpAddrTable->dwNumEntries; i++)
00366    {
00367       if(pIpAddrTable->table[i].dwAddr ==
00368          destination.v4Address.sin_addr.S_un.S_addr)
00369       {
00370          // Address is local - no need to find best route - this also avoids returning 
00371          // 127.0.0.1 that can cause havoc if the registrar and user agent are on the same box
00372          // Return default address for NIC.  Note:  We could also just return the destination, 
00373          // however returning the default address for NIC is beneficial in cases where the
00374          // co-located registrar supports redundancy via a Virtual IP address.
00375          DWORD dwNicIndex = pIpAddrTable->table[i].dwIndex;
00376          for(DWORD j = 0; j <pIpAddrTable->dwNumEntries; j++)
00377          {
00378             if(pIpAddrTable->table[j].dwIndex == dwNicIndex)  // Default address is first address found for NIC
00379             {
00380                sourceIP.sin_addr.s_addr = pIpAddrTable->table[j].dwAddr;               
00381                delete [] (char *) pIpAddrTable;
00382                return GenericIPAddress(sourceIP);
00383             }
00384          }
00385       }
00386    }
00387 
00388    // try to figure the best route to the destination
00389    MIB_IPFORWARDROW bestRoute;
00390    memset(&bestRoute, 0, sizeof(bestRoute));
00391    const sockaddr_in& sin = (const sockaddr_in&)destination.address;
00392    if (NO_ERROR != GetBestRoute(sin.sin_addr.s_addr, 0, &bestRoute)) 
00393    {
00394       delete [] (char *) pIpAddrTable;
00395       throw Exception("Can't find source address for destination", __FILE__,__LINE__);
00396    }
00397       
00398    // look throught the local ip address to find one that match the best route.
00399    enum ENICEntryPreference {ENICUnknown = 0, ENextHopNotWithinNICSubnet, ENICSubnetIsAll1s, ENICServicesNextHop};
00400    ENICEntryPreference eCurrSelection = ENICUnknown;
00401 
00402    // try to find a match
00403    for (i=0; i<pIpAddrTable->dwNumEntries; i++) 
00404    {
00405       MIB_IPADDRROW &entry = pIpAddrTable->table[i];
00406       
00407       ULONG addr = pIpAddrTable->table[i].dwAddr;
00408       ULONG gw = bestRoute.dwForwardNextHop;
00409       if(entry.dwIndex == bestRoute.dwForwardIfIndex)    // Note: there MAY be > 1 entry with the same index, see AddIPAddress.
00410       {
00411          if( (entry.dwAddr & entry.dwMask) == (bestRoute.dwForwardNextHop & entry.dwMask) )
00412          {
00413             sourceIP.sin_addr.s_addr = entry.dwAddr;
00414             eCurrSelection = ENICServicesNextHop;
00415             break;
00416          }
00417          else if (entry.dwMask == 0xffffffff && eCurrSelection < ENICSubnetIsAll1s)
00418          {
00419             sourceIP.sin_addr.s_addr = entry.dwAddr;
00420             eCurrSelection = ENICSubnetIsAll1s;    // Lucent/Avaya VPN has Subnet Mask of 255.255.255.255. Illegal perhaps but we should use
00421                                                    // if cannot find one that serves next hop.
00422          }
00423          else if (eCurrSelection < ENextHopNotWithinNICSubnet)
00424          {
00425             sourceIP.sin_addr.s_addr = entry.dwAddr;
00426             eCurrSelection = ENextHopNotWithinNICSubnet;   // should use if nothing else works since bestRoute told us to use this NIC.
00427          }
00428       }
00429    }
00430 
00431    if (eCurrSelection != ENICServicesNextHop)
00432    {
00433       // rarely happens but it does. We would fail before with the old code, let's see what the ip table looks like.
00434       in_addr subnet, netMask, nextHop;
00435       subnet.s_addr = bestRoute.dwForwardDest;
00436       netMask.s_addr = bestRoute.dwForwardMask;
00437       nextHop.s_addr = bestRoute.dwForwardNextHop;
00438       // best-route
00439       DebugLog(<< "Best Route - subnet=" <<DnsUtil::inet_ntop(subnet)
00440                <<" net-mask=" <<DnsUtil::inet_ntop(netMask)
00441                <<" next-hop=" <<DnsUtil::inet_ntop(nextHop)
00442                <<" if-index=" <<bestRoute.dwForwardIfIndex );
00443       // ip-table
00444       for (i=0; i<pIpAddrTable->dwNumEntries; i++)
00445       {
00446          MIB_IPADDRROW & entry = pIpAddrTable->table[i];
00447          in_addr nicIP, nicMask;
00448          nicIP.s_addr = entry.dwAddr;
00449          nicMask.s_addr = entry.dwMask;
00450          DebugLog(<<"IP Table entry " <<i+1 <<'/' <<pIpAddrTable->dwNumEntries <<" if-index=" <<entry.dwIndex
00451                   <<" NIC IP=" <<DnsUtil::inet_ntop(nicIP)
00452                   <<" NIC Mask=" <<DnsUtil::inet_ntop(nicMask) );
00453       }
00454    }
00455    
00456    delete [] (char *) pIpAddrTable;
00457    return GenericIPAddress(sourceIP);
00458 }
00459 #endif // !defined(NO_IPHLPAPI)
00460 
00461 GenericIPAddress
00462 WinCompat::determineSourceInterface(const GenericIPAddress& destination)
00463 {
00464 // Note:  IPHLPAPI has been known to conflict with some thirdparty DLL's.
00465 //        If you don't care about Win95/98/Me as your target system - then
00466 //        you can define NO_IPHLPAPI so that you are not required to link with this 
00467 //        library. (SLG)
00468 
00469 #if !defined(NO_IPHLPAPI)
00470 
00471    if(destination.isVersion6())
00472    {
00473       return  determineSourceInterfaceWithIPv6(destination);
00474    }
00475    else
00476    {
00477       return determineSourceInterfaceWithoutIPv6(destination);
00478    }  
00479 
00480 #else
00481    assert(0);
00482 #endif
00483    return GenericIPAddress();
00484 }
00485 
00486 
00487 std::list<std::pair<Data,Data> >
00488 WinCompat::getInterfaces(const Data& matching)
00489 {
00490    if (instance()->loadLibraryWithIPv6Failed)
00491    {
00492       if (instance()->loadLibraryWithIPv4Failed)
00493       {
00494          throw Exception("Library iphlpapi.dll not available", __FILE__,__LINE__);
00495       }
00496 
00497       // Do IPV4 only lookup - useful for Windows versions less than W2k3 and WinXp
00498       // Note:  This query does not include the Loopback Adapter
00499       PIP_ADAPTER_INFO pAdaptersInfo=NULL;
00500       std::list<std::pair<Data,Data> > results;
00501       DWORD dwRet, dwSize=0;
00502       dwRet = (instance()->getAdaptersInfo)(pAdaptersInfo, &dwSize);
00503       if (dwRet == ERROR_BUFFER_OVERFLOW)  // expected error
00504       {
00505          // Allocate memory
00506          pAdaptersInfo = (PIP_ADAPTER_INFO) LocalAlloc(LMEM_ZEROINIT,dwSize);
00507          if (pAdaptersInfo == NULL) 
00508          {
00509             throw Exception("Can't query for adapters info - LocalAlloc error", __FILE__,__LINE__);
00510          }
00511          dwRet = (instance()->getAdaptersInfo)(pAdaptersInfo, &dwSize);
00512          if (dwRet != ERROR_SUCCESS) 
00513          {
00514             LocalFree(pAdaptersInfo);
00515             throw Exception("Can't query for adapters info - GetAdaptersInfo", __FILE__,__LINE__);
00516          } 
00517          else 
00518          {
00519             IP_ADAPTER_INFO *AI;
00520             int i;
00521             for (i = 0, AI = pAdaptersInfo; AI != NULL; AI = AI->Next, i++) 
00522             {
00523                //Data name(AI->AdapterName);
00524                Data name(AI->Description);
00525                if(matching == Data::Empty || name == matching)
00526                {
00527                   for (const IP_ADDR_STRING *addr=&AI->IpAddressList; addr; addr = addr->Next)
00528                   {
00529                      results.push_back(std::make_pair(name, Data(addr->IpAddress.String)));
00530                   }
00531                }
00532             }
00533             LocalFree(pAdaptersInfo);
00534          }
00535       }
00536       return results;
00537    }
00538 
00539    // Use IPV6 compatible query
00540    // Note:  This query includes the Loopback Adapter
00541    // Obtain the size of the structure
00542    IP_ADAPTER_ADDRESSES *pAdapterAddresses;
00543    std::list<std::pair<Data,Data> > results;
00544    DWORD dwRet, dwSize=0;
00545    DWORD flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
00546    dwRet = (instance()->getAdaptersAddresses)(AF_UNSPEC, flags, NULL, NULL, &dwSize);
00547    if (dwRet == ERROR_BUFFER_OVERFLOW)  // expected error
00548    {
00549       // Allocate memory
00550       pAdapterAddresses = (IP_ADAPTER_ADDRESSES *) LocalAlloc(LMEM_ZEROINIT,dwSize);
00551       if (pAdapterAddresses == NULL) 
00552       {
00553          throw Exception("Can't query for adapter addresses - LocalAlloc error", __FILE__,__LINE__);
00554       }
00555 
00556       // Obtain network adapter information (IPv6)
00557       dwRet = (instance()->getAdaptersAddresses)(AF_UNSPEC, flags, NULL, pAdapterAddresses, &dwSize);
00558       if (dwRet != ERROR_SUCCESS) 
00559       {
00560          LocalFree(pAdapterAddresses);
00561          throw Exception("Can't query for adapter addresses - GetAdapterAddresses", __FILE__,__LINE__);
00562       } 
00563       else 
00564       {
00565          IP_ADAPTER_ADDRESSES *AI;
00566          int i;
00567          for (i = 0, AI = pAdapterAddresses; AI != NULL; AI = AI->Next, i++) 
00568          {
00569             if (AI->FirstUnicastAddress != NULL) 
00570             {
00571                LPSTR pszSimpleCharStringFromLPWSTR = ConvertLPWSTRToLPSTR(AI->FriendlyName);
00572                Data name(pszSimpleCharStringFromLPWSTR);
00573                delete [] pszSimpleCharStringFromLPWSTR;
00574 
00575                if(matching == Data::Empty || name == matching)
00576                {
00577                   for (PIP_ADAPTER_UNICAST_ADDRESS unicast = AI->FirstUnicastAddress;
00578                        unicast; unicast = unicast->Next)
00579                   {
00580 #ifndef USE_IPV6
00581                      // otherwise we would get 0.0.0.0 for AF_INET6 addresses
00582                      if (unicast->Address.lpSockaddr->sa_family != AF_INET) continue;
00583 #endif
00584                      results.push_back(std::make_pair(name, DnsUtil::inet_ntop(*unicast->Address.lpSockaddr)));
00585                   }
00586                }
00587             } 
00588          }
00589          LocalFree(pAdapterAddresses);
00590       }      
00591    }
00592    return results;
00593 }
00594 
00595 
00596 /* ====================================================================
00597  * The Vovida Software License, Version 1.0 
00598  * 
00599  * Copyright (c) 2000-2005 Vovida Networks, Inc.  All rights reserved.
00600  * 
00601  * Redistribution and use in source and binary forms, with or without
00602  * modification, are permitted provided that the following conditions
00603  * are met:
00604  * 
00605  * 1. Redistributions of source code must retain the above copyright
00606  *    notice, this list of conditions and the following disclaimer.
00607  * 
00608  * 2. Redistributions in binary form must reproduce the above copyright
00609  *    notice, this list of conditions and the following disclaimer in
00610  *    the documentation and/or other materials provided with the
00611  *    distribution.
00612  * 
00613  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00614  *    and "Vovida Open Communication Application Library (VOCAL)" must
00615  *    not be used to endorse or promote products derived from this
00616  *    software without prior written permission. For written
00617  *    permission, please contact vocal@vovida.org.
00618  *
00619  * 4. Products derived from this software may not be called "VOCAL", nor
00620  *    may "VOCAL" appear in their name, without prior written
00621  *    permission of Vovida Networks, Inc.
00622  * 
00623  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00624  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00625  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00626  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00627  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00628  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00629  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00630  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00631  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00632  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00633  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00634  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00635  * DAMAGE.
00636  * 
00637  * ====================================================================
00638  * 
00639  * This software consists of voluntary contributions made by Vovida
00640  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00641  * Inc.  For more information on Vovida Networks, Inc., please see
00642  * <http://www.vovida.org/>.
00643  *
00644  */