• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KIO

hostinfo.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright 2008 Roland Harnau <tau@gmx.eu>
00003 
00004 This library is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU Lesser General Public
00006 License as published by the Free Software Foundation; either
00007 version 2.1 of the License, or (at your option) version 3, or any
00008 later version accepted by the membership of KDE e.V. (or its
00009 successor approved by the membership of KDE e.V.), which shall
00010 act as a proxy defined in Section 6 of version 3 of the license.
00011 
00012 This library is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 Lesser General Public License for more details.
00016 
00017 You should have received a copy of the GNU Lesser General Public
00018 License along with this library.  If not, see <http://www.gnu.org/licenses/>.
00019 */
00020 
00021 #include "hostinfo_p.h"
00022 
00023 #include <kglobal.h>
00024 #include <QtCore/QString>
00025 #include <QtCore/QHash>
00026 #include <QtCore/QCache>
00027 #include <QtCore/QMetaType>
00028 #include <QtCore/QTime>
00029 #include <QtCore/QTimer>
00030 #include <QtCore/QList>
00031 #include <QtCore/QPair>
00032 #include <QtCore/QThread>
00033 #include <QtCore/QFutureWatcher>
00034 #include <QtCore/QSemaphore>
00035 #include <QtCore/QSharedPointer>
00036 #include <QtCore/QtConcurrentRun>
00037 #include <QtNetwork/QHostInfo>
00038 #include "kdebug.h"
00039 
00040 #ifdef Q_OS_UNIX
00041 # include <QtCore/QFileInfo>
00042 # include <netinet/in.h>
00043 # include <arpa/nameser.h>
00044 # include <resolv.h>            // for _PATH_RESCONF
00045 # ifndef _PATH_RESCONF
00046 #  define _PATH_RESCONF         "/etc/resolv.conf"
00047 # endif
00048 #endif
00049 
00050 #define TTL 300
00051 
00052 static int dummyHostInfoMetaType = qRegisterMetaType<QHostInfo>("QHostInfo");
00053 
00054 namespace KIO
00055 {
00056     class HostInfoAgentPrivate : public QObject
00057     {
00058         Q_OBJECT
00059     public:
00060         HostInfoAgentPrivate(int cacheSize = 100);
00061         virtual ~HostInfoAgentPrivate() {};
00062         void lookupHost(const QString& hostName, QObject* receiver, const char* member);
00063         QHostInfo lookupCachedHostInfoFor(const QString& hostName);
00064         void cacheLookup(const QHostInfo&);
00065         void setCacheSize(int s) { dnsCache.setMaxCost(s); }
00066         void setTTL(int _ttl) { ttl = _ttl; }
00067     private slots:
00068         void queryFinished(const QHostInfo&);
00069     private:
00070         class Result;
00071         class Query;
00072 
00073         QHash<QString, Query*> openQueries;
00074         QCache<QString, QPair<QHostInfo, QTime> > dnsCache;
00075         time_t resolvConfMTime;
00076         int ttl;
00077     };
00078 
00079     class HostInfoAgentPrivate::Result : public QObject
00080     {
00081         Q_OBJECT
00082     signals:
00083         void result(QHostInfo);
00084     private:
00085         friend class HostInfoAgentPrivate;
00086     };
00087 
00088     class HostInfoAgentPrivate::Query : public QObject
00089     {
00090         Q_OBJECT
00091     public:
00092         Query(): m_watcher(), m_hostName()
00093         {
00094             connect(&m_watcher, SIGNAL(finished()), this, SLOT(relayFinished()));
00095         }
00096         void start(const QString& hostName)
00097         {
00098             m_hostName = hostName;
00099             QFuture<QHostInfo> future = QtConcurrent::run(&QHostInfo::fromName, hostName);
00100             m_watcher.setFuture(future);
00101         }
00102         QString hostName() const
00103         {
00104             return m_hostName;
00105         }
00106     signals:
00107         void result(QHostInfo);
00108     private slots:
00109         void relayFinished()
00110         {
00111             emit result(m_watcher.result());
00112         }
00113     private:
00114         QFutureWatcher<QHostInfo> m_watcher;
00115         QString m_hostName;
00116     };
00117 
00118     class NameLookupThreadRequest
00119     {
00120     public:
00121         NameLookupThreadRequest(const QString& hostName) : m_hostName(hostName)
00122         {
00123         }
00124 
00125         QSemaphore *semaphore()
00126         {
00127             return &m_semaphore;
00128         }
00129 
00130         QHostInfo result() const
00131         {
00132             return m_hostInfo;
00133         }
00134 
00135         void setResult(const QHostInfo& hostInfo)
00136         {
00137             m_hostInfo = hostInfo;
00138         }
00139 
00140         QString hostName() const
00141         {
00142             return m_hostName;
00143         }
00144 
00145         int lookupId() const
00146         {
00147             return m_lookupId;
00148         }
00149 
00150         void setLookupId(int id)
00151         {
00152             m_lookupId = id;
00153         }
00154 
00155     private:
00156         Q_DISABLE_COPY(NameLookupThreadRequest);
00157         QString m_hostName;
00158         QSemaphore m_semaphore;
00159         QHostInfo m_hostInfo;
00160         int m_lookupId;
00161     };
00162 
00163     class NameLookUpThreadWorker : public QObject
00164     {
00165         Q_OBJECT
00166     public slots:
00167         void lookupHost(const QSharedPointer<NameLookupThreadRequest>& request)
00168         {
00169             const QString hostName = request->hostName();
00170             const int lookupId = QHostInfo::lookupHost(hostName, this, SLOT(lookupFinished(QHostInfo)));
00171             request->setLookupId(lookupId);
00172             m_lookups.insert(lookupId, request);
00173         }
00174 
00175         void abortLookup(const QSharedPointer<NameLookupThreadRequest>& request)
00176         {
00177             QHostInfo::abortHostLookup(request->lookupId());
00178             m_lookups.remove(request->lookupId());
00179         }
00180 
00181         void lookupFinished(const QHostInfo &hostInfo)
00182         {
00183             QMap<int, QSharedPointer<NameLookupThreadRequest> >::iterator it = m_lookups.find(hostInfo.lookupId());
00184             if (it != m_lookups.end()) {
00185                 (*it)->setResult(hostInfo);
00186                 (*it)->semaphore()->release();
00187                 m_lookups.erase(it);
00188             }
00189         }
00190 
00191     private:
00192         QMap<int, QSharedPointer<NameLookupThreadRequest> > m_lookups;
00193     };
00194 
00195     class NameLookUpThread : public QThread
00196     {
00197         Q_OBJECT
00198     public:
00199         NameLookUpThread () : m_worker(0)
00200         {
00201             qRegisterMetaType< QSharedPointer<NameLookupThreadRequest> > ("QSharedPointer<NameLookupThreadRequest>");
00202             start();
00203         }
00204 
00205         ~NameLookUpThread ()
00206         {
00207             quit();
00208             wait();
00209         }
00210 
00211         NameLookUpThreadWorker *worker()
00212         {
00213             return m_worker;
00214         }
00215 
00216         QSemaphore *semaphore()
00217         {
00218             return &m_semaphore;
00219         }
00220 
00221         void run()
00222         {
00223             NameLookUpThreadWorker worker;
00224             m_worker = &worker;
00225             m_semaphore.release();
00226             exec();
00227         }
00228 
00229     private:
00230         NameLookUpThreadWorker *m_worker;
00231         QSemaphore m_semaphore;
00232     };
00233 }
00234 
00235 using namespace KIO;
00236 
00237 K_GLOBAL_STATIC(HostInfoAgentPrivate, hostInfoAgentPrivate)
00238 K_GLOBAL_STATIC(NameLookUpThread, nameLookUpThread)
00239 
00240 void HostInfo::lookupHost(const QString& hostName, QObject* receiver,
00241     const char* member)
00242 {
00243     hostInfoAgentPrivate->lookupHost(hostName, receiver, member);
00244 }
00245 
00246 QHostInfo HostInfo::lookupHost(const QString& hostName, unsigned long timeout)
00247 {
00248     // Do not perform a reverse lookup here...
00249     QHostAddress address (hostName);
00250     QHostInfo hostInfo;
00251     if (!address.isNull()) {
00252         QList<QHostAddress> addressList;
00253         addressList << address;
00254         hostInfo.setAddresses(addressList);
00255         return hostInfo;
00256     }
00257 
00258     // Look up the name in the KIO/KHTML DNS cache...
00259     hostInfo = HostInfo::lookupCachedHostInfoFor(hostName);
00260     if (!hostInfo.hostName().isEmpty() && hostInfo.error() == QHostInfo::NoError) {
00261         return hostInfo;
00262     }
00263 
00264     // Failing all of the above, do the lookup...
00265     QSharedPointer<NameLookupThreadRequest> request = QSharedPointer<NameLookupThreadRequest>(new NameLookupThreadRequest(hostName));
00266     nameLookUpThread->semaphore()->acquire();
00267     nameLookUpThread->semaphore()->release();
00268     QMetaObject::invokeMethod(nameLookUpThread->worker(), "lookupHost", Qt::QueuedConnection, Q_ARG(QSharedPointer<NameLookupThreadRequest>, request));
00269     if (request->semaphore()->tryAcquire(1, timeout)) {
00270         hostInfo = request->result();
00271         if (!hostInfo.hostName().isEmpty() && hostInfo.error() == QHostInfo::NoError) {
00272             HostInfo::cacheLookup(hostInfo); // cache the look up...
00273         }
00274     } else {
00275         QMetaObject::invokeMethod(nameLookUpThread->worker(), "abortLookup", Qt::QueuedConnection, Q_ARG(QSharedPointer<NameLookupThreadRequest>, request));
00276     }
00277 
00278     //kDebug(7022) << "Name look up succeeded for" << hostName;
00279     return hostInfo;
00280 }
00281 
00282 QHostInfo HostInfo::lookupCachedHostInfoFor(const QString& hostName)
00283 {
00284     return hostInfoAgentPrivate->lookupCachedHostInfoFor(hostName);
00285 }
00286 
00287 void HostInfo::cacheLookup(const QHostInfo& info)
00288 {
00289     hostInfoAgentPrivate->cacheLookup(info);
00290 }
00291 
00292 void HostInfo::prefetchHost(const QString& hostName)
00293 {
00294     hostInfoAgentPrivate->lookupHost(hostName, 0, 0);
00295 }
00296 
00297 void HostInfo::setCacheSize(int s)
00298 {
00299     hostInfoAgentPrivate->setCacheSize(s);
00300 }
00301 
00302 void HostInfo::setTTL(int ttl)
00303 {
00304     hostInfoAgentPrivate->setTTL(ttl);
00305 }
00306 
00307 HostInfoAgentPrivate::HostInfoAgentPrivate(int cacheSize)
00308     : openQueries(),
00309       dnsCache(cacheSize),
00310       resolvConfMTime(0),
00311       ttl(TTL)
00312 {}
00313 
00314 void HostInfoAgentPrivate::lookupHost(const QString& hostName,
00315     QObject* receiver, const char* member)
00316 {
00317 #ifdef _PATH_RESCONF
00318     QFileInfo resolvConf(QFile::decodeName(_PATH_RESCONF));
00319     time_t currentMTime = resolvConf.lastModified().toTime_t();
00320     if (resolvConf.exists() && currentMTime != resolvConfMTime) {
00321         // /etc/resolv.conf has been modified
00322         // clear our cache
00323         resolvConfMTime = currentMTime;
00324         dnsCache.clear();
00325     }
00326 #endif
00327 
00328     if (QPair<QHostInfo, QTime>* info = dnsCache.object(hostName)) {
00329         if (QTime::currentTime() <= info->second.addSecs(ttl)) {
00330             Result result;
00331             if (receiver) {
00332                 QObject::connect(&result, SIGNAL(result(QHostInfo)),receiver, member);
00333                 emit result.result(info->first);
00334             }
00335             return;
00336         }
00337         dnsCache.remove(hostName);
00338     }
00339 
00340     if (Query* query = openQueries.value(hostName)) {
00341         if (receiver) {
00342             connect(query, SIGNAL(result(QHostInfo)), receiver, member);
00343         }
00344         return;
00345     }
00346 
00347     Query* query = new Query();
00348     openQueries.insert(hostName, query);
00349     connect(query, SIGNAL(result(QHostInfo)), this, SLOT(queryFinished(QHostInfo)));
00350     if (receiver) {
00351         connect(query, SIGNAL(result(QHostInfo)), receiver, member);
00352     }
00353     query->start(hostName);
00354 }
00355 
00356 QHostInfo HostInfoAgentPrivate::lookupCachedHostInfoFor(const QString& hostName)
00357 {
00358     QPair<QHostInfo, QTime>* info = dnsCache.object(hostName);
00359     if (info && info->second.addSecs(ttl) >= QTime::currentTime())
00360         return info->first;
00361 
00362     return QHostInfo();
00363 }
00364 
00365 void HostInfoAgentPrivate::cacheLookup(const QHostInfo& info)
00366 {
00367     if (info.hostName().isEmpty())
00368         return;
00369 
00370     if (info.error() != QHostInfo::NoError)
00371         return;
00372 
00373     dnsCache.insert(info.hostName(), new QPair<QHostInfo, QTime>(info, QTime::currentTime()));
00374 }
00375 
00376 void HostInfoAgentPrivate::queryFinished(const QHostInfo& info)
00377 {
00378     Query* query = static_cast<Query* >(sender());
00379     openQueries.remove(query->hostName());
00380     if (info.error() == QHostInfo::NoError) {
00381         dnsCache.insert(query->hostName(),
00382             new QPair<QHostInfo, QTime>(info, QTime::currentTime()));
00383     }
00384     query->deleteLater();
00385 }
00386 
00387 #include "hostinfo.moc"

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal