Qt 4.8
qnetworkinterface_win.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qnetworkinterface.h"
43 #include "qnetworkinterface_p.h"
44 
45 #ifndef QT_NO_NETWORKINTERFACE
46 
48 #include <qhostinfo.h>
49 #include <qhash.h>
50 #include <qurl.h>
51 #include <private/qsystemlibrary_p.h>
52 
54 
55 typedef DWORD (WINAPI *PtrGetAdaptersInfo)(PIP_ADAPTER_INFO, PULONG);
57 typedef ULONG (WINAPI *PtrGetAdaptersAddresses)(ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG);
59 typedef DWORD (WINAPI *PtrGetNetworkParams)(PFIXED_INFO, PULONG);
61 
62 static void resolveLibs()
63 {
64  // try to find the functions we need from Iphlpapi.dll
65  static bool done = false;
66  if (!done) {
67  QSystemLibrary iphlpapi(QLatin1String("iphlpapi"));
68  if (iphlpapi.load()) {
69  ptrGetAdaptersInfo = (PtrGetAdaptersInfo)iphlpapi.resolve("GetAdaptersInfo");
70  ptrGetAdaptersAddresses = (PtrGetAdaptersAddresses)iphlpapi.resolve("GetAdaptersAddresses");
71  ptrGetNetworkParams = (PtrGetNetworkParams)iphlpapi.resolve("GetNetworkParams");
72  }
73  done = true;
74  }
75 }
76 
77 static QHostAddress addressFromSockaddr(sockaddr *sa)
78 {
79  QHostAddress address;
80  if (!sa)
81  return address;
82 
83  if (sa->sa_family == AF_INET)
84  address.setAddress(htonl(((sockaddr_in *)sa)->sin_addr.s_addr));
85  else if (sa->sa_family == AF_INET6) {
86  address.setAddress(((qt_sockaddr_in6 *)sa)->sin6_addr.qt_s6_addr);
87  int scope = ((qt_sockaddr_in6 *)sa)->sin6_scope_id;
88  if (scope)
89  address.setScopeId(QString::number(scope));
90  } else
91  qWarning("Got unknown socket family %d", sa->sa_family);
92  return address;
93 
94 }
95 
97 {
98  //Retrieve all the IPV4 addresses & netmasks
99  IP_ADAPTER_INFO staticBuf[2]; // 2 is arbitrary
100  PIP_ADAPTER_INFO pAdapter = staticBuf;
101  ULONG bufSize = sizeof staticBuf;
102  QHash<QHostAddress, QHostAddress> ipv4netmasks;
103 
104  DWORD retval = ptrGetAdaptersInfo(pAdapter, &bufSize);
105  if (retval == ERROR_BUFFER_OVERFLOW) {
106  // need more memory
107  pAdapter = (IP_ADAPTER_INFO *)qMalloc(bufSize);
108  if (!pAdapter)
109  return ipv4netmasks;
110  // try again
111  if (ptrGetAdaptersInfo(pAdapter, &bufSize) != ERROR_SUCCESS) {
112  qFree(pAdapter);
113  return ipv4netmasks;
114  }
115  } else if (retval != ERROR_SUCCESS) {
116  // error
117  return ipv4netmasks;
118  }
119 
120  // iterate over the list and add the entries to our listing
121  for (PIP_ADAPTER_INFO ptr = pAdapter; ptr; ptr = ptr->Next) {
122  for (PIP_ADDR_STRING addr = &ptr->IpAddressList; addr; addr = addr->Next) {
123  QHostAddress address(QLatin1String(addr->IpAddress.String));
124  QHostAddress mask(QLatin1String(addr->IpMask.String));
125  ipv4netmasks[address] = mask;
126  }
127  }
128  if (pAdapter != staticBuf)
129  qFree(pAdapter);
130 
131  return ipv4netmasks;
132 
133 }
134 
136 {
138  IP_ADAPTER_ADDRESSES staticBuf[2]; // 2 is arbitrary
139  PIP_ADAPTER_ADDRESSES pAdapter = staticBuf;
140  ULONG bufSize = sizeof staticBuf;
141 
142  const QHash<QHostAddress, QHostAddress> &ipv4netmasks = ipv4Netmasks();
143  ULONG flags = GAA_FLAG_INCLUDE_PREFIX |
146  ULONG retval = ptrGetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAdapter, &bufSize);
147  if (retval == ERROR_BUFFER_OVERFLOW) {
148  // need more memory
149  pAdapter = (IP_ADAPTER_ADDRESSES *)qMalloc(bufSize);
150  if (!pAdapter)
151  return interfaces;
152  // try again
153  if (ptrGetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAdapter, &bufSize) != ERROR_SUCCESS) {
154  qFree(pAdapter);
155  return interfaces;
156  }
157  } else if (retval != ERROR_SUCCESS) {
158  // error
159  return interfaces;
160  }
161 
162  // iterate over the list and add the entries to our listing
163  for (PIP_ADAPTER_ADDRESSES ptr = pAdapter; ptr; ptr = ptr->Next) {
165  interfaces << iface;
166 
167  iface->index = 0;
168  if (ptr->Length >= offsetof(IP_ADAPTER_ADDRESSES, Ipv6IfIndex) && ptr->Ipv6IfIndex != 0)
169  iface->index = ptr->Ipv6IfIndex;
170  else if (ptr->IfIndex != 0)
171  iface->index = ptr->IfIndex;
172 
173  iface->flags = QNetworkInterface::CanBroadcast;
174  if (ptr->OperStatus == IfOperStatusUp)
176  if ((ptr->Flags & IP_ADAPTER_NO_MULTICAST) == 0)
177  iface->flags |= QNetworkInterface::CanMulticast;
178 
179  iface->name = QString::fromLocal8Bit(ptr->AdapterName);
180  iface->friendlyName = QString::fromWCharArray(ptr->FriendlyName);
181  if (ptr->PhysicalAddressLength)
182  iface->hardwareAddress = iface->makeHwAddress(ptr->PhysicalAddressLength,
183  ptr->PhysicalAddress);
184  else
185  // loopback if it has no address
186  iface->flags |= QNetworkInterface::IsLoopBack;
187 
188  // The GetAdaptersAddresses call has an interesting semantic:
189  // It can return a number N of addresses and a number M of prefixes.
190  // But if you have IPv6 addresses, generally N > M.
191  // I cannot find a way to relate the Address to the Prefix, aside from stopping
192  // the iteration at the last Prefix entry and assume that it applies to all addresses
193  // from that point on.
194  PIP_ADAPTER_PREFIX pprefix = 0;
195  if (ptr->Length >= offsetof(IP_ADAPTER_ADDRESSES, FirstPrefix))
196  pprefix = ptr->FirstPrefix;
197  for (PIP_ADAPTER_UNICAST_ADDRESS addr = ptr->FirstUnicastAddress; addr; addr = addr->Next) {
198  QNetworkAddressEntry entry;
199  entry.setIp(addressFromSockaddr(addr->Address.lpSockaddr));
200  if (pprefix) {
201  if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
202  entry.setNetmask(ipv4netmasks[entry.ip()]);
203 
204  // broadcast address is set on postProcess()
205  } else { //IPV6
206  entry.setPrefixLength(pprefix->PrefixLength);
207  }
208  pprefix = pprefix->Next ? pprefix->Next : pprefix;
209  }
210  iface->addressEntries << entry;
211  }
212  }
213 
214  if (pAdapter != staticBuf)
215  qFree(pAdapter);
216 
217  return interfaces;
218 }
219 
221 {
223  IP_ADAPTER_INFO staticBuf[2]; // 2 is arbitrary
224  PIP_ADAPTER_INFO pAdapter = staticBuf;
225  ULONG bufSize = sizeof staticBuf;
226 
227  DWORD retval = ptrGetAdaptersInfo(pAdapter, &bufSize);
228  if (retval == ERROR_BUFFER_OVERFLOW) {
229  // need more memory
230  pAdapter = (IP_ADAPTER_INFO *)qMalloc(bufSize);
231  if (!pAdapter)
232  return interfaces;
233  // try again
234  if (ptrGetAdaptersInfo(pAdapter, &bufSize) != ERROR_SUCCESS) {
235  qFree(pAdapter);
236  return interfaces;
237  }
238  } else if (retval != ERROR_SUCCESS) {
239  // error
240  return interfaces;
241  }
242 
243  // iterate over the list and add the entries to our listing
244  for (PIP_ADAPTER_INFO ptr = pAdapter; ptr; ptr = ptr->Next) {
246  interfaces << iface;
247 
248  iface->index = ptr->Index;
250  if (ptr->Type == MIB_IF_TYPE_PPP)
251  iface->flags |= QNetworkInterface::IsPointToPoint;
252  else
253  iface->flags |= QNetworkInterface::CanBroadcast;
254  iface->name = QString::fromLocal8Bit(ptr->AdapterName);
255  iface->hardwareAddress = QNetworkInterfacePrivate::makeHwAddress(ptr->AddressLength,
256  ptr->Address);
257 
258  for (PIP_ADDR_STRING addr = &ptr->IpAddressList; addr; addr = addr->Next) {
259  QNetworkAddressEntry entry;
260  entry.setIp(QHostAddress(QLatin1String(addr->IpAddress.String)));
261  entry.setNetmask(QHostAddress(QLatin1String(addr->IpMask.String)));
262  // broadcast address is set on postProcess()
263 
264  iface->addressEntries << entry;
265  }
266  }
267 
268  if (pAdapter != staticBuf)
269  qFree(pAdapter);
270 
271  return interfaces;
272 }
273 
275 {
276  resolveLibs();
277  if (ptrGetAdaptersAddresses != NULL)
278  return interfaceListingWinXP();
279  else if (ptrGetAdaptersInfo != NULL)
280  return interfaceListingWin2k();
281 
282  // failed
284 }
285 
287 {
288  return interfaceListing();
289 }
290 
292 {
293  resolveLibs();
294  if (ptrGetNetworkParams == NULL)
295  return QString(); // couldn't resolve
296 
297  FIXED_INFO info, *pinfo;
298  ULONG bufSize = sizeof info;
299  pinfo = &info;
300  if (ptrGetNetworkParams(pinfo, &bufSize) == ERROR_BUFFER_OVERFLOW) {
301  pinfo = (FIXED_INFO *)qMalloc(bufSize);
302  if (!pinfo)
303  return QString();
304  // try again
305  if (ptrGetNetworkParams(pinfo, &bufSize) != ERROR_SUCCESS) {
306  qFree(pinfo);
307  return QString(); // error
308  }
309  }
310 
311  QString domainName = QUrl::fromAce(pinfo->DomainName);
312 
313  if (pinfo != &info)
314  qFree(pinfo);
315 
316  return domainName;
317 }
318 
320 
321 #endif // QT_NO_NETWORKINTERFACE
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: qstring.cpp:6448
void setScopeId(const QString &id)
Sets the IPv6 scope ID of the address to id.
static QString fromWCharArray(const wchar_t *, int size=-1)
Returns a copy of the string, where the encoding of string depends on the size of wchar...
Definition: qstring.cpp:1019
static PtrGetAdaptersInfo ptrGetAdaptersInfo
static QHash< QHostAddress, QHostAddress > ipv4Netmasks()
static QString fromLocal8Bit(const char *, int size=-1)
Returns a QString initialized with the first size characters of the 8-bit string str.
Definition: qstring.cpp:4245
#define IP_ADAPTER_NO_MULTICAST
static mach_timebase_info_data_t info
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QHostAddress ip() const
This function returns one IPv4 or IPv6 address found, that was found in a network interface...
DWORD(WINAPI * PtrGetNetworkParams)(PFIXED_INFO, PULONG)
Q_CORE_EXPORT void qFree(void *ptr)
Definition: qmalloc.cpp:58
void setPrefixLength(int length)
Sets the prefix length of this IP address to length.
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
Q_CORE_EXPORT void * qMalloc(size_t size)
Definition: qmalloc.cpp:53
The QString class provides a Unicode character string.
Definition: qstring.h:83
The QHash class is a template class that provides a hash-table-based dictionary.
Definition: qdatastream.h:66
bool load(bool onlySystemDirectory=true)
DWORD(WINAPI * PtrGetAdaptersInfo)(PIP_ADAPTER_INFO, PULONG)
static QList< QNetworkInterfacePrivate * > interfaceListing()
ULONG(WINAPI * PtrGetAdaptersAddresses)(ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG)
static void resolveLibs()
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
char DomainName[MAX_DOMAIN_NAME_LEN+4]
static QString makeHwAddress(int len, uchar *data)
static QHostAddress addressFromSockaddr(sockaddr *sa)
QList< QNetworkInterfacePrivate * > scan()
static QList< QNetworkInterfacePrivate * > interfaceListingWinXP()
Q_CORE_EXPORT void qWarning(const char *,...)
struct FIXED_INFO * PFIXED_INFO
const T * ptr(const T &t)
#define GAA_FLAG_SKIP_MULTICAST
#define MIB_IF_TYPE_PPP
static QString fromAce(const QByteArray &)
Returns the Unicode form of the given domain name domain, which is encoded in the ASCII Compatible En...
Definition: qurl.cpp:6134
struct _IP_ADAPTER_ADDRESSES * PIP_ADAPTER_ADDRESSES
void * resolve(const char *symbol)
QAbstractSocket::NetworkLayerProtocol protocol() const
Returns the network layer protocol of the host address.
struct _IP_ADAPTER_PREFIX * Next
void setAddress(quint32 ip4Addr)
Set the IPv4 address specified by ip4Addr.
void setIp(const QHostAddress &newIp)
Sets the IP address the QNetworkAddressEntry object contains to newIp.
#define GAA_FLAG_INCLUDE_PREFIX
static PtrGetAdaptersAddresses ptrGetAdaptersAddresses
void setNetmask(const QHostAddress &newNetmask)
Sets the netmask that this QNetworkAddressEntry object contains to newNetmask.
static QList< QNetworkInterfacePrivate * > interfaceListingWin2k()
The QHostAddress class provides an IP address.
Definition: qhostaddress.h:70
#define GAA_FLAG_SKIP_DNS_SERVER
The QNetworkAddressEntry class stores one IP address supported by a network interface, along with its associated netmask and broadcast address.
static PtrGetNetworkParams ptrGetNetworkParams
static QString localDomainName()
Returns the DNS domain of this machine.
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
struct _IP_ADAPTER_INFO * PIP_ADAPTER_INFO
#define AF_INET6