summaryrefslogtreecommitdiffstats
path: root/src/network/socket/qlocalsocket_win.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/socket/qlocalsocket_win.cpp')
-rw-r--r--src/network/socket/qlocalsocket_win.cpp109
1 files changed, 59 insertions, 50 deletions
diff --git a/src/network/socket/qlocalsocket_win.cpp b/src/network/socket/qlocalsocket_win.cpp
index 229efe0226..b3f3f9002a 100644
--- a/src/network/socket/qlocalsocket_win.cpp
+++ b/src/network/socket/qlocalsocket_win.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** 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 The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlocalsocket_p.h"
#include <qscopedvaluerollback.h>
@@ -43,30 +7,48 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
namespace {
struct QSocketPoller
{
QSocketPoller(const QLocalSocketPrivate &socket);
+ qint64 getRemainingTime(const QDeadlineTimer &deadline) const;
bool poll(const QDeadlineTimer &deadline);
enum { maxHandles = 2 };
HANDLE handles[maxHandles];
DWORD handleCount = 0;
bool waitForClose = false;
+ bool writePending = false;
};
QSocketPoller::QSocketPoller(const QLocalSocketPrivate &socket)
{
- if (socket.pipeWriter)
+ if (socket.pipeWriter && socket.pipeWriter->isWriteOperationActive()) {
handles[handleCount++] = socket.pipeWriter->syncEvent();
+ writePending = true;
+ }
if (socket.pipeReader->isReadOperationActive())
handles[handleCount++] = socket.pipeReader->syncEvent();
else
waitForClose = true;
}
+qint64 QSocketPoller::getRemainingTime(const QDeadlineTimer &deadline) const
+{
+ const qint64 sleepTime = 10;
+ qint64 remainingTime = deadline.remainingTime();
+ if (waitForClose && (remainingTime > sleepTime || remainingTime == -1))
+ return sleepTime;
+
+ return remainingTime;
+}
+
/*!
+ \internal
+
Waits until new data is available for reading or write operation
completes. Returns \c true, if we need to check pipe workers;
otherwise it returns \c false (if an error occurred or the operation
@@ -77,9 +59,8 @@ QSocketPoller::QSocketPoller(const QLocalSocketPrivate &socket)
*/
bool QSocketPoller::poll(const QDeadlineTimer &deadline)
{
- const qint64 sleepTime = 10;
- QDeadlineTimer timer(waitForClose ? qMin(deadline.remainingTime(), sleepTime)
- : deadline.remainingTime());
+ Q_ASSERT(handleCount != 0);
+ QDeadlineTimer timer(getRemainingTime(deadline));
DWORD waitRet;
do {
@@ -88,7 +69,7 @@ bool QSocketPoller::poll(const QDeadlineTimer &deadline)
} while (waitRet == WAIT_IO_COMPLETION);
if (waitRet == WAIT_TIMEOUT)
- return !deadline.hasExpired();
+ return waitForClose || !deadline.hasExpired();
return waitRet - WAIT_OBJECT_0 < handleCount;
}
@@ -182,14 +163,14 @@ void QLocalSocket::connectToServer(OpenMode openMode)
emit stateChanged(d->state);
if (d->serverName.isEmpty()) {
d->error = ServerNotFoundError;
- d->errorString = tr("%1: Invalid name").arg(QLatin1String("QLocalSocket::connectToServer"));
+ d->errorString = tr("%1: Invalid name").arg("QLocalSocket::connectToServer"_L1);
d->state = UnconnectedState;
emit errorOccurred(d->error);
emit stateChanged(d->state);
return;
}
- const QLatin1String pipePath("\\\\.\\pipe\\");
+ const auto pipePath = "\\\\.\\pipe\\"_L1;
if (d->serverName.startsWith(pipePath))
d->fullServerName = d->serverName;
else
@@ -222,7 +203,7 @@ void QLocalSocket::connectToServer(OpenMode openMode)
if (localSocket == INVALID_HANDLE_VALUE) {
const DWORD winError = GetLastError();
- d->_q_winError(winError, QLatin1String("QLocalSocket::connectToServer"));
+ d->_q_winError(winError, "QLocalSocket::connectToServer"_L1);
d->fullServerName = QString();
return;
}
@@ -295,6 +276,8 @@ qint64 QLocalSocket::writeData(const char *data, qint64 len)
d->pipeWriter = new QWindowsPipeWriter(d->handle, this);
QObjectPrivate::connect(d->pipeWriter, &QWindowsPipeWriter::bytesWritten,
d, &QLocalSocketPrivate::_q_bytesWritten);
+ QObjectPrivate::connect(d->pipeWriter, &QWindowsPipeWriter::writeFailed,
+ d, &QLocalSocketPrivate::_q_writeFailed);
}
if (d->isWriteChunkCached(data, len))
@@ -379,6 +362,7 @@ void QLocalSocket::close()
Q_D(QLocalSocket);
QIODevice::close();
+ d->pipeReader->stopAndClear();
d->serverName = QString();
d->fullServerName = QString();
disconnectFromServer();
@@ -440,6 +424,16 @@ void QLocalSocketPrivate::_q_bytesWritten(qint64 bytes)
q->disconnectFromServer();
}
+void QLocalSocketPrivate::_q_writeFailed()
+{
+ Q_Q(QLocalSocket);
+ error = QLocalSocket::PeerClosedError;
+ errorString = QLocalSocket::tr("Remote closed");
+ emit q->errorOccurred(error);
+
+ _q_pipeClosed();
+}
+
qintptr QLocalSocket::socketDescriptor() const
{
Q_D(const QLocalSocket);
@@ -473,10 +467,22 @@ bool QLocalSocket::waitForDisconnected(int msecs)
}
QDeadlineTimer deadline(msecs);
+ bool wasChecked = false;
while (!d->pipeReader->isPipeClosed()) {
+ if (wasChecked && deadline.hasExpired())
+ return false;
+
QSocketPoller poller(*d);
- if (!poller.poll(deadline))
+ // The first parameter of the WaitForMultipleObjectsEx() call cannot
+ // be zero. So we have to call SleepEx() here.
+ if (!poller.writePending && poller.waitForClose) {
+ // Prevent waiting on the first pass, if both the pipe reader
+ // and the pipe writer are inactive.
+ if (wasChecked)
+ SleepEx(poller.getRemainingTime(deadline), TRUE);
+ } else if (!poller.poll(deadline)) {
return false;
+ }
if (d->pipeWriter)
d->pipeWriter->checkForWrite();
@@ -487,6 +493,7 @@ bool QLocalSocket::waitForDisconnected(int msecs)
d->pipeReader->checkPipeState();
d->pipeReader->checkForReadyRead();
+ wasChecked = true;
}
d->_q_pipeClosed();
return true;
@@ -529,22 +536,24 @@ bool QLocalSocket::waitForBytesWritten(int msecs)
return false;
QDeadlineTimer deadline(msecs);
+ bool wasChecked = false;
while (!d->pipeReader->isPipeClosed()) {
- if (bytesToWrite() == 0)
+ if (wasChecked && deadline.hasExpired())
return false;
QSocketPoller poller(*d);
- if (!poller.poll(deadline))
+ if (!poller.writePending || !poller.poll(deadline))
return false;
Q_ASSERT(d->pipeWriter);
if (d->pipeWriter->checkForWrite())
return true;
- if (poller.waitForClose)
+ if (poller.waitForClose && isValid())
d->pipeReader->checkPipeState();
d->pipeReader->checkForReadyRead();
+ wasChecked = true;
}
d->_q_pipeClosed();
return false;