6#include <qscopedvaluerollback.h>
7#include <qdeadlinetimer.h>
11using namespace Qt::StringLiterals;
18 qint64 getRemainingTime(
const QDeadlineTimer &deadline)
const;
19 bool poll(
const QDeadlineTimer &deadline);
21 enum { maxHandles = 2 };
22 HANDLE handles[maxHandles];
23 DWORD handleCount = 0;
24 bool waitForClose =
false;
25 bool writePending =
false;
30 if (socket.pipeWriter && socket.pipeWriter->isWriteOperationActive()) {
31 handles[handleCount++] = socket.pipeWriter->syncEvent();
34 if (socket.pipeReader->isReadOperationActive())
35 handles[handleCount++] = socket.pipeReader->syncEvent();
40qint64 QSocketPoller::getRemainingTime(
const QDeadlineTimer &deadline)
const
42 const qint64 sleepTime = 10;
43 qint64 remainingTime = deadline.remainingTime();
44 if (waitForClose && (remainingTime > sleepTime || remainingTime == -1))
51
52
53
54
55
56
57
58
59
60
61bool QSocketPoller::poll(
const QDeadlineTimer &deadline)
63 Q_ASSERT(handleCount != 0);
68 waitRet = WaitForMultipleObjectsEx(handleCount, handles, FALSE,
69 timer.remainingTime(), TRUE);
70 }
while (waitRet == WAIT_IO_COMPLETION);
72 if (waitRet == WAIT_TIMEOUT)
73 return waitForClose || !deadline.hasExpired();
75 return waitRet - WAIT_OBJECT_0 < handleCount;
82 pipeReader =
new QWindowsPipeReader(q);
83 QObjectPrivate::connect(pipeReader, &QWindowsPipeReader::readyRead,
84 this, &QLocalSocketPrivate::_q_canRead);
85 q->connect(pipeReader, SIGNAL(pipeClosed()), SLOT(_q_pipeClosed()), Qt::QueuedConnection);
86 q->connect(pipeReader, SIGNAL(winError(ulong,QString)), SLOT(_q_winError(ulong,QString)));
92 QLocalSocket::LocalSocketState currentState = state;
95 if (state == QLocalSocket::ConnectingState && windowsError == ERROR_SEM_TIMEOUT)
96 windowsError = ERROR_NO_DATA;
98 switch (windowsError) {
99 case ERROR_PIPE_NOT_CONNECTED:
100 case ERROR_BROKEN_PIPE:
102 error = QLocalSocket::ConnectionError;
103 errorString = QLocalSocket::tr(
"%1: Connection error").arg(function);
104 state = QLocalSocket::UnconnectedState;
106 case ERROR_FILE_NOT_FOUND:
107 error = QLocalSocket::ServerNotFoundError;
108 errorString = QLocalSocket::tr(
"%1: Invalid name").arg(function);
109 state = QLocalSocket::UnconnectedState;
111 case ERROR_ACCESS_DENIED:
112 error = QLocalSocket::SocketAccessError;
113 errorString = QLocalSocket::tr(
"%1: Access denied").arg(function);
114 state = QLocalSocket::UnconnectedState;
117 error = QLocalSocket::UnknownSocketError;
118 errorString = QLocalSocket::tr(
"%1: Unknown error %2").arg(function).arg(windowsError);
119#if defined QLOCALSOCKET_DEBUG
120 qWarning() <<
"QLocalSocket error not handled:" << errorString;
122 state = QLocalSocket::UnconnectedState;
125 if (currentState != state) {
126 emit q->stateChanged(state);
127 if (state == QLocalSocket::UnconnectedState && currentState != QLocalSocket::ConnectingState)
128 emit q->disconnected();
130 emit q->errorOccurred(error);
134 handle(INVALID_HANDLE_VALUE),
137 error(QLocalSocket::UnknownSocketError),
138 state(QLocalSocket::UnconnectedState),
139 emittedReadyRead(
false),
140 emittedBytesWritten(
false)
146 Q_ASSERT(state == QLocalSocket::UnconnectedState);
147 Q_ASSERT(handle == INVALID_HANDLE_VALUE);
148 Q_ASSERT(pipeWriter ==
nullptr);
151void QLocalSocket::connectToServer(OpenMode openMode)
154 if (state() == ConnectedState || state() == ConnectingState) {
155 d->error = OperationError;
156 d->errorString = tr(
"Trying to connect while connection is in progress");
157 emit errorOccurred(QLocalSocket::OperationError);
161 d->error = QLocalSocket::UnknownSocketError;
162 d->errorString = QString();
163 d->state = ConnectingState;
164 emit stateChanged(d->state);
165 if (d->serverName.isEmpty()) {
166 d->error = ServerNotFoundError;
167 d->errorString = tr(
"%1: Invalid name").arg(
"QLocalSocket::connectToServer"_L1);
168 d->state = UnconnectedState;
169 emit errorOccurred(d->error);
170 emit stateChanged(d->state);
174 const auto pipePath =
"\\\\.\\pipe\\"_L1;
175 if (d->serverName.startsWith(pipePath))
176 d->fullServerName = d->serverName;
178 d->fullServerName = pipePath + d->serverName;
182 DWORD permissions = (openMode & QIODevice::ReadOnly) ? GENERIC_READ : 0;
183 permissions |= (openMode & QIODevice::WriteOnly) ? GENERIC_WRITE : 0;
184 localSocket = CreateFile(
reinterpret_cast<
const wchar_t *>(d->fullServerName.utf16()),
189 FILE_FLAG_OVERLAPPED,
192 if (localSocket != INVALID_HANDLE_VALUE)
194 DWORD error = GetLastError();
196 if (ERROR_PIPE_BUSY != error) {
201 if (!WaitNamedPipe((
const wchar_t *)d->fullServerName.utf16(), 5000))
205 if (localSocket == INVALID_HANDLE_VALUE) {
206 const DWORD winError = GetLastError();
207 d->_q_winError(winError,
"QLocalSocket::connectToServer"_L1);
208 d->fullServerName = QString();
213 if (setSocketDescriptor(
reinterpret_cast<qintptr>(localSocket), ConnectedState, openMode))
232qint64 QLocalSocket::readData(
char *data, qint64 maxSize)
239 return transformPipeReaderResult(d->pipeReader->read(data, maxSize));
242qint64 QLocalSocket::readLineData(
char *data, qint64 maxSize)
251 return transformPipeReaderResult(d->pipeReader->readLine(data, maxSize + 1));
254qint64 QLocalSocket::skipData(qint64 maxSize)
261 return transformPipeReaderResult(d->pipeReader->skip(maxSize));
264qint64 QLocalSocket::writeData(
const char *data, qint64 len)
268 d->error = OperationError;
269 d->errorString = tr(
"Socket is not connected");
276 if (!d->pipeWriter) {
277 d->pipeWriter =
new QWindowsPipeWriter(d->handle,
this);
278 QObjectPrivate::connect(d->pipeWriter, &QWindowsPipeWriter::bytesWritten,
279 d, &QLocalSocketPrivate::_q_bytesWritten);
280 QObjectPrivate::connect(d->pipeWriter, &QWindowsPipeWriter::writeFailed,
281 d, &QLocalSocketPrivate::_q_writeFailed);
284 if (d->isWriteChunkCached(data, len))
285 d->pipeWriter->write(*(d->currentWriteChunk));
287 d->pipeWriter->write(data, len);
292void QLocalSocket::abort()
296 delete d->pipeWriter;
305 if (!emittedReadyRead) {
306 QScopedValueRollback<
bool> guard(emittedReadyRead,
true);
314 if (state == QLocalSocket::UnconnectedState)
317 if (state != QLocalSocket::ClosingState) {
318 state = QLocalSocket::ClosingState;
319 emit q->stateChanged(state);
320 if (state != QLocalSocket::ClosingState)
325 fullServerName.clear();
328 pipeWriter =
nullptr;
329 if (handle != INVALID_HANDLE_VALUE) {
330 DisconnectNamedPipe(handle);
332 handle = INVALID_HANDLE_VALUE;
335 state = QLocalSocket::UnconnectedState;
336 emit q->stateChanged(state);
337 emit q->readChannelFinished();
338 emit q->disconnected();
341qint64 QLocalSocket::bytesAvailable()
const
343 Q_D(
const QLocalSocket);
344 qint64 available = QIODevice::bytesAvailable();
345 available += d->pipeReader->bytesAvailable();
349qint64 QLocalSocket::bytesToWrite()
const
351 Q_D(
const QLocalSocket);
352 return d->pipeWriterBytesToWrite();
355bool QLocalSocket::canReadLine()
const
357 Q_D(
const QLocalSocket);
358 return QIODevice::canReadLine() || d->pipeReader->canReadLine();
361void QLocalSocket::close()
366 d->pipeReader->stopAndClear();
367 d->serverName = QString();
368 d->fullServerName = QString();
369 disconnectFromServer();
372bool QLocalSocket::flush()
376 return d->pipeWriter && d->pipeWriter->checkForWrite();
379void QLocalSocket::disconnectFromServer()
383 if (bytesToWrite() == 0) {
385 }
else if (d->state != QLocalSocket::ClosingState) {
386 d->state = QLocalSocket::ClosingState;
387 emit stateChanged(d->state);
391QLocalSocket::LocalSocketError QLocalSocket::error()
const
393 Q_D(
const QLocalSocket);
397bool QLocalSocket::setSocketDescriptor(qintptr socketDescriptor,
398 LocalSocketState socketState, OpenMode openMode)
401 d->pipeReader->stop();
402 d->handle =
reinterpret_cast<HANDLE>(socketDescriptor);
403 d->state = socketState;
404 d->pipeReader->setHandle(d->handle);
405 QIODevice::open(openMode);
406 emit stateChanged(d->state);
407 if (d->state == ConnectedState && openMode.testFlag(QIODevice::ReadOnly))
408 d->pipeReader->startAsyncRead();
414 return pipeWriter ? pipeWriter->bytesToWrite() : qint64(0);
420 if (!emittedBytesWritten) {
421 QScopedValueRollback<
bool> guard(emittedBytesWritten,
true);
422 emit q->bytesWritten(bytes);
424 if (state == QLocalSocket::ClosingState)
425 q->disconnectFromServer();
431 error = QLocalSocket::PeerClosedError;
432 errorString = QLocalSocket::tr(
"Remote closed");
433 emit q->errorOccurred(error);
438qintptr QLocalSocket::socketDescriptor()
const
440 Q_D(
const QLocalSocket);
441 return reinterpret_cast<qintptr>(d->handle);
444qint64 QLocalSocket::readBufferSize()
const
446 Q_D(
const QLocalSocket);
447 return d->pipeReader->maxReadBufferSize();
450void QLocalSocket::setReadBufferSize(qint64 size)
453 d->pipeReader->setMaxReadBufferSize(size);
456bool QLocalSocket::waitForConnected(
int msecs)
459 return (state() == ConnectedState);
462bool QLocalSocket::waitForDisconnected(
int msecs)
465 if (state() == UnconnectedState) {
466 qWarning(
"QLocalSocket::waitForDisconnected() is not allowed in UnconnectedState");
470 QDeadlineTimer deadline(msecs);
471 bool wasChecked =
false;
472 while (!d->pipeReader->isPipeClosed()) {
473 if (wasChecked && deadline.hasExpired())
476 QSocketPoller poller(*d);
479 if (!poller.writePending && poller.waitForClose) {
483 SleepEx(poller.getRemainingTime(deadline), TRUE);
484 }
else if (!poller.poll(deadline)) {
489 d->pipeWriter->checkForWrite();
493 if (poller.waitForClose && isValid())
494 d->pipeReader->checkPipeState();
496 d->pipeReader->checkForReadyRead();
503bool QLocalSocket::isValid()
const
505 Q_D(
const QLocalSocket);
506 return d->handle != INVALID_HANDLE_VALUE;
509bool QLocalSocket::waitForReadyRead(
int msecs)
513 if (d->state != QLocalSocket::ConnectedState)
516 QDeadlineTimer deadline(msecs);
517 while (!d->pipeReader->isPipeClosed()) {
518 QSocketPoller poller(*d);
519 if (poller.waitForClose || !poller.poll(deadline))
523 d->pipeWriter->checkForWrite();
525 if (d->pipeReader->checkForReadyRead())
532bool QLocalSocket::waitForBytesWritten(
int msecs)
536 if (d->state == QLocalSocket::UnconnectedState)
539 QDeadlineTimer deadline(msecs);
540 bool wasChecked =
false;
541 while (!d->pipeReader->isPipeClosed()) {
542 if (wasChecked && deadline.hasExpired())
545 QSocketPoller poller(*d);
546 if (!poller.writePending || !poller.poll(deadline))
549 Q_ASSERT(d->pipeWriter);
550 if (d->pipeWriter->checkForWrite())
553 if (poller.waitForClose && isValid())
554 d->pipeReader->checkPipeState();
556 d->pipeReader->checkForReadyRead();
static qint64 transformPipeReaderResult(qint64 res)