summaryrefslogtreecommitdiffstats
path: root/src/network/kernel
diff options
context:
space:
mode:
authorSami Lempinen <sami.lempinen@nokia.com>2011-04-28 08:10:57 (GMT)
committerSami Lempinen <sami.lempinen@nokia.com>2011-04-28 08:10:57 (GMT)
commit95de3f34d9dba4cd95f1f3d32b35c4a4d97e70d9 (patch)
tree7be35a9028b5c83b792190fb954127e9f558baf5 /src/network/kernel
parent9d6530b9774de482b0b3a29720f7f756e986f5c7 (diff)
parent8e615d9b07f6146b5cb6b56c4cd2e32376a8b429 (diff)
downloadQt-95de3f34d9dba4cd95f1f3d32b35c4a4d97e70d9.zip
Qt-95de3f34d9dba4cd95f1f3d32b35c4a4d97e70d9.tar.gz
Qt-95de3f34d9dba4cd95f1f3d32b35c4a4d97e70d9.tar.bz2
Merge remote-tracking branch 'qt/4.8'
Diffstat (limited to 'src/network/kernel')
-rw-r--r--src/network/kernel/kernel.pri2
-rw-r--r--src/network/kernel/qhostinfo.cpp84
-rw-r--r--src/network/kernel/qhostinfo_p.h131
-rw-r--r--src/network/kernel/qhostinfo_symbian.cpp600
-rw-r--r--src/network/kernel/qhostinfo_unix.cpp13
-rw-r--r--src/network/kernel/qnetworkinterface_symbian.cpp140
6 files changed, 892 insertions, 78 deletions
diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri
index bd3e6ec..bb98305 100644
--- a/src/network/kernel/kernel.pri
+++ b/src/network/kernel/kernel.pri
@@ -20,7 +20,7 @@ SOURCES += kernel/qauthenticator.cpp \
kernel/qnetworkproxy.cpp \
kernel/qnetworkinterface.cpp
-symbian: SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_symbian.cpp
+symbian: SOURCES += kernel/qhostinfo_symbian.cpp kernel/qnetworkinterface_symbian.cpp
unix:!symbian:SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp
win32:SOURCES += kernel/qhostinfo_win.cpp kernel/qnetworkinterface_win.cpp
integrity:SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp
diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp
index 5ec6041..c86f510 100644
--- a/src/network/kernel/qhostinfo.cpp
+++ b/src/network/kernel/qhostinfo.cpp
@@ -49,6 +49,7 @@
#include <qstringlist.h>
#include <qthread.h>
#include <qurl.h>
+#include <private/qnetworksession_p.h>
#ifdef Q_OS_UNIX
# include <unistd.h>
@@ -56,10 +57,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(QSymbianHostInfoLookupManager, theHostInfoLookupManager)
+#endif
+
/*!
\class QHostInfo
\brief The QHostInfo class provides static functions for host name lookups.
@@ -152,6 +157,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 +178,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 +195,45 @@ 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
+ QSymbianHostInfoLookupManager *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
+#ifndef QT_NO_BEARERMANAGEMENT
+ QSharedPointer<QNetworkSession> networkSession;
+ QVariant v(receiver->property("_q_networksession"));
+ if (v.isValid())
+ networkSession = qvariant_cast< QSharedPointer<QNetworkSession> >(v);
+#endif
+
+ QSymbianHostResolver *symbianResolver = 0;
+ QT_TRAP_THROWING(symbianResolver = new QSymbianHostResolver(name, id, networkSession));
+ QObject::connect(&symbianResolver->resultEmitter, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection);
+ manager->scheduleLookup(symbianResolver);
+ }
+#endif
+
return id;
}
@@ -225,10 +267,33 @@ QHostInfo QHostInfo::fromName(const QString &name)
#endif
QHostInfo hostInfo = QHostInfoAgent::fromName(name);
- QHostInfoLookupManager *manager = theHostInfoLookupManager();
+ QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager();
+ manager->cache.put(name, hostInfo);
+ return hostInfo;
+}
+
+#ifndef QT_NO_BEARERMANAGEMENT
+QHostInfo QHostInfoPrivate::fromName(const QString &name, QSharedPointer<QNetworkSession> session)
+{
+#if defined QHOSTINFO_DEBUG
+ qDebug("QHostInfoPrivate::fromName(\"%s\") with session %p",name.toLatin1().constData(), session.data());
+#endif
+
+ QHostInfo hostInfo = QHostInfoAgent::fromName(name, session);
+ QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager();
manager->cache.put(name, hostInfo);
return hostInfo;
}
+#endif
+
+#ifndef Q_OS_SYMBIAN
+// This function has a special implementation for symbian right now in qhostinfo_symbian.cpp but not on other OS.
+QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointer<QNetworkSession>)
+{
+ return QHostInfoAgent::fromName(hostName);
+}
+#endif
+
/*!
\enum QHostInfo::HostInfoError
@@ -406,6 +471,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 +698,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 +707,7 @@ QHostInfo qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char
*id = -1;
// check cache
- QHostInfoLookupManager* manager = theHostInfoLookupManager();
+ QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager();
if (manager && manager->cache.isEnabled()) {
QHostInfo info = manager->cache.get(name, valid);
if (*valid) {
@@ -657,7 +724,7 @@ QHostInfo qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char
void qt_qhostinfo_clear_cache()
{
- QHostInfoLookupManager* manager = theHostInfoLookupManager();
+ QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager();
if (manager) {
manager->clear();
}
@@ -665,7 +732,7 @@ void qt_qhostinfo_clear_cache()
void Q_AUTOTEST_EXPORT qt_qhostinfo_enable_cache(bool e)
{
- QHostInfoLookupManager* manager = theHostInfoLookupManager();
+ QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager();
if (manager) {
manager->cache.setEnabled(e);
}
@@ -733,4 +800,9 @@ void QHostInfoCache::clear()
cache.clear();
}
+QAbstractHostInfoLookupManager* QAbstractHostInfoLookupManager::globalInstance()
+{
+ return theHostInfoLookupManager();
+}
+
QT_END_NAMESPACE
diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h
index b568ec2..8da0692 100644
--- a/src/network/kernel/qhostinfo_p.h
+++ b/src/network/kernel/qhostinfo_p.h
@@ -69,9 +69,19 @@
#include <QElapsedTimer>
#include <QCache>
+#include <QNetworkSession>
+#include <QSharedPointer>
+
+#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 +101,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
@@ -102,6 +118,10 @@ public:
lookupId(0)
{
}
+#ifndef QT_NO_BEARERMANAGEMENT
+ //not a public API yet
+ static QHostInfo fromName(const QString &hostName, QSharedPointer<QNetworkSession> networkSession);
+#endif
QHostInfo::HostInfoError err;
QString errorStr;
@@ -151,7 +171,25 @@ public:
QHostInfoResult resultEmitter;
};
-class QHostInfoLookupManager : public QObject
+
+class QAbstractHostInfoLookupManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ ~QAbstractHostInfoLookupManager() {}
+ virtual void clear() = 0;
+
+ QHostInfoCache cache;
+
+protected:
+ QAbstractHostInfoLookupManager() {}
+ static QAbstractHostInfoLookupManager* globalInstance();
+
+};
+
+#ifndef Q_OS_SYMBIAN
+class QHostInfoLookupManager : public QAbstractHostInfoLookupManager
{
Q_OBJECT
public:
@@ -169,8 +207,6 @@ public:
void lookupFinished(QHostInfoRunnable *r);
bool wasAborted(int id);
- QHostInfoCache cache;
-
friend class QHostInfoRunnable;
protected:
QList<QHostInfoRunnable*> currentLookups; // in progress
@@ -189,6 +225,95 @@ private slots:
void waitForThreadPoolDone() { threadPool.waitForDone(); }
};
+#else
+
+class QSymbianHostResolver : public CActive
+{
+public:
+ QSymbianHostResolver(const QString &hostName, int id, QSharedPointer<QNetworkSession> networkSession);
+ ~QSymbianHostResolver();
+
+ void requestHostLookup();
+ void abortHostLookup();
+ int id();
+
+ void returnResults();
+
+ QHostInfoResult resultEmitter;
+
+private:
+ void DoCancel();
+ void RunL();
+ void run();
+ TInt RunError(TInt aError);
+
+ void processNameResult();
+ void nextNameResult();
+ void processAddressResult();
+
+private:
+ int iId;
+
+ const QString iHostName;
+ QString iEncodedHostName;
+ TPtrC iHostNamePtr;
+
+ RSocketServ& iSocketServ;
+ RHostResolver iHostResolver;
+ QSharedPointer<QNetworkSession> iNetworkSession;
+
+ TNameEntry iNameResult;
+ TInetAddr IpAdd;
+
+ QHostAddress iAddress;
+
+ QHostInfo iResults;
+
+ QList<QHostAddress> iHostAddresses;
+
+ enum {
+ EIdle,
+ EGetByName,
+ EGetByAddress,
+ ECompleteFromCache,
+ EError
+ } iState;
+};
+
+class QSymbianHostInfoLookupManager : public QAbstractHostInfoLookupManager
+{
+ Q_OBJECT
+public:
+ QSymbianHostInfoLookupManager();
+ ~QSymbianHostInfoLookupManager();
+
+ static QSymbianHostInfoLookupManager* 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();
+
+ // this is true for single threaded use, with multiple threads the max is ((number of threads) + KMaxConcurrentLookups - 1)
+ static const int KMaxConcurrentLookups = 5;
+
+ QList<QSymbianHostResolver*> iCurrentLookups;
+ QList<QSymbianHostResolver*> iScheduledLookups;
+
+ 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
new file mode 100644
index 0000000..2a8de1d
--- /dev/null
+++ b/src/network/kernel/qhostinfo_symbian.cpp
@@ -0,0 +1,600 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QHOSTINFO_DEBUG
+
+// Qt Headers
+#include <QByteArray>
+#include <QUrl>
+#include <QList>
+
+#include "qplatformdefs.h"
+
+#include "qhostinfo_p.h"
+#include <private/qcore_symbian_p.h>
+#include <private/qsystemerror_p.h>
+#include <private/qnetworksession_p.h>
+
+// Header does not exist in the S60 5.0 SDK
+//#include <networking/dnd_err.h>
+const TInt KErrDndNameNotFound = -5120; // Returned when no data found for GetByName
+const TInt KErrDndAddrNotFound = -5121; // Returned when no data found for GetByAddr
+
+QT_BEGIN_NAMESPACE
+
+static void setError_helper(QHostInfo &info, TInt symbianError)
+{
+ switch (symbianError) {
+ case KErrDndNameNotFound:
+ case KErrDndAddrNotFound:
+ case KErrNotFound:
+ case KErrEof:
+ // various "no more results" error codes
+ info.setError(QHostInfo::HostNotFound);
+ info.setErrorString(QObject::tr("Host not found"));
+ break;
+ default:
+ // Unknown error
+ info.setError(QHostInfo::UnknownError);
+ info.setErrorString(QSystemError(symbianError, QSystemError::NativeError).toString());
+ break;
+ }
+}
+
+QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointer<QNetworkSession> networkSession)
+{
+ QHostInfo results;
+
+ // Connect to ESOCK
+ RSocketServ socketServ(qt_symbianGetSocketServer());
+ RHostResolver hostResolver;
+
+
+ int err;
+ if (networkSession)
+ err = QNetworkSessionPrivate::nativeOpenHostResolver(*networkSession, hostResolver, KAfInet, KProtocolInetUdp);
+ else
+ err = hostResolver.Open(socketServ, KAfInet, KProtocolInetUdp);
+ if (err) {
+ setError_helper(results, err);
+ return results;
+ }
+
+ TNameEntry nameResult;
+
+#if defined(QHOSTINFO_DEBUG)
+ qDebug("QHostInfoAgent::fromName(%s) looking up...",
+ hostName.toLatin1().constData());
+#endif
+
+ QHostAddress address;
+ if (address.setAddress(hostName)) {
+ // Reverse lookup
+#if defined(QHOSTINFO_DEBUG)
+ qDebug("(reverse lookup)");
+#endif
+ TInetAddr IpAdd;
+ IpAdd.Input(qt_QString2TPtrC(hostName));
+
+ // Synchronous request. nameResult returns Host Name.
+ err = hostResolver.GetByAddress(IpAdd, nameResult);
+ if (err) {
+ //for behavioural compatibility with Qt 4.7 and unix/windows
+ //backends: don't report error, return ip address as host name
+ results.setHostName(address.toString());
+ } else {
+ results.setHostName(qt_TDesC2QString(nameResult().iName));
+ }
+ results.setAddresses(QList<QHostAddress>() << address);
+ return results;
+ }
+
+ // IDN support
+ QByteArray aceHostname = QUrl::toAce(hostName);
+ results.setHostName(hostName);
+ if (aceHostname.isEmpty()) {
+ results.setError(QHostInfo::HostNotFound);
+ results.setErrorString(hostName.isEmpty() ?
+ QCoreApplication::translate("QHostInfoAgent", "No host name given") :
+ QCoreApplication::translate("QHostInfoAgent", "Invalid hostname"));
+ return results;
+ }
+
+
+ // Call RHostResolver::GetByAddress, and place all IPv4 addresses at the start and
+ // the IPv6 addresses at the end of the address list in results.
+
+ // Synchronous request.
+ err = hostResolver.GetByName(qt_QString2TPtrC(QString::fromLatin1(aceHostname)), nameResult);
+ if (err) {
+ setError_helper(results, err);
+ return results;
+ }
+
+ QList<QHostAddress> hostAddresses;
+
+ TInetAddr hostAdd = nameResult().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 (hostResolver.Next(nameResult) == KErrNone) {
+ hostAdd = nameResult().iAddr;
+ hostAdd.Output(ipAddr);
+
+ // Ensure that record is valid (not an alias and with length greater than 0)
+ if (!(nameResult().iFlags & TNameRecord::EAlias) && !(hostAdd.IsUnspecified())) {
+ hostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr)));
+ }
+ }
+
+ hostResolver.Close();
+
+ results.setAddresses(hostAddresses);
+ return results;
+}
+
+QHostInfo QHostInfoAgent::fromName(const QString &hostName)
+{
+ // null shared pointer
+ QSharedPointer<QNetworkSession> networkSession;
+ return fromName(hostName, networkSession);
+}
+
+QString QHostInfo::localHostName()
+{
+ // Connect to ESOCK
+ RSocketServ socketServ(qt_symbianGetSocketServer());
+ RHostResolver hostResolver;
+
+ // RConnection not required to get the host name
+ int err = hostResolver.Open(socketServ, KAfInet, KProtocolInetUdp);
+ if (err)
+ return QString();
+
+ THostName hostName;
+ err = hostResolver.GetHostName(hostName);
+ if (err)
+ return QString();
+
+ hostResolver.Close();
+
+ return qt_TDesC2QString(hostName);
+}
+
+QString QHostInfo::localDomainName()
+{
+ // This concept does not exist on Symbian OS because the device can be on
+ // multiple networks with multiple "local domain" names.
+ // For now, return a null string.
+ return QString();
+}
+
+
+QSymbianHostResolver::QSymbianHostResolver(const QString &hostName, int identifier, QSharedPointer<QNetworkSession> networkSession)
+ : CActive(CActive::EPriorityStandard), iHostName(hostName),
+ iSocketServ(qt_symbianGetSocketServer()), iNetworkSession(networkSession), iResults(identifier)
+{
+ CActiveScheduler::Add(this);
+}
+
+QSymbianHostResolver::~QSymbianHostResolver()
+{
+#if defined(QHOSTINFO_DEBUG)
+ qDebug() << "QSymbianHostInfoLookupManager::~QSymbianHostResolver" << id();
+#endif
+ Cancel();
+ iHostResolver.Close();
+}
+
+// Async equivalent to QHostInfoAgent::fromName()
+void QSymbianHostResolver::requestHostLookup()
+{
+
+#if defined(QHOSTINFO_DEBUG)
+ qDebug("QSymbianHostResolver::requestHostLookup(%s) looking up... (id = %d)",
+ iHostName.toLatin1().constData(), id());
+#endif
+
+ QSymbianHostInfoLookupManager *manager = QSymbianHostInfoLookupManager::globalInstance();
+ if (manager->cache.isEnabled()) {
+ //check if name has been put in the cache while this request was queued
+ bool valid;
+ QHostInfo cachedResult = manager->cache.get(iHostName, &valid);
+ if (valid) {
+#if defined(QHOSTINFO_DEBUG)
+ qDebug("...found in cache");
+#endif
+ iResults = cachedResult;
+ iState = ECompleteFromCache;
+ SetActive();
+ TRequestStatus* stat = &iStatus;
+ User::RequestComplete(stat, KErrNone);
+ return;
+ }
+ }
+
+ int err;
+ if (iNetworkSession) {
+ err = QNetworkSessionPrivate::nativeOpenHostResolver(*iNetworkSession, iHostResolver, KAfInet, KProtocolInetUdp);
+#if defined(QHOSTINFO_DEBUG)
+ qDebug("using resolver from session (err = %d)", err);
+#endif
+ } else {
+ err = iHostResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp);
+#if defined(QHOSTINFO_DEBUG)
+ qDebug("using default resolver (err = %d)", err);
+#endif
+ }
+ if (err) {
+ setError_helper(iResults, err);
+ } else {
+
+ if (iAddress.setAddress(iHostName)) {
+ // Reverse lookup
+ 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"));
+
+ err = KErrArgument;
+ } else {
+ iEncodedHostName = QString::fromLatin1(aceHostname);
+ iHostNamePtr.Set(qt_QString2TPtrC(iEncodedHostName));
+
+ // Asynchronous request.
+ iHostResolver.GetByName(iHostNamePtr, iNameResult, iStatus);
+ iState = EGetByName;
+ }
+ }
+ }
+ SetActive();
+ if (err) {
+ iHostResolver.Close();
+
+ //self complete so that RunL can inform manager without causing recursion
+ iState = EError;
+ TRequestStatus* stat = &iStatus;
+ User::RequestComplete(stat, err);
+ }
+}
+
+void QSymbianHostResolver::abortHostLookup()
+{
+ if (resultEmitter.thread() == QThread::currentThread()) {
+#ifdef QHOSTINFO_DEBUG
+ qDebug("QSymbianHostResolver::abortHostLookup - deleting %d", id());
+#endif
+ //normal case, abort from same thread it was started
+ delete this; //will cancel outstanding request
+ } else {
+#ifdef QHOSTINFO_DEBUG
+ qDebug("QSymbianHostResolver::abortHostLookup - detaching %d", id());
+#endif
+ //abort from different thread, carry on but don't report the results
+ resultEmitter.disconnect();
+ }
+}
+
+void QSymbianHostResolver::DoCancel()
+{
+#if defined(QHOSTINFO_DEBUG)
+ qDebug() << "QSymbianHostResolver::DoCancel" << QThread::currentThreadId() << id() << (int)iState << this;
+#endif
+ if (iState == EGetByAddress || iState == EGetByName) {
+ //these states have made an async request to host resolver
+ iHostResolver.Cancel();
+ } else {
+ //for the self completing states there is nothing to cancel
+ Q_ASSERT(iState == EError || iState == ECompleteFromCache);
+ }
+}
+
+void QSymbianHostResolver::RunL()
+{
+ QT_TRYCATCH_LEAVING(run());
+}
+
+void QSymbianHostResolver::run()
+{
+ switch (iState) {
+ case EGetByName:
+ processNameResult();
+ break;
+ case EGetByAddress:
+ processAddressResult();
+ break;
+ case ECompleteFromCache:
+ case EError:
+ returnResults();
+ break;
+ default:
+ qWarning("QSymbianHostResolver internal error, bad state in run()");
+ iResults.setError(QHostInfo::UnknownError);
+ iResults.setErrorString(QSystemError(KErrCorrupt,QSystemError::NativeError).toString());
+ returnResults();
+ }
+}
+
+void QSymbianHostResolver::returnResults()
+{
+#if defined(QHOSTINFO_DEBUG)
+ qDebug() << "QSymbianHostResolver::returnResults" << iResults.error() << iResults.errorString();
+ foreach (QHostAddress addr, iResults.addresses())
+ qDebug() << addr;
+#endif
+ iState = EIdle;
+
+ QSymbianHostInfoLookupManager *manager = QSymbianHostInfoLookupManager::globalInstance();
+ if (manager->cache.isEnabled()) {
+ manager->cache.put(iHostName, iResults);
+ }
+ manager->lookupFinished(this);
+
+ resultEmitter.emitResultsReady(iResults);
+
+ delete this;
+}
+
+TInt QSymbianHostResolver::RunError(TInt aError)
+{
+ QT_TRY {
+ iState = EIdle;
+
+ QSymbianHostInfoLookupManager *manager = QSymbianHostInfoLookupManager::globalInstance();
+ manager->lookupFinished(this);
+
+ setError_helper(iResults, aError);
+
+ resultEmitter.emitResultsReady(iResults);
+ }
+ QT_CATCH(...) {}
+
+ delete this;
+
+ return KErrNone;
+}
+
+void QSymbianHostResolver::processNameResult()
+{
+ if (iStatus.Int() == KErrNone) {
+ TInetAddr hostAdd = iNameResult().iAddr;
+ // 39 is the maximum length of an IPv6 address.
+ TBuf<39> ipAddr;
+
+ hostAdd.Output(ipAddr);
+
+ // Ensure that record is valid (not an alias and with length greater than 0)
+ if (!(iNameResult().iFlags & TNameRecord::EAlias) && !(hostAdd.IsUnspecified())) {
+ iHostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr)));
+ }
+
+ iState = EGetByName;
+ iHostResolver.Next(iNameResult, iStatus);
+ SetActive();
+ }
+ else {
+ // No more addresses, so return the results (or an error if there aren't any).
+#if defined(QHOSTINFO_DEBUG)
+ qDebug() << "QSymbianHostResolver::processNameResult with err=" << iStatus.Int() << "count=" << iHostAddresses.count();
+#endif
+ if (iHostAddresses.count() > 0) {
+ iResults.setAddresses(iHostAddresses);
+ } else {
+ iState = EError;
+ setError_helper(iResults, iStatus.Int());
+ }
+ returnResults();
+ }
+}
+
+void QSymbianHostResolver::processAddressResult()
+{
+ TInt err = iStatus.Int();
+
+ if (err < 0) {
+ //For behavioural compatibility with Qt 4.7, don't report errors on reverse lookup,
+ //return the address as a string (same as unix/windows backends)
+ iResults.setHostName(iAddress.toString());
+ } else {
+ iResults.setHostName(qt_TDesC2QString(iNameResult().iName));
+ }
+ iResults.setAddresses(QList<QHostAddress>() << iAddress);
+ returnResults();
+}
+
+
+int QSymbianHostResolver::id()
+{
+ return iResults.lookupId();
+}
+
+QSymbianHostInfoLookupManager::QSymbianHostInfoLookupManager()
+{
+}
+
+QSymbianHostInfoLookupManager::~QSymbianHostInfoLookupManager()
+{
+}
+
+void QSymbianHostInfoLookupManager::clear()
+{
+ QMutexLocker locker(&mutex);
+#if defined(QHOSTINFO_DEBUG)
+ qDebug() << "QSymbianHostInfoLookupManager::clear" << QThread::currentThreadId();
+#endif
+ foreach (QSymbianHostResolver *hr, iCurrentLookups)
+ hr->abortHostLookup();
+ iCurrentLookups.clear();
+ qDeleteAll(iScheduledLookups);
+ cache.clear();
+}
+
+void QSymbianHostInfoLookupManager::lookupFinished(QSymbianHostResolver *r)
+{
+ QMutexLocker locker(&mutex);
+
+#if defined(QHOSTINFO_DEBUG)
+ qDebug() << "QSymbianHostInfoLookupManager::lookupFinished" << QThread::currentThreadId() << r->id() << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count();
+#endif
+ // 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.removeAt(i);
+ break;
+ }
+ }
+
+ runNextLookup();
+}
+
+void QSymbianHostInfoLookupManager::runNextLookup()
+{
+#if defined(QHOSTINFO_DEBUG)
+ qDebug() << "QSymbianHostInfoLookupManager::runNextLookup" << QThread::currentThreadId() << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count();
+#endif
+ // check to see if there are any scheduled lookups
+ for (int i=0; i<iScheduledLookups.count(); i++) {
+ QSymbianHostResolver* hostResolver = iScheduledLookups.at(i);
+ if (hostResolver->resultEmitter.thread() == QThread::currentThread()) {
+ // if so, move one to the current lookups and run it
+ iCurrentLookups.append(hostResolver);
+ iScheduledLookups.removeAt(i);
+ hostResolver->requestHostLookup();
+ // if spare capacity, try to start another one
+ if (iCurrentLookups.count() >= KMaxConcurrentLookups)
+ break;
+ i--; //compensate for removeAt
+ }
+ }
+}
+
+// called from QHostInfo
+void QSymbianHostInfoLookupManager::scheduleLookup(QSymbianHostResolver* r)
+{
+ QMutexLocker locker(&mutex);
+
+#if defined(QHOSTINFO_DEBUG)
+ qDebug() << "QSymbianHostInfoLookupManager::scheduleLookup" << QThread::currentThreadId() << r->id() << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count();
+#endif
+ // Check to see if we have space on the current lookups pool.
+ bool defer = false;
+ if (iCurrentLookups.count() >= KMaxConcurrentLookups) {
+ // busy, defer unless there are no request in this thread
+ // at least one active request per thread with queued requests is needed
+ for (int i=0; i < iCurrentLookups.count();i++) {
+ if (iCurrentLookups.at(i)->resultEmitter.thread() == QThread::currentThread()) {
+ defer = true;
+ break;
+ }
+ }
+ }
+ if (defer) {
+ // If no, schedule for later.
+ iScheduledLookups.append(r);
+#if defined(QHOSTINFO_DEBUG)
+ qDebug(" - scheduled");
+#endif
+ return;
+ } else {
+ // If yes, add it to the current lookups.
+ iCurrentLookups.append(r);
+
+ // ... and trigger the async call.
+ r->requestHostLookup();
+ }
+}
+
+void QSymbianHostInfoLookupManager::abortLookup(int id)
+{
+ QMutexLocker locker(&mutex);
+
+#if defined(QHOSTINFO_DEBUG)
+ qDebug() << "QSymbianHostInfoLookupManager::abortLookup" << QThread::currentThreadId() << id << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count();
+#endif
+ 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.at(i);
+ iCurrentLookups.removeAt(i);
+ r->abortHostLookup();
+ runNextLookup();
+ return;
+ }
+ }
+ // Then in the scheduled lookups.
+ for (i = 0; i < iScheduledLookups.count(); i++) {
+ if (id == iScheduledLookups[i]->id()) {
+ QSymbianHostResolver* r = iScheduledLookups.at(i);
+ iScheduledLookups.removeAt(i);
+ delete r;
+ return;
+ }
+ }
+}
+
+QSymbianHostInfoLookupManager* QSymbianHostInfoLookupManager::globalInstance()
+{
+ return static_cast<QSymbianHostInfoLookupManager*>
+ (QAbstractHostInfoLookupManager::globalInstance());
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp
index 22f6e0d..8fc6bf6 100644
--- a/src/network/kernel/qhostinfo_unix.cpp
+++ b/src/network/kernel/qhostinfo_unix.cpp
@@ -147,7 +147,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
if (address.setAddress(hostName)) {
// Reverse lookup
// Reverse lookups using getnameinfo are broken on darwin, use gethostbyaddr instead.
-#if !defined (QT_NO_GETADDRINFO) && !defined (Q_OS_DARWIN) && !defined (Q_OS_SYMBIAN)
+#if !defined (QT_NO_GETADDRINFO) && !defined (Q_OS_DARWIN)
sockaddr_in sa4;
#ifndef QT_NO_IPV6
sockaddr_in6 sa6;
@@ -208,23 +208,12 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
#ifdef Q_ADDRCONFIG
hints.ai_flags = Q_ADDRCONFIG;
#endif
-#ifdef Q_OS_SYMBIAN
-# ifdef QHOSTINFO_DEBUG
- qDebug() << "Setting flags: 'hints.ai_flags &= AI_V4MAPPED | AI_ALL'";
-# endif
-#endif
int result = getaddrinfo(aceHostname.constData(), 0, &hints, &res);
# ifdef Q_ADDRCONFIG
if (result == EAI_BADFLAGS) {
// if the lookup failed with AI_ADDRCONFIG set, try again without it
hints.ai_flags = 0;
-#ifdef Q_OS_SYMBIAN
-# ifdef QHOSTINFO_DEBUG
- qDebug() << "Setting flags: 'hints.ai_flags &= AI_V4MAPPED | AI_ALL'";
-# endif
- hints.ai_flags &= AI_V4MAPPED | AI_ALL;
-#endif
result = getaddrinfo(aceHostname.constData(), 0, &hints, &res);
}
# endif
diff --git a/src/network/kernel/qnetworkinterface_symbian.cpp b/src/network/kernel/qnetworkinterface_symbian.cpp
index 8e5db3c..7767f54 100644
--- a/src/network/kernel/qnetworkinterface_symbian.cpp
+++ b/src/network/kernel/qnetworkinterface_symbian.cpp
@@ -67,22 +67,29 @@ static QNetworkInterface::InterfaceFlags convertFlags(const TSoInetInterfaceInfo
return flags;
}
+//TODO: share this, at least QHostInfo needs to do the same thing
+static QHostAddress qt_QHostAddressFromTInetAddr(const TInetAddr& addr)
+{
+ //TODO: do we want to call v4 mapped addresses v4 or v6 outside of this file?
+ if (addr.IsV4Mapped() || addr.Family() == KAfInet) {
+ //convert v4 host address
+ return QHostAddress(addr.Address());
+ } else {
+ //convert v6 host address
+ return QHostAddress((quint8 *)(addr.Ip6Address().u.iAddr8));
+ }
+}
+
static QList<QNetworkInterfacePrivate *> interfaceListing()
{
TInt err(KErrNone);
QList<QNetworkInterfacePrivate *> interfaces;
-
- // Connect to Native socket server
- RSocketServ socketServ;
- err = socketServ.Connect();
- if (err)
- return interfaces;
+ QList<QHostAddress> addressesWithEstimatedNetmasks;
// Open dummy socket for interface queries
RSocket socket;
- err = socket.Open(socketServ, _L("udp"));
+ err = socket.Open(qt_symbianGetSocketServer(), _L("udp"));
if (err) {
- socketServ.Close();
return interfaces;
}
@@ -90,7 +97,6 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
err = socket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl);
if (err) {
socket.Close();
- socketServ.Close();
return interfaces;
}
@@ -98,8 +104,7 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
TPckgBuf<TSoInetInterfaceInfo> infoPckg;
TSoInetInterfaceInfo &info = infoPckg();
while (socket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, infoPckg) == KErrNone) {
- // Do not include IPv6 addresses because netmask and broadcast address cannot be determined correctly
- if (info.iName != KNullDesC && info.iAddress.IsV4Mapped()) {
+ if (info.iName != KNullDesC) {
TName address;
QNetworkAddressEntry entry;
QNetworkInterfacePrivate *iface = 0;
@@ -121,40 +126,58 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
}
// Get the address of the interface
- info.iAddress.Output(address);
- entry.setIp(QHostAddress(qt_TDesC2QString(address)));
+ entry.setIp(qt_QHostAddressFromTInetAddr(info.iAddress));
+
+#if defined(QNETWORKINTERFACE_DEBUG)
+ qDebug() << "address is" << info.iAddress.Family() << entry.ip();
+ qDebug() << "netmask is" << info.iNetMask.Family() << qt_QHostAddressFromTInetAddr( info.iNetMask );
+#endif
// Get the interface netmask
- // For some reason netmask is always 0.0.0.0
- // info.iNetMask.Output(address);
- // entry.setNetmask( QHostAddress( qt_TDesC2QString( address ) ) );
-
- // Workaround: Let Symbian determine netmask based on IP address class
- // TODO: Works only for IPv4 - Task: 259128 Implement IPv6 support
- TInetAddr netmask;
- netmask.NetMask(info.iAddress);
- netmask.Output(address);
- entry.setNetmask(QHostAddress(qt_TDesC2QString(address)));
-
- // Get the interface broadcast address
- if (iface->flags & QNetworkInterface::CanBroadcast) {
- // For some reason broadcast address is always 0.0.0.0
- // info.iBrdAddr.Output(address);
- // entry.setBroadcast( QHostAddress( qt_TDesC2QString( address ) ) );
-
- // Workaround: Let Symbian determine broadcast address based on IP address
- // TODO: Works only for IPv4 - Task: 259128 Implement IPv6 support
- TInetAddr broadcast;
- broadcast.NetBroadcast(info.iAddress);
- broadcast.Output(address);
- entry.setBroadcast(QHostAddress(qt_TDesC2QString(address)));
+ if (info.iNetMask.IsUnspecified()) {
+ // For some reason netmask is always 0.0.0.0 for IPv4 interfaces
+ // and loopback interfaces (which we statically know)
+ if (info.iAddress.IsV4Mapped()) {
+ if (info.iFeatures & KIfIsLoopback) {
+ entry.setPrefixLength(32);
+ } else {
+ // Workaround: Let Symbian determine netmask based on IP address class (IPv4 only API)
+ TInetAddr netmask;
+ netmask.NetMask(info.iAddress);
+ entry.setNetmask(QHostAddress(netmask.Address())); //binary convert v4 address
+ addressesWithEstimatedNetmasks << entry.ip();
+#if defined(QNETWORKINTERFACE_DEBUG)
+ qDebug() << "address class determined netmask" << entry.netmask();
+#endif
+ }
+ } else {
+ // For IPv6 interfaces
+ if (info.iFeatures & KIfIsLoopback) {
+ entry.setPrefixLength(128);
+ } else if (info.iNetMask.IsUnspecified()) {
+ //Don't see this error for IPv6, but try to handle it if it happens
+ entry.setPrefixLength(64); //most common
+#if defined(QNETWORKINTERFACE_DEBUG)
+ qDebug() << "total guess netmask" << entry.netmask();
+#endif
+ addressesWithEstimatedNetmasks << entry.ip();
+ }
+ }
+ } else {
+ //Expected code path for IPv6 non loopback interfaces (IPv4 could come here if symbian is fixed)
+ entry.setNetmask(qt_QHostAddressFromTInetAddr(info.iNetMask));
+#if defined(QNETWORKINTERFACE_DEBUG)
+ qDebug() << "reported netmask" << entry.netmask();
+#endif
}
+ // broadcast address is determined from the netmask in postProcess()
+
// Add new entry to interface address entries
iface->addressEntries << entry;
#if defined(QNETWORKINTERFACE_DEBUG)
- printf("\n Found network interface %s, interface flags:\n\
+ qDebug("\n Found network interface %s, interface flags:\n\
IsUp = %d, IsRunning = %d, CanBroadcast = %d,\n\
IsLoopBack = %d, IsPointToPoint = %d, CanMulticast = %d, \n\
ip = %s, netmask = %s, broadcast = %s,\n\
@@ -168,15 +191,20 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
}
}
+ // if we didn't have to guess any netmasks, then we're done.
+ if (addressesWithEstimatedNetmasks.isEmpty()) {
+ socket.Close();
+ return interfaces;
+ }
+
// we will try to use routing info to detect more precisely
- // netmask and then ::postProcess() should calculate
+ // estimated netmasks and then ::postProcess() should calculate
// broadcast addresses
// use dummy socket to start enumerating routes
err = socket.SetOpt(KSoInetEnumRoutes, KSolInetRtCtrl);
if (err) {
socket.Close();
- socketServ.Close();
// return what we have
// up to this moment
return interfaces;
@@ -185,16 +213,21 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
TSoInetRouteInfo routeInfo;
TPckg<TSoInetRouteInfo> routeInfoPkg(routeInfo);
while (socket.GetOpt(KSoInetNextRoute, KSolInetRtCtrl, routeInfoPkg) == KErrNone) {
- TName address;
-
// get interface address
- routeInfo.iIfAddr.Output(address);
- QHostAddress ifAddr(qt_TDesC2QString(address));
+ QHostAddress ifAddr(qt_QHostAddressFromTInetAddr(routeInfo.iIfAddr));
if (ifAddr.isNull())
continue;
+ if (!addressesWithEstimatedNetmasks.contains(ifAddr)) {
+#if defined(QNETWORKINTERFACE_DEBUG)
+ qDebug() << "skipping route from" << ifAddr << "because it wasn't an estimated netmask";
+#endif
+ continue;
+ }
- routeInfo.iDstAddr.Output(address);
- QHostAddress destination(qt_TDesC2QString(address));
+ QHostAddress destination(qt_QHostAddressFromTInetAddr(routeInfo.iDstAddr));
+#if defined(QNETWORKINTERFACE_DEBUG)
+ qDebug() << "route from" << ifAddr << "to" << destination;
+#endif
if (destination.isNull() || destination != ifAddr)
continue;
@@ -205,17 +238,13 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
QNetworkAddressEntry entry = iface->addressEntries.at(eindex);
if (entry.ip() != ifAddr) {
continue;
- } else if (entry.ip().protocol() != QAbstractSocket::IPv4Protocol) {
- // skip if not IPv4 address (e.g. IPv6)
- // as results not reliable on Symbian
- continue;
- } else {
- routeInfo.iNetMask.Output(address);
- QHostAddress netmask(qt_TDesC2QString(address));
+ } else if (!routeInfo.iNetMask.IsUnspecified()) {
+ //the route may also return 0.0.0.0 netmask, in which case don't use it.
+ QHostAddress netmask(qt_QHostAddressFromTInetAddr(routeInfo.iNetMask));
entry.setNetmask(netmask);
- // NULL boradcast address for
- // ::postProcess to have effect
- entry.setBroadcast(QHostAddress());
+#if defined(QNETWORKINTERFACE_DEBUG)
+ qDebug() << " - route netmask" << routeInfo.iNetMask.Family() << netmask << " (using route determined netmask)";
+#endif
iface->addressEntries.replace(eindex, entry);
}
}
@@ -223,7 +252,6 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
}
socket.Close();
- socketServ.Close();
return interfaces;
}