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

KIO

  • sources
  • kde-4.14
  • kdelibs
  • kio
  • kio
hostinfo.cpp
Go to the documentation of this file.
1 /*
2 Copyright 2008 Roland Harnau <tau@gmx.eu>
3 
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) version 3, or any
8 later version accepted by the membership of KDE e.V. (or its
9 successor approved by the membership of KDE e.V.), which shall
10 act as a proxy defined in Section 6 of version 3 of the license.
11 
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16 
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include "hostinfo_p.h"
22 
23 #include <kglobal.h>
24 #include <QtCore/QString>
25 #include <QtCore/QHash>
26 #include <QtCore/QCache>
27 #include <QtCore/QMetaType>
28 #include <QtCore/QTime>
29 #include <QtCore/QTimer>
30 #include <QtCore/QList>
31 #include <QtCore/QPair>
32 #include <QtCore/QThread>
33 #include <QtCore/QFutureWatcher>
34 #include <QtCore/QSemaphore>
35 #include <QtCore/QSharedPointer>
36 #include <QtCore/QtConcurrentRun>
37 #include <QtNetwork/QHostInfo>
38 #include "kdebug.h"
39 
40 #ifdef Q_OS_UNIX
41 # include <QtCore/QFileInfo>
42 # include <netinet/in.h>
43 # include <arpa/nameser.h>
44 # include <resolv.h> // for _PATH_RESCONF
45 # ifndef _PATH_RESCONF
46 # define _PATH_RESCONF "/etc/resolv.conf"
47 # endif
48 #endif
49 
50 #define TTL 300
51 
52 static int dummyHostInfoMetaType = qRegisterMetaType<QHostInfo>("QHostInfo");
53 
54 namespace KIO
55 {
56  class HostInfoAgentPrivate : public QObject
57  {
58  Q_OBJECT
59  public:
60  HostInfoAgentPrivate(int cacheSize = 100);
61  virtual ~HostInfoAgentPrivate() {};
62  void lookupHost(const QString& hostName, QObject* receiver, const char* member);
63  QHostInfo lookupCachedHostInfoFor(const QString& hostName);
64  void cacheLookup(const QHostInfo&);
65  void setCacheSize(int s) { dnsCache.setMaxCost(s); }
66  void setTTL(int _ttl) { ttl = _ttl; }
67  private slots:
68  void queryFinished(const QHostInfo&);
69  private:
70  class Result;
71  class Query;
72 
73  QHash<QString, Query*> openQueries;
74  QCache<QString, QPair<QHostInfo, QTime> > dnsCache;
75  time_t resolvConfMTime;
76  int ttl;
77  };
78 
79  class HostInfoAgentPrivate::Result : public QObject
80  {
81  Q_OBJECT
82  signals:
83  void result(QHostInfo);
84  private:
85  friend class HostInfoAgentPrivate;
86  };
87 
88  class HostInfoAgentPrivate::Query : public QObject
89  {
90  Q_OBJECT
91  public:
92  Query(): m_watcher(), m_hostName()
93  {
94  connect(&m_watcher, SIGNAL(finished()), this, SLOT(relayFinished()));
95  }
96  void start(const QString& hostName)
97  {
98  m_hostName = hostName;
99  QFuture<QHostInfo> future = QtConcurrent::run(&QHostInfo::fromName, hostName);
100  m_watcher.setFuture(future);
101  }
102  QString hostName() const
103  {
104  return m_hostName;
105  }
106  signals:
107  void result(QHostInfo);
108  private slots:
109  void relayFinished()
110  {
111  emit result(m_watcher.result());
112  }
113  private:
114  QFutureWatcher<QHostInfo> m_watcher;
115  QString m_hostName;
116  };
117 
118  class NameLookupThreadRequest
119  {
120  public:
121  NameLookupThreadRequest(const QString& hostName) : m_hostName(hostName)
122  {
123  }
124 
125  QSemaphore *semaphore()
126  {
127  return &m_semaphore;
128  }
129 
130  QHostInfo result() const
131  {
132  return m_hostInfo;
133  }
134 
135  void setResult(const QHostInfo& hostInfo)
136  {
137  m_hostInfo = hostInfo;
138  }
139 
140  QString hostName() const
141  {
142  return m_hostName;
143  }
144 
145  int lookupId() const
146  {
147  return m_lookupId;
148  }
149 
150  void setLookupId(int id)
151  {
152  m_lookupId = id;
153  }
154 
155  private:
156  Q_DISABLE_COPY(NameLookupThreadRequest)
157  QString m_hostName;
158  QSemaphore m_semaphore;
159  QHostInfo m_hostInfo;
160  int m_lookupId;
161  };
162 
163  class NameLookUpThreadWorker : public QObject
164  {
165  Q_OBJECT
166  public slots:
167  void lookupHost(const QSharedPointer<NameLookupThreadRequest>& request)
168  {
169  const QString hostName = request->hostName();
170  const int lookupId = QHostInfo::lookupHost(hostName, this, SLOT(lookupFinished(QHostInfo)));
171  request->setLookupId(lookupId);
172  m_lookups.insert(lookupId, request);
173  }
174 
175  void abortLookup(const QSharedPointer<NameLookupThreadRequest>& request)
176  {
177  QHostInfo::abortHostLookup(request->lookupId());
178  m_lookups.remove(request->lookupId());
179  }
180 
181  void lookupFinished(const QHostInfo &hostInfo)
182  {
183  QMap<int, QSharedPointer<NameLookupThreadRequest> >::iterator it = m_lookups.find(hostInfo.lookupId());
184  if (it != m_lookups.end()) {
185  (*it)->setResult(hostInfo);
186  (*it)->semaphore()->release();
187  m_lookups.erase(it);
188  }
189  }
190 
191  private:
192  QMap<int, QSharedPointer<NameLookupThreadRequest> > m_lookups;
193  };
194 
195  class NameLookUpThread : public QThread
196  {
197  Q_OBJECT
198  public:
199  NameLookUpThread () : m_worker(0)
200  {
201  qRegisterMetaType< QSharedPointer<NameLookupThreadRequest> > ("QSharedPointer<NameLookupThreadRequest>");
202  start();
203  }
204 
205  ~NameLookUpThread ()
206  {
207  quit();
208  wait();
209  }
210 
211  NameLookUpThreadWorker *worker()
212  {
213  return m_worker;
214  }
215 
216  QSemaphore *semaphore()
217  {
218  return &m_semaphore;
219  }
220 
221  void run()
222  {
223  NameLookUpThreadWorker worker;
224  m_worker = &worker;
225  m_semaphore.release();
226  exec();
227  }
228 
229  private:
230  NameLookUpThreadWorker *m_worker;
231  QSemaphore m_semaphore;
232  };
233 }
234 
235 using namespace KIO;
236 
237 K_GLOBAL_STATIC(HostInfoAgentPrivate, hostInfoAgentPrivate)
238 K_GLOBAL_STATIC(NameLookUpThread, nameLookUpThread)
239 
240 void HostInfo::lookupHost(const QString& hostName, QObject* receiver,
241  const char* member)
242 {
243  hostInfoAgentPrivate->lookupHost(hostName, receiver, member);
244 }
245 
246 QHostInfo HostInfo::lookupHost(const QString& hostName, unsigned long timeout)
247 {
248  // Do not perform a reverse lookup here...
249  QHostAddress address (hostName);
250  QHostInfo hostInfo;
251  if (!address.isNull()) {
252  QList<QHostAddress> addressList;
253  addressList << address;
254  hostInfo.setAddresses(addressList);
255  return hostInfo;
256  }
257 
258  // Look up the name in the KIO/KHTML DNS cache...
259  hostInfo = HostInfo::lookupCachedHostInfoFor(hostName);
260  if (!hostInfo.hostName().isEmpty() && hostInfo.error() == QHostInfo::NoError) {
261  return hostInfo;
262  }
263 
264  // Failing all of the above, do the lookup...
265  QSharedPointer<NameLookupThreadRequest> request = QSharedPointer<NameLookupThreadRequest>(new NameLookupThreadRequest(hostName));
266  nameLookUpThread->semaphore()->acquire();
267  nameLookUpThread->semaphore()->release();
268  QMetaObject::invokeMethod(nameLookUpThread->worker(), "lookupHost", Qt::QueuedConnection, Q_ARG(QSharedPointer<NameLookupThreadRequest>, request));
269  if (request->semaphore()->tryAcquire(1, timeout)) {
270  hostInfo = request->result();
271  if (!hostInfo.hostName().isEmpty() && hostInfo.error() == QHostInfo::NoError) {
272  HostInfo::cacheLookup(hostInfo); // cache the look up...
273  }
274  } else {
275  QMetaObject::invokeMethod(nameLookUpThread->worker(), "abortLookup", Qt::QueuedConnection, Q_ARG(QSharedPointer<NameLookupThreadRequest>, request));
276  }
277 
278  //kDebug(7022) << "Name look up succeeded for" << hostName;
279  return hostInfo;
280 }
281 
282 QHostInfo HostInfo::lookupCachedHostInfoFor(const QString& hostName)
283 {
284  return hostInfoAgentPrivate->lookupCachedHostInfoFor(hostName);
285 }
286 
287 void HostInfo::cacheLookup(const QHostInfo& info)
288 {
289  hostInfoAgentPrivate->cacheLookup(info);
290 }
291 
292 void HostInfo::prefetchHost(const QString& hostName)
293 {
294  hostInfoAgentPrivate->lookupHost(hostName, 0, 0);
295 }
296 
297 void HostInfo::setCacheSize(int s)
298 {
299  hostInfoAgentPrivate->setCacheSize(s);
300 }
301 
302 void HostInfo::setTTL(int ttl)
303 {
304  hostInfoAgentPrivate->setTTL(ttl);
305 }
306 
307 HostInfoAgentPrivate::HostInfoAgentPrivate(int cacheSize)
308  : openQueries(),
309  dnsCache(cacheSize),
310  resolvConfMTime(0),
311  ttl(TTL)
312 {}
313 
314 void HostInfoAgentPrivate::lookupHost(const QString& hostName,
315  QObject* receiver, const char* member)
316 {
317 #ifdef _PATH_RESCONF
318  QFileInfo resolvConf(QFile::decodeName(_PATH_RESCONF));
319  time_t currentMTime = resolvConf.lastModified().toTime_t();
320  if (resolvConf.exists() && currentMTime != resolvConfMTime) {
321  // /etc/resolv.conf has been modified
322  // clear our cache
323  resolvConfMTime = currentMTime;
324  dnsCache.clear();
325  }
326 #endif
327 
328  if (QPair<QHostInfo, QTime>* info = dnsCache.object(hostName)) {
329  if (QTime::currentTime() <= info->second.addSecs(ttl)) {
330  Result result;
331  if (receiver) {
332  QObject::connect(&result, SIGNAL(result(QHostInfo)),receiver, member);
333  emit result.result(info->first);
334  }
335  return;
336  }
337  dnsCache.remove(hostName);
338  }
339 
340  if (Query* query = openQueries.value(hostName)) {
341  if (receiver) {
342  connect(query, SIGNAL(result(QHostInfo)), receiver, member);
343  }
344  return;
345  }
346 
347  Query* query = new Query();
348  openQueries.insert(hostName, query);
349  connect(query, SIGNAL(result(QHostInfo)), this, SLOT(queryFinished(QHostInfo)));
350  if (receiver) {
351  connect(query, SIGNAL(result(QHostInfo)), receiver, member);
352  }
353  query->start(hostName);
354 }
355 
356 QHostInfo HostInfoAgentPrivate::lookupCachedHostInfoFor(const QString& hostName)
357 {
358  QPair<QHostInfo, QTime>* info = dnsCache.object(hostName);
359  if (info && info->second.addSecs(ttl) >= QTime::currentTime())
360  return info->first;
361 
362  return QHostInfo();
363 }
364 
365 void HostInfoAgentPrivate::cacheLookup(const QHostInfo& info)
366 {
367  if (info.hostName().isEmpty())
368  return;
369 
370  if (info.error() != QHostInfo::NoError)
371  return;
372 
373  dnsCache.insert(info.hostName(), new QPair<QHostInfo, QTime>(info, QTime::currentTime()));
374 }
375 
376 void HostInfoAgentPrivate::queryFinished(const QHostInfo& info)
377 {
378  Query* query = static_cast<Query* >(sender());
379  openQueries.remove(query->hostName());
380  if (info.error() == QHostInfo::NoError) {
381  dnsCache.insert(query->hostName(),
382  new QPair<QHostInfo, QTime>(info, QTime::currentTime()));
383  }
384  query->deleteLater();
385 }
386 
387 #include "hostinfo.moc"
kdebug.h
QHostAddress
K_GLOBAL_STATIC
#define K_GLOBAL_STATIC(TYPE, NAME)
QMap
Definition: netaccess.h:36
QHostInfo::setAddresses
void setAddresses(const QList< QHostAddress > &addresses)
KIO::HostInfo::lookupHost
void lookupHost(const QString &hostName, QObject *receiver, const char *member)
Definition: hostinfo.cpp:240
QSemaphore
KDesktopFileActions::run
bool run(const KUrl &_url, bool _is_local)
Invokes the default action for the desktop entry.
Definition: kdesktopfileactions.cpp:54
QTime::second
int second() const
kglobal.h
QSharedPointer
QHash< QString, Query * >
QObject
QString::isEmpty
bool isEmpty() const
KIO::HostInfo::setTTL
void setTTL(int ttl)
Definition: hostinfo.cpp:302
QtConcurrent::run
QFuture< T > run(Function function,...)
QString
QList
_PATH_RESCONF
#define _PATH_RESCONF
Definition: hostinfo.cpp:46
QCache
QPair
QFileInfo
KIO::HostInfo::cacheLookup
void cacheLookup(const QHostInfo &info)
Definition: hostinfo.cpp:287
QMetaObject::invokeMethod
bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0, QGenericArgument val1, QGenericArgument val2, QGenericArgument val3, QGenericArgument val4, QGenericArgument val5, QGenericArgument val6, QGenericArgument val7, QGenericArgument val8, QGenericArgument val9)
QHostInfo::fromName
QHostInfo fromName(const QString &name)
QTime::currentTime
QTime currentTime()
QHostInfo::lookupHost
int lookupHost(const QString &name, QObject *receiver, const char *member)
TTL
#define TTL
Definition: hostinfo.cpp:50
QFutureWatcher< QHostInfo >
KIO::HostInfo::lookupCachedHostInfoFor
QHostInfo lookupCachedHostInfoFor(const QString &hostName)
Definition: hostinfo.cpp:282
KIO::HostInfo::prefetchHost
void prefetchHost(const QString &hostName)
Definition: hostinfo.cpp:292
QHostInfo::abortHostLookup
void abortHostLookup(int id)
hostinfo_p.h
QThread
QHostAddress::isNull
bool isNull() const
QFuture
QHostInfo::error
HostInfoError error() const
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
dummyHostInfoMetaType
static int dummyHostInfoMetaType
Definition: hostinfo.cpp:52
KIO::HostInfo::setCacheSize
void setCacheSize(int s)
Definition: hostinfo.cpp:297
QHostInfo
QHostInfo::lookupId
int lookupId() const
QMap::find
iterator find(const Key &key)
QFile::decodeName
QString decodeName(const QByteArray &localFileName)
QHostInfo::hostName
QString hostName() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:24:52 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

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 API Reference

Skip menu "kdelibs API Reference"
  • 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

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal