summaryrefslogtreecommitdiffstats
path: root/src/network/kernel
diff options
context:
space:
mode:
authorAaron Tunney <ext-aaron.2.tunney@nokia.com>2011-03-09 14:26:43 (GMT)
committerAaron Tunney <ext-aaron.2.tunney@nokia.com>2011-03-17 14:26:45 (GMT)
commit6f7076d6fe80f656d8d2f7f1b005dc138b05bef3 (patch)
tree6fd42f51a9c05a267c675b739b9979b63c9238ce /src/network/kernel
parent8f239f0b0cb7faa580ba66197f56fb3d8109aaf7 (diff)
downloadQt-6f7076d6fe80f656d8d2f7f1b005dc138b05bef3.zip
Qt-6f7076d6fe80f656d8d2f7f1b005dc138b05bef3.tar.gz
Qt-6f7076d6fe80f656d8d2f7f1b005dc138b05bef3.tar.bz2
Implementation of async DNS lookup.
Reviewed-by: Shane Kearns
Diffstat (limited to 'src/network/kernel')
-rw-r--r--src/network/kernel/qhostinfo.cpp53
-rw-r--r--src/network/kernel/qhostinfo_p.h115
-rw-r--r--src/network/kernel/qhostinfo_symbian.cpp323
3 files changed, 473 insertions, 18 deletions
diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp
index 5ec6041..7a15a05 100644
--- a/src/network/kernel/qhostinfo.cpp
+++ b/src/network/kernel/qhostinfo.cpp
@@ -56,10 +56,14 @@
QT_BEGIN_NAMESPACE
-Q_GLOBAL_STATIC(QHostInfoLookupManager, theHostInfoLookupManager)
-
//#define QHOSTINFO_DEBUG
+#ifndef Q_OS_SYMBIAN
+Q_GLOBAL_STATIC(QHostInfoLookupManager, theHostInfoLookupManager)
+#else
+Q_GLOBAL_STATIC(QSymbianHostInfoLookupManger, theHostInfoLookupManager)
+#endif
+
/*!
\class QHostInfo
\brief The QHostInfo class provides static functions for host name lookups.
@@ -152,6 +156,7 @@ int QHostInfo::lookupHost(const QString &name, QObject *receiver,
qDebug("QHostInfo::lookupHost(\"%s\", %p, %s)",
name.toLatin1().constData(), receiver, member ? member + 1 : 0);
#endif
+
if (!QAbstractEventDispatcher::instance(QThread::currentThread())) {
qWarning("QHostInfo::lookupHost() called with no event dispatcher");
return -1;
@@ -172,7 +177,9 @@ int QHostInfo::lookupHost(const QString &name, QObject *receiver,
return id;
}
+#ifndef Q_OS_SYMBIAN
QHostInfoLookupManager *manager = theHostInfoLookupManager();
+
if (manager) {
// the application is still alive
if (manager->cache.isEnabled()) {
@@ -187,11 +194,38 @@ int QHostInfo::lookupHost(const QString &name, QObject *receiver,
return id;
}
}
+
// cache is not enabled or it was not in the cache, do normal lookup
QHostInfoRunnable* runnable = new QHostInfoRunnable(name, id);
QObject::connect(&runnable->resultEmitter, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection);
manager->scheduleLookup(runnable);
}
+#else
+ QSymbianHostInfoLookupManger *manager = theHostInfoLookupManager();
+
+ if (manager) {
+ // the application is still alive
+ if (manager->cache.isEnabled()) {
+ // check cache first
+ bool valid = false;
+ QHostInfo info = manager->cache.get(name, &valid);
+ if (valid) {
+ info.setLookupId(id);
+ QHostInfoResult result;
+ QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection);
+ result.emitResultsReady(info);
+ return id;
+ }
+ }
+
+ // cache is not enabled or it was not in the cache, do normal lookup
+ QSymbianHostResolver *symbianResolver = 0;
+ QT_TRAP_THROWING(symbianResolver = new QSymbianHostResolver(name, id));
+ QObject::connect(&symbianResolver->resultEmitter, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection);
+ manager->scheduleLookup(symbianResolver);
+ }
+#endif
+
return id;
}
@@ -225,7 +259,7 @@ QHostInfo QHostInfo::fromName(const QString &name)
#endif
QHostInfo hostInfo = QHostInfoAgent::fromName(name);
- QHostInfoLookupManager *manager = theHostInfoLookupManager();
+ QAbstractHostInfoLookupManger* manager = theHostInfoLookupManager();
manager->cache.put(name, hostInfo);
return hostInfo;
}
@@ -406,6 +440,7 @@ void QHostInfo::setErrorString(const QString &str)
\sa hostName()
*/
+#ifndef Q_OS_SYMBIAN
QHostInfoRunnable::QHostInfoRunnable(QString hn, int i) : toBeLookedUp(hn), id(i)
{
setAutoDelete(true);
@@ -632,6 +667,7 @@ void QHostInfoLookupManager::lookupFinished(QHostInfoRunnable *r)
finishedLookups.append(r);
work();
}
+#endif
// This function returns immediately when we had a result in the cache, else it will later emit a signal
QHostInfo qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char *member, bool *valid, int *id)
@@ -640,7 +676,7 @@ QHostInfo qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char
*id = -1;
// check cache
- QHostInfoLookupManager* manager = theHostInfoLookupManager();
+ QAbstractHostInfoLookupManger* manager = theHostInfoLookupManager();
if (manager && manager->cache.isEnabled()) {
QHostInfo info = manager->cache.get(name, valid);
if (*valid) {
@@ -657,7 +693,7 @@ QHostInfo qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char
void qt_qhostinfo_clear_cache()
{
- QHostInfoLookupManager* manager = theHostInfoLookupManager();
+ QAbstractHostInfoLookupManger* manager = theHostInfoLookupManager();
if (manager) {
manager->clear();
}
@@ -665,7 +701,7 @@ void qt_qhostinfo_clear_cache()
void Q_AUTOTEST_EXPORT qt_qhostinfo_enable_cache(bool e)
{
- QHostInfoLookupManager* manager = theHostInfoLookupManager();
+ QAbstractHostInfoLookupManger* manager = theHostInfoLookupManager();
if (manager) {
manager->cache.setEnabled(e);
}
@@ -733,4 +769,9 @@ void QHostInfoCache::clear()
cache.clear();
}
+QAbstractHostInfoLookupManger* QAbstractHostInfoLookupManger::globalInstance()
+{
+ return theHostInfoLookupManager();
+}
+
QT_END_NAMESPACE
diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h
index b568ec2..ec7a63e 100644
--- a/src/network/kernel/qhostinfo_p.h
+++ b/src/network/kernel/qhostinfo_p.h
@@ -69,9 +69,18 @@
#include <QElapsedTimer>
#include <QCache>
+#include <QNetworkSession>
+
+#ifdef Q_OS_SYMBIAN
+// Symbian Headers
+#include <es_sock.h>
+#include <in_sock.h>
+#endif
+
QT_BEGIN_NAMESPACE
+
class QHostInfoResult : public QObject
{
Q_OBJECT
@@ -91,6 +100,12 @@ class QHostInfoAgent : public QObject
Q_OBJECT
public:
static QHostInfo fromName(const QString &hostName);
+ static QHostInfo fromName(const QString &hostName, QSharedPointer<QNetworkSession> networkSession);
+
+#ifdef Q_OS_SYMBIAN
+ static int lookupHost(const QString &name, QObject *receiver, const char *member);
+ static void abortHostLookup(int lookupId);
+#endif
};
class QHostInfoPrivate
@@ -151,7 +166,25 @@ public:
QHostInfoResult resultEmitter;
};
-class QHostInfoLookupManager : public QObject
+
+class QAbstractHostInfoLookupManger : public QObject
+{
+ Q_OBJECT
+
+public:
+ ~QAbstractHostInfoLookupManger() {}
+ virtual void clear() = 0;
+
+ QHostInfoCache cache;
+
+protected:
+ QAbstractHostInfoLookupManger() {}
+ static QAbstractHostInfoLookupManger* globalInstance();
+
+};
+
+#ifndef Q_OS_SYMBIAN
+class QHostInfoLookupManager : public QAbstractInfoLookupManager
{
Q_OBJECT
public:
@@ -169,8 +202,6 @@ public:
void lookupFinished(QHostInfoRunnable *r);
bool wasAborted(int id);
- QHostInfoCache cache;
-
friend class QHostInfoRunnable;
protected:
QList<QHostInfoRunnable*> currentLookups; // in progress
@@ -189,6 +220,84 @@ private slots:
void waitForThreadPoolDone() { threadPool.waitForDone(); }
};
+#else
+
+class QSymbianHostResolver : public CActive
+{
+public:
+ QSymbianHostResolver(const QString &hostName, int id);
+ ~QSymbianHostResolver();
+
+ QHostInfo requestHostLookup();
+ int id();
+
+ QHostInfoResult resultEmitter;
+
+private:
+ void DoCancel();
+ void RunL();
+ void run();
+ TInt RunError(TInt aError);
+
+ void processNameResults();
+ void processAddressResults();
+
+private:
+ int iId;
+
+ const QString iHostName;
+
+ RSocketServ& iSocketServ;
+ RHostResolver iHostResolver;
+
+ TRequestStatus iStatus;
+
+ TNameEntry iNameResult;
+ QHostAddress iAddress;
+
+ QHostInfo iResults;
+
+ enum {
+ EIdle,
+ EGetByName,
+ EGetByAddress
+ } iState;
+};
+
+class QSymbianHostInfoLookupManger : public QAbstractHostInfoLookupManger
+{
+ Q_OBJECT
+public:
+ QSymbianHostInfoLookupManger();
+ ~QSymbianHostInfoLookupManger();
+
+ static QSymbianHostInfoLookupManger* globalInstance();
+
+ int id();
+ void clear();
+
+ // called from QHostInfo
+ void scheduleLookup(QSymbianHostResolver *r);
+ void abortLookup(int id);
+
+ // called from QSymbianHostResolver
+ void lookupFinished(QSymbianHostResolver *r);
+
+private:
+ void runNextLookup();
+
+ static const int KMaxConcurrentLookups = 5;
+
+ RPointerArray<QSymbianHostResolver> iCurrentLookups;
+ RPointerArray<QSymbianHostResolver> iScheduledLookups;
+ RPointerArray<QSymbianHostResolver> iFinishedLookups;
+
+ QMutex mutex;
+};
+#endif
+
+
+
QT_END_NAMESPACE
#endif // QHOSTINFO_P_H
diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp
index 9599274..2b582bd 100644
--- a/src/network/kernel/qhostinfo_symbian.cpp
+++ b/src/network/kernel/qhostinfo_symbian.cpp
@@ -41,10 +41,6 @@
//#define QHOSTINFO_DEBUG
-// Symbian Headers
-#include <es_sock.h>
-#include <in_sock.h>
-
// Qt Headers
#include <QByteArray>
#include <QUrl>
@@ -54,11 +50,13 @@
#include "qhostinfo_p.h"
#include <private/qcore_symbian_p.h>
+#include <private/qsystemerror_p.h>
QT_BEGIN_NAMESPACE
-QHostInfo QHostInfoAgent::fromName(const QString &hostName)
+
+QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointer<QNetworkSession> networkSession)
{
QHostInfo results;
@@ -66,12 +64,20 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
RSocketServ socketServ(qt_symbianGetSocketServer());
RHostResolver hostResolver;
+
+ // TODO - check if networkSession is null
+ // RConnection connection = magicalApi(networkSession);
+ // int err = connection.Open(blah, blah);
+ // if (err) {
+ // do something;
+ // }
+
// Will return both IPv4 and IPv6
// TODO: Pass RHostResolver.Open() the global RConnection
int err = hostResolver.Open(socketServ, KAfInet, KProtocolInetUdp);
if (err) {
results.setError(QHostInfo::UnknownError);
- results.setErrorString(tr("Symbian error code: %1").arg(err));
+ results.setErrorString(QSystemError(err,QSystemError::NativeError).toString());
return results;
}
@@ -99,7 +105,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
results.setErrorString(tr("Host not found"));
} else {
results.setError(QHostInfo::UnknownError);
- results.setErrorString(tr("Symbian error code: %1").arg(err));
+ results.setErrorString(QSystemError(err,QSystemError::NativeError).toString());
}
return results;
@@ -134,7 +140,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
results.setErrorString(tr("Host not found"));
} else {
results.setError(QHostInfo::UnknownError);
- results.setErrorString(tr("Symbian error code: %1").arg(err));
+ results.setErrorString(QSystemError(err,QSystemError::NativeError).toString());
}
return results;
@@ -156,7 +162,8 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
hostAdd = nameResult().iAddr;
hostAdd.Output(ipAddr);
- if (ipAddr.Length() > 0) {
+ // Ensure that record is valid (not an alias and with length greater than 0)
+ if (!(nameResult().iFlags & TNameRecord::EAlias) && (ipAddr.Length() > 0)) {
if (nameResult().iAddr.Family() == KAfInet) {
// IPv4 - prepend
hostAddresses.prepend(QHostAddress(qt_TDesC2QString(ipAddr)));
@@ -173,6 +180,13 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
return results;
}
+QHostInfo QHostInfoAgent::fromName(const QString &hostName)
+{
+ // null shared pointer
+ QSharedPointer<QNetworkSession> networkSession;
+ return fromName(hostName, networkSession);
+}
+
QString QHostInfo::localHostName()
{
// Connect to ESOCK
@@ -201,4 +215,295 @@ QString QHostInfo::localDomainName()
return QString();
}
+
+QSymbianHostResolver::QSymbianHostResolver(const QString &hostName, int identifier)
+ : CActive(CActive::EPriorityStandard), iId(identifier), iHostName(hostName),
+ iSocketServ(qt_symbianGetSocketServer())
+{
+ CActiveScheduler::Add(this);
+}
+
+QSymbianHostResolver::~QSymbianHostResolver()
+{
+ Cancel();
+ iHostResolver.Close();
+}
+
+// Async equivalent to QHostInfoAgent::fromName()
+QHostInfo QSymbianHostResolver::requestHostLookup()
+{
+
+#if defined(QHOSTINFO_DEBUG)
+ qDebug("QHostInfoAgent::fromName(%s) looking up...",
+ hostName.toLatin1().constData());
+#endif
+
+ int err = iHostResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp);
+ if (err) {
+ // What are we doing with iResults??
+ iResults.setError(QHostInfo::UnknownError);
+ iResults.setErrorString(QObject::tr("Symbian error code: %1").arg(err));
+
+ iHostResolver.Close();
+ return iResults;
+ }
+
+ if (iAddress.setAddress(iHostName)) {
+ // Reverse lookup
+
+ TInetAddr IpAdd;
+ IpAdd.Input(qt_QString2TPtrC(iHostName));
+
+ // Asynchronous request.
+ iHostResolver.GetByAddress(IpAdd, iNameResult, iStatus); // <---- ASYNC
+ iState = EGetByAddress;
+
+ } else {
+
+ // IDN support
+ QByteArray aceHostname = QUrl::toAce(iHostName);
+ iResults.setHostName(iHostName);
+ if (aceHostname.isEmpty()) {
+ iResults.setError(QHostInfo::HostNotFound);
+ iResults.setErrorString(iHostName.isEmpty() ?
+ QCoreApplication::translate("QHostInfoAgent", "No host name given") :
+ QCoreApplication::translate("QHostInfoAgent", "Invalid hostname"));
+
+ iHostResolver.Close();
+ return iResults;
+ }
+
+ // Asynchronous request.
+ iHostResolver.GetByName(qt_QString2TPtrC(QString::fromLatin1(aceHostname)), iNameResult, iStatus);
+ iState = EGetByName;
+ }
+
+ SetActive();
+
+ return iResults;
+}
+
+void QSymbianHostResolver::DoCancel()
+{
+ QSymbianHostInfoLookupManger *manager = QSymbianHostInfoLookupManger::globalInstance();
+ manager->lookupFinished(this);
+ iHostResolver.Cancel();
+}
+
+void QSymbianHostResolver::RunL()
+{
+ QT_TRYCATCH_LEAVING(run());
+}
+
+void QSymbianHostResolver::run()
+{
+ if (iState == EGetByName)
+ processNameResults();
+ else if (iState == EGetByAddress)
+ processAddressResults();
+
+ iState = EIdle;
+
+ QSymbianHostInfoLookupManger *manager = QSymbianHostInfoLookupManger::globalInstance();
+ manager->lookupFinished(this);
+
+ resultEmitter.emitResultsReady(iResults);
+
+ delete this;
+}
+
+TInt QSymbianHostResolver::RunError(TInt aError)
+{
+ QT_TRY {
+ iState = EIdle;
+
+ QSymbianHostInfoLookupManger *manager = QSymbianHostInfoLookupManger::globalInstance();
+ manager->lookupFinished(this);
+
+ iResults.setError(QHostInfo::UnknownError);
+ iResults.setErrorString(QSystemError(aError,QSystemError::NativeError).toString());
+
+ resultEmitter.emitResultsReady(iResults);
+ }
+ QT_CATCH(...) {}
+
+ delete this;
+
+ return KErrNone;
+}
+
+void QSymbianHostResolver::processNameResults()
+{
+ TInt err = iStatus.Int();
+ if (err < 0) {
+ // TODO - Could there be other errors? Symbian docs don't say.
+ if (err = KErrNotFound) {
+ iResults.setError(QHostInfo::HostNotFound);
+ iResults.setErrorString(QObject::tr("Host not found"));
+ } else {
+ iResults.setError(QHostInfo::UnknownError);
+ iResults.setErrorString(QSystemError(err,QSystemError::NativeError).toString());
+ }
+
+ iHostResolver.Close();
+ return;
+ }
+
+ QList<QHostAddress> hostAddresses;
+
+ TInetAddr hostAdd = iNameResult().iAddr;
+ // 39 is the maximum length of an IPv6 address.
+ TBuf<39> ipAddr;
+
+ // Fill ipAddr with the IP address from hostAdd
+ hostAdd.Output(ipAddr);
+ if (ipAddr.Length() > 0)
+ hostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr)));
+
+ // Check if there's more than one IP address linkd to this name
+ while (iHostResolver.Next(iNameResult) == KErrNone) {
+ hostAdd = iNameResult().iAddr;
+ hostAdd.Output(ipAddr);
+
+ // Ensure that record is valid (not an alias and with length greater than 0)
+ if (!(iNameResult().iFlags & TNameRecord::EAlias) && (ipAddr.Length() > 0)) {
+ if (iNameResult().iAddr.Family() == KAfInet) {
+ // IPv4 - prepend
+ hostAddresses.prepend(QHostAddress(qt_TDesC2QString(ipAddr)));
+ } else {
+ // IPv6 - append
+ hostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr)));
+ }
+ }
+ }
+
+ iResults.setAddresses(hostAddresses);
+}
+
+void QSymbianHostResolver::processAddressResults()
+{
+ TInt err = iStatus.Int();
+
+ if (err < 0) {
+ // TODO - Could there be other errors? Symbian docs don't say.
+ if (err = KErrNotFound) {
+ iResults.setError(QHostInfo::HostNotFound);
+ iResults.setErrorString(QObject::tr("Host not found"));
+ } else {
+ iResults.setError(QHostInfo::UnknownError);
+ iResults.setErrorString(QSystemError(err,QSystemError::NativeError).toString());
+ }
+
+ return;
+ }
+
+ iResults.setHostName(qt_TDesC2QString(iNameResult().iName));
+ iResults.setAddresses(QList<QHostAddress>() << iAddress);
+}
+
+
+int QSymbianHostResolver::id()
+{
+ return iId;
+}
+
+QSymbianHostInfoLookupManger::QSymbianHostInfoLookupManger()
+{
+}
+
+QSymbianHostInfoLookupManger::~QSymbianHostInfoLookupManger()
+{
+ iCurrentLookups.Close();
+ iScheduledLookups.Close();
+}
+
+void QSymbianHostInfoLookupManger::clear()
+{
+ QMutexLocker locker(&mutex);
+ iCurrentLookups.ResetAndDestroy();
+ iScheduledLookups.ResetAndDestroy();
+}
+
+void QSymbianHostInfoLookupManger::lookupFinished(QSymbianHostResolver *r)
+{
+ QMutexLocker locker(&mutex);
+
+ // remove finished lookup from array and destroy
+ TInt count = iCurrentLookups.Count();
+ for (TInt i = 0; i < count; i++) {
+ if (iCurrentLookups[i]->id() == r->id()) {
+ iCurrentLookups.Remove(i);
+ break;
+ }
+ }
+
+ runNextLookup();
+}
+
+void QSymbianHostInfoLookupManger::runNextLookup()
+{
+ // check to see if there are any scheduled lookups
+ if (iScheduledLookups.Count() > 0) {
+ // if so, move one to the current lookups and run it
+ // FIFO
+ QSymbianHostResolver* hostResolver = iScheduledLookups[0];
+ iCurrentLookups.Append(hostResolver);
+ iScheduledLookups.Remove(0);
+ hostResolver->requestHostLookup();
+ }
+}
+
+// called from QHostInfo
+void QSymbianHostInfoLookupManger::scheduleLookup(QSymbianHostResolver* r)
+{
+ QMutexLocker locker(&mutex);
+
+ // Check to see if we have space on the current lookups pool.
+ if (iCurrentLookups.Count() >= KMaxConcurrentLookups) {
+ // If no, schedule for later.
+ iScheduledLookups.Append(r);
+ return;
+ } else {
+ // If yes, add it to the current lookups.
+ iCurrentLookups.Append(r);
+
+ // ... and trigger the async call.
+ r->requestHostLookup();
+ }
+}
+
+void QSymbianHostInfoLookupManger::abortLookup(int id)
+{
+ QMutexLocker locker(&mutex);
+
+ int i = 0;
+ // Find the aborted lookup by ID.
+ // First in the current lookups.
+ for (i = 0; i < iCurrentLookups.Count(); i++) {
+ if (id = iCurrentLookups[i]->id()) {
+ QSymbianHostResolver* r = iCurrentLookups[i];
+ iCurrentLookups.Remove(i);
+ r->Cancel();
+ runNextLookup();
+ return;
+ }
+ }
+ // Then in the scheduled lookups.
+ for (i = 0; i < iScheduledLookups.Count(); i++) {
+ if (id = iScheduledLookups[i]->id()) {
+ QSymbianHostResolver* r = iScheduledLookups[i];
+ iScheduledLookups.Remove(i);
+ delete r;
+ return;
+ }
+ }
+}
+
+
+QSymbianHostInfoLookupManger* QSymbianHostInfoLookupManger::globalInstance()
+{
+ return static_cast<QSymbianHostInfoLookupManger*>
+ (QAbstractHostInfoLookupManger::globalInstance());
+}
+
QT_END_NAMESPACE