QNetworkInterface: Add type()

[ChangeLog][QtNetwork][QNetworkInterface] Added type().

Change-Id: I7de033f80b0e4431b7f1ffff13f9a5592b5776e1
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Thiago Macieira 2015-08-12 00:09:18 -07:00
parent 4d31fc919b
commit 5193ab97f4
7 changed files with 266 additions and 4 deletions

View File

@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Intel Corporation.
** Copyright (C) 2017 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@ -390,6 +390,57 @@ void QNetworkAddressEntry::setBroadcast(const QHostAddress &newBroadcast)
point-to-point.
*/
/*!
\enum QNetworkInterface::InterfaceType
Specifies the type of hardware (PHY layer, OSI level 1) this interface is,
if it could be determined. Interface types that are not among those listed
below will generally be listed as Unknown, though future versions of Qt may
add new enumeration values.
The possible values are:
\value Unknown The interface type could not be determined or is not
one of the other listed types.
\value Loopback The virtual loopback interface, which is assigned
the loopback IP addresses (127.0.0.1, ::1).
\value Virtual A type of interface determined to be virtual, but
not any of the other possible types. For example,
tunnel interfaces are (currently) detected as
virtual ones.
\value Ethernet IEEE 802.3 Ethernet interfaces, though on many
systems other types of IEEE 802 interfaces may also
be detected as Ethernet (especially Wi-Fi).
\value WiFi IEEE 802.11 Wi-Fi interfaces. Note that on some
systems, QNetworkInterface may be unable to
distinguish regular Ethernet from Wi-Fi and will
not return this enum value.
\value Ieee80211 An alias for WiFi.
\value CanBus ISO 11898 Controller Area Network bus interfaces,
usually found on automotive systems.
\value Fddi ANSI X3T12 Fiber Distributed Data Interface, a local area
network over optical fibers.
\value Ppp Point-to-Point Protocol interfaces, establishing a
direct connection between two nodes over a lower
transport layer (often serial over radio or physical
line).
\value Slip Serial Line Internet Protocol interfaces.
\value Phonet Interfaces using the Linux Phonet socket family, for
communication with cellular modems. See the
\l {https://www.kernel.org/doc/Documentation/networking/phonet.txt}{Linux kernel documentation}
for more information.
\value Ieee802154 IEEE 802.15.4 Personal Area Network interfaces, other
than 6LoWPAN (see below).
\value SixLoWPAN 6LoWPAN (IPv6 over Low-power Wireless Personal Area
Networks) interfaces, which operate on IEEE 802.15.4
PHY, but have specific header compression schemes
for IPv6 and UDP. This type of interface is often
used for mesh networking.
\value Ieee80216 IEEE 802.16 Wireless Metropolitan Area Network, also
known under the commercial name "WiMAX".
\value Ieee1394 IEEE 1394 interfaces (a.k.a. "FireWire").
*/
/*!
Constructs an empty network interface object.
*/
@ -493,6 +544,19 @@ QNetworkInterface::InterfaceFlags QNetworkInterface::flags() const
return d ? d->flags : InterfaceFlags(0);
}
/*!
\since 5.11
Returns the type of this interface, if it could be determined. If it could
not be determined, this function returns QNetworkInterface::Unknown.
\sa hardwareAddress()
*/
QNetworkInterface::InterfaceType QNetworkInterface::type() const
{
return d ? d->type : Unknown;
}
/*!
Returns the low-level hardware address for this interface. On
Ethernet interfaces, this will be a MAC address in string
@ -501,6 +565,8 @@ QNetworkInterface::InterfaceFlags QNetworkInterface::flags() const
Other interface types may have other types of hardware
addresses. Implementations should not depend on this function
returning a valid MAC address.
\sa type()
*/
QString QNetworkInterface::hardwareAddress() const
{
@ -686,4 +752,6 @@ QDebug operator<<(QDebug debug, const QNetworkInterface &networkInterface)
QT_END_NAMESPACE
#include "moc_qnetworkinterface.cpp"
#endif // QT_NO_NETWORKINTERFACE

View File

@ -90,6 +90,7 @@ Q_DECLARE_SHARED(QNetworkAddressEntry)
class QNetworkInterfacePrivate;
class Q_NETWORK_EXPORT QNetworkInterface
{
Q_GADGET
public:
enum InterfaceFlag {
IsUp = 0x1,
@ -100,6 +101,27 @@ public:
CanMulticast = 0x20
};
Q_DECLARE_FLAGS(InterfaceFlags, InterfaceFlag)
Q_FLAG(InterfaceFlags)
enum InterfaceType {
Loopback = 1,
Virtual,
Ethernet,
Slip,
CanBus,
Ppp,
Fddi,
Wifi,
Ieee80211 = Wifi, // alias
Phonet,
Ieee802154,
SixLoWPAN, // 6LoWPAN, but we can't start with a digit
Ieee80216,
Ieee1394,
Unknown = 0
};
Q_ENUM(InterfaceType)
QNetworkInterface();
QNetworkInterface(const QNetworkInterface &other);
@ -117,6 +139,7 @@ public:
QString name() const;
QString humanReadableName() const;
InterfaceFlags flags() const;
InterfaceType type() const;
QString hardwareAddress() const;
QList<QNetworkAddressEntry> addressEntries() const;

View File

@ -48,16 +48,76 @@
// accordding to rtnetlink(7)
#include <asm/types.h>
#include <linux/if.h>
#include <linux/if_arp.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/wireless.h>
#include <sys/socket.h>
/* in case these aren't defined in linux/if_arp.h (added since 2.6.28) */
#define ARPHRD_PHONET 820 /* v2.6.29: PhoNet media type */
#define ARPHRD_PHONET_PIPE 821 /* v2.6.29: PhoNet pipe header */
#define ARPHRD_IEEE802154 804 /* v2.6.31 */
#define ARPHRD_6LOWPAN 825 /* v3.14: IPv6 over LoWPAN */
QT_BEGIN_NAMESPACE
enum {
BufferSize = 8192
};
static QNetworkInterface::InterfaceType probeIfType(int socket, struct ifreq *req, short arptype)
{
switch (ushort(arptype)) {
case ARPHRD_LOOPBACK:
return QNetworkInterface::Loopback;
case ARPHRD_ETHER:
// check if it's a WiFi interface
if (qt_safe_ioctl(socket, SIOCGIWMODE, req) >= 0)
return QNetworkInterface::Wifi;
return QNetworkInterface::Ethernet;
case ARPHRD_SLIP:
case ARPHRD_CSLIP:
case ARPHRD_SLIP6:
case ARPHRD_CSLIP6:
return QNetworkInterface::Slip;
case ARPHRD_CAN:
return QNetworkInterface::CanBus;
case ARPHRD_PPP:
return QNetworkInterface::Ppp;
case ARPHRD_FDDI:
return QNetworkInterface::Fddi;
case ARPHRD_IEEE80211:
case ARPHRD_IEEE80211_PRISM:
case ARPHRD_IEEE80211_RADIOTAP:
return QNetworkInterface::Ieee80211;
case ARPHRD_IEEE802154:
return QNetworkInterface::Ieee802154;
case ARPHRD_PHONET:
case ARPHRD_PHONET_PIPE:
return QNetworkInterface::Phonet;
case ARPHRD_6LOWPAN:
return QNetworkInterface::SixLoWPAN;
case ARPHRD_TUNNEL:
case ARPHRD_TUNNEL6:
case ARPHRD_NONE:
case ARPHRD_VOID:
return QNetworkInterface::Virtual;
}
return QNetworkInterface::Unknown;
}
namespace {
struct NetlinkSocket
{
@ -195,6 +255,7 @@ QString QNetworkInterfaceManager::interfaceNameFromIndex(uint index)
static QList<QNetworkInterfacePrivate *> getInterfaces(int sock, char *buf)
{
QList<QNetworkInterfacePrivate *> result;
struct ifreq req;
// request all links
struct {
@ -227,6 +288,8 @@ static QList<QNetworkInterfacePrivate *> getInterfaces(int sock, char *buf)
break;
case IFLA_IFNAME: // interface name
Q_ASSERT(payloadLen <= int(sizeof(req.ifr_name)));
memcpy(req.ifr_name, payloadPtr, payloadLen); // including terminating NUL
iface->name = QString::fromLatin1(payloadPtr, payloadLen - 1);
break;
@ -245,6 +308,7 @@ static QList<QNetworkInterfacePrivate *> getInterfaces(int sock, char *buf)
qWarning("QNetworkInterface: found interface %d with no name", iface->index);
delete iface;
} else {
iface->type = probeIfType(sock, &req, ifi->ifi_type);
result.append(iface);
}
});

View File

@ -52,6 +52,7 @@
//
#include <QtNetwork/private/qtnetworkglobal_p.h>
#include <QtNetwork/qnetworkinterface.h>
#include <QtCore/qatomic.h>
#include <QtCore/qlist.h>
#include <QtCore/qreadwritelock.h>
@ -82,6 +83,7 @@ public:
int index; // interface index, if know
QNetworkInterface::InterfaceFlags flags;
QNetworkInterface::InterfaceType type = QNetworkInterface::Unknown;
QString name;
QString friendlyName;

View File

@ -384,11 +384,70 @@ static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
# elif defined(Q_OS_BSD4)
QT_BEGIN_INCLUDE_NAMESPACE
# include <net/if_dl.h>
# include <net/if_media.h>
# include <net/if_types.h>
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;
case IFM_FDDI:
return QNetworkInterface::Fddi;
case IFM_IEEE80211:
return QNetworkInterface::Ieee80211;
}
}
return QNetworkInterface::Unknown;
}
static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
{
QList<QNetworkInterfacePrivate *> interfaces;
struct ifmediareq mediareq;
int socket = -1;
// on NetBSD we use AF_LINK and sockaddr_dl
// scan the list for that family
@ -402,8 +461,13 @@ static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
iface->name = QString::fromLatin1(ptr->ifa_name);
iface->flags = convertFlags(ptr->ifa_flags);
iface->hardwareAddress = iface->makeHwAddress(sdl->sdl_alen, (uchar*)LLADDR(sdl));
strlcpy(mediareq.ifm_name, ptr->ifa_name, sizeof(mediareq.ifm_name));
iface->type = probeIfType(openSocket(socket), sdl->sdl_type, &mediareq);
}
if (socket != -1)
qt_safe_close(socket);
return interfaces;
}

