| 1 | /****************************************************************************
|
|---|
| 2 | **
|
|---|
| 3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|---|
| 4 | ** Contact: Qt Software Information ([email protected])
|
|---|
| 5 | **
|
|---|
| 6 | ** This file is part of the QtNetwork module of the Qt Toolkit.
|
|---|
| 7 | **
|
|---|
| 8 | ** $QT_BEGIN_LICENSE:LGPL$
|
|---|
| 9 | ** Commercial Usage
|
|---|
| 10 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
|---|
| 11 | ** accordance with the Qt Commercial License Agreement provided with the
|
|---|
| 12 | ** Software or, alternatively, in accordance with the terms contained in
|
|---|
| 13 | ** a written agreement between you and Nokia.
|
|---|
| 14 | **
|
|---|
| 15 | ** GNU Lesser General Public License Usage
|
|---|
| 16 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
|---|
| 17 | ** General Public License version 2.1 as published by the Free Software
|
|---|
| 18 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
|---|
| 19 | ** packaging of this file. Please review the following information to
|
|---|
| 20 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
|---|
| 21 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|---|
| 22 | **
|
|---|
| 23 | ** In addition, as a special exception, Nokia gives you certain
|
|---|
| 24 | ** additional rights. These rights are described in the Nokia Qt LGPL
|
|---|
| 25 | ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
|
|---|
| 26 | ** package.
|
|---|
| 27 | **
|
|---|
| 28 | ** GNU General Public License Usage
|
|---|
| 29 | ** Alternatively, this file may be used under the terms of the GNU
|
|---|
| 30 | ** General Public License version 3.0 as published by the Free Software
|
|---|
| 31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
|---|
| 32 | ** packaging of this file. Please review the following information to
|
|---|
| 33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
|---|
| 34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
|---|
| 35 | **
|
|---|
| 36 | ** If you are unsure which license is appropriate for your use, please
|
|---|
| 37 | ** contact the sales department at [email protected].
|
|---|
| 38 | ** $QT_END_LICENSE$
|
|---|
| 39 | **
|
|---|
| 40 | ****************************************************************************/
|
|---|
| 41 |
|
|---|
| 42 | #include "qnetworkinterface.h"
|
|---|
| 43 | #include "qnetworkinterface_p.h"
|
|---|
| 44 |
|
|---|
| 45 | #ifndef QT_NO_NETWORKINTERFACE
|
|---|
| 46 |
|
|---|
| 47 | #include "qnetworkinterface_win_p.h"
|
|---|
| 48 | #include <qhostinfo.h>
|
|---|
| 49 | #include <qhash.h>
|
|---|
| 50 | #include <qurl.h>
|
|---|
| 51 |
|
|---|
| 52 | QT_BEGIN_NAMESPACE
|
|---|
| 53 |
|
|---|
| 54 | typedef DWORD (WINAPI *PtrGetAdaptersInfo)(PIP_ADAPTER_INFO, PULONG);
|
|---|
| 55 | static PtrGetAdaptersInfo ptrGetAdaptersInfo = 0;
|
|---|
| 56 | typedef ULONG (WINAPI *PtrGetAdaptersAddresses)(ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG);
|
|---|
| 57 | static PtrGetAdaptersAddresses ptrGetAdaptersAddresses = 0;
|
|---|
| 58 | typedef DWORD (WINAPI *PtrGetNetworkParams)(PFIXED_INFO, PULONG);
|
|---|
| 59 | static PtrGetNetworkParams ptrGetNetworkParams = 0;
|
|---|
| 60 |
|
|---|
| 61 | static void resolveLibs()
|
|---|
| 62 | {
|
|---|
| 63 | // try to find the functions we need from Iphlpapi.dll
|
|---|
| 64 | static bool done = false;
|
|---|
| 65 |
|
|---|
| 66 | if (!done) {
|
|---|
| 67 | done = true;
|
|---|
| 68 |
|
|---|
| 69 | HINSTANCE iphlpapiHnd;
|
|---|
| 70 | QT_WA({
|
|---|
| 71 | iphlpapiHnd = LoadLibraryW(L"iphlpapi");
|
|---|
| 72 | }, {
|
|---|
| 73 | iphlpapiHnd = LoadLibraryA("iphlpapi");
|
|---|
| 74 | });
|
|---|
| 75 | if (iphlpapiHnd == NULL)
|
|---|
| 76 | return; // failed to load, probably Windows 95
|
|---|
| 77 |
|
|---|
| 78 | #if defined(Q_OS_WINCE)
|
|---|
| 79 | ptrGetAdaptersInfo = (PtrGetAdaptersInfo)GetProcAddressW(iphlpapiHnd, L"GetAdaptersInfo");
|
|---|
| 80 | ptrGetAdaptersAddresses = (PtrGetAdaptersAddresses)GetProcAddressW(iphlpapiHnd, L"GetAdaptersAddresses");
|
|---|
| 81 | ptrGetNetworkParams = (PtrGetNetworkParams)GetProcAddressW(iphlpapiHnd, L"GetNetworkParams");
|
|---|
| 82 | #else
|
|---|
| 83 | ptrGetAdaptersInfo = (PtrGetAdaptersInfo)GetProcAddress(iphlpapiHnd, "GetAdaptersInfo");
|
|---|
| 84 | ptrGetAdaptersAddresses = (PtrGetAdaptersAddresses)GetProcAddress(iphlpapiHnd, "GetAdaptersAddresses");
|
|---|
| 85 | ptrGetNetworkParams = (PtrGetNetworkParams)GetProcAddress(iphlpapiHnd, "GetNetworkParams");
|
|---|
| 86 | #endif
|
|---|
| 87 | }
|
|---|
| 88 | }
|
|---|
| 89 |
|
|---|
| 90 | static QHostAddress addressFromSockaddr(sockaddr *sa)
|
|---|
| 91 | {
|
|---|
| 92 | QHostAddress address;
|
|---|
| 93 | if (!sa)
|
|---|
| 94 | return address;
|
|---|
| 95 |
|
|---|
| 96 | if (sa->sa_family == AF_INET)
|
|---|
| 97 | address.setAddress(htonl(((sockaddr_in *)sa)->sin_addr.s_addr));
|
|---|
| 98 | else if (sa->sa_family == AF_INET6)
|
|---|
| 99 | address.setAddress(((qt_sockaddr_in6 *)sa)->sin6_addr.qt_s6_addr);
|
|---|
| 100 | else
|
|---|
| 101 | qWarning("Got unknown socket family %d", sa->sa_family);
|
|---|
| 102 | return address;
|
|---|
| 103 |
|
|---|
| 104 | }
|
|---|
| 105 |
|
|---|
| 106 | static QHash<QHostAddress, QHostAddress> ipv4Netmasks()
|
|---|
| 107 | {
|
|---|
| 108 | //Retrieve all the IPV4 addresses & netmasks
|
|---|
| 109 | IP_ADAPTER_INFO staticBuf[2]; // 2 is arbitrary
|
|---|
| 110 | PIP_ADAPTER_INFO pAdapter = staticBuf;
|
|---|
| 111 | ULONG bufSize = sizeof staticBuf;
|
|---|
| 112 | QHash<QHostAddress, QHostAddress> ipv4netmasks;
|
|---|
| 113 |
|
|---|
| 114 | DWORD retval = ptrGetAdaptersInfo(pAdapter, &bufSize);
|
|---|
| 115 | if (retval == ERROR_BUFFER_OVERFLOW) {
|
|---|
| 116 | // need more memory
|
|---|
| 117 | pAdapter = (IP_ADAPTER_INFO *)qMalloc(bufSize);
|
|---|
| 118 | // try again
|
|---|
| 119 | if (ptrGetAdaptersInfo(pAdapter, &bufSize) != ERROR_SUCCESS) {
|
|---|
| 120 | qFree(pAdapter);
|
|---|
| 121 | return ipv4netmasks;
|
|---|
| 122 | }
|
|---|
| 123 | } else if (retval != ERROR_SUCCESS) {
|
|---|
| 124 | // error
|
|---|
| 125 | return ipv4netmasks;
|
|---|
| 126 | }
|
|---|
| 127 |
|
|---|
| 128 | // iterate over the list and add the entries to our listing
|
|---|
| 129 | for (PIP_ADAPTER_INFO ptr = pAdapter; ptr; ptr = ptr->Next) {
|
|---|
| 130 | for (PIP_ADDR_STRING addr = &ptr->IpAddressList; addr; addr = addr->Next) {
|
|---|
| 131 | QHostAddress address(QLatin1String(addr->IpAddress.String));
|
|---|
| 132 | QHostAddress mask(QLatin1String(addr->IpMask.String));
|
|---|
| 133 | ipv4netmasks[address] = mask;
|
|---|
| 134 | }
|
|---|
| 135 | }
|
|---|
| 136 | if (pAdapter != staticBuf)
|
|---|
| 137 | qFree(pAdapter);
|
|---|
| 138 |
|
|---|
| 139 | return ipv4netmasks;
|
|---|
| 140 |
|
|---|
| 141 | }
|
|---|
| 142 |
|
|---|
| 143 | static QList<QNetworkInterfacePrivate *> interfaceListingWinXP()
|
|---|
| 144 | {
|
|---|
| 145 | QList<QNetworkInterfacePrivate *> interfaces;
|
|---|
| 146 | IP_ADAPTER_ADDRESSES staticBuf[2]; // 2 is arbitrary
|
|---|
| 147 | PIP_ADAPTER_ADDRESSES pAdapter = staticBuf;
|
|---|
| 148 | ULONG bufSize = sizeof staticBuf;
|
|---|
| 149 |
|
|---|
| 150 | const QHash<QHostAddress, QHostAddress> &ipv4netmasks = ipv4Netmasks();
|
|---|
| 151 | ULONG flags = GAA_FLAG_INCLUDE_ALL_INTERFACES |
|
|---|
| 152 | GAA_FLAG_INCLUDE_PREFIX |
|
|---|
| 153 | GAA_FLAG_SKIP_DNS_SERVER |
|
|---|
| 154 | GAA_FLAG_SKIP_MULTICAST;
|
|---|
| 155 | ULONG retval = ptrGetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAdapter, &bufSize);
|
|---|
| 156 | if (retval == ERROR_BUFFER_OVERFLOW) {
|
|---|
| 157 | // need more memory
|
|---|
| 158 | pAdapter = (IP_ADAPTER_ADDRESSES *)qMalloc(bufSize);
|
|---|
| 159 |
|
|---|
| 160 | // try again
|
|---|
| 161 | if (ptrGetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAdapter, &bufSize) != ERROR_SUCCESS) {
|
|---|
| 162 | qFree(pAdapter);
|
|---|
| 163 | return interfaces;
|
|---|
| 164 | }
|
|---|
| 165 | } else if (retval != ERROR_SUCCESS) {
|
|---|
| 166 | // error
|
|---|
| 167 | return interfaces;
|
|---|
| 168 | }
|
|---|
| 169 |
|
|---|
| 170 | // iterate over the list and add the entries to our listing
|
|---|
| 171 | for (PIP_ADAPTER_ADDRESSES ptr = pAdapter; ptr; ptr = ptr->Next) {
|
|---|
| 172 | QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate;
|
|---|
| 173 | interfaces << iface;
|
|---|
| 174 |
|
|---|
| 175 | iface->index = 0;
|
|---|
| 176 | if (ptr->Length >= offsetof(IP_ADAPTER_ADDRESSES, Ipv6IfIndex) && ptr->Ipv6IfIndex != 0)
|
|---|
| 177 | iface->index = ptr->Ipv6IfIndex;
|
|---|
| 178 | else if (ptr->IfIndex != 0)
|
|---|
| 179 | iface->index = ptr->IfIndex;
|
|---|
| 180 |
|
|---|
| 181 | iface->flags = QNetworkInterface::CanBroadcast;
|
|---|
| 182 | if (ptr->OperStatus == IfOperStatusUp)
|
|---|
| 183 | iface->flags |= QNetworkInterface::IsUp | QNetworkInterface::IsRunning;
|
|---|
| 184 | if ((ptr->Flags & IP_ADAPTER_NO_MULTICAST) == 0)
|
|---|
| 185 | iface->flags |= QNetworkInterface::CanMulticast;
|
|---|
| 186 |
|
|---|
| 187 | iface->name = QString::fromLocal8Bit(ptr->AdapterName);
|
|---|
| 188 | iface->friendlyName = QString::fromWCharArray(ptr->FriendlyName);
|
|---|
| 189 | if (ptr->PhysicalAddressLength)
|
|---|
| 190 | iface->hardwareAddress = iface->makeHwAddress(ptr->PhysicalAddressLength,
|
|---|
| 191 | ptr->PhysicalAddress);
|
|---|
| 192 | else
|
|---|
| 193 | // loopback if it has no address
|
|---|
| 194 | iface->flags |= QNetworkInterface::IsLoopBack;
|
|---|
| 195 |
|
|---|
| 196 | // The GetAdaptersAddresses call has an interesting semantic:
|
|---|
| 197 | // It can return a number N of addresses and a number M of prefixes.
|
|---|
| 198 | // But if you have IPv6 addresses, generally N > M.
|
|---|
| 199 | // I cannot find a way to relate the Address to the Prefix, aside from stopping
|
|---|
| 200 | // the iteration at the last Prefix entry and assume that it applies to all addresses
|
|---|
| 201 | // from that point on.
|
|---|
| 202 | PIP_ADAPTER_PREFIX pprefix = 0;
|
|---|
| 203 | if (ptr->Length >= offsetof(IP_ADAPTER_ADDRESSES, FirstPrefix))
|
|---|
| 204 | pprefix = ptr->FirstPrefix;
|
|---|
| 205 | for (PIP_ADAPTER_UNICAST_ADDRESS addr = ptr->FirstUnicastAddress; addr; addr = addr->Next) {
|
|---|
| 206 | QNetworkAddressEntry entry;
|
|---|
| 207 | entry.setIp(addressFromSockaddr(addr->Address.lpSockaddr));
|
|---|
| 208 | if (pprefix) {
|
|---|
| 209 | if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
|
|---|
| 210 | entry.setNetmask(ipv4netmasks[entry.ip()]);
|
|---|
| 211 |
|
|---|
| 212 | // broadcast address is set on postProcess()
|
|---|
| 213 | } else { //IPV6
|
|---|
| 214 | entry.setPrefixLength(pprefix->PrefixLength);
|
|---|
| 215 | }
|
|---|
| 216 | pprefix = pprefix->Next ? pprefix->Next : pprefix;
|
|---|
| 217 | }
|
|---|
| 218 | iface->addressEntries << entry;
|
|---|
| 219 | }
|
|---|
| 220 | }
|
|---|
| 221 |
|
|---|
| 222 | if (pAdapter != staticBuf)
|
|---|
| 223 | qFree(pAdapter);
|
|---|
| 224 |
|
|---|
| 225 | return interfaces;
|
|---|
| 226 | }
|
|---|
| 227 |
|
|---|
| 228 | static QList<QNetworkInterfacePrivate *> interfaceListingWin2k()
|
|---|
| 229 | {
|
|---|
| 230 | QList<QNetworkInterfacePrivate *> interfaces;
|
|---|
| 231 | IP_ADAPTER_INFO staticBuf[2]; // 2 is arbitrary
|
|---|
| 232 | PIP_ADAPTER_INFO pAdapter = staticBuf;
|
|---|
| 233 | ULONG bufSize = sizeof staticBuf;
|
|---|
| 234 |
|
|---|
| 235 | DWORD retval = ptrGetAdaptersInfo(pAdapter, &bufSize);
|
|---|
| 236 | if (retval == ERROR_BUFFER_OVERFLOW) {
|
|---|
| 237 | // need more memory
|
|---|
| 238 | pAdapter = (IP_ADAPTER_INFO *)qMalloc(bufSize);
|
|---|
| 239 |
|
|---|
| 240 | // try again
|
|---|
| 241 | if (ptrGetAdaptersInfo(pAdapter, &bufSize) != ERROR_SUCCESS) {
|
|---|
| 242 | qFree(pAdapter);
|
|---|
| 243 | return interfaces;
|
|---|
| 244 | }
|
|---|
| 245 | } else if (retval != ERROR_SUCCESS) {
|
|---|
| 246 | // error
|
|---|
| 247 | return interfaces;
|
|---|
| 248 | }
|
|---|
| 249 |
|
|---|
| 250 | // iterate over the list and add the entries to our listing
|
|---|
| 251 | for (PIP_ADAPTER_INFO ptr = pAdapter; ptr; ptr = ptr->Next) {
|
|---|
| 252 | QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate;
|
|---|
| 253 | interfaces << iface;
|
|---|
| 254 |
|
|---|
| 255 | iface->index = ptr->Index;
|
|---|
| 256 | iface->flags = QNetworkInterface::IsUp | QNetworkInterface::IsRunning;
|
|---|
| 257 | if (ptr->Type == MIB_IF_TYPE_PPP)
|
|---|
| 258 | iface->flags |= QNetworkInterface::IsPointToPoint;
|
|---|
| 259 | else
|
|---|
| 260 | iface->flags |= QNetworkInterface::CanBroadcast;
|
|---|
| 261 | iface->name = QString::fromLocal8Bit(ptr->AdapterName);
|
|---|
| 262 | iface->hardwareAddress = QNetworkInterfacePrivate::makeHwAddress(ptr->AddressLength,
|
|---|
| 263 | ptr->Address);
|
|---|
| 264 |
|
|---|
| 265 | for (PIP_ADDR_STRING addr = &ptr->IpAddressList; addr; addr = addr->Next) {
|
|---|
| 266 | QNetworkAddressEntry entry;
|
|---|
| 267 | entry.setIp(QHostAddress(QLatin1String(addr->IpAddress.String)));
|
|---|
| 268 | entry.setNetmask(QHostAddress(QLatin1String(addr->IpMask.String)));
|
|---|
| 269 | // broadcast address is set on postProcess()
|
|---|
| 270 |
|
|---|
| 271 | iface->addressEntries << entry;
|
|---|
| 272 | }
|
|---|
| 273 | }
|
|---|
| 274 |
|
|---|
| 275 | if (pAdapter != staticBuf)
|
|---|
| 276 | qFree(pAdapter);
|
|---|
| 277 |
|
|---|
| 278 | return interfaces;
|
|---|
| 279 | }
|
|---|
| 280 |
|
|---|
| 281 | static QList<QNetworkInterfacePrivate *> interfaceListing()
|
|---|
| 282 | {
|
|---|
| 283 | resolveLibs();
|
|---|
| 284 | if (ptrGetAdaptersAddresses != NULL)
|
|---|
| 285 | return interfaceListingWinXP();
|
|---|
| 286 | else if (ptrGetAdaptersInfo != NULL)
|
|---|
| 287 | return interfaceListingWin2k();
|
|---|
| 288 |
|
|---|
| 289 | // failed
|
|---|
| 290 | return QList<QNetworkInterfacePrivate *>();
|
|---|
| 291 | }
|
|---|
| 292 |
|
|---|
| 293 | QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan()
|
|---|
| 294 | {
|
|---|
| 295 | return interfaceListing();
|
|---|
| 296 | }
|
|---|
| 297 |
|
|---|
| 298 | QString QHostInfo::localDomainName()
|
|---|
| 299 | {
|
|---|
| 300 | resolveLibs();
|
|---|
| 301 | if (ptrGetNetworkParams == NULL)
|
|---|
| 302 | return QString(); // couldn't resolve
|
|---|
| 303 |
|
|---|
| 304 | FIXED_INFO info, *pinfo;
|
|---|
| 305 | ULONG bufSize = sizeof info;
|
|---|
| 306 | pinfo = &info;
|
|---|
| 307 | if (ptrGetNetworkParams(pinfo, &bufSize) == ERROR_BUFFER_OVERFLOW) {
|
|---|
| 308 | pinfo = (FIXED_INFO *)qMalloc(bufSize);
|
|---|
| 309 |
|
|---|
| 310 | // try again
|
|---|
| 311 | if (ptrGetNetworkParams(pinfo, &bufSize) != ERROR_SUCCESS) {
|
|---|
| 312 | qFree(pinfo);
|
|---|
| 313 | return QString(); // error
|
|---|
| 314 | }
|
|---|
| 315 | }
|
|---|
| 316 |
|
|---|
| 317 | QString domainName = QUrl::fromAce(pinfo->DomainName);
|
|---|
| 318 |
|
|---|
| 319 | if (pinfo != &info)
|
|---|
| 320 | qFree(pinfo);
|
|---|
| 321 |
|
|---|
| 322 | return domainName;
|
|---|
| 323 | }
|
|---|
| 324 |
|
|---|
| 325 | QT_END_NAMESPACE
|
|---|
| 326 |
|
|---|
| 327 | #endif // QT_NO_NETWORKINTERFACE
|
|---|