source: trunk/src/network/socket/qlocalserver_win.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 7.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtNetwork module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
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
56QT_BEGIN_NAMESPACE
57
58bool QLocalServerPrivate::addListener()
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
107void QLocalServerPrivate::setError(const QString &function)
108{
109 int windowsError = GetLastError();
110 errorString = QString::fromLatin1("%1: %2").arg(function).arg(qt_error_string(windowsError));
111 error = QAbstractSocket::UnknownSocketError;
112}
113
114void QLocalServerPrivate::init()
115{
116}
117
118bool QLocalServerPrivate::removeServer(const QString &name)
119{
120 Q_UNUSED(name);
121 return true;
122}
123
124bool 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);
138 connectionEventNotifier = new QWinEventNotifier(eventHandle , q);
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
147void QLocalServerPrivate::_q_onNewConnection()
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
167 if (pendingConnections.size() > maxPendingConnections)
168 connectionEventNotifier->setEnabled(false);
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
184void QLocalServerPrivate::closeServer()
185{
186 connectionEventNotifier->setEnabled(false); // Otherwise, closed handle is checked before deleter runs
187 connectionEventNotifier->deleteLater();
188 connectionEventNotifier = 0;
189 CloseHandle(eventHandle);
190 for (int i = 0; i < listeners.size(); ++i)
191 CloseHandle(listeners[i].handle);
192 listeners.clear();
193}
194
195void 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 {
206 _q_onNewConnection();
207 }
208}
209
210QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.