Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qnetworkinterface_win.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:trusted-data
5
6#define WIN32_LEAN_AND_MEAN 1
7
10
11#ifndef QT_NO_NETWORKINTERFACE
12
13#include <qhostinfo.h>
14#include <qhash.h>
15#include <qurl.h>
16
17// Since we need to include winsock2.h, we need to define WIN32_LEAN_AND_MEAN
18// (above) so windows.h won't include winsock.h.
19// In addition, we need to include winsock2.h before iphlpapi.h and we need
20// to include ws2ipdef.h to work around an MinGW-w64 bug
21// (http://sourceforge.net/p/mingw-w64/mailman/message/32935366/)
22#include <winsock2.h>
23#include <ws2ipdef.h>
24#include <wincrypt.h>
25#include <iphlpapi.h>
26#include <ws2tcpip.h>
27
28#include <qt_windows.h>
29
30// In case these aren't defined
31#define IF_TYPE_IEEE80216_WMAN 237
32#define IF_TYPE_IEEE802154 259
33
35
37{
38 QHostAddress address;
39 if (!sa)
40 return address;
41
42 if (sa->sa_family == AF_INET) {
43 address.setAddress(htonl(reinterpret_cast<const sockaddr_in *>(sa)->sin_addr.s_addr));
44 } else if (sa->sa_family == AF_INET6) {
45 auto sai6 = reinterpret_cast<const sockaddr_in6 *>(sa);
46 address.setAddress(sai6->sin6_addr.s6_addr);
47 if (sai6->sin6_scope_id)
48 address.setScopeId(QNetworkInterfaceManager::interfaceNameFromIndex(sai6->sin6_scope_id));
49 } else {
50 qWarning("Got unknown socket family %d", sa->sa_family);
51 }
52 return address;
53
54}
55
56uint QNetworkInterfaceManager::interfaceIndexFromName(const QString &name)
57{
58 NET_IFINDEX id;
59 NET_LUID luid;
60 if (ConvertInterfaceNameToLuidW(reinterpret_cast<const wchar_t *>(name.constData()), &luid) == NO_ERROR
61 && ConvertInterfaceLuidToIndex(&luid, &id) == NO_ERROR)
62 return uint(id);
63 return 0;
64}
65
66QString QNetworkInterfaceManager::interfaceNameFromIndex(uint index)
67{
68 NET_LUID luid;
69 if (ConvertInterfaceIndexToLuid(index, &luid) == NO_ERROR) {
70 WCHAR buf[IF_MAX_STRING_SIZE + 1];
71 if (ConvertInterfaceLuidToNameW(&luid, buf, sizeof(buf)/sizeof(buf[0])) == NO_ERROR)
72 return QString::fromWCharArray(buf);
73 }
74 return QString::number(index);
75}
76
78{
79 QList<QNetworkInterfacePrivate *> interfaces;
80 IP_ADAPTER_ADDRESSES staticBuf[2]; // 2 is arbitrary
81 PIP_ADAPTER_ADDRESSES pAdapter = staticBuf;
82 ULONG bufSize = sizeof staticBuf;
83
84 ULONG flags = GAA_FLAG_INCLUDE_PREFIX |
85 GAA_FLAG_SKIP_DNS_SERVER |
86 GAA_FLAG_SKIP_MULTICAST;
87 ULONG retval = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAdapter, &bufSize);
88 if (retval == ERROR_BUFFER_OVERFLOW) {
89 // need more memory
90 pAdapter = reinterpret_cast<IP_ADAPTER_ADDRESSES *>(malloc(bufSize));
91 if (!pAdapter)
92 return interfaces;
93 // try again
94 if (GetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAdapter, &bufSize) != ERROR_SUCCESS) {
95 free(pAdapter);
96 return interfaces;
97 }
98 } else if (retval != ERROR_SUCCESS) {
99 // error
100 return interfaces;
101 }
102
103 // iterate over the list and add the entries to our listing
104 for (PIP_ADAPTER_ADDRESSES ptr = pAdapter; ptr; ptr = ptr->Next) {
105 // the structure grows over time, so let's make sure the fields
106 // introduced in Windows Vista are present (Luid is the furthest
107 // field we access from IP_ADAPTER_ADDRESSES_LH)
108 Q_ASSERT(ptr->Length >= offsetof(IP_ADAPTER_ADDRESSES, Luid));
109 Q_ASSERT(ptr->Length >= offsetof(IP_ADAPTER_ADDRESSES, Ipv6IfIndex));
110
112 interfaces << iface;
113
114 iface->index = 0;
115 if (ptr->Ipv6IfIndex != 0)
116 iface->index = ptr->Ipv6IfIndex;
117 else if (ptr->IfIndex != 0)
118 iface->index = ptr->IfIndex;
119
120 iface->mtu = qMin<qint64>(ptr->Mtu, INT_MAX);
121 iface->flags = QNetworkInterface::CanBroadcast;
122 if (ptr->OperStatus == IfOperStatusUp)
123 iface->flags |= QNetworkInterface::IsUp | QNetworkInterface::IsRunning;
124 if ((ptr->Flags & IP_ADAPTER_NO_MULTICAST) == 0)
125 iface->flags |= QNetworkInterface::CanMulticast;
126 if (ptr->IfType == IF_TYPE_PPP)
127 iface->flags |= QNetworkInterface::IsPointToPoint;
128
129 switch (ptr->IfType) {
130 case IF_TYPE_ETHERNET_CSMACD:
131 iface->type = QNetworkInterface::Ethernet;
132 break;
133
134 case IF_TYPE_FDDI:
135 iface->type = QNetworkInterface::Fddi;
136 break;
137
138 case IF_TYPE_PPP:
139 iface->type = QNetworkInterface::Ppp;
140 break;
141
142 case IF_TYPE_SLIP:
143 iface->type = QNetworkInterface::Slip;
144 break;
145
146 case IF_TYPE_SOFTWARE_LOOPBACK:
147 iface->type = QNetworkInterface::Loopback;
148 iface->flags |= QNetworkInterface::IsLoopBack;
149 break;
150
151 case IF_TYPE_IEEE80211:
152 iface->type = QNetworkInterface::Ieee80211;
153 break;
154
155 case IF_TYPE_IEEE1394:
156 iface->type = QNetworkInterface::Ieee1394;
157 break;
158
160 iface->type = QNetworkInterface::Ieee80216;
161 break;
162
164 iface->type = QNetworkInterface::Ieee802154;
165 break;
166 }
167
168 // use ConvertInterfaceLuidToNameW because that returns a friendlier name, though not
169 // as "friendly" as FriendlyName below
170 WCHAR buf[IF_MAX_STRING_SIZE + 1];
171 if (ConvertInterfaceLuidToNameW(&ptr->Luid, buf, sizeof(buf)/sizeof(buf[0])) == NO_ERROR)
172 iface->name = QString::fromWCharArray(buf);
173 if (iface->name.isEmpty())
174 iface->name = QString::fromLocal8Bit(ptr->AdapterName);
175
176 iface->friendlyName = QString::fromWCharArray(ptr->FriendlyName);
177 if (ptr->PhysicalAddressLength)
178 iface->hardwareAddress = iface->makeHwAddress(ptr->PhysicalAddressLength,
179 ptr->PhysicalAddress);
180
181 // parse the IP (unicast) addresses
182 for (PIP_ADAPTER_UNICAST_ADDRESS addr = ptr->FirstUnicastAddress; addr; addr = addr->Next) {
183 Q_ASSERT(addr->Length >= offsetof(IP_ADAPTER_UNICAST_ADDRESS, OnLinkPrefixLength));
184
185 // skip addresses in invalid state
186 if (addr->DadState == IpDadStateInvalid)
187 continue;
188
190 entry.setIp(addressFromSockaddr(addr->Address.lpSockaddr));
191 entry.setPrefixLength(addr->OnLinkPrefixLength);
192
193 auto toDeadline = [](ULONG lifetime) -> QDeadlineTimer {
194 if (lifetime == 0xffffffffUL)
195 return QDeadlineTimer::Forever;
196 return QDeadlineTimer(lifetime * 1000);
197 };
198 entry.setAddressLifetime(toDeadline(addr->ValidLifetime), toDeadline(addr->PreferredLifetime));
199 entry.setDnsEligibility(addr->Flags & IP_ADAPTER_ADDRESS_DNS_ELIGIBLE ?
200 QNetworkAddressEntry::DnsEligible :
201 QNetworkAddressEntry::DnsIneligible);
202
203 iface->addressEntries << entry;
204 }
205 }
206
207 if (pAdapter != staticBuf)
208 free(pAdapter);
209
210 return interfaces;
211}
212
213QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan()
214{
215 return interfaceListing();
216}
217
218QString QHostInfo::localDomainName()
219{
220 FIXED_INFO info, *pinfo;
221 ULONG bufSize = sizeof info;
222 pinfo = &info;
223 if (GetNetworkParams(pinfo, &bufSize) == ERROR_BUFFER_OVERFLOW) {
224 pinfo = reinterpret_cast<FIXED_INFO *>(malloc(bufSize));
225 if (!pinfo)
226 return QString();
227 // try again
228 if (GetNetworkParams(pinfo, &bufSize) != ERROR_SUCCESS) {
229 free(pinfo);
230 return QString(); // error
231 }
232 }
233
234 QString domainName = QUrl::fromAce(pinfo->DomainName);
235
236 if (pinfo != &info)
237 free(pinfo);
238
239 return domainName;
240}
241
242QT_END_NAMESPACE
243
244#endif // QT_NO_NETWORKINTERFACE
The QNetworkAddressEntry class stores one IP address supported by a network interface,...
#define IF_TYPE_IEEE802154
static QList< QNetworkInterfacePrivate * > interfaceListing()
static QT_BEGIN_NAMESPACE QHostAddress addressFromSockaddr(sockaddr *sa)
#define IF_TYPE_IEEE80216_WMAN