winrt: Properly handle when a remote host closes a tcp connection.

Task-number: QTBUG-48476
Change-Id: I1933dfe7e73330a8f0d5ac8d3d7a834e0d77270a
Reviewed-by: Andrew Knight <andrew.knight@intopalo.com>
Reviewed-by: Samuel Nevala <samuel.nevala@intopalo.com>
Reviewed-by: Maurice Kalinowski <maurice.kalinowski@theqtcompany.com>
This commit is contained in:
Oliver Wolff 2015-10-14 08:11:04 +02:00 committed by Samuel Nevala
parent 49640d417f
commit ffa7b050a1

View File

@ -420,6 +420,16 @@ void QNativeSocketEngine::close()
{ {
Q_D(QNativeSocketEngine); Q_D(QNativeSocketEngine);
if (d->closingDown)
return;
d->closingDown = true;
d->notifyOnRead = false;
d->notifyOnWrite = false;
d->notifyOnException = false;
if (d->connectOp) { if (d->connectOp) {
ComPtr<IAsyncInfo> info; ComPtr<IAsyncInfo> info;
d->connectOp.As(&info); d->connectOp.As(&info);
@ -440,7 +450,6 @@ void QNativeSocketEngine::close()
} }
if (socket) { if (socket) {
d->closingDown = true;
socket->Close(); socket->Close();
d->socketDescriptor = -1; d->socketDescriptor = -1;
} }
@ -498,6 +507,14 @@ qint64 QNativeSocketEngine::read(char *data, qint64 maxlen)
if (d->socketType != QAbstractSocket::TcpSocket) if (d->socketType != QAbstractSocket::TcpSocket)
return -1; return -1;
// There will be a read notification when the socket was closed by the remote host. If that
// happens and there isn't anything left in the buffer, we have to return -1 in order to signal
// the closing of the socket.
if (d->readBytes.pos() == d->readBytes.size() && d->socketState != QAbstractSocket::ConnectedState) {
close();
return -1;
}
QMutexLocker mutexLocker(&d->readMutex); QMutexLocker mutexLocker(&d->readMutex);
return d->readBytes.read(data, maxlen); return d->readBytes.read(data, maxlen);
} }
@ -1184,8 +1201,16 @@ HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *async
if (wasDeleted || isDeletingChildren) if (wasDeleted || isDeletingChildren)
return S_OK; return S_OK;
if (status == Error || status == Canceled) // 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.
if (status == Error || status == Canceled) {
setError(QAbstractSocket::NetworkError, RemoteHostClosedErrorString);
socketState = QAbstractSocket::UnconnectedState;
if (notifyOnRead)
emit q->readReady();
return S_OK; return S_OK;
}
ComPtr<IBuffer> buffer; ComPtr<IBuffer> buffer;
HRESULT hr = asyncInfo->GetResults(&buffer); HRESULT hr = asyncInfo->GetResults(&buffer);
@ -1194,7 +1219,13 @@ HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *async
UINT32 bufferLength; UINT32 bufferLength;
hr = buffer->get_Length(&bufferLength); hr = buffer->get_Length(&bufferLength);
Q_ASSERT_SUCCEEDED(hr); Q_ASSERT_SUCCEEDED(hr);
// A zero sized buffer length signals, that the remote host closed the connection. The socket
// cannot be closed though, as the following read might have socket descriptor -1 and thus and
// the closing of the socket won't be communicated to the caller. So only the error is set. The
// actual socket close happens inside of read.
if (!bufferLength) { if (!bufferLength) {
setError(QAbstractSocket::NetworkError, RemoteHostClosedErrorString);
socketState = QAbstractSocket::UnconnectedState;
if (notifyOnRead) if (notifyOnRead)
emit q->readReady(); emit q->readReady();
return S_OK; return S_OK;