source: trunk/src/network/kernel/qnetworkinterface_win.cpp@ 352

Last change on this file since 352 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 11.8 KB
Line 
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
52QT_BEGIN_NAMESPACE
53
54typedef DWORD (WINAPI *PtrGetAdaptersInfo)(PIP_ADAPTER_INFO, PULONG);
55static PtrGetAdaptersInfo ptrGetAdaptersInfo = 0;
56typedef ULONG (WINAPI *PtrGetAdaptersAddresses)(ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG);
57static PtrGetAdaptersAddresses ptrGetAdaptersAddresses = 0;
58typedef DWORD (WINAPI *PtrGetNetworkParams)(PFIXED_INFO, PULONG);
59static PtrGetNetworkParams ptrGetNetworkParams = 0;
60
61static 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
90static 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
106static 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
143static 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
228static 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
281static 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
293QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan()
294{
295 return interfaceListing();
296}
297
298QString 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
325QT_END_NAMESPACE
326
327#endif // QT_NO_NETWORKINTERFACE
Note: See TracBrowser for help on using the repository browser.