source: trunk/src/network/kernel/qhostinfo_win.cpp@ 67

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

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

File size: 10.9 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#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 <qtimer.h>
54#include <qmutex.h>
55#include <private/qmutexpool_p.h>
56
57QT_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.
63struct 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// sockaddr_in6 size changed between old and new SDK
76// Only the new version is the correct one, so always
77// use this structure.
78struct qt_in6_addr {
79 uchar qt_s6_addr[16];
80};
81
82struct qt_sockaddr_in6 {
83 short sin6_family; /* AF_INET6 */
84 u_short sin6_port; /* Transport level port number */
85 u_long sin6_flowinfo; /* IPv6 flow information */
86 struct qt_in6_addr sin6_addr; /* IPv6 address */
87 u_long sin6_scope_id; /* set of interfaces for a scope */
88};
89
90//###
91#define QT_SOCKLEN_T int
92#ifndef NI_MAXHOST // already defined to 1025 in ws2tcpip.h?
93#define NI_MAXHOST 1024
94#endif
95
96typedef int (__stdcall *getnameinfoProto)(const sockaddr *, QT_SOCKLEN_T, const char *, DWORD, const char *, DWORD, int);
97typedef int (__stdcall *getaddrinfoProto)(const char *, const char *, const qt_addrinfo *, qt_addrinfo **);
98typedef int (__stdcall *freeaddrinfoProto)(qt_addrinfo *);
99static getnameinfoProto local_getnameinfo = 0;
100static getaddrinfoProto local_getaddrinfo = 0;
101static freeaddrinfoProto local_freeaddrinfo = 0;
102
103static void resolveLibrary()
104{
105 // Attempt to resolve getaddrinfo(); without it we'll have to fall
106 // back to gethostbyname(), which has no IPv6 support.
107#if !defined(Q_OS_WINCE)
108 local_getaddrinfo = (getaddrinfoProto) QLibrary::resolve(QLatin1String("ws2_32.dll"), "getaddrinfo");
109 local_freeaddrinfo = (freeaddrinfoProto) QLibrary::resolve(QLatin1String("ws2_32.dll"), "freeaddrinfo");
110 local_getnameinfo = (getnameinfoProto) QLibrary::resolve(QLatin1String("ws2_32.dll"), "getnameinfo");
111#else
112 local_getaddrinfo = (getaddrinfoProto) QLibrary::resolve(QLatin1String("ws2.dll"), "getaddrinfo");
113 local_freeaddrinfo = (freeaddrinfoProto) QLibrary::resolve(QLatin1String("ws2.dll"), "freeaddrinfo");
114 local_getnameinfo = (getnameinfoProto) QLibrary::resolve(QLatin1String("ws2.dll"), "getnameinfo");
115#endif
116}
117
118#if defined(Q_OS_WINCE)
119#include <qmutex.h>
120QMutex qPrivCEMutex;
121#endif
122/*
123 Performs a blocking call to gethostbyname or getaddrinfo, stores
124 the results in a QHostInfo structure and emits the
125 resultsReady() signal.
126*/
127QHostInfo QHostInfoAgent::fromName(const QString &hostName)
128{
129#if defined(Q_OS_WINCE)
130 QMutexLocker locker(&qPrivCEMutex);
131#endif
132 QWindowsSockInit winSock;
133
134 // Load res_init on demand.
135 static volatile bool triedResolve = false;
136 if (!triedResolve) {
137#ifndef QT_NO_THREAD
138 QMutexLocker locker(QMutexPool::globalInstanceGet(&local_getaddrinfo));
139#endif
140 if (!triedResolve) {
141 resolveLibrary();
142 triedResolve = true;
143 }
144 }
145
146 QHostInfo results;
147 results.setHostName(hostName);
148
149#if defined(QHOSTINFO_DEBUG)
150 qDebug("QHostInfoAgent::fromName(%p): looking up \"%s\" (IPv6 support is %s)",
151 this, hostName.toLatin1().constData(),
152 (local_getaddrinfo && local_freeaddrinfo) ? "enabled" : "disabled");
153#endif
154
155 QHostAddress address;
156 if (address.setAddress(hostName)) {
157 // Reverse lookup
158 if (local_getnameinfo) {
159 sockaddr_in sa4;
160 qt_sockaddr_in6 sa6;
161 sockaddr *sa;
162 QT_SOCKLEN_T saSize;
163 if (address.protocol() == QAbstractSocket::IPv4Protocol) {
164 sa = (sockaddr *)&sa4;
165 saSize = sizeof(sa4);
166 memset(&sa4, 0, sizeof(sa4));
167 sa4.sin_family = AF_INET;
168 sa4.sin_addr.s_addr = htonl(address.toIPv4Address());
169 } else {
170 sa = (sockaddr *)&sa6;
171 saSize = sizeof(sa6);
172 memset(&sa6, 0, sizeof(sa6));
173 sa6.sin6_family = AF_INET6;
174 memcpy(sa6.sin6_addr.qt_s6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr.qt_s6_addr));
175 }
176
177 char hbuf[NI_MAXHOST];
178 if (local_getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) != 0) {
179 results.setError(QHostInfo::HostNotFound);
180 results.setErrorString(tr("Host not found"));
181 return results;
182 }
183 results.setHostName(QString::fromLatin1(hbuf));
184 } else {
185 unsigned long addr = inet_addr(hostName.toLatin1().constData());
186 struct hostent *ent = gethostbyaddr((const char*)&addr, sizeof(addr), AF_INET);
187 if (!ent) {
188 results.setError(QHostInfo::HostNotFound);
189 results.setErrorString(tr("Host not found"));
190 return results;
191 }
192 results.setHostName(QString::fromLatin1(ent->h_name));
193 }
194 }
195
196 if (local_getaddrinfo && local_freeaddrinfo) {
197 // Call getaddrinfo, and place all IPv4 addresses at the start
198 // and the IPv6 addresses at the end of the address list in
199 // results.
200 qt_addrinfo *res;
201 int err = local_getaddrinfo(hostName.toLatin1().constData(), 0, 0, &res);
202 if (err == 0) {
203 QList<QHostAddress> addresses;
204 for (qt_addrinfo *p = res; p != 0; p = p->ai_next) {
205 switch (p->ai_family) {
206 case AF_INET: {
207 QHostAddress addr;
208 addr.setAddress(ntohl(((sockaddr_in *) p->ai_addr)->sin_addr.s_addr));
209 if (!addresses.contains(addr))
210 addresses.append(addr);
211 }
212 break;
213 case AF_INET6: {
214 QHostAddress addr;
215 addr.setAddress(((qt_sockaddr_in6 *) p->ai_addr)->sin6_addr.qt_s6_addr);
216 if (!addresses.contains(addr))
217 addresses.append(addr);
218 }
219 break;
220 default:
221 results.setError(QHostInfo::UnknownError);
222 results.setErrorString(tr("Unknown address type"));
223 }
224 }
225 results.setAddresses(addresses);
226 local_freeaddrinfo(res);
227 } else if (WSAGetLastError() == WSAHOST_NOT_FOUND || WSAGetLastError() == WSANO_DATA) {
228 results.setError(QHostInfo::HostNotFound);
229 results.setErrorString(tr("Host not found"));
230 } else {
231 results.setError(QHostInfo::UnknownError);
232 results.setErrorString(tr("Unknown error"));
233 }
234 } else {
235 // Fall back to gethostbyname, which only supports IPv4.
236 hostent *ent = gethostbyname(hostName.toLatin1().constData());
237 if (ent) {
238 char **p;
239 QList<QHostAddress> addresses;
240 switch (ent->h_addrtype) {
241 case AF_INET:
242 for (p = ent->h_addr_list; *p != 0; p++) {
243 long *ip4Addr = (long *) *p;
244 QHostAddress temp;
245 temp.setAddress(ntohl(*ip4Addr));
246 addresses << temp;
247 }
248 break;
249 default:
250 results.setError(QHostInfo::UnknownError);
251 results.setErrorString(tr("Unknown address type"));
252 break;
253 }
254 results.setAddresses(addresses);
255 } else if (WSAGetLastError() == 11001) {
256 results.setErrorString(tr("Host not found"));
257 results.setError(QHostInfo::HostNotFound);
258 } else {
259 results.setErrorString(tr("Unknown error"));
260 results.setError(QHostInfo::UnknownError);
261 }
262 }
263
264#if defined(QHOSTINFO_DEBUG)
265 if (results.error() != QHostInfo::NoError) {
266 qDebug("QHostInfoAgent::run(%p): error (%s)",
267 this, results.errorString().toLatin1().constData());
268 } else {
269 QString tmp;
270 QList<QHostAddress> addresses = results.addresses();
271 for (int i = 0; i < addresses.count(); ++i) {
272 if (i != 0) tmp += ", ";
273 tmp += addresses.at(i).toString();
274 }
275 qDebug("QHostInfoAgent::run(%p): found %i entries: {%s}",
276 this, addresses.count(), tmp.toLatin1().constData());
277 }
278#endif
279 return results;
280}
281
282QString QHostInfo::localHostName()
283{
284 QWindowsSockInit winSock;
285
286 char hostName[512];
287 if (gethostname(hostName, sizeof(hostName)) == -1)
288 return QString();
289 hostName[sizeof(hostName) - 1] = '\0';
290 return QString::fromLocal8Bit(hostName);
291}
292
293// QString QHostInfo::localDomainName() defined in qnetworkinterface_win.cpp
294
295QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.