util/src/network/kernel/qhostinfo.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 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 #include "qhostinfo.h"
       
    43 #include "qhostinfo_p.h"
       
    44 
       
    45 #include "QtCore/qscopedpointer.h"
       
    46 #include <qabstracteventdispatcher.h>
       
    47 #include <private/qunicodetables_p.h>
       
    48 #include <qcoreapplication.h>
       
    49 #include <qmetaobject.h>
       
    50 #include <qregexp.h>
       
    51 #include <private/qnativesocketengine_p.h>
       
    52 #include <qstringlist.h>
       
    53 #include <qthread.h>
       
    54 #include <qtimer.h>
       
    55 #include <qurl.h>
       
    56 
       
    57 #ifdef Q_OS_UNIX
       
    58 #  include <unistd.h>
       
    59 #endif
       
    60 
       
    61 QT_BEGIN_NAMESPACE
       
    62 
       
    63 #ifndef QT_NO_THREAD
       
    64 Q_GLOBAL_STATIC(QHostInfoLookupManager, theHostInfoLookupManager)
       
    65 #endif
       
    66 
       
    67 //#define QHOSTINFO_DEBUG
       
    68 
       
    69 /*!
       
    70     \class QHostInfo
       
    71     \brief The QHostInfo class provides static functions for host name lookups.
       
    72 
       
    73     \reentrant
       
    74     \inmodule QtNetwork
       
    75     \ingroup network
       
    76 
       
    77     QHostInfo uses the lookup mechanisms provided by the operating
       
    78     system to find the IP address(es) associated with a host name,
       
    79     or the host name associated with an IP address.
       
    80     The class provides two static convenience functions: one that
       
    81     works asynchronously and emits a signal once the host is found,
       
    82     and one that blocks and returns a QHostInfo object.
       
    83 
       
    84     To look up a host's IP addresses asynchronously, call lookupHost(),
       
    85     which takes the host name or IP address, a receiver object, and a slot
       
    86     signature as arguments and returns an ID. You can abort the
       
    87     lookup by calling abortHostLookup() with the lookup ID.
       
    88 
       
    89     Example:
       
    90 
       
    91     \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 0
       
    92 
       
    93 
       
    94     The slot is invoked when the results are ready. (If you use
       
    95     Qt for Embedded Linux and disabled multithreading support by defining
       
    96     \c QT_NO_THREAD, lookupHost() will block until the lookup has
       
    97     finished.) The results are stored in a QHostInfo object. Call
       
    98     addresses() to get the list of IP addresses for the host, and
       
    99     hostName() to get the host name that was looked up.
       
   100 
       
   101     If the lookup failed, error() returns the type of error that
       
   102     occurred. errorString() gives a human-readable description of the
       
   103     lookup error.
       
   104 
       
   105     If you want a blocking lookup, use the QHostInfo::fromName() function:
       
   106 
       
   107     \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 1
       
   108 
       
   109     QHostInfo supports Internationalized Domain Names (IDNs) through the
       
   110     IDNA and Punycode standards.
       
   111 
       
   112     To retrieve the name of the local host, use the static
       
   113     QHostInfo::localHostName() function.
       
   114 
       
   115     \note Since Qt 4.6.1 QHostInfo is using multiple threads for DNS lookup
       
   116     instead of one dedicated DNS thread. This improves performance,
       
   117     but also changes the order of signal emissions when using lookupHost()
       
   118     compared to previous versions of Qt.
       
   119     \note Since Qt 4.6.3 QHostInfo is using a small internal 60 second DNS cache
       
   120     for performance improvements.
       
   121 
       
   122     \sa QAbstractSocket, {http://www.rfc-editor.org/rfc/rfc3492.txt}{RFC 3492}
       
   123 */
       
   124 
       
   125 static QBasicAtomicInt theIdCounter = Q_BASIC_ATOMIC_INITIALIZER(1);
       
   126 
       
   127 /*!
       
   128     Looks up the IP address(es) associated with host name \a name, and
       
   129     returns an ID for the lookup. When the result of the lookup is
       
   130     ready, the slot or signal \a member in \a receiver is called with
       
   131     a QHostInfo argument. The QHostInfo object can then be inspected
       
   132     to get the results of the lookup.
       
   133 
       
   134     The lookup is performed by a single function call, for example:
       
   135 
       
   136     \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 2
       
   137 
       
   138     The implementation of the slot prints basic information about the
       
   139     addresses returned by the lookup, or reports an error if it failed:
       
   140 
       
   141     \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 3
       
   142 
       
   143     If you pass a literal IP address to \a name instead of a host name,
       
   144     QHostInfo will search for the domain name for the IP (i.e., QHostInfo will
       
   145     perform a \e reverse lookup). On success, the resulting QHostInfo will
       
   146     contain both the resolved domain name and IP addresses for the host
       
   147     name. Example:
       
   148 
       
   149     \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 4
       
   150 
       
   151     \note There is no guarantee on the order the signals will be emitted
       
   152     if you start multiple requests with lookupHost().
       
   153 
       
   154     \sa abortHostLookup(), addresses(), error(), fromName()
       
   155 */
       
   156 int QHostInfo::lookupHost(const QString &name, QObject *receiver,
       
   157                           const char *member)
       
   158 {
       
   159 #if defined QHOSTINFO_DEBUG
       
   160     qDebug("QHostInfo::lookupHost(\"%s\", %p, %s)",
       
   161            name.toLatin1().constData(), receiver, member ? member + 1 : 0);
       
   162 #endif
       
   163     if (!QAbstractEventDispatcher::instance(QThread::currentThread())) {
       
   164         qWarning("QHostInfo::lookupHost() called with no event dispatcher");
       
   165         return -1;
       
   166     }
       
   167 
       
   168     qRegisterMetaType<QHostInfo>("QHostInfo");
       
   169 
       
   170     int id = theIdCounter.fetchAndAddRelaxed(1); // generate unique ID
       
   171 
       
   172     if (name.isEmpty()) {
       
   173         QHostInfo hostInfo(id);
       
   174         hostInfo.setError(QHostInfo::HostNotFound);
       
   175         hostInfo.setErrorString(QObject::tr("No host name given"));
       
   176         QScopedPointer<QHostInfoResult> result(new QHostInfoResult);
       
   177         QObject::connect(result.data(), SIGNAL(resultsReady(QHostInfo)),
       
   178                          receiver, member, Qt::QueuedConnection);
       
   179         result.data()->emitResultsReady(hostInfo);
       
   180         return id;
       
   181     }
       
   182 
       
   183 #ifdef QT_NO_THREAD
       
   184     QHostInfo hostInfo = QHostInfoAgent::fromName(name);
       
   185     hostInfo.setLookupId(id);
       
   186     QScopedPointer<QHostInfoResult> result(new QHostInfoResult);
       
   187     QObject::connect(result.data(), SIGNAL(resultsReady(QHostInfo)),
       
   188                      receiver, member, Qt::QueuedConnection);
       
   189     result.data()->emitResultsReady(hostInfo);
       
   190 #else
       
   191     QHostInfoLookupManager *manager = theHostInfoLookupManager();
       
   192     if (manager) {
       
   193         // the application is still alive
       
   194         if (manager->cache.isEnabled()) {
       
   195             // check cache first
       
   196             bool valid = false;
       
   197             QHostInfo info = manager->cache.get(name, &valid);
       
   198             if (valid) {
       
   199                 info.setLookupId(id);
       
   200                 QHostInfoResult result;
       
   201                 QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection);
       
   202                 result.emitResultsReady(info);
       
   203                 return id;
       
   204             }
       
   205         }
       
   206         // cache is not enabled or it was not in the cache, do normal lookup
       
   207         QHostInfoRunnable* runnable = new QHostInfoRunnable(name, id);
       
   208         QObject::connect(&runnable->resultEmitter, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection);
       
   209         manager->scheduleLookup(runnable);
       
   210     }
       
   211 #endif
       
   212 
       
   213     return id;
       
   214 }
       
   215 
       
   216 /*!
       
   217     Aborts the host lookup with the ID \a id, as returned by lookupHost().
       
   218 
       
   219     \sa lookupHost(), lookupId()
       
   220 */
       
   221 void QHostInfo::abortHostLookup(int id)
       
   222 {
       
   223 #ifndef QT_NO_THREAD
       
   224     theHostInfoLookupManager()->abortLookup(id);
       
   225 #else
       
   226     // we cannot abort if it was non threaded.. the result signal has already been posted
       
   227     Q_UNUSED(id);
       
   228 #endif
       
   229 }
       
   230 
       
   231 /*!
       
   232     Looks up the IP address(es) for the given host \a name. The
       
   233     function blocks during the lookup which means that execution of
       
   234     the program is suspended until the results of the lookup are
       
   235     ready. Returns the result of the lookup in a QHostInfo object.
       
   236 
       
   237     If you pass a literal IP address to \a name instead of a host name,
       
   238     QHostInfo will search for the domain name for the IP (i.e., QHostInfo will
       
   239     perform a \e reverse lookup). On success, the returned QHostInfo will
       
   240     contain both the resolved domain name and IP addresses for the host name.
       
   241 
       
   242     \sa lookupHost()
       
   243 */
       
   244 QHostInfo QHostInfo::fromName(const QString &name)
       
   245 {
       
   246 #if defined QHOSTINFO_DEBUG
       
   247     qDebug("QHostInfo::fromName(\"%s\")",name.toLatin1().constData());
       
   248 #endif
       
   249 
       
   250     return QHostInfoAgent::fromName(name);
       
   251 }
       
   252 
       
   253 /*!
       
   254     \enum QHostInfo::HostInfoError
       
   255 
       
   256     This enum describes the various errors that can occur when trying
       
   257     to resolve a host name.
       
   258 
       
   259     \value NoError The lookup was successful.
       
   260     \value HostNotFound No IP addresses were found for the host.
       
   261     \value UnknownError An unknown error occurred.
       
   262 
       
   263     \sa error(), setError()
       
   264 */
       
   265 
       
   266 /*!
       
   267     Constructs an empty host info object with lookup ID \a id.
       
   268 
       
   269     \sa lookupId()
       
   270 */
       
   271 QHostInfo::QHostInfo(int id)
       
   272     : d(new QHostInfoPrivate)
       
   273 {
       
   274     d->lookupId = id;
       
   275 }
       
   276 
       
   277 /*!
       
   278     Constructs a copy of \a other.
       
   279 */
       
   280 QHostInfo::QHostInfo(const QHostInfo &other)
       
   281     : d(new QHostInfoPrivate(*other.d.data()))
       
   282 {
       
   283 }
       
   284 
       
   285 /*!
       
   286     Assigns the data of the \a other object to this host info object,
       
   287     and returns a reference to it.
       
   288 */
       
   289 QHostInfo &QHostInfo::operator=(const QHostInfo &other)
       
   290 {
       
   291     *d.data() = *other.d.data();
       
   292     return *this;
       
   293 }
       
   294 
       
   295 /*!
       
   296     Destroys the host info object.
       
   297 */
       
   298 QHostInfo::~QHostInfo()
       
   299 {
       
   300 }
       
   301 
       
   302 /*!
       
   303     Returns the list of IP addresses associated with hostName(). This
       
   304     list may be empty.
       
   305 
       
   306     Example:
       
   307 
       
   308     \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 5
       
   309 
       
   310     \sa hostName(), error()
       
   311 */
       
   312 QList<QHostAddress> QHostInfo::addresses() const
       
   313 {
       
   314     return d->addrs;
       
   315 }
       
   316 
       
   317 /*!
       
   318     Sets the list of addresses in this QHostInfo to \a addresses.
       
   319 
       
   320     \sa addresses()
       
   321 */
       
   322 void QHostInfo::setAddresses(const QList<QHostAddress> &addresses)
       
   323 {
       
   324     d->addrs = addresses;
       
   325 }
       
   326 
       
   327 /*!
       
   328     Returns the name of the host whose IP addresses were looked up.
       
   329 
       
   330     \sa localHostName()
       
   331 */
       
   332 QString QHostInfo::hostName() const
       
   333 {
       
   334     return d->hostName;
       
   335 }
       
   336 
       
   337 /*!
       
   338     Sets the host name of this QHostInfo to \a hostName.
       
   339 
       
   340     \sa hostName()
       
   341 */
       
   342 void QHostInfo::setHostName(const QString &hostName)
       
   343 {
       
   344     d->hostName = hostName;
       
   345 }
       
   346 
       
   347 /*!
       
   348     Returns the type of error that occurred if the host name lookup
       
   349     failed; otherwise returns NoError.
       
   350 
       
   351     \sa setError(), errorString()
       
   352 */
       
   353 QHostInfo::HostInfoError QHostInfo::error() const
       
   354 {
       
   355     return d->err;
       
   356 }
       
   357 
       
   358 /*!
       
   359     Sets the error type of this QHostInfo to \a error.
       
   360 
       
   361     \sa error(), errorString()
       
   362 */
       
   363 void QHostInfo::setError(HostInfoError error)
       
   364 {
       
   365     d->err = error;
       
   366 }
       
   367 
       
   368 /*!
       
   369     Returns the ID of this lookup.
       
   370 
       
   371     \sa setLookupId(), abortHostLookup(), hostName()
       
   372 */
       
   373 int QHostInfo::lookupId() const
       
   374 {
       
   375     return d->lookupId;
       
   376 }
       
   377 
       
   378 /*!
       
   379     Sets the ID of this lookup to \a id.
       
   380 
       
   381     \sa lookupId(), lookupHost()
       
   382 */
       
   383 void QHostInfo::setLookupId(int id)
       
   384 {
       
   385     d->lookupId = id;
       
   386 }
       
   387 
       
   388 /*!
       
   389     If the lookup failed, this function returns a human readable
       
   390     description of the error; otherwise "Unknown error" is returned.
       
   391 
       
   392     \sa setErrorString(), error()
       
   393 */
       
   394 QString QHostInfo::errorString() const
       
   395 {
       
   396     return d->errorStr;
       
   397 }
       
   398 
       
   399 /*!
       
   400     Sets the human readable description of the error that occurred to \a str
       
   401     if the lookup failed.
       
   402 
       
   403     \sa errorString(), setError()
       
   404 */
       
   405 void QHostInfo::setErrorString(const QString &str)
       
   406 {
       
   407     d->errorStr = str;
       
   408 }
       
   409 
       
   410 /*!
       
   411     \fn QString QHostInfo::localHostName()
       
   412 
       
   413     Returns the host name of this machine.
       
   414 
       
   415     \sa hostName()
       
   416 */
       
   417 
       
   418 /*!
       
   419     \fn QString QHostInfo::localDomainName()
       
   420 
       
   421     Returns the DNS domain of this machine.
       
   422 
       
   423     Note: DNS domains are not related to domain names found in
       
   424     Windows networks.
       
   425 
       
   426     \sa hostName()
       
   427 */
       
   428 
       
   429 #ifndef QT_NO_THREAD
       
   430 QHostInfoRunnable::QHostInfoRunnable(QString hn, int i) : toBeLookedUp(hn), id(i)
       
   431 {
       
   432     setAutoDelete(true);
       
   433 }
       
   434 
       
   435 // the QHostInfoLookupManager will at some point call this via a QThreadPool
       
   436 void QHostInfoRunnable::run()
       
   437 {
       
   438     QHostInfoLookupManager *manager = theHostInfoLookupManager();
       
   439     // check aborted
       
   440     if (manager->wasAborted(id)) {
       
   441         manager->lookupFinished(this);
       
   442         return;
       
   443     }
       
   444 
       
   445     QHostInfo hostInfo;
       
   446 
       
   447     // QHostInfo::lookupHost already checks the cache. However we need to check
       
   448     // it here too because it might have been cache saved by another QHostInfoRunnable
       
   449     // in the meanwhile while this QHostInfoRunnable was scheduled but not running
       
   450     if (manager->cache.isEnabled()) {
       
   451         // check the cache first
       
   452         bool valid = false;
       
   453         hostInfo = manager->cache.get(toBeLookedUp, &valid);
       
   454         if (!valid) {
       
   455             // not in cache, we need to do the lookup and store the result in the cache
       
   456             hostInfo = QHostInfoAgent::fromName(toBeLookedUp);
       
   457             manager->cache.put(toBeLookedUp, hostInfo);
       
   458         }
       
   459     } else {
       
   460         // cache is not enabled, just do the lookup and continue
       
   461         hostInfo = QHostInfoAgent::fromName(toBeLookedUp);
       
   462     }
       
   463 
       
   464     // check aborted again
       
   465     if (manager->wasAborted(id)) {
       
   466         manager->lookupFinished(this);
       
   467         return;
       
   468     }
       
   469 
       
   470     // signal emission
       
   471     hostInfo.setLookupId(id);
       
   472     resultEmitter.emitResultsReady(hostInfo);
       
   473 
       
   474     manager->lookupFinished(this);
       
   475 
       
   476     // thread goes back to QThreadPool
       
   477 }
       
   478 
       
   479 QHostInfoLookupManager::QHostInfoLookupManager() : mutex(QMutex::Recursive), wasDeleted(false)
       
   480 {
       
   481     moveToThread(QCoreApplicationPrivate::mainThread());
       
   482     connect(QCoreApplication::instance(), SIGNAL(destroyed()), SLOT(waitForThreadPoolDone()), Qt::DirectConnection);
       
   483     threadPool.setMaxThreadCount(5); // do 5 DNS lookups in parallel
       
   484 }
       
   485 
       
   486 QHostInfoLookupManager::~QHostInfoLookupManager()
       
   487 {
       
   488     wasDeleted = true;
       
   489 
       
   490     // don't qDeleteAll currentLookups, the QThreadPool has ownership
       
   491     qDeleteAll(postponedLookups);
       
   492     qDeleteAll(scheduledLookups);
       
   493     qDeleteAll(finishedLookups);
       
   494 }
       
   495 
       
   496 void QHostInfoLookupManager::work()
       
   497 {
       
   498     if (wasDeleted)
       
   499         return;
       
   500 
       
   501     // goals of this function:
       
   502     //  - launch new lookups via the thread pool
       
   503     //  - make sure only one lookup per host/IP is in progress
       
   504 
       
   505     QMutexLocker locker(&mutex);
       
   506 
       
   507     if (!finishedLookups.isEmpty()) {
       
   508         // remove ID from aborted if it is in there
       
   509         for (int i = 0; i < finishedLookups.length(); i++) {
       
   510            abortedLookups.removeAll(finishedLookups.at(i)->id);
       
   511         }
       
   512 
       
   513         finishedLookups.clear();
       
   514     }
       
   515 
       
   516     if (!postponedLookups.isEmpty()) {
       
   517         // try to start the postponed ones
       
   518 
       
   519         QMutableListIterator<QHostInfoRunnable*> iterator(postponedLookups);
       
   520         while (iterator.hasNext()) {
       
   521             QHostInfoRunnable* postponed = iterator.next();
       
   522 
       
   523             // check if none of the postponed hostnames is currently running
       
   524             bool alreadyRunning = false;
       
   525             for (int i = 0; i < currentLookups.length(); i++) {
       
   526                 if (currentLookups.at(i)->toBeLookedUp == postponed->toBeLookedUp) {
       
   527                     alreadyRunning = true;
       
   528                     break;
       
   529                 }
       
   530             }
       
   531             if (!alreadyRunning) {
       
   532                 iterator.remove();
       
   533                 scheduledLookups.prepend(postponed); // prepend! we want to finish it ASAP
       
   534             }
       
   535         }
       
   536     }
       
   537 
       
   538     if (!scheduledLookups.isEmpty()) {
       
   539         // try to start the new ones
       
   540         QMutableListIterator<QHostInfoRunnable*> iterator(scheduledLookups);
       
   541         while (iterator.hasNext()) {
       
   542             QHostInfoRunnable *scheduled = iterator.next();
       
   543 
       
   544             // check if a lookup for this host is already running, then postpone
       
   545             for (int i = 0; i < currentLookups.size(); i++) {
       
   546                 if (currentLookups.at(i)->toBeLookedUp == scheduled->toBeLookedUp) {
       
   547                     iterator.remove();
       
   548                     postponedLookups.append(scheduled);
       
   549                     scheduled = 0;
       
   550                     break;
       
   551                 }
       
   552             }
       
   553 
       
   554             if (scheduled && threadPool.tryStart(scheduled)) {
       
   555                 // runnable now running in new thread, track this in currentLookups
       
   556                 iterator.remove();
       
   557                 currentLookups.append(scheduled);
       
   558             } else if (scheduled) {
       
   559                 // wanted to start, but could not because thread pool is busy
       
   560                 break;
       
   561             } else {
       
   562                 // was postponed, continue iterating
       
   563                 continue;
       
   564             }
       
   565         };
       
   566     }
       
   567 }
       
   568 
       
   569 // called by QHostInfo
       
   570 void QHostInfoLookupManager::scheduleLookup(QHostInfoRunnable *r)
       
   571 {
       
   572     if (wasDeleted)
       
   573         return;
       
   574 
       
   575     QMutexLocker locker(&this->mutex);
       
   576     scheduledLookups.enqueue(r);
       
   577     work();
       
   578 }
       
   579 
       
   580 // called by QHostInfo
       
   581 void QHostInfoLookupManager::abortLookup(int id)
       
   582 {
       
   583     if (wasDeleted)
       
   584         return;
       
   585 
       
   586     QMutexLocker locker(&this->mutex);
       
   587     if (!abortedLookups.contains(id))
       
   588         abortedLookups.append(id);
       
   589 }
       
   590 
       
   591 // called from QHostInfoRunnable
       
   592 bool QHostInfoLookupManager::wasAborted(int id)
       
   593 {
       
   594     if (wasDeleted)
       
   595         return true;
       
   596 
       
   597     QMutexLocker locker(&this->mutex);
       
   598     return abortedLookups.contains(id);
       
   599 }
       
   600 
       
   601 // called from QHostInfoRunnable
       
   602 void QHostInfoLookupManager::lookupFinished(QHostInfoRunnable *r)
       
   603 {
       
   604     if (wasDeleted)
       
   605         return;
       
   606 
       
   607     QMutexLocker locker(&this->mutex);
       
   608     currentLookups.removeOne(r);
       
   609     finishedLookups.append(r);
       
   610     work();
       
   611 }
       
   612 
       
   613 // This function returns immediatly when we had a result in the cache, else it will later emit a signal
       
   614 QHostInfo qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char *member, bool *valid, int *id)
       
   615 {
       
   616     *valid = false;
       
   617     *id = -1;
       
   618 
       
   619     // check cache
       
   620     QHostInfoLookupManager* manager = theHostInfoLookupManager();
       
   621     if (manager && manager->cache.isEnabled()) {
       
   622         QHostInfo info = manager->cache.get(name, valid);
       
   623         if (*valid) {
       
   624             return info;
       
   625         }
       
   626     }
       
   627 
       
   628     // was not in cache, trigger lookup
       
   629     *id = QHostInfo::lookupHost(name, receiver, member);
       
   630 
       
   631     // return empty response, valid==false
       
   632     return QHostInfo();
       
   633 }
       
   634 
       
   635 void qt_qhostinfo_clear_cache()
       
   636 {
       
   637     QHostInfoLookupManager* manager = theHostInfoLookupManager();
       
   638     if (manager) {
       
   639         manager->cache.clear();
       
   640     }
       
   641 }
       
   642 
       
   643 void Q_AUTOTEST_EXPORT qt_qhostinfo_enable_cache(bool e)
       
   644 {
       
   645     QHostInfoLookupManager* manager = theHostInfoLookupManager();
       
   646     if (manager) {
       
   647         manager->cache.setEnabled(e);
       
   648     }
       
   649 }
       
   650 
       
   651 // cache for 60 seconds
       
   652 // cache 64 items
       
   653 QHostInfoCache::QHostInfoCache() : max_age(60), enabled(true), cache(64)
       
   654 {
       
   655 #ifdef QT_QHOSTINFO_CACHE_DISABLED_BY_DEFAULT
       
   656     enabled = false;
       
   657 #endif
       
   658 }
       
   659 
       
   660 bool QHostInfoCache::isEnabled()
       
   661 {
       
   662     return enabled;
       
   663 }
       
   664 
       
   665 // this function is currently only used for the auto tests
       
   666 // and not usable by public API
       
   667 void QHostInfoCache::setEnabled(bool e)
       
   668 {
       
   669     enabled = e;
       
   670 }
       
   671 
       
   672 
       
   673 QHostInfo QHostInfoCache::get(const QString &name, bool *valid)
       
   674 {
       
   675     QMutexLocker locker(&this->mutex);
       
   676 
       
   677     *valid = false;
       
   678     if (cache.contains(name)) {
       
   679         QHostInfoCacheElement *element = cache.object(name);
       
   680         if (element->age.elapsed() < max_age*1000)
       
   681             *valid = true;
       
   682         return element->info;
       
   683 
       
   684         // FIXME idea:
       
   685         // if too old but not expired, trigger a new lookup
       
   686         // to freshen our cache
       
   687     }
       
   688 
       
   689     return QHostInfo();
       
   690 }
       
   691 
       
   692 void QHostInfoCache::put(const QString &name, const QHostInfo &info)
       
   693 {
       
   694     // if the lookup failed, don't cache
       
   695     if (info.error() != QHostInfo::NoError)
       
   696         return;
       
   697 
       
   698     QHostInfoCacheElement* element = new QHostInfoCacheElement();
       
   699     element->info = info;
       
   700     element->age = QTime();
       
   701     element->age.start();
       
   702 
       
   703     QMutexLocker locker(&this->mutex);
       
   704     cache.insert(name, element); // cache will take ownership
       
   705 }
       
   706 
       
   707 void QHostInfoCache::clear()
       
   708 {
       
   709     QMutexLocker locker(&this->mutex);
       
   710     cache.clear();
       
   711 }
       
   712 
       
   713 #endif // QT_NO_THREAD
       
   714 
       
   715 QT_END_NAMESPACE