summaryrefslogtreecommitdiffstats
path: root/src/network/socket
diff options
context:
space:
mode:
authorOliver Wolff <oliver.wolff@qt.io>2016-10-10 14:35:19 +0200
committerOliver Wolff <oliver.wolff@qt.io>2016-10-14 05:53:06 +0000
commitdcf7da7c93c0d974bfb72ffa677a1d26fb9be5e0 (patch)
treeed0929a1f9418e6aeb16879314bac51baa19c1d5 /src/network/socket
parentd8c72f41548a01bf39f82e77da01a2be57a06d95 (diff)
winrt: Do not lose initial data for TCP connections
When a client connects and sends data immediately it was possible that initial data was lost as the state was set too late. If the callback was called before the state was set the socket engine just discarded the data. So the state has to be set before the callback is registered. The new implementation needs a list of pending read operations. It can happen that the "readyRead" callback is triggered directly while "put_Completed" is called. The callback reassigns readOp which causes a "function not implemented" exception when it jumps back to the "put_Completed" call in "initialize" Task-number: QTBUG-55889 Change-Id: I5f52e3377b6176f1f90f227ac0bf52b60ee2d95a Reviewed-by: Maurice Kalinowski <maurice.kalinowski@qt.io>
Diffstat (limited to 'src/network/socket')
-rw-r--r--src/network/socket/qnativesocketengine_winrt.cpp34
-rw-r--r--src/network/socket/qnativesocketengine_winrt_p.h2
2 files changed, 27 insertions, 9 deletions
diff --git a/src/network/socket/qnativesocketengine_winrt.cpp b/src/network/socket/qnativesocketengine_winrt.cpp
index bd9b443602..2ff028d2c5 100644
--- a/src/network/socket/qnativesocketengine_winrt.cpp
+++ b/src/network/socket/qnativesocketengine_winrt.cpp
@@ -317,26 +317,31 @@ bool QNativeSocketEngine::initialize(qintptr socketDescriptor, QAbstractSocket::
// Start processing incoming data
if (d->socketType == QAbstractSocket::TcpSocket) {
HRESULT hr;
- QEventDispatcherWinRT::runOnXamlThread([d, &hr, socket, this]() {
+ QEventDispatcherWinRT::runOnXamlThread([&hr, socket, socketState, this]() {
+ Q_D(QNativeSocketEngine);
ComPtr<IBuffer> buffer;
HRESULT hr = g->bufferFactory->Create(READ_BUFFER_SIZE, &buffer);
RETURN_OK_IF_FAILED("initialize(): Could not create buffer");
ComPtr<IInputStream> stream;
hr = socket->get_InputStream(&stream);
RETURN_OK_IF_FAILED("initialize(): Could not obtain input stream");
- hr = stream->ReadAsync(buffer.Get(), READ_BUFFER_SIZE, InputStreamOptions_Partial, d->readOp.GetAddressOf());
+ ComPtr<IAsyncBufferOperation> readOp;
+ hr = stream->ReadAsync(buffer.Get(), READ_BUFFER_SIZE, InputStreamOptions_Partial, readOp.GetAddressOf());
RETURN_OK_IF_FAILED_WITH_ARGS("initialize(): Failed to read from the socket buffer (%s).",
socketDescription(this).constData());
- hr = d->readOp->put_Completed(Callback<SocketReadCompletedHandler>(d, &QNativeSocketEnginePrivate::handleReadyRead).Get());
+ d->pendingReadOps.append(readOp);
+ d->socketState = socketState;
+ hr = readOp->put_Completed(Callback<SocketReadCompletedHandler>(d, &QNativeSocketEnginePrivate::handleReadyRead).Get());
RETURN_OK_IF_FAILED_WITH_ARGS("initialize(): Failed to set socket read callback (%s).",
socketDescription(this).constData());
return S_OK;
});
if (FAILED(hr))
return false;
+ } else {
+ d->socketState = socketState;
}
- d->socketState = socketState;
return true;
}
@@ -567,9 +572,9 @@ void QNativeSocketEngine::close()
}
#endif // _MSC_VER >= 1900
- if (d->readOp) {
+ for (ComPtr<IAsyncBufferOperation> readOp : d->pendingReadOps) {
ComPtr<IAsyncInfo> info;
- hr = d->readOp.As(&info);
+ hr = readOp.As(&info);
Q_ASSERT_SUCCEEDED(hr);
if (info) {
hr = info->Cancel();
@@ -933,9 +938,11 @@ void QNativeSocketEngine::establishRead()
hr = g->bufferFactory->Create(READ_BUFFER_SIZE, &buffer);
RETURN_HR_IF_FAILED("establishRead(): Failed to create buffer");
- hr = stream->ReadAsync(buffer.Get(), READ_BUFFER_SIZE, InputStreamOptions_Partial, &d->readOp);
+ ComPtr<IAsyncBufferOperation> readOp;
+ hr = stream->ReadAsync(buffer.Get(), READ_BUFFER_SIZE, InputStreamOptions_Partial, readOp.GetAddressOf());
RETURN_HR_IF_FAILED("establishRead(): Failed to initiate socket read");
- hr = d->readOp->put_Completed(Callback<SocketReadCompletedHandler>(d, &QNativeSocketEnginePrivate::handleReadyRead).Get());
+ d->pendingReadOps.append(readOp);
+ hr = readOp->put_Completed(Callback<SocketReadCompletedHandler>(d, &QNativeSocketEnginePrivate::handleReadyRead).Get());
RETURN_HR_IF_FAILED("establishRead(): Failed to register read callback");
return S_OK;
});
@@ -1410,7 +1417,15 @@ HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *async
}
Q_Q(QNativeSocketEngine);
+ for (int i = 0; i < pendingReadOps.count(); ++i) {
+ if (pendingReadOps.at(i).Get() == asyncInfo) {
+ pendingReadOps.takeAt(i);
+ break;
+ }
+ }
+ static QMutex mutex;
+ mutex.lock();
// A read in UnconnectedState will close the socket and return -1 and thus tell the caller,
// that the connection was closed. The socket cannot be closed here, as the subsequent read
// might fail then.
@@ -1463,6 +1478,7 @@ HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *async
if (notifyOnRead)
emit q->readReady();
+ mutex.unlock();
hr = QEventDispatcherWinRT::runOnXamlThread([buffer, q, this]() {
UINT32 readBufferLength;
@@ -1476,12 +1492,14 @@ HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *async
hr = buffer->put_Length(0);
RETURN_HR_IF_FAILED("handleReadyRead(): Could not set buffer length");
+ ComPtr<IAsyncBufferOperation> readOp;
hr = stream->ReadAsync(buffer.Get(), readBufferLength, InputStreamOptions_Partial, &readOp);
if (FAILED(hr)) {
qErrnoWarning(hr, "handleReadyRead(): Could not read into socket stream buffer (%s).",
socketDescription(q).constData());
return S_OK;
}
+ pendingReadOps.append(readOp);
hr = readOp->put_Completed(Callback<SocketReadCompletedHandler>(this, &QNativeSocketEnginePrivate::handleReadyRead).Get());
if (FAILED(hr)) {
qErrnoWarning(hr, "handleReadyRead(): Failed to set socket read callback (%s).",
diff --git a/src/network/socket/qnativesocketengine_winrt_p.h b/src/network/socket/qnativesocketengine_winrt_p.h
index 605f3631b9..79530d57f1 100644
--- a/src/network/socket/qnativesocketengine_winrt_p.h
+++ b/src/network/socket/qnativesocketengine_winrt_p.h
@@ -214,7 +214,7 @@ private:
{ return reinterpret_cast<ABI::Windows::Networking::Sockets::IDatagramSocket *>(socketDescriptor); }
Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocketListener> tcpListener;
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> connectOp;
- Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer *, UINT32>> readOp;
+ QVector<Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer *, UINT32>>> pendingReadOps;
QBuffer readBytes;
QMutex readMutex;
bool emitOnNewDatagram;