summaryrefslogtreecommitdiffstats
path: root/src/network/socket/qnativesocketengine_winrt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/socket/qnativesocketengine_winrt.cpp')
-rw-r--r--src/network/socket/qnativesocketengine_winrt.cpp415
1 files changed, 197 insertions, 218 deletions
diff --git a/src/network/socket/qnativesocketengine_winrt.cpp b/src/network/socket/qnativesocketengine_winrt.cpp
index 1646940cb8..c3be3eb408 100644
--- a/src/network/socket/qnativesocketengine_winrt.cpp
+++ b/src/network/socket/qnativesocketengine_winrt.cpp
@@ -1,40 +1,32 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 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$
+** $QT_BEGIN_LICENSE:LGPL21$
** 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
+** 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.
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** 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
+** 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$
**
****************************************************************************/
@@ -51,8 +43,14 @@
#include <qelapsedtimer.h>
#include <qthread.h>
#include <qabstracteventdispatcher.h>
+#include <qfunctions_winrt.h>
+
+#include <private/qthread_p.h>
+#include <private/qabstractsocket_p.h>
-#include <private/qeventdispatcher_winrt_p.h>
+#ifndef QT_NO_SSL
+#include <QSslSocket>
+#endif
#include <wrl.h>
#include <windows.foundation.collections.h>
@@ -124,6 +122,20 @@ struct SocketHandler
Q_GLOBAL_STATIC(SocketHandler, gSocketHandler)
+struct SocketGlobal
+{
+ SocketGlobal()
+ {
+ HRESULT hr;
+ hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
+ &bufferFactory);
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+
+ ComPtr<IBufferFactory> bufferFactory;
+};
+Q_GLOBAL_STATIC(SocketGlobal, g)
+
static inline QString qt_QStringFromHString(const HString &string)
{
UINT32 length;
@@ -131,60 +143,7 @@ static inline QString qt_QStringFromHString(const HString &string)
return QString::fromWCharArray(rawString, length);
}
-#define READ_BUFFER_SIZE 8192
-
-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;
- }
-
- ComPtr<IInputStream> inputStream() const
- {
- return m_stream;
- }
-
- void setInputStream(ComPtr<IInputStream> stream)
- {
- m_stream = stream;
- }
-
-private:
- QByteArray m_bytes;
- UINT32 m_length;
- ComPtr<IInputStream> m_stream;
-};
+#define READ_BUFFER_SIZE 65536
template <typename T>
static AsyncStatus opStatus(const ComPtr<T> &op)
@@ -207,6 +166,12 @@ static AsyncStatus opStatus(const ComPtr<T> &op)
QNativeSocketEngine::QNativeSocketEngine(QObject *parent)
: QAbstractSocketEngine(*new QNativeSocketEnginePrivate(), parent)
{
+#ifndef QT_NO_SSL
+ Q_D(QNativeSocketEngine);
+ if (parent)
+ d->sslSocket = qobject_cast<QSslSocket *>(parent->parent());
+#endif
+
connect(this, SIGNAL(connectionReady()), SLOT(connectionNotification()), Qt::QueuedConnection);
connect(this, SIGNAL(readReady()), SLOT(readNotification()), Qt::QueuedConnection);
connect(this, SIGNAL(writeReady()), SLOT(writeNotification()), Qt::QueuedConnection);
@@ -239,16 +204,14 @@ bool QNativeSocketEngine::initialize(qintptr socketDescriptor, QAbstractSocket::
if (isValid())
close();
- d->socketDescriptor = socketDescriptor;
-
// Currently, only TCP sockets are initialized this way.
- SocketHandler *handler = gSocketHandler();
- d->tcp = handler->pendingTcpSockets.take(socketDescriptor);
+ d->socketDescriptor = qintptr(gSocketHandler->pendingTcpSockets.take(socketDescriptor));
d->socketType = QAbstractSocket::TcpSocket;
- if (!d->tcp || !d->fetchConnectionParameters()) {
+ if (!d->socketDescriptor || !d->fetchConnectionParameters()) {
d->setError(QAbstractSocket::UnsupportedSocketOperationError,
d->InvalidSocketErrorString);
+ d->socketDescriptor = -1;
return false;
}
@@ -287,68 +250,23 @@ bool QNativeSocketEngine::connectToHostByName(const QString &name, quint16 port)
return false;
}
- ComPtr<IAsyncAction> op;
const QString portString = QString::number(port);
HStringReference portReference(reinterpret_cast<LPCWSTR>(portString.utf16()));
HRESULT hr = E_FAIL;
if (d->socketType == QAbstractSocket::TcpSocket)
- hr = d->tcp->ConnectAsync(remoteHost.Get(), portReference.Get(), &op);
+ hr = d->tcpSocket()->ConnectAsync(remoteHost.Get(), portReference.Get(), &d->connectOp);
else if (d->socketType == QAbstractSocket::UdpSocket)
- hr = d->udp->ConnectAsync(remoteHost.Get(), portReference.Get(), &op);
+ hr = d->udpSocket()->ConnectAsync(remoteHost.Get(), portReference.Get(), &d->connectOp);
if (FAILED(hr)) {
qWarning("QNativeSocketEnginePrivate::nativeConnect:: Could not obtain connect action");
return false;
}
-
- hr = op->put_Completed(Callback<IAsyncActionCompletedHandler>(
- d, &QNativeSocketEnginePrivate::handleConnectToHost).Get());
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Unable to set host connection callback.");
- return false;
- }
d->socketState = QAbstractSocket::ConnectingState;
- while (opStatus(op) == Started)
- d->eventLoop.processEvents();
+ hr = d->connectOp->put_Completed(Callback<IAsyncActionCompletedHandler>(
+ d, &QNativeSocketEnginePrivate::handleConnectToHost).Get());
+ Q_ASSERT_SUCCEEDED(hr);
- AsyncStatus status = opStatus(op);
- if (status == Error || status == Canceled)
- return false;
-
- 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) {
- IInputStream *stream;
- hr = d->tcp->get_InputStream(&stream);
- if (FAILED(hr))
- return false;
- ByteArrayBuffer *buffer = static_cast<ByteArrayBuffer *>(d->readBuffer.Get());
- buffer->setInputStream(stream);
- ComPtr<IAsyncBufferOperation> op;
- hr = stream->ReadAsync(buffer, READ_BUFFER_SIZE, InputStreamOptions_Partial, &op);
- if (FAILED(hr))
- return false;
- hr = op->put_Completed(Callback<SocketReadCompletedHandler>(d, &QNativeSocketEnginePrivate::handleReadyRead).Get());
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to set socket read callback.");
- return false;
- }
- }
- d->socketState = QAbstractSocket::ConnectedState;
- return true;
+ return d->socketState == QAbstractSocket::ConnectedState;
}
bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port)
@@ -385,7 +303,7 @@ bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port)
return false;
}
} else if (d->socketType == QAbstractSocket::UdpSocket) {
- hr = d->udp->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op);
+ hr = d->udpSocket()->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op);
if (FAILED(hr)) {
qErrnoWarning(hr, "Unable to bind socket."); // ### Set error message
return false;
@@ -447,13 +365,16 @@ int QNativeSocketEngine::accept()
if (d->socketType == QAbstractSocket::TcpSocket) {
IStreamSocket *socket = d->pendingConnections.takeFirst();
- IInputStream *stream;
- socket->get_InputStream(&stream);
- // TODO: delete buffer and stream on socket close
- ByteArrayBuffer *buffer = static_cast<ByteArrayBuffer *>(d->readBuffer.Get());
- buffer->setInputStream(stream);
+ HRESULT hr;
+ ComPtr<IBuffer> buffer;
+ hr = g->bufferFactory->Create(READ_BUFFER_SIZE, &buffer);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IInputStream> stream;
+ hr = socket->get_InputStream(&stream);
+ Q_ASSERT_SUCCEEDED(hr);
ComPtr<IAsyncBufferOperation> op;
- HRESULT hr = stream->ReadAsync(buffer, READ_BUFFER_SIZE, InputStreamOptions_Partial, &op);
+ hr = stream->ReadAsync(buffer.Get(), READ_BUFFER_SIZE, InputStreamOptions_Partial, &op);
if (FAILED(hr)) {
qErrnoWarning(hr, "Faild to read from the socket buffer.");
return -1;
@@ -476,17 +397,29 @@ int QNativeSocketEngine::accept()
void QNativeSocketEngine::close()
{
Q_D(QNativeSocketEngine);
+
+ if (d->connectOp) {
+ ComPtr<IAsyncInfo> info;
+ d->connectOp.As(&info);
+ if (info) {
+ info->Cancel();
+ info->Close();
+ }
+ }
+
if (d->socketDescriptor != -1) {
- IClosable *socket = 0;
- if (d->socketType == QAbstractSocket::TcpSocket && d->tcp)
- d->tcp->QueryInterface(IID_PPV_ARGS(&socket));
- else if (d->socketType == QAbstractSocket::UdpSocket && d->udp)
- d->udp->QueryInterface(IID_PPV_ARGS(&socket));
+ ComPtr<IClosable> socket;
+ if (d->socketType == QAbstractSocket::TcpSocket) {
+ d->tcpSocket()->QueryInterface(IID_PPV_ARGS(&socket));
+ d->tcpSocket()->Release();
+ } else if (d->socketType == QAbstractSocket::UdpSocket) {
+ d->udpSocket()->QueryInterface(IID_PPV_ARGS(&socket));
+ d->udpSocket()->Release();
+ }
if (socket) {
d->closingDown = true;
socket->Close();
- socket->Release();
d->socketDescriptor = -1;
}
d->socketDescriptor = -1;
@@ -550,42 +483,40 @@ qint64 QNativeSocketEngine::read(char *data, qint64 maxlen)
qint64 QNativeSocketEngine::write(const char *data, qint64 len)
{
Q_D(QNativeSocketEngine);
+ if (!isValid())
+ return -1;
+
HRESULT hr = E_FAIL;
ComPtr<IOutputStream> stream;
if (d->socketType == QAbstractSocket::TcpSocket)
- hr = d->tcp->get_OutputStream(&stream);
+ hr = d->tcpSocket()->get_OutputStream(&stream);
else if (d->socketType == QAbstractSocket::UdpSocket)
- hr = d->udp->get_OutputStream(&stream);
+ hr = d->udpSocket()->get_OutputStream(&stream);
if (FAILED(hr)) {
qErrnoWarning(hr, "Failed to get output stream to socket.");
return -1;
}
- ComPtr<ByteArrayBuffer> buffer = Make<ByteArrayBuffer>(data, len);
+ ComPtr<IBuffer> buffer;
+ hr = g->bufferFactory->Create(len, &buffer);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = buffer->put_Length(len);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
+ hr = buffer.As(&byteArrayAccess);
+ Q_ASSERT_SUCCEEDED(hr);
+ byte *bytes;
+ hr = byteArrayAccess->Buffer(&bytes);
+ Q_ASSERT_SUCCEEDED(hr);
+ memcpy(bytes, data, len);
ComPtr<IAsyncOperationWithProgress<UINT32, UINT32>> op;
hr = stream->WriteAsync(buffer.Get(), &op);
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to write to socket.");
- return -1;
- }
- hr = op->put_Completed(Callback<IAsyncOperationWithProgressCompletedHandler<UINT32, UINT32>>(
- d, &QNativeSocketEnginePrivate::handleWriteCompleted).Get());
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to set socket write callback.");
- return -1;
- }
-
- while (opStatus(op) == Started)
- d->eventLoop.processEvents();
-
- AsyncStatus status = opStatus(op);
- if (status == Error || status == Canceled)
- return -1;
+ RETURN_IF_FAILED("Failed to write to stream", return -1);
UINT32 bytesWritten;
- hr = op->GetResults(&bytesWritten);
+ hr = QWinRTFunctions::await(op, &bytesWritten);
if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to get written socket length.");
+ d->setError(QAbstractSocket::SocketAccessError, QNativeSocketEnginePrivate::AccessErrorString);
return -1;
}
@@ -624,11 +555,10 @@ qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxlen, QHostAddress
*addr = returnAddress;
*port = returnPort;
arg = d->pendingDatagrams.takeFirst();
+ arg->Release();
// TODO: fill data
Q_UNUSED(data);
- arg->Release();
- delete arg;
--i;
return maxlen;
}
@@ -657,7 +587,7 @@ qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 len, const QH
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)))
+ if (FAILED(d->udpSocket()->GetOutputStreamAsync(remoteHost.Get(), portRef.Get(), &streamOperation)))
return -1;
HRESULT hr;
while (hr = streamOperation->GetResults(&stream) == E_ILLEGAL_METHOD_CALL)
@@ -827,29 +757,50 @@ void QNativeSocketEngine::setExceptionNotificationEnabled(bool enable)
d->notifyOnException = enable;
}
+void QNativeSocketEngine::establishRead()
+{
+ Q_D(QNativeSocketEngine);
+
+ HRESULT hr;
+ ComPtr<IInputStream> stream;
+ hr = d->tcpSocket()->get_InputStream(&stream);
+ RETURN_VOID_IF_FAILED("Failed to get socket input stream");
+
+ ComPtr<IBuffer> buffer;
+ hr = g->bufferFactory->Create(READ_BUFFER_SIZE, &buffer);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IAsyncBufferOperation> op;
+ hr = stream->ReadAsync(buffer.Get(), READ_BUFFER_SIZE, InputStreamOptions_Partial, &op);
+ RETURN_VOID_IF_FAILED("Failed to initiate socket read");
+ hr = op->put_Completed(Callback<SocketReadCompletedHandler>(d, &QNativeSocketEnginePrivate::handleReadyRead).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+}
+
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)))) {
+ ComPtr<IStreamSocket> socket;
+ HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocket).Get(), &socket);
+ if (FAILED(hr)) {
qWarning("Failed to create StreamSocket instance");
return false;
}
- socketDescriptor = ++handler->socketCount;
+ socketDescriptor = qintptr(socket.Detach());
return true;
}
case QAbstractSocket::UdpSocket: {
- if (FAILED(RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_DatagramSocket).Get(),
- reinterpret_cast<IInspectable **>(&udp)))) {
+ ComPtr<IDatagramSocket> socket;
+ HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_DatagramSocket).Get(), &socket);
+ if (FAILED(hr)) {
qWarning("Failed to create stream socket");
return false;
}
EventRegistrationToken token;
- udp->add_MessageReceived(Callback<DatagramReceivedHandler>(this, &QNativeSocketEnginePrivate::handleNewDatagram).Get(), &token);
- socketDescriptor = ++handler->socketCount;
+ socketDescriptor = qintptr(socket.Detach());
+ udpSocket()->add_MessageReceived(Callback<DatagramReceivedHandler>(this, &QNativeSocketEnginePrivate::handleNewDatagram).Get(), &token);
return true;
}
default:
@@ -866,9 +817,8 @@ QNativeSocketEnginePrivate::QNativeSocketEnginePrivate()
, notifyOnException(false)
, closingDown(false)
, socketDescriptor(-1)
+ , sslSocket(Q_NULLPTR)
{
- ComPtr<ByteArrayBuffer> buffer = Make<ByteArrayBuffer>(READ_BUFFER_SIZE);
- readBuffer = buffer;
}
QNativeSocketEnginePrivate::~QNativeSocketEnginePrivate()
@@ -982,7 +932,7 @@ int QNativeSocketEnginePrivate::option(QAbstractSocketEngine::SocketOption opt)
{
ComPtr<IStreamSocketControl> control;
if (socketType == QAbstractSocket::TcpSocket) {
- if (FAILED(tcp->get_Control(&control))) {
+ if (FAILED(tcpSocket()->get_Control(&control))) {
qWarning("QNativeSocketEnginePrivate::option: Could not obtain socket control");
return -1;
}
@@ -1038,7 +988,7 @@ bool QNativeSocketEnginePrivate::setOption(QAbstractSocketEngine::SocketOption o
{
ComPtr<IStreamSocketControl> control;
if (socketType == QAbstractSocket::TcpSocket) {
- if (FAILED(tcp->get_Control(&control))) {
+ if (FAILED(tcpSocket()->get_Control(&control))) {
qWarning("QNativeSocketEnginePrivate::setOption: Could not obtain socket control");
return false;
}
@@ -1102,7 +1052,7 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters()
ComPtr<IHostName> hostName;
HString tmpHString;
ComPtr<IStreamSocketInformation> info;
- if (FAILED(tcp->get_Information(&info))) {
+ if (FAILED(tcpSocket()->get_Information(&info))) {
qWarning("QNativeSocketEnginePrivate::fetchConnectionParameters: Could not obtain socket info");
return false;
}
@@ -1131,7 +1081,7 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters()
ComPtr<IHostName> hostName;
HString tmpHString;
ComPtr<IDatagramSocketInformation> info;
- if (FAILED(udp->get_Information(&info))) {
+ if (FAILED(udpSocket()->get_Information(&info))) {
qWarning("QNativeSocketEnginePrivate::fetchConnectionParameters: Could not obtain socket information");
return false;
}
@@ -1171,8 +1121,46 @@ HRESULT QNativeSocketEnginePrivate::handleClientConnection(IStreamSocketListener
return S_OK;
}
-HRESULT QNativeSocketEnginePrivate::handleConnectToHost(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus)
+HRESULT QNativeSocketEnginePrivate::handleConnectToHost(IAsyncAction *action, AsyncStatus)
{
+ Q_Q(QNativeSocketEngine);
+
+ HRESULT hr = action->GetResults();
+ if (wasDeleted || !connectOp) // Protect against a late callback
+ return S_OK;
+
+ connectOp.Reset();
+ switch (hr) {
+ case 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.
+ setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ return S_OK;
+ case 0x80072751: // A socket operation was attempted to an unreachable host.
+ setError(QAbstractSocket::HostNotFoundError, HostUnreachableErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ return S_OK;
+ case 0x8007274d: // No connection could be made because the target machine actively refused it.
+ setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ return S_OK;
+ default:
+ if (FAILED(hr)) {
+ setError(QAbstractSocket::UnknownSocketError, UnknownSocketErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ return S_OK;
+ }
+ break;
+ }
+
+ socketState = QAbstractSocket::ConnectedState;
+ emit q->connectionReady();
+
+ // Delay the reader so that the SSL socket can upgrade
+ if (sslSocket)
+ q->connect(sslSocket, SIGNAL(encrypted()), SLOT(establishRead()));
+ else
+ q->establishRead();
+
return S_OK;
}
@@ -1185,22 +1173,25 @@ HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *async
if (status == Error || status == Canceled)
return S_OK;
- ByteArrayBuffer *buffer = 0;
- HRESULT hr = asyncInfo->GetResults((IBuffer **)&buffer);
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to get ready read results.");
- return S_OK;
- }
- UINT32 len;
- buffer->get_Length(&len);
- if (!len) {
+ ComPtr<IBuffer> buffer;
+ HRESULT hr = asyncInfo->GetResults(&buffer);
+ RETURN_OK_IF_FAILED("Failed to get read results buffer");
+
+ UINT32 bufferLength;
+ hr = buffer->get_Length(&bufferLength);
+ Q_ASSERT_SUCCEEDED(hr);
+ if (!bufferLength) {
if (q->isReadNotificationEnabled())
emit q->readReady();
return S_OK;
}
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
+ hr = buffer.As(&byteArrayAccess);
+ Q_ASSERT_SUCCEEDED(hr);
byte *data;
- buffer->Buffer(&data);
+ hr = byteArrayAccess->Buffer(&data);
+ Q_ASSERT_SUCCEEDED(hr);
readMutex.lock();
if (readBytes.atEnd()) // Everything has been read; the buffer is safe to reset
@@ -1210,15 +1201,25 @@ HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *async
qint64 readPos = readBytes.pos();
readBytes.seek(readBytes.size());
Q_ASSERT(readBytes.atEnd());
- readBytes.write(reinterpret_cast<const char*>(data), qint64(len));
+ readBytes.write(reinterpret_cast<const char*>(data), qint64(bufferLength));
readBytes.seek(readPos);
readMutex.unlock();
if (q->isReadNotificationEnabled())
emit q->readReady();
+ ComPtr<IInputStream> stream;
+ hr = tcpSocket()->get_InputStream(&stream);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ // Reuse the stream buffer
+ hr = buffer->get_Capacity(&bufferLength);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = buffer->put_Length(0);
+ Q_ASSERT_SUCCEEDED(hr);
+
ComPtr<IAsyncBufferOperation> op;
- hr = buffer->inputStream()->ReadAsync(buffer, READ_BUFFER_SIZE, InputStreamOptions_Partial, &op);
+ hr = stream->ReadAsync(buffer.Get(), bufferLength, InputStreamOptions_Partial, &op);
if (FAILED(hr)) {
qErrnoWarning(hr, "Could not read into socket stream buffer.");
return S_OK;
@@ -1231,32 +1232,10 @@ HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *async
return S_OK;
}
-HRESULT QNativeSocketEnginePrivate::handleWriteCompleted(IAsyncOperationWithProgress<UINT32, UINT32> *op, AsyncStatus status)
-{
- if (status == Error) {
- ComPtr<IAsyncInfo> info;
- HRESULT hr = op->QueryInterface(IID_PPV_ARGS(&info));
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to cast operation.");
- return S_OK;
- }
- HRESULT errorCode;
- hr = info->get_ErrorCode(&errorCode);
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to get error code.");
- return S_OK;
- }
- qErrnoWarning(errorCode, "A socket error occurred.");
- return S_OK;
- }
-
- return S_OK;
-}
-
HRESULT QNativeSocketEnginePrivate::handleNewDatagram(IDatagramSocket *socket, IDatagramSocketMessageReceivedEventArgs *args)
{
Q_Q(QNativeSocketEngine);
- Q_UNUSED(socket)
+ Q_UNUSED(socket);
pendingDatagrams.append(args);
emit q->readReady();