// // NetworkInterface.cpp // // $Id: //poco/1.2/Net/src/NetworkInterface.cpp#1 $ // // Library: Net // Package: Sockets // Module: NetworkInterface // // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH. // and Contributors. // // Permission is hereby granted, free of charge, to any person or organization // obtaining a copy of the software and accompanying documentation covered by // this license (the "Software") to use, reproduce, display, distribute, // execute, and transmit the Software, and to prepare derivative works of the // Software, and to permit third-parties to whom the Software is furnished to // do so, all subject to the following: // // The copyright notices in the Software and this entire statement, including // the above license grant, this restriction and the following disclaimer, // must be included in all copies of the Software, in whole or in part, and // all derivative works of the Software, unless such copies or derivative // works are solely in the form of machine-executable object code generated by // a source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // #include "Poco/Net/NetworkInterface.h" #include "Poco/Net/DatagramSocket.h" #include "Poco/Net/NetException.h" #include "Poco/NumberFormatter.h" #include using Poco::NumberFormatter; using Poco::FastMutex; namespace Poco { namespace Net { FastMutex NetworkInterface::_mutex; NetworkInterface::NetworkInterface(): _index(0) { } NetworkInterface::NetworkInterface(const std::string& name, const IPAddress& address, int index): _name(name), _address(address), _index(index) { } NetworkInterface::NetworkInterface(const NetworkInterface& interface): _name(interface._name), _address(interface._address), _index(interface._index) { } NetworkInterface::~NetworkInterface() { } NetworkInterface& NetworkInterface::operator = (const NetworkInterface& interface) { if (&interface != this) { _name = interface._name; _address = interface._address; _index = interface._index; } return *this; } NetworkInterface NetworkInterface::forName(const std::string& name, bool requireIPv6) { #if defined(_WIN32) NetworkInterfaceList ifs = list(); for (NetworkInterfaceList::const_iterator it = ifs.begin(); it != ifs.end(); ++it) { if (it->name() == name && it->supportsIPv6() == requireIPv6) return *it; } throw InterfaceNotFoundException(name); #else FastMutex::ScopedLock lock(_mutex); struct ifreq ifr; strncpy(ifr.ifr_name, name.c_str(), IFNAMSIZ); DatagramSocket ds(requireIPv6 ? IPAddress::IPv6 : IPAddress::IPv4); ds.impl()->ioctl(SIOCGIFADDR, &ifr); IPAddress addr; #if defined(POCO_HAVE_IPv6) if (ifr.ifr_addr.sa_family == AF_INET) addr = IPAddress(&reinterpret_cast(&ifr.ifr_addr)->sin_addr, sizeof(struct in_addr)); else if (ifr.ifr_addr.sa_family == AF_INET6) addr = IPAddress(&reinterpret_cast(&ifr.ifr_addr)->sin6_addr, sizeof(struct in6_addr)); else throw InterfaceNotFoundException(addr.toString(), "interface has no IP address"); int index = if_nametoindex(name.c_str()); #else if (ifr.ifr_addr.sa_family == AF_INET) addr = IPAddress(&reinterpret_cast(&ifr.ifr_addr)->sin_addr, sizeof(struct in_addr)); else throw InterfaceNotFoundException(addr.toString(), "interface has no IP address"); int index = 0; #endif return NetworkInterface(name, addr, index); #endif } NetworkInterface NetworkInterface::forAddress(const IPAddress& addr) { NetworkInterfaceList ifs = list(); for (NetworkInterfaceList::const_iterator it = ifs.begin(); it != ifs.end(); ++it) { if (it->address() == addr) return *it; } throw InterfaceNotFoundException(addr.toString()); } NetworkInterface NetworkInterface::forIndex(int i) { if (i != 0) { NetworkInterfaceList ifs = list(); for (NetworkInterfaceList::const_iterator it = ifs.begin(); it != ifs.end(); ++it) { if (it->index() == i) return *it; } throw InterfaceNotFoundException("#" + NumberFormatter::format(i)); } else return NetworkInterface(); } } } // namespace Poco::Net // // platform-specific code below // #if defined(POCO_OS_FAMILY_WINDOWS) // // Windows // #include namespace Poco { namespace Net { NetworkInterface::NetworkInterfaceList NetworkInterface::list() { FastMutex::ScopedLock lock(_mutex); NetworkInterfaceList result; #if defined(POCO_HAVE_IPv6) // On Windows XP/Server 2003 and later we use GetAdaptersAddresses. PIP_ADAPTER_ADDRESSES pAdapterAddresses; PIP_ADAPTER_ADDRESSES pAdapter = 0; ULONG len = sizeof(IP_ADAPTER_ADDRESSES); pAdapterAddresses = reinterpret_cast(new char[len]); // Make an initial call to GetAdaptersAddresses to get // the necessary size into len DWORD rc = GetAdaptersAddresses(AF_UNSPEC, 0, 0, pAdapterAddresses, &len); if (rc == ERROR_BUFFER_OVERFLOW) { delete [] reinterpret_cast(pAdapterAddresses); pAdapterAddresses = reinterpret_cast(new char[len]); } else if (rc != ERROR_SUCCESS) { throw NetException("cannot get network adapter list"); } try { if (GetAdaptersAddresses(AF_UNSPEC, 0, 0, pAdapterAddresses, &len) == NO_ERROR) { pAdapter = pAdapterAddresses; while (pAdapter) { if (pAdapter->FirstUnicastAddress) { IPAddress addr(pAdapter->FirstUnicastAddress->Address.lpSockaddr, pAdapter->FirstUnicastAddress->Address.iSockaddrLength); result.push_back(NetworkInterface(std::string(pAdapter->AdapterName), addr, pAdapter->Ipv6IfIndex)); pAdapter = pAdapter->Next; } } } else throw NetException("cannot get network adapter list"); } catch (Poco::Exception&) { delete [] reinterpret_cast(pAdapterAddresses); throw; } delete [] reinterpret_cast(pAdapterAddresses); #else // Add loopback interface (not returned by GetAdaptersInfo) result.push_back(NetworkInterface("Loopback", IPAddress("127.0.0.1"), -1)); // On Windows 2000 we use GetAdaptersInfo. PIP_ADAPTER_INFO pAdapterInfo; PIP_ADAPTER_INFO pAdapter = 0; ULONG len = sizeof(IP_ADAPTER_INFO); pAdapterInfo = reinterpret_cast(new char[len]); // Make an initial call to GetAdaptersInfo to get // the necessary size into len DWORD rc = GetAdaptersInfo(pAdapterInfo, &len); if (rc == ERROR_BUFFER_OVERFLOW) { delete [] reinterpret_cast(pAdapterInfo); pAdapterInfo = reinterpret_cast(new char[len]); } else if (rc != ERROR_SUCCESS) { throw NetException("cannot get network adapter list"); } try { if (GetAdaptersInfo(pAdapterInfo, &len) == NO_ERROR) { pAdapter = pAdapterInfo; while (pAdapter) { IPAddress addr(std::string(pAdapter->IpAddressList.IpAddress.String)); result.push_back(NetworkInterface(std::string(pAdapter->AdapterName), addr)); pAdapter = pAdapter->Next; } } else throw NetException("cannot get network adapter list"); } catch (Poco::Exception&) { delete [] reinterpret_cast(pAdapterInfo); throw; } delete [] reinterpret_cast(pAdapterInfo); #endif return result; } } } // namespace Poco::Net #elif defined(POCO_OS_FAMILY_BSD) || POCO_OS == POCO_OS_QNX // // BSD variants // #include #include #include #include namespace Poco { namespace Net { NetworkInterface::NetworkInterfaceList NetworkInterface::list() { FastMutex::ScopedLock lock(_mutex); NetworkInterfaceList result; struct ifaddrs* ifaphead; int rc = getifaddrs(&ifaphead); if (rc) throw NetException("cannot get network adapter list"); for (struct ifaddrs* ifap = ifaphead; ifap; ifap = ifap->ifa_next) { if (ifap->ifa_addr) { if (ifap->ifa_addr->sa_family == AF_INET) { IPAddress addr(&reinterpret_cast(ifap->ifa_addr)->sin_addr, sizeof(struct in_addr)); result.push_back(NetworkInterface(std::string(ifap->ifa_name), addr)); } #if defined(POCO_HAVE_IPv6) else if (ifap->ifa_addr->sa_family == AF_INET6) { IPAddress addr(&reinterpret_cast(ifap->ifa_addr)->sin6_addr, sizeof(struct in6_addr)); result.push_back(NetworkInterface(std::string(ifap->ifa_name), addr, if_nametoindex(ifap->ifa_name))); } #endif } } freeifaddrs(ifaphead); return result; } } } // namespace Poco::Net #elif POCO_OS == POCO_OS_LINUX // // Linux // namespace Poco { namespace Net { NetworkInterface::NetworkInterfaceList NetworkInterface::list() { FastMutex::ScopedLock lock(_mutex); NetworkInterfaceList result; DatagramSocket socket; // the following code is loosely based // on W. Richard Stevens, UNIX Network Programming, pp 434ff. int lastlen = 0; int len = 100*sizeof(struct ifreq); char* buf = 0; try { struct ifconf ifc; for (;;) { buf = new char[len]; ifc.ifc_len = len; ifc.ifc_buf = buf; if (::ioctl(socket.impl()->sockfd(), SIOCGIFCONF, &ifc) < 0) { if (errno != EINVAL || lastlen != 0) throw NetException("cannot get network adapter list"); } else { if (ifc.ifc_len == lastlen) break; lastlen = ifc.ifc_len; } len += 10*sizeof(struct ifreq); delete [] buf; } for (const char* ptr = buf; ptr < buf + ifc.ifc_len;) { const struct ifreq* ifr = reinterpret_cast(ptr); IPAddress addr; bool haveAddr = false; switch (ifr->ifr_addr.sa_family) { #if defined(POCO_HAVE_IPv6) case AF_INET6: addr = IPAddress(&reinterpret_cast(&ifr->ifr_addr)->sin6_addr, sizeof(struct in6_addr)); haveAddr = true; break; #endif case AF_INET: addr = IPAddress(&reinterpret_cast(&ifr->ifr_addr)->sin_addr, sizeof(struct in_addr)); haveAddr = true; break; default: break; } if (haveAddr) { #if defined(POCO_HAVE_IPv6) int index = if_nametoindex(ifr->ifr_name); #else int index = -1; #endif result.push_back(NetworkInterface(std::string(ifr->ifr_name), addr, index)); } ptr += sizeof(struct ifreq); } } catch (...) { delete [] buf; throw; } delete [] buf; return result; } } } // namespace Poco::Net #else // // Non-BSD Unix variants // namespace Poco { namespace Net { NetworkInterface::NetworkInterfaceList NetworkInterface::list() { FastMutex::ScopedLock lock(_mutex); NetworkInterfaceList result; DatagramSocket socket; // the following code is loosely based // on W. Richard Stevens, UNIX Network Programming, pp 434ff. int lastlen = 0; int len = 100*sizeof(struct ifreq); char* buf = 0; try { struct ifconf ifc; for (;;) { buf = new char[len]; ifc.ifc_len = len; ifc.ifc_buf = buf; if (::ioctl(socket.impl()->sockfd(), SIOCGIFCONF, &ifc) < 0) { if (errno != EINVAL || lastlen != 0) throw NetException("cannot get network adapter list"); } else { if (ifc.ifc_len == lastlen) break; lastlen = ifc.ifc_len; } len += 10*sizeof(struct ifreq); delete [] buf; } for (const char* ptr = buf; ptr < buf + ifc.ifc_len;) { const struct ifreq* ifr = reinterpret_cast(ptr); #if defined(POCO_HAVE_SALEN) len = ifr->ifr_addr.sa_len; if (sizeof(struct sockaddr) > len) len = sizeof(struct sockaddr); #else len = sizeof(struct sockaddr); #endif IPAddress addr; bool haveAddr = false; switch (ifr->ifr_addr.sa_family) { #if defined(POCO_HAVE_IPv6) case AF_INET6: if (len < sizeof(struct sockaddr_in6)) len = sizeof(struct sockaddr_in6); addr = IPAddress(&reinterpret_cast(&ifr->ifr_addr)->sin6_addr, sizeof(struct in6_addr)); haveAddr = true; break; #endif case AF_INET: if (len < sizeof(struct sockaddr_in)) len = sizeof(struct sockaddr_in); addr = IPAddress(&reinterpret_cast(&ifr->ifr_addr)->sin_addr, sizeof(struct in_addr)); haveAddr = true; break; default: break; } if (haveAddr) { #if defined(POCO_HAVE_IPv6) int index = if_nametoindex(ifr->ifr_name); #else int index = -1; #endif result.push_back(NetworkInterface(std::string(ifr->ifr_name), addr, index)); } len += sizeof(ifr->ifr_name); ptr += len; } } catch (...) { delete [] buf; throw; } delete [] buf; return result; } } } // namespace Poco::Net #endif