OSDN Git Service

implement QNetworkInterface via getifaddrs() and one ioctl() for the MAC only
authorIvailo Monev <xakepa10@gmail.com>
Mon, 7 Mar 2022 14:14:00 +0000 (16:14 +0200)
committerIvailo Monev <xakepa10@gmail.com>
Mon, 7 Mar 2022 14:14:00 +0000 (16:14 +0200)
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
src/network/kernel/qnetworkinterface.cpp
src/network/kernel/qnetworkinterface_p.h
src/network/kernel/qnetworkinterface_unix.cpp

index edc3122..849ec37 100644 (file)
@@ -103,16 +103,6 @@ QList<QSharedDataPointer<QNetworkInterfacePrivate> > QNetworkInterfaceManager::a
     return result;
 }
 
-QString QNetworkInterfacePrivate::makeHwAddress(uchar *data)
-{
-    QSTACKARRAY(char, snprintfbuf, 18);
-    ::snprintf(snprintfbuf, sizeof(snprintfbuf),
-        "%02hX:%02hX:%02hX:%02hX:%02hX:%02hX",
-        ushort(data[0]), ushort(data[1]), ushort(data[2]), ushort(data[3]), ushort(data[4]), ushort(data[5])
-    );
-    return QString::fromLatin1(snprintfbuf, sizeof(snprintfbuf) - 1);
-}
-
 /*!
     \class QNetworkAddressEntry
     \brief The QNetworkAddressEntry class stores one IP address
index 335e7d6..05db9b3 100644 (file)
@@ -69,8 +69,6 @@ public:
 
     QList<QNetworkAddressEntry> addressEntries;
 
-    static QString makeHwAddress(uchar *data);
-
 private:
     Q_DISABLE_COPY(QNetworkInterfacePrivate);
 };
index 5294b3a..e715bcc 100644 (file)
 #endif
 #include <sys/ioctl.h>
 
-#ifndef SIOCGIFBRDADDR
-#  define SIOCGIFBRDADDR 0x8919
-#endif
-
 QT_BEGIN_NAMESPACE
 
+static QString makeHwAddress(const uchar *data)
+{
+    QSTACKARRAY(char, snprintfbuf, 18);
+    ::snprintf(snprintfbuf, sizeof(snprintfbuf),
+        "%02hX:%02hX:%02hX:%02hX:%02hX:%02hX",
+        ushort(data[0]), ushort(data[1]), ushort(data[2]), ushort(data[3]), ushort(data[4]), ushort(data[5])
+    );
+    return QString::fromLatin1(snprintfbuf, sizeof(snprintfbuf) - 1);
+}
+
+
 static QHostAddress addressFromSockaddr(sockaddr *sa)
 {
     QHostAddress address;
@@ -89,264 +96,68 @@ static QNetworkInterface::InterfaceFlags convertFlags(uint rawFlags)
     return flags;
 }
 
-#ifdef QT_HAVE_GETIFADDRS
-
-static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
-{
-    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 QList<QNetworkInterfacePrivate *> interfaceListing()
+QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan()
 {
     QList<QNetworkInterfacePrivate *> interfaces;
 
-    int socket = qt_safe_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
-    if (socket == -1)
-        return interfaces;      // error
-
-    ifaddrs *interfaceListing;
-    if (::getifaddrs(&interfaceListing) == -1) {
-        // error
-        qt_safe_close(socket);
+#ifdef QT_HAVE_GETIFADDRS
+    struct ifaddrs *iflist = nullptr;
+    if (::getifaddrs(&iflist) != 0) {
         return interfaces;
     }
 
-    interfaces = createInterfaces(interfaceListing);
-    for (ifaddrs *ptr = interfaceListing; ptr; ptr = ptr->ifa_next) {
-        // Get the interface index
-        int ifindex = ::if_nametoindex(ptr->ifa_name);
-        QNetworkInterfacePrivate *iface = 0;
-        QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
-        for ( ; if_it != interfaces.end(); ++if_it)
-            if ((*if_it)->index == ifindex) {
-                // found this interface already
-                iface = *if_it;
+    int socket = qt_safe_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+    struct ifaddrs *ifiter = nullptr;
+    for (ifiter = iflist; ifiter; ifiter = ifiter->ifa_next) {
+        QNetworkInterfacePrivate *iface = nullptr;
+        const uint ifindex = ::if_nametoindex(ifiter->ifa_name);
+        foreach (QNetworkInterfacePrivate *ifaceit, interfaces) {
+            if (ifaceit->index == ifindex) {
+                iface = ifaceit;
                 break;
             }
+        }
+
         if (!iface) {
-            // skip all non-IP interfaces
-            continue;
+            iface = new QNetworkInterfacePrivate;
+            iface->index = ifindex;
+            iface->name = QString::fromLatin1(ifiter->ifa_name);
+            iface->flags = convertFlags(ifiter->ifa_flags);
+            interfaces.append(iface);
         }
 
         QNetworkAddressEntry entry;
-        entry.setIp(addressFromSockaddr(ptr->ifa_addr));
+        entry.setIp(addressFromSockaddr(ifiter->ifa_addr));
         if (entry.ip().isNull())
             // could not parse the address
             continue;
 
-        entry.setNetmask(addressFromSockaddr(ptr->ifa_netmask));
+        entry.setNetmask(addressFromSockaddr(ifiter->ifa_netmask));
         if (iface->flags & QNetworkInterface::CanBroadcast)
-            entry.setBroadcast(addressFromSockaddr(ptr->ifa_broadaddr));
+            entry.setBroadcast(addressFromSockaddr(ifiter->ifa_broadaddr));
 
         iface->addressEntries << entry;
 
 #ifdef SIOCGIFHWADDR // not defined on FreeBSD
-        struct ifreq req;
-        ::memset(&req, 0, sizeof(ifreq));
-        ::memcpy(req.ifr_name, ptr->ifa_name, sizeof(req.ifr_name) - 1);
-        // Get the HW address
-        if (::ioctl(socket, SIOCGIFHWADDR, &req) >= 0) {
-            uchar *addr = (uchar *)req.ifr_addr.sa_data;
-            iface->hardwareAddress = iface->makeHwAddress(addr);
-        }
-#endif // SIOCGIFHWADDR
-    }
-
-    ::freeifaddrs(interfaceListing);
-    qt_safe_close(socket);
-    return interfaces;
-}
-
-#else // QT_HAVE_GETIFADDRS
-
-static const int STORAGEBUFFER_GROWTH = 256;
-
-static QSet<QByteArray> interfaceNames(int socket)
-{
-    QSet<QByteArray> result;
-#ifdef QT_NO_IPV6IFNAME
-    QByteArray storageBuffer;
-    struct ifconf interfaceList;
-
-    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 (::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;
+        if (socket != -1) {
+            struct ifreq req;
+            ::memset(&req, 0, sizeof(ifreq));
+            ::memcpy(req.ifr_name, ifiter->ifa_name, sizeof(req.ifr_name) - 1);
+            // Get the HW address
+            if (::ioctl(socket, SIOCGIFHWADDR, &req) >= 0) {
+                iface->hardwareAddress = makeHwAddress((uchar *)req.ifr_addr.sa_data);
             }
-        } 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)
-{
-    int ifindex = 0;
-
-#ifndef QT_NO_IPV6IFNAME
-    // Get the interface index
-    ifindex = ::if_nametoindex(req.ifr_name);
-
-    // find the interface data
-    foreach (QNetworkInterfacePrivate *it, interfaces) {
-        if (it->index == ifindex) {
-            // existing interface
-            return it;
         }
-    }
-#else
-    // Search by name
-    foreach (QNetworkInterfacePrivate *it, interfaces) {
-        if (it->name == QString::fromLatin1(req.ifr_name)) {
-            // existing interface
-            return it;
-        }
-    }
-#endif
-
-    // new interface, create data:
-    QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate;
-    iface->index = ifindex;
-    interfaces << iface;
-
-#ifdef SIOCGIFNAME // not defined on Solaris
-    // Get the canonical name
-    QByteArray oldName = req.ifr_name;
-    if (::ioctl(socket, SIOCGIFNAME, &req) >= 0) {
-        iface->name = QString::fromLatin1(req.ifr_name);
-
-        // reset the name:
-        ::memcpy(req.ifr_name, oldName.constData(), qMin<int>(oldName.length() + 1, sizeof(req.ifr_name) - 1));
-    } else
-#endif // SIOCGIFNAME
-    {
-        // use this name anyways
-        iface->name = QString::fromLatin1(req.ifr_name);
-    }
-
-    // Get interface flags
-    if (::ioctl(socket, SIOCGIFFLAGS, &req) >= 0) {
-        iface->flags = convertFlags(req.ifr_flags);
-    }
-
-#ifdef SIOCGIFHWADDR // not defined on FreeBSD
-    // Get the HW address
-    if (::ioctl(socket, SIOCGIFHWADDR, &req) >= 0) {
-        uchar *addr = (uchar *)req.ifr_addr.sa_data;
-        iface->hardwareAddress = iface->makeHwAddress(addr);
-    }
 #endif // SIOCGIFHWADDR
-
-    return iface;
-}
-
-static QList<QNetworkInterfacePrivate *> interfaceListing()
-{
-    QList<QNetworkInterfacePrivate *> interfaces;
-
-    int socket = qt_safe_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
-    if (socket == -1)
-        return interfaces;      // error
-
-    foreach (const QByteArray &it, interfaceNames(socket)) {
-        struct ifreq req;
-        ::memset(&req, 0, sizeof(ifreq));
-        ::memcpy(req.ifr_name, it.constData(), qMin<int>(it.length() + 1, sizeof(req.ifr_name) - 1));
-
-        QNetworkInterfacePrivate *iface = findInterface(socket, interfaces, req);
-
-        // Get the interface broadcast address
-        QNetworkAddressEntry entry;
-        if (iface->flags & QNetworkInterface::CanBroadcast) {
-            if (::ioctl(socket, SIOCGIFBRDADDR, &req) >= 0) {
-                sockaddr *sa = &req.ifr_addr;
-                if (sa->sa_family == AF_INET)
-                    entry.setBroadcast(addressFromSockaddr(sa));
-            }
-        }
-
-        // Get the address of the interface
-        if (::ioctl(socket, SIOCGIFADDR, &req) >= 0) {
-            sockaddr *sa = &req.ifr_addr;
-            entry.setIp(addressFromSockaddr(sa));
-        }
-
-        // Get the interface netmask
-        if (::ioctl(socket, SIOCGIFNETMASK, &req) >= 0) {
-            sockaddr *sa = &req.ifr_addr;
-            entry.setNetmask(addressFromSockaddr(sa));
-        }
-
-        iface->addressEntries << entry;
     }
 
-    qt_safe_close(socket);
-    return interfaces;
-}
-
+    if (socket != -1) {
+        qt_safe_close(socket);
+    }
+    ::freeifaddrs(iflist);
 #endif // QT_HAVE_GETIFADDRS
 
-QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan()
-{
-    return interfaceListing();
+    return interfaces;
 }
 
 QT_END_NAMESPACE