Qt 4.8
qlocalserver_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 "qlocalserver.h"
43 #include "qlocalserver_p.h"
44 #include "qlocalsocket.h"
45 
46 #include <qdebug.h>
47 
48 // The buffer size need to be 0 otherwise data could be
49 // lost if the socket that has written data closes the connection
50 // before it is read. Pipewriter is used for write buffering.
51 #define BUFSIZE 0
52 
53 // ###: This should be a property. Should replace the insane 50 on unix as well.
54 #define SYSTEM_MAX_PENDING_SOCKETS 8
55 
57 
59 {
60  // The object must not change its address once the
61  // contained OVERLAPPED struct is passed to Windows.
62  listeners << Listener();
63  Listener &listener = listeners.last();
64 
65  listener.handle = CreateNamedPipe(
66  (const wchar_t *)fullServerName.utf16(), // pipe name
67  PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
68  PIPE_TYPE_BYTE | // byte type pipe
69  PIPE_READMODE_BYTE | // byte-read mode
70  PIPE_WAIT, // blocking mode
71  PIPE_UNLIMITED_INSTANCES, // max. instances
72  BUFSIZE, // output buffer size
73  BUFSIZE, // input buffer size
74  3000, // client time-out
75  NULL);
76 
77  if (listener.handle == INVALID_HANDLE_VALUE) {
78  setError(QLatin1String("QLocalServerPrivate::addListener"));
79  listeners.removeLast();
80  return false;
81  }
82 
83  memset(&listener.overlapped, 0, sizeof(listener.overlapped));
84  listener.overlapped.hEvent = eventHandle;
85  if (!ConnectNamedPipe(listener.handle, &listener.overlapped)) {
86  switch (GetLastError()) {
87  case ERROR_IO_PENDING:
88  listener.connected = false;
89  break;
90  case ERROR_PIPE_CONNECTED:
91  listener.connected = true;
92  SetEvent(eventHandle);
93  break;
94  default:
95  CloseHandle(listener.handle);
96  setError(QLatin1String("QLocalServerPrivate::addListener"));
97  listeners.removeLast();
98  return false;
99  }
100  } else {
101  Q_ASSERT_X(false, "QLocalServerPrivate::addListener", "The impossible happened");
102  SetEvent(eventHandle);
103  }
104  return true;
105 }
106 
107 void QLocalServerPrivate::setError(const QString &function)
108 {
109  int windowsError = GetLastError();
110  errorString = QString::fromLatin1("%1: %2").arg(function).arg(qt_error_string(windowsError));
112 }
113 
115 {
116 }
117 
119 {
120  Q_UNUSED(name);
121  return true;
122 }
123 
124 bool QLocalServerPrivate::listen(const QString &name)
125 {
126  Q_Q(QLocalServer);
127 
128  QString pipePath = QLatin1String("\\\\.\\pipe\\");
129  if (name.startsWith(pipePath))
130  fullServerName = name;
131  else
132  fullServerName = pipePath + name;
133 
134  // Use only one event for all listeners of one socket.
135  // The idea is that listener events are rare, so polling all listeners once in a while is
136  // cheap compared to waiting for N additional events in each iteration of the main loop.
137  eventHandle = CreateEvent(NULL, TRUE, FALSE, NULL);
139  q->connect(connectionEventNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_onNewConnection()));
140 
141  for (int i = 0; i < SYSTEM_MAX_PENDING_SOCKETS; ++i)
142  if (!addListener())
143  return false;
144  return true;
145 }
146 
148 {
149  Q_Q(QLocalServer);
150  DWORD dummy;
151 
152  // Reset first, otherwise we could reset an event which was asserted
153  // immediately after we checked the conn status.
154  ResetEvent(eventHandle);
155 
156  // Testing shows that there is indeed absolutely no guarantee which listener gets
157  // a client connection first, so there is no way around polling all of them.
158  for (int i = 0; i < listeners.size(); ) {
159  HANDLE handle = listeners[i].handle;
160  if (listeners[i].connected
161  || GetOverlappedResult(handle, &listeners[i].overlapped, &dummy, FALSE))
162  {
163  listeners.removeAt(i);
164 
165  addListener();
166 
169 
170  // Make this the last thing so connected slots can wreak the least havoc
171  q->incomingConnection((quintptr)handle);
172  } else {
173  if (GetLastError() != ERROR_IO_INCOMPLETE) {
174  q->close();
175  setError(QLatin1String("QLocalServerPrivate::_q_onNewConnection"));
176  return;
177  }
178 
179  ++i;
180  }
181  }
182 }
183 
185 {
186  connectionEventNotifier->setEnabled(false); // Otherwise, closed handle is checked before deleter runs
189  CloseHandle(eventHandle);
190  for (int i = 0; i < listeners.size(); ++i)
191  CloseHandle(listeners[i].handle);
192  listeners.clear();
193 }
194 
195 void QLocalServerPrivate::waitForNewConnection(int msecs, bool *timedOut)
196 {
197  Q_Q(QLocalServer);
198  if (!pendingConnections.isEmpty() || !q->isListening())
199  return;
200 
201  DWORD result = WaitForSingleObject(eventHandle, (msecs == -1) ? INFINITE : msecs);
202  if (result == WAIT_TIMEOUT) {
203  if (timedOut)
204  *timedOut = true;
205  } else {
207  }
208 }
209 
QString qt_error_string(int errorCode)
Definition: qglobal.cpp:2600
bool listen(const QString &name)
QIntegerForSizeof< void * >::Unsigned quintptr
Definition: qglobal.h:986
void waitForNewConnection(int msec, bool *timedOut)
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QList< Listener > listeners
#define BUFSIZE
#define SLOT(a)
Definition: qobjectdefs.h:226
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
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
The QString class provides a Unicode character string.
Definition: qstring.h:83
bool isEmpty() const
Returns true if the list contains no items; otherwise returns false.
Definition: qlist.h:152
#define Q_Q(Class)
Definition: qglobal.h:2483
void _q_onNewConnection()
We have received a notification that we can read on the listen socket.
#define SIGNAL(a)
Definition: qobjectdefs.h:227
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
static QIntfbScreen * connected
QQueue< QLocalSocket * > pendingConnections
const char * name
QWinEventNotifier * connectionEventNotifier
The QLocalServer class provides a local socket based server.
Definition: qlocalserver.h:58
#define FALSE
Synonym for false.
Definition: qglobal.h:1019
void * HANDLE
Definition: qnamespace.h:1671
void setError(const QString &function)
#define TRUE
Synonym for true.
Definition: qglobal.h:1018
#define Q_ASSERT_X(cond, where, what)
Definition: qglobal.h:1837
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
#define SYSTEM_MAX_PENDING_SOCKETS
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
QAbstractSocket::SocketError error
static QNSListener * listener
#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
void setEnabled(bool enable)
void deleteLater()
Schedules this object for deletion.
Definition: qobject.cpp:2145
static bool removeServer(const QString &name)
const ushort * utf16() const
Returns the QString as a &#39;\0\&#39;-terminated array of unsigned shorts.
Definition: qstring.cpp:5290