Qt 4.8
qlocalsocket_win.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qlocalsocket_p.h"
43 
44 #include <private/qthread_p.h>
45 #include <qcoreapplication.h>
46 #include <qdebug.h>
47 
49 
51 {
53  memset(&overlapped, 0, sizeof(overlapped));
54  overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
56  q->connect(dataReadNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_notified()));
57 }
58 
60 {
62  BOOL windowsError = GetLastError();
64 
65  // If the connectToServer fails due to WaitNamedPipe() time-out, assume ConnectionError
66  if (state == QLocalSocket::ConnectingState && windowsError == ERROR_SEM_TIMEOUT)
67  windowsError = ERROR_NO_DATA;
68 
69  switch (windowsError) {
70  case ERROR_PIPE_NOT_CONNECTED:
71  case ERROR_BROKEN_PIPE:
72  case ERROR_NO_DATA:
74  errorString = QLocalSocket::tr("%1: Connection error").arg(function);
76  break;
77  case ERROR_FILE_NOT_FOUND:
79  errorString = QLocalSocket::tr("%1: Invalid name").arg(function);
81  break;
82  case ERROR_ACCESS_DENIED:
84  errorString = QLocalSocket::tr("%1: Access denied").arg(function);
86  break;
87  default:
89  errorString = QLocalSocket::tr("%1: Unknown error %2").arg(function).arg(windowsError);
90 #if defined QLOCALSOCKET_DEBUG
91  qWarning() << "QLocalSocket error not handled:" << errorString;
92 #endif
94  }
95 
96  if (currentState != state) {
97  q->emit stateChanged(state);
99  q->emit disconnected();
100  }
101  emit q->error(error);
102 }
103 
105  handle(INVALID_HANDLE_VALUE),
106  pipeWriter(0),
110  readSequenceStarted(false),
111  pendingReadyRead(false),
112  pipeClosed(false),
114 {
115 }
116 
118 {
120  CloseHandle(overlapped.hEvent);
121 }
122 
124 {
125  if (handle != INVALID_HANDLE_VALUE) {
126  DisconnectNamedPipe(handle);
127  CloseHandle(handle);
128  }
129 }
130 
131 void QLocalSocket::connectToServer(const QString &name, OpenMode openMode)
132 {
133  Q_D(QLocalSocket);
134  if (state() == ConnectedState || state() == ConnectingState)
135  return;
136 
138  d->errorString = QString();
139  d->state = ConnectingState;
140  emit stateChanged(d->state);
141  if (name.isEmpty()) {
143  setErrorString(QLocalSocket::tr("%1: Invalid name").arg(QLatin1String("QLocalSocket::connectToServer")));
144  d->state = UnconnectedState;
145  emit error(d->error);
146  emit stateChanged(d->state);
147  return;
148  }
149 
150  QString pipePath = QLatin1String("\\\\.\\pipe\\");
151  if (name.startsWith(pipePath))
152  d->fullServerName = name;
153  else
154  d->fullServerName = pipePath + name;
155  // Try to open a named pipe
156  HANDLE localSocket;
157  forever {
158  DWORD permissions = (openMode & QIODevice::ReadOnly) ? GENERIC_READ : 0;
159  permissions |= (openMode & QIODevice::WriteOnly) ? GENERIC_WRITE : 0;
160  localSocket = CreateFile((const wchar_t *)d->fullServerName.utf16(), // pipe name
161  permissions,
162  0, // no sharing
163  NULL, // default security attributes
164  OPEN_EXISTING, // opens existing pipe
165  FILE_FLAG_OVERLAPPED,
166  NULL); // no template file
167 
168  if (localSocket != INVALID_HANDLE_VALUE)
169  break;
170  DWORD error = GetLastError();
171  // It is really an error only if it is not ERROR_PIPE_BUSY
172  if (ERROR_PIPE_BUSY != error) {
173  break;
174  }
175 
176  // All pipe instances are busy, so wait until connected or up to 5 seconds.
177  if (!WaitNamedPipe((const wchar_t *)d->fullServerName.utf16(), 5000))
178  break;
179  }
180 
181  if (localSocket == INVALID_HANDLE_VALUE) {
182  d->setErrorString(QLatin1String("QLocalSocket::connectToServer"));
183  d->fullServerName = QString();
184  return;
185  }
186 
187  // we have a valid handle
188  d->serverName = name;
189  if (setSocketDescriptor((quintptr)localSocket, ConnectedState, openMode)) {
190  d->handle = localSocket;
191  emit connected();
192  }
193 }
194 
195 // This is reading from the buffer
197 {
198  Q_D(QLocalSocket);
199 
200  if (d->pipeClosed && d->actualReadBufferSize == 0)
201  return -1; // signal EOF
202 
203  qint64 readSoFar;
204  // If startAsyncRead() read data, copy it to its destination.
205  if (maxSize == 1 && d->actualReadBufferSize > 0) {
206  *data = d->readBuffer.getChar();
207  d->actualReadBufferSize--;
208  readSoFar = 1;
209  } else {
210  qint64 bytesToRead = qMin(qint64(d->actualReadBufferSize), maxSize);
211  readSoFar = 0;
212  while (readSoFar < bytesToRead) {
213  const char *ptr = d->readBuffer.readPointer();
214  int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar,
215  qint64(d->readBuffer.nextDataBlockSize()));
216  memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);
217  readSoFar += bytesToReadFromThisBlock;
218  d->readBuffer.free(bytesToReadFromThisBlock);
219  d->actualReadBufferSize -= bytesToReadFromThisBlock;
220  }
221  }
222 
223  if (d->pipeClosed) {
224  if (d->actualReadBufferSize == 0)
226  } else {
227  if (!d->readSequenceStarted)
228  d->startAsyncRead();
229  d->checkReadyRead();
230  }
231 
232  return readSoFar;
233 }
234 
240 {
241  if (actualReadBufferSize > 0) {
242  if (!pendingReadyRead) {
243  Q_Q(QLocalSocket);
245  pendingReadyRead = true;
246  }
247  } else {
248  pendingReadyRead = false;
249  }
250 }
251 
257 {
258  do {
259  DWORD bytesToRead = checkPipeState();
260  if (pipeClosed)
261  return;
262 
263  if (bytesToRead == 0) {
264  // There are no bytes in the pipe but we need to
265  // start the overlapped read with some buffer size.
266  bytesToRead = initialReadBufferSize;
267  }
268 
269  if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) {
270  bytesToRead = readBufferMaxSize - readBuffer.size();
271  if (bytesToRead == 0) {
272  // Buffer is full. User must read data from the buffer
273  // before we can read more from the pipe.
274  return;
275  }
276  }
277 
278  char *ptr = readBuffer.reserve(bytesToRead);
279 
280  readSequenceStarted = true;
281  if (ReadFile(handle, ptr, bytesToRead, NULL, &overlapped)) {
283  } else {
284  switch (GetLastError()) {
285  case ERROR_IO_PENDING:
286  // This is not an error. We're getting notified, when data arrives.
287  return;
288  case ERROR_MORE_DATA:
289  // This is not an error. The synchronous read succeeded.
290  // We're connected to a message mode pipe and the message
291  // didn't fit into the pipe's system buffer.
293  break;
294  case ERROR_PIPE_NOT_CONNECTED:
295  {
296  // It may happen, that the other side closes the connection directly
297  // after writing data. Then we must set the appropriate socket state.
298  pipeClosed = true;
299  Q_Q(QLocalSocket);
300  emit q->readChannelFinished();
301  return;
302  }
303  default:
304  setErrorString(QLatin1String("QLocalSocketPrivate::startAsyncRead"));
305  return;
306  }
307  }
308  } while (!readSequenceStarted);
309 }
310 
320 {
321  ResetEvent(overlapped.hEvent);
322  readSequenceStarted = false;
323 
324  DWORD bytesRead;
325  if (!GetOverlappedResult(handle, &overlapped, &bytesRead, TRUE)) {
326  switch (GetLastError()) {
327  case ERROR_MORE_DATA:
328  // This is not an error. We're connected to a message mode
329  // pipe and the message didn't fit into the pipe's system
330  // buffer. We will read the remaining data in the next call.
331  break;
332  case ERROR_PIPE_NOT_CONNECTED:
333  return false;
334  default:
335  setErrorString(QLatin1String("QLocalSocketPrivate::completeAsyncRead"));
336  return false;
337  }
338  }
339 
340  actualReadBufferSize += bytesRead;
342  return true;
343 }
344 
345 qint64 QLocalSocket::writeData(const char *data, qint64 maxSize)
346 {
347  Q_D(QLocalSocket);
348  if (!d->pipeWriter) {
349  d->pipeWriter = new QWindowsPipeWriter(d->handle, this);
350  connect(d->pipeWriter, SIGNAL(canWrite()), this, SLOT(_q_canWrite()));
351  connect(d->pipeWriter, SIGNAL(bytesWritten(qint64)), this, SIGNAL(bytesWritten(qint64)));
352  d->pipeWriter->start();
353  }
354  return d->pipeWriter->write(data, maxSize);
355 }
356 
357 void QLocalSocket::abort()
358 {
359  Q_D(QLocalSocket);
360  if (d->pipeWriter) {
361  delete d->pipeWriter;
362  d->pipeWriter = 0;
363  }
364  close();
365 }
366 
376 {
377  Q_Q(QLocalSocket);
378  DWORD bytes;
379  if (PeekNamedPipe(handle, NULL, 0, NULL, &bytes, NULL)) {
380  return bytes;
381  } else {
382  if (!pipeClosed) {
383  pipeClosed = true;
384  emit q->readChannelFinished();
385  if (actualReadBufferSize == 0)
387  }
388  }
389  return 0;
390 }
391 
393 {
394  Q_Q(QLocalSocket);
395  q->close();
396 }
397 
399 {
400  Q_D(const QLocalSocket);
401  qint64 available = QIODevice::bytesAvailable();
402  available += (qint64) d->actualReadBufferSize;
403  return available;
404 }
405 
407 {
408  Q_D(const QLocalSocket);
409  return (d->pipeWriter) ? d->pipeWriter->bytesToWrite() : 0;
410 }
411 
412 bool QLocalSocket::canReadLine() const
413 {
414  Q_D(const QLocalSocket);
415  if (state() != ConnectedState)
416  return false;
417  return (QIODevice::canReadLine()
418  || d->readBuffer.indexOf('\n', d->actualReadBufferSize) != -1);
419 }
420 
421 void QLocalSocket::close()
422 {
423  Q_D(QLocalSocket);
424  if (state() == UnconnectedState)
425  return;
426 
428  d->state = ClosingState;
429  emit stateChanged(d->state);
430  if (!d->pipeClosed)
431  emit readChannelFinished();
432  d->serverName = QString();
433  d->fullServerName = QString();
434 
435  if (state() != UnconnectedState && bytesToWrite() > 0) {
436  disconnectFromServer();
437  return;
438  }
439  d->readSequenceStarted = false;
440  d->pendingReadyRead = false;
441  d->pipeClosed = false;
442  d->destroyPipeHandles();
443  d->handle = INVALID_HANDLE_VALUE;
444  ResetEvent(d->overlapped.hEvent);
445  d->state = UnconnectedState;
446  emit stateChanged(d->state);
447  emit disconnected();
448  if (d->pipeWriter) {
449  delete d->pipeWriter;
450  d->pipeWriter = 0;
451  }
452 }
453 
454 bool QLocalSocket::flush()
455 {
456  Q_D(QLocalSocket);
457  if (d->pipeWriter)
458  return d->pipeWriter->waitForWrite(0);
459  return false;
460 }
461 
463 {
464  Q_D(QLocalSocket);
465 
466  // Are we still connected?
467  if (!isValid()) {
468  // If we have unwritten data, the pipeWriter is still present.
469  // It must be destroyed before close() to prevent an infinite loop.
470  delete d->pipeWriter;
471  d->pipeWriter = 0;
472  }
473 
474  flush();
475  if (d->pipeWriter && d->pipeWriter->bytesToWrite() != 0) {
476  d->state = QLocalSocket::ClosingState;
477  emit stateChanged(d->state);
478  } else {
479  close();
480  }
481 }
482 
484 {
485  Q_D(const QLocalSocket);
486  return d->error;
487 }
488 
489 bool QLocalSocket::setSocketDescriptor(quintptr socketDescriptor,
490  LocalSocketState socketState, OpenMode openMode)
491 {
492  Q_D(QLocalSocket);
493  d->readBuffer.clear();
494  d->actualReadBufferSize = 0;
495  QIODevice::open(openMode);
496  d->handle = (int*)socketDescriptor;
497  d->state = socketState;
498  emit stateChanged(d->state);
499  if (d->state == ConnectedState && openMode.testFlag(QIODevice::ReadOnly)) {
500  d->startAsyncRead();
501  d->checkReadyRead();
502  }
503  return true;
504 }
505 
507 {
508  Q_Q(QLocalSocket);
510  q->close();
511 }
512 
514 {
515  Q_Q(QLocalSocket);
516  if (!completeAsyncRead()) {
517  pipeClosed = true;
518  emit q->readChannelFinished();
519  if (actualReadBufferSize == 0)
521  return;
522  }
523  startAsyncRead();
524  pendingReadyRead = false;
525  emit q->readyRead();
526 }
527 
529 {
530  if (pendingReadyRead) {
531  Q_Q(QLocalSocket);
532  pendingReadyRead = false;
533  emit q->readyRead();
534  }
535 }
536 
538 {
539  Q_D(const QLocalSocket);
540  return (quintptr)d->handle;
541 }
542 
544 {
545  Q_D(const QLocalSocket);
546  return d->readBufferMaxSize;
547 }
548 
550 {
551  Q_D(QLocalSocket);
552  d->readBufferMaxSize = size;
553 }
554 
555 bool QLocalSocket::waitForConnected(int msecs)
556 {
557  Q_UNUSED(msecs);
558  return (state() == ConnectedState);
559 }
560 
561 bool QLocalSocket::waitForDisconnected(int msecs)
562 {
563  Q_D(QLocalSocket);
564  if (state() == UnconnectedState)
565  return false;
566  if (!openMode().testFlag(QIODevice::ReadOnly)) {
567  qWarning("QLocalSocket::waitForDisconnected isn't supported for write only pipes.");
568  return false;
569  }
571  forever {
572  d->checkPipeState();
573  if (d->pipeClosed)
574  close();
575  if (state() == UnconnectedState)
576  return true;
577  Sleep(timer.nextSleepTime());
578  if (timer.hasTimedOut())
579  break;
580  }
581 
582  return false;
583 }
584 
585 bool QLocalSocket::isValid() const
586 {
587  Q_D(const QLocalSocket);
588  return d->handle != INVALID_HANDLE_VALUE;
589 }
590 
591 bool QLocalSocket::waitForReadyRead(int msecs)
592 {
593  Q_D(QLocalSocket);
594 
595  if (bytesAvailable() > 0)
596  return true;
597 
598  if (d->state != QLocalSocket::ConnectedState)
599  return false;
600 
601  // We already know that the pipe is gone, but did not enter the event loop yet.
602  if (d->pipeClosed) {
603  close();
604  return false;
605  }
606 
607  Q_ASSERT(d->readSequenceStarted);
608  DWORD result = WaitForSingleObject(d->overlapped.hEvent, msecs == -1 ? INFINITE : msecs);
609  switch (result) {
610  case WAIT_OBJECT_0:
611  d->_q_notified();
612  // We just noticed that the pipe is gone.
613  if (d->pipeClosed && !bytesAvailable()) {
614  close();
615  return false;
616  }
617  return true;
618  case WAIT_TIMEOUT:
619  return false;
620  }
621 
622  qWarning("QLocalSocket::waitForReadyRead WaitForSingleObject failed with error code %d.", int(GetLastError()));
623  return false;
624 }
625 
626 bool QLocalSocket::waitForBytesWritten(int msecs)
627 {
628  Q_D(const QLocalSocket);
629  if (!d->pipeWriter)
630  return false;
631 
632  // Wait for the pipe writer to acknowledge that it has
633  // written. This will succeed if either the pipe writer has
634  // already written the data, or if it manages to write data
635  // within the given timeout.
636  return d->pipeWriter->waitForWrite(msecs);
637 }
638 
double d
Definition: qnumeric_p.h:62
quintptr socketDescriptor() const
Returns the native socket descriptor of the QLocalSocket object if this is available; otherwise retur...
bool waitForReadyRead(int msecs=30000)
This function blocks until data is available for reading and the QIODevice::readyRead() signal has be...
QIntegerForSizeof< void * >::Unsigned quintptr
Definition: qglobal.h:986
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
LocalSocketState
This enum describes the different states in which a socket can be.
Definition: qlocalsocket.h:78
bool waitForConnected(int msecs=30000)
Waits until the socket is connected, up to msecs milliseconds.
QWinEventNotifier * dataReadNotifier
QIODevice::OpenMode openMode
Definition: qiodevice_p.h:212
virtual void close()
First emits aboutToClose(), then closes the device and sets its OpenMode to NotOpen.
Definition: qiodevice.cpp:590
QLocalSocket::LocalSocketState state
#define SLOT(a)
Definition: qobjectdefs.h:226
virtual void close()
Reimplemented Function
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition: qstring.cpp:3734
static QString tr(const char *sourceText, const char *comment=0, int n=-1)
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
EventLoopTimerRef timer
bool waitForDisconnected(int msecs=30000)
Waits until the socket has disconnected, up to msecs milliseconds.
The QString class provides a Unicode character string.
Definition: qstring.h:83
QWindowsPipeWriter * pipeWriter
virtual qint64 writeData(const char *, qint64)
Reimplemented Function
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
#define WAIT_OBJECT_0
bool completeAsyncRead()
Sets the correct size of the read buffer after a read operation.
QLocalSocket::LocalSocketError error
#define Q_D(Class)
Definition: qglobal.h:2482
The QLocalSocket class provides a local socket.
Definition: qlocalsocket.h:58
qint64 readBufferSize() const
Returns the size of the internal read buffer.
#define Q_Q(Class)
Definition: qglobal.h:2483
#define SIGNAL(a)
Definition: qobjectdefs.h:227
char * reserve(int bytes)
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
static QIntfbScreen * connected
virtual qint64 readData(char *, qint64)
Reimplemented Function
void setReadBufferSize(qint64 size)
Sets the size of QLocalSocket&#39;s internal read buffer to be size bytes.
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
const char * name
#define emit
Definition: qobjectdefs.h:76
Q_CORE_EXPORT void qWarning(const char *,...)
bool flush()
This function writes as much as possible from the internal write buffer to the socket, without blocking.
static const char * data(const QByteArray &arr)
void connectToServer(const QString &name, OpenMode openMode=ReadWrite)
Attempts to make a connection to name.
#define FALSE
Synonym for false.
Definition: qglobal.h:1019
QString errorString
Definition: qiodevice_p.h:213
const T * ptr(const T &t)
__int64 qint64
Definition: qglobal.h:942
void * HANDLE
Definition: qnamespace.h:1671
LocalSocketError error() const
Returns the type of error that last occurred.
virtual qint64 bytesToWrite() const
Reimplemented Function
bool isValid() const
Returns true if the socket is valid and ready for use; otherwise returns false.
DWORD checkPipeState()
Returns the number of available bytes in the pipe.
#define TRUE
Synonym for true.
Definition: qglobal.h:1018
virtual bool canReadLine() const
Reimplemented Function
void abort()
Aborts the current connection and resets the socket.
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
void truncate(int pos)
static const qint64 initialReadBufferSize
bool waitForBytesWritten(int msecs=30000)
Reimplemented Function
bool singleShot
This static function calls a slot after a given time interval.
Definition: qtimer.h:59
virtual qint64 bytesAvailable() const
Returns the number of bytes that are available for reading.
Definition: qiodevice.cpp:752
virtual qint64 bytesAvailable() const
Reimplemented Function
virtual bool open(OpenMode mode)
Opens the device and sets its OpenMode to mode.
Definition: qiodevice.cpp:570
QRingBuffer readBuffer
Q_CORE_EXPORT QTextStream & flush(QTextStream &s)
virtual bool canReadLine() const
Returns true if a complete line of data can be read from the device; otherwise returns false...
Definition: qiodevice.cpp:1330
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
LocalSocketError
The LocalServerError enumeration represents the errors that can occur.
Definition: qlocalsocket.h:64
bool setSocketDescriptor(quintptr socketDescriptor, LocalSocketState socketState=ConnectedState, OpenMode openMode=ReadWrite)
void setErrorString(const QString &function)
void disconnectFromServer()
Attempts to close the socket.
int size() const
#define forever
This macro is provided for convenience for writing infinite loops.
Definition: qglobal.h:2452