summaryrefslogtreecommitdiffstats
path: root/src/network/socket/qlocalserver_win.cpp
diff options
context:
space:
mode:
authorJoerg Bornemann <joerg.bornemann@theqtcompany.com>2016-03-10 14:07:16 +0100
committerJoerg Bornemann <joerg.bornemann@theqtcompany.com>2016-03-10 17:32:49 +0000
commitac8dae8b5eafa07704155dd636d8da2ec21d1c6f (patch)
treec2a050d18e5511047d24b7136162399759357d12 /src/network/socket/qlocalserver_win.cpp
parent8589bb334f1e90630897c600c747541902434fab (diff)
QLocalServer/Win: Fix race condition in listen().
Suppose a client connects while the QLocalServer is still in the loop that calls addListener. The connection would SetEvent(eventHandle), but every call to ConnectNamedPipe would ResetEvent(eventHandle). Thus, the connection is never detected by the notifier on eventHandle. Callers of addListener must check the connection state of every listener to make sure that no client connected while setting up listeners. Task-number: QTBUG-49254 Change-Id: Ia961927ea76973708e6e3f73510695eb5d6a0e4c Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Diffstat (limited to 'src/network/socket/qlocalserver_win.cpp')
-rw-r--r--src/network/socket/qlocalserver_win.cpp70
1 files changed, 40 insertions, 30 deletions
diff --git a/src/network/socket/qlocalserver_win.cpp b/src/network/socket/qlocalserver_win.cpp
index 265f894972..06ad62f548 100644
--- a/src/network/socket/qlocalserver_win.cpp
+++ b/src/network/socket/qlocalserver_win.cpp
@@ -192,6 +192,9 @@ bool QLocalServerPrivate::addListener()
memset(&listener.overlapped, 0, sizeof(listener.overlapped));
listener.overlapped.hEvent = eventHandle;
+
+ // Beware! ConnectNamedPipe will reset the eventHandle to non-signaled.
+ // Callers of addListener must check all listeners for connections.
if (!ConnectNamedPipe(listener.handle, &listener.overlapped)) {
switch (GetLastError()) {
case ERROR_IO_PENDING:
@@ -199,7 +202,6 @@ bool QLocalServerPrivate::addListener()
break;
case ERROR_PIPE_CONNECTED:
listener.connected = true;
- SetEvent(eventHandle);
break;
default:
CloseHandle(listener.handle);
@@ -251,6 +253,8 @@ bool QLocalServerPrivate::listen(const QString &name)
for (int i = 0; i < SYSTEM_MAX_PENDING_SOCKETS; ++i)
if (!addListener())
return false;
+
+ _q_onNewConnection();
return true;
}
@@ -264,37 +268,43 @@ void QLocalServerPrivate::_q_onNewConnection()
{
Q_Q(QLocalServer);
DWORD dummy;
-
- // Reset first, otherwise we could reset an event which was asserted
- // immediately after we checked the conn status.
- ResetEvent(eventHandle);
-
- // Testing shows that there is indeed absolutely no guarantee which listener gets
- // a client connection first, so there is no way around polling all of them.
- for (int i = 0; i < listeners.size(); ) {
- HANDLE handle = listeners[i].handle;
- if (listeners[i].connected
- || GetOverlappedResult(handle, &listeners[i].overlapped, &dummy, FALSE))
- {
- listeners.removeAt(i);
-
- addListener();
-
- if (pendingConnections.size() > maxPendingConnections)
- connectionEventNotifier->setEnabled(false);
-
- // Make this the last thing so connected slots can wreak the least havoc
- q->incomingConnection((quintptr)handle);
- } else {
- if (GetLastError() != ERROR_IO_INCOMPLETE) {
- q->close();
- setError(QLatin1String("QLocalServerPrivate::_q_onNewConnection"));
- return;
+ bool tryAgain;
+ do {
+ tryAgain = false;
+
+ // Reset first, otherwise we could reset an event which was asserted
+ // immediately after we checked the conn status.
+ ResetEvent(eventHandle);
+
+ // Testing shows that there is indeed absolutely no guarantee which listener gets
+ // a client connection first, so there is no way around polling all of them.
+ for (int i = 0; i < listeners.size(); ) {
+ HANDLE handle = listeners[i].handle;
+ if (listeners[i].connected
+ || GetOverlappedResult(handle, &listeners[i].overlapped, &dummy, FALSE))
+ {
+ listeners.removeAt(i);
+
+ addListener();
+
+ if (pendingConnections.size() > maxPendingConnections)
+ connectionEventNotifier->setEnabled(false);
+ else
+ tryAgain = true;
+
+ // Make this the last thing so connected slots can wreak the least havoc
+ q->incomingConnection((quintptr)handle);
+ } else {
+ if (GetLastError() != ERROR_IO_INCOMPLETE) {
+ q->close();
+ setError(QLatin1String("QLocalServerPrivate::_q_onNewConnection"));
+ return;
+ }
+
+ ++i;
}
-
- ++i;
}
- }
+ } while (tryAgain);
}
void QLocalServerPrivate::closeServer()