author | Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com> |
Tue, 06 Jul 2010 15:10:48 +0300 | |
changeset 30 | 5dc02b23752f |
parent 25 | e24348a560a6 |
permissions | -rw-r--r-- |
0 | 1 |
/**************************************************************************** |
2 |
** |
|
18
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
3 |
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
0 | 4 |
** All rights reserved. |
5 |
** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 |
** |
|
7 |
** This file is part of the QtNetwork module of the Qt Toolkit. |
|
8 |
** |
|
9 |
** $QT_BEGIN_LICENSE:LGPL$ |
|
10 |
** No Commercial Usage |
|
11 |
** This file contains pre-release code and may not be distributed. |
|
12 |
** You may use this file in accordance with the terms and conditions |
|
13 |
** contained in the Technology Preview License Agreement accompanying |
|
14 |
** this package. |
|
15 |
** |
|
16 |
** GNU Lesser General Public License Usage |
|
17 |
** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 |
** General Public License version 2.1 as published by the Free Software |
|
19 |
** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 |
** packaging of this file. Please review the following information to |
|
21 |
** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 |
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 |
** |
|
24 |
** In addition, as a special exception, Nokia gives you certain additional |
|
25 |
** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 |
** |
|
28 |
** If you have questions regarding the use of this file, please contact |
|
29 |
** Nokia at qt-info@nokia.com. |
|
30 |
** |
|
31 |
** |
|
32 |
** |
|
33 |
** |
|
34 |
** |
|
35 |
** |
|
36 |
** |
|
37 |
** |
|
38 |
** $QT_END_LICENSE$ |
|
39 |
** |
|
40 |
****************************************************************************/ |
|
41 |
||
42 |
#if defined Q_CC_MSVC && _MSC_VER <=1300 |
|
43 |
//VC.net 2002 support for templates doesn't match some PSDK requirements |
|
44 |
#define _WSPIAPI_COUNTOF(_Array) (sizeof(_Array) / sizeof(_Array[0])) |
|
45 |
#endif |
|
46 |
||
47 |
#include <winsock2.h> |
|
48 |
||
49 |
#include "qhostinfo_p.h" |
|
50 |
#include "private/qnativesocketengine_p.h" |
|
51 |
#include <ws2tcpip.h> |
|
52 |
#include <qlibrary.h> |
|
53 |
#include <qmutex.h> |
|
54 |
#include <qurl.h> |
|
55 |
#include <private/qmutexpool_p.h> |
|
56 |
||
57 |
QT_BEGIN_NAMESPACE |
|
58 |
||
59 |
//#define QHOSTINFO_DEBUG |
|
60 |
||
61 |
// Older SDKs do not include the addrinfo struct declaration, so we |
|
62 |
// include a copy of it here. |
|
63 |
struct qt_addrinfo |
|
64 |
{ |
|
65 |
int ai_flags; |
|
66 |
int ai_family; |
|
67 |
int ai_socktype; |
|
68 |
int ai_protocol; |
|
69 |
size_t ai_addrlen; |
|
70 |
char *ai_canonname; |
|
71 |
sockaddr *ai_addr; |
|
72 |
qt_addrinfo *ai_next; |
|
73 |
}; |
|
74 |
||
75 |
//### |
|
76 |
#define QT_SOCKLEN_T int |
|
77 |
#ifndef NI_MAXHOST // already defined to 1025 in ws2tcpip.h? |
|
78 |
#define NI_MAXHOST 1024 |
|
79 |
#endif |
|
80 |
||
81 |
typedef int (__stdcall *getnameinfoProto)(const sockaddr *, QT_SOCKLEN_T, const char *, DWORD, const char *, DWORD, int); |
|
82 |
typedef int (__stdcall *getaddrinfoProto)(const char *, const char *, const qt_addrinfo *, qt_addrinfo **); |
|
83 |
typedef int (__stdcall *freeaddrinfoProto)(qt_addrinfo *); |
|
84 |
static getnameinfoProto local_getnameinfo = 0; |
|
85 |
static getaddrinfoProto local_getaddrinfo = 0; |
|
86 |
static freeaddrinfoProto local_freeaddrinfo = 0; |
|
87 |
||
88 |
static void resolveLibrary() |
|
89 |
{ |
|
90 |
// Attempt to resolve getaddrinfo(); without it we'll have to fall |
|
91 |
// back to gethostbyname(), which has no IPv6 support. |
|
92 |
#if !defined(Q_OS_WINCE) |
|
93 |
local_getaddrinfo = (getaddrinfoProto) QLibrary::resolve(QLatin1String("ws2_32.dll"), "getaddrinfo"); |
|
94 |
local_freeaddrinfo = (freeaddrinfoProto) QLibrary::resolve(QLatin1String("ws2_32.dll"), "freeaddrinfo"); |
|
95 |
local_getnameinfo = (getnameinfoProto) QLibrary::resolve(QLatin1String("ws2_32.dll"), "getnameinfo"); |
|
96 |
#else |
|
97 |
local_getaddrinfo = (getaddrinfoProto) QLibrary::resolve(QLatin1String("ws2.dll"), "getaddrinfo"); |
|
98 |
local_freeaddrinfo = (freeaddrinfoProto) QLibrary::resolve(QLatin1String("ws2.dll"), "freeaddrinfo"); |
|
99 |
local_getnameinfo = (getnameinfoProto) QLibrary::resolve(QLatin1String("ws2.dll"), "getnameinfo"); |
|
100 |
#endif |
|
101 |
} |
|
102 |
||
103 |
#if defined(Q_OS_WINCE) |
|
104 |
#include <qmutex.h> |
|
105 |
QMutex qPrivCEMutex; |
|
106 |
#endif |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
107 |
|
0 | 108 |
QHostInfo QHostInfoAgent::fromName(const QString &hostName) |
109 |
{ |
|
110 |
#if defined(Q_OS_WINCE) |
|
111 |
QMutexLocker locker(&qPrivCEMutex); |
|
112 |
#endif |
|
113 |
QWindowsSockInit winSock; |
|
114 |
||
115 |
// Load res_init on demand. |
|
116 |
static volatile bool triedResolve = false; |
|
117 |
if (!triedResolve) { |
|
118 |
#ifndef QT_NO_THREAD |
|
119 |
QMutexLocker locker(QMutexPool::globalInstanceGet(&local_getaddrinfo)); |
|
120 |
#endif |
|
121 |
if (!triedResolve) { |
|
122 |
resolveLibrary(); |
|
123 |
triedResolve = true; |
|
124 |
} |
|
125 |
} |
|
126 |
||
127 |
QHostInfo results; |
|
128 |
||
129 |
#if defined(QHOSTINFO_DEBUG) |
|
130 |
qDebug("QHostInfoAgent::fromName(%p): looking up \"%s\" (IPv6 support is %s)", |
|
131 |
this, hostName.toLatin1().constData(), |
|
132 |
(local_getaddrinfo && local_freeaddrinfo) ? "enabled" : "disabled"); |
|
133 |
#endif |
|
134 |
||
135 |
QHostAddress address; |
|
136 |
if (address.setAddress(hostName)) { |
|
137 |
// Reverse lookup |
|
138 |
if (local_getnameinfo) { |
|
139 |
sockaddr_in sa4; |
|
140 |
qt_sockaddr_in6 sa6; |
|
141 |
sockaddr *sa; |
|
142 |
QT_SOCKLEN_T saSize; |
|
143 |
if (address.protocol() == QAbstractSocket::IPv4Protocol) { |
|
144 |
sa = (sockaddr *)&sa4; |
|
145 |
saSize = sizeof(sa4); |
|
146 |
memset(&sa4, 0, sizeof(sa4)); |
|
147 |
sa4.sin_family = AF_INET; |
|
148 |
sa4.sin_addr.s_addr = htonl(address.toIPv4Address()); |
|
149 |
} else { |
|
150 |
sa = (sockaddr *)&sa6; |
|
151 |
saSize = sizeof(sa6); |
|
152 |
memset(&sa6, 0, sizeof(sa6)); |
|
153 |
sa6.sin6_family = AF_INET6; |
|
154 |
memcpy(sa6.sin6_addr.qt_s6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr.qt_s6_addr)); |
|
155 |
} |
|
156 |
||
157 |
char hbuf[NI_MAXHOST]; |
|
158 |
if (local_getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0) |
|
159 |
results.setHostName(QString::fromLatin1(hbuf)); |
|
160 |
} else { |
|
161 |
unsigned long addr = inet_addr(hostName.toLatin1().constData()); |
|
162 |
struct hostent *ent = gethostbyaddr((const char*)&addr, sizeof(addr), AF_INET); |
|
163 |
if (ent) |
|
164 |
results.setHostName(QString::fromLatin1(ent->h_name)); |
|
165 |
} |
|
166 |
||
167 |
if (results.hostName().isEmpty()) |
|
168 |
results.setHostName(address.toString()); |
|
169 |
results.setAddresses(QList<QHostAddress>() << address); |
|
170 |
return results; |
|
171 |
} |
|
172 |
||
173 |
// IDN support |
|
174 |
QByteArray aceHostname = QUrl::toAce(hostName); |
|
175 |
results.setHostName(hostName); |
|
176 |
if (aceHostname.isEmpty()) { |
|
177 |
results.setError(QHostInfo::HostNotFound); |
|
178 |
results.setErrorString(hostName.isEmpty() ? tr("No host name given") : tr("Invalid hostname")); |
|
179 |
return results; |
|
180 |
} |
|
181 |
||
182 |
if (local_getaddrinfo && local_freeaddrinfo) { |
|
183 |
// Call getaddrinfo, and place all IPv4 addresses at the start |
|
184 |
// and the IPv6 addresses at the end of the address list in |
|
185 |
// results. |
|
186 |
qt_addrinfo *res; |
|
187 |
int err = local_getaddrinfo(aceHostname.constData(), 0, 0, &res); |
|
188 |
if (err == 0) { |
|
189 |
QList<QHostAddress> addresses; |
|
190 |
for (qt_addrinfo *p = res; p != 0; p = p->ai_next) { |
|
191 |
switch (p->ai_family) { |
|
192 |
case AF_INET: { |
|
193 |
QHostAddress addr; |
|
194 |
addr.setAddress(ntohl(((sockaddr_in *) p->ai_addr)->sin_addr.s_addr)); |
|
195 |
if (!addresses.contains(addr)) |
|
196 |
addresses.append(addr); |
|
197 |
} |
|
198 |
break; |
|
199 |
case AF_INET6: { |
|
200 |
QHostAddress addr; |
|
201 |
addr.setAddress(((qt_sockaddr_in6 *) p->ai_addr)->sin6_addr.qt_s6_addr); |
|
202 |
if (!addresses.contains(addr)) |
|
203 |
addresses.append(addr); |
|
204 |
} |
|
205 |
break; |
|
206 |
default: |
|
207 |
results.setError(QHostInfo::UnknownError); |
|
208 |
results.setErrorString(tr("Unknown address type")); |
|
209 |
} |
|
210 |
} |
|
211 |
results.setAddresses(addresses); |
|
212 |
local_freeaddrinfo(res); |
|
213 |
} else if (WSAGetLastError() == WSAHOST_NOT_FOUND || WSAGetLastError() == WSANO_DATA) { |
|
214 |
results.setError(QHostInfo::HostNotFound); |
|
215 |
results.setErrorString(tr("Host not found")); |
|
216 |
} else { |
|
217 |
results.setError(QHostInfo::UnknownError); |
|
218 |
results.setErrorString(tr("Unknown error")); |
|
219 |
} |
|
220 |
} else { |
|
221 |
// Fall back to gethostbyname, which only supports IPv4. |
|
222 |
hostent *ent = gethostbyname(aceHostname.constData()); |
|
223 |
if (ent) { |
|
224 |
char **p; |
|
225 |
QList<QHostAddress> addresses; |
|
226 |
switch (ent->h_addrtype) { |
|
227 |
case AF_INET: |
|
228 |
for (p = ent->h_addr_list; *p != 0; p++) { |
|
229 |
long *ip4Addr = (long *) *p; |
|
230 |
QHostAddress temp; |
|
231 |
temp.setAddress(ntohl(*ip4Addr)); |
|
232 |
addresses << temp; |
|
233 |
} |
|
234 |
break; |
|
235 |
default: |
|
236 |
results.setError(QHostInfo::UnknownError); |
|
237 |
results.setErrorString(tr("Unknown address type")); |
|
238 |
break; |
|
239 |
} |
|
240 |
results.setAddresses(addresses); |
|
241 |
} else if (WSAGetLastError() == 11001) { |
|
242 |
results.setErrorString(tr("Host not found")); |
|
243 |
results.setError(QHostInfo::HostNotFound); |
|
244 |
} else { |
|
245 |
results.setErrorString(tr("Unknown error")); |
|
246 |
results.setError(QHostInfo::UnknownError); |
|
247 |
} |
|
248 |
} |
|
249 |
||
250 |
#if defined(QHOSTINFO_DEBUG) |
|
251 |
if (results.error() != QHostInfo::NoError) { |
|
252 |
qDebug("QHostInfoAgent::run(%p): error (%s)", |
|
253 |
this, results.errorString().toLatin1().constData()); |
|
254 |
} else { |
|
255 |
QString tmp; |
|
256 |
QList<QHostAddress> addresses = results.addresses(); |
|
257 |
for (int i = 0; i < addresses.count(); ++i) { |
|
258 |
if (i != 0) tmp += ", "; |
|
259 |
tmp += addresses.at(i).toString(); |
|
260 |
} |
|
261 |
qDebug("QHostInfoAgent::run(%p): found %i entries: {%s}", |
|
262 |
this, addresses.count(), tmp.toLatin1().constData()); |
|
263 |
} |
|
264 |
#endif |
|
265 |
return results; |
|
266 |
} |
|
267 |
||
268 |
QString QHostInfo::localHostName() |
|
269 |
{ |
|
270 |
QWindowsSockInit winSock; |
|
271 |
||
272 |
char hostName[512]; |
|
273 |
if (gethostname(hostName, sizeof(hostName)) == -1) |
|
274 |
return QString(); |
|
275 |
hostName[sizeof(hostName) - 1] = '\0'; |
|
276 |
return QString::fromLocal8Bit(hostName); |
|
277 |
} |
|
278 |
||
279 |
// QString QHostInfo::localDomainName() defined in qnetworkinterface_win.cpp |
|
280 |
||
281 |
QT_END_NAMESPACE |