diff --git a/CHANGELOG b/CHANGELOG index dbf9e1b50..06efc7c1a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -64,6 +64,8 @@ Release 1.5.3 (2014-05-xx) - fixed GH #321: trivial build fixes (BB QNX build) - fixed GH #440: MongoDB ObjectId string formatting - added SevenZip library (Guenter Obiltschnig) +- fixed GH #442: Use correct prefix length field of Windows IP_ADAPTER_PREFIX structure +- improved GH #328: NetworkInterface on Windows XP Release 1.5.2 (2013-09-16) ========================== diff --git a/Foundation/include/Poco/Platform_WIN32.h b/Foundation/include/Poco/Platform_WIN32.h index 752b25225..b8c61b99b 100755 --- a/Foundation/include/Poco/Platform_WIN32.h +++ b/Foundation/include/Poco/Platform_WIN32.h @@ -24,31 +24,55 @@ #include "Poco/UnWindows.h" -// determine the real version -#if defined(_WIN32_WINNT_WIN8) +// Determine the real version. +// This setting can be forced from UnWindows.h +#if defined (_WIN32_WINNT_WINBLUE) + //Windows 8.1 _WIN32_WINNT_WINBLUE (0x0602) + #ifdef _WIN32_WINNT + #undef _WIN32_WINNT + #endif + #define _WIN32_WINNT _WIN32_WINNT_WINBLUE + #ifdef NTDDI_VERSION + #undef NTDDI_VERSION + #endif + #define NTDDI_VERSION NTDDI_WINBLUE +#elif defined (_WIN32_WINNT_WIN8) //Windows 8 _WIN32_WINNT_WIN8 (0x0602) #ifdef _WIN32_WINNT #undef _WIN32_WINNT #endif #define _WIN32_WINNT _WIN32_WINNT_WIN8 -#elif defined(_WIN32_WINNT_WIN7) + #ifdef NTDDI_VERSION + #undef NTDDI_VERSION + #endif + #define NTDDI_VERSION NTDDI_WIN8 +#elif defined (_WIN32_WINNT_WIN7) //Windows 7 _WIN32_WINNT_WIN7 (0x0601) #ifdef _WIN32_WINNT #undef _WIN32_WINNT #endif #define _WIN32_WINNT _WIN32_WINNT_WIN7 + #ifndef NTDDI_VERSION + #define NTDDI_VERSION NTDDI_WIN7 + #endif #elif defined (_WIN32_WINNT_WS08) //Windows Server 2008 _WIN32_WINNT_WS08 (0x0600) #ifdef _WIN32_WINNT #undef _WIN32_WINNT #endif #define _WIN32_WINNT _WIN32_WINNT_WS08 + #ifndef NTDDI_VERSION + #define NTDDI_VERSION NTDDI_WS08 + #endif #elif defined (_WIN32_WINNT_VISTA) //Windows Vista _WIN32_WINNT_VISTA (0x0600) #ifdef _WIN32_WINNT #undef _WIN32_WINNT #endif #define _WIN32_WINNT _WIN32_WINNT_VISTA + #ifndef NTDDI_VERSION + #define NTDDI_VERSION NTDDI_VISTA + #endif #elif defined (_WIN32_WINNT_LONGHORN) //Windows Vista and server 2008 Development _WIN32_WINNT_LONGHORN (0x0600) #ifdef _WIN32_WINNT @@ -62,12 +86,18 @@ #undef _WIN32_WINNT #endif #define _WIN32_WINNT _WIN32_WINNT_WS03 + #ifndef NTDDI_VERSION + #define NTDDI_VERSION NTDDI_WS03 + #endif #elif defined (_WIN32_WINNT_WINXP) //Windows Server 2003, Windows XP _WIN32_WINNT_WINXP (0x0501) #ifdef _WIN32_WINNT #undef _WIN32_WINNT #endif #define _WIN32_WINNT _WIN32_WINNT_WINXP + #ifndef NTDDI_VERSION + #define NTDDI_VERSION NTDDI_WINXP + #endif #elif defined (_WIN32_WINNT_WIN2K) //Windows 2000 _WIN32_WINNT_WIN2K (0x0500) #ifdef _WIN32_WINNT @@ -75,10 +105,18 @@ #endif #define _WIN32_WINNT _WIN32_WINNT_WIN2K #elif defined (WINVER) + // fail back on WINVER #ifdef _WIN32_WINNT #undef _WIN32_WINNT #endif #define _WIN32_WINNT WINVER +#elif !defined(_WIN32_WINNT) + // last resort = Win XP, SP1 is minimum supported + #define _WIN32_WINNT 0x0501 + #ifdef NTDDI_VERSION + #undef NTDDI_VERSION + #endif + #define NTDDI_VERSION 0x05010100 #endif diff --git a/Foundation/include/Poco/UnWindows.h b/Foundation/include/Poco/UnWindows.h index 2f3a10ae5..60157b857 100755 --- a/Foundation/include/Poco/UnWindows.h +++ b/Foundation/include/Poco/UnWindows.h @@ -47,11 +47,29 @@ #endif +// Microsoft Visual C++ includes copies of the Windows header files +// that were current at the time Visual C++ was released. +// The Windows header files use macros to indicate which versions +// of Windows support many programming elements. Therefore, you must +// define these macros to use new functionality introduced in each +// major operating system release. (Individual header files may use +// different macros; therefore, if compilation problems occur, check +// the header file that contains the definition for conditional +// definitions.) For more information, see SdkDdkVer.h. + #if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0501) #error Unsupported Windows version. +#elif defined(NTDDI_VERSION) && (NTDDI_VERSION < 0x05010100) + #error Unsupported Windows version. #elif !defined(_WIN32_WINNT) - // define minimum supported + // Define minimum supported version. + // This can be changed, if needed. + // Otherwise, the Platform_WIN32.h will do + // its best to determine the appropriate values + // and may redefine these. See Platform_WIN32.h + // for details. #define _WIN32_WINNT 0x0501 + #define NTDDI_VERSION 0x05010100 #endif diff --git a/Net/include/Poco/Net/NetworkInterface.h b/Net/include/Poco/Net/NetworkInterface.h index 066c768a8..ee4f118c5 100755 --- a/Net/include/Poco/Net/NetworkInterface.h +++ b/Net/include/Poco/Net/NetworkInterface.h @@ -49,6 +49,16 @@ class Net_API NetworkInterface /// The class also provides static member functions for /// enumerating or searching network interfaces and their /// respective configuration values. + /// + /// On Windows, detection capabilities vary depending on the + /// OS version/service pack. Although the best effort is made + /// not to attempt access to non-existent features through a + /// combination of compile/runtime checks, when running binaries + /// compiled on a newer version of the OS on an older one + /// problems may occur; if possible, it is best to run + /// binaries on the OS version where they were compiled. + /// This particularly applies to OS versions older than Vista + /// and XP. { public: typedef std::vector List; diff --git a/Net/src/NetworkInterface.cpp b/Net/src/NetworkInterface.cpp index bf99e6d28..49e167ed7 100755 --- a/Net/src/NetworkInterface.cpp +++ b/Net/src/NetworkInterface.cpp @@ -966,11 +966,66 @@ NetworkInterface::Type fromNative(DWORD type) } } + +IPAddress subnetMaskForInterface(const std::string& name, bool isLoopback) +{ + if (isLoopback) + { + return IPAddress::parse("255.0.0.0"); + } + else + { + std::string subKey("SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces\\"); + subKey += name; + std::string netmask; + HKEY hKey; +#if defined(POCO_WIN32_UTF8) && !defined(POCO_NO_WSTRING) + std::wstring usubKey; + Poco::UnicodeConverter::toUTF16(subKey, usubKey); + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, usubKey.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS) + return IPAddress(); + wchar_t unetmask[16]; + DWORD size = sizeof(unetmask); + if (RegQueryValueExW(hKey, L"DhcpSubnetMask", NULL, NULL, (LPBYTE)&unetmask, &size) != ERROR_SUCCESS) + { + if (RegQueryValueExW(hKey, L"SubnetMask", NULL, NULL, (LPBYTE)&unetmask, &size) != ERROR_SUCCESS) + { + RegCloseKey(hKey); + return IPAddress(); + } + } + Poco::UnicodeConverter::toUTF8(unetmask, netmask); +#else + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, subKey.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS) + return IPAddress(); + char unetmask[16]; + DWORD size = sizeof(unetmask); + if (RegQueryValueExA(hKey, "DhcpSubnetMask", NULL, NULL, (LPBYTE)&unetmask, &size) != ERROR_SUCCESS) + { + if (RegQueryValueExA(hKey, "SubnetMask", NULL, NULL, (LPBYTE)&unetmask, &size) != ERROR_SUCCESS) + { + RegCloseKey(hKey); + return IPAddress(); + } + } + netmask = unetmask; +#endif + RegCloseKey(hKey); + return IPAddress::parse(netmask); + } +} + + } /// namespace NetworkInterface::Map NetworkInterface::map(bool ipOnly, bool upOnly) { + OSVERSIONINFO osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + FastMutex::ScopedLock lock(_mutex); Map result; ULONG outBufLen = 16384; @@ -1010,15 +1065,32 @@ NetworkInterface::Map NetworkInterface::map(bool ipOnly, bool upOnly) unsigned ifIndex = 0; #if defined(POCO_HAVE_IPv6) - #if (_WIN32_WINNT >= 0x600) && defined (IP_ADAPTER_IPV6_ENABLED) - if (pAddress->Flags & IP_ADAPTER_IPV6_ENABLED) ifIndex = pAddress->Ipv6IfIndex; - #else - ifIndex = pAddress->Ipv6IfIndex; - #endif -#endif -#if (_WIN32_WINNT >= 0x600) && defined (IP_ADAPTER_IPV4_ENABLED) - if (pAddress->Flags & IP_ADAPTER_IPV4_ENABLED) ifIndex = pAddress->IfIndex; -#else + #if (_WIN32_WINNT >= 0x0501) && (NTDDI_VERSION >= 0x05010100) // Win XP SP1 + #if defined (IP_ADAPTER_IPV6_ENABLED) // Vista + if ((pAddress->Flags & IP_ADAPTER_IPV6_ENABLED) && + (osvi.dwMajorVersion >= 5) && + (osvi.dwMinorVersion >= 1) && + (osvi.dwBuildNumber >=1)) + { + ifIndex = pAddress->Ipv6IfIndex; + } + #else // !defined(IP_ADAPTER_IPV6_ENABLED) + if ((osvi.dwMajorVersion >= 5) && + (osvi.dwMinorVersion >= 1) && + (osvi.dwBuildNumber >= 0)) + { + ifIndex = pAddress->Ipv6IfIndex; + } + #endif // defined(IP_ADAPTER_IPV6_ENABLED) + #endif // (_WIN32_WINNT >= 0x0501) && (NTDDI_VERSION >= 0x05010100) +#endif // POCO_HAVE_IPv6 + +#if defined (IP_ADAPTER_IPV4_ENABLED) + if (pAddress->Flags & IP_ADAPTER_IPV4_ENABLED) + { + ifIndex = pAddress->IfIndex; + } +#else // !IP_ADAPTER_IPV4_ENABLED ifIndex = pAddress->IfIndex; #endif if (ifIndex == 0) continue; @@ -1054,7 +1126,12 @@ NetworkInterface::Map NetworkInterface::map(bool ipOnly, bool upOnly) ifIt->second.impl().setMTU(pAddress->Mtu); ifIt->second.impl().setUp(pAddress->OperStatus == IfOperStatusUp); #if (_WIN32_WINNT >= 0x0600) // Vista and newer only - ifIt->second.impl().setRunning(pAddress->ReceiveLinkSpeed > 0 || pAddress->TransmitLinkSpeed > 0); + if ((osvi.dwMajorVersion >= 6) && + (osvi.dwMinorVersion >= 0) && + (osvi.dwBuildNumber >= 0)) + { + ifIt->second.impl().setRunning(pAddress->ReceiveLinkSpeed > 0 || pAddress->TransmitLinkSpeed > 0); + } #endif ifIt->second.impl().setType(fromNative(pAddress->IfType)); if (pAddress->PhysicalAddressLength) @@ -1077,10 +1154,11 @@ NetworkInterface::Map NetworkInterface::map(bool ipOnly, bool upOnly) // On Windows, a valid broadcast address will be all 1's (== address | ~subnetMask); additionaly, on pre-Vista versions of // OS, master address structure does not contain member for prefix length; we go an extra mile here in order to make sure // we reflect the actual values held by system and protect against misconfiguration (e.g. bad DHCP config entry) -#if (_WIN32_WINNT >= 0x0600) // Vista and newer +#if (_WIN32_WINNT >= 0x0501) && (NTDDI_VERSION >= 0x05010100) // Win XP SP1 + #if (_WIN32_WINNT >= 0x0600) // Vista and newer UINT8 prefixLength = pUniAddr->OnLinkPrefixLength; broadcastAddress = getBroadcastAddress(pAddress->FirstPrefix, address); -#else + #else // _WIN32_WINNT < 0x0600 ULONG prefixLength = 0; broadcastAddress = getBroadcastAddress(pAddress->FirstPrefix, address, &prefixLength); // if previous call did not do it, make last-ditch attempt for prefix and broadcast @@ -1093,8 +1171,22 @@ NetworkInterface::Map NetworkInterface::map(bool ipOnly, bool upOnly) IPAddress host(mask & address); broadcastAddress = host | ~mask; } -#endif - subnetMask = prefixLength ? IPAddress(prefixLength, IPAddress::IPv4) : IPAddress(); + #endif // _WIN32_WINNT >= 0x0600 +#endif // (_WIN32_WINNT >= 0x0501) && (NTDDI_VERSION >= 0x05010100) + if (prefixLength) + { + subnetMask = IPAddress(prefixLength, IPAddress::IPv4); + } + else // if all of the above fails, look up the subnet mask in the registry + { + address = IPAddress(&reinterpret_cast(pUniAddr->Address.lpSockaddr)->sin_addr, sizeof(in_addr)); + subnetMask = subnetMaskForInterface(name, address.isLoopback()); + if (!address.isLoopback()) + { + broadcastAddress = address; + broadcastAddress.mask(subnetMask, IPAddress::broadcast()); + } + } ifIt->second.addAddress(address, subnetMask, broadcastAddress); } else