summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@digia.com>2014-02-19 10:06:25 +0100
committerOswald Buddenhagen <oswald.buddenhagen@digia.com>2014-02-19 10:06:25 +0100
commit30fd22b9574def54726e7b193127cc0c901c1b4c (patch)
tree96dfc923044db0515064ba39d052d9ed577e3e40 /src/network
parentd7b0581c1c2ef60c08d238dae39298af6904918f (diff)
parent6aa09bbce59828d028f6d1e81d2bfc6ba537aae1 (diff)
Merge remote-tracking branch 'origin/dev' into stable
Diffstat (limited to 'src/network')
-rw-r--r--src/network/access/access.pri4
-rw-r--r--src/network/access/qabstractprotocolhandler.cpp68
-rw-r--r--src/network/access/qabstractprotocolhandler_p.h88
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp4
-rw-r--r--src/network/access/qhttpnetworkconnection_p.h1
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp382
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel_p.h4
-rw-r--r--src/network/access/qhttpnetworkreply_p.h1
-rw-r--r--src/network/access/qhttpnetworkrequest.cpp16
-rw-r--r--src/network/access/qhttpnetworkrequest_p.h6
-rw-r--r--src/network/access/qhttpprotocolhandler.cpp431
-rw-r--r--src/network/access/qhttpprotocolhandler_p.h77
-rw-r--r--src/network/access/qhttpthreaddelegate.cpp25
-rw-r--r--src/network/access/qnetworkcookie.cpp36
-rw-r--r--src/network/access/qnetworkreply.cpp18
-rw-r--r--src/network/access/qnetworkreply.h10
-rw-r--r--src/network/doc/snippets/network/tcpwait.cpp8
-rw-r--r--src/network/kernel/kernel.pri14
-rw-r--r--src/network/kernel/qauthenticator.cpp21
-rw-r--r--src/network/kernel/qdnslookup.cpp23
-rw-r--r--src/network/kernel/qdnslookup.h6
-rw-r--r--src/network/kernel/qdnslookup_android.cpp3
-rw-r--r--src/network/kernel/qdnslookup_p.h7
-rw-r--r--src/network/kernel/qdnslookup_unix.cpp39
-rw-r--r--src/network/kernel/qdnslookup_win.cpp22
-rw-r--r--src/network/kernel/qdnslookup_winrt.cpp149
-rw-r--r--src/network/kernel/qhostaddress.cpp6
-rw-r--r--src/network/kernel/qhostinfo.cpp2
-rw-r--r--src/network/kernel/qhostinfo_unix.cpp6
-rw-r--r--src/network/kernel/qhostinfo_winrt.cpp194
-rw-r--r--src/network/kernel/qnetworkinterface_unix.cpp2
-rw-r--r--src/network/kernel/qnetworkinterface_winrt.cpp198
-rw-r--r--src/network/socket/qabstractsocket.cpp37
-rw-r--r--src/network/socket/qabstractsocket.h4
-rw-r--r--src/network/socket/qabstractsocketengine.cpp4
-rw-r--r--src/network/socket/qabstractsocketengine_p.h2
-rw-r--r--src/network/socket/qlocalserver.cpp2
-rw-r--r--src/network/socket/qnativesocketengine_p.h6
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp2
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp28
-rw-r--r--src/network/socket/qnativesocketengine_winrt.cpp1182
-rw-r--r--src/network/socket/qnativesocketengine_winrt_p.h209
-rw-r--r--src/network/socket/qsocks5socketengine.cpp7
-rw-r--r--src/network/socket/socket.pri19
-rw-r--r--src/network/ssl/qsslcipher.cpp20
-rw-r--r--src/network/ssl/qsslcipher.h1
-rw-r--r--src/network/ssl/qsslconfiguration.cpp108
-rw-r--r--src/network/ssl/qsslconfiguration.h16
-rw-r--r--src/network/ssl/qsslconfiguration_p.h8
-rw-r--r--src/network/ssl/qsslcontext.cpp60
-rw-r--r--src/network/ssl/qsslcontext_p.h20
-rw-r--r--src/network/ssl/qsslkey.cpp2
-rw-r--r--src/network/ssl/qsslsocket.cpp14
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp15
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp20
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h55
56 files changed, 3227 insertions, 485 deletions
diff --git a/src/network/access/access.pri b/src/network/access/access.pri
index aaaf05b551..3017417da8 100644
--- a/src/network/access/access.pri
+++ b/src/network/access/access.pri
@@ -7,6 +7,8 @@ HEADERS += \
access/qhttpnetworkreply_p.h \
access/qhttpnetworkconnection_p.h \
access/qhttpnetworkconnectionchannel_p.h \
+ access/qabstractprotocolhandler_p.h \
+ access/qhttpprotocolhandler_p.h \
access/qnetworkaccessauthenticationmanager_p.h \
access/qnetworkaccessmanager.h \
access/qnetworkaccessmanager_p.h \
@@ -43,6 +45,8 @@ SOURCES += \
access/qhttpnetworkreply.cpp \
access/qhttpnetworkconnection.cpp \
access/qhttpnetworkconnectionchannel.cpp \
+ access/qabstractprotocolhandler.cpp \
+ access/qhttpprotocolhandler.cpp \
access/qnetworkaccessauthenticationmanager.cpp \
access/qnetworkaccessmanager.cpp \
access/qnetworkaccesscache.cpp \
diff --git a/src/network/access/qabstractprotocolhandler.cpp b/src/network/access/qabstractprotocolhandler.cpp
new file mode 100644
index 0000000000..e72bb63236
--- /dev/null
+++ b/src/network/access/qabstractprotocolhandler.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qabstractprotocolhandler_p.h>
+#include <private/qhttpnetworkconnectionchannel_p.h>
+
+#ifndef QT_NO_HTTP
+
+QT_BEGIN_NAMESPACE
+
+QAbstractProtocolHandler::QAbstractProtocolHandler(QHttpNetworkConnectionChannel *channel)
+ : m_channel(channel), m_reply(0), m_socket(m_channel->socket), m_connection(m_channel->connection)
+{
+ Q_ASSERT(m_channel);
+ Q_ASSERT(m_socket);
+ Q_ASSERT(m_connection);
+}
+
+QAbstractProtocolHandler::~QAbstractProtocolHandler()
+{
+}
+
+void QAbstractProtocolHandler::setReply(QHttpNetworkReply *reply)
+{
+ m_reply = reply;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
diff --git a/src/network/access/qabstractprotocolhandler_p.h b/src/network/access/qabstractprotocolhandler_p.h
new file mode 100644
index 0000000000..387d08ccac
--- /dev/null
+++ b/src/network/access/qabstractprotocolhandler_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTPROTOCOLHANDLER_H
+#define QABSTRACTPROTOCOLHANDLER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QT_NO_HTTP
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QHttpNetworkConnectionChannel;
+class QHttpNetworkReply;
+class QAbstractSocket;
+class QHttpNetworkConnection;
+
+class QAbstractProtocolHandler {
+public:
+ QAbstractProtocolHandler(QHttpNetworkConnectionChannel *channel);
+ virtual ~QAbstractProtocolHandler();
+
+ virtual void _q_receiveReply() = 0;
+ virtual void _q_readyRead() = 0;
+ virtual bool sendRequest() = 0;
+ void setReply(QHttpNetworkReply *reply);
+
+protected:
+ QHttpNetworkConnectionChannel *m_channel;
+ QHttpNetworkReply *m_reply;
+ QAbstractSocket *m_socket;
+ QHttpNetworkConnection *m_connection;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
+
+#endif // QABSTRACTPROTOCOLHANDLER_H
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index e0996c4072..66c97f7485 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -512,7 +512,7 @@ void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket,
if ((channels[i].authMethod != QAuthenticatorPrivate::Ntlm && request.headerField("Authorization").isEmpty()) || channels[i].lastStatus == 401) {
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(channels[i].authenticator);
if (priv && priv->method != QAuthenticatorPrivate::None) {
- QByteArray response = priv->calculateResponse(request.d->methodName(), request.d->uri(false));
+ QByteArray response = priv->calculateResponse(request.methodName(), request.uri(false));
request.setHeaderField("Authorization", response);
channels[i].authenticationCredentialsSent = true;
}
@@ -524,7 +524,7 @@ void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket,
if (!(channels[i].proxyAuthMethod == QAuthenticatorPrivate::Ntlm && channels[i].lastStatus != 407)) {
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(channels[i].proxyAuthenticator);
if (priv && priv->method != QAuthenticatorPrivate::None) {
- QByteArray response = priv->calculateResponse(request.d->methodName(), request.d->uri(false));
+ QByteArray response = priv->calculateResponse(request.methodName(), request.uri(false));
request.setHeaderField("Proxy-Authorization", response);
channels[i].proxyCredentialsSent = true;
}
diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h
index 2aaaad24ac..526326c3fd 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -139,6 +139,7 @@ private:
friend class QHttpNetworkReply;
friend class QHttpNetworkReplyPrivate;
friend class QHttpNetworkConnectionChannel;
+ friend class QHttpProtocolHandler;
Q_PRIVATE_SLOT(d_func(), void _q_startNextRequest())
Q_PRIVATE_SLOT(d_func(), void _q_hostLookupFinished(QHostInfo))
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 6e786893ed..6f06c18732 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -48,6 +49,8 @@
#ifndef QT_NO_HTTP
+#include <private/qhttpprotocolhandler_p.h>
+
#ifndef QT_NO_SSL
# include <QtNetwork/qsslkey.h>
# include <QtNetwork/qsslcipher.h>
@@ -78,6 +81,7 @@ QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
, proxyAuthMethod(QAuthenticatorPrivate::None)
, authenticationCredentialsSent(false)
, proxyCredentialsSent(false)
+ , protocolHandler(0)
#ifndef QT_NO_SSL
, ignoreAllSslErrors(false)
#endif
@@ -163,8 +167,8 @@ void QHttpNetworkConnectionChannel::init()
if (!sslConfiguration.isNull())
sslSocket->setSslConfiguration(sslConfiguration);
}
-
#endif
+ protocolHandler.reset(new QHttpProtocolHandler(this));
#ifndef QT_NO_NETWORKPROXY
if (proxy.type() != QNetworkProxy::NoProxy)
@@ -193,349 +197,21 @@ void QHttpNetworkConnectionChannel::close()
bool QHttpNetworkConnectionChannel::sendRequest()
{
- if (!reply) {
- // heh, how should that happen!
- qWarning() << "QHttpNetworkConnectionChannel::sendRequest() called without QHttpNetworkReply";
- state = QHttpNetworkConnectionChannel::IdleState;
- return false;
- }
-
- switch (state) {
- case QHttpNetworkConnectionChannel::IdleState: { // write the header
- if (!ensureConnection()) {
- // wait for the connection (and encryption) to be done
- // sendRequest will be called again from either
- // _q_connected or _q_encrypted
- return false;
- }
- QString scheme = request.url().scheme();
- if (scheme == QLatin1String("preconnect-http")
- || scheme == QLatin1String("preconnect-https")) {
- state = QHttpNetworkConnectionChannel::IdleState;
- reply->d_func()->state = QHttpNetworkReplyPrivate::AllDoneState;
- allDone();
- connection->preConnectFinished(); // will only decrease the counter
- reply = 0; // so we can reuse this channel
- return true; // we have a working connection and are done
- }
-
- written = 0; // excluding the header
- bytesTotal = 0;
-
- QHttpNetworkReplyPrivate *replyPrivate = reply->d_func();
- replyPrivate->clear();
- replyPrivate->connection = connection;
- replyPrivate->connectionChannel = this;
- replyPrivate->autoDecompress = request.d->autoDecompress;
- replyPrivate->pipeliningUsed = false;
-
- // if the url contains authentication parameters, use the new ones
- // both channels will use the new authentication parameters
- if (!request.url().userInfo().isEmpty() && request.withCredentials()) {
- QUrl url = request.url();
- QAuthenticator &auth = authenticator;
- if (url.userName() != auth.user()
- || (!url.password().isEmpty() && url.password() != auth.password())) {
- auth.setUser(url.userName(QUrl::FullyDecoded));
- auth.setPassword(url.password(QUrl::FullyDecoded));
- connection->d_func()->copyCredentials(connection->d_func()->indexOf(socket), &auth, false);
- }
- // clear the userinfo, since we use the same request for resending
- // userinfo in url can conflict with the one in the authenticator
- url.setUserInfo(QString());
- request.setUrl(url);
- }
- // Will only be false if Qt WebKit is performing a cross-origin XMLHttpRequest
- // and withCredentials has not been set to true.
- if (request.withCredentials())
- connection->d_func()->createAuthorization(socket, request);
-#ifndef QT_NO_NETWORKPROXY
- QByteArray header = QHttpNetworkRequestPrivate::header(request,
- (connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy));
-#else
- QByteArray header = QHttpNetworkRequestPrivate::header(request, false);
-#endif
- socket->write(header);
- // flushing is dangerous (QSslSocket calls transmit which might read or error)
-// socket->flush();
- QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice();
- if (uploadByteDevice) {
- // connect the signals so this function gets called again
- QObject::connect(uploadByteDevice, SIGNAL(readyRead()),this, SLOT(_q_uploadDataReadyRead()));
-
- bytesTotal = request.contentLength();
-
- state = QHttpNetworkConnectionChannel::WritingState; // start writing data
- sendRequest(); //recurse
- } else {
- state = QHttpNetworkConnectionChannel::WaitingState; // now wait for response
- sendRequest(); //recurse
- }
-
- break;
- }
- case QHttpNetworkConnectionChannel::WritingState:
- {
- // write the data
- QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice();
- if (!uploadByteDevice || bytesTotal == written) {
- if (uploadByteDevice)
- emit reply->dataSendProgress(written, bytesTotal);
- state = QHttpNetworkConnectionChannel::WaitingState; // now wait for response
- sendRequest(); // recurse
- break;
- }
-
- // only feed the QTcpSocket buffer when there is less than 32 kB in it
- const qint64 socketBufferFill = 32*1024;
- const qint64 socketWriteMaxSize = 16*1024;
-
-
-#ifndef QT_NO_SSL
- QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket);
- // if it is really an ssl socket, check more than just bytesToWrite()
- while ((socket->bytesToWrite() + (sslSocket ? sslSocket->encryptedBytesToWrite() : 0))
- <= socketBufferFill && bytesTotal != written)
-#else
- while (socket->bytesToWrite() <= socketBufferFill
- && bytesTotal != written)
-#endif
- {
- // get pointer to upload data
- qint64 currentReadSize = 0;
- qint64 desiredReadSize = qMin(socketWriteMaxSize, bytesTotal - written);
- const char *readPointer = uploadByteDevice->readPointer(desiredReadSize, currentReadSize);
-
- if (currentReadSize == -1) {
- // premature eof happened
- connection->d_func()->emitReplyError(socket, reply, QNetworkReply::UnknownNetworkError);
- return false;
- } else if (readPointer == 0 || currentReadSize == 0) {
- // nothing to read currently, break the loop
- break;
- } else {
- qint64 currentWriteSize = socket->write(readPointer, currentReadSize);
- if (currentWriteSize == -1 || currentWriteSize != currentReadSize) {
- // socket broke down
- connection->d_func()->emitReplyError(socket, reply, QNetworkReply::UnknownNetworkError);
- return false;
- } else {
- written += currentWriteSize;
- uploadByteDevice->advanceReadPointer(currentWriteSize);
-
- emit reply->dataSendProgress(written, bytesTotal);
-
- if (written == bytesTotal) {
- // make sure this function is called once again
- state = QHttpNetworkConnectionChannel::WaitingState;
- sendRequest();
- break;
- }
- }
- }
- }
- break;
- }
-
- case QHttpNetworkConnectionChannel::WaitingState:
- {
- QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice();
- if (uploadByteDevice) {
- QObject::disconnect(uploadByteDevice, SIGNAL(readyRead()), this, SLOT(_q_uploadDataReadyRead()));
- }
-
- // HTTP pipelining
- //connection->d_func()->fillPipeline(socket);
- //socket->flush();
-
- // ensure we try to receive a reply in all cases, even if _q_readyRead_ hat not been called
- // this is needed if the sends an reply before we have finished sending the request. In that
- // case receiveReply had been called before but ignored the server reply
- if (socket->bytesAvailable())
- QMetaObject::invokeMethod(this, "_q_receiveReply", Qt::QueuedConnection);
- break;
- }
- case QHttpNetworkConnectionChannel::ReadingState:
- // ignore _q_bytesWritten in these states
- // fall through
- default:
- break;
- }
- return true;
+ Q_ASSERT(!protocolHandler.isNull());
+ return protocolHandler->sendRequest();
}
void QHttpNetworkConnectionChannel::_q_receiveReply()
{
- Q_ASSERT(socket);
-
- if (!reply) {
- if (socket->bytesAvailable() > 0)
- qWarning() << "QHttpNetworkConnectionChannel::_q_receiveReply() called without QHttpNetworkReply,"
- << socket->bytesAvailable() << "bytes on socket.";
- close();
- return;
- }
-
- // only run when the QHttpNetworkConnection is not currently being destructed, e.g.
- // this function is called from _q_disconnected which is called because
- // of ~QHttpNetworkConnectionPrivate
- if (!qobject_cast<QHttpNetworkConnection*>(connection)) {
- return;
- }
-
- QAbstractSocket::SocketState socketState = socket->state();
-
- // connection might be closed to signal the end of data
- if (socketState == QAbstractSocket::UnconnectedState) {
- if (socket->bytesAvailable() <= 0) {
- if (reply->d_func()->state == QHttpNetworkReplyPrivate::ReadingDataState) {
- // finish this reply. this case happens when the server did not send a content length
- reply->d_func()->state = QHttpNetworkReplyPrivate::AllDoneState;
- allDone();
- return;
- } else {
- handleUnexpectedEOF();
- return;
- }
- } else {
- // socket not connected but still bytes for reading.. just continue in this function
- }
- }
-
- // read loop for the response
- qint64 bytes = 0;
- qint64 lastBytes = bytes;
- do {
- lastBytes = bytes;
-
- QHttpNetworkReplyPrivate::ReplyState state = reply->d_func()->state;
- switch (state) {
- case QHttpNetworkReplyPrivate::NothingDoneState: {
- state = reply->d_func()->state = QHttpNetworkReplyPrivate::ReadingStatusState;
- // fallthrough
- }
- case QHttpNetworkReplyPrivate::ReadingStatusState: {
- qint64 statusBytes = reply->d_func()->readStatus(socket);
- if (statusBytes == -1) {
- // connection broke while reading status. also handled if later _q_disconnected is called
- handleUnexpectedEOF();
- return;
- }
- bytes += statusBytes;
- lastStatus = reply->d_func()->statusCode;
- break;
- }
- case QHttpNetworkReplyPrivate::ReadingHeaderState: {
- QHttpNetworkReplyPrivate *replyPrivate = reply->d_func();
- qint64 headerBytes = replyPrivate->readHeader(socket);
- if (headerBytes == -1) {
- // connection broke while reading headers. also handled if later _q_disconnected is called
- handleUnexpectedEOF();
- return;
- }
- bytes += headerBytes;
- // If headers were parsed successfully now it is the ReadingDataState
- if (replyPrivate->state == QHttpNetworkReplyPrivate::ReadingDataState) {
- if (replyPrivate->isCompressed() && replyPrivate->autoDecompress) {
- // remove the Content-Length from header
- replyPrivate->removeAutoDecompressHeader();
- } else {
- replyPrivate->autoDecompress = false;
- }
- if (replyPrivate->statusCode == 100) {
- replyPrivate->clearHttpLayerInformation();
- replyPrivate->state = QHttpNetworkReplyPrivate::ReadingStatusState;
- break; // ignore
- }
- if (replyPrivate->shouldEmitSignals())
- emit reply->headerChanged();
- // After headerChanged had been emitted
- // we can suddenly have a replyPrivate->userProvidedDownloadBuffer
- // this is handled in the ReadingDataState however
-
- if (!replyPrivate->expectContent()) {
- replyPrivate->state = QHttpNetworkReplyPrivate::AllDoneState;
- allDone();
- break;
- }
- }
- break;
- }
- case QHttpNetworkReplyPrivate::ReadingDataState: {
- QHttpNetworkReplyPrivate *replyPrivate = reply->d_func();
- if (socket->state() == QAbstractSocket::ConnectedState &&
- replyPrivate->downstreamLimited && !replyPrivate->responseData.isEmpty() && replyPrivate->shouldEmitSignals()) {
- // (only do the following when still connected, not when we have already been disconnected and there is still data)
- // We already have some HTTP body data. We don't read more from the socket until
- // this is fetched by QHttpNetworkAccessHttpBackend. If we would read more,
- // we could not limit our read buffer usage.
- // We only do this when shouldEmitSignals==true because our HTTP parsing
- // always needs to parse the 401/407 replies. Therefore they don't really obey
- // to the read buffer maximum size, but we don't care since they should be small.
- return;
- }
-
- if (replyPrivate->userProvidedDownloadBuffer) {
- // the user provided a direct buffer where we should put all our data in.
- // this only works when we can tell the user the content length and he/she can allocate
- // the buffer in that size.
- // note that this call will read only from the still buffered data
- qint64 haveRead = replyPrivate->readBodyVeryFast(socket, replyPrivate->userProvidedDownloadBuffer + replyPrivate->totalProgress);
- if (haveRead > 0) {
- bytes += haveRead;
- replyPrivate->totalProgress += haveRead;
- // the user will get notified of it via progress signal
- emit reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
- } else if (haveRead == 0) {
- // Happens since this called in a loop. Currently no bytes available.
- } else if (haveRead < 0) {
- connection->d_func()->emitReplyError(socket, reply, QNetworkReply::RemoteHostClosedError);
- break;
- }
- } else if (!replyPrivate->isChunked() && !replyPrivate->autoDecompress
- && replyPrivate->bodyLength > 0) {
- // bulk files like images should fulfill these properties and
- // we can therefore save on memory copying
- qint64 haveRead = replyPrivate->readBodyFast(socket, &replyPrivate->responseData);
- bytes += haveRead;
- replyPrivate->totalProgress += haveRead;
- if (replyPrivate->shouldEmitSignals()) {
- emit reply->readyRead();
- emit reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
- }
- }
- else
- {
- // use the traditional slower reading (for compressed encoding, chunked encoding,
- // no content-length etc)
- qint64 haveRead = replyPrivate->readBody(socket, &replyPrivate->responseData);
- if (haveRead > 0) {
- bytes += haveRead;
- replyPrivate->totalProgress += haveRead;
- if (replyPrivate->shouldEmitSignals()) {
- emit reply->readyRead();
- emit reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
- }
- } else if (haveRead == -1) {
- // Some error occurred
- connection->d_func()->emitReplyError(socket, reply, QNetworkReply::ProtocolFailure);
- break;
- }
- }
- // still in ReadingDataState? This function will be called again by the socket's readyRead
- if (replyPrivate->state == QHttpNetworkReplyPrivate::ReadingDataState)
- break;
+ Q_ASSERT(!protocolHandler.isNull());
+ protocolHandler->_q_receiveReply();
+}
- // everything done, fall through
- }
- case QHttpNetworkReplyPrivate::AllDoneState:
- allDone();
- break;
- default:
- break;
- }
- } while (bytes != lastBytes && reply);
+void QHttpNetworkConnectionChannel::_q_readyRead()
+{
+ Q_ASSERT(!protocolHandler.isNull());
+ protocolHandler->_q_readyRead();
}
// called when unexpectedly reading a -1 or when data is expected but socket is closed
@@ -724,6 +400,7 @@ void QHttpNetworkConnectionChannel::allDone()
if (!resendCurrent) {
request = QHttpNetworkRequest();
reply = 0;
+ protocolHandler->setReply(0);
}
// move next from pipeline to current request
@@ -738,6 +415,7 @@ void QHttpNetworkConnectionChannel::allDone()
request = messagePair.first;
reply = messagePair.second;
+ protocolHandler->setReply(messagePair.second);
state = QHttpNetworkConnectionChannel::ReadingState;
resendCurrent = false;
@@ -982,32 +660,6 @@ bool QHttpNetworkConnectionChannel::isSocketReading() const
return (state & QHttpNetworkConnectionChannel::ReadingState);
}
-//private slots
-void QHttpNetworkConnectionChannel::_q_readyRead()
-{
- if (socket->state() == QAbstractSocket::ConnectedState && socket->bytesAvailable() == 0) {
- // We got a readyRead but no bytes are available..
- // This happens for the Unbuffered QTcpSocket
- // Also check if socket is in ConnectedState since
- // this function may also be invoked via the event loop.
- char c;
- qint64 ret = socket->peek(&c, 1);
- if (ret < 0) {
- _q_error(socket->error());
- // We still need to handle the reply so it emits its signals etc.
- if (reply)
- _q_receiveReply();
- return;
- }
- }
-
- if (isSocketWaiting() || isSocketReading()) {
- state = QHttpNetworkConnectionChannel::ReadingState;
- if (reply)
- _q_receiveReply();
- }
-}
-
void QHttpNetworkConnectionChannel::_q_bytesWritten(qint64 bytes)
{
Q_UNUSED(bytes);
@@ -1224,6 +876,8 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
reply->d_func()->errorString = errorString;
emit reply->finishedWithError(errorCode, errorString);
reply = 0;
+ if (protocolHandler)
+ protocolHandler->setReply(0);
}
// send the next request
QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index c8138b5453..7230eb2543 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -66,6 +66,7 @@
#include <private/qhttpnetworkreply_p.h>
#include <private/qhttpnetworkconnection_p.h>
+#include <private/qabstractprotocolhandler_p.h>
#ifndef QT_NO_HTTP
@@ -117,6 +118,7 @@ public:
QAuthenticator proxyAuthenticator;
bool authenticationCredentialsSent;
bool proxyCredentialsSent;
+ QScopedPointer<QAbstractProtocolHandler> protocolHandler;
#ifndef QT_NO_SSL
bool ignoreAllSslErrors;
QList<QSslError> ignoreSslErrorsList;
@@ -193,6 +195,8 @@ public:
void _q_sslErrors(const QList<QSslError> &errors); // ssl errors from the socket
void _q_encryptedBytesWritten(qint64 bytes); // proceed sending
#endif
+
+ friend class QHttpProtocolHandler;
};
QT_END_NAMESPACE
diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h
index 7aea9f14ec..583c3e426f 100644
--- a/src/network/access/qhttpnetworkreply_p.h
+++ b/src/network/access/qhttpnetworkreply_p.h
@@ -164,6 +164,7 @@ private:
friend class QHttpNetworkConnection;
friend class QHttpNetworkConnectionPrivate;
friend class QHttpNetworkConnectionChannel;
+ friend class QHttpProtocolHandler;
};
diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp
index d9f9b555d7..3786f9b992 100644
--- a/src/network/access/qhttpnetworkrequest.cpp
+++ b/src/network/access/qhttpnetworkrequest.cpp
@@ -87,9 +87,9 @@ bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &ot
&& (preConnect == other.preConnect);
}
-QByteArray QHttpNetworkRequestPrivate::methodName() const
+QByteArray QHttpNetworkRequest::methodName() const
{
- switch (operation) {
+ switch (d->operation) {
case QHttpNetworkRequest::Get:
return "GET";
case QHttpNetworkRequest::Head:
@@ -107,24 +107,24 @@ QByteArray QHttpNetworkRequestPrivate::methodName() const
case QHttpNetworkRequest::Connect:
return "CONNECT";
case QHttpNetworkRequest::Custom:
- return customVerb;
+ return d->customVerb;
default:
break;
}
return QByteArray();
}
-QByteArray QHttpNetworkRequestPrivate::uri(bool throughProxy) const
+QByteArray QHttpNetworkRequest::uri(bool throughProxy) const
{
QUrl::FormattingOptions format(QUrl::RemoveFragment | QUrl::RemoveUserInfo | QUrl::FullyEncoded);
// for POST, query data is send as content
- if (operation == QHttpNetworkRequest::Post && !uploadByteDevice)
+ if (d->operation == QHttpNetworkRequest::Post && !d->uploadByteDevice)
format |= QUrl::RemoveQuery;
// for requests through proxy, the Request-URI contains full url
if (!throughProxy)
format |= QUrl::RemoveScheme | QUrl::RemoveAuthority;
- QUrl copy = url;
+ QUrl copy = d->url;
if (copy.path().isEmpty())
copy.setPath(QStringLiteral("/"));
QByteArray uri = copy.toEncoded(format);
@@ -137,9 +137,9 @@ QByteArray QHttpNetworkRequestPrivate::header(const QHttpNetworkRequest &request
QByteArray ba;
ba.reserve(40 + fields.length()*25); // very rough lower bound estimation
- ba += request.d->methodName();
+ ba += request.methodName();
ba += ' ';
- ba += request.d->uri(throughProxy);
+ ba += request.uri(throughProxy);
ba += " HTTP/";
ba += QByteArray::number(request.majorVersion());
diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h
index ce9fbb1509..f224f7329d 100644
--- a/src/network/access/qhttpnetworkrequest_p.h
+++ b/src/network/access/qhttpnetworkrequest_p.h
@@ -126,11 +126,15 @@ public:
void setUploadByteDevice(QNonContiguousByteDevice *bd);
QNonContiguousByteDevice* uploadByteDevice() const;
+ QByteArray methodName() const;
+ QByteArray uri(bool throughProxy) const;
+
private:
QSharedDataPointer<QHttpNetworkRequestPrivate> d;
friend class QHttpNetworkRequestPrivate;
friend class QHttpNetworkConnectionPrivate;
friend class QHttpNetworkConnectionChannel;
+ friend class QHttpProtocolHandler;
};
class QHttpNetworkRequestPrivate : public QHttpNetworkHeaderPrivate
@@ -141,8 +145,6 @@ public:
QHttpNetworkRequestPrivate(const QHttpNetworkRequestPrivate &other);
~QHttpNetworkRequestPrivate();
bool operator==(const QHttpNetworkRequestPrivate &other) const;
- QByteArray methodName() const;
- QByteArray uri(bool throughProxy) const;
static QByteArray header(const QHttpNetworkRequest &request, bool throughProxy);
diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp
new file mode 100644
index 0000000000..15cba48285
--- /dev/null
+++ b/src/network/access/qhttpprotocolhandler.cpp
@@ -0,0 +1,431 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qhttpprotocolhandler_p.h>
+#include <private/qnoncontiguousbytedevice_p.h>
+#include <private/qhttpnetworkconnectionchannel_p.h>
+
+#ifndef QT_NO_HTTP
+
+QT_BEGIN_NAMESPACE
+
+QHttpProtocolHandler::QHttpProtocolHandler(QHttpNetworkConnectionChannel *channel)
+ : QAbstractProtocolHandler(channel)
+{
+}
+
+void QHttpProtocolHandler::_q_receiveReply()
+{
+ Q_ASSERT(m_socket);
+
+ if (!m_reply) {
+ if (m_socket->bytesAvailable() > 0)
+ qWarning() << "QAbstractProtocolHandler::_q_receiveReply() called without QHttpNetworkReply,"
+ << m_socket->bytesAvailable() << "bytes on socket.";
+ m_channel->close();
+ return;
+ }
+
+ // only run when the QHttpNetworkConnection is not currently being destructed, e.g.
+ // this function is called from _q_disconnected which is called because
+ // of ~QHttpNetworkConnectionPrivate
+ if (!qobject_cast<QHttpNetworkConnection*>(m_connection)) {
+ return;
+ }
+
+ QAbstractSocket::SocketState socketState = m_socket->state();
+
+ // connection might be closed to signal the end of data
+ if (socketState == QAbstractSocket::UnconnectedState) {
+ if (m_socket->bytesAvailable() <= 0) {
+ if (m_reply->d_func()->state == QHttpNetworkReplyPrivate::ReadingDataState) {
+ // finish this reply. this case happens when the server did not send a content length
+ m_reply->d_func()->state = QHttpNetworkReplyPrivate::AllDoneState;
+ m_channel->allDone();
+ return;
+ } else {
+ m_channel->handleUnexpectedEOF();
+ return;
+ }
+ } else {
+ // socket not connected but still bytes for reading.. just continue in this function
+ }
+ }
+
+ // read loop for the response
+ qint64 bytes = 0;
+ qint64 lastBytes = bytes;
+ do {
+ lastBytes = bytes;
+
+ QHttpNetworkReplyPrivate::ReplyState state = m_reply->d_func()->state;
+ switch (state) {
+ case QHttpNetworkReplyPrivate::NothingDoneState: {
+ m_reply->d_func()->state = QHttpNetworkReplyPrivate::ReadingStatusState;
+ // fallthrough
+ }
+ case QHttpNetworkReplyPrivate::ReadingStatusState: {
+ qint64 statusBytes = m_reply->d_func()->readStatus(m_socket);
+ if (statusBytes == -1) {
+ // connection broke while reading status. also handled if later _q_disconnected is called
+ m_channel->handleUnexpectedEOF();
+ return;
+ }
+ bytes += statusBytes;
+ m_channel->lastStatus = m_reply->d_func()->statusCode;
+ break;
+ }
+ case QHttpNetworkReplyPrivate::ReadingHeaderState: {
+ QHttpNetworkReplyPrivate *replyPrivate = m_reply->d_func();
+ qint64 headerBytes = replyPrivate->readHeader(m_socket);
+ if (headerBytes == -1) {
+ // connection broke while reading headers. also handled if later _q_disconnected is called
+ m_channel->handleUnexpectedEOF();
+ return;
+ }
+ bytes += headerBytes;
+ // If headers were parsed successfully now it is the ReadingDataState
+ if (replyPrivate->state == QHttpNetworkReplyPrivate::ReadingDataState) {
+ if (replyPrivate->isCompressed() && replyPrivate->autoDecompress) {
+ // remove the Content-Length from header
+ replyPrivate->removeAutoDecompressHeader();
+ } else {
+ replyPrivate->autoDecompress = false;
+ }
+ if (replyPrivate->statusCode == 100) {
+ replyPrivate->clearHttpLayerInformation();
+ replyPrivate->state = QHttpNetworkReplyPrivate::ReadingStatusState;
+ break; // ignore
+ }
+ if (replyPrivate->shouldEmitSignals())
+ emit m_reply->headerChanged();
+ // After headerChanged had been emitted
+ // we can suddenly have a replyPrivate->userProvidedDownloadBuffer
+ // this is handled in the ReadingDataState however
+
+ if (!replyPrivate->expectContent()) {
+ replyPrivate->state = QHttpNetworkReplyPrivate::AllDoneState;
+ m_channel->allDone();
+ break;
+ }
+ }
+ break;
+ }
+ case QHttpNetworkReplyPrivate::ReadingDataState: {
+ QHttpNetworkReplyPrivate *replyPrivate = m_reply->d_func();
+ if (m_socket->state() == QAbstractSocket::ConnectedState &&
+ replyPrivate->downstreamLimited && !replyPrivate->responseData.isEmpty() && replyPrivate->shouldEmitSignals()) {
+ // (only do the following when still connected, not when we have already been disconnected and there is still data)
+ // We already have some HTTP body data. We don't read more from the socket until
+ // this is fetched by QHttpNetworkAccessHttpBackend. If we would read more,
+ // we could not limit our read buffer usage.
+ // We only do this when shouldEmitSignals==true because our HTTP parsing
+ // always needs to parse the 401/407 replies. Therefore they don't really obey
+ // to the read buffer maximum size, but we don't care since they should be small.
+ return;
+ }
+
+ if (replyPrivate->userProvidedDownloadBuffer) {
+ // the user provided a direct buffer where we should put all our data in.
+ // this only works when we can tell the user the content length and he/she can allocate
+ // the buffer in that size.
+ // note that this call will read only from the still buffered data
+ qint64 haveRead = replyPrivate->readBodyVeryFast(m_socket, replyPrivate->userProvidedDownloadBuffer + replyPrivate->totalProgress);
+ if (haveRead > 0) {
+ bytes += haveRead;
+ replyPrivate->totalProgress += haveRead;
+ // the user will get notified of it via progress signal
+ emit m_reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
+ } else if (haveRead == 0) {
+ // Happens since this called in a loop. Currently no bytes available.
+ } else if (haveRead < 0) {
+ m_connection->d_func()->emitReplyError(m_socket, m_reply, QNetworkReply::RemoteHostClosedError);
+ break;
+ }
+ } else if (!replyPrivate->isChunked() && !replyPrivate->autoDecompress
+ && replyPrivate->bodyLength > 0) {
+ // bulk files like images should fulfill these properties and
+ // we can therefore save on memory copying
+ qint64 haveRead = replyPrivate->readBodyFast(m_socket, &replyPrivate->responseData);
+ bytes += haveRead;
+ replyPrivate->totalProgress += haveRead;
+ if (replyPrivate->shouldEmitSignals()) {
+ emit m_reply->readyRead();
+ emit m_reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
+ }
+ }
+ else
+ {
+ // use the traditional slower reading (for compressed encoding, chunked encoding,
+ // no content-length etc)
+ qint64 haveRead = replyPrivate->readBody(m_socket, &replyPrivate->responseData);
+ if (haveRead > 0) {
+ bytes += haveRead;
+ replyPrivate->totalProgress += haveRead;
+ if (replyPrivate->shouldEmitSignals()) {
+ emit m_reply->readyRead();
+ emit m_reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
+ }
+ } else if (haveRead == -1) {
+ // Some error occurred
+ m_connection->d_func()->emitReplyError(m_socket, m_reply, QNetworkReply::ProtocolFailure);
+ break;
+ }
+ }
+ // still in ReadingDataState? This function will be called again by the socket's readyRead
+ if (replyPrivate->state == QHttpNetworkReplyPrivate::ReadingDataState)
+ break;
+
+ // everything done, fall through
+ }
+ case QHttpNetworkReplyPrivate::AllDoneState:
+ m_channel->allDone();
+ break;
+ default:
+ break;
+ }
+ } while (bytes != lastBytes && m_reply);
+}
+
+void QHttpProtocolHandler::_q_readyRead()
+{
+ if (m_socket->state() == QAbstractSocket::ConnectedState && m_socket->bytesAvailable() == 0) {
+ // We got a readyRead but no bytes are available..
+ // This happens for the Unbuffered QTcpSocket
+ // Also check if socket is in ConnectedState since
+ // this function may also be invoked via the event loop.
+ char c;
+ qint64 ret = m_socket->peek(&c, 1);
+ if (ret < 0) {
+ m_channel->_q_error(m_socket->error());
+ // We still need to handle the reply so it emits its signals etc.
+ if (m_reply)
+ _q_receiveReply();
+ return;
+ }
+ }
+
+ if (m_channel->isSocketWaiting() || m_channel->isSocketReading()) {
+ m_channel->state = QHttpNetworkConnectionChannel::ReadingState;
+ if (m_reply)
+ _q_receiveReply();
+ }
+}
+
+bool QHttpProtocolHandler::sendRequest()
+{
+ m_reply = m_channel->reply;
+
+ if (!m_reply) {
+ // heh, how should that happen!
+ qWarning() << "QAbstractProtocolHandler::sendRequest() called without QHttpNetworkReply";
+ m_channel->state = QHttpNetworkConnectionChannel::IdleState;
+ return false;
+ }
+
+ switch (m_channel->state) {
+ case QHttpNetworkConnectionChannel::IdleState: { // write the header
+ if (!m_channel->ensureConnection()) {
+ // wait for the connection (and encryption) to be done
+ // sendRequest will be called again from either
+ // _q_connected or _q_encrypted
+ return false;
+ }
+ QString scheme = m_channel->request.url().scheme();
+ if (scheme == QLatin1String("preconnect-http")
+ || scheme == QLatin1String("preconnect-https")) {
+ m_channel->state = QHttpNetworkConnectionChannel::IdleState;
+ m_reply->d_func()->state = QHttpNetworkReplyPrivate::AllDoneState;
+ m_channel->allDone();
+ m_connection->preConnectFinished(); // will only decrease the counter
+ m_reply = 0; // so we can reuse this channel
+ return true; // we have a working connection and are done
+ }
+
+ m_channel->written = 0; // excluding the header
+ m_channel->bytesTotal = 0;
+
+ QHttpNetworkReplyPrivate *replyPrivate = m_reply->d_func();
+ replyPrivate->clear();
+ replyPrivate->connection = m_connection;
+ replyPrivate->connectionChannel = m_channel;
+ replyPrivate->autoDecompress = m_channel->request.d->autoDecompress;
+ replyPrivate->pipeliningUsed = false;
+
+ // if the url contains authentication parameters, use the new ones
+ // both channels will use the new authentication parameters
+ if (!m_channel->request.url().userInfo().isEmpty() && m_channel->request.withCredentials()) {
+ QUrl url = m_channel->request.url();
+ QAuthenticator &auth = m_channel->authenticator;
+ if (url.userName() != auth.user()
+ || (!url.password().isEmpty() && url.password() != auth.password())) {
+ auth.setUser(url.userName());
+ auth.setPassword(url.password());
+ m_connection->d_func()->copyCredentials(m_connection->d_func()->indexOf(m_socket), &auth, false);
+ }
+ // clear the userinfo, since we use the same request for resending
+ // userinfo in url can conflict with the one in the authenticator
+ url.setUserInfo(QString());
+ m_channel->request.setUrl(url);
+ }
+ // Will only be false if Qt WebKit is performing a cross-origin XMLHttpRequest
+ // and withCredentials has not been set to true.
+ if (m_channel->request.withCredentials())
+ m_connection->d_func()->createAuthorization(m_socket, m_channel->request);
+#ifndef QT_NO_NETWORKPROXY
+ QByteArray header = QHttpNetworkRequestPrivate::header(m_channel->request,
+ (m_connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy));
+#else
+ QByteArray header = QHttpNetworkRequestPrivate::header(m_channel->request, false);
+#endif
+ m_socket->write(header);
+ // flushing is dangerous (QSslSocket calls transmit which might read or error)
+// m_socket->flush();
+ QNonContiguousByteDevice* uploadByteDevice = m_channel->request.uploadByteDevice();
+ if (uploadByteDevice) {
+ // connect the signals so this function gets called again
+ QObject::connect(uploadByteDevice, SIGNAL(readyRead()), m_channel, SLOT(_q_uploadDataReadyRead()));
+
+ m_channel->bytesTotal = m_channel->request.contentLength();
+
+ m_channel->state = QHttpNetworkConnectionChannel::WritingState; // start writing data
+ sendRequest(); //recurse
+ } else {
+ m_channel->state = QHttpNetworkConnectionChannel::WaitingState; // now wait for response
+ sendRequest(); //recurse
+ }
+
+ break;
+ }
+ case QHttpNetworkConnectionChannel::WritingState:
+ {
+ // write the data
+ QNonContiguousByteDevice* uploadByteDevice = m_channel->request.uploadByteDevice();
+ if (!uploadByteDevice || m_channel->bytesTotal == m_channel->written) {
+ if (uploadByteDevice)
+ emit m_reply->dataSendProgress(m_channel->written, m_channel->bytesTotal);
+ m_channel->state = QHttpNetworkConnectionChannel::WaitingState; // now wait for response
+ sendRequest(); // recurse
+ break;
+ }
+
+ // only feed the QTcpSocket buffer when there is less than 32 kB in it
+ const qint64 socketBufferFill = 32*1024;
+ const qint64 socketWriteMaxSize = 16*1024;
+
+
+#ifndef QT_NO_SSL
+ QSslSocket *sslSocket = qobject_cast<QSslSocket*>(m_socket);
+ // if it is really an ssl socket, check more than just bytesToWrite()
+ while ((m_socket->bytesToWrite() + (sslSocket ? sslSocket->encryptedBytesToWrite() : 0))
+ <= socketBufferFill && m_channel->bytesTotal != m_channel->written)
+#else
+ while (m_socket->bytesToWrite() <= socketBufferFill
+ && m_channel->bytesTotal != m_channel->written)
+#endif
+ {
+ // get pointer to upload data
+ qint64 currentReadSize = 0;
+ qint64 desiredReadSize = qMin(socketWriteMaxSize, m_channel->bytesTotal - m_channel->written);
+ const char *readPointer = uploadByteDevice->readPointer(desiredReadSize, currentReadSize);
+
+ if (currentReadSize == -1) {
+ // premature eof happened
+ m_connection->d_func()->emitReplyError(m_socket, m_reply, QNetworkReply::UnknownNetworkError);
+ return false;
+ } else if (readPointer == 0 || currentReadSize == 0) {
+ // nothing to read currently, break the loop
+ break;
+ } else {
+ qint64 currentWriteSize = m_socket->write(readPointer, currentReadSize);
+ if (currentWriteSize == -1 || currentWriteSize != currentReadSize) {
+ // socket broke down
+ m_connection->d_func()->emitReplyError(m_socket, m_reply, QNetworkReply::UnknownNetworkError);
+ return false;
+ } else {
+ m_channel->written += currentWriteSize;
+ uploadByteDevice->advanceReadPointer(currentWriteSize);
+
+ emit m_reply->dataSendProgress(m_channel->written, m_channel->bytesTotal);
+
+ if (m_channel->written == m_channel->bytesTotal) {
+ // make sure this function is called once again
+ m_channel->state = QHttpNetworkConnectionChannel::WaitingState;
+ sendRequest();
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ case QHttpNetworkConnectionChannel::WaitingState:
+ {
+ QNonContiguousByteDevice* uploadByteDevice = m_channel->request.uploadByteDevice();
+ if (uploadByteDevice) {
+ QObject::disconnect(uploadByteDevice, SIGNAL(readyRead()), m_channel, SLOT(_q_uploadDataReadyRead()));
+ }
+
+ // HTTP pipelining
+ //m_connection->d_func()->fillPipeline(m_socket);
+ //m_socket->flush();
+
+ // ensure we try to receive a reply in all cases, even if _q_readyRead_ hat not been called
+ // this is needed if the sends an reply before we have finished sending the request. In that
+ // case receiveReply had been called before but ignored the server reply
+ if (m_socket->bytesAvailable())
+ QMetaObject::invokeMethod(m_channel, "_q_receiveReply", Qt::QueuedConnection);
+ break;
+ }
+ case QHttpNetworkConnectionChannel::ReadingState:
+ // ignore _q_bytesWritten in these states
+ // fall through
+ default:
+ break;
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
diff --git a/src/network/access/qhttpprotocolhandler_p.h b/src/network/access/qhttpprotocolhandler_p.h
new file mode 100644
index 0000000000..2bbc044b6c
--- /dev/null
+++ b/src/network/access/qhttpprotocolhandler_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHTTPPROTOCOLHANDLER_H
+#define QHTTPPROTOCOLHANDLER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qabstractprotocolhandler_p.h>
+
+#ifndef QT_NO_HTTP
+
+QT_BEGIN_NAMESPACE
+
+class QHttpProtocolHandler : public QAbstractProtocolHandler {
+public:
+ QHttpProtocolHandler(QHttpNetworkConnectionChannel *channel);
+
+private:
+ virtual void _q_receiveReply() Q_DECL_OVERRIDE;
+ virtual void _q_readyRead() Q_DECL_OVERRIDE;
+ virtual bool sendRequest() Q_DECL_OVERRIDE;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
+
+#endif
diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp
index ee3911c72c..b7e8bb3f72 100644
--- a/src/network/access/qhttpthreaddelegate.cpp
+++ b/src/network/access/qhttpthreaddelegate.cpp
@@ -60,6 +60,10 @@ static QNetworkReply::NetworkError statusCodeFromHttp(int httpStatusCode, const
QNetworkReply::NetworkError code;
// we've got an error
switch (httpStatusCode) {
+ case 400: // Bad Request
+ code = QNetworkReply::ProtocolInvalidOperationError;
+ break;
+
case 401: // Authorization required
code = QNetworkReply::AuthenticationRequiredError;
break;
@@ -80,15 +84,34 @@ static QNetworkReply::NetworkError statusCodeFromHttp(int httpStatusCode, const
code = QNetworkReply::ProxyAuthenticationRequiredError;
break;
+ case 409: // Resource Conflict
+ code = QNetworkReply::ContentConflictError;
+ break;
+
+ case 410: // Content no longer available
+ code = QNetworkReply::ContentGoneError;
+ break;
+
case 418: // I'm a teapot
code = QNetworkReply::ProtocolInvalidOperationError;
break;
+ case 500: // Internal Server Error
+ code = QNetworkReply::InternalServerError;
+ break;
+
+ case 501: // Server does not support this functionality
+ code = QNetworkReply::OperationNotImplementedError;
+ break;
+
+ case 503: // Service unavailable
+ code = QNetworkReply::ServiceUnavailableError;
+ break;
default:
if (httpStatusCode > 500) {
// some kind of server error
- code = QNetworkReply::ProtocolUnknownError;
+ code = QNetworkReply::UnknownServerError;
} else if (httpStatusCode >= 400) {
// content error we did not handle above
code = QNetworkReply::UnknownContentError;
diff --git a/src/network/access/qnetworkcookie.cpp b/src/network/access/qnetworkcookie.cpp
index a871c04d56..664bc8282c 100644
--- a/src/network/access/qnetworkcookie.cpp
+++ b/src/network/access/qnetworkcookie.cpp
@@ -51,6 +51,7 @@
#include "QtCore/qstring.h"
#include "QtCore/qstringlist.h"
#include "QtCore/qurl.h"
+#include "QtNetwork/qhostaddress.h"
#include "private/qobject_p.h"
QT_BEGIN_NAMESPACE
@@ -466,12 +467,19 @@ QByteArray QNetworkCookie::toRawForm(RawForm form) const
}
if (!d->domain.isEmpty()) {
result += "; domain=";
- QString domainNoDot = d->domain;
- if (domainNoDot.startsWith(QLatin1Char('.'))) {
+ if (d->domain.startsWith(QLatin1Char('.'))) {
result += '.';
- domainNoDot = domainNoDot.mid(1);
+ result += QUrl::toAce(d->domain.mid(1));
+ } else {
+ QHostAddress hostAddr(d->domain);
+ if (hostAddr.protocol() == QAbstractSocket::IPv6Protocol) {
+ result += '[';
+ result += d->domain.toUtf8();
+ result += ']';
+ } else {
+ result += QUrl::toAce(d->domain);
+ }
}
- result += QUrl::toAce(domainNoDot);
}
if (!d->path.isEmpty()) {
result += "; path=";
@@ -1015,14 +1023,20 @@ void QNetworkCookie::normalize(const QUrl &url)
d->path = defaultPath;
}
- if (d->domain.isEmpty())
+ if (d->domain.isEmpty()) {
d->domain = url.host();
- else if (!d->domain.startsWith(QLatin1Char('.')))
- // Ensure the domain starts with a dot if its field was not empty
- // in the HTTP header. There are some servers that forget the
- // leading dot and this is actually forbidden according to RFC 2109,
- // but all browsers accept it anyway so we do that as well.
- d->domain.prepend(QLatin1Char('.'));
+ } else {
+ QHostAddress hostAddress(d->domain);
+ if (hostAddress.protocol() != QAbstractSocket::IPv4Protocol
+ && hostAddress.protocol() != QAbstractSocket::IPv6Protocol
+ && !d->domain.startsWith(QLatin1Char('.'))) {
+ // Ensure the domain starts with a dot if its field was not empty
+ // in the HTTP header. There are some servers that forget the
+ // leading dot and this is actually forbidden according to RFC 2109,
+ // but all browsers accept it anyway so we do that as well.
+ d->domain.prepend(QLatin1Char('.'));
+ }
+ }
}
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp
index ba6f706f7a..faa8464463 100644
--- a/src/network/access/qnetworkreply.cpp
+++ b/src/network/access/qnetworkreply.cpp
@@ -173,6 +173,21 @@ QNetworkReplyPrivate::QNetworkReplyPrivate()
again, but this failed for example because the upload data
could not be read a second time.
+ \value ContentConflictError the request could not be completed due
+ to a conflict with the current state of the resource.
+
+ \value ContentGoneError the requested resource is no longer
+ available at the server.
+
+ \value InternalServerError the server encountered an unexpected
+ condition which prevented it from fulfilling the request.
+
+ \value OperationNotImplementedError the server does not support the
+ functionality required to fulfill the request.
+
+ \value ServiceUnavailableError the server is unable to handle the
+ request at this time.
+
\value ProtocolUnknownError the Network Access API cannot
honor the request because the protocol is not known
@@ -191,6 +206,9 @@ QNetworkReplyPrivate::QNetworkReplyPrivate()
\value ProtocolFailure a breakdown in protocol was
detected (parsing error, invalid or unexpected responses, etc.)
+ \value UnknownServerError an unknown error related to
+ the server response was detected
+
\sa error()
*/
diff --git a/src/network/access/qnetworkreply.h b/src/network/access/qnetworkreply.h
index a7db2d189c..f11a5e816a 100644
--- a/src/network/access/qnetworkreply.h
+++ b/src/network/access/qnetworkreply.h
@@ -93,12 +93,20 @@ public:
ContentNotFoundError,
AuthenticationRequiredError,
ContentReSendError,
+ ContentConflictError,
+ ContentGoneError,
UnknownContentError = 299,
// protocol errors
ProtocolUnknownError = 301,
ProtocolInvalidOperationError,
- ProtocolFailure = 399
+ ProtocolFailure = 399,
+
+ // Server side errors (401-499)
+ InternalServerError = 401,
+ OperationNotImplementedError,
+ ServiceUnavailableError,
+ UnknownServerError = 499
};
~QNetworkReply();
diff --git a/src/network/doc/snippets/network/tcpwait.cpp b/src/network/doc/snippets/network/tcpwait.cpp
index fb44e2ded9..e5e4c1ed40 100644
--- a/src/network/doc/snippets/network/tcpwait.cpp
+++ b/src/network/doc/snippets/network/tcpwait.cpp
@@ -55,13 +55,13 @@ int main(int argv, char **args)
char buffer[50];
forever {
- numRead = socket.read(buffer, 50);
+ numRead = socket.read(buffer, 50);
- // do whatever with array
+ // do whatever with array
- numReadTotal += numRead;
+ numReadTotal += numRead;
if (numRead == 0 && !socket.waitForReadyRead())
- break;
+ break;
}
//! [0]
diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri
index 97f52fdb6e..9b584be206 100644
--- a/src/network/kernel/kernel.pri
+++ b/src/network/kernel/kernel.pri
@@ -33,9 +33,17 @@ android {
}
win32: {
- HEADERS += kernel/qnetworkinterface_win_p.h
- SOURCES += kernel/qdnslookup_win.cpp kernel/qhostinfo_win.cpp kernel/qnetworkinterface_win.cpp
- LIBS_PRIVATE += -ldnsapi
+ !winrt {
+ HEADERS += kernel/qnetworkinterface_win_p.h
+ SOURCES += kernel/qdnslookup_win.cpp \
+ kernel/qhostinfo_win.cpp \
+ kernel/qnetworkinterface_win.cpp
+ LIBS_PRIVATE += -ldnsapi
+ } else {
+ SOURCES += kernel/qdnslookup_winrt.cpp \
+ kernel/qhostinfo_winrt.cpp \
+ kernel/qnetworkinterface_winrt.cpp
+ }
}
integrity:SOURCES += kernel/qdnslookup_unix.cpp kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp
diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp
index 8c16486878..edbbbf5a75 100644
--- a/src/network/kernel/qauthenticator.cpp
+++ b/src/network/kernel/qauthenticator.cpp
@@ -55,9 +55,11 @@
#include <qmutex.h>
#include <private/qmutexpool_p.h>
#include <rpc.h>
+#ifndef Q_OS_WINRT
#define SECURITY_WIN32 1
#include <security.h>
#endif
+#endif
//#define NTLMV1_CLIENT
@@ -69,7 +71,7 @@ QT_BEGIN_NAMESPACE
static QByteArray qNtlmPhase1();
static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phase2data);
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
static QByteArray qNtlmPhase1_SSPI(QAuthenticatorPrivate *ctx);
static QByteArray qNtlmPhase3_SSPI(QAuthenticatorPrivate *ctx, const QByteArray& phase2data);
#endif
@@ -328,7 +330,7 @@ bool QAuthenticator::isNull() const
return !d;
}
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
class QNtlmWindowsHandles
{
public:
@@ -340,7 +342,7 @@ public:
QAuthenticatorPrivate::QAuthenticatorPrivate()
: method(None)
- #ifdef Q_OS_WIN
+ #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
, ntlmWindowsHandles(0)
#endif
, hasFailed(false)
@@ -354,7 +356,7 @@ QAuthenticatorPrivate::QAuthenticatorPrivate()
QAuthenticatorPrivate::~QAuthenticatorPrivate()
{
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
if (ntlmWindowsHandles)
delete ntlmWindowsHandles;
#endif
@@ -485,7 +487,7 @@ QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMet
case QAuthenticatorPrivate::Ntlm:
methodString = "NTLM ";
if (challenge.isEmpty()) {
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
QByteArray phase1Token;
if (user.isEmpty()) // Only pull from system if no user was specified in authenticator
phase1Token = qNtlmPhase1_SSPI(this);
@@ -502,7 +504,7 @@ QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMet
phase = Phase2;
}
} else {
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
QByteArray phase3Token;
if (ntlmWindowsHandles)
phase3Token = qNtlmPhase3_SSPI(this, QByteArray::fromBase64(challenge));
@@ -1475,7 +1477,7 @@ static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phas
return rc;
}
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
// See http://davenport.sourceforge.net/ntlm.html
// and libcurl http_ntlm.c
@@ -1513,7 +1515,6 @@ static bool q_NTLM_SSPI_library_load()
return true;
}
-#ifdef Q_OS_WIN
// Phase 1:
static QByteArray qNtlmPhase1_SSPI(QAuthenticatorPrivate *ctx)
{
@@ -1631,8 +1632,6 @@ static QByteArray qNtlmPhase3_SSPI(QAuthenticatorPrivate *ctx, const QByteArray&
return result;
}
-#endif // Q_OS_WIN
-
-#endif
+#endif // Q_OS_WIN && !Q_OS_WINRT
QT_END_NAMESPACE
diff --git a/src/network/kernel/qdnslookup.cpp b/src/network/kernel/qdnslookup.cpp
index 53675d083b..97a402901e 100644
--- a/src/network/kernel/qdnslookup.cpp
+++ b/src/network/kernel/qdnslookup.cpp
@@ -363,6 +363,25 @@ void QDnsLookup::setType(Type type)
}
/*!
+ \property QDnsLookup::nameserver
+ \brief the nameserver to use for DNS lookup.
+*/
+
+QHostAddress QDnsLookup::nameserver() const
+{
+ return d_func()->nameserver;
+}
+
+void QDnsLookup::setNameserver(const QHostAddress &nameserver)
+{
+ Q_D(QDnsLookup);
+ if (nameserver != d->nameserver) {
+ d->nameserver = nameserver;
+ emit nameserverChanged(nameserver);
+ }
+}
+
+/*!
Returns the list of canonical name records associated with this lookup.
*/
@@ -463,7 +482,7 @@ void QDnsLookup::lookup()
Q_D(QDnsLookup);
d->isFinished = false;
d->reply = QDnsLookupReply();
- d->runnable = new QDnsLookupRunnable(d->type, QUrl::toAce(d->name));
+ d->runnable = new QDnsLookupRunnable(d->type, QUrl::toAce(d->name), d->nameserver);
connect(d->runnable, SIGNAL(finished(QDnsLookupReply)),
this, SLOT(_q_lookupFinished(QDnsLookupReply)),
Qt::BlockingQueuedConnection);
@@ -971,7 +990,7 @@ void QDnsLookupRunnable::run()
}
// Perform request.
- query(requestType, requestName, &reply);
+ query(requestType, requestName, nameserver, &reply);
// Sort results.
if (!theDnsLookupSeedStorage()->hasLocalData()) {
diff --git a/src/network/kernel/qdnslookup.h b/src/network/kernel/qdnslookup.h
index 1df21d866e..ffbef61f92 100644
--- a/src/network/kernel/qdnslookup.h
+++ b/src/network/kernel/qdnslookup.h
@@ -180,6 +180,7 @@ class Q_NETWORK_EXPORT QDnsLookup : public QObject
Q_PROPERTY(QString errorString READ errorString NOTIFY finished)
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(Type type READ type WRITE setType NOTIFY typeChanged)
+ Q_PROPERTY(QHostAddress nameserver READ nameserver WRITE setNameserver NOTIFY nameserverChanged)
public:
enum Error
@@ -209,6 +210,7 @@ public:
explicit QDnsLookup(QObject *parent = 0);
QDnsLookup(Type type, const QString &name, QObject *parent = 0);
+ QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent = 0);
~QDnsLookup();
Error error() const;
@@ -221,6 +223,9 @@ public:
Type type() const;
void setType(QDnsLookup::Type);
+ QHostAddress nameserver() const;
+ void setNameserver(const QHostAddress &nameserver);
+
QList<QDnsDomainNameRecord> canonicalNameRecords() const;
QList<QDnsHostAddressRecord> hostAddressRecords() const;
QList<QDnsMailExchangeRecord> mailExchangeRecords() const;
@@ -238,6 +243,7 @@ Q_SIGNALS:
void finished();
void nameChanged(const QString &name);
void typeChanged(Type type);
+ void nameserverChanged(const QHostAddress &nameserver);
private:
Q_DECLARE_PRIVATE(QDnsLookup)
diff --git a/src/network/kernel/qdnslookup_android.cpp b/src/network/kernel/qdnslookup_android.cpp
index dff81dba0c..1ace5727c2 100644
--- a/src/network/kernel/qdnslookup_android.cpp
+++ b/src/network/kernel/qdnslookup_android.cpp
@@ -43,10 +43,11 @@
QT_BEGIN_NAMESPACE
-void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply)
+void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply)
{
Q_UNUSED(requestType);
Q_UNUSED(requestName);
+ Q_UNUSED(nameserver);
Q_UNUSED(reply);
qWarning() << Q_FUNC_INFO << "Not yet supported on Android";
reply->error = QDnsLookup::ResolverError;
diff --git a/src/network/kernel/qdnslookup_p.h b/src/network/kernel/qdnslookup_p.h
index 692b9088fe..7c0b0e862a 100644
--- a/src/network/kernel/qdnslookup_p.h
+++ b/src/network/kernel/qdnslookup_p.h
@@ -100,6 +100,7 @@ public:
bool isFinished;
QString name;
QDnsLookup::Type type;
+ QHostAddress nameserver;
QDnsLookupReply reply;
QDnsLookupRunnable *runnable;
@@ -111,9 +112,10 @@ class QDnsLookupRunnable : public QObject, public QRunnable
Q_OBJECT
public:
- QDnsLookupRunnable(QDnsLookup::Type type, const QByteArray &name)
+ QDnsLookupRunnable(QDnsLookup::Type type, const QByteArray &name, const QHostAddress &nameserver)
: requestType(type)
, requestName(name)
+ , nameserver(nameserver)
{ }
void run();
@@ -121,9 +123,10 @@ signals:
void finished(const QDnsLookupReply &reply);
private:
- static void query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply);
+ static void query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply);
QDnsLookup::Type requestType;
QByteArray requestName;
+ QHostAddress nameserver;
};
class QDnsLookupThreadPool : public QThreadPool
diff --git a/src/network/kernel/qdnslookup_unix.cpp b/src/network/kernel/qdnslookup_unix.cpp
index 9fb488cee6..26834dff57 100644
--- a/src/network/kernel/qdnslookup_unix.cpp
+++ b/src/network/kernel/qdnslookup_unix.cpp
@@ -115,7 +115,7 @@ static void resolveLibrary()
local_res_nquery = res_nquery_proto(lib.resolve("res_nquery"));
}
-void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply)
+void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply)
{
// Load dn_expand, res_ninit and res_nquery on demand.
static QBasicAtomicInt triedResolve = Q_BASIC_ATOMIC_INITIALIZER(false);
@@ -142,6 +142,43 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
reply->errorString = tr("Resolver initialization failed");
return;
}
+
+ //Check if a nameserver was set. If so, use it
+ if (!nameserver.isNull()) {
+ if (nameserver.protocol() == QAbstractSocket::IPv4Protocol) {
+ state.nsaddr_list[0].sin_addr.s_addr = htonl(nameserver.toIPv4Address());
+ state.nscount = 1;
+ } else if (nameserver.protocol() == QAbstractSocket::IPv6Protocol) {
+#if defined(Q_OS_LINUX)
+ struct sockaddr_in6 *ns;
+ ns = state._u._ext.nsaddrs[0];
+ // nsaddrs will be NULL if no nameserver is set in /etc/resolv.conf
+ if (!ns) {
+ // Memory allocated here will be free'd in res_close() as we
+ // have done res_init() above.
+ ns = (struct sockaddr_in6*) calloc(1, sizeof(struct sockaddr_in6));
+ Q_CHECK_PTR(ns);
+ state._u._ext.nsaddrs[0] = ns;
+ }
+ // Set nsmap[] to indicate that nsaddrs[0] is an IPv6 address
+ // See: https://sourceware.org/ml/libc-hacker/2002-05/msg00035.html
+ state._u._ext.nsmap[0] = MAXNS + 1;
+ state._u._ext.nscount6 = 1;
+ ns->sin6_family = AF_INET6;
+ ns->sin6_port = htons(53);
+
+ Q_IPV6ADDR ipv6Address = nameserver.toIPv6Address();
+ for (int i=0; i<16; i++) {
+ ns->sin6_addr.s6_addr[i] = ipv6Address[i];
+ }
+#else
+ qWarning() << Q_FUNC_INFO << "IPv6 addresses for nameservers is currently not supported";
+ reply->error = QDnsLookup::ResolverError;
+ reply->errorString = tr("IPv6 addresses for nameservers is currently not supported");
+ return;
+#endif
+ }
+ }
#ifdef QDNSLOOKUP_DEBUG
state.options |= RES_DEBUG;
#endif
diff --git a/src/network/kernel/qdnslookup_win.cpp b/src/network/kernel/qdnslookup_win.cpp
index bf80a23297..6f58e64440 100644
--- a/src/network/kernel/qdnslookup_win.cpp
+++ b/src/network/kernel/qdnslookup_win.cpp
@@ -48,15 +48,33 @@
#include <qt_windows.h>
#include <windns.h>
+#include <memory.h>
QT_BEGIN_NAMESPACE
-void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply)
+void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply)
{
// Perform DNS query.
PDNS_RECORD dns_records = 0;
const QString requestNameUtf16 = QString::fromUtf8(requestName.data(), requestName.size());
- const DNS_STATUS status = DnsQuery_W(reinterpret_cast<const wchar_t*>(requestNameUtf16.utf16()), requestType, DNS_QUERY_STANDARD, NULL, &dns_records, NULL);
+ IP4_ARRAY srvList;
+ memset(&srvList, 0, sizeof(IP4_ARRAY));
+ if (!nameserver.isNull()) {
+ if (nameserver.protocol() == QAbstractSocket::IPv4Protocol) {
+ // The below code is referenced from: http://support.microsoft.com/kb/831226
+ srvList.AddrCount = 1;
+ srvList.AddrArray[0] = htonl(nameserver.toIPv4Address());
+ } else if (nameserver.protocol() == QAbstractSocket::IPv6Protocol) {
+ // For supoprting IPv6 nameserver addresses, we'll need to switch
+ // from DnsQuey() to DnsQueryEx() as it supports passing an IPv6
+ // address in the nameserver list
+ qWarning() << Q_FUNC_INFO << "IPv6 addresses for nameservers is currently not supported";
+ reply->error = QDnsLookup::ResolverError;
+ reply->errorString = tr("IPv6 addresses for nameservers is currently not supported");
+ return;
+ }
+ }
+ const DNS_STATUS status = DnsQuery_W(reinterpret_cast<const wchar_t*>(requestNameUtf16.utf16()), requestType, DNS_QUERY_STANDARD, &srvList, &dns_records, NULL);
switch (status) {
case ERROR_SUCCESS:
break;
diff --git a/src/network/kernel/qdnslookup_winrt.cpp b/src/network/kernel/qdnslookup_winrt.cpp
new file mode 100644
index 0000000000..6ac944934a
--- /dev/null
+++ b/src/network/kernel/qdnslookup_winrt.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdnslookup_p.h"
+
+#include <qurl.h>
+#include <qdebug.h>
+
+#include <wrl.h>
+#include <windows.foundation.h>
+#include <windows.foundation.collections.h>
+#include <windows.networking.h>
+#include <windows.networking.sockets.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Foundation::Collections;
+using namespace ABI::Windows::Networking;
+using namespace ABI::Windows::Networking::Connectivity;
+using namespace ABI::Windows::Networking::Sockets;
+
+QT_BEGIN_NAMESPACE
+
+void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply)
+{
+ // TODO: Add nameserver support for winRT
+ if (!nameserver.isNull())
+ qWarning() << "Ignoring nameserver as its currently not supported on WinRT";
+
+ // TODO: is there any way to do "proper" dns lookup?
+ if (requestType != QDnsLookup::A && requestType != QDnsLookup::AAAA
+ && requestType != QDnsLookup::ANY) {
+ reply->error = QDnsLookup::InvalidRequestError;
+ reply->errorString = QLatin1String("WinRT only supports IPv4 and IPv6 requests");
+ return;
+ }
+
+ QString aceHostname = QUrl::fromAce(requestName);
+ if (aceHostname.isEmpty()) {
+ reply->error = QDnsLookup::InvalidRequestError;
+ reply->errorString = requestName.isEmpty() ? tr("No hostname given") : tr("Invalid hostname");
+ return;
+ }
+
+ IHostNameFactory *hostnameFactory;
+
+ HStringReference classId(RuntimeClass_Windows_Networking_HostName);
+ if (FAILED(GetActivationFactory(classId.Get(), &hostnameFactory))) {
+ reply->error = QDnsLookup::ResolverError;
+ reply->errorString = QLatin1String("Could not obtain hostname factory");
+ return;
+ }
+ IHostName *host;
+ HStringReference hostNameRef((const wchar_t*)aceHostname.utf16());
+ hostnameFactory->CreateHostName(hostNameRef.Get(), &host);
+ hostnameFactory->Release();
+
+ IDatagramSocketStatics *datagramSocketStatics;
+ GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_DatagramSocket).Get(), &datagramSocketStatics);
+
+ IAsyncOperation<IVectorView<EndpointPair*> *> *op;
+ HSTRING proto;
+ WindowsCreateString(L"0", 1, &proto);
+ datagramSocketStatics->GetEndpointPairsAsync(host, proto, &op);
+ datagramSocketStatics->Release();
+ host->Release();
+
+ IVectorView<EndpointPair*> *endpointPairs = 0;
+ HRESULT hr = op->GetResults(&endpointPairs);
+ int waitCount = 0;
+ while (hr == E_ILLEGAL_METHOD_CALL) {
+ WaitForSingleObjectEx(GetCurrentThread(), 50, FALSE);
+ hr = op->GetResults(&endpointPairs);
+ if (++waitCount > 1200) // Wait for 1 minute max
+ return;
+ }
+ op->Release();
+
+ if (!endpointPairs)
+ return;
+
+ unsigned int size;
+ endpointPairs->get_Size(&size);
+ for (unsigned int i = 0; i < size; ++i) {
+ IEndpointPair *endpointpair;
+ endpointPairs->GetAt(i, &endpointpair);
+ IHostName *remoteHost;
+ endpointpair->get_RemoteHostName(&remoteHost);
+ endpointpair->Release();
+ HostNameType type;
+ remoteHost->get_Type(&type);
+ if (type == HostNameType_Bluetooth || type == HostNameType_DomainName
+ || (requestType != QDnsLookup::ANY
+ && ((type == HostNameType_Ipv4 && requestType == QDnsLookup::AAAA)
+ || (type == HostNameType_Ipv6 && requestType == QDnsLookup::A))))
+ continue;
+
+ HSTRING name;
+ remoteHost->get_CanonicalName(&name);
+ remoteHost->Release();
+ UINT32 length;
+ PCWSTR rawString = WindowsGetStringRawBuffer(name, &length);
+ QDnsHostAddressRecord record;
+ record.d->name = aceHostname;
+ record.d->value = QHostAddress(QString::fromWCharArray(rawString, length));
+ reply->hostAddressRecords.append(record);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp
index 18fd6dee58..0ab72191dc 100644
--- a/src/network/kernel/qhostaddress.cpp
+++ b/src/network/kernel/qhostaddress.cpp
@@ -71,7 +71,7 @@ QT_BEGIN_NAMESPACE
// sockaddr_in6 size changed between old and new SDK
// Only the new version is the correct one, so always
// use this structure.
-#if defined(Q_OS_WINCE)
+#if defined(Q_OS_WINCE) || defined(Q_OS_WINRT)
# if !defined(u_char)
# define u_char unsigned char
# endif
@@ -448,10 +448,12 @@ QHostAddress::QHostAddress(const QString &address)
QHostAddress::QHostAddress(const struct sockaddr *sockaddr)
: d(new QHostAddressPrivate)
{
+#ifndef Q_OS_WINRT
if (sockaddr->sa_family == AF_INET)
setAddress(htonl(((sockaddr_in *)sockaddr)->sin_addr.s_addr));
else if (sockaddr->sa_family == AF_INET6)
setAddress(((qt_sockaddr_in6 *)sockaddr)->sin6_addr.qt_s6_addr);
+#endif
}
/*!
@@ -604,11 +606,13 @@ bool QHostAddress::setAddress(const QString &address)
*/
void QHostAddress::setAddress(const struct sockaddr *sockaddr)
{
+#ifndef Q_OS_WINRT
clear();
if (sockaddr->sa_family == AF_INET)
setAddress(htonl(((sockaddr_in *)sockaddr)->sin_addr.s_addr));
else if (sockaddr->sa_family == AF_INET6)
setAddress(((qt_sockaddr_in6 *)sockaddr)->sin6_addr.qt_s6_addr);
+#endif
}
/*!
diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp
index d25372ece6..025e3f3e00 100644
--- a/src/network/kernel/qhostinfo.cpp
+++ b/src/network/kernel/qhostinfo.cpp
@@ -508,7 +508,7 @@ QHostInfoLookupManager::QHostInfoLookupManager() : mutex(QMutex::Recursive), was
{
moveToThread(QCoreApplicationPrivate::mainThread());
connect(QCoreApplication::instance(), SIGNAL(destroyed()), SLOT(waitForThreadPoolDone()), Qt::DirectConnection);
- threadPool.setMaxThreadCount(5); // do 5 DNS lookups in parallel
+ threadPool.setMaxThreadCount(20); // do up to 20 DNS lookups in parallel
}
QHostInfoLookupManager::~QHostInfoLookupManager()
diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp
index 32b7318335..df8c8b145a 100644
--- a/src/network/kernel/qhostinfo_unix.cpp
+++ b/src/network/kernel/qhostinfo_unix.cpp
@@ -259,10 +259,10 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
} else if (result == EAI_NONAME
|| result == EAI_FAIL
#ifdef EAI_NODATA
- // EAI_NODATA is deprecated in RFC 3493
- || result == EAI_NODATA
+ // EAI_NODATA is deprecated in RFC 3493
+ || result == EAI_NODATA
#endif
- ) {
+ ) {
results.setError(QHostInfo::HostNotFound);
results.setErrorString(tr("Host not found"));
} else {
diff --git a/src/network/kernel/qhostinfo_winrt.cpp b/src/network/kernel/qhostinfo_winrt.cpp
new file mode 100644
index 0000000000..928c9e4628
--- /dev/null
+++ b/src/network/kernel/qhostinfo_winrt.cpp
@@ -0,0 +1,194 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhostinfo_p.h"
+
+#include <qurl.h>
+
+#include <ppltasks.h>
+#include <wrl.h>
+#include <windows.networking.h>
+#include <windows.networking.sockets.h>
+#include <windows.networking.connectivity.h>
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Foundation::Collections;
+using namespace ABI::Windows::Networking;
+using namespace ABI::Windows::Networking::Connectivity;
+using namespace ABI::Windows::Networking::Sockets;
+
+QT_BEGIN_NAMESPACE
+
+//#define QHOSTINFO_DEBUG
+
+QHostInfo QHostInfoAgent::fromName(const QString &hostName)
+{
+ QHostInfo results;
+
+ QHostAddress address;
+ if (address.setAddress(hostName)) {
+ // Reverse lookup
+ // TODO: is there a replacement for getnameinfo for winrt?
+ Q_UNIMPLEMENTED();
+ return results;
+ }
+
+ QByteArray aceHostname = QUrl::toAce(hostName);
+ results.setHostName(hostName);
+ if (aceHostname.isEmpty()) {
+ results.setError(QHostInfo::HostNotFound);
+ results.setErrorString(hostName.isEmpty() ? tr("No host name given") : tr("Invalid hostname"));
+ return results;
+ }
+
+ IHostNameFactory *hostnameFactory;
+
+ HStringReference classId(RuntimeClass_Windows_Networking_HostName);
+ if (FAILED(GetActivationFactory(classId.Get(), &hostnameFactory)))
+ Q_ASSERT(false, "Could not obtain hostname factory.");
+
+ IHostName *host;
+ HStringReference hostNameRef((const wchar_t*)hostName.utf16());
+ hostnameFactory->CreateHostName(hostNameRef.Get(), &host);
+ hostnameFactory->Release();
+
+ IDatagramSocketStatics *datagramSocketStatics;
+ GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_DatagramSocket).Get(), &datagramSocketStatics);
+
+ IAsyncOperation<IVectorView<EndpointPair*> *> *op;
+ HSTRING proto;
+ WindowsCreateString(L"0", 1, &proto);
+ datagramSocketStatics->GetEndpointPairsAsync(host, proto, &op);
+ datagramSocketStatics->Release();
+ host->Release();
+
+ IVectorView<EndpointPair*> *endpointPairs = 0;
+ HRESULT hr = op->GetResults(&endpointPairs);
+ int waitCount = 0;
+ while (hr == E_ILLEGAL_METHOD_CALL) {
+ WaitForSingleObjectEx(GetCurrentThread(), 50, FALSE);
+ hr = op->GetResults(&endpointPairs);
+ if (++waitCount > 1200) // Wait for 1 minute max
+ return results;
+ }
+ op->Release();
+
+ if (!endpointPairs)
+ return results;
+
+ unsigned int size;
+ endpointPairs->get_Size(&size);
+ QList<QHostAddress> addresses;
+ for (unsigned int i = 0; i < size; ++i) {
+ IEndpointPair *endpointpair;
+ endpointPairs->GetAt(i, &endpointpair);
+ IHostName *remoteHost;
+ endpointpair->get_RemoteHostName(&remoteHost);
+ endpointpair->Release();
+ if (!remoteHost)
+ continue;
+ HostNameType type;
+ remoteHost->get_Type(&type);
+ if (type == HostNameType_DomainName)
+ continue;
+
+ HSTRING name;
+ remoteHost->get_CanonicalName(&name);
+ remoteHost->Release();
+ UINT32 length;
+ PCWSTR rawString = WindowsGetStringRawBuffer(name, &length);
+ QHostAddress addr;
+ addr.setAddress(QString::fromWCharArray(rawString, length));
+ if (!addresses.contains(addr))
+ addresses.append(addr);
+ }
+ results.setAddresses(addresses);
+
+ return results;
+}
+
+QString QHostInfo::localHostName()
+{
+ INetworkInformationStatics *statics;
+ GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_Connectivity_NetworkInformation).Get(), &statics);
+
+ IVectorView<HostName*> *hostNames = 0;
+ statics->GetHostNames(&hostNames);
+ statics->Release();
+ if (!hostNames)
+ return QString();
+
+ unsigned int size;
+ hostNames->get_Size(&size);
+ if (size == 0)
+ return QString();
+
+ for (unsigned int i = 0; i < size; ++i) {
+ IHostName *hostName;
+ hostNames->GetAt(i, &hostName);
+ HostNameType type;
+ hostName->get_Type(&type);
+ if (type != HostNameType_DomainName)
+ continue;
+
+ HSTRING name;
+ hostName->get_CanonicalName(&name);
+ hostName->Release();
+ UINT32 length;
+ PCWSTR rawString = WindowsGetStringRawBuffer(name, &length);
+ return QString::fromWCharArray(rawString, length);
+ }
+ IHostName *firstHost;
+ hostNames->GetAt(0, &firstHost);
+ hostNames->Release();
+
+ HSTRING name;
+ firstHost->get_CanonicalName(&name);
+ firstHost->Release();
+ UINT32 length;
+ PCWSTR rawString = WindowsGetStringRawBuffer(name, &length);
+ return QString::fromWCharArray(rawString, length);
+}
+
+// QString QHostInfo::localDomainName() defined in qnetworkinterface_win.cpp
+
+QT_END_NAMESPACE
diff --git a/src/network/kernel/qnetworkinterface_unix.cpp b/src/network/kernel/qnetworkinterface_unix.cpp
index d3c830a66f..d0e2eca1e0 100644
--- a/src/network/kernel/qnetworkinterface_unix.cpp
+++ b/src/network/kernel/qnetworkinterface_unix.cpp
@@ -228,7 +228,7 @@ static QNetworkInterfacePrivate *findInterface(int socket, QList<QNetworkInterfa
memcpy(req.ifr_name, oldName, qMin<int>(oldName.length() + 1, sizeof(req.ifr_name) - 1));
} else
#endif
- {
+ {
// use this name anyways
iface->name = QString::fromLatin1(req.ifr_name);
}
diff --git a/src/network/kernel/qnetworkinterface_winrt.cpp b/src/network/kernel/qnetworkinterface_winrt.cpp
new file mode 100644
index 0000000000..6a814c85d4
--- /dev/null
+++ b/src/network/kernel/qnetworkinterface_winrt.cpp
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qnetworkinterface.h"
+#include "qnetworkinterface_p.h"
+
+#ifndef QT_NO_NETWORKINTERFACE
+
+#include <wrl.h>
+#include <windows.foundation.h>
+#include <windows.foundation.collections.h>
+#include <windows.networking.h>
+#include <windows.networking.connectivity.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Foundation::Collections;
+using namespace ABI::Windows::Networking;
+using namespace ABI::Windows::Networking::Connectivity;
+
+#include <qhostinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+struct HostNameInfo {
+ GUID adapterId;
+ unsigned char prefixLength;
+ QString address;
+};
+
+static QList<QNetworkInterfacePrivate *> interfaceListing()
+{
+ QList<QNetworkInterfacePrivate *> interfaces;
+
+ QList<HostNameInfo> hostList;
+
+ INetworkInformationStatics *hostNameStatics;
+ GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_Connectivity_NetworkInformation).Get(), &hostNameStatics);
+
+ IVectorView<HostName*> *hostNames = 0;
+ hostNameStatics->GetHostNames(&hostNames);
+ hostNameStatics->Release();
+ if (!hostNames)
+ return interfaces;
+
+ unsigned int hostNameCount;
+ hostNames->get_Size(&hostNameCount);
+ for (unsigned i = 0; i < hostNameCount; ++i) {
+ HostNameInfo hostInfo;
+ IHostName *hostName;
+ hostNames->GetAt(i, &hostName);
+
+ HostNameType type;
+ hostName->get_Type(&type);
+ if (type == HostNameType_DomainName)
+ continue;
+
+ IIPInformation *ipInformation;
+ hostName->get_IPInformation(&ipInformation);
+ INetworkAdapter *currentAdapter;
+ ipInformation->get_NetworkAdapter(&currentAdapter);
+
+ currentAdapter->get_NetworkAdapterId(&hostInfo.adapterId);
+ currentAdapter->Release();
+
+ IReference<unsigned char> *prefixLengthReference;
+ ipInformation->get_PrefixLength(&prefixLengthReference);
+ ipInformation->Release();
+
+ prefixLengthReference->get_Value(&hostInfo.prefixLength);
+ prefixLengthReference->Release();
+
+ // invalid prefixes
+ if ((type == HostNameType_Ipv4 && hostInfo.prefixLength > 32)
+ || (type == HostNameType_Ipv6 && hostInfo.prefixLength > 128))
+ continue;
+
+ HSTRING name;
+ hostName->get_CanonicalName(&name);
+ hostName->Release();
+ UINT32 length;
+ PCWSTR rawString = WindowsGetStringRawBuffer(name, &length);
+ hostInfo.address = QString::fromWCharArray(rawString, length);
+
+ hostList << hostInfo;
+ }
+ hostNames->Release();
+
+ INetworkInformationStatics *networkInfoStatics;
+ GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_Connectivity_NetworkInformation).Get(), &networkInfoStatics);
+ IVectorView<ConnectionProfile *> *connectionProfiles = 0;
+ networkInfoStatics->GetConnectionProfiles(&connectionProfiles);
+ networkInfoStatics->Release();
+ if (!connectionProfiles)
+ return interfaces;
+
+ unsigned int size;
+ connectionProfiles->get_Size(&size);
+ for (unsigned int i = 0; i < size; ++i) {
+ QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate;
+ interfaces << iface;
+
+ IConnectionProfile *profile;
+ connectionProfiles->GetAt(i, &profile);
+
+ NetworkConnectivityLevel connectivityLevel;
+ profile->GetNetworkConnectivityLevel(&connectivityLevel);
+ if (connectivityLevel != NetworkConnectivityLevel_None)
+ iface->flags = QNetworkInterface::IsUp | QNetworkInterface::IsRunning;
+
+ INetworkAdapter *adapter;
+ profile->get_NetworkAdapter(&adapter);
+ profile->Release();
+ UINT32 type;
+ adapter->get_IanaInterfaceType(&type);
+ if (type == 23)
+ iface->flags |= QNetworkInterface::IsPointToPoint;
+ GUID id;
+ adapter->get_NetworkAdapterId(&id);
+ adapter->Release();
+ OLECHAR adapterName[39]={0};
+ StringFromGUID2(id, adapterName, 39);
+ iface->name = QString::fromWCharArray(adapterName);
+
+ // According to http://stackoverflow.com/questions/12936193/how-unique-is-the-ethernet-network-adapter-id-in-winrt-it-is-derived-from-the-m
+ // obtaining the MAC address using WinRT API is impossible
+ // iface->hardwareAddress = ?
+
+ for (int i = 0; i < hostList.length(); ++i) {
+ const HostNameInfo hostInfo = hostList.at(i);
+ if (id != hostInfo.adapterId)
+ continue;
+
+ QNetworkAddressEntry entry;
+ entry.setIp(QHostAddress(hostInfo.address));
+ entry.setPrefixLength(hostInfo.prefixLength);
+ iface->addressEntries << entry;
+
+ hostList.takeAt(i);
+ --i;
+ }
+ }
+ connectionProfiles->Release();
+ return interfaces;
+}
+
+QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan()
+{
+ return interfaceListing();
+}
+
+QString QHostInfo::localDomainName()
+{
+ return QString();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_NETWORKINTERFACE
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index bebdf728a7..0345537d1c 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -372,9 +372,22 @@
IP_MULTICAST_LOOP (multicast loopback) socket option.
\value TypeOfServiceOption This option is not supported on
- Windows. This maps to the IP_TOS socket option.
+ Windows. This maps to the IP_TOS socket option. For possible values,
+ see table below.
- Possible values for the \e{TypeOfServiceOption} are:
+ \value SendBufferSizeSocketOption Sets the socket send buffer size
+ in bytes at the OS level. This maps to the SO_SNDBUF socket option.
+ This option does not affect the QIODevice or QAbstractSocket buffers.
+ This enum value has been introduced in Qt 5.3.
+
+ \value ReceiveBufferSizeSocketOption Sets the socket receive
+ buffer size in bytes at the OS level.
+ This maps to the SO_RCVBUF socket option.
+ This option does not affect the QIODevice or QAbstractSocket buffers
+ (see \l{QAbstractSocket::}{setReadBufferSize()}).
+ This enum value has been introduced in Qt 5.3.
+
+ Possible values for \e{TypeOfServiceOption} are:
\table
\header \li Value \li Description
@@ -735,8 +748,8 @@ bool QAbstractSocketPrivate::canReadNotification()
return true;
}
- if (!hasData && socketEngine)
- socketEngine->setReadNotificationEnabled(true);
+ if (isBuffered && socketEngine)
+ socketEngine->setReadNotificationEnabled(readBufferMaxSize == 0 || readBufferMaxSize > q->bytesAvailable());
// reset the read socket notifier state if we reentered inside the
// readyRead() connected slot.
@@ -1904,6 +1917,14 @@ void QAbstractSocket::setSocketOption(QAbstractSocket::SocketOption option, cons
case TypeOfServiceOption:
d_func()->socketEngine->setOption(QAbstractSocketEngine::TypeOfServiceOption, value.toInt());
break;
+
+ case SendBufferSizeSocketOption:
+ d_func()->socketEngine->setOption(QAbstractSocketEngine::SendBufferSocketOption, value.toInt());
+ break;
+
+ case ReceiveBufferSizeSocketOption:
+ d_func()->socketEngine->setOption(QAbstractSocketEngine::ReceiveBufferSocketOption, value.toInt());
+ break;
}
}
@@ -1938,6 +1959,14 @@ QVariant QAbstractSocket::socketOption(QAbstractSocket::SocketOption option)
case TypeOfServiceOption:
ret = d_func()->socketEngine->option(QAbstractSocketEngine::TypeOfServiceOption);
break;
+
+ case SendBufferSizeSocketOption:
+ ret = d_func()->socketEngine->option(QAbstractSocketEngine::SendBufferSocketOption);
+ break;
+
+ case ReceiveBufferSizeSocketOption:
+ ret = d_func()->socketEngine->option(QAbstractSocketEngine::ReceiveBufferSocketOption);
+ break;
}
if (ret == -1)
return QVariant();
diff --git a/src/network/socket/qabstractsocket.h b/src/network/socket/qabstractsocket.h
index 46114abf73..8b019cf0fb 100644
--- a/src/network/socket/qabstractsocket.h
+++ b/src/network/socket/qabstractsocket.h
@@ -115,7 +115,9 @@ public:
KeepAliveOption, // SO_KEEPALIVE
MulticastTtlOption, // IP_MULTICAST_TTL
MulticastLoopbackOption, // IP_MULTICAST_LOOPBACK
- TypeOfServiceOption //IP_TOS
+ TypeOfServiceOption, //IP_TOS
+ SendBufferSizeSocketOption, //SO_SNDBUF
+ ReceiveBufferSizeSocketOption //SO_RCVBUF
};
enum BindFlag {
DefaultForPlatform = 0x0,
diff --git a/src/network/socket/qabstractsocketengine.cpp b/src/network/socket/qabstractsocketengine.cpp
index 1275461d7d..d8abe01241 100644
--- a/src/network/socket/qabstractsocketengine.cpp
+++ b/src/network/socket/qabstractsocketengine.cpp
@@ -41,7 +41,11 @@
#include "qabstractsocketengine_p.h"
+#ifndef Q_OS_WINRT
#include "qnativesocketengine_p.h"
+#else
+#include "qnativesocketengine_winrt_p.h"
+#endif
#include "qmutex.h"
#include "qnetworkproxy.h"
diff --git a/src/network/socket/qabstractsocketengine_p.h b/src/network/socket/qabstractsocketengine_p.h
index 1dec96762c..6a30012562 100644
--- a/src/network/socket/qabstractsocketengine_p.h
+++ b/src/network/socket/qabstractsocketengine_p.h
@@ -150,7 +150,7 @@ public:
virtual bool waitForRead(int msecs = 30000, bool *timedOut = 0) = 0;
virtual bool waitForWrite(int msecs = 30000, bool *timedOut = 0) = 0;
virtual bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
- bool checkRead, bool checkWrite,
+ bool checkRead, bool checkWrite,
int msecs = 30000, bool *timedOut = 0) = 0;
QAbstractSocket::SocketError error() const;
diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp
index f7f8aab182..791227002d 100644
--- a/src/network/socket/qlocalserver.cpp
+++ b/src/network/socket/qlocalserver.cpp
@@ -131,7 +131,7 @@ QLocalServer::QLocalServer(QObject *parent)
QLocalServer::~QLocalServer()
{
if (isListening())
- close();
+ close();
}
/*!
diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h
index 97a9b98c30..fc1afa48c9 100644
--- a/src/network/socket/qnativesocketengine_p.h
+++ b/src/network/socket/qnativesocketengine_p.h
@@ -162,8 +162,8 @@ public:
bool waitForRead(int msecs = 30000, bool *timedOut = 0);
bool waitForWrite(int msecs = 30000, bool *timedOut = 0);
bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
- bool checkRead, bool checkWrite,
- int msecs = 30000, bool *timedOut = 0);
+ bool checkRead, bool checkWrite,
+ int msecs = 30000, bool *timedOut = 0);
bool isReadNotificationEnabled() const;
void setReadNotificationEnabled(bool enable);
@@ -271,7 +271,7 @@ public:
qint64 nativeWrite(const char *data, qint64 length);
int nativeSelect(int timeout, bool selectForRead) const;
int nativeSelect(int timeout, bool checkRead, bool checkWrite,
- bool *selectForRead, bool *selectForWrite) const;
+ bool *selectForRead, bool *selectForWrite) const;
#ifdef Q_OS_WIN
void setPortAndAddress(sockaddr_in * sockAddrIPv4, qt_sockaddr_in6 * sockAddrIPv6,
quint16 port, const QHostAddress & address, sockaddr ** sockAddrPtr, QT_SOCKLEN_T *sockAddrSize);
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index e076f2b4bf..b6035b5500 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -144,7 +144,7 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
int protocol = (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) ? AF_INET6 : AF_INET;
int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM;
- int socket = qt_safe_socket(protocol, type, 0);
+ int socket = qt_safe_socket(protocol, type, 0);
if (socket <= 0 && socketProtocol == QAbstractSocket::AnyIPProtocol && errno == EAFNOSUPPORT) {
protocol = AF_INET;
socket = qt_safe_socket(protocol, type, 0);
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
index 751ac9b182..b1c9073eb9 100644
--- a/src/network/socket/qnativesocketengine_win.cpp
+++ b/src/network/socket/qnativesocketengine_win.cpp
@@ -186,7 +186,7 @@ static inline void qt_socket_getPortAndAddress(SOCKET socketDescriptor, const qt
*address = a;
}
if (port)
- WSANtohs(socketDescriptor, sa6->sin6_port, port);
+ WSANtohs(socketDescriptor, sa6->sin6_port, port);
} else
if (sa->a.sa_family == AF_INET) {
@@ -194,11 +194,11 @@ static inline void qt_socket_getPortAndAddress(SOCKET socketDescriptor, const qt
unsigned long addr;
WSANtohl(socketDescriptor, sa4->sin_addr.s_addr, &addr);
QHostAddress a;
- a.setAddress(addr);
- if (address)
- *address = a;
+ a.setAddress(addr);
+ if (address)
+ *address = a;
if (port)
- WSANtohs(socketDescriptor, sa4->sin_port, port);
+ WSANtohs(socketDescriptor, sa4->sin_port, port);
}
}
@@ -276,7 +276,7 @@ QWindowsSockInit::QWindowsSockInit()
// IPv6 requires Winsock v2.0 or better.
if (WSAStartup(MAKEWORD(2,0), &wsadata) != 0) {
- qWarning("QTcpSocketAPI: WinSock v2.0 initialization failed.");
+ qWarning("QTcpSocketAPI: WinSock v2.0 initialization failed.");
} else {
version = 0x20;
}
@@ -940,14 +940,14 @@ int QNativeSocketEnginePrivate::nativeAccept()
break;
}
} else if (acceptedDescriptor != -1 && QAbstractEventDispatcher::instance()) {
- // Because of WSAAsyncSelect() WSAAccept returns a non blocking socket
- // with the same attributes as the listening socket including the current
- // WSAAsyncSelect(). To be able to change the socket to blocking mode the
- // WSAAsyncSelect() call must be cancled.
- QSocketNotifier n(acceptedDescriptor, QSocketNotifier::Read);
- n.setEnabled(true);
- n.setEnabled(false);
- }
+ // Because of WSAAsyncSelect() WSAAccept returns a non blocking socket
+ // with the same attributes as the listening socket including the current
+ // WSAAsyncSelect(). To be able to change the socket to blocking mode the
+ // WSAAsyncSelect() call must be cancled.
+ QSocketNotifier n(acceptedDescriptor, QSocketNotifier::Read);
+ n.setEnabled(true);
+ n.setEnabled(false);
+ }
#if defined (QNATIVESOCKETENGINE_DEBUG)
qDebug("QNativeSocketEnginePrivate::nativeAccept() == %i", acceptedDescriptor);
#endif
diff --git a/src/network/socket/qnativesocketengine_winrt.cpp b/src/network/socket/qnativesocketengine_winrt.cpp
new file mode 100644
index 0000000000..2a61325471
--- /dev/null
+++ b/src/network/socket/qnativesocketengine_winrt.cpp
@@ -0,0 +1,1182 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qt_windows.h>
+
+#include "qnativesocketengine_winrt_p.h"
+
+#include <qcoreapplication.h>
+#include <qabstracteventdispatcher.h>
+#include <qsocketnotifier.h>
+#include <qdatetime.h>
+#include <qnetworkinterface.h>
+#include <qelapsedtimer.h>
+#include <qthread.h>
+#include <qabstracteventdispatcher.h>
+
+#include <private/qeventdispatcher_winrt_p.h>
+
+#include <wrl.h>
+#include <windows.foundation.collections.h>
+#include <windows.storage.streams.h>
+#include <windows.networking.h>
+#include <windows.networking.sockets.h>
+#include <robuffer.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Foundation::Collections;
+using namespace ABI::Windows::Storage::Streams;
+using namespace ABI::Windows::Networking;
+using namespace ABI::Windows::Networking::Connectivity;
+using namespace ABI::Windows::Networking::Sockets;
+
+typedef ITypedEventHandler<StreamSocketListener *, StreamSocketListenerConnectionReceivedEventArgs *> ClientConnectedHandler;
+typedef ITypedEventHandler<DatagramSocket *, DatagramSocketMessageReceivedEventArgs *> DatagramReceivedHandler;
+typedef IAsyncOperationWithProgressCompletedHandler<IBuffer *, UINT32> SocketReadCompletedHandler;
+typedef IAsyncOperationWithProgressCompletedHandler<UINT32, UINT32> SocketWriteCompletedHandler;
+
+QT_BEGIN_NAMESPACE
+
+// Common constructs
+#define Q_CHECK_VALID_SOCKETLAYER(function, returnValue) do { \
+ if (!isValid()) { \
+ qWarning(""#function" was called on an uninitialized socket device"); \
+ return returnValue; \
+ } } while (0)
+#define Q_CHECK_INVALID_SOCKETLAYER(function, returnValue) do { \
+ if (isValid()) { \
+ qWarning(""#function" was called on an already initialized socket device"); \
+ return returnValue; \
+ } } while (0)
+#define Q_CHECK_STATE(function, checkState, returnValue) do { \
+ if (d->socketState != (checkState)) { \
+ qWarning(""#function" was not called in "#checkState); \
+ return (returnValue); \
+ } } while (0)
+#define Q_CHECK_NOT_STATE(function, checkState, returnValue) do { \
+ if (d->socketState == (checkState)) { \
+ qWarning(""#function" was called in "#checkState); \
+ return (returnValue); \
+ } } while (0)
+#define Q_CHECK_STATES(function, state1, state2, returnValue) do { \
+ if (d->socketState != (state1) && d->socketState != (state2)) { \
+ qWarning(""#function" was called" \
+ " not in "#state1" or "#state2); \
+ return (returnValue); \
+ } } while (0)
+#define Q_CHECK_TYPE(function, type, returnValue) do { \
+ if (d->socketType != (type)) { \
+ qWarning(#function" was called by a" \
+ " socket other than "#type""); \
+ return (returnValue); \
+ } } while (0)
+#define Q_TR(a) QT_TRANSLATE_NOOP(QNativeSocketEngine, a)
+
+typedef QHash<qintptr, IStreamSocket *> TcpSocketHash;
+
+struct SocketHandler
+{
+ SocketHandler() : socketCount(0) {}
+ qintptr socketCount;
+ TcpSocketHash pendingTcpSockets;
+};
+
+Q_GLOBAL_STATIC(SocketHandler, gSocketHandler)
+
+QString qt_QStringFromHSTRING(HSTRING string)
+{
+ UINT32 length;
+ PCWSTR rawString = WindowsGetStringRawBuffer(string, &length);
+ return QString::fromWCharArray(rawString, length);
+}
+
+class ByteArrayBuffer : public Microsoft::WRL::RuntimeClass<RuntimeClassFlags<WinRtClassicComMix>,
+ IBuffer, Windows::Storage::Streams::IBufferByteAccess>
+{
+public:
+ ByteArrayBuffer(int size) : m_bytes(size, Qt::Uninitialized), m_length(0)
+ {
+ }
+
+ ByteArrayBuffer(const char *data, int size) : m_bytes(data, size), m_length(size)
+ {
+ }
+
+ HRESULT __stdcall Buffer(byte **value)
+ {
+ *value = reinterpret_cast<byte *>(m_bytes.data());
+ return S_OK;
+ }
+
+ HRESULT __stdcall get_Capacity(UINT32 *value)
+ {
+ *value = m_bytes.size();
+ return S_OK;
+ }
+
+ HRESULT __stdcall get_Length(UINT32 *value)
+ {
+ *value = m_length;
+ return S_OK;
+ }
+
+ HRESULT __stdcall put_Length(UINT32 value)
+ {
+ Q_ASSERT(value <= UINT32(m_bytes.size()));
+ m_length = value;
+ return S_OK;
+ }
+
+ QNativeSocketEngine *engine() const
+ {
+ return m_engine;
+ }
+
+ void setEngine(QNativeSocketEngine *engine)
+ {
+ m_engine = engine;
+ }
+
+ ComPtr<IInputStream> inputStream() const
+ {
+ return m_stream;
+ }
+
+ void setInputStream(ComPtr<IInputStream> stream)
+ {
+ m_stream = stream;
+ }
+
+private:
+ QByteArray m_bytes;
+ UINT32 m_length;
+ QPointer<QNativeSocketEngine> m_engine;
+ ComPtr<IInputStream> m_stream;
+};
+
+QNativeSocketEngine::QNativeSocketEngine(QObject *parent)
+ : QAbstractSocketEngine(*new QNativeSocketEnginePrivate(), parent)
+{
+}
+
+QNativeSocketEngine::~QNativeSocketEngine()
+{
+ close();
+}
+
+bool QNativeSocketEngine::initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol)
+{
+ Q_D(QNativeSocketEngine);
+ if (isValid())
+ close();
+
+ // Create the socket
+ if (!d->createNewSocket(type, protocol))
+ return false;
+
+ d->socketType = type;
+ d->socketProtocol = protocol;
+ return true;
+}
+
+bool QNativeSocketEngine::initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState)
+{
+ Q_D(QNativeSocketEngine);
+
+ if (isValid())
+ close();
+
+ d->socketDescriptor = socketDescriptor;
+
+ // Currently, only TCP sockets are initialized this way.
+ SocketHandler *handler = gSocketHandler();
+ d->tcp = handler->pendingTcpSockets.value(socketDescriptor, Q_NULLPTR);
+ d->socketType = QAbstractSocket::TcpSocket;
+
+ if (!d->tcp || !d->fetchConnectionParameters())
+ return false;
+
+ d->socketState = socketState;
+ return true;
+}
+
+qintptr QNativeSocketEngine::socketDescriptor() const
+{
+ Q_D(const QNativeSocketEngine);
+ return d->socketDescriptor;
+}
+
+bool QNativeSocketEngine::isValid() const
+{
+ Q_D(const QNativeSocketEngine);
+ return d->socketDescriptor != -1;
+}
+
+bool QNativeSocketEngine::connectToHost(const QHostAddress &address, quint16 port)
+{
+ const QString addressString = address.toString();
+ return connectToHostByName(addressString, port);
+}
+
+bool QNativeSocketEngine::connectToHostByName(const QString &name, quint16 port)
+{
+ Q_D(QNativeSocketEngine);
+ HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(name.utf16()));
+ ComPtr<IHostNameFactory> hostNameFactory;
+ GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
+ &hostNameFactory);
+ ComPtr<IHostName> remoteHost;
+ if (FAILED(hostNameFactory->CreateHostName(hostNameRef.Get(), &remoteHost))) {
+ qWarning("QNativeSocketEnginePrivate::nativeConnect:: Could not create hostname");
+ return false;
+ }
+
+ const QString portString = QString::number(port);
+ HStringReference portReference(reinterpret_cast<LPCWSTR>(portString.utf16()));
+ ComPtr<IAsyncAction> action;
+ HRESULT hr = E_FAIL;
+ if (d->socketType == QAbstractSocket::TcpSocket)
+ hr = d->tcp->ConnectAsync(remoteHost.Get(), portReference.Get(), &action);
+ else if (d->socketType == QAbstractSocket::UdpSocket)
+ hr = d->udp->ConnectAsync(remoteHost.Get(), portReference.Get(), &action);
+ if (FAILED(hr)) {
+ qWarning("QNativeSocketEnginePrivate::nativeConnect:: Could not obtain connect action");
+ return false;
+ }
+
+ action->put_Completed(Callback<IAsyncActionCompletedHandler>(&QNativeSocketEnginePrivate::interruptEventDispatcher).Get());
+ hr = action->GetResults();
+ while ((hr = action->GetResults()) == E_ILLEGAL_METHOD_CALL)
+ QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents);
+ if (hr == 0x8007274c) { // A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
+ d->setError(QAbstractSocket::NetworkError, d->ConnectionTimeOutErrorString);
+ d->socketState = QAbstractSocket::UnconnectedState;
+ return false;
+ }
+ if (hr == 0x8007274d) { // No connection could be made because the target machine actively refused it.
+ d->setError(QAbstractSocket::ConnectionRefusedError, d->ConnectionRefusedErrorString);
+ d->socketState = QAbstractSocket::UnconnectedState;
+ return false;
+ }
+ if (FAILED(hr)) {
+ d->setError(QAbstractSocket::UnknownSocketError, d->UnknownSocketErrorString);
+ d->socketState = QAbstractSocket::UnconnectedState;
+ return false;
+ }
+
+ if (d->socketType == QAbstractSocket::TcpSocket) {
+ UINT32 capacity;
+ hr = d->inputBuffer->get_Capacity(&capacity);
+ if (FAILED(hr))
+ return false;
+ IInputStream *stream;
+ hr = d->tcp->get_InputStream(&stream);
+ if (FAILED(hr))
+ return false;
+ ByteArrayBuffer *buffer = static_cast<ByteArrayBuffer *>(d->inputBuffer.Get());
+ buffer->setEngine(this);
+ buffer->setInputStream(stream);
+ ComPtr<IAsyncOperationWithProgress<IBuffer *, UINT32>> op;
+ hr = stream->ReadAsync(buffer, capacity, InputStreamOptions_Partial, &op);
+ if (FAILED(hr))
+ return false;
+ hr = op->put_Completed(Callback<SocketReadCompletedHandler>(&QNativeSocketEnginePrivate::handleReadyRead).Get());
+ if (FAILED(hr))
+ return false;
+ }
+ d->socketState = QAbstractSocket::ConnectedState;
+ return true;
+}
+
+bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port)
+{
+ Q_D(QNativeSocketEngine);
+ ComPtr<IHostName> hostAddress;
+ if (address != QHostAddress::Any && address != QHostAddress::AnyIPv4 && address != QHostAddress::AnyIPv6) {
+ ComPtr<IHostNameFactory> hostNameFactory;
+ GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
+ &hostNameFactory);
+ const QString addressString = address.toString();
+ HStringReference addressRef(reinterpret_cast<LPCWSTR>(addressString.utf16()));
+ hostNameFactory->CreateHostName(addressRef.Get(), &hostAddress);
+ }
+
+ HRESULT hr;
+ QString portQString = port ? QString::number(port) : QString();
+ HStringReference portString(reinterpret_cast<LPCWSTR>(portQString.utf16()));
+
+ ComPtr<IAsyncAction> op;
+ if (d->socketType == QAbstractSocket::TcpSocket) {
+ if (!d->tcpListener
+ && FAILED(RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocketListener).Get(),
+ &d->tcpListener))) {
+ qWarning("Failed to create listener");
+ return false;
+ }
+
+ EventRegistrationToken token;
+ d->tcpListener->add_ConnectionReceived(Callback<ClientConnectedHandler>(d, &QNativeSocketEnginePrivate::handleClientConnection).Get(), &token);
+ hr = d->tcpListener->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op);
+ if (FAILED(hr)) {
+ qWarning("Unable to bind"); // ### Set error message
+ return false;
+ }
+ } else if (d->socketType == QAbstractSocket::UdpSocket) {
+ hr = d->udp->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op);
+ if (FAILED(hr)) {
+ qWarning("unable to bind"); // ### Set error message
+ return false;
+ }
+ }
+
+ if (op) {
+ // Wait for connection to enter bound state - TODO: timeout, check result
+ while ((hr = op->GetResults()) == E_ILLEGAL_METHOD_CALL)
+ QCoreApplication::processEvents();
+
+ d->socketState = QAbstractSocket::BoundState;
+ d->fetchConnectionParameters();
+ return true;
+ }
+
+ return false;
+}
+
+bool QNativeSocketEngine::listen()
+{
+ Q_D(QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::listen(), false);
+ Q_CHECK_STATE(QNativeSocketEngine::listen(), QAbstractSocket::BoundState, false);
+ Q_CHECK_TYPE(QNativeSocketEngine::listen(), QAbstractSocket::TcpSocket, false);
+
+ if (d->tcpListener && d->socketDescriptor != -1) {
+ d->socketState = QAbstractSocket::ListeningState;
+ return true;
+ }
+ return false;
+}
+
+int QNativeSocketEngine::accept()
+{
+ Q_D(QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::accept(), -1);
+ Q_CHECK_STATE(QNativeSocketEngine::accept(), QAbstractSocket::ListeningState, -1);
+ Q_CHECK_TYPE(QNativeSocketEngine::accept(), QAbstractSocket::TcpSocket, -1);
+
+ if (d->socketDescriptor == -1 || d->pendingConnections.isEmpty())
+ return -1;
+
+ // Start processing incoming data
+ if (d->socketType == QAbstractSocket::TcpSocket) {
+ IStreamSocket *socket = d->pendingConnections.takeFirst();
+
+ UINT32 capacity;
+ d->inputBuffer->get_Capacity(&capacity);
+ IInputStream *stream;
+ socket->get_InputStream(&stream);
+ // TODO: delete buffer and stream on socket close
+ ByteArrayBuffer *buffer = static_cast<ByteArrayBuffer *>(d->inputBuffer.Get());
+ buffer->setEngine(this);
+ buffer->setInputStream(stream);
+ ComPtr<IAsyncOperationWithProgress<IBuffer *, UINT32>> op;
+ stream->ReadAsync(buffer, capacity, InputStreamOptions_Partial, &op);
+ op->put_Completed(Callback<SocketReadCompletedHandler>(&QNativeSocketEnginePrivate::handleReadyRead).Get());
+ d->currentConnections.append(socket);
+
+ SocketHandler *handler = gSocketHandler();
+ handler->pendingTcpSockets.insert(++handler->socketCount, socket);
+ return handler->socketCount;
+ }
+
+ return -1;
+}
+
+void QNativeSocketEngine::close()
+{
+ Q_D(QNativeSocketEngine);
+ if (d->socketDescriptor != -1) {
+ IClosable *socket = 0;
+ if (d->socketType == QAbstractSocket::TcpSocket)
+ d->tcp->QueryInterface(IID_PPV_ARGS(&socket));
+ else if (d->socketType == QAbstractSocket::UdpSocket)
+ d->udp->QueryInterface(IID_PPV_ARGS(&socket));
+
+ if (socket) {
+ d->closingDown = true;
+ socket->Close();
+ socket->Release();
+ closeNotification();
+ d->socketDescriptor = -1;
+ }
+ d->socketDescriptor = -1;
+ }
+ d->socketState = QAbstractSocket::UnconnectedState;
+ d->hasSetSocketError = false;
+ d->localPort = 0;
+ d->localAddress.clear();
+ d->peerPort = 0;
+ d->peerAddress.clear();
+}
+
+bool QNativeSocketEngine::joinMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface)
+{
+ Q_UNUSED(groupAddress);
+ Q_UNUSED(iface);
+ Q_UNIMPLEMENTED();
+ return false;
+}
+
+bool QNativeSocketEngine::leaveMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface)
+{
+ Q_UNUSED(groupAddress);
+ Q_UNUSED(iface);
+ Q_UNIMPLEMENTED();
+ return false;
+}
+
+QNetworkInterface QNativeSocketEngine::multicastInterface() const
+{
+ Q_UNIMPLEMENTED();
+ return QNetworkInterface();
+}
+
+bool QNativeSocketEngine::setMulticastInterface(const QNetworkInterface &iface)
+{
+ Q_UNUSED(iface);
+ Q_UNIMPLEMENTED();
+ return false;
+}
+
+qint64 QNativeSocketEngine::bytesAvailable() const
+{
+ Q_D(const QNativeSocketEngine);
+ if (d->socketType != QAbstractSocket::TcpSocket)
+ return -1;
+
+ if (d->inputBuffer) {
+ UINT32 len;
+ d->inputBuffer->get_Length(&len);
+ return len;
+ }
+
+ return -1;
+}
+
+qint64 QNativeSocketEngine::read(char *data, qint64 maxlen)
+{
+ Q_D(QNativeSocketEngine);
+ if (d->socketType != QAbstractSocket::TcpSocket)
+ return -1;
+
+ ComPtr<IDataReaderStatics> dataReaderStatics;
+ GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataReader).Get(), &dataReaderStatics);
+ ComPtr<IDataReader> reader;
+
+ dataReaderStatics->FromBuffer(d->inputBuffer.Get(), &reader);
+
+ UINT32 bufferCapacity;
+ d->inputBuffer->get_Capacity(&bufferCapacity);
+ qint64 lengthToRead = maxlen < bufferCapacity ? maxlen : bufferCapacity;
+
+ UINT32 bufferLength;
+ d->inputBuffer->get_Length(&bufferLength);
+
+ lengthToRead = bufferLength < lengthToRead ? bufferLength : lengthToRead;
+ reader->ReadBytes(lengthToRead, (unsigned char*)data);
+ return lengthToRead;
+}
+
+template <typename T>
+static qint64 nativeWrite(T *socket, const char *data, qint64 len)
+{
+ ComPtr<IOutputStream> stream;
+ HRESULT hr = socket->get_OutputStream(&stream);
+ if (FAILED(hr))
+ return -1;
+ ComPtr<ByteArrayBuffer> buffer = Make<ByteArrayBuffer>(data, len);
+ ComPtr<IAsyncOperationWithProgress<UINT32, UINT32>> op;
+ hr = stream->WriteAsync(buffer.Get(), &op);
+ if (FAILED(hr))
+ return -1;
+ UINT32 bytesWritten;
+ while ((hr = op->GetResults(&bytesWritten)) == E_ILLEGAL_METHOD_CALL)
+ QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
+ return bytesWritten;
+}
+
+qint64 QNativeSocketEngine::write(const char *data, qint64 len)
+{
+ Q_D(QNativeSocketEngine);
+ qint64 bytesWritten = -1;
+ if (d->socketType == QAbstractSocket::TcpSocket)
+ bytesWritten = ::nativeWrite(d->tcp, data, len);
+ else if (d->socketType == QAbstractSocket::UdpSocket)
+ bytesWritten = ::nativeWrite(d->udp, data, len);
+ if (bytesWritten != -1 && d->notifyOnWrite)
+ writeNotification();
+ return bytesWritten;
+
+}
+
+qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxlen, QHostAddress *addr, quint16 *port)
+{
+ Q_D(QNativeSocketEngine);
+ if (d->socketType != QAbstractSocket::UdpSocket)
+ return -1;
+
+ QHostAddress returnAddress;
+ quint16 returnPort;
+
+ for (int i = 0; i < d->pendingDatagrams.size(); ++i) {
+ IDatagramSocketMessageReceivedEventArgs *arg = d->pendingDatagrams.at(i);
+ ComPtr<IHostName> remoteHost;
+ HSTRING remoteHostString;
+ HSTRING remotePort;
+ arg->get_RemoteAddress(&remoteHost);
+ arg->get_RemotePort(&remotePort);
+ remoteHost->get_CanonicalName(&remoteHostString);
+ returnAddress.setAddress(qt_QStringFromHSTRING(remoteHostString));
+ returnPort = qt_QStringFromHSTRING(remotePort).toInt();
+ ComPtr<IDataReader> reader;
+ arg->GetDataReader(&reader);
+ if (!reader)
+ continue;
+
+ BYTE buffer[1024];
+ reader->ReadBytes(maxlen, buffer);
+ *addr = returnAddress;
+ *port = returnPort;
+ arg = d->pendingDatagrams.takeFirst();
+
+ // TODO: fill data
+ Q_UNUSED(data);
+ arg->Release();
+ delete arg;
+ --i;
+ return maxlen;
+ }
+
+ return -1;
+}
+
+qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 len, const QHostAddress &addr, quint16 port)
+{
+ Q_D(QNativeSocketEngine);
+ if (d->socketType != QAbstractSocket::UdpSocket)
+ return -1;
+
+ ComPtr<IHostName> remoteHost;
+ ComPtr<IHostNameFactory> hostNameFactory;
+ if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
+ &hostNameFactory))) {
+ qWarning("QNativeSocketEnginePrivate::nativeSendDatagram: could not obtain hostname factory");
+ return -1;
+ }
+ const QString addressString = addr.toString();
+ HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(addressString.utf16()));
+ hostNameFactory->CreateHostName(hostNameRef.Get(), &remoteHost);
+
+ ComPtr<IAsyncOperation<IOutputStream *>> streamOperation;
+ ComPtr<IOutputStream> stream;
+ const QString portString = QString::number(port);
+ HStringReference portRef(reinterpret_cast<LPCWSTR>(portString.utf16()));
+ if (FAILED(d->udp->GetOutputStreamAsync(remoteHost.Get(), portRef.Get(), &streamOperation)))
+ return -1;
+ HRESULT hr;
+ while (hr = streamOperation->GetResults(&stream) == E_ILLEGAL_METHOD_CALL)
+ QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
+ ComPtr<IDataWriterFactory> dataWriterFactory;
+ GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataWriter).Get(), &dataWriterFactory);
+ ComPtr<IDataWriter> writer;
+ dataWriterFactory->CreateDataWriter(stream.Get(), &writer);
+ writer->WriteBytes(len, (unsigned char *)data);
+ return len;
+}
+
+bool QNativeSocketEngine::hasPendingDatagrams() const
+{
+ Q_D(const QNativeSocketEngine);
+ return d->pendingDatagrams.length() > 0;
+}
+
+qint64 QNativeSocketEngine::pendingDatagramSize() const
+{
+ Q_D(const QNativeSocketEngine);
+ qint64 ret = 0;
+ foreach (IDatagramSocketMessageReceivedEventArgs *arg, d->pendingDatagrams) {
+ ComPtr<IDataReader> reader;
+ UINT32 unconsumedBufferLength;
+ arg->GetDataReader(&reader);
+ if (!reader)
+ return -1;
+ reader->get_UnconsumedBufferLength(&unconsumedBufferLength);
+ ret += unconsumedBufferLength;
+ }
+ return ret;
+}
+
+qint64 QNativeSocketEngine::bytesToWrite() const
+{
+ return 0;
+}
+
+qint64 QNativeSocketEngine::receiveBufferSize() const
+{
+ Q_D(const QNativeSocketEngine);
+ return d->option(QAbstractSocketEngine::ReceiveBufferSocketOption);
+}
+
+void QNativeSocketEngine::setReceiveBufferSize(qint64 bufferSize)
+{
+ Q_D(QNativeSocketEngine);
+ d->setOption(QAbstractSocketEngine::ReceiveBufferSocketOption, bufferSize);
+}
+
+qint64 QNativeSocketEngine::sendBufferSize() const
+{
+ Q_D(const QNativeSocketEngine);
+ return d->option(QAbstractSocketEngine::SendBufferSocketOption);
+}
+
+void QNativeSocketEngine::setSendBufferSize(qint64 bufferSize)
+{
+ Q_D(QNativeSocketEngine);
+ d->setOption(QAbstractSocketEngine::SendBufferSocketOption, bufferSize);
+}
+
+int QNativeSocketEngine::option(QAbstractSocketEngine::SocketOption option) const
+{
+ Q_D(const QNativeSocketEngine);
+ return d->option(option);
+}
+
+bool QNativeSocketEngine::setOption(QAbstractSocketEngine::SocketOption option, int value)
+{
+ Q_D(QNativeSocketEngine);
+ return d->setOption(option, value);
+}
+
+bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut)
+{
+ Q_D(const QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForRead(), false);
+ Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForRead(),
+ QAbstractSocket::UnconnectedState, false);
+
+ if (timedOut)
+ *timedOut = false;
+
+ QElapsedTimer timer;
+ timer.start();
+ while (msecs > timer.elapsed()) {
+ // Servers with active connections are ready for reading
+ if (!d->currentConnections.isEmpty())
+ return true;
+
+ // If we are a client, we are ready to read if our buffer has data
+ UINT32 length;
+ if (FAILED(d->inputBuffer->get_Length(&length)))
+ return false;
+ if (length)
+ return true;
+
+ // Nothing to do, wait for more events
+ QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents|QEventLoop::WaitForMoreEvents);
+ }
+
+ d->setError(QAbstractSocket::SocketTimeoutError,
+ QNativeSocketEnginePrivate::TimeOutErrorString);
+
+ if (timedOut)
+ *timedOut = true;
+ return false;
+}
+
+bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut)
+{
+ Q_UNUSED(msecs);
+ Q_UNUSED(timedOut);
+ return false;
+}
+
+bool QNativeSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, int msecs, bool *timedOut)
+{
+ Q_UNUSED(readyToRead);
+ Q_UNUSED(readyToWrite);
+ Q_UNUSED(checkRead);
+ Q_UNUSED(checkWrite);
+ Q_UNUSED(msecs);
+ Q_UNUSED(timedOut);
+ return false;
+}
+
+bool QNativeSocketEngine::isReadNotificationEnabled() const
+{
+ Q_D(const QNativeSocketEngine);
+ return d->notifyOnRead;
+}
+
+void QNativeSocketEngine::setReadNotificationEnabled(bool enable)
+{
+ Q_D(QNativeSocketEngine);
+ d->notifyOnRead = enable;
+}
+
+bool QNativeSocketEngine::isWriteNotificationEnabled() const
+{
+ Q_D(const QNativeSocketEngine);
+ return d->notifyOnWrite;
+}
+
+void QNativeSocketEngine::setWriteNotificationEnabled(bool enable)
+{
+ Q_D(QNativeSocketEngine);
+ d->notifyOnWrite = enable;
+ if (enable && d->socketState == QAbstractSocket::ConnectedState) {
+ if (bytesToWrite())
+ return; // will be emitted as a result of bytes written
+ writeNotification();
+ d->notifyOnWrite = false;
+ }
+}
+
+bool QNativeSocketEngine::isExceptionNotificationEnabled() const
+{
+ Q_D(const QNativeSocketEngine);
+ return d->notifyOnException;
+}
+
+void QNativeSocketEngine::setExceptionNotificationEnabled(bool enable)
+{
+ Q_D(QNativeSocketEngine);
+ d->notifyOnException = enable;
+}
+
+bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol &socketProtocol)
+{
+ Q_UNUSED(socketProtocol);
+ SocketHandler *handler = gSocketHandler();
+ switch (socketType) {
+ case QAbstractSocket::TcpSocket: {
+ if (FAILED(RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocket).Get(),
+ reinterpret_cast<IInspectable **>(&tcp)))) {
+ qWarning("Failed to create StreamSocket instance");
+ return false;
+ }
+ socketDescriptor = ++handler->socketCount;
+ return true;
+ }
+ case QAbstractSocket::UdpSocket: {
+ if (FAILED(RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_DatagramSocket).Get(),
+ reinterpret_cast<IInspectable **>(&udp)))) {
+ qWarning("Failed to create stream socket");
+ return false;
+ }
+ EventRegistrationToken token;
+ udp->add_MessageReceived(Callback<DatagramReceivedHandler>(this, &QNativeSocketEnginePrivate::handleNewDatagram).Get(), &token);
+ socketDescriptor = ++handler->socketCount;
+ return true;
+ }
+ default:
+ qWarning("Invalid socket type");
+ return false;
+ }
+ return false;
+}
+
+QNativeSocketEnginePrivate::QNativeSocketEnginePrivate()
+ : QAbstractSocketEnginePrivate()
+ , notifyOnRead(true)
+ , notifyOnWrite(true)
+ , notifyOnException(false)
+ , closingDown(false)
+ , socketDescriptor(-1)
+{
+ ComPtr<ByteArrayBuffer> buffer = Make<ByteArrayBuffer>(8192);
+ inputBuffer = buffer;
+}
+
+QNativeSocketEnginePrivate::~QNativeSocketEnginePrivate()
+{
+}
+
+void QNativeSocketEnginePrivate::setError(QAbstractSocket::SocketError error, ErrorString errorString) const
+{
+ if (hasSetSocketError) {
+ // Only set socket errors once for one engine; expect the
+ // 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))
+ hasSetSocketError = true;
+
+ socketError = error;
+
+ switch (errorString) {
+ case NonBlockingInitFailedErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Unable to initialize non-blocking socket");
+ break;
+ case BroadcastingInitFailedErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Unable to initialize broadcast socket");
+ break;
+ // should not happen anymore
+ case NoIpV6ErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Attempt to use IPv6 socket on a platform with no IPv6 support");
+ break;
+ case RemoteHostClosedErrorString:
+ socketErrorString = QNativeSocketEngine::tr("The remote host closed the connection");
+ break;
+ case TimeOutErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Network operation timed out");
+ break;
+ case ResourceErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Out of resources");
+ break;
+ case OperationUnsupportedErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Unsupported socket operation");
+ break;
+ case ProtocolUnsupportedErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Protocol type not supported");
+ break;
+ case InvalidSocketErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Invalid socket descriptor");
+ break;
+ case HostUnreachableErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Host unreachable");
+ break;
+ case NetworkUnreachableErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Network unreachable");
+ break;
+ case AccessErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Permission denied");
+ break;
+ case ConnectionTimeOutErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Connection timed out");
+ break;
+ case ConnectionRefusedErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Connection refused");
+ break;
+ case AddressInuseErrorString:
+ socketErrorString = QNativeSocketEngine::tr("The bound address is already in use");
+ break;
+ case AddressNotAvailableErrorString:
+ socketErrorString = QNativeSocketEngine::tr("The address is not available");
+ break;
+ case AddressProtectedErrorString:
+ socketErrorString = QNativeSocketEngine::tr("The address is protected");
+ break;
+ case DatagramTooLargeErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Datagram was too large to send");
+ break;
+ case SendDatagramErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Unable to send a message");
+ break;
+ case ReceiveDatagramErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Unable to receive a message");
+ break;
+ case WriteErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Unable to write");
+ break;
+ case ReadErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Network error");
+ break;
+ case PortInuseErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Another socket is already listening on the same port");
+ break;
+ case NotSocketErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Operation on non-socket");
+ break;
+ case InvalidProxyTypeString:
+ socketErrorString = QNativeSocketEngine::tr("The proxy type is invalid for this operation");
+ break;
+ case TemporaryErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Temporary error");
+ break;
+ case UnknownSocketErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Unknown error");
+ break;
+ }
+}
+
+int QNativeSocketEnginePrivate::option(QAbstractSocketEngine::SocketOption opt) const
+{
+ ComPtr<IStreamSocketControl> control;
+ if (socketType == QAbstractSocket::TcpSocket) {
+ if (FAILED(tcp->get_Control(&control))) {
+ qWarning("QNativeSocketEnginePrivate::option: Could not obtain socket control");
+ return -1;
+ }
+ }
+ switch (opt) {
+ case QAbstractSocketEngine::NonBlockingSocketOption:
+ case QAbstractSocketEngine::BroadcastSocketOption:
+ case QAbstractSocketEngine::ReceiveOutOfBandData:
+ return 1;
+ case QAbstractSocketEngine::SendBufferSocketOption:
+ if (socketType == QAbstractSocket::UdpSocket)
+ return -1;
+
+ UINT32 bufferSize;
+ if (FAILED(control->get_OutboundBufferSizeInBytes(&bufferSize))) {
+ qWarning("Could not obtain OutboundBufferSizeInBytes information vom socket control");
+ return -1;
+ }
+ return bufferSize;
+ case QAbstractSocketEngine::LowDelayOption:
+ if (socketType == QAbstractSocket::UdpSocket)
+ return -1;
+
+ boolean noDelay;
+ if (FAILED(control->get_NoDelay(&noDelay))) {
+ qWarning("Could not obtain NoDelay information from socket control");
+ return -1;
+ }
+ return noDelay;
+ case QAbstractSocketEngine::KeepAliveOption:
+ if (socketType == QAbstractSocket::UdpSocket)
+ return -1;
+
+ boolean keepAlive;
+ if (FAILED(control->get_KeepAlive(&keepAlive))) {
+ qWarning("Could not obtain KeepAlive information from socket control");
+ return -1;
+ }
+ return keepAlive;
+ case QAbstractSocketEngine::ReceiveBufferSocketOption:
+ case QAbstractSocketEngine::AddressReusable:
+ case QAbstractSocketEngine::BindExclusively:
+ case QAbstractSocketEngine::MulticastTtlOption:
+ case QAbstractSocketEngine::MulticastLoopbackOption:
+ case QAbstractSocketEngine::TypeOfServiceOption:
+ default:
+ return -1;
+ }
+ return -1;
+}
+
+bool QNativeSocketEnginePrivate::setOption(QAbstractSocketEngine::SocketOption opt, int v)
+{
+ ComPtr<IStreamSocketControl> control;
+ if (socketType == QAbstractSocket::TcpSocket) {
+ if (FAILED(tcp->get_Control(&control))) {
+ qWarning("QNativeSocketEnginePrivate::setOption: Could not obtain socket control");
+ return false;
+ }
+ }
+ switch (opt) {
+ case QAbstractSocketEngine::NonBlockingSocketOption:
+ case QAbstractSocketEngine::BroadcastSocketOption:
+ case QAbstractSocketEngine::ReceiveOutOfBandData:
+ return v != 0;
+ case QAbstractSocketEngine::SendBufferSocketOption:
+ if (socketType == QAbstractSocket::UdpSocket)
+ return false;
+
+ if (FAILED(control->put_OutboundBufferSizeInBytes(v))) {
+ qWarning("Could not set OutboundBufferSizeInBytes");
+ return false;
+ }
+ return true;
+ case QAbstractSocketEngine::LowDelayOption: {
+ if (socketType == QAbstractSocket::UdpSocket)
+ return false;
+
+ boolean noDelay = v;
+ if (FAILED(control->put_NoDelay(noDelay))) {
+ qWarning("Could not obtain NoDelay information from socket control");
+ return false;
+ }
+ return true;
+ }
+ case QAbstractSocketEngine::KeepAliveOption: {
+ if (socketType == QAbstractSocket::UdpSocket)
+ return false;
+
+ boolean keepAlive = v;
+ if (FAILED(control->put_KeepAlive(keepAlive))) {
+ qWarning("Could not set KeepAlive value");
+ return false;
+ }
+ return true;
+ }
+ case QAbstractSocketEngine::ReceiveBufferSocketOption:
+ case QAbstractSocketEngine::AddressReusable:
+ case QAbstractSocketEngine::BindExclusively:
+ case QAbstractSocketEngine::MulticastTtlOption:
+ case QAbstractSocketEngine::MulticastLoopbackOption:
+ case QAbstractSocketEngine::TypeOfServiceOption:
+ default:
+ return false;
+ }
+ return false;
+}
+
+bool QNativeSocketEnginePrivate::fetchConnectionParameters()
+{
+ localPort = 0;
+ localAddress.clear();
+ peerPort = 0;
+ peerAddress.clear();
+
+ if (socketType == QAbstractSocket::TcpSocket) {
+ ComPtr<IHostName> hostName;
+ HSTRING tmpHString;
+ ComPtr<IStreamSocketInformation> info;
+ if (FAILED(tcp->get_Information(&info))) {
+ qWarning("QNativeSocketEnginePrivate::fetchConnectionParameters: Could not obtain socket info");
+ return false;
+ }
+ info->get_LocalAddress(&hostName);
+ if (hostName) {
+ hostName->get_CanonicalName(&tmpHString);
+ localAddress.setAddress(qt_QStringFromHSTRING(tmpHString));
+ info->get_LocalPort(&tmpHString);
+ localPort = qt_QStringFromHSTRING(tmpHString).toInt();
+ }
+ if (!localPort && tcpListener) {
+ ComPtr<IStreamSocketListenerInformation> listenerInfo = 0;
+ tcpListener->get_Information(&listenerInfo);
+ listenerInfo->get_LocalPort(&tmpHString);
+ localPort = qt_QStringFromHSTRING(tmpHString).toInt();
+ localAddress == QHostAddress::Any;
+ }
+ info->get_RemoteAddress(&hostName);
+ if (hostName) {
+ hostName->get_CanonicalName(&tmpHString);
+ peerAddress.setAddress(qt_QStringFromHSTRING(tmpHString));
+ info->get_RemotePort(&tmpHString);
+ peerPort = qt_QStringFromHSTRING(tmpHString).toInt();
+ }
+ } else if (socketType == QAbstractSocket::UdpSocket) {
+ ComPtr<IHostName> hostName;
+ HSTRING tmpHString;
+ ComPtr<IDatagramSocketInformation> info;
+ if (FAILED(udp->get_Information(&info))) {
+ qWarning("QNativeSocketEnginePrivate::fetchConnectionParameters: Could not obtain socket information");
+ return false;
+ }
+ info->get_LocalAddress(&hostName);
+ if (hostName) {
+ hostName->get_CanonicalName(&tmpHString);
+ localAddress.setAddress(qt_QStringFromHSTRING(tmpHString));
+ info->get_LocalPort(&tmpHString);
+ localPort = qt_QStringFromHSTRING(tmpHString).toInt();
+ }
+
+ info->get_RemoteAddress(&hostName);
+ if (hostName) {
+ hostName->get_CanonicalName(&tmpHString);
+ peerAddress.setAddress(qt_QStringFromHSTRING(tmpHString));
+ info->get_RemotePort(&tmpHString);
+ peerPort = qt_QStringFromHSTRING(tmpHString).toInt();
+ }
+ }
+ return true;
+}
+
+HRESULT QNativeSocketEnginePrivate::handleClientConnection(IStreamSocketListener *listener, IStreamSocketListenerConnectionReceivedEventArgs *args)
+{
+ Q_Q(QNativeSocketEngine);
+ Q_ASSERT(tcpListener.Get() == listener);
+ IStreamSocket *socket;
+ args->get_Socket(&socket);
+ pendingConnections.append(socket);
+ q->connectionNotification();
+ q->readNotification();
+ return interruptEventDispatcher(0, Completed);
+}
+
+HRESULT QNativeSocketEnginePrivate::interruptEventDispatcher(IAsyncAction *, AsyncStatus)
+{
+ if (QThread *thread = QThread::currentThread()) {
+ if (QAbstractEventDispatcher *dispatcher = thread->eventDispatcher())
+ dispatcher->interrupt();
+ }
+ return S_OK;
+}
+
+HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncOperationWithProgress<IBuffer *, UINT32> *asyncInfo, AsyncStatus)
+{
+ ByteArrayBuffer *buffer = 0;
+ HRESULT hr = asyncInfo->GetResults((IBuffer **)&buffer);
+ if (FAILED(hr))
+ return hr;
+ UINT32 len;
+ buffer->get_Length(&len);
+ QNativeSocketEngine *q = buffer->engine();
+ if (!q)
+ return S_OK;
+ if (len > 0 && q->isReadNotificationEnabled()) {
+ q->readNotification();
+ }
+
+ // Continue reading ### TODO: read into offset!!!
+ UINT32 capacity;
+ buffer->get_Capacity(&capacity);
+ ComPtr<IAsyncOperationWithProgress<IBuffer *, UINT32>> op;
+ if (SUCCEEDED(buffer->inputStream()->ReadAsync(buffer, capacity, InputStreamOptions_Partial, &op))) {
+ if (q)
+ return op->put_Completed(Callback<SocketReadCompletedHandler>(&QNativeSocketEnginePrivate::handleReadyRead).Get());
+ else
+ return op->put_Completed(nullptr);
+ }
+
+ return E_FAIL;
+}
+
+HRESULT QNativeSocketEnginePrivate::handleNewDatagram(IDatagramSocket *socket, IDatagramSocketMessageReceivedEventArgs *args)
+{
+ Q_Q(QNativeSocketEngine);
+ Q_ASSERT(udp == socket);
+ pendingDatagrams.append(args);
+ q->readNotification();
+
+ return S_OK;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/socket/qnativesocketengine_winrt_p.h b/src/network/socket/qnativesocketengine_winrt_p.h
new file mode 100644
index 0000000000..b5be5fa830
--- /dev/null
+++ b/src/network/socket/qnativesocketengine_winrt_p.h
@@ -0,0 +1,209 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QNATIVESOCKETENGINE_WINRT_P_H
+#define QNATIVESOCKETENGINE_WINRT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+#include "QtNetwork/qhostaddress.h"
+#include "private/qabstractsocketengine_p.h"
+#include <wrl.h>
+#include <windows.networking.sockets.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNativeSocketEnginePrivate;
+
+class Q_AUTOTEST_EXPORT QNativeSocketEngine : public QAbstractSocketEngine
+{
+ Q_OBJECT
+public:
+ QNativeSocketEngine(QObject *parent = 0);
+ ~QNativeSocketEngine();
+
+ bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol);
+ bool initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState);
+
+ qintptr socketDescriptor() const;
+
+ bool isValid() const;
+
+ bool connectToHost(const QHostAddress &address, quint16 port);
+ bool connectToHostByName(const QString &name, quint16 port);
+ bool bind(const QHostAddress &address, quint16 port);
+ bool listen();
+ int accept();
+ void close();
+
+#ifndef QT_NO_NETWORKINTERFACE
+ bool joinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+ bool leaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+ QNetworkInterface multicastInterface() const;
+ bool setMulticastInterface(const QNetworkInterface &iface);
+#endif
+
+ qint64 bytesAvailable() const;
+
+ qint64 read(char *data, qint64 maxlen);
+ qint64 write(const char *data, qint64 len);
+
+ qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
+ quint16 *port = 0);
+ qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr,
+ quint16 port);
+ bool hasPendingDatagrams() const;
+ qint64 pendingDatagramSize() const;
+
+ qint64 bytesToWrite() const;
+
+ qint64 receiveBufferSize() const;
+ void setReceiveBufferSize(qint64 bufferSize);
+
+ qint64 sendBufferSize() const;
+ void setSendBufferSize(qint64 bufferSize);
+
+ int option(SocketOption option) const;
+ bool setOption(SocketOption option, int value);
+
+ bool waitForRead(int msecs = 30000, bool *timedOut = 0);
+ bool waitForWrite(int msecs = 30000, bool *timedOut = 0);
+ bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
+ bool checkRead, bool checkWrite,
+ int msecs = 30000, bool *timedOut = 0);
+
+ bool isReadNotificationEnabled() const;
+ void setReadNotificationEnabled(bool enable);
+ bool isWriteNotificationEnabled() const;
+ void setWriteNotificationEnabled(bool enable);
+ bool isExceptionNotificationEnabled() const;
+ void setExceptionNotificationEnabled(bool enable);
+
+private:
+ Q_DECLARE_PRIVATE(QNativeSocketEngine)
+ Q_DISABLE_COPY(QNativeSocketEngine)
+};
+
+class QNativeSocketEnginePrivate : public QAbstractSocketEnginePrivate
+{
+ Q_DECLARE_PUBLIC(QNativeSocketEngine)
+public:
+ QNativeSocketEnginePrivate();
+ ~QNativeSocketEnginePrivate();
+
+ qintptr socketDescriptor;
+
+ bool notifyOnRead, notifyOnWrite, notifyOnException;
+ bool closingDown;
+
+ enum ErrorString {
+ NonBlockingInitFailedErrorString,
+ BroadcastingInitFailedErrorString,
+ NoIpV6ErrorString,
+ RemoteHostClosedErrorString,
+ TimeOutErrorString,
+ ResourceErrorString,
+ OperationUnsupportedErrorString,
+ ProtocolUnsupportedErrorString,
+ InvalidSocketErrorString,
+ HostUnreachableErrorString,
+ NetworkUnreachableErrorString,
+ AccessErrorString,
+ ConnectionTimeOutErrorString,
+ ConnectionRefusedErrorString,
+ AddressInuseErrorString,
+ AddressNotAvailableErrorString,
+ AddressProtectedErrorString,
+ DatagramTooLargeErrorString,
+ SendDatagramErrorString,
+ ReceiveDatagramErrorString,
+ WriteErrorString,
+ ReadErrorString,
+ PortInuseErrorString,
+ NotSocketErrorString,
+ InvalidProxyTypeString,
+ TemporaryErrorString,
+
+ UnknownSocketErrorString = -1
+ };
+
+ void setError(QAbstractSocket::SocketError error, ErrorString errorString) const;
+
+ // native functions
+ int option(QNativeSocketEngine::SocketOption option) const;
+ bool setOption(QNativeSocketEngine::SocketOption option, int value);
+
+ bool createNewSocket(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol &protocol);
+
+ bool checkProxy(const QHostAddress &address);
+ bool fetchConnectionParameters();
+private:
+ union {
+ ABI::Windows::Networking::Sockets::IStreamSocket *tcp;
+ ABI::Windows::Networking::Sockets::IDatagramSocket *udp;
+ };
+ Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocketListener> tcpListener;
+ Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBuffer> inputBuffer;
+ QList<ABI::Windows::Networking::Sockets::IDatagramSocketMessageReceivedEventArgs *> pendingDatagrams;
+ QList<ABI::Windows::Networking::Sockets::IStreamSocket *> pendingConnections;
+ QList<ABI::Windows::Networking::Sockets::IStreamSocket *> currentConnections;
+
+ HRESULT handleNewDatagram(ABI::Windows::Networking::Sockets::IDatagramSocket *socket,
+ ABI::Windows::Networking::Sockets::IDatagramSocketMessageReceivedEventArgs *args);
+ HRESULT handleClientConnection(ABI::Windows::Networking::Sockets::IStreamSocketListener *tcpListener,
+ ABI::Windows::Networking::Sockets::IStreamSocketListenerConnectionReceivedEventArgs *args);
+ static HRESULT interruptEventDispatcher(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus);
+ static HRESULT handleReadyRead(ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer *, UINT32> *asyncInfo, ABI::Windows::Foundation::AsyncStatus);
+};
+
+QT_END_NAMESPACE
+
+#endif // QNATIVESOCKETENGINE_WINRT_P_H
diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp
index 6818ff6354..b62c4a6bef 100644
--- a/src/network/socket/qsocks5socketengine.cpp
+++ b/src/network/socket/qsocks5socketengine.cpp
@@ -735,9 +735,10 @@ void QSocks5SocketEnginePrivate::reauthenticate()
proxyInfo.setPassword(auth.password());
data->authenticator = new QSocks5PasswordAuthenticator(proxyInfo.user(), proxyInfo.password());
- data->controlSocket->blockSignals(true);
- data->controlSocket->abort();
- data->controlSocket->blockSignals(false);
+ {
+ const QSignalBlocker blocker(data->controlSocket);
+ data->controlSocket->abort();
+ }
data->controlSocket->connectToHost(proxyInfo.hostName(), proxyInfo.port());
} else {
// authentication failure
diff --git a/src/network/socket/socket.pri b/src/network/socket/socket.pri
index c0c6d750d9..7e3a54e303 100644
--- a/src/network/socket/socket.pri
+++ b/src/network/socket/socket.pri
@@ -24,8 +24,10 @@ SOURCES += socket/qabstractsocketengine.cpp \
socket/qlocalsocket.cpp \
socket/qlocalserver.cpp
-SOURCES += socket/qnativesocketengine.cpp
-HEADERS += socket/qnativesocketengine_p.h
+!winrt {
+ SOURCES += socket/qnativesocketengine.cpp
+ HEADERS += socket/qnativesocketengine_p.h
+}
unix: {
SOURCES += socket/qnativesocketengine_unix.cpp \
@@ -36,11 +38,20 @@ unix: {
unix:HEADERS += \
socket/qnet_unix_p.h
-win32:SOURCES += socket/qnativesocketengine_win.cpp \
+win32:!winrt:SOURCES += socket/qnativesocketengine_win.cpp \
socket/qlocalsocket_win.cpp \
socket/qlocalserver_win.cpp
-win32:!wince*: LIBS_PRIVATE += -ladvapi32
+win32:!wince*:!winrt:LIBS_PRIVATE += -ladvapi32
+
+winrt {
+ SOURCES += socket/qnativesocketengine_winrt.cpp \
+ socket/qlocalsocket_tcp.cpp \
+ socket/qlocalserver_tcp.cpp
+ HEADERS += socket/qnativesocketengine_winrt_p.h
+
+ DEFINES += QT_LOCALSOCKET_TCP
+}
wince*: {
SOURCES -= socket/qlocalsocket_win.cpp \
diff --git a/src/network/ssl/qsslcipher.cpp b/src/network/ssl/qsslcipher.cpp
index cdb0ed9063..bb5d93e528 100644
--- a/src/network/ssl/qsslcipher.cpp
+++ b/src/network/ssl/qsslcipher.cpp
@@ -79,6 +79,26 @@ QSslCipher::QSslCipher()
/*!
Constructs a QSslCipher object for the cipher determined by \a
+ name. The constructor accepts only supported ciphers (i.e., the
+ \a name must identify a cipher in the list of ciphers returned by
+ QSslSocket::supportedCiphers()).
+
+ You can call isNull() after construction to check if \a name
+ correctly identified a supported cipher.
+*/
+QSslCipher::QSslCipher(const QString &name)
+ : d(new QSslCipherPrivate)
+{
+ foreach (const QSslCipher &cipher, QSslSocket::supportedCiphers()) {
+ if (cipher.name() == name) {
+ *this = cipher;
+ return;
+ }
+ }
+}
+
+/*!
+ Constructs a QSslCipher object for the cipher determined by \a
name and \a protocol. The constructor accepts only supported
ciphers (i.e., the \a name and \a protocol must identify a cipher
in the list of ciphers returned by
diff --git a/src/network/ssl/qsslcipher.h b/src/network/ssl/qsslcipher.h
index e351d7949b..4cebffa7ae 100644
--- a/src/network/ssl/qsslcipher.h
+++ b/src/network/ssl/qsslcipher.h
@@ -57,6 +57,7 @@ class Q_NETWORK_EXPORT QSslCipher
{
public:
QSslCipher();
+ QSslCipher(const QString &name);
QSslCipher(const QString &name, QSsl::SslProtocol protocol);
QSslCipher(const QSslCipher &other);
~QSslCipher();
diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp
index 4aad7c04c5..1e859ae6e6 100644
--- a/src/network/ssl/qsslconfiguration.cpp
+++ b/src/network/ssl/qsslconfiguration.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -52,6 +53,9 @@ const QSsl::SslOptions QSslConfigurationPrivate::defaultSslOptions = QSsl::SslOp
|QSsl::SslOptionDisableCompression
|QSsl::SslOptionDisableSessionPersistence;
+const char QSslConfiguration::NextProtocolSpdy3_0[] = "spdy/3";
+const char QSslConfiguration::NextProtocolHttp1_1[] = "http/1.1";
+
/*!
\class QSslConfiguration
\brief The QSslConfiguration class holds the configuration and state of an SSL connection
@@ -113,6 +117,33 @@ const QSsl::SslOptions QSslConfigurationPrivate::defaultSslOptions = QSsl::SslOp
*/
/*!
+ \enum QSslConfiguration::NextProtocolNegotiationStatus
+
+ Describes the status of the Next Protocol Negotiation (NPN).
+
+ \value NextProtocolNegotiationNone No application protocol
+ has been negotiated (yet).
+
+ \value NextProtocolNegotiationNegotiated A next protocol
+ has been negotiated (see nextNegotiatedProtocol()).
+
+ \value NextProtocolNegotiationUnsupported The client and
+ server could not agree on a common next application protocol.
+*/
+
+/*!
+ \variable QSslConfiguration::NextProtocolSpdy3_0
+ \brief The value used for negotiating SPDY 3.0 during the Next
+ Protocol Negotiation.
+*/
+
+/*!
+ \variable QSslConfiguration::NextProtocolHttp1_1
+ \brief The value used for negotiating HTTP 1.1 during the Next
+ Protocol Negotiation.
+*/
+
+/*!
Constructs an empty SSL configuration. This configuration contains
no valid settings and the state will be empty. isNull() will
return true after this constructor is called.
@@ -185,7 +216,10 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const
d->allowRootCertOnDemandLoading == other.d->allowRootCertOnDemandLoading &&
d->sslOptions == other.d->sslOptions &&
d->sslSession == other.d->sslSession &&
- d->sslSessionTicketLifeTimeHint == other.d->sslSessionTicketLifeTimeHint;
+ d->sslSessionTicketLifeTimeHint == other.d->sslSessionTicketLifeTimeHint &&
+ d->nextAllowedProtocols == other.d->nextAllowedProtocols &&
+ d->nextNegotiatedProtocol == other.d->nextNegotiatedProtocol &&
+ d->nextProtocolNegotiationStatus == other.d->nextProtocolNegotiationStatus;
}
/*!
@@ -221,7 +255,10 @@ bool QSslConfiguration::isNull() const
d->peerCertificateChain.count() == 0 &&
d->sslOptions == QSslConfigurationPrivate::defaultSslOptions &&
d->sslSession.isNull() &&
- d->sslSessionTicketLifeTimeHint == -1);
+ d->sslSessionTicketLifeTimeHint == -1 &&
+ d->nextAllowedProtocols.isEmpty() &&
+ d->nextNegotiatedProtocol.isNull() &&
+ d->nextProtocolNegotiationStatus == QSslConfiguration::NextProtocolNegotiationNone);
}
/*!
@@ -653,6 +690,71 @@ int QSslConfiguration::sessionTicketLifeTimeHint() const
}
/*!
+ \since 5.3
+
+ This function returns the protocol negotiated with the server
+ if the Next Protocol Negotiation (NPN) TLS extension was enabled.
+ In order for the NPN extension to be enabled, setAllowedNextProtocols()
+ needs to be called explicitly before connecting to the server.
+
+ If no protocol could be negotiated or the extension was not enabled,
+ this function returns a QByteArray which is null.
+
+ \sa setAllowedNextProtocols(), nextProtocolNegotiationStatus()
+ */
+QByteArray QSslConfiguration::nextNegotiatedProtocol() const
+{
+ return d->nextNegotiatedProtocol;
+}
+
+/*!
+ \since 5.3
+
+ This function sets the allowed \a protocols to be negotiated with the
+ server through the Next Protocol Negotiation (NPN) TLS extension; each
+ element in \a protocols must define one allowed protocol.
+ The function must be called explicitly before connecting to send the NPN
+ extension in the SSL handshake.
+ Whether or not the negotiation succeeded can be queried through
+ nextProtocolNegotiationStatus().
+
+ \sa nextNegotiatedProtocol(), nextProtocolNegotiationStatus(), allowedNextProtocols(), QSslConfiguration::NextProtocolSpdy3_0, QSslConfiguration::NextProtocolHttp1_1
+ */
+void QSslConfiguration::setAllowedNextProtocols(QList<QByteArray> protocols)
+{
+ d->nextAllowedProtocols = protocols;
+}
+
+/*!
+ \since 5.3
+
+ This function returns the allowed protocols to be negotiated with the
+ server through the Next Protocol Negotiation (NPN) TLS extension, as set
+ by setAllowedNextProtocols().
+
+ \sa nextNegotiatedProtocol(), nextProtocolNegotiationStatus(), setAllowedNextProtocols(), QSslConfiguration::NextProtocolSpdy3_0, QSslConfiguration::NextProtocolHttp1_1
+ */
+QList<QByteArray> QSslConfiguration::allowedNextProtocols() const
+{
+ return d->nextAllowedProtocols;
+}
+
+/*!
+ \since 5.3
+
+ This function returns the status of the Next Protocol Negotiation (NPN).
+ If the feature has not been enabled through setAllowedNextProtocols(),
+ this function returns NextProtocolNegotiationNone.
+ The status will be set before emitting the encrypted() signal.
+
+ \sa setAllowedNextProtocols(), allowedNextProtocols(), nextNegotiatedProtocol(), QSslConfiguration::NextProtocolNegotiationStatus
+ */
+QSslConfiguration::NextProtocolNegotiationStatus QSslConfiguration::nextProtocolNegotiationStatus() const
+{
+ return d->nextProtocolNegotiationStatus;
+}
+
+/*!
Returns the default SSL configuration to be used in new SSL
connections.
@@ -663,7 +765,7 @@ int QSslConfiguration::sessionTicketLifeTimeHint() const
\li protocol SecureProtocols (meaning either TLS 1.0 or SSL 3 will be used)
\li the system's default CA certificate list
\li the cipher list equal to the list of the SSL libraries'
- supported SSL ciphers
+ supported SSL ciphers that are 128 bits or more
\endlist
\sa QSslSocket::supportedCiphers(), setDefaultConfiguration()
diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h
index a48eceb63e..587187ca06 100644
--- a/src/network/ssl/qsslconfiguration.h
+++ b/src/network/ssl/qsslconfiguration.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -131,6 +132,21 @@ public:
static QSslConfiguration defaultConfiguration();
static void setDefaultConfiguration(const QSslConfiguration &configuration);
+ enum NextProtocolNegotiationStatus {
+ NextProtocolNegotiationNone,
+ NextProtocolNegotiationNegotiated,
+ NextProtocolNegotiationUnsupported
+ };
+
+ void setAllowedNextProtocols(QList<QByteArray> protocols);
+ QList<QByteArray> allowedNextProtocols() const;
+
+ QByteArray nextNegotiatedProtocol() const;
+ NextProtocolNegotiationStatus nextProtocolNegotiationStatus() const;
+
+ static const char NextProtocolSpdy3_0[];
+ static const char NextProtocolHttp1_1[];
+
private:
friend class QSslSocket;
friend class QSslConfigurationPrivate;
diff --git a/src/network/ssl/qsslconfiguration_p.h b/src/network/ssl/qsslconfiguration_p.h
index 71ee8d2bfe..d183c3335c 100644
--- a/src/network/ssl/qsslconfiguration_p.h
+++ b/src/network/ssl/qsslconfiguration_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -86,7 +87,8 @@ public:
allowRootCertOnDemandLoading(true),
peerSessionShared(false),
sslOptions(QSslConfigurationPrivate::defaultSslOptions),
- sslSessionTicketLifeTimeHint(-1)
+ sslSessionTicketLifeTimeHint(-1),
+ nextProtocolNegotiationStatus(QSslConfiguration::NextProtocolNegotiationNone)
{ }
QSslCertificate peerCertificate;
@@ -114,6 +116,10 @@ public:
QByteArray sslSession;
int sslSessionTicketLifeTimeHint;
+ QList<QByteArray> nextAllowedProtocols;
+ QByteArray nextNegotiatedProtocol;
+ QSslConfiguration::NextProtocolNegotiationStatus nextProtocolNegotiationStatus;
+
// in qsslsocket.cpp:
static QSslConfiguration defaultConfiguration();
static void setDefaultConfiguration(const QSslConfiguration &configuration);
diff --git a/src/network/ssl/qsslcontext.cpp b/src/network/ssl/qsslcontext.cpp
index adf42fb79a..551804ec79 100644
--- a/src/network/ssl/qsslcontext.cpp
+++ b/src/network/ssl/qsslcontext.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -263,6 +264,45 @@ init_context:
return sslContext;
}
+#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+
+static int next_proto_cb(SSL *, unsigned char **out, unsigned char *outlen,
+ const unsigned char *in, unsigned int inlen, void *arg)
+{
+ QSslContext::NPNContext *ctx = reinterpret_cast<QSslContext::NPNContext *>(arg);
+
+ // comment out to debug:
+// QList<QByteArray> supportedVersions;
+// for (unsigned int i = 0; i < inlen; ) {
+// QByteArray version(reinterpret_cast<const char *>(&in[i+1]), in[i]);
+// supportedVersions << version;
+// i += in[i] + 1;
+// }
+
+ int proto = q_SSL_select_next_proto(out, outlen, in, inlen, ctx->data, ctx->len);
+ switch (proto) {
+ case OPENSSL_NPN_UNSUPPORTED:
+ ctx->status = QSslConfiguration::NextProtocolNegotiationNone;
+ break;
+ case OPENSSL_NPN_NEGOTIATED:
+ ctx->status = QSslConfiguration::NextProtocolNegotiationNegotiated;
+ break;
+ case OPENSSL_NPN_NO_OVERLAP:
+ ctx->status = QSslConfiguration::NextProtocolNegotiationUnsupported;
+ break;
+ default:
+ qWarning("OpenSSL sent unknown NPN status");
+ }
+
+ return SSL_TLSEXT_ERR_OK;
+}
+
+QSslContext::NPNContext QSslContext::npnContext() const
+{
+ return m_npnContext;
+}
+#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
+
// Needs to be deleted by caller
SSL* QSslContext::createSsl()
{
@@ -283,6 +323,26 @@ SSL* QSslContext::createSsl()
session = 0;
}
}
+
+#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+ QList<QByteArray> protocols = sslConfiguration.d->nextAllowedProtocols;
+ if (!protocols.isEmpty()) {
+ m_supportedNPNVersions.clear();
+ for (int a = 0; a < protocols.count(); ++a) {
+ if (protocols.at(a).size() > 255) {
+ qWarning() << "TLS NPN extension" << protocols.at(a)
+ << "is too long and will be truncated to 255 characters.";
+ protocols[a] = protocols.at(a).left(255);
+ }
+ m_supportedNPNVersions.append(protocols.at(a).size()).append(protocols.at(a));
+ }
+ m_npnContext.data = reinterpret_cast<unsigned char *>(m_supportedNPNVersions.data());
+ m_npnContext.len = m_supportedNPNVersions.count();
+ m_npnContext.status = QSslConfiguration::NextProtocolNegotiationNone;
+ q_SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &m_npnContext);
+ }
+#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
+
return ssl;
}
diff --git a/src/network/ssl/qsslcontext_p.h b/src/network/ssl/qsslcontext_p.h
index 2b596798a6..20b27c1ce7 100644
--- a/src/network/ssl/qsslcontext_p.h
+++ b/src/network/ssl/qsslcontext_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -72,6 +73,21 @@ public:
QByteArray sessionASN1() const;
void setSessionASN1(const QByteArray &sessionASN1);
int sessionTicketLifeTimeHint() const;
+
+#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+ // must be public because we want to use it from an OpenSSL callback
+ struct NPNContext {
+ NPNContext() : data(0),
+ len(0),
+ status(QSslConfiguration::NextProtocolNegotiationNone)
+ { }
+ unsigned char *data;
+ unsigned short len;
+ QSslConfiguration::NextProtocolNegotiationStatus status;
+ };
+ NPNContext npnContext() const;
+#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
+
protected:
QSslContext();
@@ -84,6 +100,10 @@ private:
QSslError::SslError errorCode;
QString errorStr;
QSslConfiguration sslConfiguration;
+#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+ QByteArray m_supportedNPNVersions;
+ NPNContext m_npnContext;
+#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
};
#endif // QT_NO_SSL
diff --git a/src/network/ssl/qsslkey.cpp b/src/network/ssl/qsslkey.cpp
index cf62f44855..95eed6e4b3 100644
--- a/src/network/ssl/qsslkey.cpp
+++ b/src/network/ssl/qsslkey.cpp
@@ -256,7 +256,7 @@ QSslKey::QSslKey(const QByteArray &encoded, QSsl::KeyAlgorithm algorithm,
a valid key.
*/
QSslKey::QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm, QSsl::EncodingFormat encoding,
- QSsl::KeyType type, const QByteArray &passPhrase)
+ QSsl::KeyType type, const QByteArray &passPhrase)
: d(new QSslKeyPrivate)
{
QByteArray encoded;
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 38b493a769..6edf4efae0 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -905,6 +906,9 @@ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration)
d->configuration.sslOptions = configuration.d->sslOptions;
d->configuration.sslSession = configuration.sessionTicket();
d->configuration.sslSessionTicketLifeTimeHint = configuration.sessionTicketLifeTimeHint();
+ d->configuration.nextAllowedProtocols = configuration.allowedNextProtocols();
+ d->configuration.nextNegotiatedProtocol = configuration.nextNegotiatedProtocol();
+ d->configuration.nextProtocolNegotiationStatus = configuration.nextProtocolNegotiationStatus();
// if the CA certificates were set explicitly (either via
// QSslConfiguration::setCaCertificates() or QSslSocket::setCaCertificates(),
@@ -1195,12 +1199,9 @@ void QSslSocket::setCiphers(const QString &ciphers)
Q_D(QSslSocket);
d->configuration.ciphers.clear();
foreach (const QString &cipherName, ciphers.split(QLatin1String(":"),QString::SkipEmptyParts)) {
- for (int i = 0; i < 3; ++i) {
- // ### Crude
- QSslCipher cipher(cipherName, QSsl::SslProtocol(i));
- if (!cipher.isNull())
- d->configuration.ciphers << cipher;
- }
+ QSslCipher cipher(cipherName);
+ if (!cipher.isNull())
+ d->configuration.ciphers << cipher;
}
}
@@ -1953,6 +1954,7 @@ void QSslSocketPrivate::init()
*/
QList<QSslCipher> QSslSocketPrivate::defaultCiphers()
{
+ QSslSocketPrivate::ensureInitialized();
QMutexLocker locker(&globalData()->mutex);
return globalData()->config->ciphers;
}
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 69b9e53884..3421154114 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -596,6 +596,7 @@ void QSslSocketPrivate::resetDefaultCiphers()
SSL *mySsl = q_SSL_new(myCtx);
QList<QSslCipher> ciphers;
+ QList<QSslCipher> defaultCiphers;
STACK_OF(SSL_CIPHER) *supportedCiphers = q_SSL_get_ciphers(mySsl);
for (int i = 0; i < q_sk_SSL_CIPHER_num(supportedCiphers); ++i) {
@@ -603,8 +604,11 @@ void QSslSocketPrivate::resetDefaultCiphers()
if (cipher->valid) {
QSslCipher ciph = QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(cipher);
if (!ciph.isNull()) {
+ // Unconditionally exclude ADH ciphers since they offer no MITM protection
if (!ciph.name().toLower().startsWith(QLatin1String("adh")))
ciphers << ciph;
+ if (ciph.usedBits() >= 128)
+ defaultCiphers << ciph;
}
}
}
@@ -614,7 +618,7 @@ void QSslSocketPrivate::resetDefaultCiphers()
q_SSL_free(mySsl);
setDefaultSupportedCiphers(ciphers);
- setDefaultCiphers(ciphers);
+ setDefaultCiphers(defaultCiphers);
}
QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
@@ -1482,6 +1486,15 @@ void QSslSocketBackendPrivate::continueHandshake()
}
}
+#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+ const unsigned char *proto;
+ unsigned int proto_len;
+ q_SSL_get0_next_proto_negotiated(ssl, &proto, &proto_len);
+ QByteArray nextProtocol(reinterpret_cast<const char *>(proto), proto_len);
+ configuration.nextNegotiatedProtocol = nextProtocol;
+ configuration.nextProtocolNegotiationStatus = sslContextPointer->npnContext().status;
+#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
+
connectionEncrypted = true;
emit q->encrypted();
if (autoStartHandshake && pendingClose) {
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
index ddf53f18f4..79bce22b0d 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -346,6 +347,20 @@ DEFINEFUNC(long, SSLeay, void, DUMMYARG, return 0, return)
DEFINEFUNC(const char *, SSLeay_version, int a, a, return 0, return)
DEFINEFUNC2(int, i2d_SSL_SESSION, SSL_SESSION *in, in, unsigned char **pp, pp, return 0, return)
DEFINEFUNC3(SSL_SESSION *, d2i_SSL_SESSION, SSL_SESSION **a, a, const unsigned char **pp, pp, long length, length, return 0, return)
+#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+DEFINEFUNC6(int, SSL_select_next_proto, unsigned char **out, out, unsigned char *outlen, outlen,
+ const unsigned char *in, in, unsigned int inlen, inlen,
+ const unsigned char *client, client, unsigned int client_len, client_len,
+ return -1, return)
+DEFINEFUNC3(void, SSL_CTX_set_next_proto_select_cb, SSL_CTX *s, s,
+ int (*cb) (SSL *ssl, unsigned char **out,
+ unsigned char *outlen,
+ const unsigned char *in,
+ unsigned int inlen, void *arg), cb,
+ void *arg, arg, return, DUMMYARG)
+DEFINEFUNC3(void, SSL_get0_next_proto_negotiated, const SSL *s, s,
+ const unsigned char **data, data, unsigned *len, len, return, DUMMYARG)
+#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
#define RESOLVEFUNC(func) \
if (!(_q_##func = _q_PTR_##func(libs.first->resolve(#func))) \
@@ -815,6 +830,11 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(SSLeay_version)
RESOLVEFUNC(i2d_SSL_SESSION)
RESOLVEFUNC(d2i_SSL_SESSION)
+#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+ RESOLVEFUNC(SSL_select_next_proto)
+ RESOLVEFUNC(SSL_CTX_set_next_proto_select_cb)
+ RESOLVEFUNC(SSL_get0_next_proto_negotiated)
+#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
symbolsResolved = true;
delete libs.first;
diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h
index 7e1a1c983c..500fe9493b 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols_p.h
+++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -79,13 +80,13 @@ QT_BEGIN_NAMESPACE
// **************** Shared declarations ******************
// ret func(arg)
-# define DEFINEFUNC(ret, func, arg, a, err, funcret) \
- typedef ret (*_q_PTR_##func)(arg); \
- static _q_PTR_##func _q_##func = 0; \
- ret q_##func(arg) { \
+# define DEFINEFUNC(ret, func, arg, a, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg); \
+ static _q_PTR_##func _q_##func = 0; \
+ ret q_##func(arg) { \
if (Q_UNLIKELY(!_q_##func)) { \
qsslSocketUnresolvedSymbolWarning(#func); \
- err; \
+ err; \
} \
funcret _q_##func(a); \
}
@@ -180,8 +181,8 @@ QT_BEGIN_NAMESPACE
// **************** Static declarations ******************
// ret func(arg)
-# define DEFINEFUNC(ret, func, arg, a, err, funcret) \
- ret q_##func(arg) { funcret func(a); }
+# define DEFINEFUNC(ret, func, arg, a, err, funcret) \
+ ret q_##func(arg) { funcret func(a); }
// ret func(arg1, arg2)
# define DEFINEFUNC2(ret, func, arg1, a, arg2, b, err, funcret) \
@@ -384,7 +385,7 @@ int q_X509_cmp(X509 *a, X509 *b);
#ifdef SSLEAY_MACROS
void *q_ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, char *x);
#define q_X509_dup(x509) (X509 *)q_ASN1_dup((i2d_of_void *)q_i2d_X509, \
- (d2i_of_void *)q_d2i_X509,(char *)x509)
+ (d2i_of_void *)q_d2i_X509,(char *)x509)
#else
X509 *q_X509_dup(X509 *a);
#endif
@@ -429,22 +430,22 @@ STACK_OF(X509) *q_X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx);
#define q_BIO_get_mem_data(b, pp) (int)q_BIO_ctrl(b,BIO_CTRL_INFO,0,(char *)pp)
#define q_BIO_pending(b) (int)q_BIO_ctrl(b,BIO_CTRL_PENDING,0,NULL)
#ifdef SSLEAY_MACROS
-int q_i2d_DSAPrivateKey(const DSA *a, unsigned char **pp);
-int q_i2d_RSAPrivateKey(const RSA *a, unsigned char **pp);
+int q_i2d_DSAPrivateKey(const DSA *a, unsigned char **pp);
+int q_i2d_RSAPrivateKey(const RSA *a, unsigned char **pp);
RSA *q_d2i_RSAPrivateKey(RSA **a, unsigned char **pp, long length);
DSA *q_d2i_DSAPrivateKey(DSA **a, unsigned char **pp, long length);
-#define q_PEM_read_bio_RSAPrivateKey(bp, x, cb, u) \
+#define q_PEM_read_bio_RSAPrivateKey(bp, x, cb, u) \
(RSA *)q_PEM_ASN1_read_bio( \
(void *(*)(void**, const unsigned char**, long int))q_d2i_RSAPrivateKey, PEM_STRING_RSA, bp, (void **)x, cb, u)
-#define q_PEM_read_bio_DSAPrivateKey(bp, x, cb, u) \
+#define q_PEM_read_bio_DSAPrivateKey(bp, x, cb, u) \
(DSA *)q_PEM_ASN1_read_bio( \
(void *(*)(void**, const unsigned char**, long int))q_d2i_DSAPrivateKey, PEM_STRING_DSA, bp, (void **)x, cb, u)
-#define q_PEM_write_bio_RSAPrivateKey(bp,x,enc,kstr,klen,cb,u) \
- PEM_ASN1_write_bio((int (*)(void*, unsigned char**))q_i2d_RSAPrivateKey,PEM_STRING_RSA,\
- bp,(char *)x,enc,kstr,klen,cb,u)
-#define q_PEM_write_bio_DSAPrivateKey(bp,x,enc,kstr,klen,cb,u) \
- PEM_ASN1_write_bio((int (*)(void*, unsigned char**))q_i2d_DSAPrivateKey,PEM_STRING_DSA,\
- bp,(char *)x,enc,kstr,klen,cb,u)
+#define q_PEM_write_bio_RSAPrivateKey(bp,x,enc,kstr,klen,cb,u) \
+ PEM_ASN1_write_bio((int (*)(void*, unsigned char**))q_i2d_RSAPrivateKey,PEM_STRING_RSA,\
+ bp,(char *)x,enc,kstr,klen,cb,u)
+#define q_PEM_write_bio_DSAPrivateKey(bp,x,enc,kstr,klen,cb,u) \
+ PEM_ASN1_write_bio((int (*)(void*, unsigned char**))q_i2d_DSAPrivateKey,PEM_STRING_DSA,\
+ bp,(char *)x,enc,kstr,klen,cb,u)
#endif
#define q_SSL_CTX_set_options(ctx,op) q_SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL)
#define q_SSL_CTX_set_mode(ctx,op) q_SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL)
@@ -461,9 +462,9 @@ DSA *q_d2i_DSAPrivateKey(DSA **a, unsigned char **pp, long length);
#define q_X509_get_notAfter(x) X509_get_notAfter(x)
#define q_X509_get_notBefore(x) X509_get_notBefore(x)
#define q_EVP_PKEY_assign_RSA(pkey,rsa) q_EVP_PKEY_assign((pkey),EVP_PKEY_RSA,\
- (char *)(rsa))
+ (char *)(rsa))
#define q_EVP_PKEY_assign_DSA(pkey,dsa) q_EVP_PKEY_assign((pkey),EVP_PKEY_DSA,\
- (char *)(dsa))
+ (char *)(dsa))
#define q_OpenSSL_add_all_algorithms() q_OPENSSL_add_all_algorithms_conf()
void q_OPENSSL_add_all_algorithms_noconf();
void q_OPENSSL_add_all_algorithms_conf();
@@ -473,6 +474,20 @@ const char *q_SSLeay_version(int type);
int q_i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp);
SSL_SESSION *q_d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, long length);
+#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+int q_SSL_select_next_proto(unsigned char **out, unsigned char *outlen,
+ const unsigned char *in, unsigned int inlen,
+ const unsigned char *client, unsigned int client_len);
+void q_SSL_CTX_set_next_proto_select_cb(SSL_CTX *s,
+ int (*cb) (SSL *ssl, unsigned char **out,
+ unsigned char *outlen,
+ const unsigned char *in,
+ unsigned int inlen, void *arg),
+ void *arg);
+void q_SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data,
+ unsigned *len);
+#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
+
// Helper function
class QDateTime;
QDateTime q_getTimeFromASN1(const ASN1_TIME *aTime);