src/network/kernel/qhostinfo.cpp
changeset 19 fcece45ef507
parent 18 2f34d5167611
child 14 c0432d11811c
equal deleted inserted replaced
18:2f34d5167611 19:fcece45ef507
   110     IDNA and Punycode standards.
   110     IDNA and Punycode standards.
   111 
   111 
   112     To retrieve the name of the local host, use the static
   112     To retrieve the name of the local host, use the static
   113     QHostInfo::localHostName() function.
   113     QHostInfo::localHostName() function.
   114 
   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 
   115     \sa QAbstractSocket, {http://www.rfc-editor.org/rfc/rfc3492.txt}{RFC 3492}
   122     \sa QAbstractSocket, {http://www.rfc-editor.org/rfc/rfc3492.txt}{RFC 3492}
   116 */
   123 */
   117 
   124 
   118 static QBasicAtomicInt theIdCounter = Q_BASIC_ATOMIC_INITIALIZER(1);
   125 static QBasicAtomicInt theIdCounter = Q_BASIC_ATOMIC_INITIALIZER(1);
   119 
   126 
   179     QScopedPointer<QHostInfoResult> result(new QHostInfoResult);
   186     QScopedPointer<QHostInfoResult> result(new QHostInfoResult);
   180     QObject::connect(result.data(), SIGNAL(resultsReady(QHostInfo)),
   187     QObject::connect(result.data(), SIGNAL(resultsReady(QHostInfo)),
   181                      receiver, member, Qt::QueuedConnection);
   188                      receiver, member, Qt::QueuedConnection);
   182     result.data()->emitResultsReady(hostInfo);
   189     result.data()->emitResultsReady(hostInfo);
   183 #else
   190 #else
   184     QHostInfoRunnable* runnable = new QHostInfoRunnable(name, id);
   191     QHostInfoLookupManager *manager = theHostInfoLookupManager();
   185     QObject::connect(&runnable->resultEmitter, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection);
   192     if (manager) {
   186     theHostInfoLookupManager()->scheduleLookup(runnable);
   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     }
   187 #endif
   211 #endif
   188 
   212 
   189     return id;
   213     return id;
   190 }
   214 }
   191 
   215 
   416     if (manager->wasAborted(id)) {
   440     if (manager->wasAborted(id)) {
   417         manager->lookupFinished(this);
   441         manager->lookupFinished(this);
   418         return;
   442         return;
   419     }
   443     }
   420 
   444 
   421     // check cache
   445     QHostInfo hostInfo;
   422     // FIXME
   446 
   423 
   447     // QHostInfo::lookupHost already checks the cache. However we need to check
   424     // if not in cache: OS lookup
   448     // it here too because it might have been cache saved by another QHostInfoRunnable
   425     QHostInfo hostInfo = QHostInfoAgent::fromName(toBeLookedUp);
   449     // in the meanwhile while this QHostInfoRunnable was scheduled but not running
   426 
   450     if (manager->cache.isEnabled()) {
   427     // save to cache
   451         // check the cache first
   428     // FIXME
   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     }
   429 
   463 
   430     // check aborted again
   464     // check aborted again
   431     if (manager->wasAborted(id)) {
   465     if (manager->wasAborted(id)) {
   432         manager->lookupFinished(this);
   466         manager->lookupFinished(this);
   433         return;
   467         return;
   443 }
   477 }
   444 
   478 
   445 QHostInfoLookupManager::QHostInfoLookupManager() : mutex(QMutex::Recursive), wasDeleted(false)
   479 QHostInfoLookupManager::QHostInfoLookupManager() : mutex(QMutex::Recursive), wasDeleted(false)
   446 {
   480 {
   447     moveToThread(QCoreApplicationPrivate::mainThread());
   481     moveToThread(QCoreApplicationPrivate::mainThread());
       
   482     connect(QCoreApplication::instance(), SIGNAL(destroyed()), SLOT(waitForThreadPoolDone()), Qt::DirectConnection);
   448     threadPool.setMaxThreadCount(5); // do 5 DNS lookups in parallel
   483     threadPool.setMaxThreadCount(5); // do 5 DNS lookups in parallel
   449 }
   484 }
   450 
   485 
   451 QHostInfoLookupManager::~QHostInfoLookupManager()
   486 QHostInfoLookupManager::~QHostInfoLookupManager()
   452 {
   487 {
   453     wasDeleted = true;
   488     wasDeleted = true;
       
   489 
       
   490     // don't qDeleteAll currentLookups, the QThreadPool has ownership
       
   491     qDeleteAll(postponedLookups);
       
   492     qDeleteAll(scheduledLookups);
       
   493     qDeleteAll(finishedLookups);
   454 }
   494 }
   455 
   495 
   456 void QHostInfoLookupManager::work()
   496 void QHostInfoLookupManager::work()
   457 {
   497 {
   458     if (wasDeleted)
   498     if (wasDeleted)
   568     currentLookups.removeOne(r);
   608     currentLookups.removeOne(r);
   569     finishedLookups.append(r);
   609     finishedLookups.append(r);
   570     work();
   610     work();
   571 }
   611 }
   572 
   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 
   573 #endif // QT_NO_THREAD
   713 #endif // QT_NO_THREAD
   574 
   714 
   575 QT_END_NAMESPACE
   715 QT_END_NAMESPACE