10#include <QFutureWatcher>
20#include <QtConcurrentRun>
24#include <arpa/nameser.h>
25#include <netinet/in.h>
28#define _PATH_RESCONF "/etc/resolv.conf"
32static constexpr int TTL = 300;
36class HostInfoAgentPrivate :
public QObject
43 explicit HostInfoAgentPrivate(
int cacheSize = 100);
44 ~HostInfoAgentPrivate()
override
47 void lookupHost(
const QString &hostName,
QObject *receiver,
const char *member);
48 QHostInfo lookupCachedHostInfoFor(
const QString &hostName);
49 void cacheLookup(
const QHostInfo &);
51 void queryFinished(
const QHostInfo &info, Query *
sender);
56 QHash<QString, Query *> openQueries;
57 struct HostCacheInfo {
61 QCache<QString, HostCacheInfo> dnsCache;
62 QDateTime resolvConfMTime;
65class HostInfoAgentPrivate::Result :
public QObject
69 void result(
const QHostInfo &);
72 friend class HostInfoAgentPrivate;
75class HostInfoAgentPrivate::Query :
public QObject
85 void start(
const QString &hostName)
87 m_hostName = hostName;
89 m_watcher.setFuture(future);
91 QString hostName()
const
96 void result(
const QHostInfo &);
100 Q_EMIT result(m_watcher.result());
104 QFutureWatcher<QHostInfo> m_watcher;
108class NameLookupThreadRequest
111 NameLookupThreadRequest(
const QString &hostName)
112 : m_hostName(hostName)
116 QSemaphore *semaphore()
121 QHostInfo result()
const
126 void setResult(
const QHostInfo &hostInfo)
128 m_hostInfo = hostInfo;
131 QString hostName()
const
141 void setLookupId(
int id)
147 Q_DISABLE_COPY(NameLookupThreadRequest)
149 QSemaphore m_semaphore;
150 QHostInfo m_hostInfo;
155Q_DECLARE_METATYPE(std::shared_ptr<KIO::NameLookupThreadRequest>)
159class NameLookUpThreadWorker :
public QObject
163 void lookupHost(
const std::shared_ptr<KIO::NameLookupThreadRequest> &request)
165 const QString hostName = request->hostName();
167 request->setLookupId(lookupId);
168 m_lookups.insert(lookupId, request);
171 void abortLookup(
const std::shared_ptr<KIO::NameLookupThreadRequest> &request)
174 m_lookups.remove(request->lookupId());
177 void lookupFinished(
const QHostInfo &hostInfo)
179 auto it = m_lookups.find(hostInfo.
lookupId());
180 if (it != m_lookups.end()) {
181 (*it)->setResult(hostInfo);
182 (*it)->semaphore()->release();
188 QMap<int, std::shared_ptr<NameLookupThreadRequest>> m_lookups;
191class NameLookUpThread :
public QThread
198 qRegisterMetaType<std::shared_ptr<NameLookupThreadRequest>>();
202 ~NameLookUpThread()
override
208 NameLookUpThreadWorker *worker()
213 QSemaphore *semaphore()
220 NameLookUpThreadWorker worker;
222 m_semaphore.release();
227 NameLookUpThreadWorker *m_worker;
228 QSemaphore m_semaphore;
234Q_GLOBAL_STATIC(HostInfoAgentPrivate, hostInfoAgentPrivate)
235Q_GLOBAL_STATIC(NameLookUpThread, nameLookUpThread)
239 hostInfoAgentPrivate()->lookupHost(hostName, receiver, member);
247 if (!address.isNull()) {
249 addressList << address;
261 std::shared_ptr<NameLookupThreadRequest> request = std::make_shared<NameLookupThreadRequest>(hostName);
262 nameLookUpThread()->semaphore()->acquire();
263 nameLookUpThread()->semaphore()->release();
264 NameLookUpThreadWorker *worker = nameLookUpThread()->worker();
265 auto lookupFunc = [worker, request]() {
266 worker->lookupHost(request);
269 if (request->semaphore()->tryAcquire(1, timeout)) {
270 hostInfo = request->result();
275 auto abortFunc = [worker, request]() {
276 worker->abortLookup(request);
287 return hostInfoAgentPrivate()->lookupCachedHostInfoFor(hostName);
292 hostInfoAgentPrivate()->cacheLookup(info);
295HostInfoAgentPrivate::HostInfoAgentPrivate(
int cacheSize)
297 , dnsCache(cacheSize)
299 qRegisterMetaType<QHostInfo>();
302void HostInfoAgentPrivate::lookupHost(
const QString &hostName,
QObject *receiver,
const char *member)
306 QDateTime currentMTime = resolvConf.lastModified();
307 if (resolvConf.exists() && currentMTime != resolvConfMTime) {
310 resolvConfMTime = currentMTime;
315 if (HostCacheInfo *info = dnsCache.object(hostName)) {
320 Q_EMIT result.result(info->hostInfo);
324 dnsCache.remove(hostName);
327 if (Query *query = openQueries.value(hostName)) {
329 connect(query, SIGNAL(result(QHostInfo)), receiver, member);
334 Query *
query =
new Query();
335 openQueries.insert(hostName, query);
336 connect(query, &Query::result,
this, [
this, query](
const QHostInfo &info) {
337 queryFinished(info, query);
340 connect(query, SIGNAL(result(QHostInfo)), receiver, member);
342 query->start(hostName);
345QHostInfo HostInfoAgentPrivate::lookupCachedHostInfoFor(
const QString &hostName)
347 HostCacheInfo *info = dnsCache.object(hostName);
349 return info->hostInfo;
358void HostInfoAgentPrivate::cacheLookup(
const QHostInfo &info)
368 dnsCache.insert(info.
hostName(),
new HostCacheInfo{info, QTime::currentTime()});
371void HostInfoAgentPrivate::queryFinished(
const QHostInfo &info, Query *sender)
373 const auto host =
sender->hostName();
374 openQueries.remove(host);
381#include "hostinfo.moc"
Q_SCRIPTABLE Q_NOREPLY void start()
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
KIOCORE_EXPORT QHostInfo lookupCachedHostInfoFor(const QString &hostName)
KIOCORE_EXPORT void cacheLookup(const QHostInfo &info)
void lookupHost(const QString &hostName, QObject *receiver, const char *member)
A namespace for KIO globals.
QString decodeName(const QByteArray &localFileName)
void abortHostLookup(int id)
HostInfoError error() const const
QHostInfo fromName(const QString &name)
QString hostName() const const
int lookupHost(const QString &name, Functor &&functor)
int lookupId() const const
void setAddresses(const QList< QHostAddress > &addresses)
void setError(HostInfoError error)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * sender() const const
bool isEmpty() const const
QFuture< T > run(Function function,...)
bool wait(QDeadlineTimer deadline)
QTime addSecs(int s) const const