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

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 10.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
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** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** 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 have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
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 <private/qsystemlibrary_p.h>
53#include <qmutex.h>
54#include <qurl.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//###
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
81typedef int (__stdcall *getnameinfoProto)(const sockaddr *, QT_SOCKLEN_T, const char *, DWORD, const char *, DWORD, int);
82typedef int (__stdcall *getaddrinfoProto)(const char *, const char *, const qt_addrinfo *, qt_addrinfo **);
83typedef int (__stdcall *freeaddrinfoProto)(qt_addrinfo *);
84static getnameinfoProto local_getnameinfo = 0;
85static getaddrinfoProto local_getaddrinfo = 0;
86static freeaddrinfoProto local_freeaddrinfo = 0;
87
88static 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) QSystemLibrary::resolve(QLatin1String("ws2_32"), "getaddrinfo");
94 local_freeaddrinfo = (freeaddrinfoProto) QSystemLibrary::resolve(QLatin1String("ws2_32"), "freeaddrinfo");
95 local_getnameinfo = (getnameinfoProto) QSystemLibrary::resolve(QLatin1String("ws2_32"), "getnameinfo");
96#else
97 local_getaddrinfo = (getaddrinfoProto) QSystemLibrary::resolve(QLatin1String("ws2"), "getaddrinfo");
98 local_freeaddrinfo = (freeaddrinfoProto) QSystemLibrary::resolve(QLatin1String("ws2"), "freeaddrinfo");
99 local_getnameinfo = (getnameinfoProto) QSystemLibrary::resolve(QLatin1String("ws2"), "getnameinfo");
100#endif
101}
102
103#if defined(Q_OS_WINCE)
104#include <qmutex.h>
105QMutex qPrivCEMutex;
106#endif
107
108QHostInfo 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
268QString 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
281QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.