QNetworkInterface/Windows: solve 11 year old puzzle about Win32 API
When I introduced QNetworkInterface in Qt 4.2, I didn't understand the relationship between the prefix list and the unicast address list in the IP_ADAPTERS_ADDRESSES structure. Turns out, there isn't a (direct) one and the actual solution didn't come along until Windows Vista, adding the prefix length to each address. Change-Id: I6a556cca551116d77c7edf43f9c651dacb75348f Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> Reviewed-by: Kai Koehne <kai.koehne@qt.io> Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
This commit is contained in:
parent
59e0b6d40c
commit
758982bd74
@ -103,45 +103,6 @@ QString QNetworkInterfaceManager::interfaceNameFromIndex(uint index)
|
|||||||
return QString::number(index);
|
return QString::number(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
static QHash<QHostAddress, QHostAddress> ipv4Netmasks()
|
|
||||||
{
|
|
||||||
//Retrieve all the IPV4 addresses & netmasks
|
|
||||||
IP_ADAPTER_INFO staticBuf[2]; // 2 is arbitrary
|
|
||||||
PIP_ADAPTER_INFO pAdapter = staticBuf;
|
|
||||||
ULONG bufSize = sizeof staticBuf;
|
|
||||||
QHash<QHostAddress, QHostAddress> ipv4netmasks;
|
|
||||||
|
|
||||||
DWORD retval = GetAdaptersInfo(pAdapter, &bufSize);
|
|
||||||
if (retval == ERROR_BUFFER_OVERFLOW) {
|
|
||||||
// need more memory
|
|
||||||
pAdapter = (IP_ADAPTER_INFO *)malloc(bufSize);
|
|
||||||
if (!pAdapter)
|
|
||||||
return ipv4netmasks;
|
|
||||||
// try again
|
|
||||||
if (GetAdaptersInfo(pAdapter, &bufSize) != ERROR_SUCCESS) {
|
|
||||||
free(pAdapter);
|
|
||||||
return ipv4netmasks;
|
|
||||||
}
|
|
||||||
} else if (retval != ERROR_SUCCESS) {
|
|
||||||
// error
|
|
||||||
return ipv4netmasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
// iterate over the list and add the entries to our listing
|
|
||||||
for (PIP_ADAPTER_INFO ptr = pAdapter; ptr; ptr = ptr->Next) {
|
|
||||||
for (PIP_ADDR_STRING addr = &ptr->IpAddressList; addr; addr = addr->Next) {
|
|
||||||
QHostAddress address(QLatin1String(addr->IpAddress.String));
|
|
||||||
QHostAddress mask(QLatin1String(addr->IpMask.String));
|
|
||||||
ipv4netmasks[address] = mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pAdapter != staticBuf)
|
|
||||||
free(pAdapter);
|
|
||||||
|
|
||||||
return ipv4netmasks;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static QList<QNetworkInterfacePrivate *> interfaceListing()
|
static QList<QNetworkInterfacePrivate *> interfaceListing()
|
||||||
{
|
{
|
||||||
QList<QNetworkInterfacePrivate *> interfaces;
|
QList<QNetworkInterfacePrivate *> interfaces;
|
||||||
@ -149,7 +110,6 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
|
|||||||
PIP_ADAPTER_ADDRESSES pAdapter = staticBuf;
|
PIP_ADAPTER_ADDRESSES pAdapter = staticBuf;
|
||||||
ULONG bufSize = sizeof staticBuf;
|
ULONG bufSize = sizeof staticBuf;
|
||||||
|
|
||||||
const QHash<QHostAddress, QHostAddress> &ipv4netmasks = ipv4Netmasks();
|
|
||||||
ULONG flags = GAA_FLAG_INCLUDE_PREFIX |
|
ULONG flags = GAA_FLAG_INCLUDE_PREFIX |
|
||||||
GAA_FLAG_SKIP_DNS_SERVER |
|
GAA_FLAG_SKIP_DNS_SERVER |
|
||||||
GAA_FLAG_SKIP_MULTICAST;
|
GAA_FLAG_SKIP_MULTICAST;
|
||||||
@ -176,7 +136,6 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
|
|||||||
// field we access from IP_ADAPTER_ADDRESSES_LH)
|
// field we access from IP_ADAPTER_ADDRESSES_LH)
|
||||||
Q_ASSERT(ptr->Length >= offsetof(IP_ADAPTER_ADDRESSES, Luid));
|
Q_ASSERT(ptr->Length >= offsetof(IP_ADAPTER_ADDRESSES, Luid));
|
||||||
Q_ASSERT(ptr->Length >= offsetof(IP_ADAPTER_ADDRESSES, Ipv6IfIndex));
|
Q_ASSERT(ptr->Length >= offsetof(IP_ADAPTER_ADDRESSES, Ipv6IfIndex));
|
||||||
Q_ASSERT(ptr->Length >= offsetof(IP_ADAPTER_ADDRESSES, FirstPrefix));
|
|
||||||
|
|
||||||
QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate;
|
QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate;
|
||||||
interfaces << iface;
|
interfaces << iface;
|
||||||
@ -211,27 +170,17 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
|
|||||||
// loopback if it has no address
|
// loopback if it has no address
|
||||||
iface->flags |= QNetworkInterface::IsLoopBack;
|
iface->flags |= QNetworkInterface::IsLoopBack;
|
||||||
|
|
||||||
// The GetAdaptersAddresses call has an interesting semantic:
|
// parse the IP (unicast) addresses
|
||||||
// It can return a number N of addresses and a number M of prefixes.
|
|
||||||
// But if you have IPv6 addresses, generally N > M.
|
|
||||||
// I cannot find a way to relate the Address to the Prefix, aside from stopping
|
|
||||||
// the iteration at the last Prefix entry and assume that it applies to all addresses
|
|
||||||
// from that point on.
|
|
||||||
PIP_ADAPTER_PREFIX pprefix = 0;
|
|
||||||
pprefix = ptr->FirstPrefix;
|
|
||||||
for (PIP_ADAPTER_UNICAST_ADDRESS addr = ptr->FirstUnicastAddress; addr; addr = addr->Next) {
|
for (PIP_ADAPTER_UNICAST_ADDRESS addr = ptr->FirstUnicastAddress; addr; addr = addr->Next) {
|
||||||
|
Q_ASSERT(addr->Length >= offsetof(IP_ADAPTER_UNICAST_ADDRESS, OnLinkPrefixLength));
|
||||||
|
|
||||||
|
// skip addresses in invalid state
|
||||||
|
if (addr->DadState == IpDadStateInvalid)
|
||||||
|
continue;
|
||||||
|
|
||||||
QNetworkAddressEntry entry;
|
QNetworkAddressEntry entry;
|
||||||
entry.setIp(addressFromSockaddr(addr->Address.lpSockaddr));
|
entry.setIp(addressFromSockaddr(addr->Address.lpSockaddr));
|
||||||
if (pprefix) {
|
entry.setPrefixLength(addr->OnLinkPrefixLength);
|
||||||
if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
|
|
||||||
entry.setNetmask(ipv4netmasks[entry.ip()]);
|
|
||||||
|
|
||||||
// broadcast address is set on postProcess()
|
|
||||||
} else { //IPV6
|
|
||||||
entry.setPrefixLength(pprefix->PrefixLength);
|
|
||||||
}
|
|
||||||
pprefix = pprefix->Next ? pprefix->Next : pprefix;
|
|
||||||
}
|
|
||||||
iface->addressEntries << entry;
|
iface->addressEntries << entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user