View File

@ -62,6 +62,10 @@
#include <qt_windows.h>
// In case these aren't defined
#define IF_TYPE_IEEE80216_WMAN 237
#define IF_TYPE_IEEE802154 259
QT_BEGIN_NAMESPACE
static QHostAddress addressFromSockaddr(sockaddr *sa)
@ -155,6 +159,45 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
if (ptr->IfType == IF_TYPE_PPP)
iface->flags |= QNetworkInterface::IsPointToPoint;
switch (ptr->IfType) {
case IF_TYPE_ETHERNET_CSMACD:
iface->type = QNetworkInterface::Ethernet;
break;
case IF_TYPE_FDDI:
iface->type = QNetworkInterface::Fddi;
break;
case IF_TYPE_PPP:
iface->type = QNetworkInterface::Ppp;
break;
case IF_TYPE_SLIP:
iface->type = QNetworkInterface::Slip;
break;
case IF_TYPE_SOFTWARE_LOOPBACK:
iface->type = QNetworkInterface::Loopback;
iface->flags |= QNetworkInterface::IsLoopBack;
break;
case IF_TYPE_IEEE80211:
iface->type = QNetworkInterface::Ieee80211;
break;
case IF_TYPE_IEEE1394:
iface->type = QNetworkInterface::Ieee1394;
break;
case IF_TYPE_IEEE80216_WMAN:
iface->type = QNetworkInterface::Ieee80216;
break;
case IF_TYPE_IEEE802154:
iface->type = QNetworkInterface::Ieee802154;
break;
}
// use ConvertInterfaceLuidToNameW because that returns a friendlier name, though not
// as "friendly" as FriendlyName below
WCHAR buf[IF_MAX_STRING_SIZE + 1];
@ -167,9 +210,6 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
if (ptr->PhysicalAddressLength)
iface->hardwareAddress = iface->makeHwAddress(ptr->PhysicalAddressLength,
ptr->PhysicalAddress);
else
// loopback if it has no address
iface->flags |= QNetworkInterface::IsLoopBack;
// parse the IP (unicast) addresses
for (PIP_ADAPTER_UNICAST_ADDRESS addr = ptr->FirstUnicastAddress; addr; addr = addr->Next) {

View File

@ -138,6 +138,7 @@ void tst_QNetworkInterface::dump()
qDebug() << " index: " << i.index();
qDebug() << " flags: " << qPrintable(flags);
qDebug() << " type: " << i.type();
qDebug() << " hw address:" << qPrintable(i.hardwareAddress());
int count = 0;