Add QNetworkInterface::interface{IndexFromName,NameFromIndex}

These are for faster lookups between ID and name when one doesn't need
the full information set about the interface.

Change-Id: I7de033f80b0e4431b7f1ffff13f98d448a705c3e
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@theqtcompany.com>
Reviewed-by: Oliver Wolff <oliver.wolff@theqtcompany.com>
Reviewed-by: Kai Koehne <kai.koehne@theqtcompany.com>
This commit is contained in:
Thiago Macieira 2015-08-11 16:48:01 -07:00
parent 7db9c610f1
commit 3d52b05a63
10 changed files with 167 additions and 40 deletions

View File

@ -518,6 +518,31 @@ QList<QNetworkAddressEntry> QNetworkInterface::addressEntries() const
return d ? d->addressEntries : QList<QNetworkAddressEntry>();
}
/*!
\since 5.7
Returns the index of the interface whose name is \a name or 0 if there is
no interface with that name. This function should produce the same result
as the following code, but will probably execute faster.
\code
QNetworkInterface::interfaceFromName(name).index()
\endcode
\sa interfaceFromName(), interfaceNameFromIndex(), QUdpDatagram::interfaceIndex()
*/
int QNetworkInterface::interfaceIndexFromName(const QString &name)
{
if (name.isEmpty())
return 0;
bool ok;
uint id = name.toUInt(&ok);
if (!ok)
id = QNetworkInterfaceManager::interfaceIndexFromName(name);
return int(id);
}
/*!
Returns a QNetworkInterface object for the interface named \a
name. If no such interface exists, this function returns an
@ -552,6 +577,27 @@ QNetworkInterface QNetworkInterface::interfaceFromIndex(int index)
return result;
}
/*!
\since 5.7
Returns the name of the interface whose index is \a index or an empty
string if there is no interface with that index. This function should
produce the same result as the following code, but will probably execute
faster.
\code
QNetworkInterface::interfaceFromIndex(index).name()
\endcode
\sa interfaceFromIndex(), interfaceIndexFromName(), QUdpDatagram::interfaceIndex()
*/
QString QNetworkInterface::interfaceNameFromIndex(int index)
{
if (!index)
return QString();
return QNetworkInterfaceManager::interfaceNameFromIndex(index);
}
/*!
Returns a listing of all the network interfaces found on the host
machine. In case of failure it returns a list with zero elements.

View File

@ -113,8 +113,10 @@ public:
QString hardwareAddress() const;
QList<QNetworkAddressEntry> addressEntries() const;
static int interfaceIndexFromName(const QString &name);
static QNetworkInterface interfaceFromName(const QString &name);
static QNetworkInterface interfaceFromIndex(int index);
static QString interfaceNameFromIndex(int index);
static QList<QNetworkInterface> allInterfaces();
static QList<QHostAddress> allAddresses();

View File

@ -100,6 +100,9 @@ public:
QSharedDataPointer<QNetworkInterfacePrivate> interfaceFromIndex(int index);
QList<QSharedDataPointer<QNetworkInterfacePrivate> > allInterfaces();
static uint interfaceIndexFromName(const QString &name);
static QString interfaceNameFromIndex(uint index);
// convenience:
QSharedDataPointer<QNetworkInterfacePrivate> empty;

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2015 Intel Corporation.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@ -93,14 +94,8 @@ static QHostAddress addressFromSockaddr(sockaddr *sa, int ifindex = 0, const QSt
// 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) {
#ifndef QT_NO_IPV6IFNAME
char scopeid[IFNAMSIZ];
if (::if_indextoname(scope, scopeid)) {
address.setScopeId(QLatin1String(scopeid));
} else
#endif
address.setScopeId(QString::number(uint(scope)));
} else if (scope) {
address.setScopeId(QNetworkInterfaceManager::interfaceNameFromIndex(scope));
}
}
return address;
@ -124,6 +119,53 @@ static QNetworkInterface::InterfaceFlags convertFlags(uint rawFlags)
return flags;
}
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));
}
#ifdef QT_NO_GETIFADDRS
// getifaddrs not available

View File

@ -57,8 +57,14 @@
QT_BEGIN_NAMESPACE
typedef NETIO_STATUS (WINAPI *PtrConvertInterfaceIndexToLuid)(NET_IFINDEX, PNET_LUID);
typedef NETIO_STATUS (WINAPI *PtrConvertInterfaceLuidToName)(const NET_LUID *, PWSTR, SIZE_T);
typedef NETIO_STATUS (WINAPI *PtrConvertInterfaceLuidToIndex)(const NET_LUID *, PNET_IFINDEX);
typedef NETIO_STATUS (WINAPI *PtrConvertInterfaceNameToLuid)(const WCHAR *, PNET_LUID);
static PtrConvertInterfaceIndexToLuid ptrConvertInterfaceIndexToLuid = 0;
static PtrConvertInterfaceLuidToName ptrConvertInterfaceLuidToName = 0;
static PtrConvertInterfaceLuidToIndex ptrConvertInterfaceLuidToIndex = 0;
static PtrConvertInterfaceNameToLuid ptrConvertInterfaceNameToLuid = 0;
static void resolveLibs()
{
@ -71,10 +77,16 @@ static void resolveLibs()
#if defined(Q_OS_WINCE)
// since Windows Embedded Compact 7
ptrConvertInterfaceIndexToLuid = (PtrConvertInterfaceIndexToLuid)GetProcAddress(iphlpapiHnd, L"ConvertInterfaceIndexToLuid");
ptrConvertInterfaceLuidToName = (PtrConvertInterfaceLuidToName)GetProcAddress(iphlpapiHnd, L"ConvertInterfaceLuidToNameW");
ptrConvertInterfaceLuidToIndex = (PtrConvertInterfaceLuidToIndex)GetProcAddress(iphlpapiHnd, L"ConvertInterfaceLuidToIndex");
ptrConvertInterfaceNameToLuid = (PtrConvertInterfaceNameToLuid)GetProcAddress(iphlpapiHnd, L"ConvertInterfaceNameToLuidW");
#else
// since Windows Vista
ptrConvertInterfaceIndexToLuid = (PtrConvertInterfaceIndexToLuid)GetProcAddress(iphlpapiHnd, "ConvertInterfaceIndexToLuid");
ptrConvertInterfaceLuidToName = (PtrConvertInterfaceLuidToName)GetProcAddress(iphlpapiHnd, "ConvertInterfaceLuidToNameW");
ptrConvertInterfaceLuidToIndex = (PtrConvertInterfaceLuidToIndex)GetProcAddress(iphlpapiHnd, "ConvertInterfaceLuidToIndex");
ptrConvertInterfaceNameToLuid = (PtrConvertInterfaceNameToLuid)GetProcAddress(iphlpapiHnd, "ConvertInterfaceNameToLuidW");
#endif
done = true;
}
@ -92,13 +104,42 @@ static QHostAddress addressFromSockaddr(sockaddr *sa)
address.setAddress(((sockaddr_in6 *)sa)->sin6_addr.s6_addr);
int scope = ((sockaddr_in6 *)sa)->sin6_scope_id;
if (scope)
address.setScopeId(QString::number(scope));
address.setScopeId(QNetworkInterfaceManager::interfaceNameFromIndex(scope));
} else
qWarning("Got unknown socket family %d", sa->sa_family);
return address;
}
uint QNetworkInterfaceManager::interfaceIndexFromName(const QString &name)
{
resolveLibs();
if (!ptrConvertInterfaceNameToLuid || !ptrConvertInterfaceLuidToIndex)
return 0;
NET_IFINDEX id;
NET_LUID luid;
if (ptrConvertInterfaceNameToLuid(reinterpret_cast<const wchar_t *>(name.constData()), &luid) == NO_ERROR
&& ptrConvertInterfaceLuidToIndex(&luid, &id) == NO_ERROR)
return uint(id);
return 0;
}
QString QNetworkInterfaceManager::interfaceNameFromIndex(uint index)
{
resolveLibs();
if (ptrConvertInterfaceIndexToLuid && ptrConvertInterfaceLuidToName) {
NET_LUID luid;
if (ptrConvertInterfaceIndexToLuid(index, &luid) == NO_ERROR) {
WCHAR buf[IF_MAX_STRING_SIZE + 1];
if (ptrConvertInterfaceLuidToName(&luid, buf, sizeof(buf)/sizeof(buf[0])) == NO_ERROR)
return QString::fromWCharArray(buf);
}
}
return QString::number(index);
}
static QHash<QHostAddress, QHostAddress> ipv4Netmasks()
{
//Retrieve all the IPV4 addresses & netmasks

View File

@ -59,6 +59,20 @@ struct HostNameInfo {
QString address;
};
uint QNetworkInterfaceManager::interfaceIndexFromName(const QString &name)
{
// TBD - may not be possible
Q_UNUSED(name);
return 0;
}
QString QNetworkInterfaceManager::interfaceNameFromIndex(uint index)
{
// TBD - may not be possible
return QString::number(index);
}
static QList<QNetworkInterfacePrivate *> interfaceListing()
{
QList<QNetworkInterfacePrivate *> interfaces;

View File

@ -45,6 +45,7 @@
// We mean it.
//
#include "QtNetwork/qhostaddress.h"
#include "QtNetwork/qnetworkinterface.h"
#include "private/qabstractsocketengine_p.h"
#ifndef Q_OS_WIN
# include "qplatformdefs.h"
@ -264,7 +265,8 @@ public:
bool checkProxy(const QHostAddress &address);
bool fetchConnectionParameters();
static uint scopeIdFromString(const QString &scopeid);
static uint scopeIdFromString(const QString &scopeid)
{ return QNetworkInterface::interfaceIndexFromName(scopeid); }
/*! \internal
Sets \a address and \a port in the \a aa sockaddr structure and the size in \a sockAddrSize.

View File

@ -107,15 +107,8 @@ static inline void qt_socket_getPortAndAddress(const qt_sockaddr *s, quint16 *po
QHostAddress tmpAddress;
tmpAddress.setAddress(tmp);
*addr = tmpAddress;
if (s->a6.sin6_scope_id) {
#ifndef QT_NO_IPV6IFNAME
char scopeid[IFNAMSIZ];
if (::if_indextoname(s->a6.sin6_scope_id, scopeid)) {
addr->setScopeId(QLatin1String(scopeid));
} else
#endif
addr->setScopeId(QString::number(s->a6.sin6_scope_id));
}
if (s->a6.sin6_scope_id)
addr->setScopeId(QNetworkInterface::interfaceNameFromIndex(s->a6.sin6_scope_id));
}
if (port)
*port = ntohs(s->a6.sin6_port);
@ -131,21 +124,6 @@ static inline void qt_socket_getPortAndAddress(const qt_sockaddr *s, quint16 *po
}
}
// inline on purpose
inline uint QNativeSocketEnginePrivate::scopeIdFromString(const QString &scopeid)
{
if (scopeid.isEmpty())
return 0;
bool ok;
uint id = scopeid.toUInt(&ok);
#ifndef QT_NO_IPV6IFNAME
if (!ok)
id = ::if_nametoindex(scopeid.toLatin1());
#endif
return id;
}
static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt,
QAbstractSocket::NetworkLayerProtocol socketProtocol, int &level, int &n)
{

View File

@ -322,12 +322,6 @@ static inline int qt_socket_getMaxMsgSize(qintptr socketDescriptor)
# define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
#endif
// inline on purpose
inline uint QNativeSocketEnginePrivate::scopeIdFromString(const QString &scopeid)
{
return scopeid.toUInt();
}
bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol &socketProtocol)
{

View File

@ -203,6 +203,11 @@ void tst_QNetworkInterface::interfaceFromXXX()
QFETCH(QNetworkInterface, iface);
QVERIFY(QNetworkInterface::interfaceFromName(iface.name()).isValid());
if (int idx = iface.index()) {
QVERIFY(QNetworkInterface::interfaceFromIndex(idx).isValid());
QCOMPARE(QNetworkInterface::interfaceNameFromIndex(idx), iface.name());
QCOMPARE(QNetworkInterface::interfaceIndexFromName(iface.name()), idx);
}
foreach (QNetworkAddressEntry entry, iface.addressEntries()) {
QVERIFY(!entry.ip().isNull());