summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
authorDavid Boddie <dboddie@trolltech.com>2010-03-30 14:56:41 (GMT)
committerDavid Boddie <dboddie@trolltech.com>2010-03-30 14:56:41 (GMT)
commit87f66d52e362de003a9f2cdaafbfbe3ba4e5fbc3 (patch)
treef8b8c24056d54e19937dea1b0301af558597726a /src/network
parent09ce407aaa4a00013a606bf0011faf6cbc654c72 (diff)
parent00f7426f3906361fb5addb36e428648eee5e2983 (diff)
downloadQt-87f66d52e362de003a9f2cdaafbfbe3ba4e5fbc3.zip
Qt-87f66d52e362de003a9f2cdaafbfbe3ba4e5fbc3.tar.gz
Qt-87f66d52e362de003a9f2cdaafbfbe3ba4e5fbc3.tar.bz2
Merge branch '4.7' of git@scm.dev.nokia.troll.no:qt/oslo-staging-2 into 4.7
Conflicts: doc/src/modules.qdoc mkspecs/common/symbian/symbian.conf src/gui/graphicsview/qgraphicswidget.h src/s60installs/bwins/QtGuiu.def src/s60installs/eabi/QtGuiu.def
Diffstat (limited to 'src/network')
-rw-r--r--src/network/access/qhttpnetworkrequest.cpp70
-rw-r--r--src/network/access/qhttpnetworkrequest_p.h7
-rw-r--r--src/network/access/qnetworkaccessbackend.cpp38
-rw-r--r--src/network/access/qnetworkaccessbackend_p.h6
-rw-r--r--src/network/access/qnetworkaccessdatabackend.cpp69
-rw-r--r--src/network/access/qnetworkaccessdebugpipebackend.cpp4
-rw-r--r--src/network/access/qnetworkaccesshttpbackend.cpp71
-rw-r--r--src/network/access/qnetworkaccesshttpbackend_p.h5
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp322
-rw-r--r--src/network/access/qnetworkaccessmanager.h27
-rw-r--r--src/network/access/qnetworkaccessmanager_p.h20
-rw-r--r--src/network/access/qnetworkreply.cpp20
-rw-r--r--src/network/access/qnetworkreply.h4
-rw-r--r--src/network/access/qnetworkreplyimpl.cpp201
-rw-r--r--src/network/access/qnetworkreplyimpl_p.h36
-rw-r--r--src/network/access/qnetworkrequest.cpp51
-rw-r--r--src/network/access/qnetworkrequest.h10
-rw-r--r--src/network/bearer/bearer.pri18
-rw-r--r--src/network/bearer/qbearerengine.cpp113
-rw-r--r--src/network/bearer/qbearerengine_p.h113
-rw-r--r--src/network/bearer/qbearerplugin.cpp57
-rw-r--r--src/network/bearer/qbearerplugin_p.h93
-rw-r--r--src/network/bearer/qnetworkconfigmanager.cpp306
-rw-r--r--src/network/bearer/qnetworkconfigmanager.h102
-rw-r--r--src/network/bearer/qnetworkconfigmanager_p.cpp495
-rw-r--r--src/network/bearer/qnetworkconfigmanager_p.h133
-rw-r--r--src/network/bearer/qnetworkconfiguration.cpp433
-rw-r--r--src/network/bearer/qnetworkconfiguration.h115
-rw-r--r--src/network/bearer/qnetworkconfiguration_p.h110
-rw-r--r--src/network/bearer/qnetworksession.cpp704
-rw-r--r--src/network/bearer/qnetworksession.h138
-rw-r--r--src/network/bearer/qnetworksession_p.h150
-rw-r--r--src/network/kernel/qhostinfo.cpp2
-rw-r--r--src/network/kernel/qhostinfo_unix.cpp4
-rw-r--r--src/network/network.pro1
-rw-r--r--src/network/socket/qabstractsocket.cpp10
-rw-r--r--src/network/socket/qhttpsocketengine.cpp6
-rw-r--r--src/network/socket/qlocalsocket_unix.cpp4
-rw-r--r--src/network/socket/qnativesocketengine.cpp6
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp4
-rw-r--r--src/network/socket/qsocks5socketengine.cpp18
-rw-r--r--src/network/ssl/qsslsocket.cpp10
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp17
-rw-r--r--src/network/ssl/qsslsocket_openssl_p.h1
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp6
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h2
46 files changed, 4007 insertions, 125 deletions
diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp
index 8cdfe6a..9eb2399 100644
--- a/src/network/access/qhttpnetworkrequest.cpp
+++ b/src/network/access/qhttpnetworkrequest.cpp
@@ -61,6 +61,7 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequest
uploadByteDevice = other.uploadByteDevice;
autoDecompress = other.autoDecompress;
pipeliningAllowed = other.pipeliningAllowed;
+ customVerb = other.customVerb;
}
QHttpNetworkRequestPrivate::~QHttpNetworkRequestPrivate()
@@ -76,36 +77,38 @@ bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &ot
QByteArray QHttpNetworkRequestPrivate::methodName() const
{
- QByteArray ba;
switch (operation) {
- case QHttpNetworkRequest::Options:
- ba += "OPTIONS";
- break;
case QHttpNetworkRequest::Get:
- ba += "GET";
+ return "GET";
break;
case QHttpNetworkRequest::Head:
- ba += "HEAD";
+ return "HEAD";
break;
case QHttpNetworkRequest::Post:
- ba += "POST";
+ return "POST";
+ break;
+ case QHttpNetworkRequest::Options:
+ return "OPTIONS";
break;
case QHttpNetworkRequest::Put:
- ba += "PUT";
+ return "PUT";
break;
case QHttpNetworkRequest::Delete:
- ba += "DELETE";
+ return "DELETE";
break;
case QHttpNetworkRequest::Trace:
- ba += "TRACE";
+ return "TRACE";
break;
case QHttpNetworkRequest::Connect:
- ba += "CONNECT";
+ return "CONNECT";
+ break;
+ case QHttpNetworkRequest::Custom:
+ return customVerb;
break;
default:
break;
}
- return ba;
+ return QByteArray();
}
QByteArray QHttpNetworkRequestPrivate::uri(bool throughProxy) const
@@ -128,26 +131,37 @@ QByteArray QHttpNetworkRequestPrivate::uri(bool throughProxy) const
QByteArray QHttpNetworkRequestPrivate::header(const QHttpNetworkRequest &request, bool throughProxy)
{
- QByteArray ba = request.d->methodName();
- QByteArray uri = request.d->uri(throughProxy);
- ba += ' ' + uri;
+ QList<QPair<QByteArray, QByteArray> > fields = request.header();
+ QByteArray ba;
+ ba.reserve(40 + fields.length()*25); // very rough lower bound estimation
- QString majorVersion = QString::number(request.majorVersion());
- QString minorVersion = QString::number(request.minorVersion());
- ba += " HTTP/" + majorVersion.toLatin1() + '.' + minorVersion.toLatin1() + "\r\n";
+ ba += request.d->methodName();
+ ba += ' ';
+ ba += request.d->uri(throughProxy);
+
+ ba += " HTTP/";
+ ba += QByteArray::number(request.majorVersion());
+ ba += '.';
+ ba += QByteArray::number(request.minorVersion());
+ ba += "\r\n";
- QList<QPair<QByteArray, QByteArray> > fields = request.header();
QList<QPair<QByteArray, QByteArray> >::const_iterator it = fields.constBegin();
- for (; it != fields.constEnd(); ++it)
- ba += it->first + ": " + it->second + "\r\n";
+ QList<QPair<QByteArray, QByteArray> >::const_iterator endIt = fields.constEnd();
+ for (; it != endIt; ++it) {
+ ba += it->first;
+ ba += ": ";
+ ba += it->second;
+ ba += "\r\n";
+ }
if (request.d->operation == QHttpNetworkRequest::Post) {
// add content type, if not set in the request
if (request.headerField("content-type").isEmpty())
ba += "Content-Type: application/x-www-form-urlencoded\r\n";
if (!request.d->uploadByteDevice && request.d->url.hasQuery()) {
QByteArray query = request.d->url.encodedQuery();
- ba += "Content-Length: "+ QByteArray::number(query.size()) + "\r\n";
- ba += "\r\n";
+ ba += "Content-Length: ";
+ ba += QByteArray::number(query.size());
+ ba += "\r\n\r\n";
ba += query;
} else {
ba += "\r\n";
@@ -230,6 +244,16 @@ void QHttpNetworkRequest::setOperation(Operation operation)
d->operation = operation;
}
+QByteArray QHttpNetworkRequest::customVerb() const
+{
+ return d->customVerb;
+}
+
+void QHttpNetworkRequest::setCustomVerb(const QByteArray &customVerb)
+{
+ d->customVerb = customVerb;
+}
+
QHttpNetworkRequest::Priority QHttpNetworkRequest::priority() const
{
return d->priority;
diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h
index dad118e..1b35a84 100644
--- a/src/network/access/qhttpnetworkrequest_p.h
+++ b/src/network/access/qhttpnetworkrequest_p.h
@@ -72,7 +72,8 @@ public:
Put,
Delete,
Trace,
- Connect
+ Connect,
+ Custom
};
enum Priority {
@@ -103,6 +104,9 @@ public:
Operation operation() const;
void setOperation(Operation operation);
+ QByteArray customVerb() const;
+ void setCustomVerb(const QByteArray &customOperation);
+
Priority priority() const;
void setPriority(Priority priority);
@@ -133,6 +137,7 @@ public:
static QByteArray header(const QHttpNetworkRequest &request, bool throughProxy);
QHttpNetworkRequest::Operation operation;
+ QByteArray customVerb;
QHttpNetworkRequest::Priority priority;
mutable QNonContiguousByteDevice* uploadByteDevice;
bool autoDecompress;
diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp
index 8ac64d2..1fcfebb 100644
--- a/src/network/access/qnetworkaccessbackend.cpp
+++ b/src/network/access/qnetworkaccessbackend.cpp
@@ -46,9 +46,11 @@
#include "qnetworkreply_p.h"
#include "QtCore/qhash.h"
#include "QtCore/qmutex.h"
+#include "QtNetwork/qnetworksession.h"
#include "qnetworkaccesscachebackend_p.h"
#include "qabstractnetworkcache.h"
+#include "qhostinfo.h"
#include "private/qnoncontiguousbytedevice_p.h"
@@ -120,8 +122,11 @@ QNonContiguousByteDevice* QNetworkAccessBackend::createUploadByteDevice()
if (reply->outgoingDataBuffer)
device = QNonContiguousByteDeviceFactory::create(reply->outgoingDataBuffer);
- else
+ else if (reply->outgoingData) {
device = QNonContiguousByteDeviceFactory::create(reply->outgoingData);
+ } else {
+ return 0;
+ }
bool bufferDisallowed =
reply->request.attribute(QNetworkRequest::DoNotBufferUploadDataAttribute,
@@ -341,4 +346,35 @@ void QNetworkAccessBackend::sslErrors(const QList<QSslError> &errors)
#endif
}
+/*!
+ Starts the backend. Returns true if the backend is started. Returns false if the backend
+ could not be started due to an unopened or roaming session. The caller should recall this
+ function once the session has been opened or the roaming process has finished.
+*/
+bool QNetworkAccessBackend::start()
+{
+ if (!manager->networkSession) {
+ open();
+ return true;
+ }
+
+ // This is not ideal.
+ const QString host = reply->url.host();
+ if (host == QLatin1String("localhost") ||
+ QHostAddress(host) == QHostAddress::LocalHost ||
+ QHostAddress(host) == QHostAddress::LocalHostIPv6) {
+ // Don't need an open session for localhost access.
+ open();
+ return true;
+ }
+
+ if (manager->networkSession->isOpen() &&
+ manager->networkSession->state() == QNetworkSession::Connected) {
+ open();
+ return true;
+ }
+
+ return false;
+}
+
QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h
index 43d993c..9bc15e5 100644
--- a/src/network/access/qnetworkaccessbackend_p.h
+++ b/src/network/access/qnetworkaccessbackend_p.h
@@ -111,6 +111,7 @@ public:
// socket).
virtual void open() = 0;
+ virtual bool start();
virtual void closeDownstreamChannel() = 0;
virtual bool waitForDownstreamReadyRead(int msecs) = 0;
@@ -160,6 +161,10 @@ public:
// This will possibly enable buffering of the upload data.
virtual bool needsResetableUploadData() { return false; }
+ // Returns true if backend is able to resume downloads.
+ virtual bool canResume() const { return false; }
+ virtual void setResumeOffset(quint64 offset) { Q_UNUSED(offset); }
+
protected:
// Create the device used for reading the upload data
QNonContiguousByteDevice* createUploadByteDevice();
@@ -190,6 +195,7 @@ private:
friend class QNetworkAccessManager;
friend class QNetworkAccessManagerPrivate;
friend class QNetworkAccessBackendUploadIODevice;
+ friend class QNetworkReplyImplPrivate;
QNetworkAccessManagerPrivate *manager;
QNetworkReplyImplPrivate *reply;
};
diff --git a/src/network/access/qnetworkaccessdatabackend.cpp b/src/network/access/qnetworkaccessdatabackend.cpp
index 52c554f..efb6e3e 100644
--- a/src/network/access/qnetworkaccessdatabackend.cpp
+++ b/src/network/access/qnetworkaccessdatabackend.cpp
@@ -43,6 +43,8 @@
#include "qnetworkrequest.h"
#include "qnetworkreply.h"
#include "qurlinfo.h"
+#include "private/qdataurl_p.h"
+#include <qcoreapplication.h>
QT_BEGIN_NAMESPACE
@@ -71,64 +73,33 @@ void QNetworkAccessDataBackend::open()
if (operation() != QNetworkAccessManager::GetOperation &&
operation() != QNetworkAccessManager::HeadOperation) {
// data: doesn't support anything but GET
- QString msg = QObject::tr("Operation not supported on %1")
+ const QString msg = QCoreApplication::translate("QNetworkAccessDataBackend",
+ "Operation not supported on %1")
.arg(uri.toString());
error(QNetworkReply::ContentOperationNotPermittedError, msg);
finished();
return;
}
- if (uri.host().isEmpty()) {
- setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("text/plain;charset=US-ASCII"));
-
- // the following would have been the correct thing, but
- // reality often differs from the specification. People have
- // data: URIs with ? and #
- //QByteArray data = QByteArray::fromPercentEncoding(uri.encodedPath());
- QByteArray data = QByteArray::fromPercentEncoding(uri.toEncoded());
-
- // remove the data: scheme
- data.remove(0, 5);
-
- // parse it:
- int pos = data.indexOf(',');
- if (pos != -1) {
- QByteArray payload = data.mid(pos + 1);
- data.truncate(pos);
- data = data.trimmed();
-
- // find out if the payload is encoded in Base64
- if (data.endsWith(";base64")) {
- payload = QByteArray::fromBase64(payload);
- data.chop(7);
- }
-
- if (data.toLower().startsWith("charset")) {
- int i = 7; // strlen("charset")
- while (data.at(i) == ' ')
- ++i;
- if (data.at(i) == '=')
- data.prepend("text/plain;");
- }
-
- if (!data.isEmpty())
- setHeader(QNetworkRequest::ContentTypeHeader, data.trimmed());
-
- setHeader(QNetworkRequest::ContentLengthHeader, payload.size());
- emit metaDataChanged();
-
- QByteDataBuffer list;
- list.append(payload);
- payload.clear(); // important because of implicit sharing!
- writeDownstreamData(list);
-
- finished();
- return;
- }
+ QPair<QString, QByteArray> decoded = qDecodeDataUrl(uri);
+
+ if (! decoded.first.isNull()) {
+ setHeader(QNetworkRequest::ContentTypeHeader, decoded.first);
+ setHeader(QNetworkRequest::ContentLengthHeader, decoded.second.size());
+ emit metaDataChanged();
+
+ QByteDataBuffer list;
+ list.append(decoded.second);
+ decoded.second.clear(); // important because of implicit sharing!
+ writeDownstreamData(list);
+
+ finished();
+ return;
}
// something wrong with this URI
- QString msg = QObject::tr("Invalid URI: %1").arg(uri.toString());
+ const QString msg = QCoreApplication::translate("QNetworkAccessDataBackend",
+ "Invalid URI: %1").arg(uri.toString());
error(QNetworkReply::ProtocolFailure, msg);
finished();
}
diff --git a/src/network/access/qnetworkaccessdebugpipebackend.cpp b/src/network/access/qnetworkaccessdebugpipebackend.cpp
index 5926d0b..cd077e7 100644
--- a/src/network/access/qnetworkaccessdebugpipebackend.cpp
+++ b/src/network/access/qnetworkaccessdebugpipebackend.cpp
@@ -252,7 +252,7 @@ void QNetworkAccessDebugPipeBackend::socketError()
break;
}
- error(code, QObject::tr("Socket error on %1: %2")
+ error(code, QNetworkAccessDebugPipeBackend::tr("Socket error on %1: %2")
.arg(url().toString(), socket.errorString()));
finished();
disconnect(&socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
@@ -267,7 +267,7 @@ void QNetworkAccessDebugPipeBackend::socketDisconnected()
// normal close
} else {
// abnormal close
- QString msg = QObject::tr("Remote host closed the connection prematurely on %1")
+ QString msg = QNetworkAccessDebugPipeBackend::tr("Remote host closed the connection prematurely on %1")
.arg(url().toString());
error(QNetworkReply::RemoteHostClosedError, msg);
finished();
diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp
index af971a7..7a48c2b 100644
--- a/src/network/access/qnetworkaccesshttpbackend.cpp
+++ b/src/network/access/qnetworkaccesshttpbackend.cpp
@@ -213,6 +213,7 @@ QNetworkAccessHttpBackendFactory::create(QNetworkAccessManager::Operation op,
case QNetworkAccessManager::HeadOperation:
case QNetworkAccessManager::PutOperation:
case QNetworkAccessManager::DeleteOperation:
+ case QNetworkAccessManager::CustomOperation:
break;
default:
@@ -296,6 +297,7 @@ QNetworkAccessHttpBackend::QNetworkAccessHttpBackend()
#ifndef QT_NO_OPENSSL
, pendingSslConfiguration(0), pendingIgnoreAllSslErrors(false)
#endif
+ , resumeOffset(0)
{
}
@@ -480,10 +482,24 @@ void QNetworkAccessHttpBackend::validateCache(QHttpNetworkRequest &httpRequest,
loadedFromCache = false;
}
+static QHttpNetworkRequest::Priority convert(const QNetworkRequest::Priority& prio)
+{
+ switch (prio) {
+ case QNetworkRequest::LowPriority:
+ return QHttpNetworkRequest::LowPriority;
+ case QNetworkRequest::HighPriority:
+ return QHttpNetworkRequest::HighPriority;
+ case QNetworkRequest::NormalPriority:
+ default:
+ return QHttpNetworkRequest::NormalPriority;
+ }
+}
+
void QNetworkAccessHttpBackend::postRequest()
{
bool loadedFromCache = false;
QHttpNetworkRequest httpRequest;
+ httpRequest.setPriority(convert(request().priority()));
switch (operation()) {
case QNetworkAccessManager::GetOperation:
httpRequest.setOperation(QHttpNetworkRequest::Get);
@@ -512,6 +528,14 @@ void QNetworkAccessHttpBackend::postRequest()
httpRequest.setOperation(QHttpNetworkRequest::Delete);
break;
+ case QNetworkAccessManager::CustomOperation:
+ invalidateCache(); // for safety reasons, we don't know what the operation does
+ httpRequest.setOperation(QHttpNetworkRequest::Custom);
+ httpRequest.setUploadByteDevice(createUploadByteDevice());
+ httpRequest.setCustomVerb(request().attribute(
+ QNetworkRequest::CustomVerbAttribute).toByteArray());
+ break;
+
default:
break; // can't happen
}
@@ -519,6 +543,28 @@ void QNetworkAccessHttpBackend::postRequest()
httpRequest.setUrl(url());
QList<QByteArray> headers = request().rawHeaderList();
+ if (resumeOffset != 0) {
+ if (headers.contains("Range")) {
+ // Need to adjust resume offset for user specified range
+
+ headers.removeOne("Range");
+
+ // We've already verified that requestRange starts with "bytes=", see canResume.
+ QByteArray requestRange = request().rawHeader("Range").mid(6);
+
+ int index = requestRange.indexOf('-');
+
+ quint64 requestStartOffset = requestRange.left(index).toULongLong();
+ quint64 requestEndOffset = requestRange.mid(index + 1).toULongLong();
+
+ requestRange = "bytes=" + QByteArray::number(resumeOffset + requestStartOffset) +
+ '-' + QByteArray::number(requestEndOffset);
+
+ httpRequest.setHeaderField("Range", requestRange);
+ } else {
+ httpRequest.setHeaderField("Range", "bytes=" + QByteArray::number(resumeOffset) + '-');
+ }
+ }
foreach (const QByteArray &header, headers)
httpRequest.setHeaderField(header, request().rawHeader(header));
@@ -1094,6 +1140,31 @@ QNetworkCacheMetaData QNetworkAccessHttpBackend::fetchCacheMetaData(const QNetwo
return metaData;
}
+bool QNetworkAccessHttpBackend::canResume() const
+{
+ // Only GET operation supports resuming.
+ if (operation() != QNetworkAccessManager::GetOperation)
+ return false;
+
+ // Can only resume if server/resource supports Range header.
+ if (httpReply->headerField("Accept-Ranges", "none") == "none")
+ return false;
+
+ // We only support resuming for byte ranges.
+ if (request().hasRawHeader("Range")) {
+ QByteArray range = request().rawHeader("Range");
+ if (!range.startsWith("bytes="))
+ return false;
+ }
+
+ return true;
+}
+
+void QNetworkAccessHttpBackend::setResumeOffset(quint64 offset)
+{
+ resumeOffset = offset;
+}
+
QT_END_NAMESPACE
#endif // QT_NO_HTTP
diff --git a/src/network/access/qnetworkaccesshttpbackend_p.h b/src/network/access/qnetworkaccesshttpbackend_p.h
index 0eaf003..e5cc0ab 100644
--- a/src/network/access/qnetworkaccesshttpbackend_p.h
+++ b/src/network/access/qnetworkaccesshttpbackend_p.h
@@ -99,6 +99,9 @@ public:
// we return true since HTTP needs to send PUT/POST data again after having authenticated
bool needsResetableUploadData() { return true; }
+ bool canResume() const;
+ void setResumeOffset(quint64 offset);
+
private slots:
void replyReadyRead();
void replyFinished();
@@ -120,6 +123,8 @@ private:
QList<QSslError> pendingIgnoreSslErrorsList;
#endif
+ quint64 resumeOffset;
+
void disconnectFromHttp();
void setupConnection();
void validateCache(QHttpNetworkRequest &httpRequest, bool &loadedFromCache);
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index 03b7192..197d89e 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -47,6 +47,8 @@
#include "qnetworkcookie.h"
#include "qabstractnetworkcache.h"
+#include "QtNetwork/qnetworksession.h"
+
#include "qnetworkaccesshttpbackend_p.h"
#include "qnetworkaccessftpbackend_p.h"
#include "qnetworkaccessfilebackend_p.h"
@@ -59,6 +61,7 @@
#include "QtCore/qvector.h"
#include "QtNetwork/qauthenticator.h"
#include "QtNetwork/qsslconfiguration.h"
+#include "QtNetwork/qnetworkconfigmanager.h"
QT_BEGIN_NAMESPACE
@@ -161,12 +164,70 @@ static void ensureInitialized()
\value DeleteOperation delete contents operation (created with
deleteResource())
+ \value CustomOperation custom operation (created with
+ sendCustomRequest())
+
\omitvalue UnknownOperation
\sa QNetworkReply::operation()
*/
/*!
+ \enum QNetworkAccessManager::NetworkAccessibility
+
+ Indicates whether the network is accessible via this network access manager.
+
+ \value UnknownAccessibility The network accessibility cannot be determined.
+ \value NotAccessible The network is not currently accessible, either because there
+ is currently no network coverage or network access has been
+ explicitly disabled by a call to setNetworkAccessible().
+ \value Accessible The network is accessible.
+
+ \sa networkAccessible
+*/
+
+/*!
+ \property QNetworkAccessManager::networkAccessible
+ \brief whether the network is currently accessible via this network access manager.
+
+ \since 4.7
+
+ If the network is \l {NotAccessible}{not accessible} the network access manager will not
+ process any new network requests, all such requests will fail with an error. Requests with
+ URLs with the file:// scheme will still be processed.
+
+ By default the value of this property reflects the physical state of the device. Applications
+ may override it to disable all network requests via this network access manager by calling
+
+ \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 4
+
+ Network requests can be reenabled again by calling
+
+ \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 5
+
+ \note Calling setNetworkAccessible() does not change the network state.
+*/
+
+/*!
+ \fn void QNetworkAccessManager::networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible)
+
+ This signal is emitted when the value of the \l networkAccessible property changes.
+ \a accessible is the new network accessibility.
+*/
+
+/*!
+ \fn void QNetworkAccessManager::networkSessionConnected()
+
+ \since 4.7
+
+ \internal
+
+ This signal is emitted when the status of the network session changes into a usable (Connected)
+ state. It is used to signal to QNetworkReplys to start or migrate their network operation once
+ the network session has been opened or finished roaming.
+*/
+
+/*!
\fn void QNetworkAccessManager::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)
This signal is emitted whenever a proxy requests authentication
@@ -573,7 +634,7 @@ QNetworkReply *QNetworkAccessManager::head(const QNetworkRequest &request)
The contents as well as associated headers will be downloaded.
- \sa post(), put(), deleteResource()
+ \sa post(), put(), deleteResource(), sendCustomRequest()
*/
QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
{
@@ -592,7 +653,7 @@ QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
\note Sending a POST request on protocols other than HTTP and
HTTPS is undefined and will probably fail.
- \sa get(), put(), deleteResource()
+ \sa get(), put(), deleteResource(), sendCustomRequest()
*/
QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QIODevice *data)
{
@@ -633,7 +694,7 @@ QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, const
do not allow. Form upload mechanisms, including that of uploading
files through HTML forms, use the POST mechanism.
- \sa get(), post()
+ \sa get(), post(), deleteResource(), sendCustomRequest()
*/
QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, QIODevice *data)
{
@@ -664,7 +725,7 @@ QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, const
\note This feature is currently available for HTTP only, performing an
HTTP DELETE request.
- \sa get(), post(), put()
+ \sa get(), post(), put(), sendCustomRequest()
*/
QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &request)
{
@@ -672,6 +733,148 @@ QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &requ
}
/*!
+ \since 4.7
+
+ Sets the network configuration that will be used when creating the
+ \l {QNetworkSession}{network session} to \a config.
+
+ The network configuration is used to create and open a network session before any request that
+ requires network access is process. If no network configuration is explicitly set via this
+ function the network configuration returned by
+ QNetworkConfigurationManager::defaultConfiguration() will be used.
+
+ To restore the default network configuration set the network configuration to the value
+ returned from QNetworkConfigurationManager::defaultConfiguration().
+
+ \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 2
+
+ If an invalid network configuration is set, a network session will not be created. In this
+ case network requests will be processed regardless, but may fail. For example:
+
+ \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 3
+
+ \sa configuration(), QNetworkSession
+*/
+void QNetworkAccessManager::setConfiguration(const QNetworkConfiguration &config)
+{
+ d_func()->createSession(config);
+}
+
+/*!
+ \since 4.7
+
+ Returns the network configuration that will be used to create the
+ \l {QNetworkSession}{network session} which will be used when processing network requests.
+
+ \sa setConfiguration(), activeConfiguration()
+*/
+QNetworkConfiguration QNetworkAccessManager::configuration() const
+{
+ Q_D(const QNetworkAccessManager);
+
+ if (d->networkSession)
+ return d->networkSession->configuration();
+ else
+ return QNetworkConfiguration();
+}
+
+/*!
+ \since 4.7
+
+ Returns the current active network configuration.
+
+ If the network configuration returned by configuration() is of type
+ QNetworkConfiguration::ServiceNetwork this function will return the current active child
+ network configuration of that configuration. Otherwise returns the same network configuration
+ as configuration().
+
+ Use this function to return the actual network configuration currently in use by the network
+ session.
+
+ \sa configuration()
+*/
+QNetworkConfiguration QNetworkAccessManager::activeConfiguration() const
+{
+ Q_D(const QNetworkAccessManager);
+
+ if (d->networkSession) {
+ QNetworkConfigurationManager manager;
+
+ return manager.configurationFromIdentifier(
+ d->networkSession->sessionProperty(QLatin1String("ActiveConfiguration")).toString());
+ } else {
+ return QNetworkConfiguration();
+ }
+}
+
+/*!
+ \since 4.7
+
+ Overrides the reported network accessibility. If \a accessible is NotAccessible the reported
+ network accessiblity will always be NotAccessible. Otherwise the reported network
+ accessibility will reflect the actual device state.
+*/
+void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkAccessibility accessible)
+{
+ Q_D(QNetworkAccessManager);
+
+ if (d->networkAccessible != accessible) {
+ NetworkAccessibility previous = networkAccessible();
+ d->networkAccessible = accessible;
+ NetworkAccessibility current = networkAccessible();
+ if (previous != current)
+ emit networkAccessibleChanged(current);
+ }
+}
+
+/*!
+ \since 4.7
+
+ Returns the current network accessibility.
+*/
+QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccessible() const
+{
+ Q_D(const QNetworkAccessManager);
+
+ if (d->networkSession) {
+ // d->online holds online/offline state of this network session.
+ if (d->online)
+ return d->networkAccessible;
+ else
+ return NotAccessible;
+ } else {
+ // Network accessibility is either disabled or unknown.
+ return (d->networkAccessible == NotAccessible) ? NotAccessible : UnknownAccessibility;
+ }
+}
+
+/*!
+ \since 4.7
+
+ Sends a custom request to the server identified by the URL of \a request.
+
+ It is the user's responsibility to send a \a verb to the server that is valid
+ according to the HTTP specification.
+
+ This method provides means to send verbs other than the common ones provided
+ via get() or post() etc., for instance sending an HTTP OPTIONS command.
+
+ If \a data is not empty, the contents of the \a data
+ device will be uploaded to the server; in that case, data must be open for
+ reading and must remain valid until the finished() signal is emitted for this reply.
+
+ \note This feature is currently available for HTTP only.
+
+ \sa get(), post(), put(), deleteResource()
+*/
+QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data)
+{
+ QNetworkRequest newRequest(request);
+ newRequest.setAttribute(QNetworkRequest::CustomVerbAttribute, verb);
+ return d_func()->postProcess(createRequest(QNetworkAccessManager::CustomOperation, newRequest, data));
+}
+
+/*!
Returns a new QNetworkReply object to handle the operation \a op
and request \a req. The device \a outgoingData is always 0 for Get and
Head requests, but is the value passed to post() and put() in
@@ -700,6 +903,28 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
return new QFileNetworkReply(this, req, op);
}
+ // Return a disabled network reply if network access is disabled.
+ // Except if the scheme is empty or file://.
+ if (!d->networkAccessible && !(req.url().scheme() == QLatin1String("file") ||
+ req.url().scheme().isEmpty())) {
+ return new QDisabledNetworkReply(this, req, op);
+ }
+
+ if (!d->networkSession && (d->initializeSession || !d->networkConfiguration.isEmpty())) {
+ QNetworkConfigurationManager manager;
+ if (!d->networkConfiguration.isEmpty()) {
+ d->createSession(manager.configurationFromIdentifier(d->networkConfiguration));
+ } else {
+ if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired)
+ d->createSession(manager.defaultConfiguration());
+ else
+ d->initializeSession = false;
+ }
+ }
+
+ if (d->networkSession)
+ d->networkSession->setSessionProperty(QLatin1String("AutoCloseSessionTimeout"), -1);
+
QNetworkRequest request = req;
if (!request.header(QNetworkRequest::ContentLengthHeader).isValid() &&
outgoingData && !outgoingData->isSequential()) {
@@ -716,6 +941,10 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
// first step: create the reply
QUrl url = request.url();
QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
+ if (req.url().scheme() != QLatin1String("file") && !req.url().scheme().isEmpty()) {
+ connect(this, SIGNAL(networkSessionConnected()),
+ reply, SLOT(_q_networkSessionConnected()));
+ }
QNetworkReplyImplPrivate *priv = reply->d_func();
priv->manager = this;
@@ -750,9 +979,13 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
void QNetworkAccessManagerPrivate::_q_replyFinished()
{
Q_Q(QNetworkAccessManager);
+
QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
if (reply)
emit q->finished(reply);
+
+ if (networkSession && q->findChildren<QNetworkReply *>().count() == 1)
+ networkSession->setSessionProperty(QLatin1String("AutoCloseSessionTimeout"), 120000);
}
void QNetworkAccessManagerPrivate::_q_replySslErrors(const QList<QSslError> &errors)
@@ -1005,6 +1238,87 @@ QNetworkAccessManagerPrivate::~QNetworkAccessManagerPrivate()
{
}
+void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &config)
+{
+ Q_Q(QNetworkAccessManager);
+
+ initializeSession = false;
+
+ if (networkSession)
+ delete networkSession;
+
+ if (!config.isValid()) {
+ networkSession = 0;
+ online = false;
+
+ if (networkAccessible == QNetworkAccessManager::NotAccessible)
+ emit q->networkAccessibleChanged(QNetworkAccessManager::NotAccessible);
+ else
+ emit q->networkAccessibleChanged(QNetworkAccessManager::UnknownAccessibility);
+
+ return;
+ }
+
+ networkSession = new QNetworkSession(config, q);
+
+ QObject::connect(networkSession, SIGNAL(opened()), q, SIGNAL(networkSessionConnected()));
+ QObject::connect(networkSession, SIGNAL(closed()), q, SLOT(_q_networkSessionClosed()));
+ QObject::connect(networkSession, SIGNAL(stateChanged(QNetworkSession::State)),
+ q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)));
+ QObject::connect(networkSession, SIGNAL(newConfigurationActivated()),
+ q, SLOT(_q_networkSessionNewConfigurationActivated()));
+ QObject::connect(networkSession,
+ SIGNAL(preferredConfigurationChanged(QNetworkConfiguration,bool)),
+ q,
+ SLOT(_q_networkSessionPreferredConfigurationChanged(QNetworkConfiguration,bool)));
+
+ _q_networkSessionStateChanged(networkSession->state());
+}
+
+void QNetworkAccessManagerPrivate::_q_networkSessionClosed()
+{
+ if (networkSession) {
+ networkConfiguration = networkSession->configuration().identifier();
+
+ networkSession->deleteLater();
+ networkSession = 0;
+ }
+}
+
+void QNetworkAccessManagerPrivate::_q_networkSessionNewConfigurationActivated()
+{
+ Q_Q(QNetworkAccessManager);
+
+ if (networkSession) {
+ networkSession->accept();
+
+ emit q->networkSessionConnected();
+ }
+}
+
+void QNetworkAccessManagerPrivate::_q_networkSessionPreferredConfigurationChanged(const QNetworkConfiguration &, bool)
+{
+ if (networkSession)
+ networkSession->migrate();
+}
+
+void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession::State state)
+{
+ Q_Q(QNetworkAccessManager);
+
+ if (online) {
+ if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) {
+ online = false;
+ emit q->networkAccessibleChanged(QNetworkAccessManager::NotAccessible);
+ }
+ } else {
+ if (state == QNetworkSession::Connected || state == QNetworkSession::Roaming) {
+ online = true;
+ emit q->networkAccessibleChanged(networkAccessible);
+ }
+ }
+}
+
QT_END_NAMESPACE
#include "moc_qnetworkaccessmanager.cpp"
diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h
index d2fe527..c57c9c6 100644
--- a/src/network/access/qnetworkaccessmanager.h
+++ b/src/network/access/qnetworkaccessmanager.h
@@ -62,12 +62,16 @@ class QNetworkReply;
class QNetworkProxy;
class QNetworkProxyFactory;
class QSslError;
+class QNetworkConfiguration;
class QNetworkReplyImplPrivate;
class QNetworkAccessManagerPrivate;
class Q_NETWORK_EXPORT QNetworkAccessManager: public QObject
{
Q_OBJECT
+
+ Q_PROPERTY(NetworkAccessibility networkAccessible READ networkAccessible WRITE setNetworkAccessible NOTIFY networkAccessibleChanged)
+
public:
enum Operation {
HeadOperation = 1,
@@ -75,10 +79,17 @@ public:
PutOperation,
PostOperation,
DeleteOperation,
+ CustomOperation,
UnknownOperation = 0
};
+ enum NetworkAccessibility {
+ UnknownAccessibility = -1,
+ NotAccessible = 0,
+ Accessible = 1
+ };
+
explicit QNetworkAccessManager(QObject *parent = 0);
~QNetworkAccessManager();
@@ -102,6 +113,14 @@ public:
QNetworkReply *put(const QNetworkRequest &request, QIODevice *data);
QNetworkReply *put(const QNetworkRequest &request, const QByteArray &data);
QNetworkReply *deleteResource(const QNetworkRequest &request);
+ QNetworkReply *sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data = 0);
+
+ void setConfiguration(const QNetworkConfiguration &config);
+ QNetworkConfiguration configuration() const;
+ QNetworkConfiguration activeConfiguration() const;
+
+ void setNetworkAccessible(NetworkAccessibility accessible);
+ NetworkAccessibility networkAccessible() const;
Q_SIGNALS:
#ifndef QT_NO_NETWORKPROXY
@@ -113,6 +132,10 @@ Q_SIGNALS:
void sslErrors(QNetworkReply *reply, const QList<QSslError> &errors);
#endif
+ void networkSessionConnected();
+
+ void networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible);
+
protected:
virtual QNetworkReply *createRequest(Operation op, const QNetworkRequest &request,
QIODevice *outgoingData = 0);
@@ -122,6 +145,10 @@ private:
Q_DECLARE_PRIVATE(QNetworkAccessManager)
Q_PRIVATE_SLOT(d_func(), void _q_replyFinished())
Q_PRIVATE_SLOT(d_func(), void _q_replySslErrors(QList<QSslError>))
+ Q_PRIVATE_SLOT(d_func(), void _q_networkSessionClosed())
+ Q_PRIVATE_SLOT(d_func(), void _q_networkSessionNewConfigurationActivated())
+ Q_PRIVATE_SLOT(d_func(), void _q_networkSessionPreferredConfigurationChanged(QNetworkConfiguration,bool))
+ Q_PRIVATE_SLOT(d_func(), void _q_networkSessionStateChanged(QNetworkSession::State))
};
QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h
index 1749373..1785685 100644
--- a/src/network/access/qnetworkaccessmanager_p.h
+++ b/src/network/access/qnetworkaccessmanager_p.h
@@ -58,6 +58,7 @@
#include "qnetworkaccessbackend_p.h"
#include "private/qobject_p.h"
#include "QtNetwork/qnetworkproxy.h"
+#include "QtNetwork/qnetworksession.h"
QT_BEGIN_NAMESPACE
@@ -74,6 +75,10 @@ public:
#ifndef QT_NO_NETWORKPROXY
proxyFactory(0),
#endif
+ networkSession(0),
+ networkAccessible(QNetworkAccessManager::Accessible),
+ online(false),
+ initializeSession(true),
cookieJarCreated(false)
{ }
~QNetworkAccessManagerPrivate();
@@ -99,6 +104,14 @@ public:
QNetworkAccessBackend *findBackend(QNetworkAccessManager::Operation op, const QNetworkRequest &request);
+ void createSession(const QNetworkConfiguration &config);
+
+ void _q_networkSessionClosed();
+ void _q_networkSessionNewConfigurationActivated();
+ void _q_networkSessionPreferredConfigurationChanged(const QNetworkConfiguration &config,
+ bool isSeamless);
+ void _q_networkSessionStateChanged(QNetworkSession::State state);
+
// this is the cache for storing downloaded files
QAbstractNetworkCache *networkCache;
@@ -110,8 +123,13 @@ public:
QNetworkProxyFactory *proxyFactory;
#endif
- bool cookieJarCreated;
+ QNetworkSession *networkSession;
+ QString networkConfiguration;
+ QNetworkAccessManager::NetworkAccessibility networkAccessible;
+ bool online;
+ bool initializeSession;
+ bool cookieJarCreated;
// this cache can be used by individual backends to cache e.g. their TCP connections to a server
// and use the connections for multiple requests.
diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp
index 0a8ea5d..c8b8c1f 100644
--- a/src/network/access/qnetworkreply.cpp
+++ b/src/network/access/qnetworkreply.cpp
@@ -125,6 +125,11 @@ QNetworkReplyPrivate::QNetworkReplyPrivate()
encrypted channel could not be established. The sslErrors() signal
should have been emitted.
+ \value TemporaryNetworkFailureError the connection was broken due
+ to disconnection from the network, however the system has initiated
+ roaming to another access point. The request should be resubmitted
+ and will be processed as soon as the connection is re-established.
+
\value ProxyConnectionRefusedError the connection to the proxy
server was refused (the proxy server is not accepting requests)
@@ -533,6 +538,21 @@ QByteArray QNetworkReply::rawHeader(const QByteArray &headerName) const
return QByteArray();
}
+/*! \typedef QNetworkReply::RawHeaderPair
+
+ RawHeaderPair is a QPair<QByteArray, QByteArray> where the first
+ QByteArray is the header name and the second is the header.
+ */
+
+/*!
+ Returns a list of raw header pairs.
+ */
+const QList<QNetworkReply::RawHeaderPair>& QNetworkReply::rawHeaderPairs() const
+{
+ Q_D(const QNetworkReply);
+ return d->rawHeaders;
+}
+
/*!
Returns a list of headers fields that were sent by the remote
server, in the order that they were sent. Duplicate headers are
diff --git a/src/network/access/qnetworkreply.h b/src/network/access/qnetworkreply.h
index 5be4cce..acb7379 100644
--- a/src/network/access/qnetworkreply.h
+++ b/src/network/access/qnetworkreply.h
@@ -77,6 +77,7 @@ public:
TimeoutError,
OperationCanceledError,
SslHandshakeFailedError,
+ TemporaryNetworkFailureError,
UnknownNetworkError = 99,
// proxy errors (101-199):
@@ -128,6 +129,9 @@ public:
QList<QByteArray> rawHeaderList() const;
QByteArray rawHeader(const QByteArray &headerName) const;
+ typedef QPair<QByteArray, QByteArray> RawHeaderPair;
+ const QList<RawHeaderPair>& rawHeaderPairs() const;
+
// attributes
QVariant attribute(QNetworkRequest::Attribute code) const;
diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp
index 59c7d76..edd6889 100644
--- a/src/network/access/qnetworkreplyimpl.cpp
+++ b/src/network/access/qnetworkreplyimpl.cpp
@@ -46,7 +46,9 @@
#include "QtCore/qcoreapplication.h"
#include "QtCore/qdatetime.h"
#include "QtNetwork/qsslconfiguration.h"
+#include "QtNetwork/qnetworksession.h"
#include "qnetworkaccesshttpbackend_p.h"
+#include "qnetworkaccessmanager_p.h"
#include <QtCore/QCoreApplication>
@@ -57,7 +59,7 @@ inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate()
copyDevice(0),
cacheEnabled(false), cacheSaveDevice(0),
notificationHandlingPaused(false),
- bytesDownloaded(0), lastBytesDownloaded(-1), bytesUploaded(-1),
+ bytesDownloaded(0), lastBytesDownloaded(-1), bytesUploaded(-1), preMigrationDownloaded(-1),
httpStatusCode(0),
state(Idle)
{
@@ -65,6 +67,8 @@ inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate()
void QNetworkReplyImplPrivate::_q_startOperation()
{
+ Q_Q(QNetworkReplyImpl);
+
// ensure this function is only being called once
if (state == Working) {
qDebug("QNetworkReplyImpl::_q_startOperation was called more than once");
@@ -82,7 +86,27 @@ void QNetworkReplyImplPrivate::_q_startOperation()
return;
}
- backend->open();
+ if (!backend->start()) {
+ // backend failed to start because the session state is not Connected.
+ // QNetworkAccessManager will call reply->backend->start() again for us when the session
+ // state changes.
+ state = WaitingForSession;
+
+ QNetworkSession *session = manager->d_func()->networkSession;
+
+ if (session) {
+ QObject::connect(session, SIGNAL(error(QNetworkSession::SessionError)),
+ q, SLOT(_q_networkSessionFailed()));
+
+ if (!session->isOpen())
+ session->open();
+ } else {
+ qWarning("Backend is waiting for QNetworkSession to connect, but there is none!");
+ }
+
+ return;
+ }
+
if (state != Finished) {
if (operation == QNetworkAccessManager::GetOperation)
pendingNotifications.append(NotifyDownstreamReadyWrite);
@@ -134,6 +158,8 @@ void QNetworkReplyImplPrivate::_q_copyReadyRead()
lastBytesDownloaded = bytesDownloaded;
QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
+ if (preMigrationDownloaded != Q_INT64_C(-1))
+ totalSize = totalSize.toLongLong() + preMigrationDownloaded;
pauseNotificationHandling();
emit q->downloadProgress(bytesDownloaded,
totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
@@ -206,6 +232,47 @@ void QNetworkReplyImplPrivate::_q_bufferOutgoingData()
}
}
+void QNetworkReplyImplPrivate::_q_networkSessionConnected()
+{
+ Q_Q(QNetworkReplyImpl);
+
+ if (manager.isNull())
+ return;
+
+ QNetworkSession *session = manager->d_func()->networkSession;
+ if (!session)
+ return;
+
+ if (session->state() != QNetworkSession::Connected)
+ return;
+
+ switch (state) {
+ case QNetworkReplyImplPrivate::Buffering:
+ case QNetworkReplyImplPrivate::Working:
+ case QNetworkReplyImplPrivate::Reconnecting:
+ // Migrate existing downloads to new network connection.
+ migrateBackend();
+ break;
+ case QNetworkReplyImplPrivate::WaitingForSession:
+ // Start waiting requests.
+ QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
+ break;
+ default:
+ ;
+ }
+}
+
+void QNetworkReplyImplPrivate::_q_networkSessionFailed()
+{
+ // Abort waiting replies.
+ if (state == WaitingForSession) {
+ state = Working;
+ error(QNetworkReplyImpl::UnknownNetworkError,
+ QCoreApplication::translate("QNetworkReply", "Network session error."));
+ finished();
+ }
+}
+
void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const QNetworkRequest &req,
QIODevice *data)
{
@@ -251,11 +318,15 @@ void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const
// for HTTP, we want to send out the request as fast as possible to the network, without
// invoking methods in a QueuedConnection
+#ifndef QT_NO_HTTP
if (qobject_cast<QNetworkAccessHttpBackend *>(backend)) {
_q_startOperation();
} else {
QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
}
+#else
+ QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
+#endif // QT_NO_HTTP
}
q->QIODevice::open(QIODevice::ReadOnly);
@@ -457,6 +528,8 @@ void QNetworkReplyImplPrivate::appendDownstreamData(QByteDataBuffer &data)
QPointer<QNetworkReplyImpl> qq = q;
QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
+ if (preMigrationDownloaded != Q_INT64_C(-1))
+ totalSize = totalSize.toLongLong() + preMigrationDownloaded;
pauseNotificationHandling();
emit q->downloadProgress(bytesDownloaded,
totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
@@ -498,14 +571,42 @@ void QNetworkReplyImplPrivate::appendDownstreamData(QIODevice *data)
void QNetworkReplyImplPrivate::finished()
{
Q_Q(QNetworkReplyImpl);
- if (state == Finished || state == Aborted)
+
+ if (state == Finished || state == Aborted || state == WaitingForSession)
return;
+ pauseNotificationHandling();
+ QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
+ if (preMigrationDownloaded != Q_INT64_C(-1))
+ totalSize = totalSize.toLongLong() + preMigrationDownloaded;
+
+ if (!manager.isNull()) {
+ QNetworkSession *session = manager->d_func()->networkSession;
+ if (session && session->state() == QNetworkSession::Roaming &&
+ state == Working && errorCode != QNetworkReply::OperationCanceledError) {
+ // only content with a known size will fail with a temporary network failure error
+ if (!totalSize.isNull()) {
+ if (bytesDownloaded != totalSize) {
+ if (migrateBackend()) {
+ // either we are migrating or the request is finished/aborted
+ if (state == Reconnecting || state == WaitingForSession) {
+ resumeNotificationHandling();
+ return; // exit early if we are migrating.
+ }
+ } else {
+ error(QNetworkReply::TemporaryNetworkFailureError,
+ QNetworkReply::tr("Temporary network failure."));
+ }
+ }
+ }
+ }
+ }
+ resumeNotificationHandling();
+
state = Finished;
pendingNotifications.clear();
pauseNotificationHandling();
- QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
if (totalSize.isNull() || totalSize == -1) {
emit q->downloadProgress(bytesDownloaded, bytesDownloaded);
}
@@ -514,7 +615,9 @@ void QNetworkReplyImplPrivate::finished()
emit q->uploadProgress(0, 0);
resumeNotificationHandling();
- completeCacheSave();
+ // if we don't know the total size of or we received everything save the cache
+ if (totalSize.isNull() || totalSize == -1 || bytesDownloaded == totalSize)
+ completeCacheSave();
// note: might not be a good idea, since users could decide to delete us
// which would delete the backend too...
@@ -634,6 +737,13 @@ void QNetworkReplyImpl::close()
d->finished();
}
+bool QNetworkReplyImpl::canReadLine () const
+{
+ Q_D(const QNetworkReplyImpl);
+ return QNetworkReply::canReadLine() || d->readBuffer.canReadLine();
+}
+
+
/*!
Returns the number of bytes available for reading with
QIODevice::read(). The number of bytes available may grow until
@@ -722,6 +832,87 @@ bool QNetworkReplyImpl::event(QEvent *e)
return QObject::event(e);
}
+/*
+ Migrates the backend of the QNetworkReply to a new network connection if required. Returns
+ true if the reply is migrated or it is not required; otherwise returns false.
+*/
+bool QNetworkReplyImplPrivate::migrateBackend()
+{
+ Q_Q(QNetworkReplyImpl);
+
+ // Network reply is already finished or aborted, don't need to migrate.
+ if (state == Finished || state == Aborted)
+ return true;
+
+ // Backend does not support resuming download.
+ if (!backend->canResume())
+ return false;
+
+ // Request has outgoing data, not migrating.
+ if (outgoingData)
+ return false;
+
+ // Request is serviced from the cache, don't need to migrate.
+ if (copyDevice)
+ return true;
+
+ state = QNetworkReplyImplPrivate::Reconnecting;
+
+ if (backend) {
+ delete backend;
+ backend = 0;
+ }
+
+ cookedHeaders.clear();
+ rawHeaders.clear();
+
+ preMigrationDownloaded = bytesDownloaded;
+
+ backend = manager->d_func()->findBackend(operation, request);
+
+ if (backend) {
+ backend->setParent(q);
+ backend->reply = this;
+ backend->setResumeOffset(bytesDownloaded);
+ }
+
+#ifndef QT_NO_HTTP
+ if (qobject_cast<QNetworkAccessHttpBackend *>(backend)) {
+ _q_startOperation();
+ } else {
+ QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
+ }
+#else
+ QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
+#endif // QT_NO_HTTP
+
+ return true;
+}
+
+QDisabledNetworkReply::QDisabledNetworkReply(QObject *parent,
+ const QNetworkRequest &req,
+ QNetworkAccessManager::Operation op)
+: QNetworkReply(parent)
+{
+ setRequest(req);
+ setUrl(req.url());
+ setOperation(op);
+
+ qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
+
+ QString msg = QCoreApplication::translate("QNetworkAccessManager",
+ "Network access is disabled.");
+ setError(UnknownNetworkError, msg);
+
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QNetworkReply::NetworkError, UnknownNetworkError));
+ QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
+}
+
+QDisabledNetworkReply::~QDisabledNetworkReply()
+{
+}
+
QT_END_NAMESPACE
#include "moc_qnetworkreplyimpl_p.cpp"
diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h
index 168e5cf..fcb3397 100644
--- a/src/network/access/qnetworkreplyimpl_p.h
+++ b/src/network/access/qnetworkreplyimpl_p.h
@@ -77,10 +77,11 @@ public:
~QNetworkReplyImpl();
virtual void abort();
- // reimplemented from QNetworkReply
+ // reimplemented from QNetworkReply / QIODevice
virtual void close();
virtual qint64 bytesAvailable() const;
virtual void setReadBufferSize(qint64 size);
+ virtual bool canReadLine () const;
virtual qint64 readData(char *data, qint64 maxlen);
virtual bool event(QEvent *);
@@ -98,6 +99,8 @@ public:
Q_PRIVATE_SLOT(d_func(), void _q_copyReadChannelFinished())
Q_PRIVATE_SLOT(d_func(), void _q_bufferOutgoingData())
Q_PRIVATE_SLOT(d_func(), void _q_bufferOutgoingDataFinished())
+ Q_PRIVATE_SLOT(d_func(), void _q_networkSessionConnected())
+ Q_PRIVATE_SLOT(d_func(), void _q_networkSessionFailed())
};
class QNetworkReplyImplPrivate: public QNetworkReplyPrivate
@@ -110,11 +113,13 @@ public:
};
enum State {
- Idle,
- Buffering,
- Working,
- Finished,
- Aborted
+ Idle, // The reply is idle.
+ Buffering, // The reply is buffering outgoing data.
+ Working, // The reply is uploading/downloading data.
+ Finished, // The reply has finished.
+ Aborted, // The reply has been aborted.
+ WaitingForSession, // The reply is waiting for the session to open before connecting.
+ Reconnecting // The reply will reconnect to once roaming has completed.
};
typedef QQueue<InternalNotifications> NotificationQueue;
@@ -128,6 +133,8 @@ public:
void _q_copyReadChannelFinished();
void _q_bufferOutgoingData();
void _q_bufferOutgoingDataFinished();
+ void _q_networkSessionConnected();
+ void _q_networkSessionFailed();
void setup(QNetworkAccessManager::Operation op, const QNetworkRequest &request,
QIODevice *outgoingData);
@@ -161,6 +168,8 @@ public:
QIODevice *copyDevice;
QAbstractNetworkCache *networkCache() const;
+ bool migrateBackend();
+
bool cacheEnabled;
QIODevice *cacheSaveDevice;
@@ -177,6 +186,7 @@ public:
qint64 bytesDownloaded;
qint64 lastBytesDownloaded;
qint64 bytesUploaded;
+ qint64 preMigrationDownloaded;
QString httpReasonPhrase;
int httpStatusCode;
@@ -186,6 +196,20 @@ public:
Q_DECLARE_PUBLIC(QNetworkReplyImpl)
};
+class QDisabledNetworkReply : public QNetworkReply
+{
+ Q_OBJECT
+
+public:
+ QDisabledNetworkReply(QObject *parent, const QNetworkRequest &req,
+ QNetworkAccessManager::Operation op);
+ ~QDisabledNetworkReply();
+
+ void abort() { }
+protected:
+ qint64 readData(char *, qint64) { return -1; }
+};
+
QT_END_NAMESPACE
#endif
diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp
index c4ff24d..61c116d 100644
--- a/src/network/access/qnetworkrequest.cpp
+++ b/src/network/access/qnetworkrequest.cpp
@@ -184,6 +184,12 @@ QT_BEGIN_NAMESPACE
Indicates whether the HTTP pipelining was used for receiving
this reply.
+ \value CustomVerbAttribute
+ Requests only, type: QVariant::ByteArray
+ Holds the value for the custom HTTP verb to send (destined for usage
+ of other verbs than GET, POST, PUT and DELETE). This verb is set
+ when calling QNetworkAccessManager::sendCustomRequest().
+
\value User
Special type. Additional information can be passed in
QVariants with types ranging from User to UserMax. The default
@@ -220,8 +226,9 @@ class QNetworkRequestPrivate: public QSharedData, public QNetworkHeadersPrivate
{
public:
inline QNetworkRequestPrivate()
+ : priority(QNetworkRequest::NormalPriority)
#ifndef QT_NO_OPENSSL
- : sslConfiguration(0)
+ , sslConfiguration(0)
#endif
{ qRegisterMetaType<QNetworkRequest>(); }
~QNetworkRequestPrivate()
@@ -236,6 +243,7 @@ public:
: QSharedData(other), QNetworkHeadersPrivate(other)
{
url = other.url;
+ priority = other.priority;
#ifndef QT_NO_OPENSSL
sslConfiguration = 0;
@@ -247,12 +255,14 @@ public:
inline bool operator==(const QNetworkRequestPrivate &other) const
{
return url == other.url &&
+ priority == other.priority &&
rawHeaders == other.rawHeaders &&
attributes == other.attributes;
// don't compare cookedHeaders
}
QUrl url;
+ QNetworkRequest::Priority priority;
#ifndef QT_NO_OPENSSL
mutable QSslConfiguration *sslConfiguration;
#endif
@@ -518,6 +528,45 @@ QObject *QNetworkRequest::originatingObject() const
return d->originatingObject.data();
}
+/*!
+ \since 4.7
+
+ Return the priority of this request.
+
+ \sa setPriority()
+*/
+QNetworkRequest::Priority QNetworkRequest::priority() const
+{
+ return d->priority;
+}
+
+/*! \enum QNetworkRequest::Priority
+
+ \since 4.7
+
+ This enum lists the possible network request priorities.
+
+ \value HighPriority High priority
+ \value NormalPriority Normal priority
+ \value LowPriority Low priority
+ */
+
+/*!
+ \since 4.7
+
+ Set the priority of this request to \a priority.
+
+ \note The \a priority is only a hint to the network access
+ manager. It can use it or not. Currently it is used for HTTP to
+ decide which request should be sent first to a server.
+
+ \sa priority()
+*/
+void QNetworkRequest::setPriority(Priority priority)
+{
+ d->priority = priority;
+}
+
static QByteArray headerName(QNetworkRequest::KnownHeaders header)
{
switch (header) {
diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h
index fe01f8c..a0ef1a6 100644
--- a/src/network/access/qnetworkrequest.h
+++ b/src/network/access/qnetworkrequest.h
@@ -78,6 +78,7 @@ public:
DoNotBufferUploadDataAttribute,
HttpPipeliningAllowedAttribute,
HttpPipeliningWasUsedAttribute,
+ CustomVerbAttribute,
User = 1000,
UserMax = 32767
@@ -89,6 +90,12 @@ public:
AlwaysCache
};
+ enum Priority {
+ HighPriority = 1,
+ NormalPriority = 3,
+ LowPriority = 5
+ };
+
explicit QNetworkRequest(const QUrl &url = QUrl());
QNetworkRequest(const QNetworkRequest &other);
~QNetworkRequest();
@@ -123,6 +130,9 @@ public:
void setOriginatingObject(QObject *object);
QObject *originatingObject() const;
+ Priority priority() const;
+ void setPriority(Priority priority);
+
private:
QSharedDataPointer<QNetworkRequestPrivate> d;
friend class QNetworkRequestPrivate;
diff --git a/src/network/bearer/bearer.pri b/src/network/bearer/bearer.pri
new file mode 100644
index 0000000..44e97fd
--- /dev/null
+++ b/src/network/bearer/bearer.pri
@@ -0,0 +1,18 @@
+# Qt network bearer management module
+
+HEADERS += bearer/qnetworkconfiguration.h \
+ bearer/qnetworksession.h \
+ bearer/qnetworkconfigmanager.h \
+ bearer/qnetworkconfigmanager_p.h \
+ bearer/qnetworkconfiguration_p.h \
+ bearer/qnetworksession_p.h \
+ bearer/qbearerengine_p.h \
+ bearer/qbearerplugin_p.h
+
+SOURCES += bearer/qnetworksession.cpp \
+ bearer/qnetworkconfigmanager.cpp \
+ bearer/qnetworkconfiguration.cpp \
+ bearer/qnetworkconfigmanager_p.cpp \
+ bearer/qbearerengine.cpp \
+ bearer/qbearerplugin.cpp
+
diff --git a/src/network/bearer/qbearerengine.cpp b/src/network/bearer/qbearerengine.cpp
new file mode 100644
index 0000000..c42e2d2
--- /dev/null
+++ b/src/network/bearer/qbearerengine.cpp
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "qbearerengine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QBearerEngine::QBearerEngine(QObject *parent)
+: QObject(parent), mutex(QMutex::Recursive)
+{
+}
+
+QBearerEngine::~QBearerEngine()
+{
+ QHash<QString, QNetworkConfigurationPrivatePointer>::Iterator it;
+ QHash<QString, QNetworkConfigurationPrivatePointer>::Iterator end;
+ for (it = snapConfigurations.begin(), end = snapConfigurations.end(); it != end; ++it) {
+ it.value()->isValid = false;
+ it.value()->id.clear();
+ }
+
+ for (it = accessPointConfigurations.begin(), end = accessPointConfigurations.end();
+ it != end; ++it) {
+ it.value()->isValid = false;
+ it.value()->id.clear();
+ }
+
+ for (it = userChoiceConfigurations.begin(), end = userChoiceConfigurations.end();
+ it != end; ++it) {
+ it.value()->isValid = false;
+ it.value()->id.clear();
+ }
+}
+
+bool QBearerEngine::requiresPolling() const
+{
+ return false;
+}
+
+/*
+ Returns true if configurations are in use; otherwise returns false.
+
+ If configurations are in use and requiresPolling() returns true, polling will be enabled for
+ this engine.
+*/
+bool QBearerEngine::configurationsInUse() const
+{
+ QHash<QString, QNetworkConfigurationPrivatePointer>::ConstIterator it;
+ QHash<QString, QNetworkConfigurationPrivatePointer>::ConstIterator end;
+
+ QMutexLocker locker(&mutex);
+
+ for (it = accessPointConfigurations.begin(),
+ end = accessPointConfigurations.end(); it != end; ++it) {
+ if (it.value()->ref > 1)
+ return true;
+ }
+
+ for (it = snapConfigurations.begin(), end = snapConfigurations.end(); it != end; ++it) {
+ if (it.value()->ref > 1)
+ return true;
+ }
+
+ for (it = userChoiceConfigurations.begin(),
+ end = userChoiceConfigurations.end(); it != end; ++it) {
+ if (it.value()->ref > 1)
+ return true;
+ }
+
+ return false;
+}
+
+#include "moc_qbearerengine_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/network/bearer/qbearerengine_p.h b/src/network/bearer/qbearerengine_p.h
new file mode 100644
index 0000000..fd4bf87
--- /dev/null
+++ b/src/network/bearer/qbearerengine_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QBEARERENGINE_P_H
+#define QBEARERENGINE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qnetworkconfiguration_p.h"
+#include "qnetworksession.h"
+#include "qnetworkconfigmanager.h"
+
+#include <QtCore/qobject.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkConfiguration;
+
+class Q_NETWORK_EXPORT QBearerEngine : public QObject
+{
+ Q_OBJECT
+
+ friend class QNetworkConfigurationManagerPrivate;
+
+public:
+ QBearerEngine(QObject *parent = 0);
+ virtual ~QBearerEngine();
+
+ virtual bool hasIdentifier(const QString &id) = 0;
+
+ virtual QNetworkConfigurationManager::Capabilities capabilities() const = 0;
+
+ virtual QNetworkSessionPrivate *createSessionBackend() = 0;
+
+ virtual QNetworkConfigurationPrivatePointer defaultConfiguration() = 0;
+
+ virtual bool requiresPolling() const;
+ bool configurationsInUse() const;
+
+Q_SIGNALS:
+ void configurationAdded(QNetworkConfigurationPrivatePointer config);
+ void configurationRemoved(QNetworkConfigurationPrivatePointer config);
+ void configurationChanged(QNetworkConfigurationPrivatePointer config);
+
+ void updateCompleted();
+
+protected:
+ //this table contains an up to date list of all configs at any time.
+ //it must be updated if configurations change, are added/removed or
+ //the members of ServiceNetworks change
+ QHash<QString, QNetworkConfigurationPrivatePointer> accessPointConfigurations;
+ QHash<QString, QNetworkConfigurationPrivatePointer> snapConfigurations;
+ QHash<QString, QNetworkConfigurationPrivatePointer> userChoiceConfigurations;
+
+ mutable QMutex mutex;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/bearer/qbearerplugin.cpp b/src/network/bearer/qbearerplugin.cpp
new file mode 100644
index 0000000..4509fd0
--- /dev/null
+++ b/src/network/bearer/qbearerplugin.cpp
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "qbearerplugin_p.h"
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+QBearerEnginePlugin::QBearerEnginePlugin(QObject *parent)
+: QObject(parent)
+{
+}
+
+QBearerEnginePlugin::~QBearerEnginePlugin()
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/bearer/qbearerplugin_p.h b/src/network/bearer/qbearerplugin_p.h
new file mode 100644
index 0000000..36709c2
--- /dev/null
+++ b/src/network/bearer/qbearerplugin_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QBEARERPLUGIN_P_H
+#define QBEARERPLUGIN_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qbearerengine_p.h"
+
+#include <QtCore/qplugin.h>
+#include <QtCore/qfactoryinterface.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+struct Q_NETWORK_EXPORT QBearerEngineFactoryInterface : public QFactoryInterface
+{
+ virtual QBearerEngine *create(const QString &key = QString()) const = 0;
+};
+
+#define QBearerEngineFactoryInterface_iid "com.trolltech.Qt.QBearerEngineFactoryInterface"
+Q_DECLARE_INTERFACE(QBearerEngineFactoryInterface, QBearerEngineFactoryInterface_iid)
+
+class Q_NETWORK_EXPORT QBearerEnginePlugin : public QObject, public QBearerEngineFactoryInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QBearerEngineFactoryInterface:QFactoryInterface)
+
+public:
+ explicit QBearerEnginePlugin(QObject *parent = 0);
+ virtual ~QBearerEnginePlugin();
+
+ virtual QStringList keys() const = 0;
+ virtual QBearerEngine *create(const QString &key = QString()) const = 0;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
+
diff --git a/src/network/bearer/qnetworkconfigmanager.cpp b/src/network/bearer/qnetworkconfigmanager.cpp
new file mode 100644
index 0000000..1ba5dab
--- /dev/null
+++ b/src/network/bearer/qnetworkconfigmanager.cpp
@@ -0,0 +1,306 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "qnetworkconfigmanager.h"
+
+#include "qnetworkconfigmanager_p.h"
+#include "qbearerengine_p.h"
+
+#include <QtCore/qstringlist.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QNetworkConfigurationManagerPrivate, connManager);
+
+QNetworkConfigurationManagerPrivate *qNetworkConfigurationManagerPrivate()
+{
+ return connManager();
+}
+
+/*!
+ \class QNetworkConfigurationManager
+
+ \brief The QNetworkConfigurationManager class manages the network configurations provided
+ by the system.
+
+ \since 4.7
+
+ \inmodule QtNetwork
+ \ingroup network
+
+ QNetworkConfigurationManager provides access to the network configurations known to the system and
+ enables applications to detect the system capabilities (with regards to network sessions) at runtime.
+
+ A QNetworkConfiguration abstracts a set of configuration options describing how a
+ network interface has to be configured to connect to a particular target network.
+ QNetworkConfigurationManager maintains and updates the global list of
+ QNetworkConfigurations. Applications can access and filter this list via
+ allConfigurations(). If a new configuration is added or an existing one is removed or changed
+ the configurationAdded(), configurationRemoved() and configurationChanged() signals are emitted
+ respectively.
+
+ The defaultConfiguration() can be used when intending to immediately create a new
+ network session without caring about the particular configuration. It returns
+ a \l QNetworkConfiguration::Discovered configuration. If there are not any
+ discovered ones an invalid configuration is returned.
+
+ Some configuration updates may require some time to perform updates. A WLAN scan is
+ such an example. Unless the platform performs internal updates it may be required to
+ manually trigger configuration updates via QNetworkConfigurationManager::updateConfigurations().
+ The completion of the update process is indicted by emitting the updateCompleted()
+ signal. The update process ensures that every existing QNetworkConfiguration instance
+ is updated. There is no need to ask for a renewed configuration list via allConfigurations().
+
+ \sa QNetworkConfiguration
+*/
+
+/*!
+ \fn void QNetworkConfigurationManager::configurationAdded(const QNetworkConfiguration& config)
+
+ This signal is emitted whenever a new network configuration is added to the system. The new
+ configuration is specified by \a config.
+*/
+
+/*!
+ \fn void QNetworkConfigurationManager::configurationRemoved(const QNetworkConfiguration& configuration)
+
+ This signal is emitted when a configuration is about to be removed from the system. The removed
+ \a configuration is invalid but retains name and identifier.
+*/
+
+/*!
+ \fn void QNetworkConfigurationManager::updateCompleted()
+
+ This signal is emitted when the configuration update has been completed. Such an update can
+ be initiated via \l updateConfigurations().
+*/
+
+/*! \fn void QNetworkConfigurationManager::configurationChanged(const QNetworkConfiguration& config)
+
+ This signal is emitted when the \l {QNetworkConfiguration::state()}{state} of \a config changes.
+*/
+
+/*!
+ \fn void QNetworkConfigurationManager::onlineStateChanged(bool isOnline)
+
+ This signal is emitted when the device changes from online to offline mode or vice versa.
+ \a isOnline represents the new state of the device.
+
+ The state is considered to be online for as long as
+ \l{allConfigurations()}{allConfigurations}(QNetworkConfiguration::Active) returns a list with
+ at least one entry.
+*/
+
+/*!
+ \enum QNetworkConfigurationManager::Capability
+
+ Specifies the system capabilities of the bearer API. The possible values are:
+
+ \value CanStartAndStopInterfaces Network sessions and their underlying access points can be
+ started and stopped. If this flag is not set QNetworkSession
+ can only monitor but not influence the state of access points.
+ On some platforms this feature may require elevated user
+ permissions. This option is platform specific and may not
+ always be available.
+ \value DirectConnectionRouting Network sessions and their sockets can be bound to a
+ particular network interface. Any packet that passes through
+ the socket goes to the specified network interface and thus
+ disregards standard routing table entries. This may be useful
+ when two interfaces can reach overlapping IP ranges or an
+ application has specific needs in regards to target networks.
+ This option is platform specific and may not always be
+ available.
+ \value SystemSessionSupport If this flag is set the underlying platform ensures that a
+ network interface is not shut down until the last network
+ session has been \l{QNetworkSession::close()}{closed()}. This
+ works across multiple processes. If the platform session
+ support is missing this API can only ensure the above behavior
+ for network sessions within the same process.
+ In general mobile platforms (such as Symbian/S60) have such
+ support whereas most desktop platform lack this capability.
+ \value ApplicationLevelRoaming The system gives applications control over the systems roaming
+ behavior. Applications can initiate roaming (in case the
+ current link is not suitable) and are consulted if the system
+ has identified a more suitable access point.
+ \value ForcedRoaming The system disconnects an existing access point and reconnects
+ via a more suitable one. The application does not have any
+ control over this process and has to reconnect its active
+ sockets.
+ \value DataStatistics If this flag is set QNetworkSession can provide statistics
+ about transmitted and received data.
+ \value NetworkSessionRequired If this flag is set the platform requires that a network
+ session is created before network operations can be performed.
+*/
+
+/*!
+ Constructs a QNetworkConfigurationManager with the given \a parent.
+*/
+QNetworkConfigurationManager::QNetworkConfigurationManager( QObject* parent )
+ : QObject(parent)
+{
+ QNetworkConfigurationManagerPrivate *priv = connManager();
+
+ connect(priv, SIGNAL(configurationAdded(QNetworkConfiguration)),
+ this, SIGNAL(configurationAdded(QNetworkConfiguration)));
+ connect(priv, SIGNAL(configurationRemoved(QNetworkConfiguration)),
+ this, SIGNAL(configurationRemoved(QNetworkConfiguration)));
+ connect(priv, SIGNAL(configurationUpdateComplete()),
+ this, SIGNAL(updateCompleted()));
+ connect(priv, SIGNAL(onlineStateChanged(bool)),
+ this, SIGNAL(onlineStateChanged(bool)));
+ connect(priv, SIGNAL(configurationChanged(QNetworkConfiguration)),
+ this, SIGNAL(configurationChanged(QNetworkConfiguration)));
+
+ priv->enablePolling();
+}
+
+/*!
+ Frees the resources associated with the QNetworkConfigurationManager object.
+*/
+QNetworkConfigurationManager::~QNetworkConfigurationManager()
+{
+ QNetworkConfigurationManagerPrivate *priv = connManager();
+
+ priv->disablePolling();
+}
+
+
+/*!
+ Returns the default configuration to be used. This function always returns a discovered
+ configuration; otherwise an invalid configuration.
+
+ In some cases it may be required to call updateConfigurations() and wait for the
+ updateCompleted() signal before calling this function.
+
+ \sa allConfigurations()
+*/
+QNetworkConfiguration QNetworkConfigurationManager::defaultConfiguration() const
+{
+ return connManager()->defaultConfiguration();
+}
+
+/*!
+ Returns the list of configurations which comply with the given \a filter.
+
+ By default this function returns all (defined and undefined) configurations.
+
+ A wireless network with a particular SSID may only be accessible in a
+ certain area despite the fact that the system has a valid configuration
+ for it. Therefore the filter flag may be used to limit the list to
+ discovered and possibly connected configurations only.
+
+ If \a filter is set to zero this function returns all possible configurations.
+
+ Note that this function returns the states for all configurations as they are known at
+ the time of this function call. If for instance a configuration of type WLAN is defined
+ the system may have to perform a WLAN scan in order to determine whether it is
+ actually available. To obtain the most accurate state updateConfigurations() should
+ be used to update each configuration's state. Note that such an update may require
+ some time. It's completion is signalled by updateCompleted(). In the absence of a
+ configuration update this function returns the best estimate at the time of the call.
+ Therefore, if WLAN configurations are of interest, it is recommended that
+ updateConfigurations() is called once after QNetworkConfigurationManager
+ instantiation (WLAN scans are too time consuming to perform in constructor).
+ After this the data is kept automatically up-to-date as the system reports
+ any changes.
+*/
+QList<QNetworkConfiguration> QNetworkConfigurationManager::allConfigurations(QNetworkConfiguration::StateFlags filter) const
+{
+ return connManager()->allConfigurations(filter);
+}
+
+/*!
+ Returns the QNetworkConfiguration for \a identifier; otherwise returns an
+ invalid QNetworkConfiguration.
+
+ \sa QNetworkConfiguration::identifier()
+*/
+QNetworkConfiguration QNetworkConfigurationManager::configurationFromIdentifier(const QString &identifier) const
+{
+ return connManager()->configurationFromIdentifier(identifier);
+}
+
+/*!
+ Returns true if the system is considered to be connected to another device via an active
+ network interface; otherwise returns false.
+
+ This is equivalent to the following code snippet:
+
+ \snippet doc/src/snippets/code/src_network_bearer_qnetworkconfigmanager.cpp 0
+
+ \sa onlineStateChanged()
+*/
+bool QNetworkConfigurationManager::isOnline() const
+{
+ return connManager()->isOnline();
+}
+
+/*!
+ Returns the capabilities supported by the current platform.
+*/
+QNetworkConfigurationManager::Capabilities QNetworkConfigurationManager::capabilities() const
+{
+ return connManager()->capFlags;
+}
+
+/*!
+ Initiates an update of all configurations. This may be used to initiate WLAN scans or other
+ time consuming updates which may be required to obtain the correct state for configurations.
+
+ This call is asynchronous. On completion of this update the updateCompleted() signal is
+ emitted. If new configurations are discovered or old ones were removed or changed the update
+ process may trigger the emission of one or multiple configurationAdded(),
+ configurationRemoved() and configurationChanged() signals.
+
+ If a configuration state changes as a result of this update all existing QNetworkConfiguration
+ instances are updated automatically.
+
+ \sa allConfigurations()
+*/
+void QNetworkConfigurationManager::updateConfigurations()
+{
+ connManager()->performAsyncConfigurationUpdate();
+}
+
+#include "moc_qnetworkconfigmanager.cpp"
+
+QT_END_NAMESPACE
+
diff --git a/src/network/bearer/qnetworkconfigmanager.h b/src/network/bearer/qnetworkconfigmanager.h
new file mode 100644
index 0000000..bb4d8a0
--- /dev/null
+++ b/src/network/bearer/qnetworkconfigmanager.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QNETWORKCONFIGURATIONMANAGER_H
+#define QNETWORKCONFIGURATIONMANAGER_H
+
+#include <QtCore/qobject.h>
+#include <QtNetwork/qnetworkconfiguration.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+class QNetworkConfigurationManagerPrivate;
+class Q_NETWORK_EXPORT QNetworkConfigurationManager : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ enum Capability {
+ CanStartAndStopInterfaces = 0x00000001,
+ DirectConnectionRouting = 0x00000002,
+ SystemSessionSupport = 0x00000004,
+ ApplicationLevelRoaming = 0x00000008,
+ ForcedRoaming = 0x00000010,
+ DataStatistics = 0x00000020,
+ NetworkSessionRequired = 0x00000040
+ };
+
+ Q_DECLARE_FLAGS(Capabilities, Capability)
+
+ QNetworkConfigurationManager( QObject* parent = 0 );
+ virtual ~QNetworkConfigurationManager();
+
+
+ QNetworkConfigurationManager::Capabilities capabilities() const;
+
+ QNetworkConfiguration defaultConfiguration() const;
+ QList<QNetworkConfiguration> allConfigurations(QNetworkConfiguration::StateFlags flags = 0) const;
+ QNetworkConfiguration configurationFromIdentifier(const QString& identifier) const;
+ void updateConfigurations();
+
+ bool isOnline() const;
+
+Q_SIGNALS:
+ void configurationAdded(const QNetworkConfiguration& config);
+ void configurationRemoved(const QNetworkConfiguration& config);
+ void configurationChanged(const QNetworkConfiguration& config);
+ void onlineStateChanged(bool isOnline);
+ void updateCompleted();
+
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QNetworkConfigurationManager::Capabilities)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif //QNETWORKCONFIGURATIONMANAGER_H
+
diff --git a/src/network/bearer/qnetworkconfigmanager_p.cpp b/src/network/bearer/qnetworkconfigmanager_p.cpp
new file mode 100644
index 0000000..c665fa2
--- /dev/null
+++ b/src/network/bearer/qnetworkconfigmanager_p.cpp
@@ -0,0 +1,495 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "qnetworkconfigmanager_p.h"
+#include "qbearerplugin_p.h"
+
+#include <QtCore/private/qfactoryloader_p.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qthread.h>
+#include <QtCore/private/qcoreapplication_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QBearerEngineFactoryInterface_iid, QLatin1String("/bearer")))
+
+QNetworkConfigurationManagerPrivate::QNetworkConfigurationManagerPrivate()
+: capFlags(0), mutex(QMutex::Recursive), pollTimer(0), forcedPolling(0), firstUpdate(true)
+{
+ qRegisterMetaType<QNetworkConfiguration>("QNetworkConfiguration");
+
+ moveToThread(QCoreApplicationPrivate::mainThread());
+ updateConfigurations();
+}
+
+QNetworkConfigurationManagerPrivate::~QNetworkConfigurationManagerPrivate()
+{
+ QMutexLocker locker(&mutex);
+
+ qDeleteAll(sessionEngines);
+}
+
+QNetworkConfiguration QNetworkConfigurationManagerPrivate::defaultConfiguration()
+{
+ QMutexLocker locker(&mutex);
+
+ foreach (QBearerEngine *engine, sessionEngines) {
+ QNetworkConfigurationPrivatePointer ptr = engine->defaultConfiguration();
+
+ if (ptr) {
+ QNetworkConfiguration config;
+ config.d = ptr;
+ return config;
+ }
+ }
+
+ // Engines don't have a default configuration.
+
+ // Return first active snap
+ QNetworkConfigurationPrivatePointer defaultConfiguration;
+
+ foreach (QBearerEngine *engine, sessionEngines) {
+ QHash<QString, QNetworkConfigurationPrivatePointer>::Iterator it;
+ QHash<QString, QNetworkConfigurationPrivatePointer>::Iterator end;
+
+ QMutexLocker locker(&engine->mutex);
+
+ for (it = engine->snapConfigurations.begin(), end = engine->snapConfigurations.end();
+ it != end; ++it) {
+ QNetworkConfigurationPrivatePointer ptr = it.value();
+
+ QMutexLocker configLocker(&ptr->mutex);
+
+ if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
+ QNetworkConfiguration config;
+ config.d = ptr;
+ return config;
+ } else if (!defaultConfiguration) {
+ if ((ptr->state & QNetworkConfiguration::Discovered) ==
+ QNetworkConfiguration::Discovered) {
+ defaultConfiguration = ptr;
+ }
+ }
+ }
+ }
+
+ // No Active SNAPs return first Discovered SNAP.
+ if (defaultConfiguration) {
+ QNetworkConfiguration config;
+ config.d = defaultConfiguration;
+ return config;
+ }
+
+ /*
+ No Active or Discovered SNAPs, find the perferred access point.
+ The following priority order is used:
+
+ 1. Active Ethernet
+ 2. Active WLAN
+ 3. Active Other
+ 4. Discovered Ethernet
+ 5. Discovered WLAN
+ 6. Discovered Other
+ */
+
+ defaultConfiguration.reset();
+
+ foreach (QBearerEngine *engine, sessionEngines) {
+ QHash<QString, QNetworkConfigurationPrivatePointer>::Iterator it;
+ QHash<QString, QNetworkConfigurationPrivatePointer>::Iterator end;
+
+ QMutexLocker locker(&engine->mutex);
+
+ for (it = engine->accessPointConfigurations.begin(),
+ end = engine->accessPointConfigurations.end(); it != end; ++it) {
+ QNetworkConfigurationPrivatePointer ptr = it.value();
+
+ const QString bearerName = ptr->bearerName();
+ QMutexLocker configLocker(&ptr->mutex);
+
+ if ((ptr->state & QNetworkConfiguration::Discovered) ==
+ QNetworkConfiguration::Discovered) {
+ if (!defaultConfiguration) {
+ defaultConfiguration = ptr;
+ } else {
+ if (defaultConfiguration->state == ptr->state) {
+ if (defaultConfiguration->bearerName() == QLatin1String("Ethernet")) {
+ // do nothing
+ } else if (defaultConfiguration->bearerName() == QLatin1String("WLAN")) {
+ // ethernet beats wlan
+ if (bearerName == QLatin1String("Ethernet"))
+ defaultConfiguration = ptr;
+ } else {
+ // ethernet and wlan beats other
+ if (bearerName == QLatin1String("Ethernet") ||
+ bearerName == QLatin1String("WLAN")) {
+ defaultConfiguration = ptr;
+ }
+ }
+ } else {
+ // active beats discovered
+ if ((defaultConfiguration->state & QNetworkConfiguration::Active) !=
+ QNetworkConfiguration::Active) {
+ defaultConfiguration = ptr;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // No Active InternetAccessPoint return first Discovered InternetAccessPoint.
+ if (defaultConfiguration) {
+ QNetworkConfiguration config;
+ config.d = defaultConfiguration;
+ return config;
+ }
+
+ return QNetworkConfiguration();
+}
+
+QList<QNetworkConfiguration> QNetworkConfigurationManagerPrivate::allConfigurations(QNetworkConfiguration::StateFlags filter)
+{
+ QList<QNetworkConfiguration> result;
+
+ QMutexLocker locker(&mutex);
+
+ foreach (QBearerEngine *engine, sessionEngines) {
+ QHash<QString, QNetworkConfigurationPrivatePointer>::Iterator it;
+ QHash<QString, QNetworkConfigurationPrivatePointer>::Iterator end;
+
+ QMutexLocker locker(&engine->mutex);
+
+ //find all InternetAccessPoints
+ for (it = engine->accessPointConfigurations.begin(),
+ end = engine->accessPointConfigurations.end(); it != end; ++it) {
+ QNetworkConfigurationPrivatePointer ptr = it.value();
+
+ QMutexLocker configLocker(&ptr->mutex);
+
+ if ((ptr->state & filter) == filter) {
+ QNetworkConfiguration pt;
+ pt.d = ptr;
+ result << pt;
+ }
+ }
+
+ //find all service networks
+ for (it = engine->snapConfigurations.begin(),
+ end = engine->snapConfigurations.end(); it != end; ++it) {
+ QNetworkConfigurationPrivatePointer ptr = it.value();
+
+ QMutexLocker configLocker(&ptr->mutex);
+
+ if ((ptr->state & filter) == filter) {
+ QNetworkConfiguration pt;
+ pt.d = ptr;
+ result << pt;
+ }
+ }
+ }
+
+ return result;
+}
+
+QNetworkConfiguration QNetworkConfigurationManagerPrivate::configurationFromIdentifier(const QString &identifier)
+{
+ QNetworkConfiguration item;
+
+ QMutexLocker locker(&mutex);
+
+ foreach (QBearerEngine *engine, sessionEngines) {
+ QMutexLocker locker(&engine->mutex);
+
+ if (engine->accessPointConfigurations.contains(identifier))
+ item.d = engine->accessPointConfigurations.value(identifier);
+ else if (engine->snapConfigurations.contains(identifier))
+ item.d = engine->snapConfigurations.value(identifier);
+ else if (engine->userChoiceConfigurations.contains(identifier))
+ item.d = engine->userChoiceConfigurations.value(identifier);
+ else
+ continue;
+
+ return item;
+ }
+
+ return item;
+}
+
+bool QNetworkConfigurationManagerPrivate::isOnline()
+{
+ QMutexLocker locker(&mutex);
+
+ return !onlineConfigurations.isEmpty();
+}
+
+void QNetworkConfigurationManagerPrivate::configurationAdded(QNetworkConfigurationPrivatePointer ptr)
+{
+ QMutexLocker locker(&mutex);
+
+ if (!firstUpdate) {
+ QNetworkConfiguration item;
+ item.d = ptr;
+ emit configurationAdded(item);
+ }
+
+ ptr->mutex.lock();
+ if (ptr->state == QNetworkConfiguration::Active) {
+ ptr->mutex.unlock();
+ onlineConfigurations.insert(ptr->id);
+ if (!firstUpdate && onlineConfigurations.count() == 1)
+ emit onlineStateChanged(true);
+ } else {
+ ptr->mutex.unlock();
+ }
+}
+
+void QNetworkConfigurationManagerPrivate::configurationRemoved(QNetworkConfigurationPrivatePointer ptr)
+{
+ QMutexLocker locker(&mutex);
+
+ ptr->mutex.lock();
+ ptr->isValid = false;
+ ptr->mutex.unlock();
+
+ if (!firstUpdate) {
+ QNetworkConfiguration item;
+ item.d = ptr;
+ emit configurationRemoved(item);
+ }
+
+ onlineConfigurations.remove(ptr->id);
+ if (!firstUpdate && onlineConfigurations.isEmpty())
+ emit onlineStateChanged(false);
+}
+
+void QNetworkConfigurationManagerPrivate::configurationChanged(QNetworkConfigurationPrivatePointer ptr)
+{
+ QMutexLocker locker(&mutex);
+
+ if (!firstUpdate) {
+ QNetworkConfiguration item;
+ item.d = ptr;
+ emit configurationChanged(item);
+ }
+
+ bool previous = !onlineConfigurations.isEmpty();
+
+ ptr->mutex.lock();
+ if (ptr->state == QNetworkConfiguration::Active)
+ onlineConfigurations.insert(ptr->id);
+ else
+ onlineConfigurations.remove(ptr->id);
+ ptr->mutex.unlock();
+
+ bool online = !onlineConfigurations.isEmpty();
+
+ if (!firstUpdate && online != previous)
+ emit onlineStateChanged(online);
+}
+
+void QNetworkConfigurationManagerPrivate::updateConfigurations()
+{
+ QMutexLocker locker(&mutex);
+
+ if (firstUpdate) {
+ if (sender())
+ return;
+
+ updating = false;
+
+ QFactoryLoader *l = loader();
+
+ QBearerEngine *generic = 0;
+
+ foreach (const QString &key, l->keys()) {
+ QBearerEnginePlugin *plugin = qobject_cast<QBearerEnginePlugin *>(l->instance(key));
+ if (plugin) {
+ QBearerEngine *engine = plugin->create(key);
+ if (!engine)
+ continue;
+
+ if (key == QLatin1String("generic"))
+ generic = engine;
+ else
+ sessionEngines.append(engine);
+
+ engine->moveToThread(QCoreApplicationPrivate::mainThread());
+
+ connect(engine, SIGNAL(updateCompleted()),
+ this, SLOT(updateConfigurations()));
+ connect(engine, SIGNAL(configurationAdded(QNetworkConfigurationPrivatePointer)),
+ this, SLOT(configurationAdded(QNetworkConfigurationPrivatePointer)));
+ connect(engine, SIGNAL(configurationRemoved(QNetworkConfigurationPrivatePointer)),
+ this, SLOT(configurationRemoved(QNetworkConfigurationPrivatePointer)));
+ connect(engine, SIGNAL(configurationChanged(QNetworkConfigurationPrivatePointer)),
+ this, SLOT(configurationChanged(QNetworkConfigurationPrivatePointer)));
+
+ capFlags |= engine->capabilities();
+
+ QMetaObject::invokeMethod(engine, "requestUpdate");
+ }
+ }
+
+ if (generic)
+ sessionEngines.append(generic);
+ }
+
+ QBearerEngine *engine = qobject_cast<QBearerEngine *>(sender());
+ if (!updatingEngines.isEmpty() && engine) {
+ int index = sessionEngines.indexOf(engine);
+ if (index >= 0)
+ updatingEngines.remove(index);
+ }
+
+ if (updating && updatingEngines.isEmpty()) {
+ updating = false;
+ emit configurationUpdateComplete();
+ }
+
+ if (engine && !pollingEngines.isEmpty()) {
+ int index = sessionEngines.indexOf(engine);
+ if (index >= 0)
+ pollingEngines.remove(index);
+
+ if (pollingEngines.isEmpty())
+ startPolling();
+ }
+
+ if (firstUpdate)
+ firstUpdate = false;
+}
+
+void QNetworkConfigurationManagerPrivate::performAsyncConfigurationUpdate()
+{
+ QMutexLocker locker(&mutex);
+
+ if (sessionEngines.isEmpty()) {
+ emit configurationUpdateComplete();
+ return;
+ }
+
+ updating = true;
+
+ for (int i = 0; i < sessionEngines.count(); ++i) {
+ updatingEngines.insert(i);
+ QMetaObject::invokeMethod(sessionEngines.at(i), "requestUpdate");
+ }
+}
+
+QList<QBearerEngine *> QNetworkConfigurationManagerPrivate::engines()
+{
+ QMutexLocker locker(&mutex);
+
+ return sessionEngines;
+}
+
+void QNetworkConfigurationManagerPrivate::startPolling()
+{
+ QMutexLocker locker(&mutex);
+
+ bool pollingRequired = false;
+
+ if (forcedPolling > 0) {
+ foreach (QBearerEngine *engine, sessionEngines) {
+ if (engine->requiresPolling()) {
+ pollingRequired = true;
+ break;
+ }
+ }
+ }
+
+ if (!pollingRequired) {
+ foreach (QBearerEngine *engine, sessionEngines) {
+ if (engine->configurationsInUse()) {
+ pollingRequired = true;
+ break;
+ }
+ }
+ }
+
+ if (pollingRequired) {
+ if (!pollTimer) {
+ pollTimer = new QTimer(this);
+ pollTimer->setInterval(10000);
+ pollTimer->setSingleShot(true);
+ connect(pollTimer, SIGNAL(timeout()), this, SLOT(pollEngines()));
+ }
+
+ pollTimer->start();
+ }
+}
+
+void QNetworkConfigurationManagerPrivate::pollEngines()
+{
+ QMutexLocker locker(&mutex);
+
+ for (int i = 0; i < sessionEngines.count(); ++i) {
+ if ((forcedPolling && sessionEngines.at(i)->requiresPolling()) ||
+ sessionEngines.at(i)->configurationsInUse()) {
+ pollingEngines.insert(i);
+ QMetaObject::invokeMethod(sessionEngines.at(i), "requestUpdate");
+ }
+ }
+}
+
+void QNetworkConfigurationManagerPrivate::enablePolling()
+{
+ QMutexLocker locker(&mutex);
+
+ ++forcedPolling;
+
+ if (forcedPolling == 1)
+ QMetaObject::invokeMethod(this, "startPolling");
+}
+
+void QNetworkConfigurationManagerPrivate::disablePolling()
+{
+ QMutexLocker locker(&mutex);
+
+ --forcedPolling;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/bearer/qnetworkconfigmanager_p.h b/src/network/bearer/qnetworkconfigmanager_p.h
new file mode 100644
index 0000000..dba9d2c
--- /dev/null
+++ b/src/network/bearer/qnetworkconfigmanager_p.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QNETWORKCONFIGURATIONMANAGERPRIVATE_H
+#define QNETWORKCONFIGURATIONMANAGERPRIVATE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qnetworkconfigmanager.h"
+#include "qnetworkconfiguration_p.h"
+
+#include <QtCore/qmutex.h>
+#include <QtCore/qset.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBearerEngine;
+class QTimer;
+
+class Q_NETWORK_EXPORT QNetworkConfigurationManagerPrivate : public QObject
+{
+ Q_OBJECT
+
+public:
+ QNetworkConfigurationManagerPrivate();
+ virtual ~QNetworkConfigurationManagerPrivate();
+
+ QNetworkConfiguration defaultConfiguration();
+ QList<QNetworkConfiguration> allConfigurations(QNetworkConfiguration::StateFlags filter);
+ QNetworkConfiguration configurationFromIdentifier(const QString &identifier);
+
+ bool isOnline();
+
+ QNetworkConfigurationManager::Capabilities capFlags;
+
+ void performAsyncConfigurationUpdate();
+
+ QList<QBearerEngine *> engines();
+
+ Q_INVOKABLE void startPolling();
+
+ void enablePolling();
+ void disablePolling();
+
+public slots:
+ void updateConfigurations();
+
+Q_SIGNALS:
+ void configurationAdded(const QNetworkConfiguration& config);
+ void configurationRemoved(const QNetworkConfiguration& config);
+ void configurationUpdateComplete();
+ void configurationChanged(const QNetworkConfiguration& config);
+ void onlineStateChanged(bool isOnline);
+
+ void abort();
+
+private:
+ QMutex mutex;
+
+ QTimer *pollTimer;
+
+ QList<QBearerEngine *> sessionEngines;
+
+ QSet<QString> onlineConfigurations;
+
+ QSet<int> updatingEngines;
+ bool updating;
+
+ QSet<int> pollingEngines;
+ int forcedPolling;
+
+ bool firstUpdate;
+
+private Q_SLOTS:
+ void configurationAdded(QNetworkConfigurationPrivatePointer ptr);
+ void configurationRemoved(QNetworkConfigurationPrivatePointer ptr);
+ void configurationChanged(QNetworkConfigurationPrivatePointer ptr);
+
+ void pollEngines();
+};
+
+Q_NETWORK_EXPORT QNetworkConfigurationManagerPrivate *qNetworkConfigurationManagerPrivate();
+
+QT_END_NAMESPACE
+
+#endif //QNETWORKCONFIGURATIONMANAGERPRIVATE_H
diff --git a/src/network/bearer/qnetworkconfiguration.cpp b/src/network/bearer/qnetworkconfiguration.cpp
new file mode 100644
index 0000000..4108fee
--- /dev/null
+++ b/src/network/bearer/qnetworkconfiguration.cpp
@@ -0,0 +1,433 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "qnetworkconfiguration.h"
+#include "qnetworkconfiguration_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QNetworkConfiguration
+
+ \brief The QNetworkConfiguration class provides an abstraction of one or more access point configurations.
+
+ \since 4.7
+
+ \inmodule QtNetwork
+ \ingroup network
+
+ QNetworkConfiguration encapsulates a single access point or service network.
+ In most cases a single access point configuration can be mapped to one network
+ interface. However a single network interface may not always map to only one
+ access point configuration. Multiple configurations for the same
+ network device may enable multiple access points. An example
+ device that could exhibit such a configuration might be a
+ Smartphone which allows the user to manage multiple WLAN
+ configurations while the device itself has only one WLAN network device.
+
+ The QNetworkConfiguration also supports the concept of service networks.
+ This concept allows the grouping of multiple access point configurations
+ into one entity. Such a group is called service network and can be
+ beneficial in cases whereby a network session to a
+ particular destination network is required (e.g. a company network).
+ When using a service network the user doesn't usually care which one of the
+ connectivity options is chosen (e.g. corporate WLAN or VPN via GPRS)
+ as long as he can reach the company's target server. Depending
+ on the current position and time some of the access points that make
+ up the service network may not even be available. Furthermore
+ automated access point roaming can be enabled which enables the device
+ to change the network interface configuration dynamically while maintaining
+ the applications connection to the target network. It allows adaption
+ to the changing environment and may enable optimization with regards to
+ cost, speed or other network parameters.
+
+ Special configurations of type UserChoice provide a placeholder configuration which is
+ resolved to an actual network configuration by the platform when a
+ \l {QNetworkSession}{session} is \l {QNetworkSession::open()}{opened}. Not all platforms
+ support the concept of a user choice configuration.
+
+ \section1 Configuration states
+
+ The list of available configurations can be obtained via
+ QNetworkConfigurationManager::allConfigurations(). A configuration can have
+ multiple states. The \l Defined configuration state indicates that the configuration
+ is stored on the device. However the configuration is not yet ready to be activated
+ as e.g. a WLAN may not be available at the current time.
+
+ The \l Discovered state implies that the configuration is \l Defined and
+ the outside conditions are such that the configuration can be used immediately
+ to open a new network session. An example of such an outside condition may be
+ that the Ethernet cable is actually connected to the device or that the WLAN
+ with the specified SSID is in range.
+
+ The \l Active state implies that the configuration is \l Discovered. A configuration
+ in this state is currently being used by an application. The underlying network
+ interface has a valid IP configuration and can transfer IP packets between the
+ device and the target network.
+
+ The \l Undefined state indicates that the system has knowledge of possible target
+ networks but cannot actually use that knowledge to connect to it. An example
+ for such a state could be an encrypted WLAN that has been discovered
+ but the user hasn't actually saved a configuration including the required password
+ which would allow the device to connect to it.
+
+ Depending on the type of configuration some states are transient in nature. A GPRS/UMTS
+ connection may almost always be \l Discovered if the GSM/UMTS network is available.
+ However if the GSM/UMTS network looses the connection the associated configuration may change its state
+ from \l Discovered to \l Defined as well. A similar use case might be triggered by
+ WLAN availability. QNetworkConfigurationManager::updateConfigurations() can be used to
+ manually trigger updates of states. Note that some platforms do not require such updates
+ as they implicitly change the state once it has been discovered. If the state of a
+ configuration changes all related QNetworkConfiguration instances change their state automatically.
+
+ \sa QNetworkSession, QNetworkConfigurationManager
+*/
+
+/*!
+ \enum QNetworkConfiguration::Type
+
+ This enum describes the type of configuration.
+
+ \value InternetAccessPoint The configuration specifies the details for a single access point.
+ Note that configurations of type InternetAccessPoint may be part
+ of other QNetworkConfigurations of type ServiceNetwork.
+ \value ServiceNetwork The configuration is based on a group of QNetworkConfigurations of
+ type InternetAccessPoint. All group members can reach the same
+ target network. This type of configuration is a mandatory
+ requirement for roaming enabled network sessions. On some
+ platforms this form of configuration may also be called Service
+ Network Access Point (SNAP).
+ \value UserChoice The configuration is a placeholder which will be resolved to an
+ actual configuration by the platform when a session is opened. Depending
+ on the platform the selection may generate a popup dialog asking the user
+ for his preferred choice.
+ \value Invalid The configuration is invalid.
+*/
+
+/*!
+ \enum QNetworkConfiguration::StateFlag
+
+ Specifies the configuration states.
+
+ \value Undefined This state is used for transient configurations such as newly discovered
+ WLANs for which the user has not actually created a configuration yet.
+ \value Defined Defined configurations are known to the system but are not immediately
+ usable (e.g. a configured WLAN is not within range or the Ethernet cable
+ is currently not plugged into the machine).
+ \value Discovered A discovered configuration can be immediately used to create a new
+ QNetworkSession. An example of a discovered configuration could be a WLAN
+ which is within in range. If the device moves out of range the discovered
+ flag is dropped. A second example is a GPRS configuration which generally
+ remains discovered for as long as the device has network coverage. A
+ configuration that has this state is also in state
+ QNetworkConfiguration::Defined. If the configuration is a service network
+ this flag is set if at least one of the underlying access points
+ configurations has the Discovered state.
+ \value Active The configuration is currently used by an open network session
+ (see \l QNetworkSession::isOpen()). However this does not mean that the
+ current process is the entity that created the open session. It merely
+ indicates that if a new QNetworkSession were to be constructed based on
+ this configuration \l QNetworkSession::state() would return
+ \l QNetworkSession::Connected. This state implies the
+ QNetworkConfiguration::Discovered state.
+*/
+
+/*!
+ \enum QNetworkConfiguration::Purpose
+
+ Specifies the purpose of the configuration.
+
+ \value UnknownPurpose The configuration doesn't specify any purpose. This is the default value.
+ \value PublicPurpose The configuration can be used for general purpose internet access.
+ \value PrivatePurpose The configuration is suitable to access a private network such as an office Intranet.
+ \value ServiceSpecificPurpose The configuration can be used for operator specific services (e.g.
+ receiving MMS messages or content streaming).
+*/
+
+/*!
+ Constructs an invalid configuration object.
+
+ \sa isValid()
+*/
+QNetworkConfiguration::QNetworkConfiguration()
+ : d(0)
+{
+}
+
+/*!
+ Creates a copy of the QNetworkConfiguration object contained in \a other.
+*/
+QNetworkConfiguration::QNetworkConfiguration(const QNetworkConfiguration& other)
+ : d(other.d)
+{
+}
+
+/*!
+ Copies the content of the QNetworkConfiguration object contained in \a other into this one.
+*/
+QNetworkConfiguration& QNetworkConfiguration::operator=(const QNetworkConfiguration& other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Frees the resources associated with the QNetworkConfiguration object.
+*/
+QNetworkConfiguration::~QNetworkConfiguration()
+{
+}
+
+/*!
+ Returns true, if this configuration is the same as the \a other
+ configuration given; otherwise returns false.
+*/
+bool QNetworkConfiguration::operator==(const QNetworkConfiguration& other) const
+{
+ if (!d)
+ return !other.d;
+
+ if (!other.d)
+ return false;
+
+ return (d == other.d);
+}
+
+/*!
+ \fn bool QNetworkConfiguration::operator!=(const QNetworkConfiguration& other) const
+
+ Returns true if this configuration is not the same as the \a other
+ configuration given; otherwise returns false.
+*/
+
+/*!
+ Returns the user visible name of this configuration.
+
+ The name may either be the name of the underlying access point or the
+ name for service network that this configuration represents.
+*/
+QString QNetworkConfiguration::name() const
+{
+ if (!d)
+ return QString();
+
+ QMutexLocker locker(&d->mutex);
+ return d->name;
+}
+
+/*!
+ Returns the unique and platform specific identifier for this network configuration;
+ otherwise an empty string.
+*/
+QString QNetworkConfiguration::identifier() const
+{
+ if (!d)
+ return QString();
+
+ QMutexLocker locker(&d->mutex);
+ return d->id;
+}
+
+/*!
+ Returns the type of the configuration.
+
+ A configuration can represent a single access point configuration or
+ a set of access point configurations. Such a set is called service network.
+ A configuration that is based on a service network can potentially support
+ roaming of network sessions.
+*/
+QNetworkConfiguration::Type QNetworkConfiguration::type() const
+{
+ if (!d)
+ return QNetworkConfiguration::Invalid;
+
+ QMutexLocker locker(&d->mutex);
+ return d->type;
+}
+
+/*!
+ Returns true if this QNetworkConfiguration object is valid.
+ A configuration may become invalid if the user deletes the configuration or
+ the configuration was default-constructed.
+
+ The addition and removal of configurations can be monitored via the
+ QNetworkConfigurationManager.
+
+ \sa QNetworkConfigurationManager
+*/
+bool QNetworkConfiguration::isValid() const
+{
+ if (!d)
+ return false;
+
+ QMutexLocker locker(&d->mutex);
+ return d->isValid;
+}
+
+/*!
+ Returns the current state of the configuration.
+*/
+QNetworkConfiguration::StateFlags QNetworkConfiguration::state() const
+{
+ if (!d)
+ return QNetworkConfiguration::Undefined;
+
+ QMutexLocker locker(&d->mutex);
+ return d->state;
+}
+
+/*!
+ Returns the purpose of this configuration.
+
+ The purpose field may be used to programmatically determine the
+ purpose of a configuration. Such information is usually part of the
+ access point or service network meta data.
+*/
+QNetworkConfiguration::Purpose QNetworkConfiguration::purpose() const
+{
+ if (!d)
+ return QNetworkConfiguration::UnknownPurpose;
+
+ QMutexLocker locker(&d->mutex);
+ return d->purpose;
+}
+
+/*!
+ Returns true if this configuration supports roaming; otherwise false.
+*/
+bool QNetworkConfiguration::isRoamingAvailable() const
+{
+ if (!d)
+ return false;
+
+ QMutexLocker locker(&d->mutex);
+ return d->roamingSupported;
+}
+
+/*!
+ Returns all sub configurations of this network configuration.
+ Only network configurations of type \l ServiceNetwork can have children. Otherwise
+ this function returns an empty list.
+*/
+QList<QNetworkConfiguration> QNetworkConfiguration::children() const
+{
+ QList<QNetworkConfiguration> results;
+
+ if (type() != QNetworkConfiguration::ServiceNetwork || !isValid())
+ return results;
+
+ QMutexLocker locker(&d->mutex);
+
+ QMutableListIterator<QNetworkConfigurationPrivatePointer> iter(d->serviceNetworkMembers);
+ while (iter.hasNext()) {
+ QNetworkConfigurationPrivatePointer p = iter.next();
+
+ //if we have an invalid member get rid of it -> was deleted earlier on
+ {
+ QMutexLocker childLocker(&p->mutex);
+
+ if (!p->isValid) {
+ iter.remove();
+ continue;
+ }
+ }
+
+ QNetworkConfiguration item;
+ item.d = p;
+ results << item;
+ }
+
+ return results;
+}
+
+/*!
+ Returns the type of bearer. The string is not translated and
+ therefore can not be shown to the user. The subsequent table presents the currently known
+ bearer types:
+
+ \table
+ \header
+ \o Value
+ \o Description
+ \row
+ \o Unknown
+ \o The session is based on an unknown or unspecified bearer type.
+ \row
+ \o Ethernet
+ \o The session is based on Ethernet.
+ \row
+ \o WLAN
+ \o The session is based on Wireless LAN.
+ \row
+ \o 2G
+ \o The session uses CSD, GPRS, HSCSD, EDGE or cdmaOne.
+ \row
+ \o CDMA2000
+ \o The session uses CDMA.
+ \row
+ \o WCDMA
+ \o The session uses W-CDMA/UMTS.
+ \row
+ \o HSPA
+ \o The session uses High Speed Packet Access.
+ \row
+ \o Bluetooth
+ \o The session uses Bluetooth.
+ \row
+ \o WiMAX
+ \o The session uses WiMAX.
+ \endtable
+
+ This function returns an empty string if this is an invalid configuration,
+ a network configuration of type \l QNetworkConfiguration::ServiceNetwork or
+ \l QNetworkConfiguration::UserChoice.
+*/
+QString QNetworkConfiguration::bearerName() const
+{
+ if (!isValid())
+ return QString();
+
+ return d->bearerName();
+}
+
+
+QT_END_NAMESPACE
+
diff --git a/src/network/bearer/qnetworkconfiguration.h b/src/network/bearer/qnetworkconfiguration.h
new file mode 100644
index 0000000..dad6198
--- /dev/null
+++ b/src/network/bearer/qnetworkconfiguration.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QNETWORKCONFIGURATION_H
+#define QNETWORKCONFIGURATION_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qlist.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+class QNetworkConfigurationPrivate;
+class Q_NETWORK_EXPORT QNetworkConfiguration
+{
+public:
+ QNetworkConfiguration();
+ QNetworkConfiguration(const QNetworkConfiguration& other);
+ QNetworkConfiguration &operator=(const QNetworkConfiguration& other);
+ ~QNetworkConfiguration();
+
+ bool operator==(const QNetworkConfiguration& cp) const;
+ inline bool operator!=(const QNetworkConfiguration& cp) const
+ { return !operator==(cp); }
+
+ enum Type {
+ InternetAccessPoint = 0,
+ ServiceNetwork,
+ UserChoice,
+ Invalid
+ };
+
+ enum Purpose {
+ UnknownPurpose = 0,
+ PublicPurpose,
+ PrivatePurpose,
+ ServiceSpecificPurpose
+ };
+
+ enum StateFlag {
+ Undefined = 0x0000001,
+ Defined = 0x0000002,
+ Discovered = 0x0000006,
+ Active = 0x000000e
+ };
+
+ Q_DECLARE_FLAGS(StateFlags, StateFlag)
+
+ StateFlags state() const;
+ Type type() const;
+ Purpose purpose() const;
+ QString bearerName() const;
+ QString identifier() const;
+ bool isRoamingAvailable() const;
+ QList<QNetworkConfiguration> children() const;
+
+ QString name() const;
+ bool isValid() const;
+
+private:
+ friend class QNetworkConfigurationPrivate;
+ friend class QNetworkConfigurationManager;
+ friend class QNetworkConfigurationManagerPrivate;
+ friend class QNetworkSessionPrivate;
+ QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif //QNETWORKCONFIGURATION_H
diff --git a/src/network/bearer/qnetworkconfiguration_p.h b/src/network/bearer/qnetworkconfiguration_p.h
new file mode 100644
index 0000000..ccbe670
--- /dev/null
+++ b/src/network/bearer/qnetworkconfiguration_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QNETWORKCONFIGURATIONPRIVATE_H
+#define QNETWORKCONFIGURATIONPRIVATE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qnetworkconfiguration.h"
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+typedef QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> QNetworkConfigurationPrivatePointer;
+class QNetworkConfigurationPrivate : public QSharedData
+{
+public:
+ QNetworkConfigurationPrivate ()
+ : mutex(QMutex::Recursive), type(QNetworkConfiguration::Invalid),
+ purpose(QNetworkConfiguration::UnknownPurpose),
+ isValid(false), roamingSupported(false)
+ {
+ }
+
+ virtual ~QNetworkConfigurationPrivate()
+ {
+ //release pointers to member configurations
+ serviceNetworkMembers.clear();
+ }
+
+ virtual QString bearerName() const
+ {
+ QMutexLocker locker(&mutex);
+
+ return bearer;
+ }
+
+ mutable QMutex mutex;
+
+ QString bearer;
+ QString name;
+ QString id;
+
+ QNetworkConfiguration::StateFlags state;
+ QNetworkConfiguration::Type type;
+ QNetworkConfiguration::Purpose purpose;
+
+ QList<QNetworkConfigurationPrivatePointer> serviceNetworkMembers;
+
+ bool isValid;
+ bool roamingSupported;
+
+private:
+ // disallow detaching
+ QNetworkConfigurationPrivate &operator=(const QNetworkConfigurationPrivate &other);
+ QNetworkConfigurationPrivate(const QNetworkConfigurationPrivate &other);
+};
+
+QT_END_NAMESPACE
+
+#endif //QNETWORKCONFIGURATIONPRIVATE_H
diff --git a/src/network/bearer/qnetworksession.cpp b/src/network/bearer/qnetworksession.cpp
new file mode 100644
index 0000000..1bba56f
--- /dev/null
+++ b/src/network/bearer/qnetworksession.cpp
@@ -0,0 +1,704 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include <QEventLoop>
+#include <QTimer>
+
+#include "qnetworksession.h"
+#include "qbearerengine_p.h"
+#include "qnetworkconfigmanager_p.h"
+#include "qnetworksession_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QNetworkSession
+
+ \brief The QNetworkSession class provides control over the system's access points
+ and enables session management for cases when multiple clients access the same access point.
+
+ \since 4.7
+
+ \inmodule QtNetwork
+ \ingroup network
+
+ A QNetworkSession enables control over the system's network interfaces. The session's configuration
+ parameter are determined via the QNetworkConfiguration object to which it is bound. Depending on the
+ type of the session (single access point or service network) a session may be linked to one or more
+ network interfaces. By means of \l{open()}{opening} and \l{close()}{closing} of network sessions
+ a developer can start and stop the systems network interfaces. If the configuration represents
+ multiple access points (see \l QNetworkConfiguration::ServiceNetwork) more advanced features such as roaming may be supported.
+
+ QNetworkSession supports session management within the same process and depending on the platform's
+ capabilities may support out-of-process sessions. If the same
+ network configuration is used by multiple open sessions the underlying network interface is only terminated once
+ the last session has been closed.
+
+ \section1 Roaming
+
+ Applications may connect to the preferredConfigurationChanged() signal in order to
+ receive notifications when a more suitable access point becomes available.
+ In response to this signal the application must either initiate the roaming via migrate()
+ or ignore() the new access point. Once the session has roamed the
+ newConfigurationActivated() signal is emitted. The application may now test the
+ carrier and must either accept() or reject() it. The session will return to the previous
+ access point if the roaming was rejected. The subsequent state diagram depicts the required
+ state transitions.
+
+ \image roaming-states.png
+
+ Some platforms may distinguish forced roaming and application level roaming (ALR).
+ ALR implies that the application controls (via migrate(), ignore(), accept() and reject())
+ whether a network session can roam from one access point to the next. Such control is useful
+ if the application maintains stateful socket connections and wants to control the transition from
+ one interface to the next. Forced roaming implies that the system automatically roams to the next network without
+ consulting the application. This has the advantage that the application can make use of roaming features
+ without actually being aware of it. It is expected that the application detects that the underlying
+ socket is broken and automatically reconnects via the new network link.
+
+ If the platform supports both modes of roaming, an application indicates its preference
+ by connecting to the preferredConfigurationChanged() signal. Connecting to this signal means that
+ the application wants to take control over the roaming behavior and therefore implies application
+ level roaming. If the client does not connect to the preferredConfigurationChanged(), forced roaming
+ is used. If forced roaming is not supported the network session will not roam by default.
+
+ Some applications may want to suppress any form of roaming altogether. Possible use cases may be
+ high priority downloads or remote services which cannot handle a roaming enabled client. Clients
+ can suppress roaming by connecting to the preferredConfigurationChanged() signal and answer each
+ signal emission with ignore().
+
+ \sa QNetworkConfiguration, QNetworkConfigurationManager
+*/
+
+/*!
+ \enum QNetworkSession::State
+
+ This enum describes the connectivity state of the session. If the session is based on a
+ single access point configuration the state of the session is the same as the state of the
+ associated network interface.
+
+ \value Invalid The session is invalid due to an invalid configuration. This may
+ happen due to a removed access point or a configuration that was
+ invalid to begin with.
+ \value NotAvailable The session is based on a defined but not yet discovered QNetworkConfiguration
+ (see \l QNetworkConfiguration::StateFlag).
+ \value Connecting The network session is being established.
+ \value Connected The network session is connected. If the current process wishes to use this session
+ it has to register its interest by calling open(). A network session
+ is considered to be ready for socket operations if it isOpen() and connected.
+ \value Closing The network session is in the process of being shut down.
+ \value Disconnected The network session is not connected. The associated QNetworkConfiguration
+ has the state QNetworkConfiguration::Discovered.
+ \value Roaming The network session is roaming from one access point to another
+ access point.
+*/
+
+/*!
+ \enum QNetworkSession::SessionError
+
+ This enum describes the session errors that can occur.
+
+ \value UnknownSessionError An unidentified error occurred.
+ \value SessionAbortedError The session was aborted by the user or system.
+ \value RoamingError The session cannot roam to a new configuration.
+ \value OperationNotSupportedError The operation is not supported for current configuration.
+ \value InvalidConfigurationError The operation cannot currently be performed for the
+ current configuration.
+*/
+
+/*!
+ \fn void QNetworkSession::stateChanged(QNetworkSession::State state)
+
+ This signal is emitted whenever the state of the network session changes.
+ The \a state parameter is the new state.
+
+ \sa state()
+*/
+
+/*!
+ \fn void QNetworkSession::error(QNetworkSession::SessionError error)
+
+ This signal is emitted after an error occurred. The \a error parameter
+ describes the error that occurred.
+
+ \sa error(), errorString()
+*/
+
+/*!
+ \fn void QNetworkSession::preferredConfigurationChanged(const QNetworkConfiguration& config, bool isSeamless)
+
+ This signal is emitted when the preferred configuration/access point for the
+ session changes. Only sessions which are based on service network configurations
+ may emit this signal. \a config can be used to determine access point specific
+ details such as proxy settings and \a isSeamless indicates whether roaming will
+ break the sessions IP address.
+
+ As a consequence to this signal the application must either start the roaming process
+ by calling migrate() or choose to ignore() the new access point.
+
+ If the roaming process is non-seamless the IP address will change which means that
+ a socket becomes invalid. However seamless mobility can ensure that the local IP address
+ does not change. This is achieved by using a virtual IP address which is bound to the actual
+ link address. During the roaming process the virtual address is attached to the new link
+ address.
+
+ Some platforms may support the concept of Forced Roaming and Application Level Roaming (ALR).
+ Forced roaming implies that the platform may simply roam to a new configuration without
+ consulting applications. It is up to the application to detect the link layer loss and reestablish
+ its sockets. In contrast ALR provides the opportunity to prevent the system from roaming.
+ If this session is based on a configuration that supports roaming the application can choose
+ whether it wants to be consulted (ALR use case) by connecting to this signal. For as long as this signal
+ connection remains the session remains registered as a roaming stakeholder; otherwise roaming will
+ be enforced by the platform.
+
+ \sa migrate(), ignore(), QNetworkConfiguration::isRoamingAvailable()
+*/
+
+/*!
+ \fn void QNetworkSession::newConfigurationActivated()
+
+ This signal is emitted once the session has roamed to the new access point.
+ The application may reopen its socket and test the suitability of the new network link.
+ Subsequently it must either accept() or reject() the new access point.
+
+ \sa accept(), reject()
+*/
+
+/*!
+ \fn void QNetworkSession::opened()
+
+ This signal is emitted when the network session has been opened.
+
+ The underlying network interface will not be shut down as long as the session remains open.
+ Note that this feature is dependent on \l{QNetworkConfigurationManager::SystemSessionSupport}{system wide session support}.
+*/
+
+/*!
+ \fn void QNetworkSession::closed()
+
+ This signal is emitted when the network session has been closed.
+*/
+
+/*!
+ Constructs a session based on \a connectionConfig with the given \a parent.
+
+ \sa QNetworkConfiguration
+*/
+QNetworkSession::QNetworkSession(const QNetworkConfiguration& connectionConfig, QObject* parent)
+: QObject(parent), d(0)
+{
+ foreach (QBearerEngine *engine, qNetworkConfigurationManagerPrivate()->engines()) {
+ if (engine->hasIdentifier(connectionConfig.identifier())) {
+ d = engine->createSessionBackend();
+ d->q = this;
+ d->publicConfig = connectionConfig;
+ d->syncStateWithInterface();
+ connect(d, SIGNAL(quitPendingWaitsForOpened()), this, SIGNAL(opened()));
+ connect(d, SIGNAL(error(QNetworkSession::SessionError)),
+ this, SIGNAL(error(QNetworkSession::SessionError)));
+ connect(d, SIGNAL(stateChanged(QNetworkSession::State)),
+ this, SIGNAL(stateChanged(QNetworkSession::State)));
+ connect(d, SIGNAL(closed()), this, SIGNAL(closed()));
+ connect(d, SIGNAL(preferredConfigurationChanged(QNetworkConfiguration,bool)),
+ this, SIGNAL(preferredConfigurationChanged(QNetworkConfiguration,bool)));
+ connect(d, SIGNAL(newConfigurationActivated()),
+ this, SIGNAL(newConfigurationActivated()));
+ break;
+ }
+ }
+}
+
+/*!
+ Frees the resources associated with the QNetworkSession object.
+*/
+QNetworkSession::~QNetworkSession()
+{
+ delete d;
+}
+
+/*!
+ Creates an open session which increases the session counter on the underlying network interface.
+ The system will not terminate a network interface until the session reference counter reaches zero.
+ Therefore an open session allows an application to register its use of the interface.
+
+ As a result of calling open() the interface will be started if it is not connected/up yet.
+ Some platforms may not provide support for out-of-process sessions. On such platforms the session
+ counter ignores any sessions held by another process. The platform capabilities can be
+ detected via QNetworkConfigurationManager::capabilities().
+
+ Note that this call is asynchronous. Depending on the outcome of this call the results can be enquired
+ by connecting to the stateChanged(), opened() or error() signals.
+
+ It is not a requirement to open a session in order to monitor the underlying network interface.
+
+ \sa close(), stop(), isOpen()
+*/
+void QNetworkSession::open()
+{
+ if (d)
+ d->open();
+ else
+ emit error(InvalidConfigurationError);
+}
+
+/*!
+ Waits until the session has been opened, up to \a msecs milliseconds. If the session has been opened, this
+ function returns true; otherwise it returns false. In the case where it returns false, you can call error()
+ to determine the cause of the error.
+
+ The following example waits up to one second for the session to be opened:
+
+ \code
+ session->open();
+ if (session->waitForOpened(1000))
+ qDebug("Open!");
+ \endcode
+
+ If \a msecs is -1, this function will not time out.
+
+ \sa open(), error()
+*/
+bool QNetworkSession::waitForOpened(int msecs)
+{
+ if (!d)
+ return false;
+
+ if (d->isOpen)
+ return true;
+
+ if (d->state != Connecting)
+ return false;
+
+ QEventLoop* loop = new QEventLoop(this);
+ QObject::connect(d, SIGNAL(quitPendingWaitsForOpened()),
+ loop, SLOT(quit()));
+ QObject::connect(this, SIGNAL(error(QNetworkSession::SessionError)),
+ loop, SLOT(quit()));
+
+ //final call
+ if (msecs>=0)
+ QTimer::singleShot(msecs, loop, SLOT(quit()));
+
+ loop->exec();
+ loop->disconnect();
+ loop->deleteLater();
+
+ return d->isOpen;
+}
+
+/*!
+ Decreases the session counter on the associated network configuration. If the session counter reaches zero
+ the active network interface is shut down. This also means that state() will only change from \l Connected to
+ \l Disconnected if the current session was the last open session.
+
+ If the platform does not support out-of-process sessions calling this function does not stop the
+ interface. In this case \l{stop()} has to be used to force a shut down.
+ The platform capabilities can be detected via QNetworkConfigurationManager::capabilities().
+
+ Note that this call is asynchronous. Depending on the outcome of this call the results can be enquired
+ by connecting to the stateChanged(), opened() or error() signals.
+
+ \sa open(), stop(), isOpen()
+*/
+void QNetworkSession::close()
+{
+ if (d)
+ d->close();
+}
+
+/*!
+ Invalidates all open sessions against the network interface and therefore stops the
+ underlying network interface. This function always changes the session's state() flag to
+ \l Disconnected.
+
+ On Symbian platform, a 'NetworkControl' capability is required for
+ full interface-level stop (without the capability, only the current session is stopped).
+
+ \sa open(), close()
+*/
+void QNetworkSession::stop()
+{
+ if (d)
+ d->stop();
+}
+
+/*!
+ Returns the QNetworkConfiguration that this network session object is based on.
+
+ \sa QNetworkConfiguration
+*/
+QNetworkConfiguration QNetworkSession::configuration() const
+{
+ return d ? d->publicConfig : QNetworkConfiguration();
+}
+
+#ifndef QT_NO_NETWORKINTERFACE
+/*!
+ Returns the network interface that is used by this session.
+
+ This function only returns a valid QNetworkInterface when this session is \l Connected.
+
+ The returned interface may change as a result of a roaming process.
+
+ Note: this function does not work in Symbian emulator due to the way the
+ connectivity is emulated on Windows.
+
+ \sa state()
+*/
+QNetworkInterface QNetworkSession::interface() const
+{
+ return d ? d->currentInterface() : QNetworkInterface();
+}
+#endif
+
+/*!
+ Returns true if this session is open. If the number of all open sessions is greater than
+ zero the underlying network interface will remain connected/up.
+
+ The session can be controlled via open() and close().
+*/
+bool QNetworkSession::isOpen() const
+{
+ return d ? d->isOpen : false;
+}
+
+/*!
+ Returns the state of the session.
+
+ If the session is based on a single access point configuration the state of the
+ session is the same as the state of the associated network interface. Therefore
+ a network session object can be used to monitor network interfaces.
+
+ A \l QNetworkConfiguration::ServiceNetwork based session summarizes the state of all its children
+ and therefore returns the \l Connected state if at least one of the service network's
+ \l {QNetworkConfiguration::children()}{children()} configurations is active.
+
+ Note that it is not required to hold an open session in order to obtain the network interface state.
+ A connected but closed session may be used to monitor network interfaces whereas an open and connected
+ session object may prevent the network interface from being shut down.
+
+ \sa error(), stateChanged()
+*/
+QNetworkSession::State QNetworkSession::state() const
+{
+ return d ? d->state : QNetworkSession::Invalid;
+}
+
+/*!
+ Returns the type of error that last occurred.
+
+ \sa state(), errorString()
+*/
+QNetworkSession::SessionError QNetworkSession::error() const
+{
+ return d ? d->error() : InvalidConfigurationError;
+}
+
+/*!
+ Returns a human-readable description of the last device error that
+ occurred.
+
+ \sa error()
+*/
+QString QNetworkSession::errorString() const
+{
+ return d ? d->errorString() : tr("Invalid configuration.");
+}
+
+/*!
+ Returns the value for property \a key.
+
+ A network session can have properties attached which may describe the session in more details.
+ This function can be used to gain access to those properties.
+
+ The following property keys are guaranteed to be specified on all platforms:
+
+ \table
+ \header
+ \o Key \o Description
+ \row
+ \o ActiveConfiguration
+ \o If the session \l isOpen() this property returns the identifier of the
+ QNetworkConfiguration that is used by this session; otherwise an empty string.
+
+ The main purpose of this key is to determine which Internet access point is used
+ if the session is based on a \l{QNetworkConfiguration::ServiceNetwork}{ServiceNetwork}.
+ The following code snippet highlights the difference:
+ \code
+ QNetworkConfigurationManager mgr;
+ QNetworkConfiguration ap = mgr.defaultConfiguration();
+ QNetworkSession* session = new QNetworkSession(ap);
+ ... //code activates session
+
+ QString ident = session->sessionProperty("ActiveConfiguration").toString();
+ if ( ap.type() == QNetworkConfiguration::ServiceNetwork ) {
+ Q_ASSERT( ap.identifier() != ident );
+ Q_ASSERT( ap.children().contains( mgr.configurationFromIdentifier(ident) ) );
+ } else if ( ap.type() == QNetworkConfiguration::InternetAccessPoint ) {
+ Q_ASSERT( ap.identifier() == ident );
+ }
+ \endcode
+ \row
+ \o UserChoiceConfiguration
+ \o If the session \l isOpen() and is bound to a QNetworkConfiguration of type
+ UserChoice, this property returns the identifier of the QNetworkConfiguration that the
+ configuration resolved to when \l open() was called; otherwise an empty string.
+
+ The purpose of this key is to determine the real QNetworkConfiguration that the
+ session is using. This key is different to \i ActiveConfiguration in that
+ this key may return an identifier for either a
+ \l {QNetworkConfiguration::ServiceNetwork}{service network} or a
+ \l {QNetworkConfiguration::InternetAccessPoint}{Internet access points} configurations
+ whereas \i ActiveConfiguration always returns identifiers to
+ \l {QNetworkConfiguration::InternetAccessPoint}{Internet access points} configurations.
+ \row
+ \o ConnectInBackground
+ \o Setting this property to \i true before calling \l open() implies that the connection attempt
+ is made but if no connection can be established, the user is not connsulted and asked to select
+ a suitable connection. This property is not set by default and support for it depends on the platform.
+
+ \row
+ \o AutoCloseSessionTimeout
+ \o If the session requires polling to keep its state up to date, this property holds
+ the timeout in milliseconds before the session will automatically close. If the
+ value of this property is -1 the session will not automatically close. This property
+ is set to -1 by default.
+
+ The purpose of this property is to minimize resource use on platforms that use
+ polling to update the state of the session. Applications can set the value of this
+ property to the desired timeout before the session is closed. In response to the
+ closed() signal the network session should be deleted to ensure that all polling is
+ stopped. The session can then be recreated once it is required again. This property
+ has no effect for sessions that do not require polling.
+ \endtable
+*/
+QVariant QNetworkSession::sessionProperty(const QString& key) const
+{
+ if (!d)
+ return QVariant();
+
+ if (!d->publicConfig.isValid())
+ return QVariant();
+
+ if (key == QLatin1String("ActiveConfiguration")) {
+ if (!d->isOpen)
+ return QString();
+ else
+ return d->activeConfig.identifier();
+ }
+
+ if (key == QLatin1String("UserChoiceConfiguration")) {
+ if (!d->isOpen || d->publicConfig.type() != QNetworkConfiguration::UserChoice)
+ return QString();
+
+ if (d->serviceConfig.isValid())
+ return d->serviceConfig.identifier();
+ else
+ return d->activeConfig.identifier();
+ }
+
+ return d->sessionProperty(key);
+}
+
+/*!
+ Sets the property \a value on the session. The property is identified using
+ \a key. Removing an already set property can be achieved by passing an
+ invalid QVariant.
+
+ Note that the \e UserChoiceConfiguration and \e ActiveConfiguration
+ properties are read only and cannot be changed using this method.
+*/
+void QNetworkSession::setSessionProperty(const QString& key, const QVariant& value)
+{
+ if (!d)
+ return;
+
+ if (key == QLatin1String("ActiveConfiguration") ||
+ key == QLatin1String("UserChoiceConfiguration")) {
+ return;
+ }
+
+ d->setSessionProperty(key, value);
+}
+
+/*!
+ Instructs the session to roam to the new access point. The old access point remains active
+ until the application calls accept().
+
+ The newConfigurationActivated() signal is emitted once roaming has been completed.
+
+ \sa accept()
+*/
+void QNetworkSession::migrate()
+{
+ if (d)
+ d->migrate();
+}
+
+/*!
+ This function indicates that the application does not wish to roam the session.
+
+ \sa migrate()
+*/
+void QNetworkSession::ignore()
+{
+ // Needed on at least Symbian platform: the roaming must be explicitly
+ // ignore()'d or migrate()'d
+ if (d)
+ d->ignore();
+}
+
+/*!
+ Instructs the session to permanently accept the new access point. Once this function
+ has been called the session may not return to the old access point.
+
+ The old access point may be closed in the process if there are no other network sessions for it.
+ Therefore any open socket that still uses the old access point
+ may become unusable and should be closed before completing the migration.
+*/
+void QNetworkSession::accept()
+{
+ if (d)
+ d->accept();
+}
+
+/*!
+ The new access point is not suitable for the application. By calling this function the
+ session returns to the previous access point/configuration. This action may invalidate
+ any socket that has been created via the not desired access point.
+
+ \sa accept()
+*/
+void QNetworkSession::reject()
+{
+ if (d)
+ d->reject();
+}
+
+
+/*!
+ Returns the amount of data sent in bytes; otherwise 0.
+
+ This field value includes the usage across all open network
+ sessions which use the same network interface.
+
+ If the session is based on a service network configuration the number of
+ sent bytes across all active member configurations are returned.
+
+ This function may not always be supported on all platforms and returns
+ 0. The platform capability can be detected via QNetworkConfigurationManager::DataStatistics.
+*/
+quint64 QNetworkSession::bytesWritten() const
+{
+ return d ? d->bytesWritten() : Q_UINT64_C(0);
+}
+
+/*!
+ Returns the amount of data received in bytes; otherwise 0.
+
+ This field value includes the usage across all open network
+ sessions which use the same network interface.
+
+ If the session is based on a service network configuration the number of
+ sent bytes across all active member configurations are returned.
+
+ This function may not always be supported on all platforms and returns
+ 0. The platform capability can be detected via QNetworkConfigurationManager::DataStatistics.
+*/
+quint64 QNetworkSession::bytesReceived() const
+{
+ return d ? d->bytesReceived() : Q_UINT64_C(0);
+}
+
+/*!
+ Returns the number of seconds that the session has been active.
+*/
+quint64 QNetworkSession::activeTime() const
+{
+ return d ? d->activeTime() : Q_UINT64_C(0);
+}
+
+/*!
+ \internal
+
+ This function is required to detect whether the client wants to control
+ the roaming process. If he connects to preferredConfigurationChanged() signal
+ he intends to influence it. Otherwise QNetworkSession always roams
+ without registering this session as a stakeholder in the roaming process.
+
+ For more details check the Forced vs ALR roaming section in the QNetworkSession
+ class description.
+*/
+void QNetworkSession::connectNotify(const char *signal)
+{
+ QObject::connectNotify(signal);
+ //check for preferredConfigurationChanged() signal connect notification
+ //This is not required on all platforms
+ if (!d)
+ return;
+
+ if (qstrcmp(signal, SIGNAL(preferredConfigurationChanged(QNetworkConfiguration,bool))) == 0)
+ d->setALREnabled(true);
+}
+
+/*!
+ \internal
+
+ This function is called when the client disconnects from the preferredConfigurationChanged()
+ signal.
+
+ \sa connectNotify()
+*/
+void QNetworkSession::disconnectNotify(const char *signal)
+{
+ QObject::disconnectNotify(signal);
+ //check for preferredConfigurationChanged() signal disconnect notification
+ //This is not required on all platforms
+ if (!d)
+ return;
+
+ if (qstrcmp(signal, SIGNAL(preferredConfigurationChanged(QNetworkConfiguration,bool))) == 0)
+ d->setALREnabled(false);
+}
+
+#include "moc_qnetworksession.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/network/bearer/qnetworksession.h b/src/network/bearer/qnetworksession.h
new file mode 100644
index 0000000..596f527
--- /dev/null
+++ b/src/network/bearer/qnetworksession.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QNETWORKSESSION_H
+#define QNETWORKSESSION_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+#include <QtNetwork/qnetworkinterface.h>
+#include <QtCore/qvariant.h>
+#include <QtNetwork/qnetworkconfiguration.h>
+
+#if defined(Q_OS_WIN) && defined(interface)
+#undef interface
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+class QNetworkSessionPrivate;
+class Q_NETWORK_EXPORT QNetworkSession : public QObject
+{
+ Q_OBJECT
+public:
+ enum State {
+ Invalid = 0,
+ NotAvailable,
+ Connecting,
+ Connected,
+ Closing,
+ Disconnected,
+ Roaming
+ };
+
+ enum SessionError {
+ UnknownSessionError = 0,
+ SessionAbortedError,
+ RoamingError,
+ OperationNotSupportedError,
+ InvalidConfigurationError
+ };
+
+ explicit QNetworkSession(const QNetworkConfiguration& connConfig, QObject* parent =0);
+ virtual ~QNetworkSession();
+
+ bool isOpen() const;
+ QNetworkConfiguration configuration() const;
+#ifndef QT_NO_NETWORKINTERFACE
+ QNetworkInterface interface() const;
+#endif
+
+ State state() const;
+ SessionError error() const;
+ QString errorString() const;
+ QVariant sessionProperty(const QString& key) const;
+ void setSessionProperty(const QString& key, const QVariant& value);
+
+ quint64 bytesWritten() const;
+ quint64 bytesReceived() const;
+ quint64 activeTime() const;
+
+ bool waitForOpened(int msecs = 30000);
+
+public Q_SLOTS:
+ void open();
+ void close();
+ void stop();
+
+ //roaming related slots
+ void migrate();
+ void ignore();
+ void accept();
+ void reject();
+
+
+Q_SIGNALS:
+ void stateChanged(QNetworkSession::State);
+ void opened();
+ void closed();
+ void error(QNetworkSession::SessionError);
+ void preferredConfigurationChanged(const QNetworkConfiguration& config, bool isSeamless);
+ void newConfigurationActivated();
+
+protected:
+ virtual void connectNotify(const char *signal);
+ virtual void disconnectNotify(const char *signal);
+
+private:
+ QNetworkSessionPrivate* d;
+ friend class QNetworkSessionPrivate;
+ };
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif //QNETWORKSESSION_H
diff --git a/src/network/bearer/qnetworksession_p.h b/src/network/bearer/qnetworksession_p.h
new file mode 100644
index 0000000..a341eaf
--- /dev/null
+++ b/src/network/bearer/qnetworksession_p.h
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QNETWORKSESSIONPRIVATE_H
+#define QNETWORKSESSIONPRIVATE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qnetworksession.h"
+#include "qnetworkconfiguration_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_NETWORK_EXPORT QNetworkSessionPrivate : public QObject
+{
+ Q_OBJECT
+
+ friend class QNetworkSession;
+
+public:
+ QNetworkSessionPrivate()
+ : state(QNetworkSession::Invalid), isOpen(false)
+ {
+ }
+
+ virtual ~QNetworkSessionPrivate()
+ {
+ }
+
+ //called by QNetworkSession constructor and ensures
+ //that the state is immediately updated (w/o actually opening
+ //a session). Also this function should take care of
+ //notification hooks to discover future state changes.
+ virtual void syncStateWithInterface() = 0;
+
+#ifndef QT_NO_NETWORKINTERFACE
+ virtual QNetworkInterface currentInterface() const = 0;
+#endif
+ virtual QVariant sessionProperty(const QString& key) const = 0;
+ virtual void setSessionProperty(const QString& key, const QVariant& value) = 0;
+
+ virtual void open() = 0;
+ virtual void close() = 0;
+ virtual void stop() = 0;
+
+ virtual void setALREnabled(bool /*enabled*/) { }
+ virtual void migrate() = 0;
+ virtual void accept() = 0;
+ virtual void ignore() = 0;
+ virtual void reject() = 0;
+
+ virtual QString errorString() const = 0; //must return translated string
+ virtual QNetworkSession::SessionError error() const = 0;
+
+ virtual quint64 bytesWritten() const = 0;
+ virtual quint64 bytesReceived() const = 0;
+ virtual quint64 activeTime() const = 0;
+
+protected:
+ inline QNetworkConfigurationPrivatePointer privateConfiguration(const QNetworkConfiguration &config) const
+ {
+ return config.d;
+ }
+
+ inline void setPrivateConfiguration(QNetworkConfiguration &config,
+ QNetworkConfigurationPrivatePointer ptr) const
+ {
+ config.d = ptr;
+ }
+
+Q_SIGNALS:
+ //releases any pending waitForOpened() calls
+ void quitPendingWaitsForOpened();
+
+ void error(QNetworkSession::SessionError error);
+ void stateChanged(QNetworkSession::State state);
+ void closed();
+ void newConfigurationActivated();
+ void preferredConfigurationChanged(const QNetworkConfiguration &config, bool isSeamless);
+
+protected:
+ // The config set on QNetworkSession.
+ QNetworkConfiguration publicConfig;
+
+ // If publicConfig is a ServiceNetwork this is a copy of publicConfig.
+ // If publicConfig is an UserChoice that is resolved to a ServiceNetwork this is the actual
+ // ServiceNetwork configuration.
+ QNetworkConfiguration serviceConfig;
+
+ // This is the actual active configuration currently in use by the session.
+ // Either a copy of publicConfig or one of serviceConfig.children().
+ QNetworkConfiguration activeConfig;
+
+ QNetworkSession::State state;
+ bool isOpen;
+
+ QNetworkSession *q;
+};
+
+QT_END_NAMESPACE
+
+#endif //QNETWORKSESSIONPRIVATE_H
+
diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp
index 6894978..baf69e7 100644
--- a/src/network/kernel/qhostinfo.cpp
+++ b/src/network/kernel/qhostinfo.cpp
@@ -172,7 +172,7 @@ int QHostInfo::lookupHost(const QString &name, QObject *receiver,
if (name.isEmpty()) {
QHostInfo hostInfo(id);
hostInfo.setError(QHostInfo::HostNotFound);
- hostInfo.setErrorString(QObject::tr("No host name given"));
+ hostInfo.setErrorString(QCoreApplication::translate("QHostInfo", "No host name given"));
QScopedPointer<QHostInfoResult> result(new QHostInfoResult);
QObject::connect(result.data(), SIGNAL(resultsReady(QHostInfo)),
receiver, member, Qt::QueuedConnection);
diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp
index be06b6e..a186e78 100644
--- a/src/network/kernel/qhostinfo_unix.cpp
+++ b/src/network/kernel/qhostinfo_unix.cpp
@@ -193,7 +193,9 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
results.setHostName(hostName);
if (aceHostname.isEmpty()) {
results.setError(QHostInfo::HostNotFound);
- results.setErrorString(hostName.isEmpty() ? QObject::tr("No host name given") : QObject::tr("Invalid hostname"));
+ results.setErrorString(hostName.isEmpty() ?
+ QCoreApplication::translate("QHostInfoAgent", "No host name given") :
+ QCoreApplication::translate("QHostInfoAgent", "Invalid hostname"));
return results;
}
diff --git a/src/network/network.pro b/src/network/network.pro
index e890b94..8582d8a 100644
--- a/src/network/network.pro
+++ b/src/network/network.pro
@@ -17,6 +17,7 @@ unix:QMAKE_PKGCONFIG_REQUIRES = QtCore
include(../qbase.pri)
include(access/access.pri)
+include(bearer/bearer.pri)
include(kernel/kernel.pri)
include(socket/socket.pri)
include(ssl/ssl.pri)
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index 95721ee..21cd0fd 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -365,12 +365,12 @@
#include "private/qhostinfo_p.h"
#include <qabstracteventdispatcher.h>
-#include <qdatetime.h>
#include <qhostaddress.h>
#include <qhostinfo.h>
#include <qmetaobject.h>
#include <qpointer.h>
#include <qtimer.h>
+#include <qelapsedtimer.h>
#ifndef QT_NO_OPENSSL
#include <QtNetwork/qsslsocket.h>
@@ -1738,7 +1738,7 @@ bool QAbstractSocket::waitForConnected(int msecs)
bool wasPendingClose = d->pendingClose;
d->pendingClose = false;
- QTime stopWatch;
+ QElapsedTimer stopWatch;
stopWatch.start();
if (d->state == HostLookupState) {
@@ -1819,7 +1819,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs)
return false;
}
- QTime stopWatch;
+ QElapsedTimer stopWatch;
stopWatch.start();
// handle a socket in connecting state
@@ -1878,7 +1878,7 @@ bool QAbstractSocket::waitForBytesWritten(int msecs)
if (d->writeBuffer.isEmpty())
return false;
- QTime stopWatch;
+ QElapsedTimer stopWatch;
stopWatch.start();
// handle a socket in connecting state
@@ -1960,7 +1960,7 @@ bool QAbstractSocket::waitForDisconnected(int msecs)
return false;
}
- QTime stopWatch;
+ QElapsedTimer stopWatch;
stopWatch.start();
// handle a socket in connecting state
diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp
index 3293ff5..dfda257 100644
--- a/src/network/socket/qhttpsocketengine.cpp
+++ b/src/network/socket/qhttpsocketengine.cpp
@@ -42,9 +42,9 @@
#include "qhttpsocketengine_p.h"
#include "qtcpsocket.h"
#include "qhostaddress.h"
-#include "qdatetime.h"
#include "qurl.h"
#include "qhttp.h"
+#include "qelapsedtimer.h"
#if !defined(QT_NO_NETWORKPROXY) && !defined(QT_NO_HTTP)
#include <qdebug.h>
@@ -319,7 +319,7 @@ bool QHttpSocketEngine::waitForRead(int msecs, bool *timedOut)
if (!d->socket || d->socket->state() == QAbstractSocket::UnconnectedState)
return false;
- QTime stopWatch;
+ QElapsedTimer stopWatch;
stopWatch.start();
// Wait for more data if nothing is available.
@@ -366,7 +366,7 @@ bool QHttpSocketEngine::waitForWrite(int msecs, bool *timedOut)
return true;
}
- QTime stopWatch;
+ QElapsedTimer stopWatch;
stopWatch.start();
// If we're not connected yet, wait until we are, and until bytes have
diff --git a/src/network/socket/qlocalsocket_unix.cpp b/src/network/socket/qlocalsocket_unix.cpp
index 1ca11d8..f14decc 100644
--- a/src/network/socket/qlocalsocket_unix.cpp
+++ b/src/network/socket/qlocalsocket_unix.cpp
@@ -52,9 +52,9 @@
#include <fcntl.h>
#include <errno.h>
-#include <qdatetime.h>
#include <qdir.h>
#include <qdebug.h>
+#include <qelapsedtimer.h>
#ifdef Q_OS_VXWORKS
# include <selectLib.h>
@@ -534,7 +534,7 @@ bool QLocalSocket::waitForConnected(int msec)
int result = -1;
// on Linux timeout will be updated by select, but _not_ on other systems.
- QTime timer;
+ QElapsedTimer timer;
timer.start();
while (state() == ConnectingState
&& (-1 == msec || timer.elapsed() < msec)) {
diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp
index a890b3b..a169ca0 100644
--- a/src/network/socket/qnativesocketengine.cpp
+++ b/src/network/socket/qnativesocketengine.cpp
@@ -185,6 +185,9 @@ void QNativeSocketEnginePrivate::setError(QAbstractSocket::SocketError error, Er
// socket to recreate its engine after an error. Note: There's
// one exception: SocketError(11) bypasses this as it's purely
// a temporary internal error condition.
+ // Another exception is the way the waitFor*() functions set
+ // an error when a timeout occurs. After the call to setError()
+ // they reset the hasSetSocketError to false
return;
}
if (error != QAbstractSocket::SocketError(11))
@@ -859,6 +862,7 @@ bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut)
*timedOut = true;
d->setError(QAbstractSocket::SocketTimeoutError,
QNativeSocketEnginePrivate::TimeOutErrorString);
+ d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions
return false;
} else if (state() == QAbstractSocket::ConnectingState) {
connectToHost(d->peerAddress, d->peerPort);
@@ -927,6 +931,7 @@ bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut)
*timedOut = true;
d->setError(QAbstractSocket::SocketTimeoutError,
QNativeSocketEnginePrivate::TimeOutErrorString);
+ d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions
return false;
} else if (state() == QAbstractSocket::ConnectingState) {
connectToHost(d->peerAddress, d->peerPort);
@@ -978,6 +983,7 @@ bool QNativeSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWri
*timedOut = true;
d->setError(QAbstractSocket::SocketTimeoutError,
QNativeSocketEnginePrivate::TimeOutErrorString);
+ d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions
return false;
} else if (state() == QAbstractSocket::ConnectingState) {
connectToHost(d->peerAddress, d->peerPort);
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index 9a2c349..6c800fe 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -44,8 +44,8 @@
#include "private/qnet_unix_p.h"
#include "qiodevice.h"
#include "qhostaddress.h"
+#include "qelapsedtimer.h"
#include "qvarlengtharray.h"
-#include "qdatetime.h"
#include <time.h>
#include <errno.h>
#include <fcntl.h>
@@ -1003,7 +1003,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c
#ifndef Q_OS_SYMBIAN
ret = qt_safe_select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv);
#else
- QTime timer;
+ QElapsedTimer timer;
timer.start();
do {
diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp
index 924530e..f68edfe 100644
--- a/src/network/socket/qsocks5socketengine.cpp
+++ b/src/network/socket/qsocks5socketengine.cpp
@@ -49,7 +49,7 @@
#include "qdebug.h"
#include "qhash.h"
#include "qqueue.h"
-#include "qdatetime.h"
+#include "qelapsedtimer.h"
#include "qmutex.h"
#include "qthread.h"
#include "qcoreapplication.h"
@@ -308,7 +308,7 @@ struct QSocks5BindData : public QSocks5Data
quint16 localPort;
QHostAddress peerAddress;
quint16 peerPort;
- QDateTime timeStamp;
+ QElapsedTimer timeStamp;
};
struct QSocks5RevivedDatagram
@@ -369,7 +369,7 @@ void QSocks5BindStore::add(int socketDescriptor, QSocks5BindData *bindData)
if (store.contains(socketDescriptor)) {
// qDebug() << "delete it";
}
- bindData->timeStamp = QDateTime::currentDateTime();
+ bindData->timeStamp.start();
store.insert(socketDescriptor, bindData);
// start sweep timer if not started
if (sweepTimerId == -1)
@@ -412,7 +412,7 @@ void QSocks5BindStore::timerEvent(QTimerEvent * event)
QMutableHashIterator<int, QSocks5BindData *> it(store);
while (it.hasNext()) {
it.next();
- if (it.value()->timeStamp.secsTo(QDateTime::currentDateTime()) > 350) {
+ if (it.value()->timeStamp.hasExpired(350000)) {
QSOCKS5_DEBUG << "QSocks5BindStore removing JJJJ";
it.remove();
}
@@ -1355,7 +1355,7 @@ bool QSocks5SocketEngine::bind(const QHostAddress &address, quint16 port)
}
int msecs = SOCKS5_BLOCKING_BIND_TIMEOUT;
- QTime stopWatch;
+ QElapsedTimer stopWatch;
stopWatch.start();
d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port());
if (!d->waitForConnected(msecs, 0) ||
@@ -1455,7 +1455,7 @@ void QSocks5SocketEngine::close()
if (d->data && d->data->controlSocket) {
if (d->data->controlSocket->state() == QAbstractSocket::ConnectedState) {
int msecs = 100;
- QTime stopWatch;
+ QElapsedTimer stopWatch;
stopWatch.start();
while (!d->data->controlSocket->bytesToWrite()) {
if (!d->data->controlSocket->waitForBytesWritten(qt_timeout_value(msecs, stopWatch.elapsed())))
@@ -1674,7 +1674,7 @@ bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut)
mode == BindMode ? BindSuccess :
UdpAssociateSuccess;
- QTime stopWatch;
+ QElapsedTimer stopWatch;
stopWatch.start();
while (socks5State != wantedState) {
@@ -1699,7 +1699,7 @@ bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut)
d->readNotificationActivated = false;
- QTime stopWatch;
+ QElapsedTimer stopWatch;
stopWatch.start();
// are we connected yet?
@@ -1749,7 +1749,7 @@ bool QSocks5SocketEngine::waitForWrite(int msecs, bool *timedOut)
Q_D(QSocks5SocketEngine);
QSOCKS5_DEBUG << "waitForWrite" << msecs;
- QTime stopWatch;
+ QElapsedTimer stopWatch;
stopWatch.start();
// are we connected yet?
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 9623570..86b11b9 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -286,8 +286,8 @@
#include <QtCore/qdebug.h>
#include <QtCore/qdir.h>
-#include <QtCore/qdatetime.h>
#include <QtCore/qmutex.h>
+#include <QtCore/qelapsedtimer.h>
#include <QtNetwork/qhostaddress.h>
#include <QtNetwork/qhostinfo.h>
@@ -1393,7 +1393,7 @@ bool QSslSocket::waitForEncrypted(int msecs)
if (d->mode == UnencryptedMode && !d->autoStartHandshake)
return false;
- QTime stopWatch;
+ QElapsedTimer stopWatch;
stopWatch.start();
if (d->plainSocket->state() != QAbstractSocket::ConnectedState) {
@@ -1433,7 +1433,7 @@ bool QSslSocket::waitForReadyRead(int msecs)
bool *previousReadyReadEmittedPointer = d->readyReadEmittedPointer;
d->readyReadEmittedPointer = &readyReadEmitted;
- QTime stopWatch;
+ QElapsedTimer stopWatch;
stopWatch.start();
if (!d->connectionEncrypted) {
@@ -1470,7 +1470,7 @@ bool QSslSocket::waitForBytesWritten(int msecs)
if (d->mode == UnencryptedMode)
return d->plainSocket->waitForBytesWritten(msecs);
- QTime stopWatch;
+ QElapsedTimer stopWatch;
stopWatch.start();
if (!d->connectionEncrypted) {
@@ -1508,7 +1508,7 @@ bool QSslSocket::waitForDisconnected(int msecs)
if (d->mode == UnencryptedMode)
return d->plainSocket->waitForDisconnected(msecs);
- QTime stopWatch;
+ QElapsedTimer stopWatch;
stopWatch.start();
if (!d->connectionEncrypted) {
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index ce2aee1..050fb1b 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -146,13 +146,14 @@ static void locking_function(int mode, int lockNumber, const char *, int)
}
static unsigned long id_function()
{
- return (unsigned long)QThread::currentThreadId();
+ return (quintptr)QThread::currentThreadId();
}
} // extern "C"
QSslSocketBackendPrivate::QSslSocketBackendPrivate()
: ssl(0),
ctx(0),
+ pkey(0),
readBio(0),
writeBio(0),
session(0)
@@ -311,11 +312,14 @@ init_context:
}
// Load private key
- EVP_PKEY *pkey = q_EVP_PKEY_new();
+ pkey = q_EVP_PKEY_new();
+ // before we were using EVP_PKEY_assign_R* functions and did not use EVP_PKEY_free.
+ // this lead to a memory leak. Now we use the *_set1_* functions which do not
+ // take ownership of the RSA/DSA key instance because the QSslKey already has ownership.
if (configuration.privateKey.algorithm() == QSsl::Rsa)
- q_EVP_PKEY_assign_RSA(pkey, (RSA *)configuration.privateKey.handle());
+ q_EVP_PKEY_set1_RSA(pkey, (RSA *)configuration.privateKey.handle());
else
- q_EVP_PKEY_assign_DSA(pkey, (DSA *)configuration.privateKey.handle());
+ q_EVP_PKEY_set1_DSA(pkey, (DSA *)configuration.privateKey.handle());
if (!q_SSL_CTX_use_PrivateKey(ctx, pkey)) {
q->setErrorString(QSslSocket::tr("Error loading private key, %1").arg(SSL_ERRORSTR()));
emit q->error(QAbstractSocket::UnknownSocketError);
@@ -922,6 +926,11 @@ void QSslSocketBackendPrivate::disconnected()
q_SSL_CTX_free(ctx);
ctx = 0;
}
+ if (pkey) {
+ q_EVP_PKEY_free(pkey);
+ pkey = 0;
+ }
+
}
QSslCipher QSslSocketBackendPrivate::sessionCipher() const
diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h
index 836f064..3c08757 100644
--- a/src/network/ssl/qsslsocket_openssl_p.h
+++ b/src/network/ssl/qsslsocket_openssl_p.h
@@ -97,6 +97,7 @@ public:
bool initSslContext();
SSL *ssl;
SSL_CTX *ctx;
+ EVP_PKEY *pkey;
BIO *readBio;
BIO *writeBio;
SSL_SESSION *session;
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
index 94cc9d2..d2eb6f1 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -119,6 +119,8 @@ DEFINEFUNC2(char *, ERR_error_string, unsigned long a, a, char *b, b, return 0,
DEFINEFUNC(unsigned long, ERR_get_error, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(const EVP_CIPHER *, EVP_des_ede3_cbc, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC3(int, EVP_PKEY_assign, EVP_PKEY *a, a, int b, b, char *c, c, return -1, return)
+DEFINEFUNC2(int, EVP_PKEY_set1_RSA, EVP_PKEY *a, a, RSA *b, b, return -1, return)
+DEFINEFUNC2(int, EVP_PKEY_set1_DSA, EVP_PKEY *a, a, DSA *b, b, return -1, return)
DEFINEFUNC(void, EVP_PKEY_free, EVP_PKEY *a, a, return, DUMMYARG)
DEFINEFUNC(DSA *, EVP_PKEY_get1_DSA, EVP_PKEY *a, a, return 0, return)
DEFINEFUNC(RSA *, EVP_PKEY_get1_RSA, EVP_PKEY *a, a, return 0, return)
@@ -510,6 +512,8 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(ERR_get_error, 749, libs.second )
RESOLVEFUNC(EVP_des_ede3_cbc, 919, libs.second )
RESOLVEFUNC(EVP_PKEY_assign, 859, libs.second )
+ RESOLVEFUNC(EVP_PKEY_set1_RSA, 880, libs.second )
+ RESOLVEFUNC(EVP_PKEY_set1_DSA, 879, libs.second )
RESOLVEFUNC(EVP_PKEY_free, 867, libs.second )
RESOLVEFUNC(EVP_PKEY_get1_DSA, 869, libs.second )
RESOLVEFUNC(EVP_PKEY_get1_RSA, 870, libs.second )
@@ -632,6 +636,8 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(ERR_get_error)
RESOLVEFUNC(EVP_des_ede3_cbc)
RESOLVEFUNC(EVP_PKEY_assign)
+ RESOLVEFUNC(EVP_PKEY_set1_RSA)
+ RESOLVEFUNC(EVP_PKEY_set1_DSA)
RESOLVEFUNC(EVP_PKEY_free)
RESOLVEFUNC(EVP_PKEY_get1_DSA)
RESOLVEFUNC(EVP_PKEY_get1_RSA)
diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h
index c93d547..ef61dbf 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols_p.h
+++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h
@@ -227,6 +227,8 @@ char *q_ERR_error_string(unsigned long a, char *b);
unsigned long q_ERR_get_error();
const EVP_CIPHER *q_EVP_des_ede3_cbc();
int q_EVP_PKEY_assign(EVP_PKEY *a, int b, char *c);
+int q_EVP_PKEY_set1_RSA(EVP_PKEY *a, RSA *b);
+int q_EVP_PKEY_set1_DSA(EVP_PKEY *a, DSA *b);
void q_EVP_PKEY_free(EVP_PKEY *a);
RSA *q_EVP_PKEY_get1_RSA(EVP_PKEY *a);
DSA *q_EVP_PKEY_get1_DSA(EVP_PKEY *a);