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

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 7.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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_MESSAGE | // message type pipe
69 PIPE_READMODE_MESSAGE | // message-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 break;
89 case ERROR_PIPE_CONNECTED:
90 SetEvent(eventHandle);
91 break;
92 default:
93 CloseHandle(listener.handle);
94 setError(QLatin1String("QLocalServerPrivate::addListener"));
95 listeners.removeLast();
96 return false;
97 }
98 } else {
99 Q_ASSERT_X(false, "QLocalServerPrivate::addListener", "The impossible happened");
100 SetEvent(eventHandle);
101 }
102 return true;
103}
104
105void QLocalServerPrivate::setError(const QString &function)
106{
107 int windowsError = GetLastError();
108 errorString = QString::fromLatin1("%1: %2").arg(function).arg(qt_error_string(windowsError));
109 error = QAbstractSocket::UnknownSocketError;
110}
111
112void QLocalServerPrivate::init()
113{
114}
115
116bool QLocalServerPrivate::removeServer(const QString &name)
117{
118 Q_UNUSED(name);
119 return true;
120}
121
122bool QLocalServerPrivate::listen(const QString &name)
123{
124 Q_Q(QLocalServer);
125
126 QString pipePath = QLatin1String("\\\\.\\pipe\\");
127 if (name.startsWith(pipePath))
128 fullServerName = name;
129 else
130 fullServerName = pipePath + name;
131
132 // Use only one event for all listeners of one socket.
133 // The idea is that listener events are rare, so polling all listeners once in a while is
134 // cheap compared to waiting for N additional events in each iteration of the main loop.
135 eventHandle = CreateEvent(NULL, TRUE, FALSE, NULL);
136 connectionEventNotifier = new QWinEventNotifier(eventHandle , q);
137 q->connect(connectionEventNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_onNewConnection()));
138
139 for (int i = 0; i < SYSTEM_MAX_PENDING_SOCKETS; ++i)
140 if (!addListener())
141 return false;
142 return true;
143}
144
145void QLocalServerPrivate::_q_onNewConnection()
146{
147 Q_Q(QLocalServer);
148 DWORD dummy;
149
150 // Reset first, otherwise we could reset an event which was asserted
151 // immediately after we checked the conn status.
152 ResetEvent(eventHandle);
153
154 // Testing shows that there is indeed absolutely no guarantee which listener gets
155 // a client connection first, so there is no way around polling all of them.
156 for (int i = 0; i < listeners.size(); ) {
157 HANDLE handle = listeners[i].handle;
158 if (GetOverlappedResult(handle, &listeners[i].overlapped, &dummy, FALSE)) {
159 listeners.removeAt(i);
160
161 addListener();
162
163 if (pendingConnections.size() > maxPendingConnections)
164 connectionEventNotifier->setEnabled(false);
165
166 // Make this the last thing so connected slots can wreak the least havoc
167 q->incomingConnection((quintptr)handle);
168 } else {
169 if (GetLastError() != ERROR_IO_INCOMPLETE) {
170 setError(QLatin1String("QLocalServerPrivate::_q_onNewConnection"));
171 closeServer();
172 return;
173 }
174
175 ++i;
176 }
177 }
178}
179
180void QLocalServerPrivate::closeServer()
181{
182 connectionEventNotifier->setEnabled(false); // Otherwise, closed handle is checked before deleter runs
183 connectionEventNotifier->deleteLater();
184 connectionEventNotifier = 0;
185 CloseHandle(eventHandle);
186 for (int i = 0; i < listeners.size(); ++i)
187 CloseHandle(listeners[i].handle);
188 listeners.clear();
189}
190
191void QLocalServerPrivate::waitForNewConnection(int msecs, bool *timedOut)
192{
193 Q_Q(QLocalServer);
194 if (!pendingConnections.isEmpty() || !q->isListening())
195 return;
196
197 DWORD result = WaitForSingleObject(eventHandle, (msecs == -1) ? INFINITE : msecs);
198 if (result == WAIT_TIMEOUT) {
199 if (timedOut)
200 *timedOut = true;
201 } else {
202 _q_onNewConnection();
203 }
204}
205
206QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.