Qt 4.8
qhostinfo_win.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <winsock2.h>
43 
44 #include "qhostinfo_p.h"
45 #include "private/qnativesocketengine_p.h"
46 #include <ws2tcpip.h>
47 #include <private/qsystemlibrary_p.h>
48 #include <qurl.h>
49 
51 
52 //#define QHOSTINFO_DEBUG
53 
54 // Older SDKs do not include the addrinfo struct declaration, so we
55 // include a copy of it here.
57 {
58  int ai_flags;
59  int ai_family;
62  size_t ai_addrlen;
63  char *ai_canonname;
64  sockaddr *ai_addr;
66 };
67 
68 //###
69 #define QT_SOCKLEN_T int
70 #ifndef NI_MAXHOST // already defined to 1025 in ws2tcpip.h?
71 #define NI_MAXHOST 1024
72 #endif
73 
74 typedef int (__stdcall *getnameinfoProto)(const sockaddr *, QT_SOCKLEN_T, const char *, DWORD, const char *, DWORD, int);
75 typedef int (__stdcall *getaddrinfoProto)(const char *, const char *, const qt_addrinfo *, qt_addrinfo **);
76 typedef int (__stdcall *freeaddrinfoProto)(qt_addrinfo *);
80 
81 static void resolveLibrary()
82 {
83  // Attempt to resolve getaddrinfo(); without it we'll have to fall
84  // back to gethostbyname(), which has no IPv6 support.
85  static bool triedResolve = false;
86  if (triedResolve)
87  return;
88 
89 #if !defined(Q_OS_WINCE)
90  QSystemLibrary ws2lib(QLatin1String("ws2_32"));
91 #else
92  QSystemLibrary ws2lib(QLatin1String("ws2"));
93 #endif
94  if (ws2lib.load()) {
95  local_getaddrinfo = (getaddrinfoProto)ws2lib.resolve("getaddrinfo");
96  local_freeaddrinfo = (freeaddrinfoProto)ws2lib.resolve("freeaddrinfo");
97  local_getnameinfo = (getnameinfoProto)ws2lib.resolve("getnameinfo");
98  }
99 
100  triedResolve = true;
101 }
102 
103 #if defined(Q_OS_WINCE)
104 #include <qmutex.h>
105 Q_GLOBAL_STATIC(QMutex, qPrivCEMutex)
106 #endif
107 
108 static void translateWSAError(int error, QHostInfo *results)
109 {
110  switch (error) {
111  case WSAHOST_NOT_FOUND: //authoritative not found
112  case WSATRY_AGAIN: //non authoritative not found
113  case WSANO_DATA: //valid name, no associated address
115  results->setErrorString(QHostInfoAgent::tr("Host not found"));
116  return;
117  default:
119  results->setErrorString(QHostInfoAgent::tr("Unknown error (%1)").arg(error));
120  return;
121  }
122 }
123 
125 {
126  resolveLibrary();
127 
128 #if defined(Q_OS_WINCE)
129  QMutexLocker locker(qPrivCEMutex());
130 #endif
131 
132  QWindowsSockInit winSock;
133 
134  QHostInfo results;
135 
136 #if defined(QHOSTINFO_DEBUG)
137  qDebug("QHostInfoAgent::fromName(%p): looking up \"%s\" (IPv6 support is %s)",
138  this, hostName.toLatin1().constData(),
139  (local_getaddrinfo && local_freeaddrinfo) ? "enabled" : "disabled");
140 #endif
141 
142  QHostAddress address;
143  if (address.setAddress(hostName)) {
144  // Reverse lookup
145  if (local_getnameinfo) {
146  sockaddr_in sa4;
147  qt_sockaddr_in6 sa6;
148  sockaddr *sa;
149  QT_SOCKLEN_T saSize;
150  if (address.protocol() == QAbstractSocket::IPv4Protocol) {
151  sa = (sockaddr *)&sa4;
152  saSize = sizeof(sa4);
153  memset(&sa4, 0, sizeof(sa4));
154  sa4.sin_family = AF_INET;
155  sa4.sin_addr.s_addr = htonl(address.toIPv4Address());
156  } else {
157  sa = (sockaddr *)&sa6;
158  saSize = sizeof(sa6);
159  memset(&sa6, 0, sizeof(sa6));
160  sa6.sin6_family = AF_INET6;
161  memcpy(sa6.sin6_addr.qt_s6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr.qt_s6_addr));
162  }
163 
164  char hbuf[NI_MAXHOST];
165  if (local_getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0)
166  results.setHostName(QString::fromLatin1(hbuf));
167  } else {
168  unsigned long addr = inet_addr(hostName.toLatin1().constData());
169  struct hostent *ent = gethostbyaddr((const char*)&addr, sizeof(addr), AF_INET);
170  if (ent)
171  results.setHostName(QString::fromLatin1(ent->h_name));
172  }
173 
174  if (results.hostName().isEmpty())
175  results.setHostName(address.toString());
176  results.setAddresses(QList<QHostAddress>() << address);
177  return results;
178  }
179 
180  // IDN support
181  QByteArray aceHostname = QUrl::toAce(hostName);
182  results.setHostName(hostName);
183  if (aceHostname.isEmpty()) {
185  results.setErrorString(hostName.isEmpty() ? tr("No host name given") : tr("Invalid hostname"));
186  return results;
187  }
188 
190  // Call getaddrinfo, and place all IPv4 addresses at the start
191  // and the IPv6 addresses at the end of the address list in
192  // results.
193  qt_addrinfo *res;
194  int err = local_getaddrinfo(aceHostname.constData(), 0, 0, &res);
195  if (err == 0) {
196  QList<QHostAddress> addresses;
197  for (qt_addrinfo *p = res; p != 0; p = p->ai_next) {
198  switch (p->ai_family) {
199  case AF_INET: {
200  QHostAddress addr;
201  addr.setAddress(ntohl(((sockaddr_in *) p->ai_addr)->sin_addr.s_addr));
202  if (!addresses.contains(addr))
203  addresses.append(addr);
204  }
205  break;
206  case AF_INET6: {
207  QHostAddress addr;
208  addr.setAddress(((qt_sockaddr_in6 *) p->ai_addr)->sin6_addr.qt_s6_addr);
209  if (!addresses.contains(addr))
210  addresses.append(addr);
211  }
212  break;
213  default:
215  results.setErrorString(tr("Unknown address type"));
216  }
217  }
218  results.setAddresses(addresses);
219  local_freeaddrinfo(res);
220  } else {
221  translateWSAError(WSAGetLastError(), &results);
222  }
223  } else {
224  // Fall back to gethostbyname, which only supports IPv4.
225  hostent *ent = gethostbyname(aceHostname.constData());
226  if (ent) {
227  char **p;
228  QList<QHostAddress> addresses;
229  switch (ent->h_addrtype) {
230  case AF_INET:
231  for (p = ent->h_addr_list; *p != 0; p++) {
232  long *ip4Addr = (long *) *p;
233  QHostAddress temp;
234  temp.setAddress(ntohl(*ip4Addr));
235  addresses << temp;
236  }
237  break;
238  default:
240  results.setErrorString(tr("Unknown address type"));
241  break;
242  }
243  results.setAddresses(addresses);
244  } else {
245  translateWSAError(WSAGetLastError(), &results);
246  }
247  }
248 
249 #if defined(QHOSTINFO_DEBUG)
250  if (results.error() != QHostInfo::NoError) {
251  qDebug("QHostInfoAgent::run(%p): error (%s)",
252  this, results.errorString().toLatin1().constData());
253  } else {
254  QString tmp;
255  QList<QHostAddress> addresses = results.addresses();
256  for (int i = 0; i < addresses.count(); ++i) {
257  if (i != 0) tmp += ", ";
258  tmp += addresses.at(i).toString();
259  }
260  qDebug("QHostInfoAgent::run(%p): found %i entries: {%s}",
261  this, addresses.count(), tmp.toLatin1().constData());
262  }
263 #endif
264  return results;
265 }
266 
268 {
269  QWindowsSockInit winSock;
270 
271  char hostName[512];
272  if (gethostname(hostName, sizeof(hostName)) == -1)
273  return QString();
274  hostName[sizeof(hostName) - 1] = '\0';
275  return QString::fromLocal8Bit(hostName);
276 }
277 
278 // QString QHostInfo::localDomainName() defined in qnetworkinterface_win.cpp
279 
quint8 c[16]
Definition: qhostaddress.h:65
static QString fromLocal8Bit(const char *, int size=-1)
Returns a QString initialized with the first size characters of the 8-bit string str.
Definition: qstring.cpp:4245
Q_IPV6ADDR toIPv6Address() const
Returns the IPv6 address as a Q_IPV6ADDR structure.
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
The QMutex class provides access serialization between threads.
Definition: qmutex.h:60
qt_addrinfo * ai_next
void setErrorString(const QString &errorString)
Sets the human readable description of the error that occurred to str if the lookup failed...
Definition: qhostinfo.cpp:465
sockaddr * ai_addr
#define error(msg)
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
static freeaddrinfoProto local_freeaddrinfo
static QString tr(const char *sourceText, const char *comment=0, int n=-1)
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
HostInfoError error() const
Returns the type of error that occurred if the host name lookup failed; otherwise returns NoError...
Definition: qhostinfo.cpp:413
struct qt_in6_addr sin6_addr
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
quint32 toIPv4Address() const
Returns the IPv4 address as a number.
The QString class provides a Unicode character string.
Definition: qstring.h:83
bool load(bool onlySystemDirectory=true)
QList< QHostAddress > addresses() const
Returns the list of IP addresses associated with hostName().
Definition: qhostinfo.cpp:372
#define QT_SOCKLEN_T
Q_CORE_EXPORT void qDebug(const char *,...)
int(__stdcall * getaddrinfoProto)(const char *, const char *, const qt_addrinfo *, qt_addrinfo **)
static QByteArray toAce(const QString &)
Returns the ASCII Compatible Encoding of the given domain name domain.
Definition: qurl.cpp:6158
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QBool contains(const T &t) const
Returns true if the list contains an occurrence of value; otherwise returns false.
Definition: qlist.h:880
void setHostName(const QString &name)
Sets the host name of this QHostInfo to hostName.
Definition: qhostinfo.cpp:402
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
void setAddresses(const QList< QHostAddress > &addresses)
Sets the list of addresses in this QHostInfo to addresses.
Definition: qhostinfo.cpp:382
QString hostName() const
Returns the name of the host whose IP addresses were looked up.
Definition: qhostinfo.cpp:392
static getnameinfoProto local_getnameinfo
#define Q_GLOBAL_STATIC(TYPE, NAME)
Declares a global static variable with the given type and name.
Definition: qglobal.h:1968
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
The QHostInfo class provides static functions for host name lookups.
Definition: qhostinfo.h:58
char * ai_canonname
QString toString() const
Returns the address as a string.
static QString localHostName()
Returns the host name of this machine.
QByteArray toLatin1() const Q_REQUIRED_RESULT
Returns a Latin-1 representation of the string as a QByteArray.
Definition: qstring.cpp:3993
int(__stdcall * freeaddrinfoProto)(qt_addrinfo *)
size_t ai_addrlen
void setError(HostInfoError error)
Sets the error type of this QHostInfo to error.
Definition: qhostinfo.cpp:423
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
static getaddrinfoProto local_getaddrinfo
static void resolveLibrary()
The QMutexLocker class is a convenience class that simplifies locking and unlocking mutexes...
Definition: qmutex.h:101
void * resolve(const char *symbol)
QAbstractSocket::NetworkLayerProtocol protocol() const
Returns the network layer protocol of the host address.
void setAddress(quint32 ip4Addr)
Set the IPv4 address specified by ip4Addr.
u_char qt_s6_addr[16]
#define NI_MAXHOST
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
static void translateWSAError(int error, QHostInfo *results)
QString errorString() const
If the lookup failed, this function returns a human readable description of the error; otherwise "Unk...
Definition: qhostinfo.cpp:454
bool isEmpty() const
Returns true if the byte array has size 0; otherwise returns false.
Definition: qbytearray.h:421
The QHostAddress class provides an IP address.
Definition: qhostaddress.h:70
static QHostInfo fromName(const QString &hostName)
int(__stdcall * getnameinfoProto)(const sockaddr *, QT_SOCKLEN_T, const char *, DWORD, const char *, DWORD, int)
#define AF_INET6