Changeset 561 for trunk/src/network/socket/qlocalserver_win.cpp
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/network/socket/qlocalserver_win.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information ([email protected]) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation ([email protected]) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 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 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you 37 ** @nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 45 45 46 46 #include <qdebug.h> 47 #include <qdatetime.h>48 #include <qcoreapplication.h>49 #include <QMetaType>50 47 51 48 // The buffer size need to be 0 otherwise data could be … … 54 51 #define BUFSIZE 0 55 52 53 54 55 56 56 QT_BEGIN_NAMESPACE 57 57 58 QLocalServerThread::QLocalServerThread(QObject *parent) : QThread(parent), 59 maxPendingConnections(1) 60 { 61 stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 62 gotConnectionEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 63 } 64 65 QLocalServerThread::~QLocalServerThread() 66 { 67 stop(); 68 closeServer(); 69 CloseHandle(stopEvent); 70 CloseHandle(gotConnectionEvent); 71 } 72 73 void QLocalServerThread::stop() 74 { 75 if (isRunning()) { 76 SetEvent(stopEvent); 77 wait(); 78 ResetEvent(stopEvent); 79 } 80 } 81 82 void QLocalServerThread::closeServer() 83 { 84 while (!pendingHandles.isEmpty()) 85 CloseHandle(pendingHandles.dequeue()); 86 } 87 88 QString QLocalServerThread::setName(const QString &name) 89 { 90 QString pipePath = QLatin1String("\\\\.\\pipe\\"); 91 if (name.startsWith(pipePath)) 92 fullServerName = name; 93 else 94 fullServerName = pipePath + name; 95 for (int i = pendingHandles.count(); i < maxPendingConnections; ++i) 96 if (!makeHandle()) 97 break; 98 return fullServerName; 99 } 100 101 bool QLocalServerThread::makeHandle() 102 { 103 if (pendingHandles.count() >= maxPendingConnections) 104 return false; 105 106 HANDLE handle = INVALID_HANDLE_VALUE; 107 QT_WA({ 108 handle = CreateNamedPipeW( 109 (TCHAR*)fullServerName.utf16(), // pipe name 58 bool 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 110 67 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access 111 68 PIPE_TYPE_MESSAGE | // message type pipe … … 117 74 3000, // client time-out 118 75 NULL); 119 }, { 120 handle = CreateNamedPipeA( 121 fullServerName.toLocal8Bit().constData(), // pipe name 122 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access 123 PIPE_TYPE_MESSAGE | // message type pipe 124 PIPE_READMODE_MESSAGE | // message-read mode 125 PIPE_WAIT, // blocking mode 126 PIPE_UNLIMITED_INSTANCES, // max. instances 127 BUFSIZE, // output buffer size 128 BUFSIZE, // input buffer size 129 3000, // client time-out 130 NULL); 131 }); 132 133 if (INVALID_HANDLE_VALUE == handle) { 76 77 if (listener.handle == INVALID_HANDLE_VALUE) { 78 setError(QLatin1String("QLocalServerPrivate::addListener")); 79 listeners.removeLast(); 134 80 return false; 135 81 } 136 pendingHandles.enqueue(handle); 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 } 137 102 return true; 138 103 } 139 104 140 void QLocalServerThread::run() 141 { 142 OVERLAPPED op; 143 HANDLE handleArray[2]; 144 memset(&op, 0, sizeof(op)); 145 handleArray[0] = op.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 146 handleArray[1] = stopEvent; 147 HANDLE handle = INVALID_HANDLE_VALUE; 148 149 forever { 150 if (INVALID_HANDLE_VALUE == handle) { 151 makeHandle(); 152 if (!pendingHandles.isEmpty()) 153 handle = pendingHandles.dequeue(); 154 } 155 if (INVALID_HANDLE_VALUE == handle) { 156 int windowsError = GetLastError(); 157 QString function = QLatin1String("QLocalServer::run"); 158 QString errorString = QLocalServer::tr("%1: Unknown error %2").arg(function).arg(windowsError); 159 emit error(QAbstractSocket::UnknownSocketError, errorString); 160 CloseHandle(handleArray[0]); 161 SetEvent(gotConnectionEvent); 162 return; 163 } 164 165 BOOL isConnected = ConnectNamedPipe(handle, &op) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); 166 if (!isConnected) { 167 switch (WaitForMultipleObjects(2, handleArray, FALSE, INFINITE)) 168 { 169 case WAIT_OBJECT_0 + 1: 170 CloseHandle(handle); 171 CloseHandle(handleArray[0]); 105 void 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 112 void QLocalServerPrivate::init() 113 { 114 } 115 116 bool QLocalServerPrivate::removeServer(const QString &name) 117 { 118 Q_UNUSED(name); 119 return true; 120 } 121 122 bool 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 145 void 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 172 return; 173 173 } 174 175 174 176 } 175 emit connected(handle); 176 handle = INVALID_HANDLE_VALUE; 177 ResetEvent(handleArray[0]); 178 SetEvent(gotConnectionEvent); 179 } 180 } 181 182 void QLocalServerPrivate::init() 183 { 184 Q_Q(QLocalServer); 185 qRegisterMetaType<HANDLE>("HANDLE"); 186 q->connect(&waitForConnection, SIGNAL(connected(HANDLE)), 187 q, SLOT(_q_openSocket(HANDLE)), Qt::QueuedConnection); 188 q->connect(&waitForConnection, SIGNAL(finished()), 189 q, SLOT(_q_stoppedListening()), Qt::QueuedConnection); 190 q->connect(&waitForConnection, SIGNAL(terminated()), 191 q, SLOT(_q_stoppedListening()), Qt::QueuedConnection); 192 q->connect(&waitForConnection, SIGNAL(error(QAbstractSocket::SocketError, const QString &)), 193 q, SLOT(_q_setError(QAbstractSocket::SocketError, const QString &))); 194 } 195 196 bool QLocalServerPrivate::removeServer(const QString &name) 197 { 198 Q_UNUSED(name); 199 return true; 200 } 201 202 bool QLocalServerPrivate::listen(const QString &name) 203 { 204 fullServerName = waitForConnection.setName(name); 205 serverName = name; 206 waitForConnection.start(); 207 return true; 208 } 209 210 void QLocalServerPrivate::_q_setError(QAbstractSocket::SocketError e, const QString &eString) 211 { 212 error = e; 213 errorString = eString; 214 } 215 216 void QLocalServerPrivate::_q_stoppedListening() 217 { 218 Q_Q(QLocalServer); 219 if (!inWaitingFunction) 220 q->close(); 221 } 222 223 void QLocalServerPrivate::_q_openSocket(HANDLE handle) 224 { 225 Q_Q(QLocalServer); 226 q->incomingConnection((int)handle); 177 } 227 178 } 228 179 229 180 void QLocalServerPrivate::closeServer() 230 181 { 231 waitForConnection.stop(); 232 waitForConnection.closeServer(); 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(); 233 189 } 234 190 … … 239 195 return; 240 196 241 DWORD result = WaitForSingleObject(waitForConnection.gotConnectionEvent, 242 (msecs == -1) ? INFINITE : msecs); 197 DWORD result = WaitForSingleObject(eventHandle, (msecs == -1) ? INFINITE : msecs); 243 198 if (result == WAIT_TIMEOUT) { 244 199 if (timedOut) 245 200 *timedOut = true; 246 201 } else { 247 ResetEvent(waitForConnection.gotConnectionEvent); 248 QCoreApplication::instance()->processEvents(); 202 _q_onNewConnection(); 249 203 } 250 204 }
Note:
See TracChangeset
for help on using the changeset viewer.