diff --git a/Net/include/Poco/Net/IPAddress.h b/Net/include/Poco/Net/IPAddress.h index fe58a76db..d602bf98c 100644 --- a/Net/include/Poco/Net/IPAddress.h +++ b/Net/include/Poco/Net/IPAddress.h @@ -42,6 +42,7 @@ #include "Poco/Net/Net.h" #include "Poco/Net/SocketDefs.h" +#include namespace Poco { @@ -74,6 +75,8 @@ class Net_API IPAddress /// supports IPv6. { public: + typedef std::vector List; + enum Family /// Possible address families for IP addresses. { @@ -193,7 +196,7 @@ public: /// Only IPv4 addresses can be broadcast addresses. In a broadcast /// address, all bits are one. /// - /// For a IPv6 address, returns always false. + /// For an IPv6 address, returns always false. bool isLoopback() const; /// Returns true iff the address is a loopback address. diff --git a/Net/include/Poco/Net/NetworkInterface.h b/Net/include/Poco/Net/NetworkInterface.h index d5fc13046..7d1174d48 100644 --- a/Net/include/Poco/Net/NetworkInterface.h +++ b/Net/include/Poco/Net/NetworkInterface.h @@ -43,7 +43,8 @@ #include "Poco/Net/Net.h" #include "Poco/Net/IPAddress.h" #include "Poco/Mutex.h" -#include +#include "Poco/Tuple.h" +#include namespace Poco { @@ -61,11 +62,25 @@ class Net_API NetworkInterface /// messages. /// /// The class also provides static member functions for - /// enumerating or searching network interfaces. + /// enumerating or searching network interfaces and their + /// respective configuration values. { public: - typedef std::vector NetworkInterfaceList; - + typedef std::vector List; + typedef List NetworkInterfaceList;//@deprecated + typedef std::map Map; + typedef Poco::Tuple AddressTuple; + typedef std::vector AddressList; + typedef AddressList::iterator AddressIterator; + typedef AddressList::const_iterator ConstAddressIterator; + + enum AddressType + { + IP_ADDRESS, + SUBNET_MASK, + BROADCAST_ADDRESS + }; + enum IPVersion { IPv4_ONLY, /// Return interfaces with IPv4 address only @@ -73,7 +88,7 @@ public: IPv4_OR_IPv6 /// Return interfaces with IPv4 or IPv6 address }; - NetworkInterface(); + NetworkInterface(std::size_t index = 0); /// Creates a NetworkInterface representing the /// default interface. /// @@ -88,15 +103,18 @@ public: NetworkInterface& operator = (const NetworkInterface& interfc); /// Assigns another NetworkInterface. - + + bool operator < (const NetworkInterface& other) const; + /// Operatorr less-than. + + bool operator == (const NetworkInterface& other) const; + /// Operator equal. Compares interface indices. + void swap(NetworkInterface& other); /// Swaps the NetworkInterface with another one. - int index() const; + std::size_t index() const; /// Returns the interface index. - /// - /// Only supported if IPv6 is available. - /// Returns -1 if IPv6 is not available. const std::string& name() const; /// Returns the interface name. @@ -110,16 +128,25 @@ public: /// /// On other platforms this is the same as name(). - const IPAddress& address() const; + const IPAddress& address(std::size_t index = 0) const; /// Returns the IP address bound to the interface. - - const IPAddress& subnetMask() const; - /// Returns the IPv4 subnet mask for this network interface. - - const IPAddress& broadcastAddress() const; - /// Returns the IPv4 broadcast address for this network interface. - const IPAddress& destAddress() const; + void addAddress(const IPAddress& address); + /// Adds address to the interface. + + void addAddress(const IPAddress& address, const IPAddress& subnetMask, const IPAddress& broadcastAddress); + /// Adds address to the interface. + + const AddressList& addressList() const; + /// Returns the list of IP addresses bound to the interface. + + const IPAddress& subnetMask(std::size_t index = 0) const; + /// Returns the subnet mask for this network interface. + + const IPAddress& broadcastAddress(std::size_t index = 0) const; + /// Returns the broadcast address for this network interface. + + const IPAddress& destAddress(std::size_t index = 0) const; /// Returns the IPv4 point-to-point destiation address for this network interface. int mtu() const; @@ -184,21 +211,30 @@ public: /// with the given index does not exist (or IPv6 is not /// available). - static NetworkInterfaceList list(); + static List list(); /// Returns a list with all network interfaces /// on the system. /// /// If there are multiple addresses bound to one interface, - /// multiple NetworkInterface instances are created for + /// multiple NetworkInterface entries are listed for /// the same interface. + static Map map(); + /// Returns a map with all network interfaces + /// on the system. Map is keyed by interface system + /// indices. + /// + /// If there are multiple addresses bound to one interface, + /// they are contained within the NetworkInterface (second) + /// member of the pair. + protected: NetworkInterface(const std::string& name, const std::string& displayName, const IPAddress& address, int index = -1); /// Creates the NetworkInterface. NetworkInterface(const std::string& name, const std::string& displayName, const IPAddress& address, const IPAddress& subnetMask, const IPAddress& broadcastAddress, int index = -1); /// Creates the NetworkInterface. - + NetworkInterface(const std::string& name, const IPAddress& address, int index = -1); /// Creates the NetworkInterface. @@ -211,6 +247,8 @@ protected: int interfaceNameToIndex(const std::string& interfaceName) const; /// Determines the interface index of the interface with the given name. + NetworkInterfaceImpl& impl() { return *_pImpl; }; + private: NetworkInterfaceImpl* _pImpl; @@ -218,6 +256,23 @@ private: }; +/// +/// inlines +/// + + +inline bool NetworkInterface::operator < (const NetworkInterface& other) const +{ + return this->index() < other.index(); +} + + +inline bool NetworkInterface::operator == (const NetworkInterface& other) const +{ + return this->index() == other.index(); +} + + } } // namespace Poco::Net diff --git a/Net/src/NetworkInterface.cpp b/Net/src/NetworkInterface.cpp index ca7021f65..5664a931c 100644 --- a/Net/src/NetworkInterface.cpp +++ b/Net/src/NetworkInterface.cpp @@ -39,7 +39,8 @@ #include "Poco/Net/NetException.h" #include "Poco/NumberFormatter.h" #include "Poco/RefCountedObject.h" -#if defined(_WIN32) +#include "Poco/Format.h" +#if defined(POCO_OS_FAMILY_WINDOWS) #if defined(POCO_WIN32_UTF8) #include "Poco/UnicodeConverter.h" #endif @@ -51,6 +52,7 @@ using Poco::NumberFormatter; using Poco::FastMutex; +using Poco::format; namespace Poco { @@ -65,17 +67,29 @@ namespace Net { class NetworkInterfaceImpl: public Poco::RefCountedObject { public: - NetworkInterfaceImpl(); + typedef NetworkInterface::AddressTuple AddressTuple; + typedef NetworkInterface::AddressList AddressList; + + NetworkInterfaceImpl(int index = -1); NetworkInterfaceImpl(const std::string& name, const std::string& displayName, const IPAddress& address, int index = -1); NetworkInterfaceImpl(const std::string& name, const std::string& displayName, const IPAddress& address, const IPAddress& subnetMask, const IPAddress& broadcastAddress, int index = -1); - int index() const; + int index() const; const std::string& name() const; const std::string& displayName() const; - const IPAddress& address() const; - const IPAddress& subnetMask() const; - const IPAddress& broadcastAddress() const; - const IPAddress& destAddress() const; + void addAddress(const AddressTuple& address); + const IPAddress& address(std::size_t index = 0) const; + const NetworkInterface::AddressList& addressList() const; + bool hasAddress(const IPAddress& address) const; + const IPAddress& subnetMask(std::size_t index = 0) const; + const IPAddress& broadcastAddress(std::size_t index = 0) const; + const IPAddress& destAddress(std::size_t index = 0) const; + bool supportsIPv4() const; + bool supportsIPv6() const; + + void setName(const std::string& name); + void setDisplayName(const std::string& name); + void addAddress(const IPAddress& addr); int mtu() const; int ifindex() const; @@ -89,65 +103,50 @@ public: protected: ~NetworkInterfaceImpl(); -#if defined(_WIN32) +#if defined(POCO_OS_FAMILY_WINDOWS) void setFlags(DWORD flags, DWORD iftype); #else void setFlags(short flags); #endif - void setMtu(int mtu) - { - _mtu = mtu; - } - - void setIfIndex(unsigned ifIndex) - { - _ifindex = ifIndex; - } - + void setUp(bool up); + void setMtu(int mtu); + void setIndex(std::size_t index); void getPhyParams(); - void getIPv4Params(); - void getPeerAddress(); private: - std::string _name; - std::string _displayName; - IPAddress _address; - IPAddress _subnetMask; - IPAddress _broadcastAddress; - IPAddress _destAddress; - int _index; + std::string _name; + std::string _displayName; + AddressList _addressList; + std::size_t _index; + bool _broadcast; + bool _loopback; + bool _multicast; + bool _pointToPoint; + bool _up; + bool _running; + int _mtu; - bool _broadcast; - bool _loopback; - bool _multicast; - bool _pointToPoint; - bool _up; - bool _running; - int _mtu; - int _ifindex; - -#if defined(_WIN32) - friend NetworkInterface::NetworkInterfaceList NetworkInterface::list(); +#if defined(POCO_OS_FAMILY_WINDOWS) + friend NetworkInterface::Map NetworkInterface::map(); #endif }; -NetworkInterfaceImpl::NetworkInterfaceImpl(): - _index(-1), - _mtu(-1), - _ifindex(-1) +NetworkInterfaceImpl::NetworkInterfaceImpl(int index): + _index(index), + _mtu(-1) { + _addressList.resize(1); } NetworkInterfaceImpl::NetworkInterfaceImpl(const std::string& name, const std::string& displayName, const IPAddress& address, int index): _name(name), _displayName(displayName), - _address(address), _index(index), _broadcast(false), _loopback(false), @@ -155,24 +154,19 @@ NetworkInterfaceImpl::NetworkInterfaceImpl(const std::string& name, const std::s _pointToPoint(false), _up(false), _running(false), - _mtu(-1), - _ifindex(-1) + _mtu(-1) { + _addressList.push_back(AddressTuple(address, IPAddress(), IPAddress())); getPhyParams(); // get remaining IPv4 params from kernel - if (address.family() == IPAddress::IPv4) - getIPv4Params(); - if (_pointToPoint) - getPeerAddress(); + if (address.family() == IPAddress::IPv4) getIPv4Params(); + if (_pointToPoint) getPeerAddress(); } NetworkInterfaceImpl::NetworkInterfaceImpl(const std::string& name, const std::string& displayName, const IPAddress& address, const IPAddress& subnetMask, const IPAddress& broadcastAddress, int index): _name(name), _displayName(displayName), - _address(address), - _subnetMask(subnetMask), - _broadcastAddress(broadcastAddress), _index(index), _broadcast(false), _loopback(false), @@ -180,19 +174,18 @@ NetworkInterfaceImpl::NetworkInterfaceImpl(const std::string& name, const std::s _pointToPoint(false), _up(false), _running(false), - _mtu(-1), - _ifindex(-1) + _mtu(-1) { + _addressList.push_back(AddressTuple(address, subnetMask, broadcastAddress)); getPhyParams(); - if (_pointToPoint) - getPeerAddress(); + if (_pointToPoint) getPeerAddress(); } void NetworkInterfaceImpl::getPhyParams() { -#if !defined(_WIN32) && !defined(POCO_VXWORKS) - const IPAddress::Family family = _address.family(); +#if !defined(POCO_OS_FAMILY_WINDOWS) && !defined(POCO_VXWORKS) + const IPAddress::Family family = _addressList.family(); struct ifreq ifr; std::strncpy(ifr.ifr_name, _name.c_str(), IFNAMSIZ); DatagramSocket ds(family); @@ -203,18 +196,19 @@ void NetworkInterfaceImpl::getPhyParams() ds.impl()->ioctl(SIOCGIFMTU, &ifr); setMtu(ifr.ifr_mtu); -#if POCO_OS == POCO_OS_MAC_OS_X - setIfIndex(if_nametoindex(ifr.ifr_name)); -#else - ds.impl()->ioctl(SIOCGIFINDEX, &ifr); - setIfIndex(ifr.ifr_ifindex); -#endif + #if POCO_OS == POCO_OS_MAC_OS_X + setIfIndex(if_nametoindex(ifr.ifr_name)); + #else + ds.impl()->ioctl(SIOCGIFINDEX, &ifr); + setIfIndex(ifr.ifr_ifindex); + #endif #endif } + void NetworkInterfaceImpl::getIPv4Params() { -#if !defined(_WIN32) && !defined(POCO_VXWORKS) +#if !defined(POCO_OS_FAMILY_WINDOWS) && !defined(POCO_VXWORKS) struct ifreq ifr; std::strncpy(ifr.ifr_name, _name.c_str(), IFNAMSIZ); DatagramSocket ds(IPAddress::IPv4); @@ -241,20 +235,28 @@ void NetworkInterfaceImpl::getIPv4Params() #endif } + void NetworkInterfaceImpl::getPeerAddress() { -#if !defined(_WIN32) && !defined(POCO_VXWORKS) - const IPAddress::Family family = _address.family(); - struct ifreq ifr; - std::strncpy(ifr.ifr_name, _name.c_str(), IFNAMSIZ); - DatagramSocket ds(family); - - ds.impl()->ioctl(SIOCGIFDSTADDR, &ifr); - if (ifr.ifr_dstaddr.sa_family == AF_INET) - _destAddress = IPAddress(ifr.ifr_dstaddr); - else - _destAddress = IPAddress(&reinterpret_cast(&ifr.ifr_dstaddr)->sin6_addr, sizeof(struct in6_addr), _index); + AddressList::iterator it = _addressList.begin(); + AddressList::iterator end = _addressList.end(); + for (; it != end; ++it) + { + IPAddress::Family family = it->get().family(); + DatagramSocket ds(family); +#if !defined(POCO_OS_FAMILY_WINDOWS) && !defined(POCO_VXWORKS) + struct ifreq ifr; + std::strncpy(ifr.ifr_name, _name.c_str(), IFNAMSIZ); + ds.impl()->ioctl(SIOCGIFDSTADDR, &ifr); + // for PPP-type connections, broadcastAddress member holds the peer address + if (ifr.ifr_dstaddr.sa_family == AF_INET) + it->set(IPAddress(ifr.ifr_dstaddr)); + else + it->set(IPAddress(&reinterpret_cast(&ifr.ifr_dstaddr)->sin6_addr, sizeof(struct in6_addr), _index)); +#else + //TODO #endif + } } @@ -263,6 +265,34 @@ NetworkInterfaceImpl::~NetworkInterfaceImpl() } +bool NetworkInterfaceImpl::supportsIPv4() const +{ + AddressList::const_iterator it = _addressList.begin(); + AddressList::const_iterator end = _addressList.end(); + for (; it != end; ++it) + { + if (IPAddress::IPv4 == it->get().family()) + return true; + } + + return false; +} + + +bool NetworkInterfaceImpl::supportsIPv6() const +{ + AddressList::const_iterator it = _addressList.begin(); + AddressList::const_iterator end = _addressList.end(); + for (; it != end; ++it) + { + if (IPAddress::IPv6 == it->get().family()) + return true; + } + + return false; +} + + inline int NetworkInterfaceImpl::index() const { return _index; @@ -281,73 +311,113 @@ inline const std::string& NetworkInterfaceImpl::displayName() const } -inline const IPAddress& NetworkInterfaceImpl::address() const +void NetworkInterfaceImpl::addAddress(const AddressTuple& address) { - return _address; + _addressList.push_back(address); } -inline const IPAddress& NetworkInterfaceImpl::subnetMask() const +bool NetworkInterfaceImpl::hasAddress(const IPAddress& address) const { - return _subnetMask; + NetworkInterface::ConstAddressIterator it = _addressList.begin(); + NetworkInterface::ConstAddressIterator end = _addressList.end(); + for (; it != end; ++it) + { + if (it->get() == address) + return true; + } + return false; } -inline const IPAddress& NetworkInterfaceImpl::broadcastAddress() const +inline const IPAddress& NetworkInterfaceImpl::address(std::size_t index) const { - return _broadcastAddress; + if (index < _addressList.size()) return _addressList[index].get(); + else throw NotFoundException(Poco::format("No address with index %z.", index)); } -inline const IPAddress& NetworkInterfaceImpl::destAddress() const +inline const NetworkInterface::AddressList& NetworkInterfaceImpl::addressList() const { - return _destAddress; + return _addressList; } + +inline const IPAddress& NetworkInterfaceImpl::subnetMask(std::size_t index) const +{ + if (index < _addressList.size()) + return _addressList[index].get(); + + throw NotFoundException(Poco::format("No subnet mask with index %z.", index)); +} + + +inline const IPAddress& NetworkInterfaceImpl::broadcastAddress(std::size_t index) const +{ + if (index < _addressList.size()) + return _addressList[index].get(); + + throw NotFoundException(Poco::format("No subnet mask with index %z.", index)); +} + + +inline const IPAddress& NetworkInterfaceImpl::destAddress(std::size_t index) const +{ + if (!pointToPoint()) + throw InvalidAccessException("Only PPP addresses have destination address."); + else if (index < _addressList.size()) + return _addressList[index].get(); + + throw NotFoundException(Poco::format("No address with index %z.", index)); +} + + inline int NetworkInterfaceImpl::mtu() const { return _mtu; } -inline int NetworkInterfaceImpl::ifindex() const -{ - return _ifindex; -} inline bool NetworkInterfaceImpl::broadcast() const { return _broadcast; } + inline bool NetworkInterfaceImpl::loopback() const { return _loopback; } + inline bool NetworkInterfaceImpl::multicast() const { return _multicast; } + inline bool NetworkInterfaceImpl::pointToPoint() const { return _pointToPoint; } + inline bool NetworkInterfaceImpl::running() const { return _running; } + inline bool NetworkInterfaceImpl::up() const { return _up; } -#if defined(_WIN32) + +#if defined(POCO_OS_FAMILY_WINDOWS) + void NetworkInterfaceImpl::setFlags(DWORD flags, DWORD iftype) { - // sigh... _running = _up = true; switch (iftype) { case IF_TYPE_ETHERNET_CSMACD: @@ -368,7 +438,9 @@ void NetworkInterfaceImpl::setFlags(DWORD flags, DWORD iftype) if (!(flags & IP_ADAPTER_NO_MULTICAST)) _multicast = true; } + #else + void NetworkInterfaceImpl::setFlags(short flags) { #ifdef POCO_OS_FAMILY_UNIX @@ -380,9 +452,46 @@ void NetworkInterfaceImpl::setFlags(short flags) _up = ((flags & IFF_UP) != 0); #endif } + #endif +inline void NetworkInterfaceImpl::setUp(bool up) +{ + _up = up; +} + + +inline void NetworkInterfaceImpl::setMtu(int mtu) +{ + _mtu = mtu; +} + + +inline void NetworkInterfaceImpl::setIndex(unsigned index) +{ + _index = index; +} + + +inline void NetworkInterfaceImpl::setName(const std::string& name) +{ + _name = name; +} + + +inline void NetworkInterfaceImpl::setDisplayName(const std::string& name) +{ + _displayName = name; +} + + +inline void NetworkInterfaceImpl::addAddress(const IPAddress& addr) +{ + _addressList.push_back(addr); +} + + // // NetworkInterface // @@ -391,8 +500,8 @@ void NetworkInterfaceImpl::setFlags(short flags) FastMutex NetworkInterface::_mutex; -NetworkInterface::NetworkInterface(): - _pImpl(new NetworkInterfaceImpl) +NetworkInterface::NetworkInterface(std::size_t index): + _pImpl(new NetworkInterfaceImpl(index)) { } @@ -449,7 +558,7 @@ void NetworkInterface::swap(NetworkInterface& other) } -int NetworkInterface::index() const +std::size_t NetworkInterface::index() const { return _pImpl->index(); } @@ -467,49 +576,63 @@ const std::string& NetworkInterface::displayName() const } -const IPAddress& NetworkInterface::address() const +void NetworkInterface::addAddress(const IPAddress& address) { - return _pImpl->address(); + _pImpl->addAddress(AddressTuple(address, IPAddress(), IPAddress())); } -const IPAddress& NetworkInterface::subnetMask() const +void NetworkInterface::addAddress(const IPAddress& address, const IPAddress& subnetMask, const IPAddress& broadcastAddress) { - return _pImpl->subnetMask(); + _pImpl->addAddress(AddressTuple(address, subnetMask, broadcastAddress)); } -const IPAddress& NetworkInterface::broadcastAddress() const +const IPAddress& NetworkInterface::address(std::size_t index) const { - return _pImpl->broadcastAddress(); + return _pImpl->address(index); } -const IPAddress& NetworkInterface::destAddress() const +const NetworkInterface::AddressList& NetworkInterface::addressList() const { - return _pImpl->destAddress(); + return _pImpl->addressList(); } + +const IPAddress& NetworkInterface::subnetMask(std::size_t index) const +{ + return _pImpl->subnetMask(index); +} + + +const IPAddress& NetworkInterface::broadcastAddress(std::size_t index) const +{ + return _pImpl->broadcastAddress(index); +} + + +const IPAddress& NetworkInterface::destAddress(std::size_t index) const +{ + return _pImpl->destAddress(index); +} + + int NetworkInterface::mtu() const { return _pImpl->mtu(); } -int NetworkInterface::ifindex() const -{ - return _pImpl->ifindex(); -} - bool NetworkInterface::supportsIPv4() const { - return _pImpl->index() == -1; + return _pImpl->supportsIPv4(); } bool NetworkInterface::supportsIPv6() const { - return _pImpl->index() != -1; + return _pImpl->supportsIPv6(); } @@ -603,6 +726,42 @@ NetworkInterface NetworkInterface::forIndex(int i) } +NetworkInterface::List NetworkInterface::list() +{ + List list; + Map m = map(); + + for (NetworkInterface::Map::const_iterator it = m.begin(); it != m.end(); ++it) + { + int index = it->second.index(); + std::string name = it->second.name(); + std::string displayName = it->second.displayName(); + + typedef NetworkInterface::AddressList List; + const List& ipList = it->second.addressList(); + List::const_iterator ipIt = ipList.begin(); + List::const_iterator ipEnd = ipList.end(); + for (int counter = 0; ipIt != ipEnd; ++ipIt, ++counter) + { + IPAddress addr = ipIt->get(); + IPAddress mask = ipIt->get(); + NetworkInterface ni; + if (mask.isWildcard()) + ni = NetworkInterface(name, displayName, addr, index); + else + { + IPAddress broadcast = ipIt->get(); + ni = NetworkInterface(name, displayName, addr, mask, broadcast, index); + } + + list.push_back(ni); + } + } + + return list; +} + + } } // namespace Poco::Net @@ -617,136 +776,130 @@ NetworkInterface NetworkInterface::forIndex(int i) // +#include "Poco/Buffer.h" +#include + + namespace Poco { namespace Net { - -NetworkInterface::NetworkInterfaceList NetworkInterface::list() +NetworkInterface::Map NetworkInterface::map() { FastMutex::ScopedLock lock(_mutex); - NetworkInterfaceList result; - DWORD rc; - -#define GAA_FLAGS (GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX) - const unsigned gaaFlags = GAA_FLAGS; - + Map result; + ULONG outBufLen = 16384; + Poco::Buffer memory(outBufLen); + ULONG flags = (GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX); #if defined(POCO_HAVE_IPv6) - const unsigned gaaFamily = AF_UNSPEC; + const unsigned family = AF_UNSPEC; //IPv4 and IPv6 #else - const unsigned gaaFamily = AF_INET; + const unsigned family = AF_INET; //IPv4 only #endif + DWORD dwRetVal = 0; + ULONG iterations = 0; + PIP_ADAPTER_ADDRESSES pAddresses = reinterpret_cast(memory.begin()); + do + { + if ((dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen)) == ERROR_BUFFER_OVERFLOW) + memory.resize(outBufLen); + else break; + } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (++iterations <= 2)); - // On Windows XP/Server 2003 and later we use GetAdaptersAddresses. - PIP_ADAPTER_ADDRESSES pAdapterAddresses; - PIP_ADAPTER_ADDRESSES pAddress = 0; - ULONG addrLen = sizeof(IP_ADAPTER_ADDRESSES); - pAdapterAddresses = reinterpret_cast(new char[addrLen]); - // Make an initial call to GetAdaptersAddresses to get - // the necessary size into addrLen - rc = GetAdaptersAddresses(gaaFamily, gaaFlags, 0, pAdapterAddresses, &addrLen); - if (rc == ERROR_BUFFER_OVERFLOW) + if (dwRetVal == ERROR_NO_DATA) return result;// no network interfaces found + + if (dwRetVal == NO_ERROR) { - delete [] reinterpret_cast(pAdapterAddresses); - pAdapterAddresses = reinterpret_cast(new char[addrLen]); - } - else if (rc != ERROR_SUCCESS) - { - throw NetException("cannot get network adapter list"); - } - try - { - if (GetAdaptersAddresses(gaaFamily, gaaFlags, 0, pAdapterAddresses, &addrLen) == NO_ERROR) + for (PIP_ADAPTER_ADDRESSES pAddress = pAddresses; pAddress; pAddress = pAddress->Next) { - for (pAddress = pAdapterAddresses; pAddress; pAddress = pAddress->Next) + IPAddress address; + IPAddress subnetMask; + IPAddress broadcastAddress; + IPAddress destAddress; + unsigned ifIndex = ~0; + +#if defined(POCO_HAVE_IPv6) + if (pAddress->Flags & IP_ADAPTER_IPV6_ENABLED) ifIndex = pAddress->Ipv6IfIndex; + else +#endif + if (pAddress->Flags & IP_ADAPTER_IPV4_ENABLED) ifIndex = pAddress->IfIndex; + + PIP_ADAPTER_PREFIX pPrefix = pAddress->FirstPrefix; + for (PIP_ADAPTER_UNICAST_ADDRESS pUniAddr = pAddress->FirstUnicastAddress; + pUniAddr; + pUniAddr = pUniAddr->Next, pPrefix = pPrefix ? pPrefix->Next : 0) { - IPAddress address; - IPAddress subnetMask; - IPAddress broadcastAddress; - unsigned ifIndex = ~0; - -#if defined(POCO_HAVE_IPv6) - if (pAddress->Flags & IP_ADAPTER_IPV6_ENABLED) - ifIndex = pAddress->Ipv6IfIndex; - else -#endif - if (pAddress->Flags & IP_ADAPTER_IPV4_ENABLED) - ifIndex = pAddress->IfIndex; - - IP_ADAPTER_PREFIX *pPrefix; - unsigned i, prefixlen; - for (i = 0, pPrefix = pAddress->FirstPrefix; pPrefix; pPrefix = pPrefix->Next, ++i) - { - switch (i) { - case 0: - prefixlen = pPrefix->PrefixLength; - if (pPrefix->Address.lpSockaddr->sa_family == AF_INET) - subnetMask = IPAddress(pPrefix->PrefixLength, IPAddress::IPv4); -#if defined(POCO_HAVE_IPv6) - else - subnetMask = IPAddress(pPrefix->PrefixLength, IPAddress::IPv6); -#endif - break; - case 1: - address = IPAddress(pPrefix->Address); - break; - case 2: - broadcastAddress = IPAddress(pPrefix->Address); - break; - case 3: - case 4: - // ignore multicast and broadcast prefixes - break; - } - } - - if (pAddress->OperStatus == IfOperStatusUp) - { - PIP_ADAPTER_UNICAST_ADDRESS pUniAddr; - for (pUniAddr = pAddress->FirstUnicastAddress; pUniAddr; pUniAddr = pUniAddr->Next) - { - std::string name(pAddress->AdapterName); - std::string displayName; + std::string name(pAddress->AdapterName); + std::string displayName; #ifdef POCO_WIN32_UTF8 - Poco::UnicodeConverter::toUTF8(pAddress->FriendlyName, displayName); + Poco::UnicodeConverter::toUTF8(pAddress->FriendlyName, displayName); #else - char displayNameBuffer[1024]; - int rc = WideCharToMultiByte(CP_ACP, WC_DEFAULTCHAR, pAddress->FriendlyName, -1, displayNameBuffer, sizeof(displayNameBuffer), NULL, NULL); - if (rc) displayName = displayNameBuffer; + char displayNameBuffer[1024]; + int rc = WideCharToMultiByte(CP_ACP, WC_DEFAULTCHAR, pAddress->FriendlyName, -1, displayNameBuffer, sizeof(displayNameBuffer), NULL, NULL); + if (rc) displayName = displayNameBuffer; #endif - NetworkInterface* intf; - switch (pUniAddr->Address.lpSockaddr->sa_family) + address = IPAddress(pUniAddr->Address); + ADDRESS_FAMILY family = pUniAddr->Address.lpSockaddr->sa_family; + Map::iterator ifIt = result.find(ifIndex); + switch (family) + { + case AF_INET: + { + bool hasBroadcast = (pAddress->IfType == IF_TYPE_ETHERNET_CSMACD); + subnetMask = pPrefix ? IPAddress(pPrefix->Length, IPAddress::IPv4) : IPAddress(); + broadcastAddress = address | ~subnetMask; + if (ifIt == result.end()) { - case AF_INET: - address = IPAddress(pUniAddr->Address); - result.push_back(NetworkInterface(name, displayName, address, subnetMask, broadcastAddress, -1)); - intf = &result.back(); - intf->_pImpl->setMtu(pAddress->Mtu); - intf->_pImpl->setFlags(pAddress->Flags, pAddress->IfType); - intf->_pImpl->setIfIndex(ifIndex); - break; -#if defined(POCO_HAVE_IPv6) - case AF_INET6: - address = IPAddress(pUniAddr->Address); - result.push_back(NetworkInterface(name, displayName, address, pAddress->Ipv6IfIndex)); - intf = &result.back(); - intf->_pImpl->setMtu(pAddress->Mtu); - intf->_pImpl->setFlags(pAddress->Flags, pAddress->IfType); - intf->_pImpl->setIfIndex(ifIndex); - break; -#endif // POCO_HAVE_IPv6 + if (hasBroadcast) + ifIt = result.insert(Map::value_type(ifIndex, NetworkInterface(name, displayName, address, subnetMask, broadcastAddress, ifIndex))).first; + else + ifIt = result.insert(Map::value_type(ifIndex, NetworkInterface(name, displayName, address, ifIndex))).first; } - } - } - } - } - else throw NetException("cannot get network adapter list"); - } - catch (Poco::Exception&) + else + { + if (hasBroadcast) + ifIt->second.addAddress(address, subnetMask, broadcastAddress); + else + ifIt->second.addAddress(address); + } + } break; +#if defined(POCO_HAVE_IPv6) + case AF_INET6: + { + if (ifIt == result.end()) ifIt = result.insert(Map::value_type(ifIndex, NetworkInterface(name, displayName, address, ifIndex))).first; + else + ifIt->second.addAddress(address); + } break; +#endif + } // switch family + ifIt->second.impl().setFlags(pAddress->Flags, pAddress->IfType); + ifIt->second.impl().setMtu(pAddress->Mtu); + ifIt->second.impl().setUp(pAddress->OperStatus == IfOperStatusUp); + } // for addresses + } // for adapters + } // if no error + else // error occurred { - delete [] reinterpret_cast(pAdapterAddresses); - throw; + std::string errMsg; + DWORD dwFlg = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; +#if defined(POCO_WIN32_UTF8) && !defined(POCO_NO_WSTRING) + LPWSTR lpMsgBuf = 0; + if (FormatMessageW(dwFlg, 0, dwRetVal, 0, (LPWSTR) & lpMsgBuf, 0, NULL)) + { + UnicodeConverter::toUTF8(lpMsgBuf, errMsg); + LocalFree(lpMsgBuf); + } +#else + LPTSTR lpMsgBuf = 0; + if (FormatMessageA(dwFlg, 0, dwRetVal, 0, (LPTSTR) & lpMsgBuf, 0, NULL)) + { + errMsg = lpMsgBuf; + LocalFree(lpMsgBuf); + } +#endif + + throw SystemException(format("An error occurred whiel trying to obtain list of network interfaces: [%s]", errMsg)); } - delete [] reinterpret_cast(pAdapterAddresses); + return result; } diff --git a/Net/testsuite/src/IPAddressTest.cpp b/Net/testsuite/src/IPAddressTest.cpp index c456534b7..48524d95a 100644 --- a/Net/testsuite/src/IPAddressTest.cpp +++ b/Net/testsuite/src/IPAddressTest.cpp @@ -441,7 +441,7 @@ void IPAddressTest::testMCClassification6() assert (!ip1.isOrgLocalMC()); assert (!ip1.isGlobalMC()); - IPAddress ip2("FF01:0:0:0:0:0:0:FB"); // node-local unicast + IPAddress ip2("ff01:0:0:0:0:0:0:FB"); // node-local unicast assert (!ip2.isWildcard()); assert (!ip2.isBroadcast()); assert (!ip2.isLoopback()); @@ -456,7 +456,7 @@ void IPAddressTest::testMCClassification6() assert (!ip2.isOrgLocalMC()); assert (!ip2.isGlobalMC()); - IPAddress ip3("FF05:0:0:0:0:0:0:FB"); // site local unicast + IPAddress ip3("ff05:0:0:0:0:0:0:FB"); // site local unicast assert (!ip3.isWildcard()); assert (!ip3.isBroadcast()); assert (!ip3.isLoopback()); @@ -471,7 +471,7 @@ void IPAddressTest::testMCClassification6() assert (!ip3.isOrgLocalMC()); assert (!ip3.isGlobalMC()); - IPAddress ip4("FF18:0:0:0:0:0:0:FB"); // org local unicast + IPAddress ip4("ff18:0:0:0:0:0:0:FB"); // org local unicast assert (!ip4.isWildcard()); assert (!ip4.isBroadcast()); assert (!ip4.isLoopback()); @@ -486,7 +486,7 @@ void IPAddressTest::testMCClassification6() assert (ip4.isOrgLocalMC()); assert (!ip4.isGlobalMC()); - IPAddress ip5("FF1F:0:0:0:0:0:0:FB"); // global unicast + IPAddress ip5("ff1f:0:0:0:0:0:0:FB"); // global unicast assert (!ip5.isWildcard()); assert (!ip5.isBroadcast()); assert (!ip5.isLoopback()); diff --git a/Net/testsuite/src/NetworkInterfaceTest.cpp b/Net/testsuite/src/NetworkInterfaceTest.cpp index 9e62864b8..e776e8e25 100644 --- a/Net/testsuite/src/NetworkInterfaceTest.cpp +++ b/Net/testsuite/src/NetworkInterfaceTest.cpp @@ -34,10 +34,12 @@ #include "CppUnit/TestCaller.h" #include "CppUnit/TestSuite.h" #include "Poco/Net/NetworkInterface.h" +#include "Poco/Net/IPAddress.h" #include using Poco::Net::NetworkInterface; +using Poco::Net::IPAddress; NetworkInterfaceTest::NetworkInterfaceTest(const std::string& name): CppUnit::TestCase(name) @@ -50,18 +52,66 @@ NetworkInterfaceTest::~NetworkInterfaceTest() } +void NetworkInterfaceTest::testMap() +{ + NetworkInterface::Map map = NetworkInterface::map(); + assert (!map.empty()); + for (NetworkInterface::Map::const_iterator it = map.begin(); it != map.end(); ++it) + { + std::cout << std::endl << "=============" << std::endl; + + 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; + + typedef NetworkInterface::AddressList List; + const List& ipList = it->second.addressList(); + List::const_iterator ipIt = ipList.begin(); + List::const_iterator ipEnd = ipList.end(); + for (int counter = 0; ipIt != ipEnd; ++ipIt, ++counter) + { + std::cout << std::endl << "----------" << std::endl; + std::cout << "Address " << counter << std::endl; + std::cout << "----------" << std::endl; + std::cout << "Address: " << ipIt->get().toString() << std::endl; + IPAddress addr = ipIt->get(); + if (!addr.isWildcard()) std::cout << "Subnet: " << addr.toString() << std::endl; + addr = ipIt->get(); + if (!addr.isWildcard()) std::cout << "Broadcast: " << addr.toString() << std::endl; + } + + std::cout << "=============" << std::endl << std::endl; + } +} + + void NetworkInterfaceTest::testList() { - NetworkInterface::NetworkInterfaceList list = NetworkInterface::list(); + NetworkInterface::List list = NetworkInterface::list(); assert (!list.empty()); for (NetworkInterface::NetworkInterfaceList::const_iterator it = list.begin(); it != list.end(); ++it) { + std::cout << "==============" << std::endl; + + std::cout << "Index: " << it->index() << std::endl; std::cout << "Name: " << it->name() << std::endl; std::cout << "DisplayName: " << it->displayName() << std::endl; - std::cout << "Address: " << it->address().toString() << std::endl; - std::cout << "Subnet: " << it->subnetMask().toString() << std::endl; - std::cout << "Broadcast: " << it->broadcastAddress().toString() << std::endl; - std::cout << "Index: " << it->index() << std::endl; + + typedef NetworkInterface::AddressList List; + const List& ipList = it->addressList(); + List::const_iterator ipIt = ipList.begin(); + List::const_iterator ipEnd = ipList.end(); + for (int counter = 0; ipIt != ipEnd; ++ipIt, ++counter) + { + std::cout << "IP Address: " << ipIt->get().toString() << std::endl; + IPAddress addr = ipIt->get(); + if (!addr.isWildcard()) std::cout << "Subnet: " << ipIt->get().toString() << std::endl; + addr = ipIt->get(); + if (!addr.isWildcard()) std::cout << "Broadcast: " << ipIt->get().toString() << std::endl; + } + + std::cout << "==============" << std::endl << std::endl; } } @@ -116,6 +166,7 @@ CppUnit::Test* NetworkInterfaceTest::suite() CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("NetworkInterfaceTest"); CppUnit_addTest(pSuite, NetworkInterfaceTest, testList); + CppUnit_addTest(pSuite, NetworkInterfaceTest, testMap); CppUnit_addTest(pSuite, NetworkInterfaceTest, testForName); CppUnit_addTest(pSuite, NetworkInterfaceTest, testForAddress); CppUnit_addTest(pSuite, NetworkInterfaceTest, testForIndex); diff --git a/Net/testsuite/src/NetworkInterfaceTest.h b/Net/testsuite/src/NetworkInterfaceTest.h index 23cc65c04..e2ac26b1c 100644 --- a/Net/testsuite/src/NetworkInterfaceTest.h +++ b/Net/testsuite/src/NetworkInterfaceTest.h @@ -47,6 +47,7 @@ public: ~NetworkInterfaceTest(); void testList(); + void testMap(); void testForName(); void testForAddress(); void testForIndex();