| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Copyright (C) 2016 Intel Corporation. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtNetwork module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qbytearray.h" |
| #include "qset.h" |
| #include "qnetworkinterface.h" |
| #include "qnetworkinterface_p.h" |
| #include "qnetworkinterface_unix_p.h" |
| #include "qalgorithms.h" |
| |
| #ifndef QT_NO_NETWORKINTERFACE |
| |
| #if defined(QT_NO_CLOCK_MONOTONIC) |
| # include "qdatetime.h" |
| #endif |
| |
| #if defined(QT_LINUXBASE) |
| # define QT_NO_GETIFADDRS |
| #endif |
| |
| #ifndef QT_NO_GETIFADDRS |
| # include <ifaddrs.h> |
| #endif |
| |
| #ifdef QT_LINUXBASE |
| # include <arpa/inet.h> |
| # ifndef SIOCGIFBRDADDR |
| # define SIOCGIFBRDADDR 0x8919 |
| # endif |
| #endif // QT_LINUXBASE |
| |
| #include <qplatformdefs.h> |
| |
| QT_BEGIN_NAMESPACE |
| |
| static QHostAddress addressFromSockaddr(sockaddr *sa, int ifindex = 0, const QString &ifname = QString()) |
| { |
| QHostAddress address; |
| if (!sa) |
| return address; |
| |
| if (sa->sa_family == AF_INET) |
| address.setAddress(htonl(((sockaddr_in *)sa)->sin_addr.s_addr)); |
| else if (sa->sa_family == AF_INET6) { |
| address.setAddress(((sockaddr_in6 *)sa)->sin6_addr.s6_addr); |
| int scope = ((sockaddr_in6 *)sa)->sin6_scope_id; |
| if (scope && scope == ifindex) { |
| // this is the most likely scenario: |
| // a scope ID in a socket is that of the interface this address came from |
| address.setScopeId(ifname); |
| } else if (scope) { |
| address.setScopeId(QNetworkInterfaceManager::interfaceNameFromIndex(scope)); |
| } |
| } |
| return address; |
| |
| } |
| |
| uint QNetworkInterfaceManager::interfaceIndexFromName(const QString &name) |
| { |
| #ifndef QT_NO_IPV6IFNAME |
| return ::if_nametoindex(name.toLatin1()); |
| #elif defined(SIOCGIFINDEX) |
| struct ifreq req; |
| int socket = qt_safe_socket(AF_INET, SOCK_STREAM, 0); |
| if (socket < 0) |
| return 0; |
| |
| QByteArray name8bit = name.toLatin1(); |
| memset(&req, 0, sizeof(ifreq)); |
| memcpy(req.ifr_name, name8bit, qMin<int>(name8bit.length() + 1, sizeof(req.ifr_name) - 1)); |
| |
| uint id = 0; |
| if (qt_safe_ioctl(socket, SIOCGIFINDEX, &req) >= 0) |
| id = req.ifr_ifindex; |
| qt_safe_close(socket); |
| return id; |
| #else |
| return 0; |
| #endif |
| } |
| |
| QString QNetworkInterfaceManager::interfaceNameFromIndex(uint index) |
| { |
| #ifndef QT_NO_IPV6IFNAME |
| char buf[IF_NAMESIZE]; |
| if (::if_indextoname(index, buf)) |
| return QString::fromLatin1(buf); |
| #elif defined(SIOCGIFNAME) |
| struct ifreq req; |
| int socket = qt_safe_socket(AF_INET, SOCK_STREAM, 0); |
| if (socket >= 0) { |
| memset(&req, 0, sizeof(ifreq)); |
| req.ifr_ifindex = index; |
| |
| if (qt_safe_ioctl(socket, SIOCGIFNAME, &req) >= 0) { |
| qt_safe_close(socket); |
| return QString::fromLatin1(req.ifr_name); |
| } |
| qt_safe_close(socket); |
| } |
| #endif |
| return QString::number(uint(index)); |
| } |
| |
| static int getMtu(int socket, struct ifreq *req) |
| { |
| #ifdef SIOCGIFMTU |
| if (qt_safe_ioctl(socket, SIOCGIFMTU, req) == 0) |
| return req->ifr_mtu; |
| #endif |
| return 0; |
| } |
| |
| #ifdef QT_NO_GETIFADDRS |
| // getifaddrs not available |
| |
| static QSet<QByteArray> interfaceNames(int socket) |
| { |
| QSet<QByteArray> result; |
| #ifdef QT_NO_IPV6IFNAME |
| QByteArray storageBuffer; |
| struct ifconf interfaceList; |
| static const int STORAGEBUFFER_GROWTH = 256; |
| |
| forever { |
| // grow the storage buffer |
| storageBuffer.resize(storageBuffer.size() + STORAGEBUFFER_GROWTH); |
| interfaceList.ifc_buf = storageBuffer.data(); |
| interfaceList.ifc_len = storageBuffer.size(); |
| |
| // get the interface list |
| if (qt_safe_ioctl(socket, SIOCGIFCONF, &interfaceList) >= 0) { |
| if (int(interfaceList.ifc_len + sizeof(ifreq) + 64) < storageBuffer.size()) { |
| // if the buffer was big enough, break |
| storageBuffer.resize(interfaceList.ifc_len); |
| break; |
| } |
| } else { |
| // internal error |
| return result; |
| } |
| if (storageBuffer.size() > 100000) { |
| // out of space |
| return result; |
| } |
| } |
| |
| int interfaceCount = interfaceList.ifc_len / sizeof(ifreq); |
| for (int i = 0; i < interfaceCount; ++i) { |
| QByteArray name = QByteArray(interfaceList.ifc_req[i].ifr_name); |
| if (!name.isEmpty()) |
| result << name; |
| } |
| |
| return result; |
| #else |
| Q_UNUSED(socket); |
| |
| // use if_nameindex |
| struct if_nameindex *interfaceList = ::if_nameindex(); |
| for (struct if_nameindex *ptr = interfaceList; ptr && ptr->if_name; ++ptr) |
| result << ptr->if_name; |
| |
| if_freenameindex(interfaceList); |
| return result; |
| #endif |
| } |
| |
| static QNetworkInterfacePrivate *findInterface(int socket, QList<QNetworkInterfacePrivate *> &interfaces, |
| struct ifreq &req) |
| { |
| QNetworkInterfacePrivate *iface = 0; |
| int ifindex = 0; |
| |
| #if !defined(QT_NO_IPV6IFNAME) || defined(SIOCGIFINDEX) |
| // Get the interface index |
| # ifdef SIOCGIFINDEX |
| if (qt_safe_ioctl(socket, SIOCGIFINDEX, &req) >= 0) |
| # if defined(Q_OS_HAIKU) |
| ifindex = req.ifr_index; |
| # else |
| ifindex = req.ifr_ifindex; |
| # endif |
| # else |
| ifindex = if_nametoindex(req.ifr_name); |
| # endif |
| |
| // find the interface data |
| QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin(); |
| for ( ; if_it != interfaces.end(); ++if_it) |
| if ((*if_it)->index == ifindex) { |
| // existing interface |
| iface = *if_it; |
| break; |
| } |
| #else |
| // Search by name |
| QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin(); |
| for ( ; if_it != interfaces.end(); ++if_it) |
| if ((*if_it)->name == QLatin1String(req.ifr_name)) { |
| // existing interface |
| iface = *if_it; |
| break; |
| } |
| #endif |
| |
| if (!iface) { |
| // new interface, create data: |
| iface = new QNetworkInterfacePrivate; |
| iface->index = ifindex; |
| interfaces << iface; |
| } |
| |
| return iface; |
| } |
| |
| static QList<QNetworkInterfacePrivate *> interfaceListing() |
| { |
| QList<QNetworkInterfacePrivate *> interfaces; |
| |
| int socket; |
| if ((socket = qt_safe_socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == -1) |
| return interfaces; // error |
| |
| QSet<QByteArray> names = interfaceNames(socket); |
| QSet<QByteArray>::ConstIterator it = names.constBegin(); |
| for ( ; it != names.constEnd(); ++it) { |
| ifreq req; |
| memset(&req, 0, sizeof(ifreq)); |
| memcpy(req.ifr_name, *it, qMin<int>(it->length() + 1, sizeof(req.ifr_name) - 1)); |
| |
| QNetworkInterfacePrivate *iface = findInterface(socket, interfaces, req); |
| |
| #ifdef SIOCGIFNAME |
| // Get the canonical name |
| QByteArray oldName = req.ifr_name; |
| if (qt_safe_ioctl(socket, SIOCGIFNAME, &req) >= 0) { |
| iface->name = QString::fromLatin1(req.ifr_name); |
| |
| // reset the name: |
| memcpy(req.ifr_name, oldName, qMin<int>(oldName.length() + 1, sizeof(req.ifr_name) - 1)); |
| } else |
| #endif |
| { |
| // use this name anyways |
| iface->name = QString::fromLatin1(req.ifr_name); |
| } |
| |
| // Get interface flags |
| if (qt_safe_ioctl(socket, SIOCGIFFLAGS, &req) >= 0) { |
| iface->flags = convertFlags(req.ifr_flags); |
| } |
| iface->mtu = getMtu(socket, &req); |
| |
| #ifdef SIOCGIFHWADDR |
| // Get the HW address |
| if (qt_safe_ioctl(socket, SIOCGIFHWADDR, &req) >= 0) { |
| uchar *addr = (uchar *)req.ifr_addr.sa_data; |
| iface->hardwareAddress = iface->makeHwAddress(6, addr); |
| } |
| #endif |
| |
| // Get the address of the interface |
| QNetworkAddressEntry entry; |
| if (qt_safe_ioctl(socket, SIOCGIFADDR, &req) >= 0) { |
| sockaddr *sa = &req.ifr_addr; |
| entry.setIp(addressFromSockaddr(sa)); |
| |
| // Get the interface broadcast address |
| if (iface->flags & QNetworkInterface::CanBroadcast) { |
| if (qt_safe_ioctl(socket, SIOCGIFBRDADDR, &req) >= 0) { |
| sockaddr *sa = &req.ifr_addr; |
| if (sa->sa_family == AF_INET) |
| entry.setBroadcast(addressFromSockaddr(sa)); |
| } |
| } |
| |
| // Get the interface netmask |
| if (qt_safe_ioctl(socket, SIOCGIFNETMASK, &req) >= 0) { |
| sockaddr *sa = &req.ifr_addr; |
| entry.setNetmask(addressFromSockaddr(sa)); |
| } |
| |
| iface->addressEntries << entry; |
| } |
| } |
| |
| ::close(socket); |
| return interfaces; |
| } |
| |
| #else |
| // use getifaddrs |
| |
| // platform-specific defs: |
| # ifdef Q_OS_LINUX |
| QT_BEGIN_INCLUDE_NAMESPACE |
| # include <features.h> |
| QT_END_INCLUDE_NAMESPACE |
| # endif |
| |
| # if defined(Q_OS_LINUX) && __GLIBC__ - 0 >= 2 && __GLIBC_MINOR__ - 0 >= 1 && !defined(QT_LINUXBASE) |
| # include <netpacket/packet.h> |
| |
| static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList) |
| { |
| Q_UNUSED(getMtu) |
| QList<QNetworkInterfacePrivate *> interfaces; |
| QSet<QString> seenInterfaces; |
| QVarLengthArray<int, 16> seenIndexes; // faster than QSet<int> |
| |
| // On Linux, glibc, uClibc and MUSL obtain the address listing via two |
| // netlink calls: first an RTM_GETLINK to obtain the interface listing, |
| // then one RTM_GETADDR to get all the addresses (uClibc implementation is |
| // copied from glibc; Bionic currently doesn't support getifaddrs). They |
| // synthesize AF_PACKET addresses from the RTM_GETLINK responses, which |
| // means by construction they currently show up first in the interface |
| // listing. |
| for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) { |
| if (ptr->ifa_addr && ptr->ifa_addr->sa_family == AF_PACKET) { |
| sockaddr_ll *sll = (sockaddr_ll *)ptr->ifa_addr; |
| QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate; |
| interfaces << iface; |
| iface->index = sll->sll_ifindex; |
| iface->name = QString::fromLatin1(ptr->ifa_name); |
| iface->flags = convertFlags(ptr->ifa_flags); |
| iface->hardwareAddress = iface->makeHwAddress(sll->sll_halen, (uchar*)sll->sll_addr); |
| |
| Q_ASSERT(!seenIndexes.contains(iface->index)); |
| seenIndexes.append(iface->index); |
| seenInterfaces.insert(iface->name); |
| } |
| } |
| |
| // see if we missed anything: |
| // - virtual interfaces with no HW address have no AF_PACKET |
| // - interface labels have no AF_PACKET, but shouldn't be shown as a new interface |
| for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) { |
| if (!ptr->ifa_addr || ptr->ifa_addr->sa_family != AF_PACKET) { |
| QString name = QString::fromLatin1(ptr->ifa_name); |
| if (seenInterfaces.contains(name)) |
| continue; |
| |
| int ifindex = if_nametoindex(ptr->ifa_name); |
| if (seenIndexes.contains(ifindex)) |
| continue; |
| |
| seenInterfaces.insert(name); |
| seenIndexes.append(ifindex); |
| |
| QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate; |
| interfaces << iface; |
| iface->name = name; |
| iface->flags = convertFlags(ptr->ifa_flags); |
| iface->index = ifindex; |
| } |
| } |
| |
| return interfaces; |
| } |
| |
| static void getAddressExtraInfo(QNetworkAddressEntry *entry, struct sockaddr *sa, const char *ifname) |
| { |
| Q_UNUSED(entry); |
| Q_UNUSED(sa); |
| Q_UNUSED(ifname) |
| } |
| |
| # elif defined(Q_OS_BSD4) |
| QT_BEGIN_INCLUDE_NAMESPACE |
| # include <net/if_dl.h> |
| #if defined(QT_PLATFORM_UIKIT) |
| # include "qnetworkinterface_uikit_p.h" |
| #if !defined(QT_WATCHOS_OUTDATED_SDK_WORKAROUND) |
| // TODO: remove it as soon as SDK is updated on CI!!! |
| # include <net/if_types.h> |
| #endif |
| #else |
| # include <net/if_media.h> |
| # include <net/if_types.h> |
| # include <netinet/in_var.h> |
| #endif // QT_PLATFORM_UIKIT |
| QT_END_INCLUDE_NAMESPACE |
| |
| static int openSocket(int &socket) |
| { |
| if (socket == -1) |
| socket = qt_safe_socket(AF_INET, SOCK_DGRAM, 0); |
| return socket; |
| } |
| |
| static QNetworkInterface::InterfaceType probeIfType(int socket, int iftype, struct ifmediareq *req) |
| { |
| // Determine the interface type. |
| |
| // On Darwin, these are #defines, but on FreeBSD they're just an |
| // enum, so we can't #ifdef them. Use the authoritative list from |
| // https://www.iana.org/assignments/smi-numbers/smi-numbers.xhtml#smi-numbers-5 |
| switch (iftype) { |
| case IFT_PPP: |
| return QNetworkInterface::Ppp; |
| |
| case IFT_LOOP: |
| return QNetworkInterface::Loopback; |
| |
| case IFT_SLIP: |
| return QNetworkInterface::Slip; |
| |
| case 0x47: // IFT_IEEE80211 |
| return QNetworkInterface::Ieee80211; |
| |
| case IFT_IEEE1394: |
| return QNetworkInterface::Ieee1394; |
| |
| case IFT_GIF: |
| case IFT_STF: |
| return QNetworkInterface::Virtual; |
| } |
| |
| // For the remainder (including Ethernet), let's try SIOGIFMEDIA |
| req->ifm_count = 0; |
| if (qt_safe_ioctl(socket, SIOCGIFMEDIA, req) == 0) { |
| // see https://man.openbsd.org/ifmedia.4 |
| |
| switch (IFM_TYPE(req->ifm_current)) { |
| case IFM_ETHER: |
| return QNetworkInterface::Ethernet; |
| |
| #ifdef IFM_FDDI |
| case IFM_FDDI: |
| return QNetworkInterface::Fddi; |
| #endif |
| |
| case IFM_IEEE80211: |
| return QNetworkInterface::Ieee80211; |
| } |
| } |
| |
| return QNetworkInterface::Unknown; |
| } |
| |
| static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList) |
| { |
| QList<QNetworkInterfacePrivate *> interfaces; |
| union { |
| struct ifmediareq mediareq; |
| struct ifreq req; |
| }; |
| int socket = -1; |
| memset(&mediareq, 0, sizeof(mediareq)); |
| |
| // ensure both structs start with the name field, of size IFNAMESIZ |
| Q_STATIC_ASSERT(sizeof(mediareq.ifm_name) == sizeof(req.ifr_name)); |
| Q_ASSERT(&mediareq.ifm_name == &req.ifr_name); |
| |
| // on NetBSD we use AF_LINK and sockaddr_dl |
| // scan the list for that family |
| for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) |
| if (ptr->ifa_addr && ptr->ifa_addr->sa_family == AF_LINK) { |
| QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate; |
| interfaces << iface; |
| |
| sockaddr_dl *sdl = (sockaddr_dl *)ptr->ifa_addr; |
| iface->index = sdl->sdl_index; |
| iface->name = QString::fromLatin1(ptr->ifa_name); |
| iface->flags = convertFlags(ptr->ifa_flags); |
| iface->hardwareAddress = iface->makeHwAddress(sdl->sdl_alen, (uchar*)LLADDR(sdl)); |
| |
| qstrncpy(mediareq.ifm_name, ptr->ifa_name, sizeof(mediareq.ifm_name)); |
| iface->type = probeIfType(openSocket(socket), sdl->sdl_type, &mediareq); |
| iface->mtu = getMtu(socket, &req); |
| } |
| |
| if (socket != -1) |
| qt_safe_close(socket); |
| return interfaces; |
| } |
| |
| static void getAddressExtraInfo(QNetworkAddressEntry *entry, struct sockaddr *sa, const char *ifname) |
| { |
| // get IPv6 address lifetimes |
| if (sa->sa_family != AF_INET6) |
| return; |
| |
| struct in6_ifreq ifr; |
| |
| int s6 = qt_safe_socket(AF_INET6, SOCK_DGRAM, 0); |
| if (Q_UNLIKELY(s6 < 0)) { |
| qErrnoWarning("QNetworkInterface: could not create IPv6 socket"); |
| return; |
| } |
| |
| qstrncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
| |
| // get flags |
| ifr.ifr_addr = *reinterpret_cast<struct sockaddr_in6 *>(sa); |
| if (qt_safe_ioctl(s6, SIOCGIFAFLAG_IN6, &ifr) < 0) { |
| qt_safe_close(s6); |
| return; |
| } |
| int flags = ifr.ifr_ifru.ifru_flags6; |
| QNetworkInterfacePrivate::calculateDnsEligibility(entry, |
| flags & IN6_IFF_TEMPORARY, |
| flags & IN6_IFF_DEPRECATED); |
| |
| // get lifetimes |
| ifr.ifr_addr = *reinterpret_cast<struct sockaddr_in6 *>(sa); |
| if (qt_safe_ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr) < 0) { |
| qt_safe_close(s6); |
| return; |
| } |
| qt_safe_close(s6); |
| |
| auto toDeadline = [](time_t when) { |
| QDeadlineTimer deadline = QDeadlineTimer::Forever; |
| if (when) { |
| #if defined(QT_NO_CLOCK_MONOTONIC) |
| // no monotonic clock |
| deadline.setPreciseRemainingTime(when - QDateTime::currentSecsSinceEpoch()); |
| #else |
| deadline.setPreciseDeadline(when); |
| #endif |
| } |
| return deadline; |
| }; |
| entry->setAddressLifetime(toDeadline(ifr.ifr_ifru.ifru_lifetime.ia6t_preferred), |
| toDeadline(ifr.ifr_ifru.ifru_lifetime.ia6t_expire)); |
| } |
| |
| # else // Generic version |
| |
| static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList) |
| { |
| Q_UNUSED(getMtu) |
| QList<QNetworkInterfacePrivate *> interfaces; |
| |
| // make sure there's one entry for each interface |
| for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) { |
| // Get the interface index |
| int ifindex = if_nametoindex(ptr->ifa_name); |
| |
| QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin(); |
| for ( ; if_it != interfaces.end(); ++if_it) |
| if ((*if_it)->index == ifindex) |
| // this one has been added already |
| break; |
| |
| if (if_it == interfaces.end()) { |
| // none found, create |
| QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate; |
| interfaces << iface; |
| |
| iface->index = ifindex; |
| iface->name = QString::fromLatin1(ptr->ifa_name); |
| iface->flags = convertFlags(ptr->ifa_flags); |
| } |
| } |
| |
| return interfaces; |
| } |
| |
| static void getAddressExtraInfo(QNetworkAddressEntry *entry, struct sockaddr *sa, const char *ifname) |
| { |
| Q_UNUSED(entry); |
| Q_UNUSED(sa); |
| Q_UNUSED(ifname) |
| } |
| # endif |
| |
| static QList<QNetworkInterfacePrivate *> interfaceListing() |
| { |
| QList<QNetworkInterfacePrivate *> interfaces; |
| |
| ifaddrs *interfaceListing; |
| if (getifaddrs(&interfaceListing) == -1) { |
| // error |
| return interfaces; |
| } |
| |
| interfaces = createInterfaces(interfaceListing); |
| for (ifaddrs *ptr = interfaceListing; ptr; ptr = ptr->ifa_next) { |
| // Find the interface |
| QLatin1String name(ptr->ifa_name); |
| QNetworkInterfacePrivate *iface = 0; |
| QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin(); |
| for ( ; if_it != interfaces.end(); ++if_it) |
| if ((*if_it)->name == name) { |
| // found this interface already |
| iface = *if_it; |
| break; |
| } |
| |
| if (!iface) { |
| // it may be an interface label, search by interface index |
| int ifindex = if_nametoindex(ptr->ifa_name); |
| for (if_it = interfaces.begin(); if_it != interfaces.end(); ++if_it) |
| if ((*if_it)->index == ifindex) { |
| // found this interface already |
| iface = *if_it; |
| break; |
| } |
| } |
| |
| if (!iface) { |
| // skip all non-IP interfaces |
| continue; |
| } |
| |
| QNetworkAddressEntry entry; |
| entry.setIp(addressFromSockaddr(ptr->ifa_addr, iface->index, iface->name)); |
| if (entry.ip().isNull()) |
| // could not parse the address |
| continue; |
| |
| entry.setNetmask(addressFromSockaddr(ptr->ifa_netmask, iface->index, iface->name)); |
| if (iface->flags & QNetworkInterface::CanBroadcast) |
| entry.setBroadcast(addressFromSockaddr(ptr->ifa_broadaddr, iface->index, iface->name)); |
| getAddressExtraInfo(&entry, ptr->ifa_addr, name.latin1()); |
| |
| iface->addressEntries << entry; |
| } |
| |
| freeifaddrs(interfaceListing); |
| return interfaces; |
| } |
| #endif |
| |
| QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan() |
| { |
| return interfaceListing(); |
| } |
| |
| QT_END_NAMESPACE |
| |
| #endif // QT_NO_NETWORKINTERFACE |