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
This commit is contained in:
Günter Obiltschnig
2014-09-15 19:17:09 +02:00
parent 67b206f663
commit 63f4bfa54b
8 changed files with 120 additions and 35 deletions

View File

@@ -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()");
}

View File

@@ -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<const UInt16*>(&_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<const UInt16*>(&_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<const UInt16*>(&_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<const UInt16*>(&_addr);
return (ntohs(words[0]) & 0xFFE0) == 0xFF00;
}
bool IPv6AddressImpl::isLinkLocal() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ntohs(words[0]) & 0xFFE0) == 0xFE80;
}
bool IPv6AddressImpl::isSiteLocal() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return ((ntohs(words[0]) & 0xFFE0) == 0xFEC0) || ((ntohs(words[0]) & 0xFF00) == 0xFC00);
}
bool IPv6AddressImpl::isIPv4Compatible() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_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<const UInt16*>(&_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<const UInt16*>(&_addr);
return (ntohs(words[0]) & 0xFFF0) == 0xFF00;
}
bool IPv6AddressImpl::isNodeLocalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ntohs(words[0]) & 0xFFEF) == 0xFF01;
}
bool IPv6AddressImpl::isLinkLocalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ntohs(words[0]) & 0xFFEF) == 0xFF02;
}
bool IPv6AddressImpl::isSiteLocalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ntohs(words[0]) & 0xFFEF) == 0xFF05;
}
bool IPv6AddressImpl::isOrgLocalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ntohs(words[0]) & 0xFFEF) == 0xFF08;
}
bool IPv6AddressImpl::isGlobalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_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);

View File

@@ -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<const unsigned char*>(addr), static_cast<const unsigned char*>(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::SUBNET_MASK>();
NetworkInterface ni;
if (mask.isWildcard())
{
ni = NetworkInterface(name, displayName, adapterName, addr, index, &mac);
}
else
{
IPAddress broadcast = ipIt->get<NetworkInterface::BROADCAST_ADDRESS>();
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<unsigned>(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<unsigned>(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<unsigned>(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);

View File

@@ -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;
}

View File

@@ -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");

View File

@@ -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");

View File

@@ -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);
}