[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-core-devel
Subject: Re: [PATCH] DNS cache for Konqueror/KIO
From: "Roland Harnau" <truthandprogress () googlemail ! com>
Date: 2008-06-25 18:03:05
Message-ID: 476f836a0806251103n192e1099gdc9827518ac1e826 () mail ! gmail ! com
[Download RAW message or body]
2008/6/23, Thiago Macieira <thiago@kde.org>:
> I didn't like the indention style. Please don't put function opening
> brackets on the same line as their declaration. You also have whitespace
> errors (lines ending in whitespace).
The location of the opening brackets is maybe too much of Java style
for KDE. Attached is somewhat improved patch adhering a bit more to
kdelibs coding style and hopefully without superfluous whitespace.
> This is also a first step in fixing the long issue of not having a
> centralised slave manager. One that would allow us to say "only one FTP
> slave per host", for instance.
"Centralised" as session- or system-wide manager? Otherwise the
Scheduler should take care of such things.
Roland
["kdelibs-DNS-cache.patch" (text/x-patch)]
diff --git a/kio/CMakeLists.txt b/kio/CMakeLists.txt
index 8984907..cf4acfe 100644
--- a/kio/CMakeLists.txt
+++ b/kio/CMakeLists.txt
@@ -116,6 +116,7 @@ set(kiocore_STAT_SRCS
kio/slaveinterface.cpp
kio/tcpslavebase.cpp
kio/udsentry.cpp
+ kio/hostinfoagent.cpp
)
qt4_add_dbus_adaptor(kiocore_STAT_SRCS kio/org.kde.kio.FileUndoManager.xml \
fileundomanager_p.h KIO::FileUndoManagerPrivate fileundomanager_adaptor \
KIOFileUndoManagerAdaptor)
diff --git a/kio/kio/global.h b/kio/kio/global.h
index b1fcbc5..4e5d10b 100644
--- a/kio/kio/global.h
+++ b/kio/kio/global.h
@@ -177,7 +177,8 @@ namespace KIO
CMD_READ = 'Z', // 90
CMD_WRITE = 91,
CMD_SEEK = 92,
- CMD_CLOSE = 93
+ CMD_CLOSE = 93,
+ CMD_HOST_INFO = 94
// Add new ones here once a release is done, to avoid breaking binary \
compatibility.
// Note that protocol-specific commands shouldn't be added here, but \
should use special. };
diff --git a/kio/kio/hostinfoagent.cpp b/kio/kio/hostinfoagent.cpp
new file mode 100644
index 0000000..66bf233
--- /dev/null
+++ b/kio/kio/hostinfoagent.cpp
@@ -0,0 +1,181 @@
+/*
+Copyright 2008 Roland Harnau <tau@gmx.eu>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see \
<http://www.gnu.org/licenses/>. +*/
+
+#include "hostinfoagent.h"
+
+#include <QtCore/QString>
+#include <QtCore/QHash>
+#include <QtCore/QCache>
+#include <QtCore/QTime>
+#include <QtCore/QList>
+#include <QtCore/QPair>
+#include <QtCore/QFutureWatcher>
+#include <QtCore/QtConcurrentRun>
+#include <QtNetwork/QHostInfo>
+
+#define TTL 300
+
+namespace KIO
+{
+ class HostInfoAgentPrivate : public QObject
+ {
+ Q_OBJECT
+ public:
+ HostInfoAgentPrivate(int cacheSize = 100);
+ virtual ~HostInfoAgentPrivate() {};
+ void lookupHost(const QString& hostName, QObject* receiver, const \
char* member); + private Q_SLOTS:
+ void queryFinished(const QHostInfo&);
+ private:
+ class Result;
+ class Query;
+
+ QHash<QString, Query*> openQueries;
+ QCache<QString, QPair<QHostInfo, QTime> > dnsCache;
+ };
+
+ class HostInfoAgentPrivate::Result : public QObject
+ {
+ Q_OBJECT
+ Q_SIGNALS:
+ void result(QHostInfo);
+ friend class HostInfoAgentPrivate;
+ };
+
+ class HostInfoAgentPrivate::Query : public QObject
+ {
+ Q_OBJECT
+ public:
+ Query(): m_watcher(), m_hostName()
+ {
+ connect(&m_watcher, SIGNAL(finished()), this, \
SLOT(relayFinished())); + }
+ void start(const QString& hostName)
+ {
+ m_hostName = hostName;
+ QFuture<QHostInfo> future = \
QtConcurrent::run(&QHostInfo::fromName, hostName); + \
m_watcher.setFuture(future); + }
+ QString hostName() const
+ {
+ return m_hostName;
+ }
+ Q_SIGNALS:
+ void result(QHostInfo);
+ private Q_SLOTS:
+ void relayFinished()
+ {
+ Q_EMIT result(m_watcher.result());
+ }
+ private:
+ QFutureWatcher<QHostInfo> m_watcher;
+ QString m_hostName;
+ };
+}
+
+using namespace KIO;
+
+HostInfoAgent::HostInfoAgent(int cacheSize) : d(new \
HostInfoAgentPrivate(cacheSize)) {} +
+HostInfoAgent::~HostInfoAgent()
+{
+ delete(d);
+}
+
+HostInfoAgent* HostInfoAgent::instance()
+{
+ if (m_instance == 0) {
+ m_instance = new HostInfoAgent();
+ }
+ return m_instance;
+}
+
+void HostInfoAgent::lookupHost(const QString& hostName, QObject* receiver, \
const char* member) +{
+ d->lookupHost(hostName, receiver, member);
+}
+
+HostInfoAgent* HostInfoAgent::m_instance;
+
+HostInfoAgentPrivate::HostInfoAgentPrivate(int cacheSize) : openQueries(), \
dnsCache(cacheSize) {} +
+void HostInfoAgentPrivate::lookupHost(const QString& hostName, QObject* \
receiver, const char* member) +{
+ if(dnsCache.contains(hostName)) {
+ QPair<QHostInfo, QTime> info (*dnsCache.object(hostName));
+
+ if (QTime::currentTime() <= info.second.addSecs(TTL)) {
+ Result result;
+ QObject::connect(&result, SIGNAL(result(QHostInfo)),receiver, \
member); + Q_EMIT result.result(info.first);
+ return;
+ }
+ dnsCache.remove(hostName);
+ }
+
+ if (openQueries.contains(hostName)) {
+ Query* query = openQueries.value(hostName);
+ connect(query, SIGNAL(result(QHostInfo)), receiver, member);
+ return;
+ }
+
+ Query* query = new Query();
+ openQueries.insert(hostName, query);
+ connect(query, SIGNAL(result(QHostInfo)), this, \
SLOT(queryFinished(QHostInfo))); + connect(query, \
SIGNAL(result(QHostInfo)), receiver, member); + query->start(hostName);
+}
+
+void HostInfoAgentPrivate::queryFinished(const QHostInfo& info)
+{
+ Query* query = static_cast<Query* >(sender());
+
+ openQueries.remove(query->hostName());
+ if (!info.addresses().isEmpty())
+ dnsCache.insert(query->hostName(),
+ new QPair<QHostInfo, QTime>(info, QTime::currentTime()));
+
+ query->deleteLater();
+}
+
+QDataStream& operator<<(QDataStream& out, const QHostInfo& info)
+{
+ out << info.hostName() << info.addresses() << info.error() << \
info.errorString(); + return out;
+}
+
+QDataStream& operator>>(QDataStream& in, QHostInfo& info)
+{
+ QString hostName;
+ QList<QHostAddress> addresses;
+ int error;
+ QString errorString;
+
+ in >> hostName >> addresses >> error >> errorString;
+
+ info.setHostName(hostName);
+ info.setAddresses(addresses);
+ info.setError(QHostInfo::HostInfoError(error));
+ info.setErrorString(errorString);
+
+ return in;
+}
+
+#include "hostinfoagent.moc"
diff --git a/kio/kio/hostinfoagent.h b/kio/kio/hostinfoagent.h
new file mode 100644
index 0000000..c1ce03b
--- /dev/null
+++ b/kio/kio/hostinfoagent.h
@@ -0,0 +1,49 @@
+/*
+Copyright 2008 Roland Harnau <tau@gmx.eu>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see \
<http://www.gnu.org/licenses/>. +*/
+
+#ifndef HOSTINFO_H_
+#define HOSTINFO_H_
+
+#include <QtCore/QString>
+#include <QtCore/QDataStream>
+#include <QtNetwork/QHostInfo>
+
+namespace KIO
+{
+ class HostInfoAgentPrivate;
+
+ class HostInfoAgent
+ {
+ public:
+ static HostInfoAgent* instance();
+ void lookupHost(const QString& hostName, QObject* receiver, const \
char* member); + private:
+ HostInfoAgent(int cacheSize = 100);
+ ~HostInfoAgent();
+ static HostInfoAgent* m_instance;
+
+ HostInfoAgentPrivate* d;
+ };
+}
+
+QDataStream& operator<<(QDataStream& out, const QHostInfo& info);
+QDataStream& operator>>(QDataStream& in, QHostInfo& info);
+
+#endif
diff --git a/kio/kio/slavebase.cpp b/kio/kio/slavebase.cpp
index 9485da1..8ce03a2 100644
--- a/kio/kio/slavebase.cpp
+++ b/kio/kio/slavebase.cpp
@@ -22,6 +22,7 @@
**/
#include "slavebase.h"
+#include "hostinfoagent.h"
#include <config.h>
@@ -1330,3 +1331,25 @@ void SlaveBase::send(int cmd, const QByteArray& arr \
)
void SlaveBase::virtual_hook( int, void* )
{ /*BASE::virtual_hook( id, data );*/ }
+
+void SlaveBase::lookupHost(const QString& host)
+{
+ KIO_DATA << host;
+ send(MSG_HOST_INFO_REQ, data);
+}
+
+int SlaveBase::waitForHostInfo(QHostInfo& info)
+{
+ QByteArray data;
+ int result = waitForAnswer(CMD_HOST_INFO, 0, data);
+
+ if (result == -1){
+ info.setError(QHostInfo::UnknownError);
+ info.setErrorString("Unknown Error.");
+ return result;
+ }
+
+ QDataStream stream(data);
+ stream >> info;
+ return result;
+}
diff --git a/kio/kio/slavebase.h b/kio/kio/slavebase.h
index 7d87e95..412389e 100644
--- a/kio/kio/slavebase.h
+++ b/kio/kio/slavebase.h
@@ -27,6 +27,7 @@
#include <klocale.h>
#include <QtCore/QByteArray>
+#include <QtNetwork/QHostInfo>
class KConfigGroup;
class KRemoteEncoding;
@@ -774,6 +775,16 @@ public:
*/
void setKillFlag();
+ /** Internally used
+ * @internal
+ */
+ void lookupHost(const QString& host);
+
+ /** Internally used
+ * @internal
+ */
+ int waitForHostInfo(QHostInfo& info);
+
protected:
/**
* Name of the protocol supported by this slave
diff --git a/kio/kio/slaveinterface.cpp b/kio/kio/slaveinterface.cpp
index 8e41ea7..54043ff 100644
--- a/kio/kio/slaveinterface.cpp
+++ b/kio/kio/slaveinterface.cpp
@@ -21,6 +21,7 @@
#include "slavebase.h"
#include "connection.h"
+#include "hostinfoagent.h"
#include <errno.h>
#include <assert.h>
#include <kdebug.h>
@@ -336,7 +337,13 @@ bool SlaveInterface::dispatch( int _cmd, const \
QByteArray &rawdata ) emit needSubUrlData();
break;
}
- default:
+ case MSG_HOST_INFO_REQ: {
+ QString hostName;
+ stream >> hostName;
+ HostInfoAgent::instance()->lookupHost(hostName, this, \
SLOT(setHostInfo(QHostInfo))); + break;
+ }
+ default:
kWarning(7007) << "Slave sends unknown command (" << _cmd << "), \
dropping slave"; return false;
}
@@ -496,4 +503,13 @@ int SlaveInterfacePrivate::messageBox(int type, const \
QString &text, return result;
}
+void SlaveInterface::setHostInfo(const QHostInfo& info)
+{
+ Q_D(SlaveInterface);
+ QByteArray data;
+ QDataStream stream(&data, QIODevice::WriteOnly);
+ stream << info;
+ d->connection->send(CMD_HOST_INFO, data);
+}
+
#include "slaveinterface.moc"
diff --git a/kio/kio/slaveinterface.h b/kio/kio/slaveinterface.h
index d17c5c2..d3be6b4 100644
--- a/kio/kio/slaveinterface.h
+++ b/kio/kio/slaveinterface.h
@@ -24,6 +24,7 @@
#include <sys/types.h>
#include <QtCore/QObject>
+#include <QtNetwork/QHostInfo>
#include <kio/global.h>
#include <kio/udsentry.h>
@@ -82,7 +83,8 @@ class SlaveInterfacePrivate;
MSG_AUTH_KEY, // 115 // deprecated.
MSG_DEL_AUTH_KEY, // deprecated.
MSG_OPENED,
- MSG_WRITTEN
+ MSG_WRITTEN,
+ MSG_HOST_INFO_REQ
// add new ones here once a release is done, to avoid breaking binary \
compatibility };
@@ -169,10 +171,11 @@ protected:
protected Q_SLOTS:
void calcSpeed();
-
protected:
SlaveInterfacePrivate* const d_ptr;
Q_DECLARE_PRIVATE(SlaveInterface)
+private Q_SLOTS:
+ void setHostInfo(const QHostInfo& info);
};
}
diff --git a/kio/kio/tcpslavebase.cpp b/kio/kio/tcpslavebase.cpp
index e281cae..cd62a1f 100644
--- a/kio/kio/tcpslavebase.cpp
+++ b/kio/kio/tcpslavebase.cpp
@@ -2,7 +2,8 @@
* Copyright (C) 2000 Alex Zepeda <zipzippy@sonic.net
* Copyright (C) 2001-2003 George Staikos <staikos@kde.org>
* Copyright (C) 2001 Dawit Alemayehu <adawit@kde.org>
- * Copyright (C) 2007,2008 Andreas Hartmetz <ahartmetz@gmail.com>
+ * Copyright (C) 2007,2008 Andreas Hartmetz <ahartmetz@gmail.com>
+ * Copyright (C) 2008 Roland Harnau <tau@gmx.eu>
*
* This file is part of the KDE project
*
@@ -279,25 +280,32 @@ bool TCPSlaveBase::connectToHost(const QString \
&/*protocol*/,
//FIXME! KTcpSocket doesn't know or care about protocol ports! Fix \
it there, then use it here.
- kDebug(7029) << "before connectToHost: Socket error is"
- << d->socket.error() << ", Socket state is" << \
d->socket.state();
- d->socket.connectToHost(host, port);
- kDebug(7029) << "after connectToHost: Socket error is"
- << d->socket.error() << ", Socket state is" << \
d->socket.state(); + QHostAddress address;
+ QList<QHostAddress> addresses;
- bool connectOk = d->socket.waitForConnected(d->timeout > -1 ? \
d->timeout * 1000 : -1);
- kDebug(7029) << "after waitForConnected: Socket error is"
- << d->socket.error() << ", Socket state is" << \
d->socket.state()
- << ", waitForConnected returned " << connectOk;
+ if (address.setAddress(host)){
+ addresses.append(address);
+ } else {
+ QHostInfo info;
+ lookupHost(host);
+ waitForHostInfo(info);
+ if (info.error() != QHostInfo::NoError){
+ error(ERR_UNKNOWN_HOST, info.errorString());
+ return false;
+ }
+ addresses = info.addresses();
+ }
+
+ QListIterator<QHostAddress> it(addresses);
+ while (it.hasNext()){
+ d->socket.connectToHost(it.next(), port);
+ bool connectOk = d->socket.waitForConnected(d->timeout > -1 ? \
d->timeout * 1000 : -1); + if (connectOk) break;
+ }
if (d->socket.state() != KTcpSocket::ConnectedState) {
- if (d->socket.error() == KTcpSocket::HostNotFoundError) {
- error(ERR_UNKNOWN_HOST,
+ error(ERR_COULD_NOT_CONNECT,
host + QLatin1String(": ") + \
d->socket.errorString());
- } else {
- error(ERR_COULD_NOT_CONNECT,
- host + QLatin1String(": ") + \
d->socket.errorString());
- }
return false;
}
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic