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