diff -r 000000000000 -r 1918ee327afb src/network/kernel/qnetworkinterface.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/network/kernel/qnetworkinterface.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,619 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnetworkinterface.h" +#include "qnetworkinterface_p.h" + +#include "qdebug.h" +#include "qendian.h" + +#ifndef QT_NO_NETWORKINTERFACE + +QT_BEGIN_NAMESPACE + +static QList postProcess(QList list) +{ + // Some platforms report a netmask but don't report a broadcast address + // Go through all available addresses and calculate the broadcast address + // from the IP and the netmask + // + // This is an IPv4-only thing -- IPv6 has no concept of broadcasts + // The math is: + // broadcast = IP | ~netmask + + QList::Iterator it = list.begin(); + const QList::Iterator end = list.end(); + for ( ; it != end; ++it) { + QList::Iterator addr_it = (*it)->addressEntries.begin(); + const QList::Iterator addr_end = (*it)->addressEntries.end(); + for ( ; addr_it != addr_end; ++addr_it) { + if (addr_it->ip().protocol() != QAbstractSocket::IPv4Protocol) + continue; + + if (!addr_it->netmask().isNull() && addr_it->broadcast().isNull()) { + QHostAddress bcast = addr_it->ip(); + bcast = QHostAddress(bcast.toIPv4Address() | ~addr_it->netmask().toIPv4Address()); + addr_it->setBroadcast(bcast); + } + } + } + + return list; +} + +Q_GLOBAL_STATIC(QNetworkInterfaceManager, manager) + +QNetworkInterfaceManager::QNetworkInterfaceManager() +{ +} + +QNetworkInterfaceManager::~QNetworkInterfaceManager() +{ +} + +QSharedDataPointer QNetworkInterfaceManager::interfaceFromName(const QString &name) +{ + QList > interfaceList = allInterfaces(); + QList >::ConstIterator it = interfaceList.constBegin(); + for ( ; it != interfaceList.constEnd(); ++it) + if ((*it)->name == name) + return *it; + + return empty; +} + +QSharedDataPointer QNetworkInterfaceManager::interfaceFromIndex(int index) +{ + QList > interfaceList = allInterfaces(); + QList >::ConstIterator it = interfaceList.constBegin(); + for ( ; it != interfaceList.constEnd(); ++it) + if ((*it)->index == index) + return *it; + + return empty; +} + +QList > QNetworkInterfaceManager::allInterfaces() +{ + QList list = postProcess(scan()); + QList > result; + + foreach (QNetworkInterfacePrivate *ptr, list) + result << QSharedDataPointer(ptr); + + return result; +} + +QString QNetworkInterfacePrivate::makeHwAddress(int len, uchar *data) +{ + QString result; + for (int i = 0; i < len; ++i) { + if (i) + result += QLatin1Char(':'); + + char buf[3]; +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && defined(_MSC_VER) && _MSC_VER >= 1400 + sprintf_s(buf, 3, "%02hX", ushort(data[i])); +#else + sprintf(buf, "%02hX", ushort(data[i])); +#endif + result += QLatin1String(buf); + } + return result; +} + +/*! + \class QNetworkAddressEntry + \brief The QNetworkAddressEntry class stores one IP address + supported by a network interface, along with its associated + netmask and broadcast address. + + \since 4.2 + \reentrant + \ingroup network + + Each network interface can contain zero or more IP addresses, which + in turn can be associated with a netmask and/or a broadcast + address (depending on support from the operating system). + + This class represents one such group. +*/ + +/*! + Constructs an empty QNetworkAddressEntry object. +*/ +QNetworkAddressEntry::QNetworkAddressEntry() + : d(new QNetworkAddressEntryPrivate) +{ +} + +/*! + Constructs a QNetworkAddressEntry object that is a copy of the + object \a other. +*/ +QNetworkAddressEntry::QNetworkAddressEntry(const QNetworkAddressEntry &other) + : d(new QNetworkAddressEntryPrivate(*other.d.data())) +{ +} + +/*! + Makes a copy of the QNetworkAddressEntry object \a other. +*/ +QNetworkAddressEntry &QNetworkAddressEntry::operator=(const QNetworkAddressEntry &other) +{ + *d.data() = *other.d.data(); + return *this; +} + +/*! + Destroys this QNetworkAddressEntry object. +*/ +QNetworkAddressEntry::~QNetworkAddressEntry() +{ +} + +/*! + Returns true if this network address entry is the same as \a + other. +*/ +bool QNetworkAddressEntry::operator==(const QNetworkAddressEntry &other) const +{ + if (d == other.d) return true; + if (!d || !other.d) return false; + return d->address == other.d->address && + d->netmask == other.d->netmask && + d->broadcast == other.d->broadcast; +} + +/*! + \fn bool QNetworkAddressEntry::operator!=(const QNetworkAddressEntry &other) const + + Returns true if this network address entry is different from \a + other. +*/ + +/*! + This function returns one IPv4 or IPv6 address found, that was + found in a network interface. +*/ +QHostAddress QNetworkAddressEntry::ip() const +{ + return d->address; +} + +/*! + Sets the IP address the QNetworkAddressEntry object contains to \a + newIp. +*/ +void QNetworkAddressEntry::setIp(const QHostAddress &newIp) +{ + d->address = newIp; +} + +/*! + Returns the netmask associated with the IP address. The + netmask is expressed in the form of an IP address, such as + 255.255.0.0. + + For IPv6 addresses, the prefix length is converted to an address + where the number of bits set to 1 is equal to the prefix + length. For a prefix length of 64 bits (the most common value), + the netmask will be expressed as a QHostAddress holding the + address FFFF:FFFF:FFFF:FFFF:: + + \sa prefixLength() +*/ +QHostAddress QNetworkAddressEntry::netmask() const +{ + return d->netmask; +} + +/*! + Sets the netmask that this QNetworkAddressEntry object contains to + \a newNetmask. Setting the netmask also sets the prefix length to + match the new netmask. + + \sa setPrefixLength() +*/ +void QNetworkAddressEntry::setNetmask(const QHostAddress &newNetmask) +{ + if (newNetmask.protocol() != ip().protocol()) { + d->netmask = QNetmaskAddress(); + return; + } + + d->netmask.setAddress(newNetmask); +} + +/*! + \since 4.5 + Returns the prefix length of this IP address. The prefix length + matches the number of bits set to 1 in the netmask (see + netmask()). For IPv4 addresses, the value is between 0 and 32. For + IPv6 addresses, it's contained between 0 and 128 and is the + preferred form of representing addresses. + + This function returns -1 if the prefix length could not be + determined (i.e., netmask() returns a null QHostAddress()). + + \sa netmask() +*/ +int QNetworkAddressEntry::prefixLength() const +{ + return d->netmask.prefixLength(); +} + +/*! + \since 4.5 + Sets the prefix length of this IP address to \a length. The value + of \a length must be valid for this type of IP address: between 0 + and 32 for IPv4 addresses, between 0 and 128 for IPv6 + addresses. Setting to any invalid value is equivalent to setting + to -1, which means "no prefix length". + + Setting the prefix length also sets the netmask (see netmask()). + + \sa setNetmask() +*/ +void QNetworkAddressEntry::setPrefixLength(int length) +{ + d->netmask.setPrefixLength(d->address.protocol(), length); +} + +/*! + Returns the broadcast address associated with the IPv4 + address and netmask. It can usually be derived from those two by + setting to 1 the bits of the IP address where the netmask contains + a 0. (In other words, by bitwise-OR'ing the IP address with the + inverse of the netmask) + + This member is always empty for IPv6 addresses, since the concept + of broadcast has been abandoned in that system in favor of + multicast. In particular, the group of hosts corresponding to all + the nodes in the local network can be reached by the "all-nodes" + special multicast group (address FF02::1). +*/ +QHostAddress QNetworkAddressEntry::broadcast() const +{ + return d->broadcast; +} + +/*! + Sets the broadcast IP address of this QNetworkAddressEntry object + to \a newBroadcast. +*/ +void QNetworkAddressEntry::setBroadcast(const QHostAddress &newBroadcast) +{ + d->broadcast = newBroadcast; +} + +/*! + \class QNetworkInterface + \brief The QNetworkInterface class provides a listing of the host's IP + addresses and network interfaces. + + \since 4.2 + \reentrant + \ingroup network + + QNetworkInterface represents one network interface attached to the + host where the program is being run. Each network interface may + contain zero or more IP addresses, each of which is optionally + associated with a netmask and/or a broadcast address. The list of + such trios can be obtained with addressEntries(). Alternatively, + when the netmask or the broadcast addresses aren't necessary, use + the allAddresses() convenience function to obtain just the IP + addresses. + + QNetworkInterface also reports the interface's hardware address with + hardwareAddress(). + + Not all operating systems support reporting all features. Only the + IPv4 addresses are guaranteed to be listed by this class in all + platforms. In particular, IPv6 address listing is only supported + on Windows XP and more recent versions, Linux, MacOS X and the + BSDs. + + \sa QNetworkAddressEntry +*/ + +/*! + \enum QNetworkInterface::InterfaceFlag + Specifies the flags associated with this network interface. The + possible values are: + + \value IsUp the network interface is active + \value IsRunning the network interface has resources + allocated + \value CanBroadcast the network interface works in + broadcast mode + \value IsLoopBack the network interface is a loopback + interface: that is, it's a virtual + interface whose destination is the + host computer itself + \value IsPointToPoint the network interface is a + point-to-point interface: that is, + there is one, single other address + that can be directly reached by it. + \value CanMulticast the network interface supports + multicasting + + Note that one network interface cannot be both broadcast-based and + point-to-point. +*/ + +/*! + Constructs an empty network interface object. +*/ +QNetworkInterface::QNetworkInterface() + : d(0) +{ +} + +/*! + Frees the resources associated with the QNetworkInterface object. +*/ +QNetworkInterface::~QNetworkInterface() +{ +} + +/*! + Creates a copy of the QNetworkInterface object contained in \a + other. +*/ +QNetworkInterface::QNetworkInterface(const QNetworkInterface &other) + : d(other.d) +{ +} + +/*! + Copies the contents of the QNetworkInterface object contained in \a + other into this one. +*/ +QNetworkInterface &QNetworkInterface::operator=(const QNetworkInterface &other) +{ + d = other.d; + return *this; +} + +/*! + Returns true if this QNetworkInterface object contains valid + information about a network interface. +*/ +bool QNetworkInterface::isValid() const +{ + return !name().isEmpty(); +} + +/*! + \since 4.5 + Returns the interface system index, if known. This is an integer + assigned by the operating system to identify this interface and it + generally doesn't change. It matches the scope ID field in IPv6 + addresses. + + If the index isn't known, this function returns 0. +*/ +int QNetworkInterface::index() const +{ + return d ? d->index : 0; +} + +/*! + Returns the name of this network interface. On Unix systems, this + is a string containing the type of the interface and optionally a + sequence number, such as "eth0", "lo" or "pcn0". On Windows, it's + an internal ID that cannot be changed by the user. +*/ +QString QNetworkInterface::name() const +{ + return d ? d->name : QString(); +} + +/*! + \since 4.5 + + Returns the human-readable name of this network interface on + Windows, such as "Local Area Connection", if the name could be + determined. If it couldn't, this function returns the same as + name(). The human-readable name is a name that the user can modify + in the Windows Control Panel, so it may change during the + execution of the program. + + On Unix, this function currently always returns the same as + name(), since Unix systems don't store a configuration for + human-readable names. +*/ +QString QNetworkInterface::humanReadableName() const +{ + return d ? !d->friendlyName.isEmpty() ? d->friendlyName : name() : QString(); +} + +/*! + Returns the flags associated with this network interface. +*/ +QNetworkInterface::InterfaceFlags QNetworkInterface::flags() const +{ + return d ? d->flags : InterfaceFlags(0); +} + +/*! + Returns the low-level hardware address for this interface. On + Ethernet interfaces, this will be a MAC address in string + representation, separated by colons. + + Other interface types may have other types of hardware + addresses. Implementations should not depend on this function + returning a valid MAC address. +*/ +QString QNetworkInterface::hardwareAddress() const +{ + return d ? d->hardwareAddress : QString(); +} + +/*! + Returns the list of IP addresses that this interface possesses + along with their associated netmasks and broadcast addresses. + + If the netmask or broadcast address information is not necessary, + you can call the allAddresses() function to obtain just the IP + addresses. +*/ +QList QNetworkInterface::addressEntries() const +{ + return d ? d->addressEntries : QList(); +} + +/*! + Returns a QNetworkInterface object for the interface named \a + name. If no such interface exists, this function returns an + invalid QNetworkInterface object. + + \sa name(), isValid() +*/ +QNetworkInterface QNetworkInterface::interfaceFromName(const QString &name) +{ + QNetworkInterface result; + result.d = manager()->interfaceFromName(name); + return result; +} + +/*! + Returns a QNetworkInterface object for the interface whose internal + ID is \a index. Network interfaces have a unique identifier called + the "interface index" to distinguish it from other interfaces on + the system. Often, this value is assigned progressively and + interfaces being removed and then added again get a different + value every time. + + This index is also found in the IPv6 address' scope ID field. +*/ +QNetworkInterface QNetworkInterface::interfaceFromIndex(int index) +{ + QNetworkInterface result; + result.d = manager()->interfaceFromIndex(index); + return result; +} + +/*! + Returns a listing of all the network interfaces found on the host + machine. +*/ +QList QNetworkInterface::allInterfaces() +{ + QList > privs = manager()->allInterfaces(); + QList result; + foreach (QSharedDataPointer p, privs) { + QNetworkInterface item; + item.d = p; + result << item; + } + + return result; +} + +/*! + This convenience function returns all IP addresses found on the + host machine. It is equivalent to calling addressEntries() on all the + objects returned by allInterfaces() to obtain lists of QHostAddress + objects then calling QHostAddress::ip() on each of these. +*/ +QList QNetworkInterface::allAddresses() +{ + QList > privs = manager()->allInterfaces(); + QList result; + foreach (const QSharedDataPointer p, privs) { + foreach (const QNetworkAddressEntry &entry, p->addressEntries) + result += entry.ip(); + } + + return result; +} + +#ifndef QT_NO_DEBUG_STREAM +static inline QDebug flagsDebug(QDebug debug, QNetworkInterface::InterfaceFlags flags) +{ + if (flags & QNetworkInterface::IsUp) + debug.nospace() << "IsUp "; + if (flags & QNetworkInterface::IsRunning) + debug.nospace() << "IsRunning "; + if (flags & QNetworkInterface::CanBroadcast) + debug.nospace() << "CanBroadcast "; + if (flags & QNetworkInterface::IsLoopBack) + debug.nospace() << "IsLoopBack "; + if (flags & QNetworkInterface::IsPointToPoint) + debug.nospace() << "IsPointToPoint "; + if (flags & QNetworkInterface::CanMulticast) + debug.nospace() << "CanMulticast "; + return debug.nospace(); +} + +static inline QDebug operator<<(QDebug debug, const QNetworkAddressEntry &entry) +{ + debug.nospace() << "(address = " << entry.ip(); + if (!entry.netmask().isNull()) + debug.nospace() << ", netmask = " << entry.netmask(); + if (!entry.broadcast().isNull()) + debug.nospace() << ", broadcast = " << entry.broadcast(); + debug.nospace() << ')'; + return debug.space(); +} + +QDebug operator<<(QDebug debug, const QNetworkInterface &networkInterface) +{ + debug.nospace() << "QNetworkInterface(name = " << networkInterface.name() + << ", hardware address = " << networkInterface.hardwareAddress() + << ", flags = "; + flagsDebug(debug, networkInterface.flags()); +#if defined(Q_CC_RVCT) + // RVCT gets confused with << networkInterface.addressEntries(), reason unknown. + debug.nospace() << ")\n"; +#else + debug.nospace() << ", entries = " << networkInterface.addressEntries() + << ")\n"; +#endif + return debug.space(); +} +#endif + +QT_END_NAMESPACE + +#endif // QT_NO_NETWORKINTERFACE