From 63f4bfa54b4345c40be271d6b76eceecd0a2c735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnter=20Obiltschnig?= Date: Mon, 15 Sep 2014 19:17:09 +0200 Subject: [PATCH] fixed NetworkInterface for WinCE code cleanup in NetworkInterface class IPAddress: do not format IPv6 loopback address as IPv4 compatible workaround for WEC2013 getsockname() issue testsuite fixes for WEC2013 --- Net/src/IPAddress.cpp | 5 +- Net/src/IPAddressImpl.cpp | 35 +++++++++- Net/src/NetworkInterface.cpp | 74 ++++++++++++++++------ Net/src/TCPServer.cpp | 9 +++ Net/testsuite/src/FTPClientSessionTest.cpp | 8 ++- Net/testsuite/src/IPAddressTest.cpp | 4 ++ Net/testsuite/src/NetworkInterfaceTest.cpp | 4 +- Net/testsuite/src/TCPServerTest.cpp | 16 ++--- 8 files changed, 120 insertions(+), 35 deletions(-) diff --git a/Net/src/IPAddress.cpp b/Net/src/IPAddress.cpp index 9a856b97f..cd32e3a53 100644 --- a/Net/src/IPAddress.cpp +++ b/Net/src/IPAddress.cpp @@ -159,16 +159,19 @@ IPAddress::IPAddress(unsigned prefix, Family family) { if (prefix <= 32) newIPv4(prefix); + else + throw Poco::InvalidArgumentException("Invalid prefix length passed to IPAddress()"); } #if defined(POCO_HAVE_IPv6) else if (family == IPv6) { if (prefix <= 128) newIPv6(prefix); + else + throw Poco::InvalidArgumentException("Invalid prefix length passed to IPAddress()"); } #endif else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()"); - if (!pImpl()) throw Poco::InvalidArgumentException("Invalid prefix length passed to IPAddress()"); } diff --git a/Net/src/IPAddressImpl.cpp b/Net/src/IPAddressImpl.cpp index d0a293687..b237711b5 100644 --- a/Net/src/IPAddressImpl.cpp +++ b/Net/src/IPAddressImpl.cpp @@ -56,6 +56,7 @@ namespace Poco { namespace Net { namespace Impl { + // // IPAddressImpl // @@ -75,6 +76,7 @@ IPAddressImpl::~IPAddressImpl() // IPv4AddressImpl // + IPv4AddressImpl::IPv4AddressImpl() { std::memset(&_addr, 0, sizeof(_addr)); @@ -348,11 +350,13 @@ IPv6AddressImpl::IPv6AddressImpl(): _scope(0) std::memset(&_addr, 0, sizeof(_addr)); } + IPv6AddressImpl::IPv6AddressImpl(const void* addr): _scope(0) { std::memcpy(&_addr, addr, sizeof(_addr)); } + IPv6AddressImpl::IPv6AddressImpl(const void* addr, Poco::UInt32 scope): _scope(scope) { std::memcpy(&_addr, addr, sizeof(_addr)); @@ -396,10 +400,11 @@ IPv6AddressImpl::IPv6AddressImpl(unsigned prefix): #endif } + std::string IPv6AddressImpl::toString() const { const UInt16* words = reinterpret_cast(&_addr); - if (isIPv4Compatible() || isIPv4Mapped()) + if ((isIPv4Compatible() && !isLoopback()) || isIPv4Mapped()) { std::string result; result.reserve(24); @@ -460,26 +465,31 @@ std::string IPv6AddressImpl::toString() const } } + poco_socklen_t IPv6AddressImpl::length() const { return sizeof(_addr); } + const void* IPv6AddressImpl::addr() const { return &_addr; } + IPAddressImpl::Family IPv6AddressImpl::family() const { return IPAddressImpl::IPv6; } + int IPv6AddressImpl::af() const { return AF_INET6; } + unsigned IPv6AddressImpl::prefixLength() const { unsigned bits = 0; @@ -510,6 +520,7 @@ Poco::UInt32 IPv6AddressImpl::scope() const return _scope; } + bool IPv6AddressImpl::isWildcard() const { const UInt16* words = reinterpret_cast(&_addr); @@ -517,11 +528,13 @@ bool IPv6AddressImpl::isWildcard() const words[4] == 0 && words[5] == 0 && words[6] == 0 && words[7] == 0; } + bool IPv6AddressImpl::isBroadcast() const { return false; } + bool IPv6AddressImpl::isLoopback() const { const UInt16* words = reinterpret_cast(&_addr); @@ -529,72 +542,84 @@ bool IPv6AddressImpl::isLoopback() const words[4] == 0 && words[5] == 0 && words[6] == 0 && ntohs(words[7]) == 0x0001; } + bool IPv6AddressImpl::isMulticast() const { const UInt16* words = reinterpret_cast(&_addr); return (ntohs(words[0]) & 0xFFE0) == 0xFF00; } - + + bool IPv6AddressImpl::isLinkLocal() const { const UInt16* words = reinterpret_cast(&_addr); return (ntohs(words[0]) & 0xFFE0) == 0xFE80; } + bool IPv6AddressImpl::isSiteLocal() const { const UInt16* words = reinterpret_cast(&_addr); return ((ntohs(words[0]) & 0xFFE0) == 0xFEC0) || ((ntohs(words[0]) & 0xFF00) == 0xFC00); } + bool IPv6AddressImpl::isIPv4Compatible() const { const UInt16* words = reinterpret_cast(&_addr); return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && words[4] == 0 && words[5] == 0; } + bool IPv6AddressImpl::isIPv4Mapped() const { const UInt16* words = reinterpret_cast(&_addr); return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && words[4] == 0 && ntohs(words[5]) == 0xFFFF; } + bool IPv6AddressImpl::isWellKnownMC() const { const UInt16* words = reinterpret_cast(&_addr); return (ntohs(words[0]) & 0xFFF0) == 0xFF00; } + bool IPv6AddressImpl::isNodeLocalMC() const { const UInt16* words = reinterpret_cast(&_addr); return (ntohs(words[0]) & 0xFFEF) == 0xFF01; } + bool IPv6AddressImpl::isLinkLocalMC() const { const UInt16* words = reinterpret_cast(&_addr); return (ntohs(words[0]) & 0xFFEF) == 0xFF02; } + bool IPv6AddressImpl::isSiteLocalMC() const { const UInt16* words = reinterpret_cast(&_addr); return (ntohs(words[0]) & 0xFFEF) == 0xFF05; } + bool IPv6AddressImpl::isOrgLocalMC() const { const UInt16* words = reinterpret_cast(&_addr); return (ntohs(words[0]) & 0xFFEF) == 0xFF08; } + bool IPv6AddressImpl::isGlobalMC() const { const UInt16* words = reinterpret_cast(&_addr); return (ntohs(words[0]) & 0xFFEF) == 0xFF0F; } + IPv6AddressImpl IPv6AddressImpl::parse(const std::string& addr) { if (addr.empty()) return IPv6AddressImpl(); @@ -637,16 +662,19 @@ IPv6AddressImpl IPv6AddressImpl::parse(const std::string& addr) #endif } + void IPv6AddressImpl::mask(const IPAddressImpl* pMask, const IPAddressImpl* pSet) { throw Poco::NotImplementedException("mask() is only supported for IPv4 addresses"); } + IPAddressImpl* IPv6AddressImpl::clone() const { return new IPv6AddressImpl(&_addr, _scope); } + IPv6AddressImpl IPv6AddressImpl::operator & (const IPv6AddressImpl& addr) const { IPv6AddressImpl result(&_addr); @@ -668,6 +696,7 @@ IPv6AddressImpl IPv6AddressImpl::operator & (const IPv6AddressImpl& addr) const return result; } + IPv6AddressImpl IPv6AddressImpl::operator | (const IPv6AddressImpl& addr) const { IPv6AddressImpl result(&_addr); @@ -689,6 +718,7 @@ IPv6AddressImpl IPv6AddressImpl::operator | (const IPv6AddressImpl& addr) const return result; } + IPv6AddressImpl IPv6AddressImpl::operator ^ (const IPv6AddressImpl& addr) const { IPv6AddressImpl result(&_addr); @@ -710,6 +740,7 @@ IPv6AddressImpl IPv6AddressImpl::operator ^ (const IPv6AddressImpl& addr) const return result; } + IPv6AddressImpl IPv6AddressImpl::operator ~ () const { IPv6AddressImpl result(&_addr); diff --git a/Net/src/NetworkInterface.cpp b/Net/src/NetworkInterface.cpp index 7270eb5d1..7972e3069 100644 --- a/Net/src/NetworkInterface.cpp +++ b/Net/src/NetworkInterface.cpp @@ -151,13 +151,20 @@ private: NetworkInterface::MACAddress _macAddress; - friend NetworkInterface::Map NetworkInterface::map(bool, bool); + friend class NetworkInterface; }; NetworkInterfaceImpl::NetworkInterfaceImpl(unsigned index): _index(index), - _mtu(0) + _broadcast(false), + _loopback(false), + _multicast(false), + _pointToPoint(false), + _up(false), + _running(false), + _mtu(0), + _type(NetworkInterface::NI_TYPE_OTHER) { } @@ -173,7 +180,8 @@ NetworkInterfaceImpl::NetworkInterfaceImpl(const std::string& name, const std::s _pointToPoint(false), _up(false), _running(false), - _mtu(0) + _mtu(0), + _type(NetworkInterface::NI_TYPE_OTHER) { _addressList.push_back(AddressTuple(address, IPAddress(), IPAddress())); setPhyParams(); @@ -192,7 +200,8 @@ NetworkInterfaceImpl::NetworkInterfaceImpl(const std::string& name, const std::s _pointToPoint(false), _up(false), _running(false), - _mtu(0) + _mtu(0), + _type(NetworkInterface::NI_TYPE_OTHER) { setPhyParams(); if (pMACAddress) setMACAddress(*pMACAddress); @@ -430,6 +439,7 @@ inline bool NetworkInterfaceImpl::up() const #if defined(POCO_OS_FAMILY_WINDOWS) + void NetworkInterfaceImpl::setFlags(DWORD flags, DWORD iftype) { _running = _up = false; @@ -453,13 +463,16 @@ void NetworkInterfaceImpl::setFlags(DWORD flags, DWORD iftype) _multicast = true; } + void NetworkInterfaceImpl::setRunning(bool running) { _running = running; } + #else + void NetworkInterfaceImpl::setFlags(short flags) { #ifdef POCO_OS_FAMILY_UNIX @@ -472,6 +485,7 @@ void NetworkInterfaceImpl::setFlags(short flags) #endif } + #endif @@ -525,8 +539,6 @@ inline void NetworkInterfaceImpl::addAddress(const IPAddress& addr) inline void NetworkInterfaceImpl::setMACAddress(const NetworkInterface::MACAddress& addr) { - - _macAddress = addr; } @@ -534,8 +546,7 @@ inline void NetworkInterfaceImpl::setMACAddress(const NetworkInterface::MACAddre inline void NetworkInterfaceImpl::setMACAddress(const void *addr, std::size_t len) { _macAddress.clear(); - for (unsigned i = 0; i < len; ++i) - _macAddress.push_back(((unsigned char *)addr)[i]); + _macAddress.insert(_macAddress.end(), static_cast(addr), static_cast(addr) + len); } @@ -719,11 +730,13 @@ unsigned NetworkInterface::mtu() const return _pImpl->mtu(); } + NetworkInterface::Type NetworkInterface::type() const { return _pImpl->type(); } + bool NetworkInterface::supportsIP() const { return _pImpl->supportsIPv4() || _pImpl->supportsIPv6(); @@ -760,7 +773,6 @@ bool NetworkInterface::isLoopback() const } - bool NetworkInterface::isPointToPoint() const { return _pImpl->pointToPoint(); @@ -874,13 +886,24 @@ NetworkInterface::List NetworkInterface::list(bool ipOnly, bool upOnly) IPAddress mask = ipIt->get(); NetworkInterface ni; if (mask.isWildcard()) + { ni = NetworkInterface(name, displayName, adapterName, addr, index, &mac); + } else { IPAddress broadcast = ipIt->get(); ni = NetworkInterface(name, displayName, adapterName, addr, mask, broadcast, index, &mac); } + ni._pImpl->_broadcast = it->second._pImpl->_broadcast; + ni._pImpl->_loopback = it->second._pImpl->_loopback; + ni._pImpl->_multicast = it->second._pImpl->_multicast; + ni._pImpl->_pointToPoint = it->second._pImpl->_pointToPoint; + ni._pImpl->_up = it->second._pImpl->_up; + ni._pImpl->_running = it->second._pImpl->_running; + ni._pImpl->_mtu = it->second._pImpl->_mtu; + ni._pImpl->_type = it->second._pImpl->_type; + list.push_back(ni); } } @@ -975,6 +998,7 @@ IPAddress subnetMaskForInterface(const std::string& name, bool isLoopback) } else { +#if !defined(_WIN32_WCE) std::string subKey("SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces\\"); subKey += name; std::string netmask; @@ -1012,6 +1036,9 @@ IPAddress subnetMaskForInterface(const std::string& name, bool isLoopback) #endif RegCloseKey(hKey); return IPAddress::parse(netmask); +#else + return IPAddress(); +#endif // !defined(_WIN32_WCE) } } @@ -1054,7 +1081,8 @@ NetworkInterface::Map NetworkInterface::map(bool ipOnly, bool upOnly) throw SystemException(format("An error occurred while trying to obtain list of network interfaces: [%s]", Error::getMessage(dwRetVal))); else break; - } while ((ERROR_BUFFER_OVERFLOW == dwRetVal) && (++iterations <= 2)); + } + while ((ERROR_BUFFER_OVERFLOW == dwRetVal) && (++iterations <= 2)); poco_assert (NO_ERROR == dwRetVal); for (; pAddress; pAddress = pAddress->Next) @@ -1158,36 +1186,41 @@ NetworkInterface::Map NetworkInterface::map(bool ipOnly, bool upOnly) // we reflect the actual values held by system and protect against misconfiguration (e.g. bad DHCP config entry) #if defined(_WIN32_WCE) ULONG prefixLength = 0; + #if _WIN32_WCE >= 0x0800 + prefixLength = pUniAddr->OnLinkPrefixLength; + broadcastAddress = getBroadcastAddress(pAddress->FirstPrefix, address); + #else broadcastAddress = getBroadcastAddress(pAddress->FirstPrefix, address, &prefixLength); + #endif // if previous call did not do it, make last-ditch attempt for prefix and broadcast if (prefixLength == 0 && pAddress->FirstPrefix) prefixLength = pAddress->FirstPrefix->PrefixLength; poco_assert (prefixLength <= 32); if (broadcastAddress.isWildcard()) { - IPAddress mask ((unsigned) prefixLength, IPAddress::IPv4); + IPAddress mask(static_cast(prefixLength), IPAddress::IPv4); IPAddress host(mask & address); broadcastAddress = host | ~mask; } #elif (_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 // _WIN32_WINNT < 0x0600 ULONG prefixLength = 0; + #if (_WIN32_WINNT >= 0x0600) // Vista and newer + prefixLength = pUniAddr->OnLinkPrefixLength; + broadcastAddress = getBroadcastAddress(pAddress->FirstPrefix, address); + #else broadcastAddress = getBroadcastAddress(pAddress->FirstPrefix, address, &prefixLength); + #endif poco_assert (prefixLength <= 32); if (broadcastAddress.isWildcard()) { - IPAddress mask ((unsigned) prefixLength, IPAddress::IPv4); + IPAddress mask(static_cast(prefixLength), IPAddress::IPv4); IPAddress host(mask & address); broadcastAddress = host | ~mask; } - #endif // _WIN32_WINNT >= 0x0600 #endif // (_WIN32_WINNT >= 0x0501) && (NTDDI_VERSION >= 0x05010100) if (prefixLength) { - subnetMask = IPAddress(prefixLength, IPAddress::IPv4); + subnetMask = IPAddress(static_cast(prefixLength), IPAddress::IPv4); } else // if all of the above fails, look up the subnet mask in the registry { @@ -1202,8 +1235,11 @@ NetworkInterface::Map NetworkInterface::map(bool ipOnly, bool upOnly) ifIt->second.addAddress(address, subnetMask, broadcastAddress); } else + { ifIt->second.addAddress(address); - } break; + } + } + break; #if defined(POCO_HAVE_IPv6) case AF_INET6: ifIt->second.addAddress(address); diff --git a/Net/src/TCPServer.cpp b/Net/src/TCPServer.cpp index 431bdb9bb..28c615893 100644 --- a/Net/src/TCPServer.cpp +++ b/Net/src/TCPServer.cpp @@ -177,9 +177,18 @@ int TCPServer::refusedConnections() const std::string TCPServer::threadName(const ServerSocket& socket) { +#if _WIN32_WCE == 0x0800 + // Workaround for WEC2013: only the first call to getsockname() + // succeeds. To mitigate the impact of this bug, do not call + // socket.address(), which calls getsockname(), here. + std::string name("TCPServer"); + #pragma message("Using WEC2013 getsockname() workaround in TCPServer::threadName(). Remove when no longer needed.") +#else std::string name("TCPServer: "); name.append(socket.address().toString()); +#endif return name; + } diff --git a/Net/testsuite/src/FTPClientSessionTest.cpp b/Net/testsuite/src/FTPClientSessionTest.cpp index a73c597e0..c3ef9f46d 100644 --- a/Net/testsuite/src/FTPClientSessionTest.cpp +++ b/Net/testsuite/src/FTPClientSessionTest.cpp @@ -124,7 +124,8 @@ void FTPClientSessionTest::testLogin2() server.addResponse("331 Password required"); server.addResponse("230 Welcome"); server.addResponse("200 Type set to I"); - FTPClientSession session("localhost", server.port(), "user", "password"); + Poco::UInt16 serverPort = server.port(); + FTPClientSession session("localhost", serverPort, "user", "password"); assert (session.isOpen()); assert (session.isLoggedIn()); server.addResponse("221 Good Bye"); @@ -138,7 +139,7 @@ void FTPClientSessionTest::testLogin2() server.addResponse("331 Password required"); server.addResponse("230 Welcome"); server.addResponse("200 Type set to I"); - session.open("localhost", server.port(), "user", "password"); + session.open("localhost", serverPort, "user", "password"); assert (session.isOpen()); assert (session.isLoggedIn()); server.addResponse("221 Good Bye"); @@ -451,9 +452,10 @@ void FTPClientSessionTest::testDownloadPASV() server.addResponse("500 EPSV not understood"); DialogServer dataServer(false); + Poco::UInt16 dataServerPort = dataServer.port(); dataServer.addResponse("This is some data"); std::ostringstream pasv; - pasv << "227 Entering Passive Mode (127,0,0,1," << (dataServer.port()/256) << "," << (dataServer.port() % 256) << ")"; + pasv << "227 Entering Passive Mode (127,0,0,1," << (dataServerPort/256) << "," << (dataServerPort % 256) << ")"; server.addResponse(pasv.str()); server.addResponse("150 sending data\r\n226 Transfer complete"); diff --git a/Net/testsuite/src/IPAddressTest.cpp b/Net/testsuite/src/IPAddressTest.cpp index 984ffdfb0..8f122dc6e 100644 --- a/Net/testsuite/src/IPAddressTest.cpp +++ b/Net/testsuite/src/IPAddressTest.cpp @@ -58,6 +58,10 @@ void IPAddressTest::testStringConv() void IPAddressTest::testStringConv6() { #ifdef POCO_HAVE_IPv6 + IPAddress ia0("::1"); + assert (ia0.family() == IPAddress::IPv6); + assert (ia0.toString() == "::1"); + IPAddress ia1("1080:0:0:0:8:600:200a:425c"); assert (ia1.family() == IPAddress::IPv6); assert (ia1.toString() == "1080::8:600:200a:425c"); diff --git a/Net/testsuite/src/NetworkInterfaceTest.cpp b/Net/testsuite/src/NetworkInterfaceTest.cpp index 863ae0c55..840d8d0d2 100644 --- a/Net/testsuite/src/NetworkInterfaceTest.cpp +++ b/Net/testsuite/src/NetworkInterfaceTest.cpp @@ -50,7 +50,7 @@ void NetworkInterfaceTest::testMap() std::cout << "Index: " << it->second.index() << std::endl; std::cout << "Name: " << it->second.name() << std::endl; std::cout << "DisplayName: " << it->second.displayName() << std::endl; - std::cout << "Status: " << (it->second.isUp() ? "Up" : "Down") << std::endl; + std::cout << "Status: " << (it->second.isUp() ? "Up" : "Down") << std::endl; NetworkInterface::MACAddress mac(it->second.macAddress()); if (!mac.empty() && (it->second.type() != NetworkInterface::NI_TYPE_SOFTWARE_LOOPBACK)) @@ -88,7 +88,7 @@ void NetworkInterfaceTest::testList() std::cout << "Index: " << it->index() << std::endl; std::cout << "Name: " << it->name() << std::endl; std::cout << "DisplayName: " << it->displayName() << std::endl; - std::cout << "Status: " << (it->isUp() ? "Up" : "Down") << std::endl; + std::cout << "Status: " << (it->isUp() ? "Up" : "Down") << std::endl; NetworkInterface::MACAddress mac(it->macAddress()); if (!mac.empty() && (it->type() != NetworkInterface::NI_TYPE_SOFTWARE_LOOPBACK)) diff --git a/Net/testsuite/src/TCPServerTest.cpp b/Net/testsuite/src/TCPServerTest.cpp index ebd66fbe0..8f2f5acfc 100644 --- a/Net/testsuite/src/TCPServerTest.cpp +++ b/Net/testsuite/src/TCPServerTest.cpp @@ -97,7 +97,7 @@ void TCPServerTest::testOneConnection() assert (srv.queuedConnections() == 0); assert (srv.totalConnections() == 1); ss1.close(); - Thread::sleep(300); + Thread::sleep(1000); assert (srv.currentConnections() == 0); } @@ -132,14 +132,14 @@ void TCPServerTest::testTwoConnections() assert (srv.queuedConnections() == 0); assert (srv.totalConnections() == 2); ss1.close(); - Thread::sleep(300); + Thread::sleep(1000); assert (srv.currentConnections() == 1); assert (srv.currentThreads() == 1); assert (srv.queuedConnections() == 0); assert (srv.totalConnections() == 2); ss2.close(); - Thread::sleep(300); + Thread::sleep(1000); assert (srv.currentConnections() == 0); } @@ -200,28 +200,28 @@ void TCPServerTest::testMultiConnections() assert (srv.queuedConnections() == 2); ss1.close(); - Thread::sleep(300); + Thread::sleep(2000); assert (srv.currentConnections() == 4); assert (srv.currentThreads() == 4); assert (srv.queuedConnections() == 1); assert (srv.totalConnections() == 5); ss2.close(); - Thread::sleep(300); + Thread::sleep(1000); assert (srv.currentConnections() == 4); assert (srv.currentThreads() == 4); assert (srv.queuedConnections() == 0); assert (srv.totalConnections() == 6); ss3.close(); - Thread::sleep(300); + Thread::sleep(1000); assert (srv.currentConnections() == 3); assert (srv.currentThreads() == 3); assert (srv.queuedConnections() == 0); assert (srv.totalConnections() == 6); ss4.close(); - Thread::sleep(300); + Thread::sleep(1000); assert (srv.currentConnections() == 2); assert (srv.currentThreads() == 2); assert (srv.queuedConnections() == 0); @@ -229,7 +229,7 @@ void TCPServerTest::testMultiConnections() ss5.close(); ss6.close(); - Thread::sleep(300); + Thread::sleep(1000); assert (srv.currentConnections() == 0); }